mieki256's diary



2018/11/14(水) [n年前の日記]

#1 [tic80] TIC-80でシューティングゲームっぽいものを書いてみようかなと

せっかくだからTIC-80上で横スクロールシューティングっぽいものを書いてみようかなと。環境は、Windows10 x64 + TIC-80 0.70.6。

自機の移動。 :

まずは、自機の移動処理。カーソルキーでスプライトを動かすあたりを書いてみる。ついでに、後々のことも考えて、Playerクラスを作って分離してみる。

stgsample1_ss1_opt.gif

-- 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クラスを作って、一定時間毎に発生させる。

stgsample2_ss1_opt.gif

-- 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_ss1_opt.gif

-- 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

以上です。

過去ログ表示

Prev - 2018/11 - Next
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project