小ネタ!~LightFunctionって何??~

ライト系のアクター(ポイントライトやスポットライト)の詳細パネルでこのようなものがある。

f:id:Free_Gamer:20180912002108p:plain

LightFunction

 

いったいこれは何かというと・・・

 

光の形状をマテリアルで好きなように設定できるのだ。

 

例えばスポットライトだと光の形状が円錐状になっているが

f:id:Free_Gamer:20180912002314p:plain

LightFunctionを設定すると・・・

f:id:Free_Gamer:20180912002458p:plain

このような表現が可能だ。

 

~やり方~

まずペイントツールで表現したい光の形状を作成しよう。

自分は手裏剣型にした。

f:id:Free_Gamer:20180912002601p:plain

作成した光の形状を、UE4に直接ドラッグ&ドロップでインポートしよう。

f:id:Free_Gamer:20180912002953p:plain

 

マテリアルを作成。名前はとりあえず「M_LightFunction」にした。

f:id:Free_Gamer:20180912003543p:plain

中身はこう。

f:id:Free_Gamer:20180912003221p:plain

詳細パネルは以下のように。

f:id:Free_Gamer:20180912003253p:plain

 

レベル上にスポットライトを配置し、詳細パネル内のLightFunctionに作成した「M_LightFunction」を設定すると・・・

f:id:Free_Gamer:20180912003518p:plain

 

このようになったはずだ。

f:id:Free_Gamer:20180912002458p:plain

シンプルでとても面白い機能だと思う。

 

今のところ使い道はあまり思いつかないが、ナイトクラブとかそういうパーティー系のレベルを作る時にこのLightFunctionを使えばなかなかいい表現が出来るのではないだろうか??

 

もちろんスポットライトだけでなくポイントライトでも設定が可能だ。

ぜひ、自由に試して遊んでみてほしい。

 

それではまた!^^ノシ

 

 

ハイスコア処理で苦労した事!

ハイスコア処理で苦労した点。それは・・・

 

なぜかハイスコアが保存されない(デフォルト値のまま)

 

僕が最初にやっていた処理を見せる。

f:id:Free_Gamer:20180907181140p:plain

処理の内容としては・・・

・Boxコリジョンにプレイヤーがオーバーラップ。現在のステージのセーブデータが存在するかチェック。

f:id:Free_Gamer:20180907181454p:plain

・1回目のプレイはセーブデータが存在しないので、Falseへ。

f:id:Free_Gamer:20180907181422p:plain

・ゲームモードからスコア(タイム)を参照。CreatSaveGameObjectで新規セーブデータを作成し、変数に格納。

f:id:Free_Gamer:20180907181622p:plain

・ハイスコアにも格納。最後にセーブ。

f:id:Free_Gamer:20180907181702p:plain

 

・2回目以降のプレイ。Trueの処理。

f:id:Free_Gamer:20180907181804p:plain

・CreatSaveGameObjectで新規にセーブデータを作成。ゲームモードからスコア(タイム)を参照。変数に格納

f:id:Free_Gamer:20180907181622p:plain

・セーブデータをロード。

f:id:Free_Gamer:20180907182016p:plain

・ハイスコア判定。現在のクリアータイム(スコア)と前回のハイスコアを比較。

f:id:Free_Gamer:20180907200159p:plain

・ハイスコアならTrueへ行き、ハイスコアを上書き。ハイスコアじゃなければFalseへ。

f:id:Free_Gamer:20180907200301p:plain

 

 

 

さて、なぜ

 

なぜかハイスコアが保存されない(デフォルト値のまま)

 

↑のような問題が起きたのか。原因は、

 

 

ステージをクリアーする度、新規にセーブデータを作成していたから。

 

1回目のプレイで、CreatSaveGameObjectで新規に現在のステージのセーブデータを作成。

スコアが保存され、ハイスコアも保存される。

 

もう一度プレイした時、

f:id:Free_Gamer:20180907212752p:plain

またCreatSaveGameObjectで新規にセーブデータを作成しているのだ。

そうなると、前回ハイスコアに保存していた値がリセットされてしまう。

 

セーブデータを記録用紙に例えるなら・・・

 

1回目のプレイの記録用紙が

f:id:Free_Gamer:20180907213454p:plain

