Арканоид

Frez
Posts: 23
Joined: Fri Apr 03, 2015 4:49 am
My devices: iPad mini

Арканоид

Post by Frez » Wed Apr 15, 2015 7:00 am

Черновая версия игры Arcanoid, популярной раньше на тетрисах и NES.
При разработке возникла проблема коллизии спрайтов. Для движения шарика у меня выставлен очень маленький sprite delay, в связи с чем основная часть программы не всегда успевает обработать коллизию, и спрайт улетает за нижнюю доску. Решить вроде бы удалось костылями типа дополнительной проверки координат доски, но сомневаюсь, что это лучшее решение. Также были проблемы с непробиваемыми блоками, от которых шар просто должен отскакивать, не удаляя их с поля: иногда, в определенных местах коллизии, шар просто не успевал отскочить и начинал дергаться из стороны в сторону уже внутри блока. Опять же вроде бы решил, но снова костылями.

Разработкой игры с фоновыми процессами занимаюсь впервые, очень прошу проанализировать код и указать на ошибки. Заранее спасибо!

GRAPHICS
bgr=0.2!bgg=0.2!bgb=0.2
GRAPHICS CLEAR bgr,bgg,bgb
SET ORIENTATION PORTRAIT
w=SCREEN_WIDTH()
h=SCREEN_HEIGHT()
bat_wid=100
ball_size=8
bl_w=w/12


DEF score(s)
SPRITE "score" BEGIN
GRAPHICS CLEAR .bgr,.bgg,.bgb
DRAW COLOR 1,1,1
DRAW TEXT "Счёт: "&s AT .bl_w/3,20
SPRITE END
ENDDEF

DEF lifes(s)
DRAW COLOR 1,1,1
SPRITE "lifes_spent" BEGIN
GRAPHICS CLEAR .bgr,.bgg,.bgb
DRAW TEXT "x"&s AT 0,0
SPRITE END
ENDDEF

REFRESH OFF

SPRITE "score" BEGIN bl_w*3,45
DRAW TEXT "Счёт: 0" AT bl_w/3, 20
SPRITE END

SPRITE "kvadrat" BEGIN bat_wid,20
FILL COLOR 0,0,0
FILL RECT 0,0 TO bat_wid-1,19
FILL COLOR 0,0.2,0.8
FILL RECT 2,2 TO bat_wid-3,17
SPRITE END

SPRITE "krug" BEGIN ball_size*2,ball_size*2 'летающий круг
FILL COLOR 1,1,1
FILL CIRCLE ball_size, ball_size SIZE ball_size-1
FILL COLOR 1,0.5,0.5
FILL CIRCLE ball_size, ball_size SIZE ball_size-3
SPRITE END
SPRITE "krug" ORDER 100

SPRITE "krug" COPY "lifes"
SPRITE "lifes" AT w-(bl_w), 20
SPRITE "lifes" SHOW


SPRITE "lifes_spent" BEGIN bl_w*2-(ball_size*2), 20
SPRITE END
SPRITE "lifes_spent" AT w-(bl_w)+(ball_size*2), 20
SPRITE "lifes_spent" SHOW

SPRITE "pol" BEGIN w,10
FILL COLOR 1,0,0
FILL RECT 0,0 TO w,10
SPRITE END

SPRITE "fg" BEGIN w,h
FILL COLOR 0,0,0
FILL RECT 0,0 TO w,h
SPRITE END
SPRITE "fg" ALPHA 0.5

SPRITE "pol" AT 0,h-10
SPRITE "pol" SHOW
SPRITE "krug" DELAY 0.005
SPRITE "score" SHOW

SPRITE "krug" DELAY 0.0015

restart:
level_number=1
bl=0
speed=2
life=3
s=0
score(s)
lifes(life)
TIME RESET

FOR i=1 TO 20
IF LABEL_EXISTS(STR$(i))=0 THEN BREAK
level_max=i
NEXT i

level_init:
IF level_number>1 THEN s+=(100-INT(TIMER()/1000))*10
IF level_number>level_max THEN restart
OPTION SPRITE POS NORMAL
REFRESH OFF
block_count=0
bl_max=0
bl=0
cells=0
speed+=0.2
score(s)
began=0

ON level_number RESTORE TO 1,2,3

DIM level(8,8)
FOR i=0 TO 7 'строка
FOR j=0 TO 7 'столбец
READ level(i,j)
IF level(i,j)=9 THEN !i=7!j=7!ENDIF
IF level(i,j)>0 THEN block_count+=1
IF level(i,j)=1 THEN bl_max+=1
NEXT j
NEXT i

