原カバンは鞄のお店ではありません。

Unityを使ったゲーム制作のあれこれを綴っていきます。

【Unity】オブジェクトの衝突位置を取得する

暑い・・・

去年と比べて今年は全然暑くないなぁ、とか思っていたら梅雨明けと同時に蒸し暑い季節がやってきました。

兎に角、動くたびに汗をかくので制汗シートが欠かせないのですが、この前、薬局で売っていたICE-Typeというやつを購入してみたら、室内だと冷えすぎて逆に痛いです。

シートには40枚分とか書いてるんですが、どうしよう。

 

本題

さて、ご存じのように次回作は2.5Dのシューティングゲームになる予定なのですが、2.5Dというだけあってある程度広い空間(ステージ)の中を強制スクロールで進んでいく形式になっています。


なので自機の移動範囲をそのステージ内に収める必要があるのですが、この『ステージ内に収める』という仕様を満たすために外壁となるオブジェクトを設定して、その外壁に自機がぶつかったら強制的にステージ内に戻す、みたいな処理を作ることにしました。

つまり今回はステージの外壁部分との衝突を判定しよう、というお話。

 

衝突判定

通常、Unityで衝突判定を行う場合は「当てる側」「当てられる側」の両方にColliderコンポーネントを設定して、OnTrigger系関数かOnCollision系関数で判定する手法を取ります。

 

衝突判定にOnTriggerとOnCollisionの二種類あるのは、OnCollisionを使う場合はCollider以外に物理演算用のコンポーネント『Rigidbody』をオブジェクトに設定する必要があるためで、「動くオブジェクト=Rigidbody有り」「動かないオブジェクト=Rigidbody無し」みたいな使い分けを行う場合のために、OnTrigger系関数とOnCollision系関数の二種類が用意されています。

 

ただ、OnTrigger系関数を使う場合は衝突の有無は判定できますが、衝突したオブジェクトはすり抜けしまいます。また、衝突が発生した正確な位置は分からないため、衝突位置にパーティクル等のエフェクトを表示したい場合には、Collider.ClosestPoint()を使って求めた「コライダー内の最も近い点」を衝突位置として扱う事になります。

 

今回の場合、外壁とぶつかったら自機はステージの中へ戻ってほしいのでOnCollisionを使う方針にしました。

 

OnCollisionを使うために

前述のようにOnCollisionを使うためにはColliderに加えてRigidbodyが必要となります。また、ColliderにはMeshColliderを使用しているためConvexオプションをONにします。ConvexオプションはMeshCollider同士の衝突判定有無の設定です。

これを自機と外壁のオブジェクトどちらにも設定します。

 

f:id:Karvan:20190730232912p:plain

自機側のMeshCollider(見え辛いけど…)

 

f:id:Karvan:20190730232955p:plain

自機側のInspector設定

 

OnCollisionで衝突を検知するには外壁側にもRigidbodyが必要なのですが、外壁部分は動かないオブジェクトなのでIsKinematicオプションをONにして物理演算を無効に設定します

ただIsKinematicをONにしても衝突によるRigidbodyの影響は受けるので、自機に比べてMass(重量)を大きく設定します。

 

f:id:Karvan:20190730233151p:plain

 

f:id:Karvan:20190730233209p:plain

外壁側のColliderとInspector設定

 

 スクリプト側の処理

ここまで設定すれば衝突時にOnCollision系関数が呼ばれるようになります。


自機側のOnCollisionEnter(衝突発生時)にて衝突位置を求めて、その衝突位置から自機へ向かうベクトルの方向にAddForceで力を加えてやれば自機がステージ内に戻ってくれます。

 
/// <summary>
/// 衝突発生時の処理
/// </summary>
/// <param name="collision">衝突したCollider</param>
private void OnCollisionEnter(Collision collision)
{
	float boundsPower = 10.0f;
	
	// 衝突位置を取得する
	Vector3 hitPos = collision.contacts[0].point;
	
	// 衝突位置から自機へ向かうベクトルを求める
	Vector3 boundVec = this.transform.position - hitPos;
	
	// 逆方向にはねる
	Vector3 forceDir = boundsPower * boundVec.normalized;
	this.GetComponent<Rigidbody>().AddForce(forceDir, ForceMode.Impulse);
}