ぺらっと新しい記録用紙に変えられて記録されるようなもの。(分かりにくい絵かも・・・)

f:id:Free_Gamer:20180907213602p:plain

 

しかも2回目以降の処理は、

・現在クリアーした時のスコアを保存。

・前回のハイスコアと現在のクリアータイムを比較

 

という流れだ。

 

この時点で

ハイスコアには何も値(スコア)が格納されていない。

 

何故なら、前回のハイスコアの記録が先程の↓イラストのように無くなってしまっているからだ。

f:id:Free_Gamer:20180907213602p:plain

だからハイスコア配列はデフォルト値を返すしかないのだ。

 

ハイスコア配列のデフォルト値は「0」

「0秒」以下でクリアーなど出来るはずもないからどんなに早くクリアーしても一生ハイスコアという事にはならないのである。

 

自分なりに分かりやすく解説したつもりだがどうだっただろう・・・

 

何かの役に立てれば幸い。

 

それではまた!^^ノシ

 

 

 

 

 

 

レベル別でのハイスコア処理!

前回の続きのようなもの。

 

以下の記事で書いたが、

free-gamer.hatenablog.com

 

ステージ数が3つあるゲーム。という体で話を進めてきた。

 

前回まではStage1のみでのハイスコア処理を語ってきたので、今回からは残りの2ステージ、つまり

 

レベル別でのハイスコア処理!

 

を解説していく。

 

レベルはちゃんと3つ作ってあるはずなので、

f:id:Free_Gamer:20180904180616p:plain

「Stage2」レベルを開こう。

 

「Stage2」のレベルBPには、このような処理があるはずだ。

f:id:Free_Gamer:20180904181305p:plain

 

前回でも言ったが、

 

StageID・・・何ステージ目かを示す番号

 

なので、「Stage2」をクリアーした時には・・・

f:id:Free_Gamer:20180906185205p:plain

↑この名前でセーブデータが作成される。

 

「Stage3」は、レベルBPでStageIDを以下のようにセットしてるから、

f:id:Free_Gamer:20180904181321p:plain

↓以下の名前でセーブデータが作成される。

f:id:Free_Gamer:20180906185430p:plain

 

あとの処理は一緒。

レベル(ステージ)が変わり、それによってStageIDが変わって現在のレベル(ステージ)ごとにセーブデータが作成されるだけ。

 

↓赤枠で囲った部分が変わるだけ。あとは変わらない。

f:id:Free_Gamer:20180906185738p:plain

 

これによりレベル別のハイスコア判定ができるわけだ。

 

実際にプレイ。

 

Stage1を「10秒」でクリアー

Stage2を「15秒」でクリアー

Stage3を「20秒」でクリアーしてみる。

 

Stage1

youtu.be

Stage2

youtu.be

Stage3

youtu.be

 

次に全ステージを、前回よりも早くクリアーする。

 

Stage1

youtu.be

Stage2

youtu.be

Stage3

youtu.be

 

左上の文字を見ればわかるが、

「ハイスコア!」と表示されていた。

 

しっかりとレベル別にハイスコア判定が行われてることが分かる。

 

ここまで長々と書き連ねてきたから、色々雑な説明があるかもしれない。

 

だが、画像は比較的多く出してるつもりなので、とりあえず画像の通りにやってみれば、しっかりとハイスコア処理が出来るはずだ。

 

それではまた!^^ノシ

ハイスコア処理!(ハイスコア判定の方法!)

例えば、

1回目のプレイで、ゴールに10秒で着いたとする。

2回目のプレイで、ゴールに5秒で着いたら、10秒よりも早く着いたから「ハイスコア」ということになる。

 

今回はその

 

ハイスコア判定の方法

 

を紹介する。

 

「BP_Goal」を開こう。

変数を用意。

f:id:Free_Gamer:20180904214151p:plain

StageIDは、前回の記事で説明したから割愛。

SaveSlotNameArrayは、String型の配列変数だ。

 

デフォルト値は以下の通りに。

値(文字)は、個人の自由でいい。

ただ、この配列内の文字は「各ステージごとの名称」を表しているという事だけは言っておく。

f:id:Free_Gamer:20180904214324p:plain

 

イベントグラフ

f:id:Free_Gamer:20180903195927p:plain

