2013年07月30日

ランダムでアイテムを落とす

敵を倒すとランダムで一つのアイテムを落とす、という動作を実装したいとき、真っ先に思いつくのは敵が死ぬたびに乱数を取得し、その値に応じたアイテムを落とすというやり方です。

例えば 10%の確率で宝箱、90%の確率でコインを落とさせたいときには、

if (GetRandomInteger(100) < 10) {
DropTresure();
} else {
DropCoin();
}

みたいにするわけですが、これはあまりよくないやり方です。毎回乱数を使ってアイテムを決めると、実感としてかなり偏った出方をします。宝箱が10%の確率でしか出現しないはずなのに、4回ぐらい連続で出てしまったりとか、逆に40回ぐらいやっても宝箱が一つも出現しないとか、わりとよくあります。


この場合は考え方を変えて、毎回乱数で抽選するのではなく、「あと何回敵を倒したら宝箱が出るか」を決めてやります。
そうすれば、例えば「次の宝箱が出現するまで最低4回、最長で20回敵を倒す必要がある」のような決め方ができるので、比較的意図通りの出現パターンになります。ちなみに「最低1回、最大10回」は出現率10%ではないので注意してください。この場合、アイテムの出現するまでの試行回数は (1+2+3+4+5+6+7+8+9+10) / 10 = 5.5 で期待値5.5になり、5.5回に1回の割合で出現するようになるため、出現率は 1 / 5.5 = 18%になってしまいます。


もっと細かく制御したければ、敵が落とすものを100回程度先まであらかじめ決めておく、といった方法もあります。
これなら完全に思い通りのタイミングと順番で宝箱を出すことができます。

posted by JUNOSOFT at 09:26| Comment(0) | プログラミング

2013年07月24日

キャラクターの操作

ゲームのキャラクターを実装するときに以下のことに気をつけていると後々楽になります

【実装1】キャラクターのアニメーション部分と操作部分を分離しておく(別々のクラスにまとめる)

 操作部分を複数用意して、目的に応じて差し替えることができるようにします。
 例えば敵キャラだったら、同じキャラで異なる行動パターンを適用したり(難易度別とか)、
 イベントシーンにおけるキャラ劇が実装しやすくなったり、必要に応じてパッド入力による操作、スクリプトによる操作に変えることができます
 
 
【実装2】プレイヤーキャラだけでなく、敵キャラもパッドで操作できるようにしておく
 敵キャラを自分で好きなように動かせるので、新しい敵を作ったときなどの動作確認がすごく楽になります。
 プレイヤーが敵キャラに変身するなどの行動も面白いかもしれません。
 その敵にしかない特殊行動なんかは、通常のゲームプレイでは使わないボタンに割り当てる必要がありますが。
 これは【実装1】による恩恵の一つです。
 
 
【実装3】敵キャラが自動行動するとき、行動を直接指定するのではなく、擬似パッド入力を送るようにしておく
 たとえば敵を移動→攻撃させたいとき、「移動アニメに変更」、「攻撃アニメに変更」というふうに動きを直接指定するのではなく、「パッド左押す」「パッド左離す」「攻撃ボタン押す」「攻撃ボタン離す」のようにダミーのパッド操作を送信します。その命令を受け取る敵キャラは、それが実際のパッドから入力されたものなのか、それともCOM操作による入力なのかは区別できません(区別する必要がない)。
 これは【実装2】による恩恵の一つです
 
 また、普段プレイヤーが使っているキャラをCOMが操作するときに、人間のプレイヤーにはできないような行動がとれなくなります。たとえば、必ずアクションA→アクションBの順番で出る技があったとして、アクションを直接指定すると、アクションAを経由せずにいきなりアクションBを出すことも可能ですが、パッドの擬似入力なら、人間が操作したときと同じ条件で操作することになります。人間の代わりにロボットがパッドのボタンを押している、という考え方です。パッドを介して操作している限り、COMには人間と同じ操作しかできません(入力の速さや正確さは別にして)。逆に言えば人間が操作するときと同じ動きしかできない、ということですが、これをメリットと見るかデメリットと見るかは状況次第です。格闘ゲームで対戦相手をCOMが操作している場合なんかには有効です。


posted by JUNOSOFT at 05:24| Comment(0) | プログラミング

