Saturday, December 29, 2018

Lumberyard 1.17.0.0インストール

Lumberyardの新バージョン1.17が出ました。
私の環境では前回と同様に、最初インストールがfailしました。という事でまたMicrosoft Visual C++ 2017 Redistributable (x64)をアンインストールしてからLumberyardをインストールしました。

Wednesday, December 19, 2018

Amazon Lumberyard学習メモ:Tick毎に処理を行う

前回の続きです。今回は移動とジャンプについての説明です。

こちらが移動とジャンプのスクリプトです。


移動については以前キャラクターで作ったのと同じ処理です。ゲームパッドのアナログスティックの入力値に適当な値を掛け、Add Impulseノードを使って移動させます。
ただ、今回の様にジャンプが入るとそれだけでは不十分です。接地している時と空中にいる時とでは抵抗が異なるので、移動中にジャンプするといきなり移動速度が上がります。
それを防ぐ為に、上記スクリプトではジャンプの入力があった時点で移動に使うImpulseの処理を停止する様にしています。

しかし、ジャンプだけでなく段差からの落下の時も同じ問題が起きます。それを防ぐ為の処理を作るには、まずオブジェクトが空中にいるかどうかの判定を行う必要があります。

コリジョン間の接触検知といえばシューターの実験の時に使ったOn Collisionノードが思い浮かびますが、残念ながら分離は検知出来ない様です。他に接触判定に使えそうな物が分からなかったのでアプローチを変え、「垂直方向の加速度が重力加速度と一致したら落下中=空中にいる」という判定方法を取る事にしました。

Script CanvasのNode Palette内を探したところGet Accelerationというそのままの名前のノードを見つけたのですが、実験したところ何故か値0.0を返します。このノードだけではなくPhysics Componentカテゴリの他のGet系ノード(Get Mass等)も0.0を返す様です。使い方が間違ってるのか?
どうやったら正しい値が取れるのかLumberyardのフォーラムで質問しましたが返事が貰えなかったので、仕方なく加速度を検出するスクリプトを作りました。


やっている事は簡単で、
1)Tick毎にZ座標を取得する
2)二つのZ座標の差をTickのDeltaで割って速度を求める
3)二つの速度差をTickのDeltaで割って加速度を求める
という処理です。
実際は1Tick毎に処理すると数値の揺らぎがあり使い物になる値が得られなかったので、数Tick毎の累積で処理を行う様にしています。ですが累積時間があまりに長いと処理を行っている間にオブジェクトのXY方向の加速が大きくなってしまうので、なるべく短くしなければなりません。今回は2Tickにしました。(これでもよく見ると落下直後にXY方向に微妙に加速しているのが分かってしまいますが…)

垂直方向の加速度との比較に使う値ですが、空気抵抗を考慮して、重力加速度よりもやや小さい8.0としました。また、重要な事ですが、Lumberyard Editor1.16.0.0のエディタのデフォルトの重力加速度は何故か-13に設定されていますので、最初に(というかエディタを起動する度に)値を-9.8に設定し直さなければなりません。設定は以下の様に行います。
1)Tools - Consoleでコンソールを開く
2)コンソール左下隅の(x)アイコンをクリックしてConsole Variablesを開く
3)p_gravity_zの値を-9.8にする


最後に、オブジェクトの移動が終了した時にブレーキがかかる処理を作ります。
下図のスクリプトでは、アナログスティックを傾けた時にDampingを小さく、まっすぐに戻した時にDampingを大きくしています。


オブジェクトのデフォルトのDampingも停止時の値にしておきます。

Amazon Lumberyard学習メモ:Transformが変更される毎に処理を行う

最近フィジックス周りを調べている流れで、汎用の移動オブジェクトを作ってみました。結果的には余り実用的ではない物が出来上がってしまったのですが、色々面白かったので記事にします。



このオブジェクトは二つのEntityで構成されています。一つは足元の球、もう一つはその上にある本体です。下図の様な構成になっています。


球部分は地形や他のオブジェクトの上を移動します。本体部分はその球に追従します。
こちらがスクリプトです。


On Transform ChangedノードはTransformが変更される毎に、つまり球(self)が移動する毎に実行されます。次のGet World Translationノードで球の座標を取得し、次のAddノードでZ座標に任意の値を足して、最後のSet World Translationノードで本体部分の座標をセットします。

ただしこのままゲームを実行すると本体部分が落下しておかしな事になるので、Entity Inspectorで本体部分の質量を0.0に設定しておきます。

