Арканоид
Posted: 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
При разработке возникла проблема коллизии спрайтов. Для движения шарика у меня выставлен очень маленький 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