どうもNYLONです。今回も最近作ったゲーム(https://nylon1919.github.io/mogura/)について解説していきます。
1.開発初期
なんか広く縦横無尽に進むゲーム作りたいなーっていうのと掘り進むアクションとしてモグラを題材にしたゲームが作りたいなっていう発想から開発を始める。十字キーの入力通りに移動するのも面白くないなと思い角度を変えるという操作を実装。開発初期は今の8方向のみならず15度ずつ方向が変わるよう制作していた。
2.飽きる
とりあえず移動方法とカメラをスクロールするところと角度に応じてコマを切り替えるところまで実装したらなんかそれっぽくなったので飽きてしまった。また細かいゲームの方針はまだ立っておらず、このまま作りかけファイルとして永遠に開かれない運命を辿るかに思えた。
3.でも再開する
とは言っても暇は暇なので開発を再開する。見た目と進む方向が一致しないので角度を45ずつに変更。またモグラであり掘り進めていることを強調するため掘った痕跡が残るように変更。しかし毎フレーム画面を消去することがこれによってできなくなり、カメラスクロールもうまく実装できなかったため広い探索という当初の構想と離れてしまう。ただモグラが狭い場所を進むという大して面白くないゲームができてしまった。
4.構想を練る
面白くないものを作っても意味がないのでそれっぽい目的とゲーム性をゲームに与える。これもなんとなくで綺麗な宝石を集めるとかいいんじゃないかなくらいでまず宝石を描いてみることにした。ドット絵 宝石とかでググりながら自分なりに描いてみて割とカラフルで一つ一つ異なったデザインにすることができ少なからずこのゲームの面白みを向上させることに成功した。やはりゲームにおいて報酬は重要である。ただこれだと宝石を集めるだけでゲーム性は無いので失敗条件を与えなくてはならない。これは素朴な発想で敵を実装することにより解決する。これによって大まかなゲームの方向性は敵から逃げながら宝石を集めるゲームとして決まった。
5.さらに構想を練る
そこまでの骨組みが決まっても0点が30点になったくらいである。遊べるものができただけで面白いとは言い難い。そこでさらにゲームをデザインしていく。自分は爽快感があるゲームが好きなのでアクションゲームが好きだがこのゲームには少し求めにくい。(もちろん敵を攻撃するなどできれば別であるが画面を消せないからあんましたくなかったし宝石の方が見て欲しかった)その為他のゲームを面白くする手段としてリスクとリターンを考えてみることにした。実際に実装したのは宝石を決められた順番で取るとスコアが上がるというシステムだったが他にも敵をギリギリで避けるとスコアが入る(これは東方のパクリだし簡単なステージで稼がれてしまうのでやめた)など考えていた。その他敵の移動速度や敵が増えすぎると団子になってしまうので敵の行動パターンの変更などテコ入れをして60点くらいのゲームにした。
6.各種アルゴリズム
今回のゲームを作る上でもいろいろな数学的な問題に直面した。いろいろ考えて解決したがもっと賢いやり方もあるかも。
6.1角度とアニメの管理
結局8段階しか変化しないのでif文を使いまわせば解決してしまうのだが360度で考えていたときの名残でキモいプログラムが書かれている。
function pl_spr()
local a=pl.arg%8-4
if a==0 then
pl.s=2
elseif abs(a)==1 then
pl.s=1
pl.xf=false
if a>0 then
pl.yf=true
else
pl.yf=false
end
elseif abs(a)==2 then
pl.s=0
elseif abs(a)==3 then
pl.s=1
pl.xf=true
if a>0 then
pl.yf=true
else
pl.yf=false
end
else
pl.s=2
end
end
解説していくと角について0~8が0~2πに対応していて、まず一般角を0~7までにしているのがpl.arg%4でわかる。そのあと4を引くのは-πからπのイメージで考えたいからである。(もちろん半周期前にずれたことには気を付ける)そこからは絶対値を用いif文で180度、135度か225度、90度か270度、45度か315度、0度に分けている。aの正負で上か下かわかるので場合に応じて反転させている。左右の反転は斜めになったときに行っている。なんか大人しくif文八本連ねた方がよかったかも。
6.2アイテムや敵の生成
function make_table(n,a)
local ptable={}
for i=1,n do
ptable[i]=i
end
for i=1,n do
local k=flr(rnd(n+1-i))+1
a[i]=ptable[k]
del(ptable,ptable[k])
end
end
これだけじゃなんだかわからないので解説していく。これは1~nまでの数字の並び替えをaに突っ込む関数である。まず1~nまで箱に突っ込んでランダムに取り出して書き出すイメージで実装した。(もっといいやり方あったら教えて。)
これとアイテムや敵の生成がどう関わってくるかというとアイテムや敵を完全ランダムな位置に生成すると位置が重なったりしてクソゲーになってしまうのでそもそも盤面をイメージし1マスに1つしか物が作られないようにする必要がある。ここでゲーム画面を7×7マスとしてその49マスから被らないように物を生成するため乱数列を作った。
function add_item(n)
local i={}
local tbl=(table[n]+24)%49
local x,y=tbl%7,flr(tbl/7)
i.x=16*x+16+rnd(8)-4
i.y=16*y+20+rnd(8)-4
i.px=i.x
i.py=i.y
i.n=n
i.s=63+n
add(item,i)
end
49マスを一次元的に考えているので7で割った商が0から順に上から並べられ、7で割った余りが0から順に左から並べられている。実際は1~48までを入れ替え中央の24は自機がある為生成せず全て24を足したあと49の余りを取って盤面としている。綺麗に並んでいるとちょっとキモいので少しマスの中でずらしている。また自機の目の前である17(24を足す前は42)が出てきた場合最初に一番後ろに置かれなおしている。
for i=1,46 do
if table[i]==42 then
table[i],table[48]=table[48],table[i]
end
end
これによってリスキルが起きにくい。ちなみにmake_tableは宝石を取る順番にも用いている。(もちろん別のtableに突っ込んでいる)思ったより短いコードで実装されたので満足している。
7.その他の頑張り
デザインに関しては結構凝った。基本めんどくさがりで楽はしたいので手を抜いてるところは抜いたがそれなりに頑張った。前述の宝石のデザインもそうだがタイトルロゴやhow to playなども意外と頑張っている。逆に敵は自分でも何なのかわかってないくらい大して考えてない。
また音楽も割とよくできた。なんか適当に作ったけどいい感じになった。PICO8の作曲はできることが少ないしどう転んでもそれっぽい音にはすぐなるから意外と簡単なのかも。
タイトルロゴの作り方を学ぶため思いっきりパクっている様子が伺える。
8.総括
自分はゲーム作るようになって8ヵ月くらい経つがまだ開発技術的に足りないことや知識に疎い部分もある。その一方でゲームは好きなのでゲームデザインについて感覚的に欲しいものを実装したり、抽象的に考えて実装したりそういうことは得意なつもりである。ゲームを面白くする上で定番や決まった構図を使うのもある種正しいし、オリジナリティを出す為に敢えて定番を崩すのも正しい。しかし考えなしに否定しても意味がないので新しいものを作るときほど定番を抽象的に理解している必要がある。そうすることで必要な部分と不必要な部分が見えてきて正しく定番の否定が行えるのである。今やいろんなゲームが出尽くしてしまい自分のような技術力では太刀打ちできないかもしれないが動物タワーバトルのような成功をしてみたい。