2018/11/13(火) [n年前の日記]
#1 [tic80] TIC-80でゲームっぽい何かを書いてみた
_TIC-80
を触り始めたことだし、せっかくだからゲームっぽい何かを書いてみようかなと。
しかし何を書こうか…。と悩んだところで、ふと、昔の _「るびま(Rubyist Magazine)」 で公開されていた、Ruby/SDL のサンプルゲームっぽいものを書いてみたらどうだろうと思いついたわけで。上から林檎 or 爆弾が落ちてくるので、プレイヤーキャラを操作して林檎だけキャッチする、というゲーム内容。
_Ruby/SDLで始めるゲームプログラミング【前編】
_Ruby/SDL で始めるゲームプログラミング【後編】
てなわけで、TIC-80上でも書いてみました。環境は、Windows10 x64 + TIC-80 0.70.6。
ブラウザ上で動かせます。以下をクリックすれば動くかなと。(音が出ます。)
_newtototone.tic.html
画像やソースを見たいときは、ブラウザ上で動かしてる状態でESCキーを押すとメニューが出てくるので、「CLOSE GAME」を選んでZキー(Aボタン)。その後、F1 〜 F5キーを叩けば、ソースや画像が見れるはず。
余談だけど。ローカルのTIC-80で動かした場合と、ブラウザ上で動かした場合で、疑似乱数の出方が違うようだなと…。ローカルで動くLuaと、ブラウザ上で動くJavaScriptは、疑似乱数の処理がそれぞれ違うのかもしれない…。
一応 .tic(TIC-80のファイル形式)も、 zip にして置いときます。
_newtototone_20181113.zip
しかし何を書こうか…。と悩んだところで、ふと、昔の _「るびま(Rubyist Magazine)」 で公開されていた、Ruby/SDL のサンプルゲームっぽいものを書いてみたらどうだろうと思いついたわけで。上から林檎 or 爆弾が落ちてくるので、プレイヤーキャラを操作して林檎だけキャッチする、というゲーム内容。
_Ruby/SDLで始めるゲームプログラミング【前編】
_Ruby/SDL で始めるゲームプログラミング【後編】
てなわけで、TIC-80上でも書いてみました。環境は、Windows10 x64 + TIC-80 0.70.6。
ブラウザ上で動かせます。以下をクリックすれば動くかなと。(音が出ます。)
_newtototone.tic.html
画像やソースを見たいときは、ブラウザ上で動かしてる状態でESCキーを押すとメニューが出てくるので、「CLOSE GAME」を選んでZキー(Aボタン)。その後、F1 〜 F5キーを叩けば、ソースや画像が見れるはず。
余談だけど。ローカルのTIC-80で動かした場合と、ブラウザ上で動かした場合で、疑似乱数の出方が違うようだなと…。ローカルで動くLuaと、ブラウザ上で動くJavaScriptは、疑似乱数の処理がそれぞれ違うのかもしれない…。
一応 .tic(TIC-80のファイル形式)も、 zip にして置いときます。
_newtototone_20181113.zip
◎ ソース。 :
一応ソースも貼り付けておくのです。
ちなみに、Lua はまだ全然勉強中なので、本来ならクラスの継承を使うべきところで使ってなかったり。精進します。
-- title: NEWTOTOTONE -- author: mieki256 -- desc: It's a game to catch an apple. -- script: lua scrw,scrh=240,136 Player={} Player.new=function() local obj={ alive=true,flip=0, x=scrw/2,y=scrh-32+8 } setmetatable(obj,{__index=Player}) return obj end Player.init=function(self) self.alive=true self.x=scrw/2 self.y=scrh-32+8 self.flip=0 end Player.update=function(self) if not self.alive then return end local spd=2 if btn(2) then self.x=self.x-spd self.flip=0 end if btn(3) then self.x=self.x+spd self.flip=1 end if self.x <= 8 then self.x=8 end if self.x >= scrw-8 then self.x=scrw-8 end end Player.draw=function(self) local id if self.alive then id=1+t%60//30*2 else id=9 self.flip=t%20//10 end local x,y=self.x-8,self.y-8 spr(id,x,y,14,1,self.flip,0,2,2) end Item={} Item.new=function(_x,_y,_kind) local obj={ alive=true, x=_x,y=_y,dx=0,dy=0, hit=false,kind=_kind, sprid=5 } if _kind==1 then obj.sprid=7 end setmetatable(obj,{__index=Item}) return obj end Item.update=function(self) self.x=self.x+self.dx self.y=self.y+self.dy self.dy=self.dy+0.3*9.8/60.0 if self.y >= scrh then self.y=-16 self.dy=0 self.alive=false end if self.hit then if self.kind==0 then score=score+10 bornInfo(self.x,self.y,10) end self.alive=false end end Item.draw=function(self) if self.alive then spr(self.sprid,self.x-8,self.y-8, 14,1,0,0,2,2) end end Info={} Info.new=function(_x,_y,_str) local obj={ alive=true, x=_x,y=_y,str=_str,timer=0 } setmetatable(obj,{__index=Info}) return obj end Info.update=function(self) self.y=self.y-0.5 self.timer=self.timer+1 if self.timer>30 then self.alive=false end end Info.draw=function(self) print(self.str,self.x+1,self.y+1,0) print(self.str,self.x,self.y,15) end function bornInfo(_x,_y,_score) local info=Info.new(_x,_y-16,"+".._score) table.insert(infos,info) end function hitcheck(p,objs) for i,spr in ipairs(objs) do local dx,dy,dist dx=math.abs(spr.x-p.x) dy=math.abs(spr.y-p.y) if spr.kind==0 then if dx<=8 and dy<=8 then spr.hit=true sfx(1, "C-5") end elseif spr.kind==1 then if (dx*dx+dy*dy)<(8*8) then spr.hit=true p.alive=false end end end end function updateSprites(objs) for i,spr in ipairs(objs) do spr:update() end end function removeSprites(objs) local elen=#objs for i=elen,1,-1 do if not objs[i].alive then table.remove(objs,i) end end end function drawSprites(objs) for i,spr in ipairs(objs) do spr:draw() end end function printCt(_s,_y,_scale) local w=print(_s,0,-6) local x=(scrw-(w*_scale))//2 local a=_scale print(_s,x+a,_y+a,0,false,_scale) print(_s,x,_y,15,false,_scale) end score=0 hiscore=0 gmstep=0 t=0 brate=100 player=Player.new() items={} infos={} PALADDR=0x3FC0+14*3 R1,G1,B1=0x59,0x7D,0xCE R2,G2,B2=0x6D,0xC2,0xCA function SCN(row) -- sky gradient local d,hh,h hh=scrh-8*4 h=hh*0.75 if row<h then d=0 elseif row>hh then d=1 else d=(row-h)/(hh-h) end poke(PALADDR,R1+(R2-R1)*d) poke(PALADDR+1,G1+(G2-G1)*d) poke(PALADDR+2,B1+(B2-B1)*d) end function TIC() if gmstep==0 then -- title if btnp(0) then gmstep=1 score=0 brate=100 music(0) math.randomseed(0) end elseif gmstep==1 then -- game main hitcheck(player,items) player:update() -- born item if t%60==0 then brate=brate-1 if brate<=1 then brate=100 end end if t%8==0 then local ex,b,k,item ex=math.random(8,scrw-8) b=math.max(20,brate) k=(math.random(100)>b) and 1 or 0 item=Item.new(ex,-16,k) table.insert(items,item) end updateSprites(items) updateSprites(infos) removeSprites(items) removeSprites(infos) if score>hiscore then hiscore=score end if not player.alive then gmstep=2 t=0 sfx(2,"C-5") music() -- music stop end elseif gmstep==2 then -- game over if t>=60+30 then player:init() gmstep=0 items={} infos={} end end -- draw cls(14) map(0,0,30,17,0,0,14) player:draw() drawSprites(items) drawSprites(infos) print("SCORE: "..score,4,2) print("HI-SCORE: "..hiscore,120,2) if gmstep==0 then printCt("NEWTOTOTONE",52,2) printCt("MOVE: LEFT,RIGHT KEY",84,1) printCt("PUSH UP KEY TO START",94,1) elseif gmstep==2 then printCt("GAME OVER",54,2) end t=t+1 end
- 〜.new が、クラスのインスタンス発生+初期化処理
- 〜.update が更新処理(1秒間に60回呼ばれる)
- 〜.draw が描画処理
ちなみに、Lua はまだ全然勉強中なので、本来ならクラスの継承を使うべきところで使ってなかったり。精進します。
◎ 宿題。 :
これだけではゲームとして全然面白くないよなと…。プレイしていて、なんだか修行僧になった気分…。
さて、どうすれば、ちょっとは面白くなるのだろうか…。
例えばだけど…。
何にせよ、この段階では「変化」「ご褒美」が無いよなと…。ゲームにおいて「ご褒美」は大事。皆、何かしらの「ご褒美」が欲しくてプレイするわけだから…。
さて、どうすれば、ちょっとは面白くなるのだろうか…。
例えばだけど…。
- 時間制限をつけて、1分以内に何点稼げるかで競う感じにするとか。
- 地面の上に蛇でも出すとか。プレイヤーキャラはジャンプで避けるとか。あるいは弾を撃って蛇を倒すとか。
- フィーバータイムをつけるとか。何かを取ると一定時間、全てが林檎に変化したり。
- ステージを設けるとか。ある程度取るとステージクリア。
- 長くプレイしてると背景が変わってくるとか。徐々に夕焼けになったり、夜空になったり。
何にせよ、この段階では「変化」「ご褒美」が無いよなと…。ゲームにおいて「ご褒美」は大事。皆、何かしらの「ご褒美」が欲しくてプレイするわけだから…。
[ ツッコむ ]
以上です。