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分以内に何点稼げるかで競う感じにするとか。
- 地面の上に蛇でも出すとか。プレイヤーキャラはジャンプで避けるとか。あるいは弾を撃って蛇を倒すとか。
- フィーバータイムをつけるとか。何かを取ると一定時間、全てが林檎に変化したり。
- ステージを設けるとか。ある程度取るとステージクリア。
- 長くプレイしてると背景が変わってくるとか。徐々に夕焼けになったり、夜空になったり。
何にせよ、この段階では「変化」「ご褒美」が無いよなと…。ゲームにおいて「ご褒美」は大事。皆、何かしらの「ご褒美」が欲しくてプレイするわけだから…。
[ ツッコむ ]
以上です。