モンスターに攻撃できるようにする、ターン制度の作成
今回はモンスターに攻撃を行い、倒すプログラムを作成しました。また、今後のプログラムで敵も攻撃を仕掛けてくるようにしたいと考えているので、ターン数カウントの作成も行いました。
~今回の内容~
画像のように敵に攻撃できるようになっています。攻撃が当たったら音が流れるようになっています。また、敵にはそれぞれ体力が設定してあって、敵の体力を0にすると画面上から消えて敵を倒したことになります。
~プログラムの説明~
タイトルのプログラムを解説する前に追加した要素の説明を行いたいと思います。少しだけ関係はありますが、タイトルの部分だけ知りたいという方は飛ばしていただいてもかまいません。
追加要素の説明
グローバル変数に turn、turncount、Ecount、chp、cstmを追加しました。
turnは経過ターン数を数える変数、
turncountはターンが経過したことを判定するために使用する変数、
Ecountはマップ上に存在するモンスターの数を認識するための変数、
chpは主人公の体力の値を、cstmは主人公のおなかの値を格納します。
関数mapselectの中です。
198行目にEcountの値をリセットするプログラムを記述しています。このゲームではプレイヤーが正常な位置に配置されるようにマップをロードする際に何度も何度もマップを作成します。モンスターが出現するたびにEcountを増やすことによってマップ上のモンスターの数を認識しようとしています。そのため、何度もマップをロードする過程でモンスターも生まれるので、Ecountがたくさん増えてしまいます。このプログラムは適切なモンスター数を把握するために記述しています。
205行目ではchara変数にplayerオブジェクトのインスタンスを格納しています。インスタンスにchp(体力)、cstm(おなか)、10(攻撃力)、10(防御力)を追加しました。
見にくくてすみません... |
Enemy変数とそのインスタンスです。
243行目は黒玉ねぎに関するプログラムです。
初めにif文を作成することで、画面上に一体生成されたら2体目を生成できなくしています。現在はゲームを完成させることを目標にしているため、こうしました。...とかそれっぽいこと言ってますが、どうプログラムを書けばよいのか思い浮かばなかったです(泣)同じモンスターを生成することができればゲームが面白くなるかなと思うのでできれば実装したいですね。
次にEnemy1変数にmonsterオブジェクトのインスタンスを格納しています。インスタンスに名前、体力、攻撃力、防御力、経験値を追加しました。
最後に、Ecount変数をインクリメントしています。モンスターが生成されるとEcount変数が1増え、生成されたモンスターの総数を管理することができます。
プレイヤーオブジェクトとなるplayer関数です。
画像に表示されている259行目~がプレイヤーオブジェクトのプロパティです。
px,pyプロパティはプレイやーを描画する一のx座標、y座標で仮引数px,pyの値で指定しています。
dx,dyプロパティはプレイヤーの動く方向を指定するのに使用します。
dirプロパティはプレイヤーの向いている方向を表すのに使用します。
ax,ayプロパティはプレイヤーが攻撃する槍のx座標、y座標です。
Lvプロパティはプレイヤーのレベルを表します。経験値を得ることで増えるように今後していきたいと思います。
hpプロパティはプレイヤーの現在の体力の値を表します。
maxhpプロパティはプレイヤーの最大体力を表します。体力の上限以上まで回復できないようにするために使用します。
stmプロパティはプレイヤーの現在のおなかの値を表します。
maxstmプロパティはプレイヤーのおなかの最大値を表します。
powプロパティはプレイヤーが敵に攻撃するときのダメージ計算に使用します。
defプロパティはプレイヤーが敵から攻撃を受けた時のダメージ計算に使用します。移動に関するプログラムです。主に282行目~301行目を追加しました。
284~291行目ではプレイヤーが持ってる武器をプレイヤーと一緒に移動させるプログラムです。284行目でプレイヤーが左右のどちらかに移動したとき、移動した方向に槍をプレイヤーと一緒に移動させるように描画します。288行目は上記処理が上下移動に変わった時のプログラムです。
293~295行目ではキャラの体力が最大値を超えた際に最大値を表示するようにしています。これがないとどこまでも体力を回復できてしまい、ゲームが崩壊してしまいます。
297行目では歩くたびに体力が1ずつ増えるようにしています。
299行目からはstm(おなか)の値を減らすプログラムを作成しています。一歩進むごとに判定を行い、2/7の確率でおなかの値が減るようにしています。今思いましたが小数点以下切り捨てしてるので1/3の確率ですね。後で直しておきます。
キー操作の処理にスペースキーを押した際の動作を追加し、その他細かい要素を追加しました。
320行目がスペースキーを押した際のプログラムです。スペースキーを押すとthis.attackが真になり、ターン数が経過するようにしています。
321行目はボタンを離した時のプログラムです。キーを話した際にキャラを移動させるわけにはいかないので移動に関する変数は変動させません。そして、攻撃していないため、this.attackを偽としています。
マップ上の階段を踏んだ時のプログラムです。346,347,348行目を加えました。
346行目ではturncount変数にturnの値に0.9を加えた値を代入しています。この0.9は後程解説します
347行目はstm(おなか)の値を次のマップに引き継ぐプログラムです。これがないとマップを移動するたびに初期値に戻ってしまいゲーム性が崩壊してしまいます。
348行目も同じくhpの値を次のマップに引き継ぐプログラムになっています。
マップ上にプレイキャラクターと槍を描画するプログラムです。357~366行目が追加したものになります。
357行目は槍をしまっている(?)ように描画するプログラムです。if文を用いてthis.attackが偽の時に動きます。this.attackが偽ということで、攻撃をしていないときに槍を持って移動している風に描画します。
362行目はthis.attackが真の時に動くプログラムです。this.attackが真のときはスペースキーを押して攻撃しているときです。284~295行目のプログラムと連動して動き、上を向いていたら上に槍が飛び出るように、左を向いていたら左側に槍が飛び出るようにします。
モンスターオブジェクトとなるmonster関数です。371~383行目がモンスタープロパティになります。
基本的にはプレイヤープロパティと同じ内容になりますので、プレイヤープロパティにはないものを説明します。
376行目はプレイヤーとモンスターとの距離を測るために使用します。いずれはモンスターがプレイヤーに向かって動くようにしたいので用意しています。
381行目のexpプロパティはプレイヤーの経験値を貯め、レベル機能を実装する時に使います。まだプログラムは作成していませんが、今後作っていこうと思います。
init関数です。527行目と528行目を追加し、ゲームスタートした時点でのプレイヤーの体力とおなかの値を指定しています。
tick関数です。541~543行目,545行目を追加しています。
541行目ではプレイヤーの攻撃が敵にヒットした時にattackcheck関数を実行するようにしています。
545行目ではstatspaint関数を実行しています。画面下側の黒枠を描画する関数になります。
statuspaint関数です。画面下の黒枠を描画するための関数になります。体力、おなかの値の表示、階段を上った数、プレイヤーのレベルを現在は表記しています。後々メッセージウィンドウを表示させたいと考えています。
599~600行目では枠の色と描画する範囲を指定しています。
601,602行目ではテキストを白色に、大きさを18px、フォントを明朝体にしています。
603~606行目は表示するテキストの内容です。現在は開発の都合上、turnとturncount変数の値を表示するようにしています。
モンスターへ攻撃するプログラム
いよいよモンスターに攻撃するプログラムの解説を行います。
こちらが主なプログラムになります。552~559行目と560~564行目は同じ動作を上下と左右で分けたものになりますので552~559行目のみにさせていただきます。
550,551行目はモンスターとプレイヤーの上下、左右の距離を計算するプログラムです。新しく変数xdis,ydisを追加しています。そこに、モンスターのx座標とプレイヤーのx座標を引き、求めた値のx座標をxdis変数に代入しています。これにより、モンスターとプレイヤーとのx座標の距離を把握することができます。
552行目からのif文はモンスターとプレイヤーの位置関係が縦か横かで分岐をしています。今回開設するのは位置関係が縦の場合で解説します。
553行目でモンスターの体力プロパティにモンスターの体力からプレイヤーの攻撃力を引いた値を代入しています。これで、ダメージ計算を行っています。
554行目ではモンスターのhpの値が0未満になった際にhpの値を0にするようにしています。これにより、hpが-5とかになるのを防いでいます。
555行目では攻撃を行ったときにモンスターの体力が0ではないときにダメージSEを鳴らします。
556行目ではモンスターの体力が0だった時にモンスターを倒した時のSEが鳴るようにしています。
557行目でmonsterattack関数を行うようにしています。今は作っていませんが、いずれはターン性で敵モンスターも攻撃できるようにしたいので一応書いておきました。
566行目はモンスターを倒したときにそれぞれに指定してあるflag変数をfalseに置き換え、Ecountをデクリメントすることによって、マップ上のモンスターの数が減ったことをプログラムに認識させています。
ターン制度の作成
次にターン制度に関するプログラムを解説します。
まず、プレイヤーの動きに連動するターンカウントです。
315行目~320行目はキー操作を行った時のプログラムです。320行目以外のプログラム全てにturn++と書いています。このことにより、移動もしくは攻撃を行ったときにターンが進むようにしています。
プレイヤーの動きに関するターンカウントは簡単に作成しましたが、攻撃とともにモンスターが動いているため、このままではターン性バトルを行うときに支障が出てしまうことが考えられます。この辺は今後改良したいと思います。
これはモンスターの移動に関するプログラムです。以前は移動ボタンを押してプレイヤーを動かすと同時にモンスターも動かしていました。しかし、今回の改良ではプレイヤーが何かしら動作を行ってターンが経過したことを認識したらモンスターが動くようにしています。
409行目がそうです。turnとturncountは何もしなければ1の位が同じ値になるようになっています。turnがturncountよりも大きいときに動くようにしているので、turnが増えなければモンスター側は動くことができません。
390~395行目のプログラムは移動が完了したときのプログラムです。ここにモンスターの移動が終わったときにturncountを増やすプログラムを加えました。
当初、モンスターの移動が終わり次第turncount変数をインクリメントしてturnと合わせればいいやと考えており、そのようにプログラムを組んでいました。すると、当たり前ですがモンスターの移動が終わったら1ずつ増えるように動作しました。これの何がいけないかというと、マップ上に表示されているモンスターの数だけturncount変数を増やしてしまっていたのです。
例)turn = 0、turncount = 0 と仮定する。プレイヤーをキー操作によって動かしたので、マップ上に3体いるモンスターがランダムに移動した。この時、turn変数がインクリメントされturn = 1 となる。turncount変数もモンスターが動いたときにインクリメントされ、turncount = 3 となる。
上記のようになってしまい、プレイヤーがモンスターよりも3回多く動けるようになってしまっているのです。これはチートですねぇ...
このような状況を回避するために394行目の計算を行っています。
大雑把に説明すると、マップ上に表示されているモンスターの数だけ1を割り、割った数にターンカウントを足しています。
例)turn = 1、turncount = 1、マップ上にモンスターが2体いるとき。プレイヤーが動き turn = 2 になります。すると、409行目のif (turn > turncount) が真となりモンスターが動きます。一体目が動いたとき、計算式は 1/2 + 1 となり、答えは1.5となります。2体目が動いたときは1/2 + 1.5 となり、答えが2になります。409行目のif文はこの時点で偽になるのでモンスターは動かなくなります。
こんな感じになりました。こうして振り返ってみると案外簡単ですね。時間かけて試行錯誤したのですが...;;
...ところで、マップ上の階段を踏んだ時のプログラムでturncount変数にturnの値に0.9を加えた値を代入していたのを覚えていますか?または画面上のturncountの値が 0.9 から始まっているのに気づきましたか?
これは、スタート時のモンスターの挙動に関する不具合を修正するために加えています。これを行わないと、マップ上のモンスターの数が割り切れない時にモンスターが初めのターンで2回行動してしまいます。
例)turn = 0、turncount = 0、モンスターが3体いるとき。プレイヤーがキー操作を行い turn = 1 となりました。409行目のif (turn > turncount) が真となりモンスターが動きます。3体のモンスターが動き終わったとき、turncountの値は0.99999...となる。本来であればここで移動が終わってほしいものだが、turnの値がturncountよりも大きいままなので、409行目条件分岐が偽にならず、2回目の行動を行ってしまう。
このような仕組みで動いてしまうのです。新しいマップに移動した際に、プレイヤーからモンスターが離れた位置にいればあまり影響はないです。しかし、もし真横にいた場合にはプレイヤーが一回動作を行うだけでモンスターから2回攻撃を食らうことになります。これだと少しハードモードですよね。
おわり
いかがでしたか。今回はモンスターに攻撃することをメインにプログラムを作りました。正直授業で習ったことを応用するだけでしたのでメインのほうは割と簡単にできました。でも、今後ターン性バトル要素を加えることを考えると、いろいろと追加しなければならないことが多く、そっちのプログラムの作成に時間を追われてしまいましたね。
でも、まだまだ改良したい点ばかりです。攻撃するたびにモンスターが動くので動画を作成するのに手間がかかりました。モンスターとプレイヤーが戦う際は2体とも向き合うようにしたいのでそういったプログラムもいずれ追加したいですね。また、モンスターがプレイヤーに近づくようにプログラムするといったものですね。プログラム組んでると色々と追加したいことが増えて大変ですよね。メモ取ってないので実装したいことを忘れてしまいそうです。
残り約3ヵ月ですが、どこまで開発することできるでしょうか。武器とか追加したいしアイテムも使用できるようにした。BGMも作りたい、絵もそれなりにいいものを書きたい。
...本当にどこまで開発できるでしょうか。早いうちにゲームの大枠だけでも完成させたいです。
コメント
コメントを投稿