2013年07月17日

フォント描画とか

どうやら GetGlyphMetrics では空白文字の横幅は取れないみたいですね。
この関数の引数に半角スペースや全角スペースを指定すると、なぜかエラーになってしまいます。

というわけで、GetGlyphMetrics を呼ぶ前に、調査対象が空白文字だった場合の処理をしなくてはなりません。

ところで可変ピッチフォントのスペース幅っていくつなんでしょう?
探してみたら、参考になりそうなものがリコーのサイトにありました。

「MSゴシック」、「MS明朝」についてのお話
http://www.ricoh.co.jp/font/related_info/knowledge/fontknowledge01.html

どうやら「MS Pゴシック」の場合、半角スペースは「MS ゴシック」文字幅の 1/3 に、全角スペースは 2/3 になっているみたいです。じゃあプロポーショナル版しか存在しないフォントのスペース幅はどうしようか?と思ったのですが、emという単位が存在するぐらいだし、大文字 M の横幅を基準に考えて良いのではないかという結論に達しました。

emとは
http://www.sophia-it.com/content/em

しかし文字をただ並べるだけなのにこんなに手間がかかるとは…。その点、固定ピッチフォントは楽ですね。
posted by JUNOSOFT at 23:51| Comment(0) | プログラミング

2013年07月14日

ロードのタイミング

ゲームデータのロードっていつやってますか?
必要なデータの量が増えてくると、ゲーム開始時のロード時間が長くなりますよね。
というわけで、自分がゲームを作るときに使うロード方法をまとめてみました。


■一括ロード

ゲーム起動時に全ステージ、全てのデータを読み込む
・一度ロードしてしまえば、その後一切ロードする必要がなくなるためゲーム中はすごく快適。
・ゲームの起動時間が長くなる
・最終ステージのデータなど、結局使われないであろうデータも一緒にロードしてしまう
・データに不備があってロード不可能な場合、ゲーム起動時に発見できる


■シーン単位でロード

タイトル、ゲームステージ、ステージクリア、ゲームオーバーなど、ゲームをシーン単位で区切って、各シーンの開始時に必要なデータをロードする
・たぶん一番お手軽で一般的な方法
・シーンの変わり目ごとにロード処理が入るが、シーンの変わり目なので多少ロードによる遅延があっても許される?
・でもデータが多い場合はやっぱり「Loading...」の画面が必要になる



■データを使う時にロード

ゲーム開始時、ステージ開始時にまとめてロードするのではなく、とあるデータが必要になったときにその場でロードする
一度ロードしたら破棄しないで次のためにとっておく。例えば会話のためのデータは、会話が始まるその瞬間までロードしないし、
キャラクターのデータは、そのキャラクターが登場するその瞬間までロードしない
・ゲームの開始時、ステージの開始時にロード画面を設けたりする必要がない
・ゲーム起動中に行ったデータファイルへの変更が即座に反映されるので、ゲームの開発中、デバッグ中に便利
・キャラクターの出現時、音楽を鳴らすとき、なにかの画像を表示するタイミングでちょくちょくロードによる遅延が発生する
・データにエラーがあってロード不可能な場合、そのことに気づくのが遅れる。例えば最終面のボスデータに不備があってロード不可能だった場合、そのボスが登場するまでロードエラーには気づくことができない



■データを使いそうな時ロード

データをロードする場面に近づいたら、実際にその場面に出くわす前に、ロード専用スレッドでデータを読み込んでおく。
ゲームの起動から終了まで、待ち時間が発生することはほとんどない。

例えば…

・マップセレクト画面で、プレイヤーがカーソルを「マップ1」に合わせたら、その時点でマップ1のデータをロードし始める。その後プレイヤーがカーソルをマップ2に移動してしまった場合は、マップ1データを破棄してマップ2をロードし始める。このとき順番を工夫して、マップを最初に選ばせて、つぎにプレイヤーの装備や難易度などの選択画面を置いておけば、その間にマップデータをロードできる。

・マップ1をプレイ中に、マップ2への移動地点が近づいたら、その時点でマップ2のデータを読み始めてしまう。
予想に反してプレイヤーがマップ2に移動せず引き返してしまった場合は、データを捨てるもよし、そのまま保持し続けるもよし。