これで球が移動すると本体もそれに合わせて移動する様になります。

ところで、最初のムービーでは特に問題はなさそうに見えていますが、実際は厄介な現象が起きます。
ムービー内でRigidが適用された直方体を押しのけて移動していますが、対象物がどれだけ大きい質量を持っていても関係なく押す事が出来てしまいます。本体部分は座標を指定する事で移動させているので反動を受けないんですね。
更に、Staticが適用された物体が相手の場合は全く反動を受けずめり込んでしまいます。


…という事で使い方にかなり制限がありますが、操作するのはなかなか楽しいです。
次回は移動とジャンプ部分の処理について説明します。

Sunday, December 9, 2018

Amazon Lumberyard学習メモ:Tagを使ってコリジョンを識別する

前回からの続きです。今回は目標物を用意し、前回作った弾をぶつけてみます。

参考資料:Script Canvasチュートリアル:エンティティを生成して衝突を検出することによるターゲットの射撃

新規にEntityを作り、Mesh・Mesh Collider・Rigid Body Physicsの各コンポーネントを追加します。Meshにはシステムで用意されているprimitive_cubeをロードしました。
スケールと位置を調整して壁にします。


Play Gameで前回作った弾をぶつけてみます。

上手く作動している様です。

次に弾のSliceを改修し、弾がコリジョンに当たったら弾を消す処理を入れてみます。
Entity Outlinerで右クリックで出るメニューからInstantiate slice...を実行し、ファイルブラウザで前回作った弾のSliceを選びます。


弾のSliceのインスタンスが作成されました。


これにScript Canvasコンポーネントを追加し、新規にスクリプトファイルを作ってロードします。


そのスクリプトファイルに下図のスクリプトを作成します。

On Collisionノードでコリジョンの接触が検知されると、Destroy Game EntityノードでEntityが消去される仕組みです。消去するEntityにはSelfが設定されているので、弾自身が消去される事になります。

改修が終わったのでSliceをセーブしましょう。
Entity Outlinerで右クリックで出るメニューからSave slice overridesに入り、改修したSliceを選択してセーブします。

セーブが終わったらEntity OutlinerでSliceを削除します。

ではPlay Gameでテストです。

壁に接触した時点で弾が消えているのが分かります。

次に、壁にも同じ処理を入れ、弾が当たったら弾と壁の両方が消える様にしてみます。
壁のEntityにScript Canvasコンポーネントを追加します。


そしてこちらにも、弾と同じ内容のスクリプトを作成します。
これで、この壁が他のコリジョンと接触すると壁自身を消去する様になります。


Play Gameでテストしてみます。

…Play Gameを実行すると壁が消えてしまいました。
考えてみれば当然で、壁が地面のコリジョンと接触したのでスクリプトが作動してしまったんですね。

今回は弾のコリジョンとの接触だけに反応させたいので、弾のSliceにTagコンポーネントを追加し、そのTagを検知した時だけ消去するという処理を作ります。

改修の為、再び弾のSliceのインスタンスを作成します。


弾のSliceのインスタンスが作成されました。


Tagコンポーネントを追加します。


Add new child elementアイコンをクリックします。


Tagの項目が追加されます。


ここに任意の文字列を追加します。
今回はbullet_Aという文字列にしました。


弾のSliceをセーブします。


セーブが終わったらEntity OutlinerでSliceを削除します。

次は壁の方の作業です。
壁のScript Canvasコンポーネントからスクリプトを開きます。


Script Canvas右下のCreate Variableをクリックします。


使用出来る変数(variable)のリストが表示されます。そこからCollisionを選択します。


Collisionタイプの変数が作成されます。それをScript Canvas内にドラッグ&ドロップし、メニューからSet(変数名)を選びます。


変数をセットするノードが作成されます。


下図の様に接続します。


Setを作成したのと同じ手順でGetも作成します。


Script Canvasの左カラムから必要なノードを選んで追加し、下図のスクリプトを作成します。Destroy Game Entityは処理の最後に移動させました。
赤字が処理の説明です。


これで、特定のTagを持つオブジェクト(今回は弾)が接触した時だけ壁が消える様になりました。

ですがテストした所、このままだと処理が動きません。どうも接触時に弾が先に消えてしまって接触が検知されない様です。そこで、弾のスクリプトに遅延処理を入れる事にしました。
これはスクリプトだけの改修なので、先程までの様に弾のSliceのインスタンスを作成する必要は無く、Script Canvasでの作業になります。

