UE4 で Yaw 軸に回転し続ける Actor を作る

f:id:dany1468:20191124205550p:plain

上記の画像のように Yaw (Z) 軸でその場でぐるぐる回り続けるだけ

BluePrint

Component としては Cube があるだけ。

f:id:dany1468:20191124205821p:plain

なんとか収まったので 1 枚で。

f:id:dany1468:20191124205756p:plain

内容

Delta Seconds 毎に Yaw 軸 180° の Rotator を作成し、AddRelativeRotatorCube に対して相対的に追加。この時点で期待通りにくるくる回る。

その後、その時点の Yaw 値を World 座標に設定して終わりです。実は World 座標に設定し直す理由はよく分かっていません。。

Game Builder : July update: Share actors, custom terrain textures, and more!

steamcommunity.com

Actor の共有

‘CREATE` からできるようになってる。

f:id:dany1468:20190728212055p:plain

f:id:dany1468:20190728212112p:plain

まだ共有されているものは少ないが、簡単にインポートできるし、LOGIC を見ることもできる。

Terrain Texture のインポート

TERRAIN の Texture を選ぶ場所にフォルダ icon が追加されており、そこからローカルにある png を追加できる。
最初に Upload する時に Steam の規約に再度同意する必要があるがそれだけ。

f:id:dany1468:20190728213439p:plain

f:id:dany1468:20190728213449p:plain

インポートした Texture は先頭に追加される。アップロードが終わるまではステータスバーのようなものが出るので、それが消えるまで待つ。 あとは普通に使える。

f:id:dany1468:20190728213534p:plain

Terrain の Rotate

今までそういえばできなかったのかという。

ちょっと分かりにくいが、ROTATE SHAPE (R) というボタンが TERRAIN に追加されている。これを押すよりは R のショートカットキーを使うほうが早い。

f:id:dany1468:20190728214037p:plain

Terrain の CREATE 中に Ctrl を押すと DELETE に

これ、前は CREATE / DELETE でそれぞれ Shift を押すと切り替えになってた気がするんだけど、その挙動は今はないので記憶が定かではない。まあ、こっちのが便利か。

Change Camera CARD

試すと確かにカメラを切り替えられる、そして、そのカメラが他の Actor の子であっても自 Actor の子に移動している。と書きつつ、まあ普通は切り替え対象のカメラも対象 Actor がまとめて持っているんだろうと思う。

Cameras without camera cards no longer reparent (and thus no longer follow) the target actor, for flexibility.

これもリリースノートには入っているが、確かに camera cards を持たないカメラの場合は CAMERA Actor が親を移動することはなかった。

CAMERA PANEL 自体にも Target Actor を指定できるので、Actor の親子関係も含めて、カメラを使うようになったら整理してみたい。

offstage と onstage 関連

・IF-THEN panel can now be made to work offstage.
・Added a Go Onstage card to allow an actor to return to the stage upon receiving an event, for instance.

実際試していないが、これも今までできなかったんだなぁという感じ。

その他

共有カードのインポートにアップされてるものが増えてるよっていう宣伝(というか、このリリースノートが他のもまとめてるのか)が入っていた。確かに覗いてみるとちょっと増えてた。

Game Builder を起動したときに出てくる Workshop にアップされてる一覧も結構面白そうなのが増えてる。ボンバーマン作ってみたいなぁと思ってたら、すでに作ってる人がいた。

Actor の属性みたいなものを初期状態で設定する

「初期状態」というのを表現するのに以下の選択肢がある。

  1. GAME START Panel で trigger する Action CARD を作る
  2. onInit を持つ CARD を作る

初期状態の設定

CARD の設定として簡単に付けられるように props を利用しておくと便利。
以下では onInit を使っているが、 1 の GAME START panel で使う場合には onInitonAction に変えるだけである。

export const PROPS = [
  propActor('target', '')
];

export function onInit() {
  mem.target= props.target

  setVar('target', target);
}

export function onResetGame() {
  delete mem.target;
}

memsetVar

http://gamebuilder.area120.com/setVar.html

Sets a custom variable on the current actor. This is just a key/value pair that gets attached to the actor and can be read by other actors with getVar. All variables get deleted on game reset.

http://gamebuilder.area120.com/mem.html

Memory object for the current actor. This is an object behaviors can freely use to store their state. The contents of this object will depend on what the actor's behaviors have stored it in.

You can use this to store anything that the actor needs to remember from one tick to the next, such as the state it is in, any counters, etc.

Remember to reset any data to its default state on onResetGame.

Note: an actor's memory is private to the actor, so other actors can't access it. If you want to publish a value that other actors can read, you can set it with setAttrib.

card もあるが、 card は CARD 内でしか読めないので、 Actor に対する属性として利用するのは難しい。
mem の最後の説明にあるが、「値を他の Actor からも読めるようにするなら setVar を使う」ということになる。

log(JSON.stringify(mem)); で見てみるとわかるが、 setVar で設定した値は mem の中に __variables として格納されている。

onInit

http://gamebuilder.area120.com/onInit.html

If you implement this function, it will get called when the game is reset, and also when the card has just been added to an actor. You can use this function to initialize your card memory variables.

Game Builder : July 11th, 2019 Release notes

steamcommunity.com

雑多

  • Alt+Click a panel's header to duplicate it
  • Press CTRL+L to toggle Actor List

どちらも地味に便利。

共有カードのインポート

これは結構大きそう。これまでも Steam Community の方で共有されているものはあったけど、それが import をサクッとできるのはありがたい。

Logic の Library から import/export を選べるようになっている。

f:id:dany1468:20190714224502p:plain

上記の一覧に出ている Debug Screen は試してみたが、以下のガイドにあるものが import できるようになったものだと思う。

steamcommunity.com

UI Features

自分が UI を作ることが今のところないので、あまり注目できないが機能追加されているらしい。これを機に試してみたい。

Dead Cells

dead-cells.com

  • 環境: Nintendo Switch
  • プレイした時間: 30 時間ぐらい
  • 進行状況: 王の手は倒したが、それより先にはいけていない

感想

友達に薦められてやってみた。
難易度の高いアクションゲームに苦手意識があったが、2D ということとローグライクゲームというジャンルをやったことが無かったので試してみようという感じ。(後、仮に全然合わなくても値段が手頃なので許容できそう)

やってみては、、とにかく最初はビビりまくっていて、すごい時間をかけて最初の牢獄をクリアした。ただ、結局次のステージであっさり死んでしまった。
何回か繰り返していると、ステージの進行も少しずつするのと、牢獄の最初の部分が変化していったりで「おー、なんか面白い」と少しずつなっていった。

何時間かやってると、死ぬことは慣れてきて、一つのステージを早くクリアすることや、ノーダメージで n 体倒すというのにチャレンジできるようになってきた。
どこかで、ある程度操作も手慣れてきたのか、時計塔から王の手の部分まで一気に進んでしまい、おおおおおっとなったがあっさり死亡。
その後も、何回かチャレンジしていたが、全然勝てそうになく、もっと武器とかアンロックしないといかんなぁと思っていたら、偶然レジェンダリー装備が 2 つ手に入った状態で王の手まで行くことができ、気がつけば倒していた。

ただ、その後はやはりなかなか王の手には勝てず、現在に至る。。

薦めてくれた友達と話していたが、このゲームのストーリーは僕は結構気になったりしたのだけど、友達は途中から気にならなくなったみたいな感じで、ゲームに対するスタンスも変化していて面白いなと思った。

この記事が、考察系では特に面白かった。 jp.ign.com

Collision した Actor からデータをもらう

Actor A と Actor B で Collision した場合に、B から A にデータを受け渡すというケースです。以下の 2 つを例にしてみます。

  1. Actor B から A に send する
    • A が B に Collision した時に、 B 側から A にメッセージを送る形でデータを渡します
  2. Actor B の custom variable から取得する
    • A が B に Collision した時に、A が B を参照し、custom variable の値を読み出す形でデータを受け取る

Actor B から A に send する

Actor B

Damage とかとだいたい同じです。

f:id:dany1468:20190711073000p:plain f:id:dany1468:20190711073021p:plain

Send Any Message の CODE

export const PROPS = [
  propCardTargetActor("Target", {
    label: "Send to:"
  })
];

/**
 * @param {GActionMessage} actionMessage
 */
export function onAction(actionMessage) {
  const target = getCardTargetActor("Target", actionMessage);

  if (!target) {
    return;
  }
  
  send(target, "ReceiveAnyMessage", "送りたいデータ");
}

Actor A

単に send あれたイベントを Receive するだけだとデータが取れないので、以下のようなイベントを作成します。

f:id:dany1468:20190711095527p:plain

まず、Receive Any Message CARD です。
もともとの ReceiveMessage CARD の CODE では card.triggeredEvent{} が入っていて、後続の Action に値を渡せません。よって、以下のように onReceiveAnyMessage で渡ってきた値をそのまま渡しています。

/**
 * @return {GEvent|undefined} The event, if one occurred.
 */
export function onCheck() {
  if (card.triggeredEvent !== undefined) {
    const rv = card.triggeredEvent;
    delete card.triggeredEvent;
    return rv;
  }
  else {
    return undefined;
  }
}

export function onReceiveAnyMessage(properties) {
  card.triggeredEvent = properties;
}

export function onResetGame() {
  delete card.triggeredEvent;
}

次に Say Message CARD です。Say Something CARD とほぼ同じなので、受け取ったデータをどう取り出すかだけ。

export function onAction(actionMessage) {
  const receivedData = actionMessage.event;
}

Actor B の custom variable から取得する

Actor A

custom variable は他の actor からも読めるので、それを利用します。

逆にどの actor からも読めてしまいます

一つ目の例と同じように Collision Event と組み合わせた場合の Action 側の CARD の CODE です。

export const PROPS = [
  propCardTargetActor("Target", {
    label: "Receive from:"
  })
];

/**
 * @param {GActionMessage} actionMessage
 */
export function onAction(actionMessage) {
  const target = getCardTargetActor("Target", actionMessage);

  if (!target) {
    return;
  }
  
  const receivedData = getVar('受け取りたいデータの key', target)
}

Actor B

渡すデータをあらかじめ設定しておきたいとします。

GAME START panel で設定するような Action の CARD を用意します。

f:id:dany1468:20190711092434p:plain

export function onAction() {
  setVar('渡したいデータの key', '渡したいデータ');
}

setVar に関しては object も渡せます。
http://gamebuilder.area120.com/setVar.html

props を使って、CARD の properties として setVar に渡す値を設定できるようにしてもよさそうです。

Game Builder で CARD の CODE を編集するときのログ出力

Debug Action CARD

f:id:dany1468:20190710065039p:plain

とりあえず CARD だけで LOGIC を作っているときにログを出したいときに使う CARD です。 これは Actor が Flush もしますがログメッセージも出します。

実装はとても単純な Action の実装になっています。 ログも二つ出しているだけです。

export function onResetGame() {

}

/**
 * @param {GActionMessage} actionMessage
 */
export function onAction(actionMessage) {
  log(`Action message received`);
  log(actionMessage);
}

ログの確認

~ を押すことで有効になります。赤枠で囲っている部分が Debug Action の表示結果です。 Collision Event に対する Player の Action の場合です。

f:id:dany1468:20190710065437p:plain

actionMessage の表示

場合によるとは思いますが、上記の場合は actionMessage のログが空で表示されています。 log はオブジェクトをプリントできないらしいので、以下のように Debug Action を編集します。

export function onAction(actionMessage) {
  log(`Action message received`);
-  log(actionMessage);
+  log(JSON.stringify(actionMessage));
}

こうすることで以下のような出力を得ることができます。

f:id:dany1468:20190710065935p:plain

CARD の CODE でのログ出力

はい、Debug Action と同じようにできます。 log を使い確認するだけです。また、オブジェクトの場合は (現状) JSON.stringify することでプリントできます。 ログ Viewer で空の表示なったからと焦らず JSON.stringify してみましょう。

Appendix

Game Builder のログ

C:\Users\<user>\AppData\LocalLow\Area 120\Game Builder\output_log.txt にあります。