・ボスとのイベント場所に近づいたら、その時点でボスのデータを読み始める。



自分は「一括ロード」、「シーン単位でのロード」、「データを使う時にロード」を状況に応じて使っていますが、
「データを使いそうなときにロード」だけは大変面倒くさそうなので実装したことがありません…

posted by JUNOSOFT at 22:08| Comment(0) | プログラミング

2013年07月11日

HSP

最近、「プログラムって何?」と聞かれることが何回かあり、適当に説明したりしてたんですが、こういうのは実際にいじらせてみるのが一番ですよね。
ところが定番の C も Java もとても初心者&学習向けとは思えないし、HELLO WORLD しても文字が出るだけなので全く面白みがありません。
GLUTなんかと組み合わせてみても少しハードルが高いだろうし、そもそも開発環境のインストールの時点で疲れそうです。

覚えやすくて、インストールが簡単で、シンプルなIDEが一緒についてきて、プログラムを新規作成しようとしたら最初にファイルの保存先を選ぶなんてことやる必要がなくて、簡単なコードでウィンドウ出したり図形が描けたりする都合のよいスクリプトは?と考えたときに、ふとHSPのことを思い出しました。

よくHSPの名前を聞くことはあったのですが、「初心者むけの簡単スクリプト言語!!」みたいなイメージがあったので、特にチェックすることもなくスルーしてました。
そういえば小学生向けの本なんかも出てたなーと思い、とりあえずダウンロードして軽くいじってみたのですが、いやー、至れり尽くせりでびっくりしました。
テキストエディタはそこそこ使いやすいし、ヘルプも充実。入力支援もあるし、ちょっと作ってみよう→書く→実行が本当に気軽にできます。プログラム部品を配置していくだけでよい HSP Peas とか、もうゴメンナサイって感じ。
次からはこれを使って教えてみようと思います。
posted by JUNOSOFT at 04:07| Comment(0) | プログラミング

2013年07月09日

構文解析とか

大学の授業なんてほとんどその場限りのイベントに過ぎないのですが、唯一実際に役に立ったのが、コンパイラ構成という授業でやった構文解析についてです。それ以前に、 数式を直接入力できる電卓プログラムを作ろうとして挫折したことがあったのですが、まさにその問題の解決法を授業で習ったのです。知ってしまえば理屈は非常に簡単で、その後無事に電卓を完成させました。その後もゲームスクリプトを独自開発するというときに、もう少し本格的な構文解析について調べたのですが、基本はカッコつき四則演算式の解析と変わりません。

というわけで、もしスクリプトを自分で作りたかったり、複雑な数式を直接入力できるような電卓を作ってみたい という型は構文解析でググってくださいね。と。

ちなみにコンパイラのための構文解析では、この本に大変お世話になりました。いわゆるドラゴン・ブックてやつです。
少し高いですが、それに見合った内容ですよ。ちなみにこれは上下巻に分かれています
「コンパイラ 原理・技法・ツール(1)」
「コンパイラ 原理・技法・ツール(2)」
http://www.amazon.co.jp/%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E2%80%95%E5%8E%9F%E7%90%86%E3%83%BB%E6%8A%80%E6%B3%95%E3%83%BB%E3%83%84%E3%83%BC%E3%83%AB-Information-Computing-A-V-%E3%82%A8%E3%82%A4%E3%83%9B/dp/478191229X

バイブルといっても良いかも。
posted by JUNOSOFT at 04:36| Comment(0) | プログラミング

2013年07月03日

処理の順序(2/2)

こんにちは。いまだに自動車の不具合と戦っているプログラム担当です。
今回は前回「処理の順序(1/2)」の続きです

1. 全キャラクターの行動パターンを更新。それに合わせてアニメと移動速度を設定

まず最初に、全てのキャラクターの行動を更新します。プレイヤーならばゲームパッドからの入力を元にして、移動するとか、攻撃するとかを決定します。敵ならば敵の出現パターンにしたがって移動速度を決定したり、敵の弾を生成したりします。


2. 全キャラクターの座標を更新+地形との判定による座標補正

全てのキャラクターの行動が決まったら、次に移動処理をします。速度にしたがって座標を更新し、
必要ならば加速度にしたがって速度も更新します。そのとき、地形との接触判定もやっておき、地形と矛盾した場所に移動しないように、座標を補正しておきます。