DIM white_blocks(block_count*10)

DEF block_init(n,y,r,g,b)
SPRITE n BEGIN .bl_w,y
FILL COLOR r,g,b
FILL RECT 0,0 TO .bl_w-2,y-2
FILL COLOR r-0.1,g-0.1,b-0.1
FILL RECT 0,y*0.5-1 TO .bl_w-3,3
DRAW COLOR 0.3,0.3,0.3
DRAW RECT 0,0 TO .bl_w-1,y-1
SPRITE END
ENDDEF


!r=RND(1.0)!g=RND(1.0)!b=RND(1.0)
n=1
FOR i=0 TO 7
FOR j=0 TO 7
block_pos=bl_w+bl_w*j
IF level(i,j)<>0 AND level(i,j)<>9 THEN
IF level(i,j)=1 THEN block_init(n,45,r,g,b)
IF level(i,j)=2 THEN ! block_init(n,45,1,1,1) !white_blocks(n)=n !ENDIF
SPRITE n AT block_pos+((ball_size*2+1)*j), 100+block_init.y*i+((ball_size*2+1)*i)
SPRITE n SHOW
n+=1
ENDIF
NEXT j
r+=0.1 !g+=0.1!b-=0.1
NEXT i

1
data 0,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1
data 9

2
data 1,1,1,0,0,1,1,1
data 0,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1
data 1,1,1,0,0,1,1,1
data 9

3
data 0,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,0
data 1,2,2,1,1,2,2,1
Data 9

REFRESH ON

START:

OPTION SPRITE POS CENTRAL
SPRITE "kvadrat" AT w/2,h-40
SPRITE "krug" AT w/2, h-60
SPRITE "krug" SHOW
SPRITE "kvadrat" SHOW
RANDOMIZE
r=RND(1.0)
sdx=-0.25
sdy=-(1-ABS(sdx))
GET SPRITE "krug" POS kr_x,kr_y
t=0
IF TOUCH_X(0)>-1 THEN GOTO LOOP
GOTO START

LOOP:

GET SPRITE "kvadrat" POS kv_x,kv_y
GET SPRITE "krug" POS kr_x,kr_y
SPRITE "krug" AT sdx*speed+kr_x,sdy*speed+kr_y

IF kr_x-ball_size<=1 THEN ! sdx=ABS(sdx) ! SPRITE "krug" AT kr_x+(ball_size),kr_y ! wh=-1 !ENDIF 'слева
IF kr_x+ball_size>=w-1 AND sdx>0 THEN ! sdx=-sdx ! SPRITE "krug" AT kr_x-(ball_size),kr_y ! wh=-1 !ENDIF' справа
IF kr_y-ball_size<=1 AND sdy<0 THEN ! sdy=ABS(sdy) ! SPRITE "krug" AT kr_x,kr_y+(ball_size) !wh=-1 ! ENDIF
IF kr_y+20>=h THEN
life-=1!
IF life>=0 THEN ! lifes(life) ! PAUSE 2 ! GOTO START ! ELSE ! GOTO lose ! ENDIF
ENDIF


GET TOUCH 0 AS x,y
IF x>-1 THEN
IF t=0 THEN
x1=TOUCH_X(0)
GET SPRITE "kvadrat" POS kv_x1,kv_y1
ENDIF
delta=x-x1
IF kv_x1+(bat_wid/2)+delta>=w THEN
SPRITE "kvadrat" AT w-(bat_wid/2),kv_y1
ELSE
IF kv_x1-(bat_wid/2)+delta<=0 THEN
SPRITE "kvadrat" AT bat_wid/2,kv_y1
ELSE
SPRITE "kvadrat" AT kv_x1+delta,h-40
ENDIF ! ENDIF
t=1
ELSE
t=0
ENDIF

GET SPRITE "krug" POS kr_x,kr_y
GET SPRITE "kvadrat" POS kv_x,kv_y
IF kr_x+ball_size>=kv_x-bat_wid/2 AND kr_x-ball_size<=kv_x+bat_wid/2 AND kr_y+ball_size>=h-50 THEN
bat_wid_f=bat_wid+(ball_size*2)
point=bat_wid_f/2/6
IF kv_x>kr_x THEN ' если коллизия слева
LEFT = kv_x-(bat_wid_f/2)
left1 = LEFT+point
FOR i=1 TO 6
IF kr_x>=LEFT AND kr_x<left1 THEN sdx=(-0.6)+(i/10)
LEFT=LEFT+point
left1=left1+point
NEXT i
ENDIF