上のソースでは直に取得していますが、GetComponentでRigidbodyを取得している箇所は、Start関数などで事前に取得しておく方が負荷が少ないです。

動作確認

実際に動かしてみるとこんな感じになります。
見た目が地味だったので、上の処理に加えて衝突位置にパーティクルを表示するようにしています。
 

f:id:Karvan:20190730233626g:plain

 まぁ、パーティクルをつけても地味ですが・・・

 

【進捗報告】シューティングゲームだからって弾を発射すべきなのか

世間が騒がしかった一週間

先週から今週にわたって世間では放火事件があったり、参院選があったり、大雨が降ったりと予想もできない出来事が一遍に巻き起こって色々と騒がしい一週間でしたが、こと私に限って言えば、いつも通りの安定した低空飛行で、週末も選挙に行った以外は部屋に閉じこもってPCと向き合う日々でした。

 

こんな私にも手を差し伸べて拾い上げてくれるような、「不安よな、動きます」とか言ってくるような心優しい先輩芸人がいれば良いのですが、なんせ人望とお金がないことには自信があるので自分で上昇気流に乗るしかないようです。

 

そんなわけで今回は制作中のゲームの進捗報告。

 

進捗報告をするよ

振り返ってみると、次回作として2.5Dのシューティングゲームを作っていることは前々からブログ内で紹介しているのですが、進捗の具合については記事にしていませんでした。


まぁ、線表を引いてプロジェクト管理しているわけではないので、ゲーム開発の進捗具合を表現するのは中々難しいのですが、今回のシューティングゲームに限って言えばコガネブログさんのシューティングゲームチュートリアル記事が指標になると思います。

 

baba-s.hatenablog.com

 

シューティングゲームを作る上で必要な作成工程をそれぞれの工程に分けて記事にしているので、この工程のどこまで終わったかを判定すれば現在の進捗具合を見極めることができます。

 

現在の進捗は・・・

と、いうことでそれで示せば、現在のところは背景のスクロールぐらいまでは完成していて、敵の動作パターンも増やしている状況なので20%ぐらい、ということになるでしょうか。


ただ、上記のチュートリアルでは全26回中の7回目という早い段階で取り上げられている、『弾の作成と発射』という工程、自機なり敵機なりが弾を発射する処理の作成に取り掛かるべきなんですが、未だにそこには手を付けていません。

 

というのも、自機にしても敵機しても弾をただ撃つだけなら簡単に作れるのですが、撃たれた弾は自機なり敵機なりに衝突するか、画面外に消えた場合に破棄もしくは回収しなくてはいけない。それに加えてただ真直ぐ飛ぶだけでは物足りないから、放射線状に動くとか、拡散するとか連帯を組むとかパターンを考えないといけないし、かつ、それらはゲーム内に数多く登場させて動かさないといけない。

 

ゲーム的にはただの弾だとしてもUnityの処理的には一つ一つがObjectになるので数が多くなると処理は当然重くなりますし、それに伴って高速化の手段も考えないといけない。

 

つまりはやる事が多すぎて手を付ける段階から二の足を踏んでいる、という感じ。
ゲーム制作ではゲーム中では簡単そうに見えるものでも意外と手のかかるものって色々と多いのですが、シューティングゲームの弾というのもその一つだと思います。オブジェクトプールを使用したりJobSystemを利用したり、弾幕用のアセットもあるし意外と手が込む。

 

大体、シューティングゲームだからって弾を発射すべきなのかって話ですよ。
自機が進みます、敵が来ます、かわします、進みます、かわします、クリアします、それでいいじゃない。
弾を撃ったとか撃たれたとか、玉を取ったとか取られたとかやくざの出入りじゃあるまいし、憲法九条の輝くこの日本に相応しくない、やられてもやられてもやめて下さいって言っている方が良いって作家なのかタレントなのか分からない自己顕示欲だけは高そうな女性コメンテーターも言っているように専守防衛の崇高な精神ですよ、そんな気位だけは高い時代遅れのインディゲームが一つあってもいいじゃない、って思うわけですよ。


なので、、、

 

 

 

 

ドーン

 

 

 

 

 

f:id:Karvan:20190723233638p:plain

自機を弾丸にしました。

 

