プログラミング未経験だけどゲームつくる - 5 : 座標からのダメージ判定と無敵時間【LOVE2d】
セブンイレブンの冷凍食品は企業努力。
どうも、サトウダイスケです。
猫ちゃんのゲームですが、当たり判定となるx座標とy座標を設定することでダメージ判定ができるようになりました。座標が点だとあまりにもぬるいので、x軸は足から足くらい(大雑把なのでこれもどうにかしたい)の幅にし、対象の石ころと重なっているときにy座標が地とイコールか否かで判断することにしました。
取り敢えず長いコードを載せます。
function love.load()
love.graphics.setBackgroundColor( 256, 256, 256 )
love.graphics.setDefaultFilter('nearest', 'nearest')
cat = love.graphics.newImage('images/neko_for_sprite.png')
background = love.graphics.newImage('images/background.png')
cat_walk = love.graphics.newQuad(0, 0, 16, 16, cat:getDimensions())
cat_jump = love.graphics.newQuad(0, 0, 16, 16, cat:getDimensions())
cat_idle = love.graphics.newQuad(0, 0, 16, 16, cat:getDimensions())
cat_now = cat_idle
x = 0
neko_x = window_w-20
speed = 300
dir = 1
right_to_left = 0
scale = 8
chara_w_h = 16
neko_center_x = neko_x+chara_w_h*scale/2+x
zimen_h = window_h/2.8+scale*chara_w_h
neko_center_y = zimen_h
damage = 0
damage_muteki = 0
damage_muteki_time = 2
damage_muteki_time_remaing = damage_muteki_time
walk = {}
walk = {fps=4, num_frames=2, xoffset, timer=1/4 ,frame=1}
jump = {}
jump = {fps=8, num_frames=10, xoffset, timer=1/8 ,frame=1}
local snd
-- フォントや文字の設定
utf8 = require("utf8")
message_font = love.graphics.newFont("k8x12.ttf", 30)
love.graphics.setFont(message_font)
message01 = {"めがさめると、おいしそうなにおいがしたんだ。","なぜかうれしくなって、いっぱいはしってた。"}
message02 = {"このままどこかにいきたい。","どこかとおくにいってしまいたい。"}
message_h = 40 -- 1行の高さ
st = love.timer.getTime() -- 開始時刻を記録
-- 音楽と効果音の設定
snd_jump = love.audio.newSource("sound/jump06.wav", "static")
snd_message = love.audio.newSource("sound/select03.wav", "static")
snd_walk = love.audio.newSource("sound/putting_a_jar.wav", "static")
snd_damage = love.audio.newSource("sound/surprising_girl.wav", "static")
bgm = love.audio.newSource("sound/yuuenchi.wav", "static")
-- 音楽の再生
bgm:play()
bgm:setLooping(true)
end
function love.update(dt)
if dt > 0.035 then return end --処理落ち対策
-- 猫が停止している表現
if cat_now == cat_idle then
cat_idle:setViewport(0, 0, 16, 16)
end
-- 猫が歩いているアニメーション表現
if cat_now == cat_walk then
walk.timer = walk.timer - dt
if walk.timer <= 0 then
walk.timer = 1 / walk.fps
walk.frame = walk.frame + 1
if walk.frame > walk.num_frames then walk.frame = 1 end
walk.xoffset = 16 * walk.frame
cat_walk:setViewport(walk.xoffset-16, 0, 16, 16)
end
end
-- 猫がジャンプしているアニメーション表現
if cat_now == cat_jump then
jump.timer = jump.timer - dt
if jump.timer <= 0 then
jump.timer = 1 / jump.fps
jump.frame = jump.frame + 1
if jump.frame == jump.num_frames-8 then
neko_center_y = neko_center_y - 10
end
if jump.frame == jump.num_frames-4 then
neko_center_y = neko_center_y + 10
end
if jump.frame > jump.num_frames then
jump.frame = 1
cat_now = cat_idle
end
jump.xoffset = 16 * jump.frame
cat_jump:setViewport(jump.xoffset-16, 0, 16, 16)
end
end
-- キー操作による移動の計算
local dx = 0
if love.keyboard.isDown("right") then
dx = speed * dt
if dir == 1 then
dir_switch = "left_to_right"
end
if cat_now ~= cat_jump then
cat_now = cat_walk
love.audio.play(snd_walk)
end
dir = -1
elseif love.keyboard.isDown("left") then
dx = -speed * dt
if dir == -1 then
dir_switch = "right_to_left"
end
if cat_now ~= cat_jump then
cat_now = cat_walk
love.audio.play(snd_walk)
end
dir = 1
else
if cat_now ~= cat_jump then
cat_now = cat_idle
end
end
neko_center_x = neko_center_x + dx
x = x + dx
-- キー操作によるジャンプの計算
if cat_now ~= cat_jump then --ジャンプしてる最中ではないことの確認
if love.keyboard.isDown("space") then
love.audio.stop(snd_jump)
love.audio.play(snd_jump)
cat_now = cat_jump
end
end
-- ダメージを受けた際の計算
if damage_muteki == 0 then
if neko_center_x-chara_w_h*(scale-5)/2 < 200
and
200 < neko_center_x-chara_w_h*(scale-5)/2+chara_w_h*(scale-5)
or
neko_center_x-chara_w_h*(scale-5)/2 < 210
and
210 < neko_center_x-chara_w_h*(scale-5)/2+chara_w_h*(scale-5)
then
if neko_center_y == zimen_h then
damage = damage + 1
damage_muteki = 1
love.audio.play(snd_damage)
damage_muteki_time_remaing = damage_muteki_time
end
end
end
-- ダメージを受けた際の無敵時間の計算
if damage_muteki == 1 then
damage_muteki_time_remaing = damage_muteki_time_remaing - dt
if damage_muteki_time_remaing <= 0 then
damage_muteki = 0
damage_muteki_time_remaing = damage_muteki_time
end
end
end
function love.draw()
-- love.graphics.setColor(255, 255, 255 , 0.4)
-- love.graphics.draw(background,1,-220,0,1,1)
-- 地面の描写
love.graphics.setColor(0, 0, 0 , 255)
love.graphics.rectangle("fill", 0, zimen_h, window_w, window_h)
-- 石ころの描写
love.graphics.rectangle("fill", 200, zimen_h-10, 10, 10)
-- 猫の描写
love.graphics.setColor(255, 255, 255)
if dir_switch == "left_to_right" then
x = x + chara_w_h*scale
elseif dir_switch == "right_to_left" then
x = x - chara_w_h*scale
end
if damage_muteki == 1 then
love.graphics.setColor(255, 255, 255 , 0.5)
love.graphics.draw(cat, cat_now, neko_x+x, window_h/2.8, 0, scale*dir, scale)
else
love.graphics.setColor(255, 255, 255 , 1)
love.graphics.draw(cat, cat_now, neko_x+x, window_h/2.8, 0, scale*dir, scale)
end
dir_switch = 0
-- 当たり判定の位置描写
love.graphics.setColor(255, 0, 0,0.5)
love.graphics.rectangle("fill", neko_center_x-chara_w_h*(scale-5)/2, neko_center_y - 10,chara_w_h*(scale-5) , 10)
-- 猫の座標の描写
love.graphics.setColor(0, 0, 0)
love.graphics.print(window_w-20+x, 10, 10)
-- ダメージ数の描写
love.graphics.setColor(0, 0, 0)
love.graphics.print(damage, 10, 40)
-- 無敵判定か否かの描写
love.graphics.setColor(0, 0, 0)
love.graphics.print(damage_muteki, 10, 70)
-- 文字出しの描写
love.graphics.setColor(255, 255, 255)
message_quantity = (love.timer.getTime() - st) / 0.1 -- 表示する文字数(経過時間÷0.1秒)
message_y = window_h-window_h/3.8 -- 1文字目を表示するy座標
i = 1 -- 何文字目か
for j, s in ipairs(message01) do -- message を順に処理
message_x = math.floor(window_w/14) -- 行の1文字目を表示するx座標(行変わりで初期化)
for pos, code in utf8.codes(s) do
if i > message_quantity then break end -- 表示する文字数を超過していれば終了
local ss = utf8.char(code) -- 文字を1つずつ取り出す
love.graphics.print(ss, message_x, message_y) -- 表示
message_x = message_x + message_font:getWidth(ss) -- 文字の幅だけ右にずらす
i = i + 1 -- 忘れないように!
end
message_y = message_y + message_h -- 行の高さだけ下にずらす
i = i + 5 -- 行ごとに間を置く(10文字ぶん)
end
end
-- command+F5で更新する関数
love.keypressed = function(key, unicode)
if 'up' == key then
love.filesystem.load('main.lua')()
love.load()
love.audio.play(snd_message)
love.audio.stop(bgm)
end
end
相変わらず汚いコードですいません。
来週くらいには少しは綺麗になっている予定...
まず、猫ちゃんの当たり判定ですが、
-- ダメージを受けた際の計算
if damage_muteki == 0 then
if neko_center_x-chara_w_h*(scale-5)/2 < 200
and
200 < neko_center_x-chara_w_h*(scale-5)/2+chara_w_h*(scale-5)
or
neko_center_x-chara_w_h*(scale-5)/2 < 210
and
210 < neko_center_x-chara_w_h*(scale-5)/2+chara_w_h*(scale-5)
then
if neko_center_y == zimen_h then
damage = damage + 1
damage_muteki = 1
love.audio.play(snd_damage)
damage_muteki_time_remaing = damage_muteki_time
end
end
end
こんな感じで半ば強引に設定しています。
ドット絵の塗りに対して正確に当たり判定となると少し面倒臭そう。
見えないけど画像ファイルとしては透明な部分もあったりするから、画像全体を当たり判定にするわけにもいかないし。
-- 猫がジャンプしているアニメーション表現
if cat_now == cat_jump then
jump.timer = jump.timer - dt
if jump.timer <= 0 then
jump.timer = 1 / jump.fps
jump.frame = jump.frame + 1
if jump.frame == jump.num_frames-8 then
neko_center_y = neko_center_y - 10
end
if jump.frame == jump.num_frames-4 then
neko_center_y = neko_center_y + 10
end
if jump.frame > jump.num_frames then
jump.frame = 1
cat_now = cat_idle
end
jump.xoffset = 16 * jump.frame
cat_jump:setViewport(jump.xoffset-16, 0, 16, 16)
end
end
y座標の移動はここで設定。
jump.num_frames-8=2なので、2フレーム目で地面から浮いて、
jump.num_frames-4=6なので、6フレーム目で着地してます。
-- 当たり判定の位置描写
love.graphics.setColor(255, 0, 0,0.5)
love.graphics.rectangle("fill", neko_center_x-chara_w_h*(scale-5)/2, neko_center_y - 10,chara_w_h*(scale-5) , 10)
開発段階では当たり判定位置がわかった方が良いのでうっすら赤く表示しています。
あと、
neko_center_x-chara_w_h*(scale-5)/2 < 200 < neko_center_x-chara_w_h*(scale-5)/2+chara_w_h*(scale-5)
or
neko_center_x-chara_w_h*(scale-5)/2 < 210 < neko_center_x-chara_w_h*(scale-5)/2+chara_w_h*(scale-5)
みたいな表現にしたかったけど、エラーが出たから取り敢えず上のような記述にしました。
石ころの位置もx軸の200~210に設定。
ゲームにするにはランダムで設定しなければいけないし、その場合どうすればいいんだろうかとか課題は山積みですね。
ダメージを受けたあとは一定時間、無敵時間になります。
-- ダメージを受けた際の無敵時間の計算
if damage_muteki == 1 then
damage_muteki_time_remaing = damage_muteki_time_remaing - dt
if damage_muteki_time_remaing <= 0 then
damage_muteki = 0
damage_muteki_time_remaing = damage_muteki_time
end
end
と、まあ、こんな感じです。
目的はあくまでもまずは形にすることなので、汎用化や記述の整理などは後日ひとつずつグルーピングする感じで解決していきます!
個人的なメモと、おそらく素人の過程は誰かのタメになるのではということで...
左上の二段目の数字がダメージを受けた回数。
三段目の数字が無敵状態か否かの変数の数値です。
1のときは猫ちゃんも半透明で無敵状態になってます。
GIF動画がたまにアスペクト比がイカれる...
ちなみにmacのQuickTimeの部分画面収録したMOVファイルをGiftedっていうアプリで簡単にGIFアニメーション化しています。
今、解決したいことは、
【直近にやりたいこと】
・タイトルページをつくる
・制限時間を設定する
・スコアやHPの表示をできるようにする
・画面外に猫ちゃんが出ていかないようにする
【おおよそ見えてきたらやりたいこと】
・石ころをランダムに配置して、それに対する当たり判定をつくる
・ゆくゆくはネズミとかにして敵が動き回るようにする
・コードの記述を整理する
・見た目が複雑なので変数に置き換えれるものを変数にする
・テキストメッセージのコードを解読してテキストメッセージを自由に出せるようにする
・ストーリーを組み込む
・マウス操作ができるようにする(実は本来作りたいゲームがマウス操作必須なのでこれが最終目標でもある)
【本当は優先順位は低いけどやりたいこと】
・猫ちゃんがダメージ受けたときのアニメーション
・背景のイラスト
・無敵時間終了が近づくと透明度が変わって点滅する
・画面が少しずつスクロールしてステージが進んでいく
といった感じでしょうか。
次回はタイトルページを作りたいと思います。
この記事が気に入ったらサポートをしてみませんか?