IF kv_x<kr_x THEN 'если коллизия справа
RIGHT=kv_x
right1=RIGHT+point
FOR i=1 TO 6
IF kr_x>=RIGHT AND kr_x<right1 THEN sdx=i/10-0.1
RIGHT=RIGHT+point
right1=right1+point
NEXT i
ENDIF
sdy=-(1-ABS(sdx))
SPRITE "krug" AT kr_x+(sdx*speed),kr_y+(sdy*speed)
k=0
wh=-1
ENDIF


FOR i=1 TO block_count

GET SPRITE i POS bl_x, bl_y
GET SPRITE "krug" POS kr_x, kr_y
bl_top=bl_y
bl_bottom=bl_y+block_init.y
bl_left=bl_x
bl_right=bl_x+bl_w
ball_top=kr_y-ball_size
ball_bottom=kr_y+ball_size
ball_left=kr_x-ball_size
ball_right=kr_x+ball_size

IF ball_right>=bl_left AND ball_left<=bl_right AND ball_top<=bl_bottom AND ball_bottom>=bl_top AND SPRITE_VISIBLE(STR$(i)) THEN

IF i<>white_blocks(i) THEN
bl+=1
s+=100
score(s)
SPRITE i HIDE
wh=0
ELSE
wh=1
ENDIF

IF kr_y>=bl_top AND kr_y<=bl_bottom THEN
sdx=-sdx
IF wh=1 THEN
wh=0
vonx=MIN(ABS(bl_right-ball_left),ABS(bl_left-ball_right))
IF sdx>0 THEN
SPRITE "krug" AT kr_x+vonx+(sdx*speed),kr_y+(sdy*speed)
ELSE
SPRITE "krug" AT kr_x-vonx+(sdx*speed),kr_y+(sdy*speed)
ENDIF
ENDIF
ELSE
sdy=-sdy
IF wh=1 THEN
wh=0
vony=MIN(ABS(bl_bottom-ball_top),ABS(bl_top-ball_bottom))
IF sdy>0 THEN
SPRITE "krug" AT kr_x+(sdx*speed),kr_y+vony+(sdy*speed)
ELSE
SPRITE "krug" AT kr_x+(sdx*speed),kr_y-vony+(sdy*speed)
ENDIF
ENDIF
ENDIF

IF bl=bl_max THEN ! level_number+=1 ! GOTO level_init! ENDIF
GOTO LOOP
ENDIF
NEXT i

GOTO LOOP

lose:
SPRITE "fg" SHOW
IF l<>1 THEN
SPRITE "lose" BEGIN bl_w*6, bl_w*6
SHADOW ON
DRAW FONT SIZE 70
DRAW TEXT "YOU LOSE" AT 0,bl_w
DRAW FONT SIZE 40!DRAW TEXT "Ваш счёт: "&s AT 0,bl_w+70
DRAW FONT SIZE 20
SPRITE END
SPRITE "lose" AT w/2,h/2
SPRITE "lose" SHOW
l=1
ENDIF
IF TOUCH_X(2)>-1 THEN ! SPRITE "fg" HIDE!SPRITE "lose" HIDE! l=0!
SPRITE "lose" BEGIN!GRAPHICS CLEAR!SPRITE "lose" END
GOTO restart! ENDIF
GOTO lose
Last edited by Frez on Wed Apr 15, 2015 1:46 pm, edited 4 times in total.

User avatar
Mr. Kibernetik
Site Admin
Posts: 4610
Joined: Mon Nov 19, 2012 10:16 pm
My devices: iPad, iPhone, MacBook
Location: Russia
Flag: Russia

Re: Ping Pong

Post by Mr. Kibernetik » Wed Apr 15, 2015 7:11 am

Интересная программа.
Но я не думаю, что коллизию спрайтов стоит использовать для анализа столкновения с блоками.
Потому что коллизия спрайтов - это очень ресурсоемкий процесс, который включает в себя попиксельный анализ на перекрытие двух спрайтов.
Может быть анализ на попадание шарика в прямоугольники блоков будет работать быстрее.

Frez
Posts: 23
Joined: Fri Apr 03, 2015 4:49 am
My devices: iPad mini

Re: Ping Pong

Post by Frez » Wed Apr 15, 2015 7:32 am

Mr. Kibernetik wrote:Интересная программа.
Но я не думаю, что коллизию спрайтов стоит использовать для анализа столкновения с блоками.
Потому что коллизия спрайтов - это очень ресурсоемкий процесс, который включает в себя попиксельный анализ на перекрытие двух спрайтов.
Может быть анализ на попадание шарика в прямоугольники блоков будет работать быстрее.
А малое значение sprite delay может вызывать такие проблемы? У меня оно составляет всего 0.0015.
Обойтись без коллизий пытался, и везде куда дотянулся обошелся другими средствами. С блоками пока по-другому не получается, буду думать. :)