3. いよいよ攻撃・ダメージ判定ですが、まず最初にプレイヤーの攻撃判定と敵のダメージ判定を処理します。
(これは、「プレイヤーの攻撃が敵に当っていて、かつ敵の攻撃もプレイヤーに当たっている」という状況が同時に発生した場合に、プレイヤーの攻撃を優先するためです。相反する状況が同時に発生した場合は、かならずプレイヤーに有利なほうを選びます。
例えばボスを倒した瞬間に敵の弾に当たり、ステージクリアとゲームオーバーの条件を同時に満たしてしまった場合は、ステージクリアを優先させます)
ここで、プレイヤーの弾、オプションキャラクターなど、敵に対する全ての攻撃判定と、敵側のダメージ判定の接触を調べ、組み合わせをリスト化しておきます。


4. リスト化された全ての接触の組み合わせを見て、攻撃やダメージの処理を行います。なぜわざわざリスト化してから処理するのかといえば、複数の攻撃が同時にヒットした場合の処理を簡単にするためです。ダメージを受けた敵は爆発するか、もしかしたら進行方向が変わるだけかもしれません。ただ、たとえ進行方向が変化したとしても、ここでは速度を再設定するだけにしておきます


5. 今度は敵の攻撃判定と、味方のダメージ判定の処理です。プレイヤーに対する全ての攻撃判定と、プレイヤー側のダメージ判定を調べ、接触していればその組み合わせをリスト化しておきます


6. 5で作成したリストを元にしてプレイヤーのダメージ処理を行います。ちなみにプレイヤーが無敵状態の場合は、5 と 6 をスキップします。ダメージを受けたことによって吹き飛ばされたり、進行方向が変わるかもしれませんが、ここでは速度を設定するだけで座標は変えないでおきます


7. この時点でのアニメ(行動に適したキャラクタ画像)、座標を使って全てのキャラクターを描画します


--
このような感じで、キャラクター単位で処理するよりも、機能単位で処理したほうがなにかと便利です。
ある特定のキャラクターの状態によって別のキャラクターの行動が変化するなど、キャラクター同士が影響を及ぼしあう場合、処理の順番に気をつけないと思わぬ事故が発生する場合があるので、気をつけましょう。
シューティングやアクションゲームのようなリアルタイムに進行するゲームでは全員が同時に動くのでややこしいですが、
結局はターン制のゲームと同じで、ただ敵のターンと味方のターンが超高速で切り替わっているだけと考えれば、すこしは楽になるかもしれません。
posted by JUNOSOFT at 04:33| Comment(0) | プログラミング

2013年07月01日

処理の順序(1/2)

こんにちは。モンスターエナジーがあれば徹夜もへっちゃら、プログラム担当です

突然ですが自分が最初にゲームを作り始めた頃、わりと悩んでいたのが、1フレームごとにどういう順番でキャラクターの処理をするか、です。

例えばシューティングゲームならば、
・キャラクターを移動させる
・プレイヤーの弾と敵、敵本体とプレイヤー同士の接触判定
・キャラクターの状態によるアニメーションの更新
・描画

などの処理を毎フレーム行うわけですが、どの順番で処理していくのか、結構迷っていました。
また、当然ですがキャラクターは複数存在するため、
キャラクタ1に関する全ての項目を更新→キャラクタ2に関する全ての項目を全更新→ ... とのようにキャラクタ単位で処理していく方法と、
全キャラのアニメだけ更新→全キャラの座標だけ更新→全キャラの接触判定だけ処理→ ... のように機能単位で処理していく方法があります。

自分の結論としては、
1. 全キャラクターの行動パターンを更新。それに合わせてアニメと移動速度を設定
2. 全キャラクターの座標を更新+地形との判定による座標補正
3. 味方の攻撃判定と、敵のダメージ判定の接触を検出
4. 3で検出した全ての接触に対する処理
5. 敵の攻撃判定と、味方のダメージ判定の接触を検出
6. 5で検出した全ての接触に対する処理
7. 描画
の順番で処理するのが一番やりやすかったです。

次回もう少し詳しくお話します
それでは。
posted by JUNOSOFT at 19:51| Comment(0) | プログラミング