科学忍法火の鳥ですよ(知らない良い子はお父さんに聞いてね)。Kamikaze Attackの精神は最強なので、この一撃で全ての敵を倒せる仕様にします(ボスを含め)。敵をロックオンする⇒敵に向かってKamikaze Attack=最強、これで行きます。弾が撃てない?あんなの飾りです。偉い人にはそれがわからんのですよ。

 

ゲームの仕様は決まった

そんな訳でSTGと言えば弾幕STGが主流となっている中、弾幕の中をかい潜りながら敵をロックしてホーミング弾を撃つとか、レーザーで一掃するとか、そんな感じのゲームにはならない予定です。主流のゲームデザインとは異なることで好き嫌いが分かれそうとか、「はっきり言う。気にいらんな。」みたいに言わそうとか懸念はあるのですが、そんな時はきっと「貴方ならうまくやれますよ」と言えば、「ありがとう。信じよう」と返してくれるはずなので大丈夫です。気休めかもしれませんが。(知らない良い子はお父さんに聞いてね(二度目))

 

あ、実際のゲームではこんな感じです(今のところ)
f:id:Karvan:20190723234207g:plain

 

あー、でも敵が弾を撃つ仕様は必要かなぁ・・・じゃないと地味だし。


 

【Unity】Particleにポリゴンを使ってもいいじゃない。

Unity1週間ゲームジャム

前回の記事でも紹介しましたが、unityroomの1週間ゲームジャムに参加して「倉庫番系」のパズルゲームを投稿しました。PCなら誰でも遊ぶことができるので、是非、下のリンク先から遊んでみてください。

 

unityroom.com

この1週間ゲームジャムに参加すると締め切り日の二週間後にユーザ評価ランキングが発表され、その時初めて自分のゲームの評価点(楽しさ・絵作り・サウンド・操作性・雰囲気・斬新さ)が分かる仕組みなのですが、上のゲームはどの項目も3.5点前後という、至極平均的でなんとも言い難い評価を頂いております。ありがとうございます。

 

実質3日で作り上げたゲームとしてはこれでも上出来な結果とは思いますが、お祭りの中での評価点なので下駄を履かせてもらったのかなぁ、という気がしないでもない。
上位にランクされているゲームと比べてみると、自分の作品の至らなさばかりが気になってしまいネガティブな気分にもなりますが、この反省を生かして次のゲーム作りに励んでいきたいと思います。

 

反省文は早々に、本編

で、このゲームは各色のGEMを周囲のパネルを足し引きしながら同じ色のHOLEのところまで運ぶ、というパズルゲームなのですが、GEMと呼ぶオブジェクトは一般的な3Dモデルを使用するではなく、パーティクルを使って表示しています。

 

f:id:Karvan:20190716221151g:plain

パネル上のクルクル廻っているのがGEM

 

なぜ3Dモデルでなくパーティクルを使ったのか、というと

  • GEMはホログラムっぽく半透明で表示したい
  • GEMはずっとグルグル回っていて欲しい
  • GEMに当たり判定は必要ない
  • パネルを動かして移動するするので、GEM自体を動かすことはない

と、ここら辺の構想を実現するのに最適だと判断したからです。

 

もちろん、普通に3Dモデルを使ってホログラムっぽいシェーダーを用意しても良いのですが、UnityのParticleシステムなら既に用意されているシェーダー(Particles/Standard Surface)を使えば良いし、オブジェクトを回転させるのも簡単ですぐに実装できます。

 

パーティクルをポリゴンで

やり方をざっくり説明すると、ParticleシステムのRenderのRenderModeをMeshに変更し、そこに表示したいメッシュを指定するだけです。

 

f:id:Karvan:20190716221409p:plain

上の図の矢印の箇所

 

表示したい形状が立方体や球ならUnityにてプリセットされているメッシュを指定します、今回の場合は下の図のような四角鋲型のメッシュを用意して使用しました。

f:id:Karvan:20190716221434p:plain

 

ただ、これだけだとモデルにはColor over LifetimeやColor By Speedで指定した単一に塗られた色でしか表示できません。
なので前述のシェーダー(Particles/Standard Surface)にテクスチャを設定したマテリアルを作成し、RenderのMaterialにそれを指定しました。

 

f:id:Karvan:20190716221459p:plain

パーティクル用のマテリアル

 