BP_GoalのBoxコリジョンにオーバーラップしたら、まずこのステージのハイスコアを保存したセーブデータががあるかどうかを確認する。

f:id:Free_Gamer:20180904214843p:plain

DoesSaveGameExistノードは、SlotName名と一致するセーブデータが存在するかどうかを確認するためのノードだ。

存在していればTrue。存在してなければFalseを返す。

f:id:Free_Gamer:20180905182207p:plain

 

例えば、現在のステージが「Stage1」なら

f:id:Free_Gamer:20180904215210p:plain

SaveSlotNameArray内の、Index「0」にある「Stage1」という名のセーブデータがあるかどうかを確認する。といった感じだ。

 

なぜIndex「0」なのか??

「Stage1」のレベルBPで、StageIDが「0」にセットされてるからだ。

f:id:Free_Gamer:20180904181247p:plain

↓前回の記事でも書いたが、

f:id:Free_Gamer:20180904220012p:plain

StageIDは、「現在のステージがいくつ目なのかを示すための変数だ」ということ。

 

つまり、

 

現在プレイしているステージが「Stage1(StageID『0』)」なら、SaveSlotNameArray内のIndex「0」にある「Stage1」という名ののセーブデータがあるかどうかを確認する。

 

という流れだ。

 

「Stage1(StageID『0』)」の

f:id:Free_Gamer:20180905181324p:plain

 セーブデータがあるかを確認する。

f:id:Free_Gamer:20180904215451p:plain

 

だが初回プレイ、つまり1回目のプレイだから普通はセーブデータが存在しない。

だから、DoesSaveGameExistノードによって処理はFalseに流れる。

 

セーブデータが存在しなかった場合の処理

Sequenceノードで順番に処理を行っている。

f:id:Free_Gamer:20180905182724p:plain

 Then0・・・CreatSaveGameObjectノードで現在プレイしているステージのセーブデータを作成

f:id:Free_Gamer:20180905182852p:plain

 Then1・・・「MyGameInstance」から「分」と「秒」を参照。それを「SaveMinute」と「SaveSecond」に格納

f:id:Free_Gamer:20180905182947p:plain

 Then2・・・「MyGameInstance」の「分」と「秒」をハイスコア用の配列に格納

f:id:Free_Gamer:20180905200954p:plain

Then3・・・最後にセーブ。これで現在のスコアとハイスコアの保存が出来た。

f:id:Free_Gamer:20180905201205p:plain

 

2回目以降のプレイ。つまり現在のステージのセーブデータが存在してる場合の処理。ここでもSequenceで順番に処理を行っている。

f:id:Free_Gamer:20180905201331p:plain

Then0・・・現在のステージのセーブデータをロードし、それを変数に格納

f:id:Free_Gamer:20180905201454p:plain

Then1・・・現在クリアーしたタイムを変数に格納

f:id:Free_Gamer:20180905182947p:plain

下のセーブデータが存在しなかった場合の処理に無理やり繋げている。

f:id:Free_Gamer:20180905203529p:plain

Then2・・・ハイスコア判定。

「MyGameInstance(現在クリアーした時点でのタイム)」のスコアと「SaveScore」のハイスコアを比較。

「MyGameInstance」のタイムの方がハイスコアよりも早い場合、処理はTrueに流れる。

逆に、「MyGameInstance」のスコアがハイスコアよりも遅い場合はFalseに。

f:id:Free_Gamer:20180905201825p:plain

例えば、1回目のプレイを10秒でクリアーしたとする。

2回目のプレイを5秒でクリアーしたらハイスコア。(True)

逆に10秒よりも遅い20秒とかでクリアーした場合、ハイスコアではない。(False)となる。

ハイスコアだった場合Trueに処理が流れ、現在のスコアをハイスコアとして配列に上書きする。

ハイスコアじゃない場合は何もない。

f:id:Free_Gamer:20180905203657p:plain

Then3・・・セーブ。

f:id:Free_Gamer:20180905203845p:plain

 

これでプレイしてみよう。

まず1回目のプレイ。セーブデータが存在していない場合の処理

youtu.be

10秒でクリアーした。

分かりやすく左上に「クリアー!」という文字が出ているはずだ。

この時点で、10秒というスコアがハイスコアとして保存された。

 