User avatar
Mr. Kibernetik
Site Admin
Posts: 4610
Joined: Mon Nov 19, 2012 10:16 pm
My devices: iPad, iPhone, MacBook
Location: Russia
Flag: Russia

Re: Ping Pong

Post by Mr. Kibernetik » Wed Apr 15, 2015 7:37 am

Если вы знакомы с анимацией, то DELAY в данном случае - это частота кадров анимации спрайта.
В принципе fps 25 считается нормой чтобы не было явного моргания. Это соответствует DELAY 1/25.

Можете прикинуть, что сейчас вы анимируете спрайт 666 раз в секунду. Глаз столько не различает, а вот CPU - напрягается.

Соответственно при уменьшении частоты кадров величину покадрового смещения спрайта будет нужно увеличить (конечно пока он не проскакивает препятствие за один кадр).

User avatar
Mr. Kibernetik
Site Admin
Posts: 4610
Joined: Mon Nov 19, 2012 10:16 pm
My devices: iPad, iPhone, MacBook
Location: Russia
Flag: Russia

Re: Ping Pong

Post by Mr. Kibernetik » Wed Apr 15, 2015 7:45 am

Классическое название этой игры - арканоид.

User avatar
Фант
Posts: 1358
Joined: Sat Nov 30, 2013 10:01 am
My devices: iPad 4 (iOS 9.3), iMac (MAC OS 11.03)
Location: Россия,Санкт-Петербург
Flag: Russia
Contact:

Re: Ping Pong

Post by Фант » Wed Apr 15, 2015 8:09 am

Привет! Я скажу что отличная программа! Классический арканоид. На айпад 4 все работает великолепно. Добавить выпадающие бонусы, добавить звук-будет готовый продукт.

Frez
Posts: 23
Joined: Fri Apr 03, 2015 4:49 am
My devices: iPad mini

Re: Ping Pong

Post by Frez » Wed Apr 15, 2015 8:31 am

Mr. Kibernetik wrote:Если вы знакомы с анимацией, то DELAY в данном случае - это частота кадров анимации спрайта.
В принципе fps 25 считается нормой чтобы не было явного моргания. Это соответствует DELAY 1/25.

Можете прикинуть, что сейчас вы анимируете спрайт 666 раз в секунду. Глаз столько не различает, а вот CPU - напрягается.

Соответственно при уменьшении частоты кадров величину покадрового смещения спрайта будет нужно увеличить (конечно пока он не проскакивает препятствие за один кадр).
В том-то и дело, что если существенно увеличить задержку, интервал смещения по вектору придется выставить слишком большой - оно приводит к регулярным косякам, взаимодействие спрайтов то и дело обрабатывается некорректно.

Арканоид, точно :)

Frez
Posts: 23
Joined: Fri Apr 03, 2015 4:49 am
My devices: iPad mini

Re: Ping Pong

Post by Frez » Wed Apr 15, 2015 8:34 am

Фант wrote:Привет! Я скажу что отличная программа! Классический арканоид. На айпад 4 все работает великолепно. Добавить выпадающие бонусы, добавить звук-будет готовый продукт.
Спасибо за оценку и тестирование :) Разнообразие блоков и звуки в планах на будущее, наряду с таблицей рекордов и вменяемыми pop-up окнами победы и поражения.

User avatar
Фант
Posts: 1358
Joined: Sat Nov 30, 2013 10:01 am
My devices: iPad 4 (iOS 9.3), iMac (MAC OS 11.03)
Location: Россия,Санкт-Петербург
Flag: Russia
Contact:

Re: Ping Pong

Post by Фант » Wed Apr 15, 2015 8:55 am

Планка и мячик двигаются отлично-все работает четко. Мячик с блоками тоже работает как надо. Думаю есть шероховатости при пропуске мяча. Как то не внятно работает этот момент.

Frez
Posts: 23
Joined: Fri Apr 03, 2015 4:49 am
My devices: iPad mini

Re: Ping Pong

Post by Frez » Wed Apr 15, 2015 9:04 am

Фант wrote:Думаю есть шероховатости при пропуске мяча. Как то не внятно работает этот момент.
По задумке при пропуске мяча, то есть когда он достигает пола, игра ставится на 2-секундную паузу, а затем и доска, и мяч возвращаются в центр по своей оси X. На моем устройстве это работает именно так, а у вас как?

Post Reply