マテリアルのBlending OptionsのRendering Modeに「Additive(加算)」を指定し、Mapsの項目に緑色のテクスチャを指定します。
テクスチャの模様をハッキリと表示させたい場合にはEmissonの項目にもテクスチャを指定すればよいです。

 

逆にParticleシステム側のColor over Lifetimeに白色の設定を行います。

f:id:Karvan:20190716221536p:plain

 

Particleを廻す

GEMはその場でグルグル廻ってほしいので、ParticleシステムのStart Speedには0を指定し、Rotation over LifetimeとEmissionの項目でパーティクルが回転するように設定を行います。

 

f:id:Karvan:20190716221648p:plain

 

以上、ざっくりとした説明でしたがポリゴンを使ったParticleの説明でした。
需要があるかどうかは微妙ですが、まぁこれも一つの手法ということで。。。

 

 

【Unity】締め切りに追われた一週間ゲームジャム

1週間ゲームジャム

先週(7/1~7/8)はunityroom主催で「1週間ゲームジャム」というイベントが行われていました。


これは文字通りUnityを使って1週間でゲームを作るイベントで今回で12回目の開催となります。


私も前々からこのイベントの存在は知っていて「面白そうだなぁ」とは思っていたものの、「一週間で作成するは無理だなぁ・・・」と尻込みしてしまい参加することはありませんでした。

 

ただ今年のゴールデンウィークにroom6主催のゲームジャムに参加して、ギリギリではあるものの何とか締め切り内にゲームを完成させることができたので、今回はこちらのゲームジャムにもチャレンジしてみることにしました。

 

まぁ、結果として期限の20時には間に合わなかったのですが、特に締め切られることなく無事に投稿することができました。

 

こんな感じのゲーム

パネルを使って同じ色のGEMを集めるパズルゲームです。

f:id:Karvan:20190709215700g:plain

 

難易度的には簡単な部類のパズルだと思うので是非遊んでください。

下のリンクから飛ぶことができます。

unityroom.com

 

振り返るよ

上の動画でもお分かりいただけると思うのですが、出来上がったゲームは非常に単純な内容でプレイ時間も短いゲームなんです。

 

とは言え、やっぱり1つの作品ができる上がるまでには色んな苦労がありました。 

今回はそれらを振り返った記事になります。

 

・月曜日(7/1)

朝、出勤途中にTwitterをチェックして「1週間ゲームジャム」が「あつめる」というお題で開催されたことを知る。


なので日中は仕事半分、ゲーム構想半分で過ごし、「絡まった糸をほどいて中央にリングを集める」という企画を頭の中でまとめる。

 

早速帰宅後にプロトタイプの作成に取り掛かる。色々と熱中し過ぎて深夜3時近くまで作業する。

 

・火曜日(7/2)

平日は6時半過ぎには起床しなくてはいけないので糞眠い。
日中は仕事半分、睡眠半分で過ごす。いや、1:2ぐらいかも。

 

帰宅後にプロトタイプの完成を急ぐが前日の無理が祟ったのか作業中に寝落ちする。
目を開けたら既に3時を廻っていたので、これ以上の作業を諦めて床に就く

 

・水曜日(7/3)

この日も帰宅早々からプロトタイプ作りに励む、そして深夜二時ぐらいになってあることにハッキリと気づく。明確な確信。それは。。。

 

f:id:Karvan:20190709221258p:plain

 

 行列計算とか駆使しないといけない事が分かって頭の悪い私には全く無理ゲーだった。

なので当初予定していた「絡まった糸をほどいて・・・」でのゲームは断念する。


つまり既に3日経過しているのに進捗は0、これから別のアイデアでのゲーム制作をしなくてはいけない。

 

f:id:Karvan:20190507220439p:plain

 

とはいえ、眠気には勝てないので明日きっと良いアイデアが浮かぶことを期待して就寝する。

 

 ・木曜日(7/4)

一からアイデアを練り直すにしても時間がないので、ゲームのジャンルを一番作業工数が少なそうなパズルゲームに絞る。期間内に出来上がることを優先しての決断

 

一口にパズルゲームとはいっても、ルールが複雑だったり、いろんなイベントが発生するようなものは時間が掛かるので、本当に単純で簡単にできそうなパズルゲームにしないといけない。とはいえ、ゲームとして不出来なものは作りたくないし、少しは個性を出したものに仕上げたい。

f:id:Karvan:20190507220034p:plain

 