2回目以降のプレイ。

15秒でクリアーしてみる。

 youtu.be

左上に「ハイスコアではない!」という文字が出てきたはずだ。

 

今度は8秒でクリアーしてみる。

youtu.be

左上に「ハイスコア!」と表示されていたはずだ。

この時点で、前回の「10秒」というハイスコアが「8秒」に上書きされた。

しっかりハイスコア判定がされているのが分かった。

 

かなり長くなってしまった為雑な説明があるかもしれない。

その際はぜひともコメント等で言ってほしい。

 

次回は、今回の引き続きのようなものだ。

 

それではまた!^^ノシ

ハイスコア処理の方法!(下準備)

今回やる事は、

 

ステージ制のゲームでのハイスコア処理

 

だ。

 

ゲーム内容としては、

 

スタート地点からゴール地点まで、何秒でたどり着けるか

というもの。

そして、クリアーした時間が「スコア」となる。速くゴールすればその時の時間が「ハイスコア」となる。

ステージ数は3つ。という体で行く。

 

処理全体。最終的にこうなる。

f:id:Free_Gamer:20180903195927p:plain

あまり1つの記事に長々と書きたくないので(めんどくせぇし)、小分けにして記事を出していく。

 

今回は、下準備だ。

 

用意するもの

ActorクラスのBP(記事内では「BP_Goal」という名前で出てくる)

・GameInstance(記事内では「MyGameInstance」という名前で出てくる)

・GameModeBase(記事内では「MyGameMode」という名前で出てくる)

・3つのマップ(レベル)

・レベルBP

・SaveGame(記事内では「SaveScore」という名前で出てくる)

 

「BP_Goal」の作成

前述の通り、ActorクラスのBPだ。

この「BP_Goal」は、ゴール地点としての役割を担う存在だ。

コンポーネント

f:id:Free_Gamer:20180903201444p:plain

Box・・・オーバーラップコリジョン。プレイヤーがオーバーラップしたらゴール!という判定をする為のもの。

ParticleSystem・・・ゴールだという事を分かりやすくするための目印のようなもの。

 

自分はこんな感じにした。派手な炎エフェクトで分かりやすいだろう。

f:id:Free_Gamer:20180903201653p:plain

変数

「StageID」という名のInteger型の変数だ。

これは、今何ステージ目をプレイしてるのかを示すための変数だ。

今回の処理でとても重要だ。

デフォルト値は「0」のままでいい。

f:id:Free_Gamer:20180904180042p:plain

 

「MyGameInstance」の作成

これはタイマー、つまり時間の「分」と「秒」を格納する為のもの。

今回ハイスコア処理をするうえで重要な存在となる。

変数

f:id:Free_Gamer:20180903202301p:plain

MinuteInstance・・・「分」を格納する為の変数

SecondInstance・・・「秒」を格納する為の変数

 

「MyGameMode」の作成

これは主にタイマー処理を行う為のもの。

処理は以下の通り。

f:id:Free_Gamer:20180903202842p:plain

 

「秒」の処理。

f:id:Free_Gamer:20180903202937p:plain

「秒」と「分」を、ゲームインスタンスに格納

「Minute」は「MinuteInstance」に。

「Second」は「SecondInstance」に。

f:id:Free_Gamer:20180903203131p:plain

「分」を更新する処理

「秒(Second)」が「60」に達した時、つまり「60秒」に達した時

Trueに処理が流れ、

f:id:Free_Gamer:20180904175308p:plain

「分(Minute)」に「1」を足す。つまり、「1分」経ったという事になる。

この時、「秒(Second)」が「60」以上行ったらおかしいから、「秒(Second)」を「0」にセット。

そしてまた「秒(Second)」が1秒おきに更新されていく・・・といった感じだ。

f:id:Free_Gamer:20180904175431p:plain

 

3つのマップ(レベル)の作成

3つレベルを作成する。

ステージ名はそれぞれ分かりやすく「Stage1」「Stage2」「Stage3」にしといた。

f:id:Free_Gamer:20180904180616p:plain

それぞれのレベルにゴール地点の役割を担う「BP_Goal」を配置しよう。

Stage1

f:id:Free_Gamer:20180904180929p:plain

Stage2

f:id:Free_Gamer:20180904180949p:plain

