2018/11/14(水) [n年前の日記]
#1 [tic80] TIC-80でシューティングゲームっぽいものを書いてみようかなと
せっかくだからTIC-80上で横スクロールシューティングっぽいものを書いてみようかなと。環境は、Windows10 x64 + TIC-80 0.70.6。
◎ 自機の移動。 :
まずは、自機の移動処理。カーソルキーでスプライトを動かすあたりを書いてみる。ついでに、後々のことも考えて、Playerクラスを作って分離してみる。
TIC-80上で new と打てば Hello world相当がロードされた状態になるので、F1キーを押してエディタを表示してソースを眺めれば、カーソルキーの入力や、スプライト描画のやり方はすぐわかるのだけど…。
8方向に動かす際には、斜め移動の距離について、ちょっと注意しないといけない。詳しくは以下を参考に…。
_アナログ入力の斜め補正
_第5回 キー入力によってキャラクタを8方向へ動かす | TAKABO SOFT
_斜めに移動させる | ゲームプログラミング入門〜bituse〜
とりあえず今回は、斜め移動の時だけ、math.cos(math.rad(45)) を掛けた値を自機の移動量にしてみたり。
ちなみに以下の行は、画面外に自機が出ていかないようにしている。
-- title: stg sample 1 -- author: mieki256 -- desc: short description -- script: lua scrw,scrh=240,136 -- ---------------------------------------- -- Player class Player={} Player.new=function() local o={ alive=true, x=scrw/2, y=scrh/2, sprid=5 } setmetatable(o,{__index=Player}) return o end Player.update=function(self) local spd=2.0 local dx,dy=0,0 if btn(0) then dy=-spd end if btn(1) then dy=spd end if btn(2) then dx=-spd end if btn(3) then dx=spd end if dx~=0 and dy~=0 then local d=math.cos(math.rad(45)) dx=dx*d dy=dy*d end self.x=self.x+dx self.y=self.y+dy self.x=math.min(math.max(self.x,8),scrw-8) self.y=math.min(math.max(self.y,8),scrh-8) end Player.draw=function(self) local x,y=self.x-8,self.y-8 spr(self.sprid,x,y,14,1,0,0,2,2) end -- init score=0 t=0 player=Player.new() -- main loop function TIC() player:update() cls(0) player:draw() print("SCORE: "..score,2,2) t=t+1 end
TIC-80上で new と打てば Hello world相当がロードされた状態になるので、F1キーを押してエディタを表示してソースを眺めれば、カーソルキーの入力や、スプライト描画のやり方はすぐわかるのだけど…。
8方向に動かす際には、斜め移動の距離について、ちょっと注意しないといけない。詳しくは以下を参考に…。
_アナログ入力の斜め補正
_第5回 キー入力によってキャラクタを8方向へ動かす | TAKABO SOFT
_斜めに移動させる | ゲームプログラミング入門〜bituse〜
とりあえず今回は、斜め移動の時だけ、math.cos(math.rad(45)) を掛けた値を自機の移動量にしてみたり。
if dx~=0 and dy~=0 then local d=math.cos(math.rad(45)) dx=dx*d dy=dy*d end
ちなみに以下の行は、画面外に自機が出ていかないようにしている。
self.x=math.min(math.max(self.x,8),scrw-8) self.y=math.min(math.max(self.y,8),scrh-8)math.min(v1, v2) は最小値、math.max(v1, v2) は最大値を取得できる。 _Lua言語のライブラリ関数 の、 _math.min 、 _math.max が参考になる、かなと。
◎ 弾を撃つ。 :
自機から弾を撃ってみる。弾を担当する Bulletクラスを作って、一定時間毎に発生させる。
Bulletクラスの他にも、複数のオブジェクトを処理する関数、objsUpdate()、objsDraw()、objsRemove() を書いた。また、プレイヤーの更新処理(update())の中で、一定時間毎に弾を発生させる処理を追加した。
弾は、初期座標、速度、角度(方向)を与えて発生させている。弾は、その方向にまっすぐ進んで、画面外に出たら自分の存在フラグ(?)を false にする。後で、objsRemove() が、存在フラグが false になってるインスタンスを探して削除してくれる。
-- title: stg sample 2 -- author: mieki256 -- desc: short description -- script: lua scrw,scrh=240,136 -- --------------------------------------- -- Player class Player={} Player.new=function() local o={ alive=true, x=scrw/2, y=scrh/2, sprid=5 } setmetatable(o,{__index=Player}) return o end Player.update=function(self) local spd=2.0 local dx,dy=0,0 if btn(0) then dy=-spd end if btn(1) then dy=spd end if btn(2) then dx=-spd end if btn(3) then dx=spd end if dx~=0 and dy~=0 then local d=math.cos(math.rad(45)) dx=dx*d dy=dy*d end self.x=self.x+dx self.y=self.y+dy self.x=math.min(math.max(self.x,8),scrw-8) self.y=math.min(math.max(self.y,8),scrh-8) -- shot if t%6==0 then local x,y=self.x,self.y spd=6 table.insert(bullets,Bullet.new(x,y,spd,0)) table.insert(bullets,Bullet.new(x,y,spd,12)) table.insert(bullets,Bullet.new(x,y,spd,-12)) table.insert(bullets,Bullet.new(x,y,spd,180)) end end Player.draw=function(self) local x,y=self.x-8,self.y-8 spr(self.sprid,x,y,14,1,0,0,2,2) end -- --------------------------------------- -- Bullet class Bullet={} Bullet.new=function(_x,_y,_spd,_ang) local o={ alive=true, x=_x,y=_y,spd=_spd,ang=_ang, sprid=7 } local ra=math.rad(_ang) o.dx=_spd*math.cos(ra) o.dy=_spd*math.sin(ra) setmetatable(o,{__index=Bullet}) return o end Bullet.update=function(self) self.x=self.x+self.dx self.y=self.y+self.dy if self.x<-16 or self.x>scrw+16 or self.y<-16 or self.y>scrh+16 then self.alive=false end end Bullet.draw=function(self) local x,y=self.x-4,self.y-4 spr(self.sprid,x,y,0,1,0,0,1,1) end -- ---------------------------------------- function objsUpdate(objs) for i,o in ipairs(objs) do o:update() end end function objsDraw(objs) for i,o in ipairs(objs) do o:draw() end end function objsRemove(objs) local l=#objs for i=l,1,-1 do if not objs[i].alive then table.remove(objs,i) end end end -- init score=0 t=0 player=Player.new() bullets={} -- main loop function TIC() player:update() objsUpdate(bullets) objsRemove(bullets) cls(0) objsDraw(bullets) player:draw() print("SCORE: "..score,2,2) print("bullets: "..#bullets,120,2) t=t+1 end
Bulletクラスの他にも、複数のオブジェクトを処理する関数、objsUpdate()、objsDraw()、objsRemove() を書いた。また、プレイヤーの更新処理(update())の中で、一定時間毎に弾を発生させる処理を追加した。
弾は、初期座標、速度、角度(方向)を与えて発生させている。弾は、その方向にまっすぐ進んで、画面外に出たら自分の存在フラグ(?)を false にする。後で、objsRemove() が、存在フラグが false になってるインスタンスを探して削除してくれる。
◎ 雑魚敵を出す。 :
雑魚敵を出してみる。Zakoクラスを作って、これまた一定時間毎に出してみる。とりあえず、弾と同様に、まっすぐ進むだけの処理を書いておいた。
さて、弾を撃って、雑魚敵も出せたから、アタリ判定を入れたくなるなと…。
とりあえず、今日はここまで。ブラウザ上で動く版は以下。
_stgsample3.tic.html
-- title: stg sample 3 -- author: mieki256 -- desc: short description -- script: lua scrw,scrh=240,136 -- -------------------- -- Player class Player={} Player.new=function() local o={ alive=true, x=scrw/2, y=scrh/2, sprid=5 } setmetatable(o,{__index=Player}) return o end Player.update=function(self) local spd=2.0 local dx,dy=0,0 if btn(0) then dy=-spd end if btn(1) then dy=spd end if btn(2) then dx=-spd end if btn(3) then dx=spd end if dx~=0 and dy~=0 then local d=math.cos(math.rad(45)) dx=dx*d dy=dy*d end self.x=self.x+dx self.y=self.y+dy self.x=math.min(math.max(self.x,8),scrw-8) self.y=math.min(math.max(self.y,8),scrh-8) -- shot if t%6==0 then local o local x,y=self.x,self.y spd=6 table.insert(bullets,Bullet.new(x,y,spd,0)) -- table.insert(bullets,Bullet.new(x,y,spd,12)) -- table.insert(bullets,Bullet.new(x,y,spd,-12)) -- table.insert(bullets,Bullet.new(x,y,spd,180)) end end Player.draw=function(self) local x,y=self.x-8,self.y-8 spr(self.sprid,x,y,14,1,0,0,2,2) end -- -------------------- -- Bullet class Bullet={} Bullet.new=function(_x,_y,_spd,_ang) local o={ alive=true, x=_x,y=_y,spd=_spd,ang=_ang, sprid=7 } local ra=math.rad(_ang) o.dx=_spd*math.cos(ra) o.dy=_spd*math.sin(ra) setmetatable(o,{__index=Bullet}) return o end Bullet.update=function(self) self.x=self.x+self.dx self.y=self.y+self.dy if self.x<-16 or self.x>scrw+16 or self.y<-16 or self.y>scrh+16 then self.alive=false end end Bullet.draw=function(self) local x,y=self.x-4,self.y-4 spr(self.sprid,x,y,0,1,0,0,1,1) end -- -------------------- -- Zako enemy class Zako={} Zako.new=function(_x,_y,_spd,_ang) local o={ alive=true,x=_x,y=_y, spd=_spd,ang=_ang, sprid=1,t=0 } local ra=math.rad(_ang) o.dx=_spd*math.cos(ra) o.dy=_spd*math.sin(ra) setmetatable(o,{__index=Zako}) return o end Zako.update=function(self) self.x=self.x+self.dx self.y=self.y+self.dy self.t=self.t+1 if self.x<-32 or self.x>scrw+32 or self.y<-32 or self.y>scrh+32 then self.alive=false end end Zako.draw=function(self) local x,y=self.x-8,self.y-8 spr(self.sprid,x,y,14,1,0,0,2,2) end -- -------------------- function objsUpdate(objs) for i,o in ipairs(objs) do o:update() end end function objsDraw(objs) for i,o in ipairs(objs) do o:draw() end end function objsRemove(objs) local l=#objs for i=l,1,-1 do if not objs[i].alive then table.remove(objs,i) end end end function bornEnemys() if t%50==0 then for i=1,3 do local o,spd,ang,x,y spd=1.5 x=scrw+16 y=math.random(8,scrh-8) ang=180+25*((y-(scrh/2))/(scrh/2)) o=Zako.new(x,y,spd,ang) table.insert(enemys,o) end end end -- init score=0 t=0 player=Player.new() bullets={} enemys={} -- main loop function TIC() bornEnemys() player:update() objsUpdate(bullets) objsUpdate(enemys) objsRemove(bullets) objsRemove(enemys) cls(0) objsDraw(enemys) objsDraw(bullets) player:draw() print("SCORE: "..score,2,2) print("enemys: "..#enemys,120,2) t=t+1 end
さて、弾を撃って、雑魚敵も出せたから、アタリ判定を入れたくなるなと…。
とりあえず、今日はここまで。ブラウザ上で動く版は以下。
_stgsample3.tic.html
[ ツッコむ ]
以上、1 日分です。