とりあえず色々素材を並べて、それっぽい画面を作ってみる。

で、その画面を見ながらパズルのルールとかギミックとかを考えることに。

 

f:id:Karvan:20190709222944p:plain

結局、完成予想図として上のような画面で落ち着く。気がつけばやっぱりこの日も二時過ぎまで作業をしていた。

 

・金曜日(7/5)

この日から本格的に作業に取り掛かる。パズルのルールは半透明のGEMが乗ったパネルを押したり引いたりしてゴールまで運ぶという、いわゆる「倉庫番系」ゲーム

 

上・左ボタンを押すとその列にパネルが追加され、既存のパネルが押し出される。

下・右ボタンを押すと一番端のパネルが削除され、既存のパネルが引き寄せられる。

 ただし、端から連結されていないパネルは動ない

 

たったこれだけのルールなので少ない残り日数でも完成できるはず。明日は休みだし、徹夜でもすれば遅れを取り戻せるし、絶対間に合う。

そんな楽観的予測を胸に抱いたもの、前日までの深夜作業の影響なのか23時を過ぎたあたりから急激に眠くなり気が付けばベットの中。。。

 

この日はボタンを押してパネルが列に並ぶところまでしか完成しなかった。

 

・土曜日(7/6)

朝から作業を進めていくが思いのほかバグが多くて進捗が進まない。

一度パネルを連結した後に他の列のパネルを動かして連結状態を解除したはずなのに、なぜか一緒に動いてしまう。

一列全てをパネルで埋めた後、その列のパネルを全部消そうとすると、端のパネルだけ残ってしまう。

一日中ゲーム作りをすると誓ったはずなのに、なぜかサッカーを観るためにスタジアムへ出かけてしまう。。等々

何故か色々な問題が発生し、思うように進みませんでした。それでも明日という日に全てを掛けようと、明日こそは一日中ゲーム作りをしようと、そう心に誓っていた私は衝撃の事実を知ってしまったのです。

 

それは・・・

f:id:Karvan:20190709234820p:plain

 

 

f:id:Karvan:20190709235622p:plain

 

「え?20時締め切り・・・」

 

 

f:id:Karvan:20190709221258p:plain

(二度目)

 

 ・日曜日(7/7)

最終日となったものの完成にはほど遠く、積み残しの作業をざっと並べてみると

  • GEMがゴールに到達した判定
  • そもそもステージクリアの判定がない
  • っていうことはステージクリア⇒次ステージの処理もない
  • いや、その前にステージデータを読込む処理がない
  • 音楽、SEもない
  • ってか音を鳴らす処理がない
  • あ、あとUIもない

f:id:Karvan:20190710000422p:plain

もうこんな気分

 

とはいえギリギリまでは頑張ってみようと、休日なのに早朝に起床して作業に取り掛かる。

音を鳴らす処理は他のプロジェクトのソースをコピペして作成、ステージデータのCSVファイルを読み込む処理はネットから拾って、こちらもコピー&ペーストで作成。UIの素材やら音楽、SEもネットから。GEMの到達判定からステージのクリア等々へ続いていく処理は気合と勘と開き直りでコーディングする。バグ取りとか何それ?美味しいの?という感じで、作ったステージは一回PlayしてOKならそれでいいや、ってことにして、アイコン作ってビルドセッティングしてビルドをGO!!

 

・・・そうしてビルドが完了したのが20時06分

あとはこれをunityroomへアップして・・・・

f:id:Karvan:20190710001843p:plain

アップロード完了!!!

f:id:Karvan:20190710001905p:plain

 

どうもありがとうございました。

 

感想

room6のゲームジャムに参加した時もそうだったのですが、限られた時間で一つの作品を作り上げる、ということは非常にゲーム作りの勉強になりました。

 

ゲームを作っているとアレコレ要素を付け足したくなるものですが、時間に制約があると必要なものを優先して作らなくてはいけなくなるので、逆に何が必要なのかを見極める力がついたような気がします。

 

反省点としてはスケジュール管理をちゃんとしよう、ということですかね。今回の場合は途中で仕様を変えたことが原因ですが。

 

【Unity】ロックオンした敵を捉える、ロックオンを解除する

2019年上半期終了

早いもので2019年の上半期が終了し、今年も残り半年となってしまいました。

 