Stage3

f:id:Free_Gamer:20180904181009p:plain

もちろん自分の好きな位置に置いてくれて構わない。

 

レベルBPの作成

それぞれのレベルのレベルBPに以下のような処理を組む。

 

Stage1のレベルBP

f:id:Free_Gamer:20180904181247p:plain

Stage2のレベルBP

f:id:Free_Gamer:20180904181305p:plain

Stage3のレベルBP

f:id:Free_Gamer:20180904181321p:plain

「BP_Goal」から「StageID」変数を参照。

各レベルごとに数値をセットしている。

これは今回の処理でとても重要だ。

 

「SaveScore」の作成

SaveGameクラスのBP。

SaveMinute・・・タイマーの「分」を格納し、セーブする為の変数

SaveSecond・・・タイマーの「秒」を格納し、セーブする為の変数

HighScoreMinute・・・ハイスコアの「分」を格納し、セーブする為の変数

HighScoreSecond・・・ハイスコアの「秒」を格納し、セーブする為の変数

f:id:Free_Gamer:20180905200419p:plain

 

 今回はここまで。

 

次回は、実際にどのようにハイスコア処理をしていくのかを紹介する。

 

それではまた!^^ノシ

 

 

 

 

 

 

 

 

 

 

 

Set Array Elemって何よ!?!?!

今回「Set Array Elem」という気になったノードがあったので、色々調べた。

f:id:Free_Gamer:20180828194707p:plain

このノードは、

 

「指定した配列(Array)の、指定したIndexに、Item(要素)を追加する」

 

というものだ。

 

使用例を紹介しよう。

 

(例)

String型の配列「MyArray」から、指定したIndex(画像だと「3」)のString値をPrintStringで表示。

f:id:Free_Gamer:20180828200254p:plain

「MyArray」の中身

f:id:Free_Gamer:20180828200522p:plain

 

これでプレイすると・・・

f:id:Free_Gamer:20180828200704p:plain

f:id:Free_Gamer:20180828200722p:plain

指定したIndex「3」に入ってた「DANTE」の文字がしっかり表示される。

 

ここで、例えば「DANTE」という名前を他の名前に変えたいとき。

ここで、Set Array Elemを使うのだ。

 

f:id:Free_Gamer:20180828201256p:plain

TargetArray(MyArray)内の、IndexのItem(要素)を変更する。

Index「3」に入ってる「DANTE」を「聖徳太子」に変更だ。

f:id:Free_Gamer:20180828201531p:plain

 

これでプレイすると・・・

f:id:Free_Gamer:20180828202259p:plain

f:id:Free_Gamer:20180828202320p:plain

しっかりと変更されている。

 

プレイ前プレイ中で比べてみよう。

 

プレイ前

f:id:Free_Gamer:20180828203310p:plain

プレイ中

f:id:Free_Gamer:20180828203350p:plain

OK!

 

ちなみに、

f:id:Free_Gamer:20180828203735p:plain

「Size to Fit」というのは、

 

Trueの場合、指定したIndexがTargetArrayのサイズよりも大きい場合、指定したIndexまでTargetArray内のIndexを拡張する。

 

というもの。

 

ちょっと分かりにくいかもしれないので、また例を出しておく。

 

(例)

ここでポイントなのは、Set Array Elem内のIndexに「8」を指定してるところ。

TargetArray内のIndex「8」にItem内の文字を追加している。

本来Target Array内のIndexは「0~5」までなのだが、Size to Fitを使うことで

Target Arrayのサイズを「0~5」から「0~8」に拡張が可能なのだ。

指定したIndexまで拡張が可能。という感じだ。

f:id:Free_Gamer:20180828204726p:plain

 

これでプレイすると・・・

f:id:Free_Gamer:20180828205134p:plain

f:id:Free_Gamer:20180828205408p:plain

しっかり表示。

 

配列内も、プレイ前とプレイ中で確認しよう。

 

プレイ前

f:id:Free_Gamer:20180828205006p:plain

プレイ中

f:id:Free_Gamer:20180828205053p:plain

しっかり配列内が「0~8」まで拡張されて、指定したIndex「8」に指定したItem(要素)が追加されている。

 

以上がSet Array Elemの概要でした!

 

それではまた!^^ノシ

