rn.log

備忘録など

UE4未経験者が5日間でインベーダーゲームを作った話

はじめに

UE4未経験な私が5日間で単純なゲームを完成させることができたので、まとめたいと思います。

作ったゲーム

上から迫ってくるエネミーたちを撃ってKILLするゲームです。 いわゆるインベーダーゲーム
f:id:r-ngtm:20180208103213g:plain

全てのエネミーを倒すとクリア
f:id:r-ngtm:20180208103347g:plain

エネミーが撃つ弾に触ってしまうとゲームオーバーです。
[f:id:r-ngtm:20180208103507g:plain

エネミーが下まで来てしまってもゲームオーバーです。
f:id:r-ngtm:20180208104237g:plain

開発環境

Windows 10
UE4.18.3

学習開始時のUE4スキル

UE4の学習を始めた時点での私のUE4スキルを挙げると以下の通りです。
・2年前にUE4インストールしたことがある
・2年前にレベルブループリントを使って画面に"Hello"と表示させたことがある。
UE4ゲームを作ったことは無い

これはUE4未経験といっても差し支えないでしょう。
そんなUE4未経験な私が5日間でインベーダーゲーム完成させるまでの過程を紹介したいと思います。

学習の流れ

以下の流れで学習とゲーム作成を行いました。
・初日~3日目 : UE4の基本を覚える
・4~5日目 : インベーダーゲームを作る

初日~3日目 : UE4の使い方を覚える

最初にやった事はUE4の基本を覚えること。人から勧められた下記の書籍を読みました。

www.borndigital.co.jp

全ての章を読んだ訳ではなく、6章~12章だけを読みました。
また、この書籍にはハンズオン動画が付いており、これを観ながらUE4の学習を進めました。

書籍だけを読むよりハンズオン動画を観たほうが速いです。ハンズオン動画オススメ

覚えたことは全部メモする

今回、一度覚えたことは忘れないようにGoogleスプレッドシート全てメモする、という事をやっていました。

f:id:r-ngtm:20180208105257p:plain

覚えたことを忘れてしまった場合でも、メモを作ってるおかげですぐに思い出すことができます。
調べ直す手間を省略することができます。

メモしたもの

GoogleSpreadシートにメモしたものは主に以下のものです。
・分からないことを調べていた時に見つけたWebサイトのURL
・ショートカットキー
・エディタの操作方法
・ブループリントで使用したノード
・マテリアルで使用したノード
コンポーネント

1回調べた物は2度調べなくていいように全てをメモします。
こうすることで時間を節約することができます。

4~5日目 : インベーダーゲームの開発

6~12章を読み終えたところで基礎をおさえることができました。
4日目からインベーダーゲームの作成に取り掛かります。

プロジェクトの新規作成

テンプレート; "TwinStickExample" を使用して新規プロジェクトを作成しました。

プレイヤーキャラの実装

TwinStickExampleではキーボード操作の上下左右移動が実装されています。
f:id:r-ngtm:20180208112702g:plain

今回はインベーダーゲームを作りたいのでこれを改造し、左右だけに移動するようにしました。
f:id:r-ngtm:20180208113056g:plain

また、弾の上下左右発射が実装されていたのでこれを改造し、マウスボタンを押しているときにだけ上方向に弾を発射するようにしました。

Tips: マウスの入力をとる方法

プロジェクト設定のAxisMappingを利用してマウス入力をとっています。
f:id:r-ngtm:20180208114345p:plain:w300

AxisMappingで設定した入力はブループリント側から取得することができます。
f:id:r-ngtm:20180208114459p:plain:w300

弾を生成するFactoryクラスを用意

弾を生成部分のロジックがかなり複雑なので、ロジックを見やすくするために専用のFactoryクラスを用意することにしました。
f:id:r-ngtm:20180208120706p:plain

中身はこんな感じです。
f:id:r-ngtm:20180208121005p:plain:w400

このFactoryクラスは位置と向きを指定して弾を生成するFireShot関数を持っています。
FireShot関数はTwinStickPawnが持つFireShot関数をベースとして作成しました。

エネミーキャラの用意

TwinStickExampleではプレイヤーが操作する水色の機体が用意されています。
f:id:r-ngtm:20180208112328p:plain

これを複製してマテリアルを差し替え、エネミー用の赤い機体を用意しました。
f:id:r-ngtm:20180208120359p:plain

また、一定時間ごとに弾を下方向に発射するようにロジックを改造しました。
f:id:r-ngtm:20180208121445p:plain

エネミーのFireShow関数の中身はこんな感じ。
f:id:r-ngtm:20180208121610p:plain

Factoryクラスを作ったことおかげで、エネミーの弾の発射ロジックを簡潔に組むことができました。

エネミーのジグザグ移動の実装

エネミーのジグザグ移動の実装にはスプライン曲線を利用しました。

下記URLを参考に作成しました
[UE4] スプライン上を動く足場の作り方|株式会社ヒストリア

壁の用意

インベーダーゲームでは弾を防ぐ壁があるので、これを実装しました。
f:id:r-ngtm:20180208122028p:plain

壁の仕様は以下の通りです
・壁に弾が当たったら弾を消す
・壁にはHPがある
・弾が当たると壁そのもののHPが削れ、サイズも小さくなる
・壁のHPがゼロになったら壁は消滅

詳細は割愛しますが、壁のブループリントのイベントグラフだけ載せておきます。
f:id:r-ngtm:20180208122941p:plain:w400

弾の改造

今回は「弾はプレイヤーのものなのか、エネミーのものなのか」という情報を持たせたいので、TwinStickProjectileには列挙型PawnType型の変数を持たせます。
f:id:r-ngtm:20180208124032p:plain
f:id:r-ngtm:20180208123909p:plain

列挙型PawnTypeにはPLAYERとENEMYの二つを持たせています。
f:id:r-ngtm:20180208124503p:plain:w300
f:id:r-ngtm:20180208124304p:plain:w300

ちなみに、列挙型は自分で作る必要があります。
f:id:r-ngtm:20180208124556p:plain:w300

エネミー死亡判定

エネミーにプレイヤーの弾が当たったときにエネミーが死ぬようにします。
f:id:r-ngtm:20180208123344p:plain

判定時に弾のPawnTypeを見て、弾がプレイヤーのものだった場合にエネミーを破棄するということをやっています。

ゲームオーバー・ゲームクリア表示の用意

ゲームクリア表示・ゲームオーバー表示はWidgetを使っています。
f:id:r-ngtm:20180208125021p:plain

ゲームオーバー時に表示を出す

プレイヤーに弾が当たったときにプレイヤーが死んでGameOverが表示されるようにします。
f:id:r-ngtm:20180208125341p:plain
f:id:r-ngtm:20180208125234p:plain

完成

以上でインベーダーゲームの完成です。

f:id:r-ngtm:20180208103213g:plain

【UE4】経過時間を表示するテキストを画面に出してみる

はじめに

UE4を触っていた時に出てきた疑問。
UIを画面に表示させるにはどうすればいいんだろう? ゲーム内のスコアとか画面に表示させたいな....」

そこで今回はUIを作り方の勉強の一環として、ゲーム開始からの経過時間を表示するテキストを画面に出す方法をまとめてみました。

作ったもの

ゲーム再生からの経過時間を表示するテキストを画面に出してみました。
f:id:r-ngtm:20180207113751g:plain

作成手順

STEP1. Widgetを作成する
STEP2. WidgetにTextを設置する
STEP3. ブループリントを使ってゲーム開始時にWidgetを画面に出す
STEP4. 経過時間をTextへ反映するイベントグラフを組む

STEP1. Widgetを作成する

コンテンツブラウザの右クリックメニューからWidgetを作成します
f:id:r-ngtm:20180207110020p:plain

名前は UI_HUDとしておきます。

f:id:r-ngtm:20180207110107p:plain

STEP2. WidgetにTextを設置する

作成したWidgeアセットを開き、ドラッグ&ドロップでTextを配置します。

f:id:r-ngtm:20180207110756g:plain

Textの名前は HogeText としておきます。

STEP3. ブループリントを使ってゲーム開始時にWidgetを画面に出す

レベルブループリントを開き、以下のイベントグラフを組みます。

f:id:r-ngtm:20180207110337p:plain

ウィジェットを作成ノード」Widgetを作成し、「Add to Viewportノード」を使ってWidgetを画面に追加しています。

確認してみる

この状態でゲームを再生すると、以下のような画面になります。

f:id:r-ngtm:20180207111207p:plain

Widgetが画面に出ていることが確認できます。

STEP4. 経過時間をTextを反映するイベントグラフを組む

次に、経過時間をTextに反映させるようにします。

WidgetHogeTextを選択し、詳細パネルでContent/Textのバインドボタンをクリックして「バインディングを作成」を選択します。
f:id:r-ngtm:20180207111934p:plain

イベントグラフが作成されるので、リターンノードにGet Game Time in Secondsノードを接続します。

確認してみる

この状態でゲームを再生すると、テキストに経過時間が反映されるようになります。

f:id:r-ngtm:20180207112749g:plain

ゲーム内経過時間を表示するテキストを作ることができました。

まとめ

・UIを作るにはWidgetアセットを作成すると良い

Widgetアセットを画面に表示させるにはウィジェットを作成ノード」Widgetを作成し、「Add to Viewportノード」を使ってWidgetを画面に追加する。

Widget表示を動的に変更するにはバインディングを作成すると良い

バインディングで作成した関数のリターンノードに渡したデータはUIに反映される

参考

Unreal Engine | プロパティのバインディング



豆知識: バインディングには変数も設定できる

バインディングにはWidgetのイベントグラフで定義した変数も使用できます。
f:id:r-ngtm:20180207115832p:plain

f:id:r-ngtm:20180207115908p:plain

【UE4】マテリアルのUVスケールをランダム変更するブループリントを組んでみた

最近、UE4をまじめに勉強し始めました。
ぷちこん提出したい。

マテリアルをコンパイルせずに変えたい

ここからが本題ですが、マテリアルを触っていた時の疑問
「マテリアルをコンパイルせずにテクスチャUVスケールを変えるにはどうすればいいんだろう?」

これを解決するために調べながら作ったものをまとめてみます。

今回作ったもの

今回は勉強がてら、マテリアルのテクスチャUVスケールをランダムに変えるブループリントを組んでみました。

f:id:r-ngtm:20180206113424g:plain

環境

UE4.18.3
テンプレート : Twin Stick Shooter

作成手順

STEP1. UVスケールのfloat値を持ったマテリアルコレクションを用意

STEP2. マテリアル内部でマテリアルコレクションのUVスケールを取得してテクスチャに適用

STEP3. ブループリント側からマテリアルコレクションのUVスケール値をランダムに変更

STEP1. マテリアルコレクションの用意

マテリアルに外部からパラメータを渡すにはマテリアルコレクションを使います。

まずは右クリックからマテリアルコレクションを作成。
f:id:r-ngtm:20180206111744p:plain

マテリアルコレクションの名前はMC_Floorとしておきます。
f:id:r-ngtm:20180206111820p:plain

マテリアルコレクションの設定

マテリアルコレクションにはUVスケール値として2つのfloat値 ScaleXScaleYを追加しておきます。

f:id:r-ngtm:20180206112202p:plain

STEP2. マテリアルの作成

右クリックメニューからマテリアルを作成します。
f:id:r-ngtm:20180206121209p:plain

以下のようなマテリアルを組みました。
f:id:r-ngtm:20180206112322p:plain

マテリアルコレクションのScaleXとScaleYを使ってテクスチャをUVスケールしています。

マテリアル解説

左端にある緑色のノードはCollectionParameterノードです。
STEP1で作成したマテリアルコレクションからfloat値を取得しています。

f:id:r-ngtm:20180206121828p:plain

MakeFloat2ノードを使い、取得したScaleXとScaleYからfloat2を作成しています。
f:id:r-ngtm:20180206112607p:plain

テクスチャのスケールを変更するにはTextureCoordinateノードを使用します。
f:id:r-ngtm:20180206114649p:plain

今回は、マテリアルコレクションを使ってスケール値を変更したいので、ScaleUVsByCenterノードを使って 乗算したものをTextureSampleノードのUVsに入力しています。

STEP3. ブループリントを組む

以下のようなイベントグラフを組みました。
f:id:r-ngtm:20180206115409p:plain
1秒ごとにマテリアルコレクションのScaleXとScaleYを 1~2間のランダムなfloatに設定するイベントグラフです。

ブループリント解説

イベントTickノードにDelayノードをつなげることで1秒ごとにイベントが発火するようにしています。
f:id:r-ngtm:20180206115539p:plain

RandomノードにLerpノードをつなげることで、1-2の間のランダムなfloat値を取得しています。
f:id:r-ngtm:20180206115841p:plain

SetScalarParameterValueノードを使い、マテリアルコレクションMC_Floor内部の変数の値を変更しています。
f:id:r-ngtm:20180206120029p:plain

まとめ

・マテリアルをコンパイルせずにパラメータを変更するにはマテリアルコレクションを使う。
マテリアル内部でマテリアルコレクションにアクセスするにはCollectionParameterノードを使う
・TextureCoordinateノードの出力をパラメータで乗算するにはScaleUVsByCenterノードを使う
ブループリントからマテリアルコレクションを変更するときはSetScalarParameterValueノードを使う。

【プレイ感想】モンハンワールドはストレスが少ない

モンハンワールドを買いました。

まだ3時間しかプレイしていませんが感想を。

良かった点

・テンポ感が良くなった
・マップの単調さが減った

悪かった点

・拠点で迷う
・文字が小さすぎて読みづらい

良かった点

今までのモンハン = 採集のテンポが悪い

個人的に今までのモンハンで一番不満だった点は、採集モーションが長く退屈だということ。

私はPSPのモンハン2ndGから入り、NintendoSwitchのモンハンダブルクロスまでプレイしましたが、

その間採集モーションが全く変わっていません。 


おっさんがしゃがんで素材をかき集める採集モーションは数千、数万回は眺めているんじゃないでしょうか。

同じモーションを眺めるのは正直飽きました

おまけに、モーション完了までの時間が地味に長い


採集モーションを眺めるのは退屈で、苦痛だというのが正直なところです。

今回のモンハン = 採集のテンポが良い 

この退屈な採集モーション、モンハンワールドでは短くなります。

そして素材回収も簡略化され、短いモーションを1回(特殊な素材の場合は数回)見るだけで素材の回収が完了します。

テンポ感が格段に良くなりました。


例えば、今までのモンハンではハチミツ5個集める時に採集を5回繰り返す必要がありました。

モンハンワールドの場合、1回のモーションで全てのハチミツを回収します。

素材をサクサク集めることができるので快適です。

今までのモンハン = マップ移動時にロードが入る

今までのモンハンだとマップ移動時にローディングが入っていました。

マップ1からマップ2へ移動するときにロード、 マップ2からマップ3へ移動するときにもロード。

このロード処理、ロード完了を待つのがなかなかの苦痛です。 

今回のモンハン = マップ移動のロードが無い

モンハンワールドを2時間ほどプレイしてようやく気が付いたんですが、なんとこのモンハンワールド、

ロード処理が皆無です。ゼロ回です。

おそらく、クエスト開始時にマップをメモリに展開するか、ゲームプレイ中に裏で動的にマップをロードしているのでしょうか。

ロード処理がなくなったことによってゲームプレイの没入感が上がったように思います。

ストレスが減って素晴らしい。

今までのモンハン = 移動が退屈

これまでのモンハンシリーズでは、マップの高低差が少ない平たいマップであることが多かったです。

つまり、プレイしていても代わり映えがあまり無いマップになっています。


移動時にプレイヤーがやることは、目的地への最短経路をただ走るだけという単純作業。

モンハンを始めたころはまだ良いですが、繰り返しプレイしていると正直飽きます

移動が退屈で、苦痛で仕方がない。

今回のモンハン = 移動が刺激的

今までのモンハンだと高低差のあまり無い、平たい地形だったので地図を見ていれば道に迷うことはまずありませんでした。

迷わないので、退屈


モンハンワールドの場合、高低差が激しく、かなり複雑な地形になっています。

私は地図を見ていても迷いました

地形が複雑になったことにより、冒険をしている感があって楽しい。

マップの要素が増えた

おまけに、モンハンワールドでは天井には仕掛けがあったり、空中にモンスターがいたり、地面では痕跡があったり、といろんな要素がマップのあちらこちらに散りばめられています。


今までのモンハンと比べてマップ移動時にやることが爆発的に増え飽きさせない作りになっていると感じました。

素晴らしい。

悪かった点

拠点で迷う

初回プレイ時、拠点でクエストの受付嬢がどこにいるのかが分からなくなり、1時間ほど迷ってしまいました。

地図を見ても、受付嬢の居場所が載っていない。

ここがちょっと不親切に感じました。

文字が小さい

プレイに支障をきたすレベルで画面の文字が小さいと思いました。
読めない。

設定メニューから文字サイズを大きき変更できるようにしてほしかったと思いました。

目が悪い人には不親切かも。

「メガネを買え」ということなのかもしれません。

【Unity2018.1】Particle Systemを軽く覗いてみた

Unity2018.1のParticleSystemを軽く覗いてみました。

ParticleSystemの機能のうち、気になったものを紹介していきたいと思います。

環境

Unity2018.1.0b2

WIndows 10

機能その1: パーティクル再生終了時に処理を実行する Stop Action

パーティクルの再生終了時処理を実行する機能です

f:id:r-ngtm:20180115190330p:plain

Stop Actionを使うにはMainモジュールのLoopingのチェックを外しておく必要があります。
(チェックが入っていると再生終了しないため)

詳細

Stop Actionの選択項目は4種類あります。

f:id:r-ngtm:20180115190521p:plain

None = 何もしない
Disable = 再生終了時に自身のGameObjectを非アクティブ化
Destroy = 再生終了時に自身のGameObjectを破棄
Callback = 再生終了時に自身のコールバックを呼び出す

コールバックの使い方

下記スクリプトをParticleSystemにアタッチすると再生終了時にOnParticleSystemStopped()が実行されます。(Stop Action = "Callback"の場合のみ)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ParticleTest : MonoBehaviour
{
    void OnParticleSystemStopped()
    {
        Debug.Log("OnParticleSystemStopped");
    }
}

機能その2:パーティクルの初期色にテクスチャを使う

パーティクルのテクスチャを使用して設定できるようになりました。

f:id:r-ngtm:20180115191218p:plain

これを使うとテクスチャから湧き出るようなエフェクトが作れます。

f:id:r-ngtm:20180115184600g:plain


魔法陣エフェクトとかも簡単に作れそう。いろいろ応用がききそうな機能です。

f:id:r-ngtm:20180115185013g:plain

iPhoneXのアルファ抜きフレーム画像

iPhoneXの開発時にあると便利そうなフレーム画像。

探しても全然見つからないのでPhotoshopでサクッと作ってみました。

汎用性が高そうなので公開します。

たて (Portrait)

1125 x 2436 ピクセル

よこ (Landscape)

2436 x 1125 ピクセル

【Windowsコマンド】複数のMSペイントをまとめて消す

はじめに

私はMSペイントを使ってスクリーンショットの切り抜きをよくやるのですが、大量のMSペイントを起動してしまうことがよくあります。

MSペイントを大量に起動してしまった場合、これらをマウス操作で消していくのはなかなか大変です。

今回の記事では複数のMSペイントをコマンド一発で全部まとめて消す方法を紹介します。

MSペイントの厄介な敵 : 保存確認ダイアログ

MSペイントですが、閉じようとすると保存確認ダイアログが表示されてしまいます。 

f:id:r-ngtm:20180109163713p:plain

MSペイントを1,2個起動しているだけならまだいいですが、10、20個も起動してしまった場合は厄介です。

「保存しない」を10回も20回もクリックしないと全てのMSペイントを閉じられない。 面倒くさい。

コマンドを使うと全部まとめて消せる

「保存なんてしなくていいから全部まとめて消したい!

という場合はtaskkillコマンドを使うと複数のMSペイントを一気に消すことができます。

STEP1. コマンドプロンプトを素早く起動

「ファイル名を指定して実行」ウィンドウに cmd と入力するとコマンドプロンプトが起動できます。

f:id:r-ngtm:20180109170228p:plain:w250

Win + X を押した後 R を押すと「ファイル名を指定して実行」ウィンドウを手早く起動できます。

STEP2. taskkillコマンドでMSペイントをまとめて消す

以下のコマンドを実行すると実行中のすべてのMSペイントを強制終了します。

taskkill /im mspaint.exe /f

参考: Windowsでプロセスを強制終了するコマンド