振り返ってみるとインディゲーム界隈では「World for two」がアプリランク1位となり、Bitsummitの盛況ぶりがマスコミで話題になるなど、インディゲームという分野の盛り上がりを感じた半年でしたが、個人的な振り返りをすれば、ゲームアプリをリリースするも特に市場にインパクトを残すことなくストアの山に埋もれてしまい、加えてAdmobのアカウントが停止されたり、GooglePlayからアプリがBanされるなど、散々な出来事しかなかった半年でした。

 

ヨルシカが「所詮、売れないなら全部が無駄だ」という歌詞を歌っていますが、まさにその通りであることを現在、実感しています。ゲームアプリの制作には苦労が多く、色々な努力を必要としますが、結果が出ないならそれらは全部無駄です。

 

とりあえず主機をつくる

とはいえ他にやることもないので、前回の記事でお知らせしたように、次回作は3D(2.5D)シューティングゲームの方向で試行版を作成しています。

 

そして最近の作業は、Playerの操る主機どうするか、ということに頭を痛めていました。

 

シューティングゲームということで、オーソドックスに戦闘機型のスペースシップを探してUnityのアセットストアを眺めていましたが、ローポリのものからハイエンドなものまで数多くの3Dモデルアセットが揃っており、色々と目移りして中々決められませんでした。

 

そうこうして時間ばかりが過ぎていくうちに頭が沸騰してきたのか、「格好いい戦闘機が主役のシューティングはストアに溢れている=同じことをしても目立たない=逆にシンプルなデザインの方がウケるかも」みたいなトチ狂った考えが湧き上がってきて、「とにかくシンプルに!無駄な装飾は全部削除!必要最小限の要素で最大公約数の機能を!」という仕事の出来ないSEが叫んでいそうな号令が頭の中で響く中、プリミティブなオブジェクトを組み上げて出来上がったのがこんな感じ。

 

ドン!!

f:id:Karvan:20190702205738p:plain

 

中抜きし過ぎたミニ四駆みたいですが、エリマキみたいなウィングもあるし戦闘機に見えなくもない。


名前は決めていないんですがとりあえず「ジラース」と呼んでいます。
(ジラースを知らない良い子はお父さんに聞いてみよう)

 

 ロックオンした敵を捉える

シューティングゲームということで、敵をロックオンして攻撃する、なんて機能を実現したいです。
その為には当然ながらロックオンした敵の方向へ弾丸を発射する必要があるので、自機を移動させながらもロックオンした敵の方向へ自機を向ける処理を実装しました。

 

オブジェクトを特定のオブジェクトの方向へ向けるメジャーな方法としてtransformコンポーネントのLookAtを使う手法があります。

 

this.transform.LookAt(targetObject.transform,Vector3.up);

 

こんな感じで指定すると、オブジェクトのZ軸方向(forward)をtargetObjectの方向へ向けることできます。


第二引数には上方ベクトルを指定しますがデフォルト引数がVector3.upとなっているので省略可能です。
もし、Z軸方向以外の方向へ向けたい場合は、この第二引数を変更する必要があります。

 

ロックオンを解除する

上記のようにロックオンした敵の方向に向く処理の実装は簡単なのですが、とはいえ、ずっとロックしておく訳にもいきません。
敵が画面の範囲外に移動してしまったり、敵と自機との距離があまりに離れてしまった場合には自動でロックを解除する必要があります。

 

今回の場合は、自機の進行方向と自機の向きとの角度を求めて、それが閾値以上になった場合にはロック解除する、とします。

 

図解するとこんな感じ、点線のベクトル(自機の向き)と実線のベクトル(進行方向)の角度を求めます。

f:id:Karvan:20190702211440p:plain

 

2つのベクトルの角度を求めるにはVector3.Angleを使います
自機の進行方向は常にZ方向なので、敵方向を向いた自機の向きベクトルを計算すればベクトルの角度が計算できます。

  

void Update()
{
	// ロック中の場合
	if(isLockOn)
	{
		// 敵方向を向くベクトル
		Vector3 diff = targetObject.transform.position - this.transform.position;

		// ロックターゲットとの角度計算
		var axisAngle = Vector3.Angle(new Vector3(0.0f, 0.0f, 1.0f), diff);

		 // 閾値以上の場合
		if (axisAngle > ThresholdAngle)
		{
			// ロックを解除する
			isLockOn = false;
		}
		else
		{
			// 敵の方向を向く
			this.transform.forward = diff;
		}
	}
}

 

