当前位置: 首页 > news >正文

制作一款打飞机游戏50:敌人跟随

敌人行为设计

我们希望为敌人设计一些行为,比如冲锋和跟随玩家。这样,主要敌人就可以攻击玩家或与玩家互动。我们还想实现一个循环命令,但我现在还不太确定如何实现它。我会再考虑一下的。

接下来,我们可能会设计BOSS角色。我们已经实现了大脑克隆命令,但我想先从一些基础功能开始,比如追踪功能。

追踪功能的实现

在实现追踪功能时,我们遇到了一个问题:当使用克隆命令时,每个克隆体都会有自己的覆盖层,这让我们有点难以处理。其实,我们只需要一个主敌人,其他的都是它的克隆体。因此,我想实现一个重置敌人的功能,专门用于重置所有敌人的状态。

我们已经有了一个生成敌人的函数,但现在还需要一个重置函数。我们可以在更新大脑(可能是一个游戏循环中的函数)时调用这个重置函数,来重置敌人的状态和追踪轨迹。

追踪轨迹的显示

为了让玩家更清楚地看到敌人的移动轨迹,我们决定实现一个轨迹显示功能。当按下某个键时,就会显示敌人的移动轨迹。我们通过记录敌人每个时间点的位置来实现这一功能,并在屏幕上绘制出来。

玩家交互与敌人AI优化

为了让游戏更加有趣,我们希望敌人能够跟随玩家。但是,如果敌人一直紧贴着玩家,那游戏就太简单了。因此,我们决定当敌人靠近玩家到一定程度时,就停止跟随,而是继续沿着之前的轨迹移动。

为了实现这一点,我们需要计算敌人与玩家之间的距离。当距离小于某个阈值时,就停止跟随。

角度计算与动画

为了让敌人能够平滑地转向玩家,我们需要计算敌人当前角度与目标角度之间的差值,并根据这个差值来调整敌人的角度。但是,在计算角度时,我们遇到了一个度的问题:当角度跨越度时,计算会变得复杂。

为了解决这个问题,我们决定当角度差值的绝对值大于度时,就通过加减度来调整角度,以确保敌人总是选择最短的路径来转向玩家。