Script CanvasのFile - Openで弾のSliceで使っているスクリプトファイルを開きます。


こちらが弾のスクリプトです。


下図の様にDelayノードを入れ、Timeを0.001に設定します。


テストしてみます。

弾が当たると弾と壁の両方が消える様になりました。

上手く行きましたが、考えてみたら壁の方にも同じ遅延処理を入れておかないと逆の状況が発生する可能性があるのでは…ですが面倒なので今回はこれで済ませます。これを応用する事があったらその時そうしよう。

さて、1回の着弾で壁が消えるのは何かあっさりしている気がするので、複数回の着弾で消える様に変更します。
壁のスクリプトの最後のDestroy Game Entityの直前に、下図の様にインクリメント処理を挟みます。


3回の着弾で壁が消える様になりました。


前回から書いてきましたシューターに関する記事は以上です。
ところで何故この辺りを色々調べていたかというと、こちらのキャラクターのパンチを作る為です。

要は腕の位置で短射程の射撃を行っているのと同じ事です。射程はTriggerで設定しています。

Saturday, December 8, 2018

Amazon Lumberyard学習メモ:ゲーム実行中にオブジェクトを生成する

今回から、公式サイトのシューターを作るチュートリアルを元に色々分かった事を書いていきます。

参考資料:Script Canvasチュートリアル:エンティティを生成して衝突を検出することによるターゲットの射撃
Spawnerコンポーネントのリファレンス

さて、シューターを作るには銃・弾・目標物が必要です。
まずは弾の作成です。

Entityを作成します。


作成したEntityに名前を付けます。今回はTest_Bullet_00という名前にしました。


このEntityに、Add Componentで以下のコンポーネントを追加します。
・Mesh
・Mesh Collider
・Rigid Body Physics
Meshコンポーネントにはシステムに用意されているprimitive_sphereをロードしました。

なお、Rigid Body Physicsとコリジョンが適用されたオブジェクトであれば構成は何でも良いので、Primitive Colliderを使っても構いません。

弾となる球が出来ました。


このEntityをEntity Outlinerで右クリックし、メニューからCreate slice...を実行します。


ファイルブラウザーが表示されますので、任意の場所に.sliceとしてセーブします。
セーブが終わるとEntity Outliner上での表示がこんな感じに変わります。


Tools - Asset Browserを実行します。


Asset Browserで先程セーブしたSlice(.sliceファイル)を右クリックし、メニューからSet Dynamic Sliceを実行します。


以上で、とりあえず弾として使えるオブジェクトが用意出来ました。
セーブが終わったSliceはEntity Outlinerから削除します。


次は銃の作成です。(ただし銃といっても今回は弾を生成する機能だけのオブジェクトで、メッシュは載せません。)

新規Entityを作成します。


名前を付けます。今回はGunという名前にしました。


このEntityに以下のコンポーネントを追加します。
・Input
・Script Canvas
・Spawner


今回InputにはゲームパッドのAボタンを割り当て、Event Nameはfireと付けました。


Script Canvasのスクリプトは以下の様にします。

これで、ゲームパッドのAボタンを押すとオブジェクトが生成される様になります。

生成するオブジェクトはSpawnerコンポーネントで指定します。
SpawnerコンポーネントのBrowseアイコンをクリックしてファイルブラウザを出し、先ほどセーブした弾のSliceファイルをロードします。


ロードされました。


では、Play Gameでテストしてみます。

ゲームパッドのAボタンを押すと弾のSliceが生成されました。

生成が上手くいったので、次は弾を飛ばす処理を作ります。
Script CanvasでSpawnerノードとSet Velocityノードを使い、下図の様にスクリプトを作成します。


このスクリプトは以下の様に動きます。

ゲームパッドのAボタンを押すとfireイベントが発行され、それに従ってInput Handlerが処理を開始し、SpawnノードがEntityを生成します。
Spawnerノードを使うと生成されたEntityがどれなのかが分かるので、Set VelocityノードでそのEntityに速度を与えます。

Play Gameでテストです。

弾が飛ぶ様になりました。

もし飛ばなければ、下図の様にDelayノードを挟んで、生成後にわずかに時間を置いてから速度を与える様にします。この図ではTimeを0.03にしていますが、場合によっては何故か0でも上手く行く事があります。


次回は目標物を用意して弾をぶつけてみます。