敵の方向を向く処理には、先ほどはLookAtを使って説明しましたが、上のコードでは敵方向に向くベクトルを求めているで、それを利用してtransform.forwardに直接指定しています。

 

これらを使って実際に動作せるとこんな感じなりました。
敵をロックオンした後、敵との角度が急角度になると自動的にロックを解除しています。

f:id:Karvan:20190702211640g:plain

 

後は弾を打つだけなんですがねぇ。。。。

 

【Unity】ロックオンターゲットをパーティクルで作成する

試行錯誤

次回作についてアレコレ試行錯誤をしていく中で、『(知る人ぞ知る名作ゲーム)DATA WINGっぽいゲームを作ってみよう』などと、おこがましい考えが頭をよぎったのですが、案の定、早々に挫折してしまい、今のところ3Dシューティングゲームの方向でプロトタイプ版を作成している最中です。

 

f:id:Karvan:20190625235025p:plain

 

シューティングゲームなので銃弾を発射するのは当たり前なのですが、他のシューティングゲームでもそうであるように、ただ弾丸が前方に飛ぶだけでなく、敵をロックして誘導弾を発射するといったロックオンシステムも実装しよう、と思うわけです。

 

ここで敵をロックする、ということはそれがプレイヤー側に分かるようにロックオンターゲットを表示する必要があるわけで、今回はこのロックオンターゲットを表示する手法についてのお話

 

ロックオンターゲットの表示

ロックオンターゲットを表示する手法は色々あるのですが、代表的なものとしては

  • uGUIにてターゲットを表示する
  • Spriteでターゲットを表示する

といったような手法があります。

 

どちらの手法でもメリット・デメリットがあり、uGUIを使う場合、ターゲットアイコンはスクリーン上にあるので絶えず同じ形で表示できますが、ロックしたオブジェクトが動くたびにスクリーン上の座標を求めて追従させる必要があります。

 

また、Spriteを使う場合はターゲットアイコンをロックオブジェクトの子オブジェクトにすれば追従させる必要がないので手軽に実装できますが、親オブジェクトの向きに影響されてしまうので、絶えずスクリーンの方を向いて表示させようとするとちょっと面倒くさいです。

 

なので、これらのデメリットを解消するためにParticleSystemを使ってロックオンターゲットを表示させることにしました。

 

参照したのは以下の記事です。

qiita.com

 

ターゲットのアニメーション設定

ParticleSystemでもSpriteのようなアニメーションを設定することが出来ます。
今回はコマ割り画像を連続表示させてターゲットがグリグリ廻るアニメーションを作ります。

 

1.アニメのコマ割り画像を並べて一枚の大きな画像(Texture)を作る。

今回はこんな画像を作りました。

f:id:Karvan:20190625233131p:plain

 

2.そのTextureを指定したマテリアルを作る。

Particles/Additiveなどのシェーダを使ったマテリアルに先程のTextureを指定します。

f:id:Karvan:20190625233215p:plain

見づらいけどTextureに先ほどの画像を指定しています。

 

3.Particle SystemのTexture Sheet Animationでアニメーションを設定する

f:id:Karvan:20190625233338p:plain

 

ModeをGridに指定すると、Tilesと言う項目が現れます。

これは『TestureをX/Yのそれぞれに対して何分割するか』を設定しています。


これに加えてAnimationにWholeSheetを設定することで、テクスチャシート全体を順にアニメーションさせるようにします。

 

その他の設定

上記の設定でターゲットのアニメーションはできました。
次にParticleSystemを以下のように設定していきます。

 

f:id:Karvan:20190625233842p:plain

・LoopingのチェックをONにする

・PreWarmをONにして起動と同時に発生するように

・StartSpeedを0にしてその場に留まるようにする

 

f:id:Karvan:20190625234052p:plain

・RenderのRenderModeをBillboardに設定、併せてRender AlignmentにViewを設定

Billboardに設定することで、ターゲットのParticleは絶えずカメラ方向を向いて表示されるようになります。

 

あとはこのParticleSystemをロックオンしたオブジェクトの子オブジェクトに設定すればロックオンターゲットの完成となります。

 