pico-8 cartridge // http://www.pico-8.com
version 41
__lua__
--todo-- goal
-- 7 boss-- todo
-- loopfunction _init()--- customize here ---#include shmup_brains.txt#include shmup_brains_meta.txtfile="shmup_brains.txt"filem="shmup_brains_meta.txt"arrname="brains"data=brains#include shmup_myspr.txt#include shmup_enlib.txt#include shmup_anilib.txt----------------------debug={}msg={}_drw=draw_brain_upd=update_brainmenuitem(1,"export",export)reload(0x0,0x0,0x2000,"cowshmup.p8")curx=1cury=1scrolly=0scrollx=0selbrain=1cmdlist={"hed","wai","asp","got","fir","adr","clo","flw"}execy=0scroll=0enemies={}muzz={}overlay=falseshowtrails=falsenewtrails={}curtrails={}pspr={x=64,y=110}poke(0x5f2d, 1)t=0
endfunction _draw()_drw()if #msg>0 thenbgprint(msg[1].txt,64-#msg[1].txt*2,80,14)msg[1].t-=1if msg[1].t<=0 thendeli(msg,1)end  end-- debug --cursor(4,4)color(8)for txt in all(debug) doprint(txt)endendfunction _update60()t+=1dokeys()mscroll=stat(36)scroll+=0.2scroll=scroll%16_upd()
endfunction dokeys()if stat(30) thenkey=stat(31)if key=="p" thenpoke(0x5f30,1)endelsekey=nilendend
-->8
--drawfunction draw_brain()cls(13)if flr(scroll)%2==0 thenfillp(0b0000111100001111.1)elsefillp(0b1111000011110000.1)endfor i=0,7 doline(i*16,0,i*16,128,5)endfillp(▥)for i=-1,7 doline(0,i*16+scroll,128,i*16+scroll,5)endfillp()circ(pspr.x,pspr.y,3,5)for e in all(enemies) dodrawobj(e)if overlay and e==protag thenlocal ox=sin(e.ang)local oy=cos(e.ang)local ox1=e.x+ox*12local oy1=e.y+oy*12pset(e.x,e.y,11)line(ox1,oy1,ox1+ox*8*e.spd,oy1+oy*8*e.spd,11)endend-- temp muzzle flashesfor m in all(muzz) dom.r-=1if m.en thencircfill(m.en.x,m.en.y,m.r,7)endif m.r<=0 thendel(muzz,m)endendif showtrails thenfor t in all(curtrails) dopset(t[1],t[2],11)endenddrawmenu()line(1,execy,1,execy+6,11)
endfunction draw_table()cls(2)--spr(0,0,0,16,16)drawmenu()--[[for i=1,#data dofor j=1,#data[i] dobgprint(data[i][j],2+18*j,2+8*i,7)endend]]
endfunction drawmenu()if menu thenfor i=1,#menu dofor j=1,#menu[i] dolocal mymnu=menu[i][j]local c=mymnu.c or 13if i==cury and j==curx thenc=7if _upd==upd_type thenc=0endendbgprint(mymnu.w,mymnu.x+scrollx,mymnu.y+scrolly,13)   bgprint(mymnu.txt,mymnu.x+scrollx,mymnu.y+scrolly,c) endendendif menui thenfor i=1,#menui dofor j=1,#menui[i] dolocal mymnui=menui[i][j]local c=mymnui.c or 13if i==cury and j==curx thenc=7if _upd==upd_type thenc=0endend bgprint(mymnui.w,mymnui.x+scrollx,mymnui.y+scrolly,13)   bgprint(mymnui.txt,mymnui.x+scrollx,mymnui.y+scrolly,c) endendendif _upd==upd_type thenlocal mymnu=menu[cury][curx]local txt_bef=sub(typetxt,1,typecur-1)local txt_cur=sub(typetxt,typecur,typecur)local txt_aft=sub(typetxt,typecur+1)txt_cur=txt_cur=="" and " " or txt_cur if (time()*2)%1<0.5 thentxt_cur="\^i"..txt_cur.."\^-i"endlocal txt=txt_bef..txt_cur..txt_aftbgprint(txt,mymnu.x+scrollx,mymnu.y+scrolly,7)end
end-->8
--updatefunction update_setup()refresh_setup()if btnp(⬆️) thencury-=1endif btnp(⬇️) thencury+=1endcury=mid(2,cury,#menu)curx=2if btnp(❎) thenlocal mymnu=menu[cury][curx]if mymnu.cmd=="meta" then_upd=upd_typetypetxt=tostr(mymnu.txt)typecur=#typetxt+1callback=enter_metaendendif btnp(🅾️) then_upd=update_brainrefresh_brain()returnendif data[selbrain] thenif #enemies==0 thenlocal selmeta=meta[selbrain]if enlib[selmeta[1]]!=nil thenreseten()end  enddoenemies()  elseenemies={}endendfunction update_brain()refresh_brain()pspr.x=stat(32)pspr.y=stat(33)if key=="1" thenoverlay= not overlayendif key=="2" thenshowtrails= not showtrailsendif btnp(⬆️) thencury-=1endif btnp(⬇️) thencury+=1endcury=mid(1,cury,#menu)if cury==1 thenif btnp(⬅️) thenselbrain-=1enemies={}curtrails={}endif btnp(➡️) thenselbrain+=1enemies={}curtrails={}endselbrain=mid(1,selbrain,#data+1)elseif btnp(⬅️) thencurx-=1endif btnp(➡️) thencurx+=1endcurx=mid(1,curx,#menu[cury])endif btnp(❎) thenlocal mymnu=menu[cury][curx]if mymnu.cmd=="edit" then_upd=upd_typetypetxt=tostr(mymnu.txt)typecur=#typetxt+1callback=enter_brainelseif mymnu.cmd=="newline" thenadd(data[mymnu.cmdb],"wai",mymnu.cmdi)add(data[mymnu.cmdb],0,mymnu.cmdi+1)add(data[mymnu.cmdb],0,mymnu.cmdi+2)cury+=1curx=1elseif mymnu.cmd=="setup" thenrefresh_setup()_upd=update_setupreturnelseif mymnu.cmd=="newbrain" thenadd(data,{"wai",0,0})add(meta,{1,64,10})endreturn endif data[selbrain] thenif #enemies==0 thenlocal selmeta=meta[selbrain]if enlib[selmeta[1]]!=nil thenreseten()endenddoenemies()if protag and t%5==0 thenadd(newtrails,{protag.x,protag.y})endelseenemies={}end
endfunction update_table()refresh_table()if btnp(⬆️) thencury-=1endif btnp(⬇️) thencury+=1endcury=(cury-1)%#menu+1cury-=mscrollcury=mid(1,cury,#menu)if btnp(⬅️) thencurx-=1endif btnp(➡️) thencurx+=1endif cury<#menu thencurx=(curx-2)%(#menu[cury]-1)+2elsecurx=1endlocal mymnu=menu[cury][curx]if mymnu.y+scrolly>110 thenscrolly-=4endif mymnu.y+scrolly<10 thenscrolly+=4endscrolly=min(0,scrolly)if mymnu.x+scrollx>110 thenscrollx-=2endif mymnu.x+scrollx<20 thenscrollx+=2endscrollx=min(0,scrollx)if btnp(❎) thenlocal mymnu=menu[cury][curx]if mymnu.cmd=="edit" then_upd=upd_typetypetxt=tostr(mymnu.txt)typecur=#typetxt+1callback=enter_tableelseif mymnu.cmd=="newline" thenadd(data,{0})  elseif mymnu.cmd=="newcell" thenadd(data[mymnu.cmdy],0)endend
endfunction upd_type()if key thenif key=="\r" then-- enterpoke(0x5f30,1)callback()returnelseif key=="\b" then--backspaceif typecur>1 thenif typecur>#typetxt thentypetxt=sub(typetxt,1,#typetxt-1)elselocal txt_bef=sub(typetxt,1,typecur-2)local txt_aft=sub(typetxt,typecur)typetxt=txt_bef..txt_aftendtypecur-=1endelseif typecur>#typetxt thentypetxt..=keyelselocal txt_bef=sub(typetxt,1,typecur-1)local txt_aft=sub(typetxt,typecur)typetxt=txt_bef..key..txt_aftendtypecur+=1endendif btnp(⬅️) thentypecur-=1endif btnp(➡️) thentypecur+=1endtypecur=mid(1,typecur,#typetxt+1)
end
-->8
--toolsfunction bgprint(txt,x,y,c)print("\#0"..txt,x,y,c)
endfunction split2d(s)local arr=split(s,"|",false)for k, v in pairs(arr) doarr[k] = split(v)endreturn arr
endfunction spacejam(n)local ret=""for i=1,n doret..=" "endreturn ret
endfunction mspr(si,sx,sy)local _x,_y,_w,_h,_ox,_oy,_fx,_nx=unpack(myspr[si])sspr(_x,_y,_w,_h,sx-_ox,sy-_oy,_w,_h,_fx==1)if _fx==2 thensspr(_x,_y,_w,_h,sx-_ox+_w,sy-_oy,_w,_h,true)endif _nx thenmspr(_nx,sx,sy)end
endfunction cyc(age,arr,anis)local anis=anis or 1return arr[(age\anis-1)%#arr+1]
endfunction drawobj(obj)mspr(cyc(obj.age,obj.ani,obj.anis),obj.x,obj.y)--★if coldebug and obj.col thenmsprc(obj.col,obj.x,obj.y)end
endfunction onscreen(obj)if obj.x<-8 then return false endif obj.y<-8 then return false endif obj.x>136 then return false endif obj.y>136 then return false end return true
end
-->8
--i/o
function export()local s=arrname.."=split2d\""for i=1,#data doif i>1 thens..="|"endfor j=1,#data[i] doif j>1 thens..=","ends..=data[i][j]endends..="\""printh(s,file,true)local s="meta=split2d\""for i=1,#meta doif i>1 thens..="|"endfor j=1,#meta[i] doif j>1 thens..=","ends..=meta[i][j]endends..="\""printh(s,filem,true)add(msg,{txt="exported!",t=120})--debug[1]="exported!"
end
-->8
--uifunction refresh_setup()menu={}menui={}add(menu,{{txt="brain "..selbrain,w="        ",cmd="",x=3,y=3,c=13  }})local cap={"en:"," x:"," y:"}local selmeta=meta[selbrain]for i=1,3 dolocal lne={}add(lne,{txt=cap[i],w="  ",cmd="",x=3,y=3+i*6+2,c=13  })add(lne,{txt=selmeta[i],w="   ",cmd="meta",cmdy=i,x=3+12,y=3+i*6+2,c=13  })add(menu,lne)endendfunction refresh_brain()menu={}menui={}execy=-16if selbrain>#data then--empty brain slotadd(menu,{{txt="< new brain ",w="           ",cmd="newbrain",x=3,y=3,c=13  }}) returnendadd(menu,{{txt="< brain "..selbrain.." >",w="            ",cmd="head",x=3,y=3,c=13  }}) add(menu,{{txt="◆setup",w="       ",cmd="setup",x=3,y=3+8,c=13 }})local mybra=brains[selbrain]local ly=19for i=1,#mybra,3 doif enemies[1] thenlocal myen=enemies[1]if myen.brain==selbrain and myen.bri==i thenexecy=ly-9endendlocal lne={}add(lne,{txt=mybra[i],w="   ",cmd="edit",cmdi=i,cmdb=selbrain,x=3,y=ly,c=13    })local lx=3+14 for j=1,2 dolocal mytxt=tostr(mybra[i+j])add(lne,{txt=mytxt,w=spacejam(#mytxt),cmd="edit",cmdi=i+j,cmdb=selbrain,x=lx,y=ly,c=13    })lx+=#mytxt*4+2endif cury==#menu+1 thenadd(lne,{txt="+",w=" ",cmd="newline",cmdi=i+3,cmdb=selbrain,x=lx,y=ly,c=13    })endadd(menu,lne)ly+=8endif menu[cury] thenlocal mymnu=menu[cury][curx]if mymnu and mymnu.cmd=="edit" thenadd(menui,{{txt="i:"..mymnu.cmdi,w="    ",cmd="",x=3,y=120,c=15    }})endend
endfunction refresh_table()menu={}menui={}for i=1,#data dolocal lne={}local linemax=#data[i]if i==cury thenlinemax+=1  endadd(lne,{txt=i,w="   ",cmd="",x=4,y=-4+8*i,c=2  })for j=1,linemax doif j==#data[i]+1 thenadd(lne,{txt="+",w=" ",cmd="newcell",cmdy=i,x=-10+14*(j+1),y=-4+8*i, })elseadd(lne,{txt=data[i][j],cmd="edit",cmdx=j,cmdy=i,x=-10+14*(j+1),y=-4+8*i,w="   "})endendadd(menu,lne)endadd(menu,{{txt=" + ",w="   ",cmd="newline",x=4,y=-4+8*(#data+1), }})
endfunction enter_table()local mymnu=menu[cury][curx]local typeval=typetxtif typeval==nil or typeval=="" thenif mymnu.cmdx==#data[mymnu.cmdy] and typetxt=="" then--delete celldeli(data[mymnu.cmdy],mymnu.cmdx)if mymnu.cmdx==1 thendeli(data,mymnu.cmdy)end_upd=update_tablereturnend  typeval=0end   data[mymnu.cmdy][mymnu.cmdx]=typeval_upd=update_table
endfunction enter_brain()_upd=update_brainlocal mymnu=menu[cury][curx]local typeval=typetxtenemies={}if mymnu.cmdi%3==1 then--editing command entryif typeval=="" thendeli(data[mymnu.cmdb],mymnu.cmdi)deli(data[mymnu.cmdb],mymnu.cmdi)deli(data[mymnu.cmdb],mymnu.cmdi)if #data[mymnu.cmdb]==0 thendeli(data,mymnu.cmdb)deli(meta,mymnu.cmdb)add(msg,{txt="brain deleted!",t=120})endreturnelse local found=false for c in all(cmdlist) doif typeval==c thenfound=trueend endif not found thentypeval="wai"endendelse--editing parameterstypeval=tonum(typetxt)if typeval==nil thentypeval=0endenddata[mymnu.cmdb][mymnu.cmdi]=typevalendfunction enter_meta()_upd=update_setuplocal mymnu=menu[cury][curx]local typeval=tonum(typetxt)enemies={}if typeval==nil thentypeval=0endmeta[selbrain][mymnu.cmdy]=typevalend
-->8
--enemyfunction dobrain(e,depth)--★ remove robustnessif braincheck(e)==false then return endlocal depth=depth or 1if depth>100 thenif #msg>0 thenmsg[1].t=5elseadd(msg,{txt="infinite loop",t=5})endreturnend -- robustness code endlocal mybra=brains[e.brain]local quit=falseif e.bri<#mybra thenlocal cmd=mybra[e.bri]local par1=mybra[e.bri+1]local par2=mybra[e.bri+2]if cmd=="hed" then--set heading / speede.ang=par1e.spd=par2e.aspt=nile.flw=falseelseif cmd=="wai" then--wait x framese.wait=par1e.dist=par2quit=trueelseif cmd=="asp" then--animate speede.aspt=par1e.asps=par2elseif cmd=="adr" then--animate directione.adrt=par1e.adrs=par2e.flw=falseelseif cmd=="got" then--gotoe.brain=par1e.bri=par2-3elseif cmd=="fir" then--firefirebul(e,par1,par2)elseif cmd=="clo" then--clonefor i=1,par1 dolocal myclo=copylist(e)myclo.wait+=i*par2myclo.bri+=3add(enemies,myclo)endelseif cmd=="flw" then--followe.flw=truee.flws=par1--par2??else--★ extra robustnessreturnende.bri+=3if quit then return enddobrain(e,depth+1)end
endfunction doenemies()for e in all(enemies) doif e.wait>0 thene.wait-=1elseif e.dist<=0 thendobrain(e)endif e.flw thenlocal diff=atan2(pspr.y-e.y,pspr.x-e.x)-e.ang   if abs(diff)>0.5 thendiff-=sgn(diff)ende.ang+=mid(-e.flws,diff,e.flws)if dist(pspr.x,pspr.y,e.x,e.y)<25 thene.flw=falseende.ang=e.ang%1endif e.aspt thene.spd+=e.aspsif abs(e.aspt-e.spd)<abs(e.asps) thene.spd=e.aspte.aspt=nilendendif e.adrt thene.ang+=e.adrsif abs(e.adrt-e.ang)<abs(e.adrs) thene.ang=e.adrte.adrt=nilendende.sx=sin(e.ang)*e.spde.sy=cos(e.ang)*e.spde.dist=max(0,e.dist-abs(e.spd))e.x+=e.sxe.y+=e.sye.age+=1if not onscreen(e) thendel(enemies,e)--★ code for editorif e==protag thencurtrails=newtrailsendendend
endfunction reseten()t=0enemies={}local selmeta=meta[selbrain]spawnen(selmeta[1],selmeta[2],selmeta[3])protag=enemies[1]newtrails={}
endfunction spawnen(eni,enx,eny)local en=enlib[eni]add(enemies,{x=enx,y=eny,ani=anilib[en[1]],anis=en[2],sx=0,sy=0,ang=0,spd=0,brain=selbrain,bri=1,age=0,flash=0,hp=en[4],col=en[5],wait=0,dist=0})endfunction braincheck(e)if brains[e.brain]==nil thenif #msg>0 thenmsg[1].t=5elseadd(msg,{txt="bad brain "..e.brain,t=5})endreturn falseendlocal mybra=brains[e.brain]if e.bri<1 thenif #msg>0 thenmsg[1].t=5elseadd(msg,{txt="brain command index < 1",t=5})endreturn falseelseif e.bri<#mybra thenlocal cmd=mybra[e.bri]local found=falsefor c in all(cmdlist) doif c==cmd thenfound=trueendendif found==false thenif #msg>0 thenmsg[1].t=5elseadd(msg,{txt="bad command "..cmd,t=5})endreturn falseendendreturn true
endfunction firebul(_en,par1,par2)add(muzz,{en=_en,r=8})
end--- tools function copylist(org)local ret={}for k, v in pairs(org) doret[k]=vendreturn ret
endfunction dist(x1,y1,x2,y2)local dx,dy=x2-x1,y2-y1return sqrt(dx*dx+dy*dy)
end
__gfx__
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__map__
0000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

相关文章:

  • 2:OpenCV—加载显示图像
  • 中大型水闸安全监测系统建设实施方案
  • 工具生态构建对比分析
  • bili.png
  • Docker 无法拉取镜像解决办法
  • 什么是SMBus
  • Node.js 实战二:接口参数校验与类型安全方案
  • 《指针与整数相加减的深入解析》
  • docker学习与使用(概念、镜像、容器、数据卷、dockerfile等)
  • 14、Python时间表示:Unix时间戳、毫秒微秒精度与time模块实战
  • Android framework 中间件开发(一)
  • LearnOpenGL --- 你好三角形
  • 科达嘉数字功放电感应用于英飞凌参考设计REF_MA5302BTLSPS_400W
  • PYTHON训练营DAY27
  • Mendix 中的XPath 令牌(XPath Tokens)详解
  • Elasticsearch 分词与字段类型(keyword vs. text)面试题
  • 【python】直线型雷达图
  • 东芝第3代SiC MOSFET助于降低应用中电源损耗
  • 今日行情明日机会——20250516
  • RK3588平台GDC鱼眼矫正开发全解析:原理、实践与优化
  • 法律顾问被控配合他人诈骗酒店资产一审判8年,二审辩称无罪
  • 上市公司重大资产重组新规九要点:引入私募“反向挂钩”,压缩审核流程
  • 朝鲜称将在各领域采取反制措施,应对美国敌对挑衅
  • 350种咖啡主题图书集结上海,20家参展书店买书送咖啡
  • 中国青年报:为见义勇为者安排补考,体现了教育的本质目标
  • 株洲一重病妇女被要求本人到银行取款时去世?当地警方:正在处理