セーブ・ロードの方法!

お久しぶりです!

最近はPS4のDETROIT Become Humenにドハマりしてい為、ブログとUE4の事はすっかり頭からすっ飛んでいたが、ようやく頭と体がUE4に戻りたがってきた為、活動を再開する事にした。

 

DETROIT Become Humen、面白いですよ!(おすすめです!)(宣伝)

 

今回はタイトル通り、「ゲームのセーブ・ロード」の方法だ。

 

意外と簡単なので身構える必要はないと思う。

 

今回は、「自分のステータスと自分の位置をセーブ・ロード」するという形式で行く。

 

SaveGameの作成

SaveGameクラスのBPを作成。

SaveGameは、値の保存を行う事が出来る。金で言えば「ATM」のようなもの。

名前はご自由に。僕は「MySaveGame」と付けた。

f:id:Free_Gamer:20180813011818p:plain「MySaveGame」を開き、2つの変数を用意。

SaveMoney・・・所持金をセーブする為の変数。

SaveLocation・・・キャラの位置をセーブする為の変数。

f:id:Free_Gamer:20180813012338p:plain

デフォルト値は不要。これでSaveGameの設定は以上だ。

 

 

キャラクターBP

変数を用意。

Money・・・所持金(ステータス)デフォルト値「100」Integer型の変数。

イベントグラフ

所持金の減算

「10」ずつ減らしていく。

f:id:Free_Gamer:20180813011345p:plain

セーブ処理

f:id:Free_Gamer:20180813012701p:plain

「CreatSaveGameObject」のSaveGameClassには先程作成した「MySaveGame」を指定。

f:id:Free_Gamer:20180813012830p:plain

 

GetActorLocationで現在の位置を、「SaveLocation」に保存。

現在の所持金「Money」を「SaveMoney」に保存。

f:id:Free_Gamer:20180813013139p:plain

 

「SaveGametoSlot」で、保存した情報に「名前を付けて保存する」処理を行っている(個人的解釈なので間違いの可能性あり)

SlotNameには任意の名前を入力。僕は「SaveSlot」と入れた。

UserIndexはよくわからん。

f:id:Free_Gamer:20180813013512p:plain

ちなみに、保存された内容は自分のPCのフォルダに保存される。

UnrealProjects→プロジェクト名(今回の場合は「TEST」という名前にしてある)→Saved→SaveGamesに保存されている。

先程SlotNameに入力した名前「SaveSlot」という名で保存されている。

f:id:Free_Gamer:20180813014221p:plain

 

ロード処理

f:id:Free_Gamer:20180813014518p:plain

「LoadGameFromSlot」で、保存した内容をロードする。

キャストが必要。「MySaveGame」をキャストする。

f:id:Free_Gamer:20180813014834p:plain

「MySaveGame」から保存した内容(SaveLocation・SaveMoney)を参照する。

SetActorLocationで前回セーブした位置に移動する。

前回セーブした所持金「SaveMoney」をMoneyに渡す。

f:id:Free_Gamer:20180813015043p:plain

 

これでプレイしてみよう!

youtu.be

まず、所持金を50まで減らして、好きな位置でセーブしてみよう!

スタートした位置からかなり離れた位置まで移動し、所持金を50まで減らしてセーブをした。

その後、セーブした位置から遠く離れた場所に移動し、ロードした結果しっかりと前回セーブした位置に移動した。

これで自分の位置がしっかりセーブされているのが分かった!

 

だが、肝心の所持金はどうだろう??

50まで減らしてセーブしたところで、ロードしてからまた減らそうとしてもそのまま40、30、20・・・と減っていくのは当然なのだから、果たして所持金までしっかりセーブされているのか分からないだろう。

簡単に確かめられる。

 

もう一度、ゲームをプレイしてみよう。

youtu.be

先程のセーブした情報が、PCのフォルダにずっと残っているので、いきなりロードが可能。

なので、前回セーブした位置からいきなりロードできる。

普通、プレイ開始して所持金を減らしたら、デフォルト値は「100」なので90、80、70・・・と10ずつ減っていく。

だが、ロードしてから減らしてみると、いきなり40、30、20・・・と減っている。

これで所持金もしっかりセーブされているのが分かった!

 

それではまた!^^ノシ