f:id:Karvan:20190625234138g:plain

ロックオンしたオブジェクトにターゲットParticle表示

 

注意事項と追加

LoopingのチェックをONにしているので、Particleの生成を停止(=Stop)しただけではターゲットは消えません。


ターゲットを非表示にするにはStopコール時に生成済みパーティクルを全消去するオプションを設定するか、ParticleSystem自体のSetActiveをfalseにする必要があります。

 

ロックオンターゲットとしてはこれで十分なのですが、ちょっとコレだけでは地味なので、ターゲットのParticle表示前にロックオン発生のParticleを追加してみました。

 

こんな感じ

f:id:Karvan:20190625234314g:plain

わかりますかね?

ロックオンターゲット表示前に六角形が収縮するParticleを表示しています。

 

なとなくシューティングゲームっぽくなってきた気がしますが、未だ銃弾を撃てないんですよね。。。

 

【Unity】Alipay SDKについての続報

前回からの続報

前回の記事でAlipay SDKの使用を理由にGooglePlayからBANされた場合の対処法を記載しました。

www.karvan1230.com

その記事での紹介した対処法は

現在の回避策は、IAPを使用していない場合はUntiyChannel.libを削除し、Xiaomi Store SDKを追加しないようにすることです。

というものでしたが、当該トピックスに関するUnityForumでの議論は未だ続いているようです。

 

https://forum.unity.com/threads/google-bans-app-due-alipay-sdk.687451/

 

前回記事からの追加の情報としては、

IAPを使用していない、またはXiaomi Game Center SDKを使用していないにもかかわらずこの問題の影響を受けている場合は、Android Studioを使用してBuild / Analyze APK ...を選択し、APKを表示してプロジェクトのルートにあるAndroidManifestを確認し、XiaomiまたはAliPayへの参照を探します。参照が表示されない場合は、ゲームをGoogle Playに再送信しても問題ありません。

と言う返信がUnity Technologiesから上がっています。

 

GooglePlayから同じような理由でBANされていて、プロジェクトフォルダのPulginフォルダ内に「UnityChannel」が見当たらない、と言う方は、上記のように一度、Android Studioを使用してAndroidManifestを確認することをお勧めします。

 

進捗が無い・・・

ここ最近は次回作についてアレコレ試行錯誤して時間を過ごすばかりで、コレといった進捗がありません。

 

そもそも葦名の国でラスボスを倒したけどそのまま二週目を始めちゃってUnity起動してない、って話もありますけど、とりあえず夏までには簡易なプロトタイプ版をunityroomなりに公開できるように頑張りたい・・・と思います。

 

◇プライバシーポリシー

●個人情報の利用目的

当ブログでは、メールでのお問い合わせ、メールマガジンへの登録などの際に、名前(ハンドルネーム)、メールアドレス等の個人情報をご登録いただく場合がございます。

これらの個人情報は質問に対する回答や必要な情報を電子メールなどをでご連絡する場合に利用させていただくものであり、個人情報をご提供いただく際の目的以外では利用いたしません。

●個人情報の第三者への開示

当サイトでは、個人情報は適切に管理し、以下に該当する場合を除いて第三者に開示することはありません。

・本人のご了解がある場合
・法令等への協力のため、開示が必要となる場合

個人情報の開示、訂正、追加、削除、利用停止
ご本人からの個人データの開示、訂正、追加、削除、利用停止のご希望の場合には、ご本人であることを確認させていただいた上、速やかに対応させていただきます。

アクセス解析ツールについて

当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。

このGoogleアナリティクスはトラフィックデータの収集のためにCookieを使用しています。このトラフィックデータは匿名で収集されており、個人を特定するものではありません。
この機能はCookieを無効にすることで収集を拒否することが出来ますので、お使いのブラウザの設定をご確認ください。

●免責事項

当サイトからリンクやバナーなどによって他のサイトに移動された場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。

当サイトのコンテンツ・情報につきまして、可能な限り正確な情報を掲載するよう努めておりますが、誤情報が入り込んだり、情報が古くなっていることもございます。

当サイトに掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。

●プライバシーポリシーの変更について

当サイトは、個人情報に関して適用される日本の法令を遵守するとともに、本ポリシーの内容を適宜見直しその改善に努めます。

修正された最新のプライバシーポリシーは常に本ページにて開示されます。