ハイスコア処理!(ハイスコア判定の方法!)
例えば、
1回目のプレイで、ゴールに10秒で着いたとする。
2回目のプレイで、ゴールに5秒で着いたら、10秒よりも早く着いたから「ハイスコア」ということになる。
今回はその
ハイスコア判定の方法
を紹介する。
「BP_Goal」を開こう。
変数を用意。
StageIDは、前回の記事で説明したから割愛。
SaveSlotNameArrayは、String型の配列変数だ。
デフォルト値は以下の通りに。
値(文字)は、個人の自由でいい。
ただ、この配列内の文字は「各ステージごとの名称」を表しているという事だけは言っておく。
イベントグラフ
BP_GoalのBoxコリジョンにオーバーラップしたら、まずこのステージのハイスコアを保存したセーブデータががあるかどうかを確認する。
DoesSaveGameExistノードは、SlotName名と一致するセーブデータが存在するかどうかを確認するためのノードだ。
存在していればTrue。存在してなければFalseを返す。
例えば、現在のステージが「Stage1」なら
SaveSlotNameArray内の、Index「0」にある「Stage1」という名のセーブデータがあるかどうかを確認する。といった感じだ。
なぜIndex「0」なのか??
「Stage1」のレベルBPで、StageIDが「0」にセットされてるからだ。
↓前回の記事でも書いたが、
StageIDは、「現在のステージがいくつ目なのかを示すための変数だ」ということ。
つまり、
現在プレイしているステージが「Stage1(StageID『0』)」なら、SaveSlotNameArray内のIndex「0」にある「Stage1」という名ののセーブデータがあるかどうかを確認する。
という流れだ。
「Stage1(StageID『0』)」の
セーブデータがあるかを確認する。
だが初回プレイ、つまり1回目のプレイだから普通はセーブデータが存在しない。
だから、DoesSaveGameExistノードによって処理はFalseに流れる。
セーブデータが存在しなかった場合の処理
Sequenceノードで順番に処理を行っている。
Then0・・・CreatSaveGameObjectノードで現在プレイしているステージのセーブデータを作成
Then1・・・「MyGameInstance」から「分」と「秒」を参照。それを「SaveMinute」と「SaveSecond」に格納
Then2・・・「MyGameInstance」の「分」と「秒」をハイスコア用の配列に格納
Then3・・・最後にセーブ。これで現在のスコアとハイスコアの保存が出来た。
2回目以降のプレイ。つまり現在のステージのセーブデータが存在してる場合の処理。ここでもSequenceで順番に処理を行っている。
Then0・・・現在のステージのセーブデータをロードし、それを変数に格納
Then1・・・現在クリアーしたタイムを変数に格納
下のセーブデータが存在しなかった場合の処理に無理やり繋げている。
Then2・・・ハイスコア判定。
「MyGameInstance(現在クリアーした時点でのタイム)」のスコアと「SaveScore」のハイスコアを比較。
「MyGameInstance」のタイムの方がハイスコアよりも早い場合、処理はTrueに流れる。
逆に、「MyGameInstance」のスコアがハイスコアよりも遅い場合はFalseに。
例えば、1回目のプレイを10秒でクリアーしたとする。
2回目のプレイを5秒でクリアーしたらハイスコア。(True)
逆に10秒よりも遅い20秒とかでクリアーした場合、ハイスコアではない。(False)となる。
ハイスコアだった場合Trueに処理が流れ、現在のスコアをハイスコアとして配列に上書きする。
ハイスコアじゃない場合は何もない。
Then3・・・セーブ。
これでプレイしてみよう。
まず1回目のプレイ。セーブデータが存在していない場合の処理
10秒でクリアーした。
分かりやすく左上に「クリアー!」という文字が出ているはずだ。
この時点で、10秒というスコアがハイスコアとして保存された。
2回目以降のプレイ。
15秒でクリアーしてみる。
左上に「ハイスコアではない!」という文字が出てきたはずだ。
今度は8秒でクリアーしてみる。
左上に「ハイスコア!」と表示されていたはずだ。
この時点で、前回の「10秒」というハイスコアが「8秒」に上書きされた。
しっかりハイスコア判定がされているのが分かった。
かなり長くなってしまった為雑な説明があるかもしれない。
その際はぜひともコメント等で言ってほしい。
次回は、今回の引き続きのようなものだ。
それではまた!^^ノシ
ハイスコア処理の方法!(下準備)
今回やる事は、
ステージ制のゲームでのハイスコア処理
だ。
ゲーム内容としては、
スタート地点からゴール地点まで、何秒でたどり着けるか
というもの。
そして、クリアーした時間が「スコア」となる。速くゴールすればその時の時間が「ハイスコア」となる。
ステージ数は3つ。という体で行く。
処理全体。最終的にこうなる。
あまり1つの記事に長々と書きたくないので(めんどくせぇし)、小分けにして記事を出していく。
今回は、下準備だ。
用意するもの
・ActorクラスのBP(記事内では「BP_Goal」という名前で出てくる)
・GameInstance(記事内では「MyGameInstance」という名前で出てくる)
・GameModeBase(記事内では「MyGameMode」という名前で出てくる)
・3つのマップ(レベル)
・レベルBP
・SaveGame(記事内では「SaveScore」という名前で出てくる)
「BP_Goal」の作成
前述の通り、ActorクラスのBPだ。
この「BP_Goal」は、ゴール地点としての役割を担う存在だ。
Box・・・オーバーラップコリジョン。プレイヤーがオーバーラップしたらゴール!という判定をする為のもの。
ParticleSystem・・・ゴールだという事を分かりやすくするための目印のようなもの。
自分はこんな感じにした。派手な炎エフェクトで分かりやすいだろう。
変数
「StageID」という名のInteger型の変数だ。
これは、今何ステージ目をプレイしてるのかを示すための変数だ。
今回の処理でとても重要だ。
デフォルト値は「0」のままでいい。
「MyGameInstance」の作成
これはタイマー、つまり時間の「分」と「秒」を格納する為のもの。
今回ハイスコア処理をするうえで重要な存在となる。
変数
MinuteInstance・・・「分」を格納する為の変数
SecondInstance・・・「秒」を格納する為の変数
「MyGameMode」の作成
これは主にタイマー処理を行う為のもの。
処理は以下の通り。
「秒」の処理。
「秒」と「分」を、ゲームインスタンスに格納
「Minute」は「MinuteInstance」に。
「Second」は「SecondInstance」に。
「分」を更新する処理
「秒(Second)」が「60」に達した時、つまり「60秒」に達した時
Trueに処理が流れ、
「分(Minute)」に「1」を足す。つまり、「1分」経ったという事になる。
この時、「秒(Second)」が「60」以上行ったらおかしいから、「秒(Second)」を「0」にセット。
そしてまた「秒(Second)」が1秒おきに更新されていく・・・といった感じだ。
3つのマップ(レベル)の作成
3つレベルを作成する。
ステージ名はそれぞれ分かりやすく「Stage1」「Stage2」「Stage3」にしといた。
それぞれのレベルにゴール地点の役割を担う「BP_Goal」を配置しよう。
Stage1
Stage2
Stage3
もちろん自分の好きな位置に置いてくれて構わない。
レベルBPの作成
それぞれのレベルのレベルBPに以下のような処理を組む。
Stage1のレベルBP
Stage2のレベルBP
Stage3のレベルBP
「BP_Goal」から「StageID」変数を参照。
各レベルごとに数値をセットしている。
これは今回の処理でとても重要だ。
「SaveScore」の作成
SaveGameクラスのBP。
SaveMinute・・・タイマーの「分」を格納し、セーブする為の変数
SaveSecond・・・タイマーの「秒」を格納し、セーブする為の変数
HighScoreMinute・・・ハイスコアの「分」を格納し、セーブする為の変数
HighScoreSecond・・・ハイスコアの「秒」を格納し、セーブする為の変数
今回はここまで。
次回は、実際にどのようにハイスコア処理をしていくのかを紹介する。
それではまた!^^ノシ
Set Array Elemって何よ!?!?!
今回「Set Array Elem」という気になったノードがあったので、色々調べた。
このノードは、
「指定した配列(Array)の、指定したIndexに、Item(要素)を追加する」
というものだ。
使用例を紹介しよう。
(例)
String型の配列「MyArray」から、指定したIndex(画像だと「3」)のString値をPrintStringで表示。
「MyArray」の中身
これでプレイすると・・・
指定したIndex「3」に入ってた「DANTE」の文字がしっかり表示される。
ここで、例えば「DANTE」という名前を他の名前に変えたいとき。
ここで、Set Array Elemを使うのだ。
TargetArray(MyArray)内の、IndexのItem(要素)を変更する。
Index「3」に入ってる「DANTE」を「聖徳太子」に変更だ。
これでプレイすると・・・
しっかりと変更されている。
プレイ前とプレイ中で比べてみよう。
プレイ前
プレイ中
OK!
ちなみに、
「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まで拡張が可能。という感じだ。
これでプレイすると・・・
しっかり表示。
配列内も、プレイ前とプレイ中で確認しよう。
プレイ前
プレイ中
しっかり配列内が「0~8」まで拡張されて、指定したIndex「8」に指定したItem(要素)が追加されている。
以上がSet Array Elemの概要でした!
それではまた!^^ノシ
セーブ・ロードの方法!
お久しぶりです!
最近はPS4のDETROIT Become Humenにドハマりしてい為、ブログとUE4の事はすっかり頭からすっ飛んでいたが、ようやく頭と体がUE4に戻りたがってきた為、活動を再開する事にした。
DETROIT Become Humen、面白いですよ!(おすすめです!)(宣伝)
今回はタイトル通り、「ゲームのセーブ・ロード」の方法だ。
意外と簡単なので身構える必要はないと思う。
今回は、「自分のステータスと自分の位置をセーブ・ロード」するという形式で行く。
SaveGameの作成
SaveGameクラスのBPを作成。
SaveGameは、値の保存を行う事が出来る。金で言えば「ATM」のようなもの。
名前はご自由に。僕は「MySaveGame」と付けた。
「MySaveGame」を開き、2つの変数を用意。
SaveMoney・・・所持金をセーブする為の変数。
SaveLocation・・・キャラの位置をセーブする為の変数。
デフォルト値は不要。これでSaveGameの設定は以上だ。
キャラクターBP
変数を用意。
Money・・・所持金(ステータス)デフォルト値「100」Integer型の変数。
イベントグラフ
所持金の減算
「10」ずつ減らしていく。
セーブ処理
「CreatSaveGameObject」のSaveGameClassには先程作成した「MySaveGame」を指定。
GetActorLocationで現在の位置を、「SaveLocation」に保存。
現在の所持金「Money」を「SaveMoney」に保存。
「SaveGametoSlot」で、保存した情報に「名前を付けて保存する」処理を行っている(個人的解釈なので間違いの可能性あり)
SlotNameには任意の名前を入力。僕は「SaveSlot」と入れた。
UserIndexはよくわからん。
ちなみに、保存された内容は自分のPCのフォルダに保存される。
UnrealProjects→プロジェクト名(今回の場合は「TEST」という名前にしてある)→Saved→SaveGamesに保存されている。
先程SlotNameに入力した名前「SaveSlot」という名で保存されている。
ロード処理
「LoadGameFromSlot」で、保存した内容をロードする。
キャストが必要。「MySaveGame」をキャストする。
「MySaveGame」から保存した内容(SaveLocation・SaveMoney)を参照する。
SetActorLocationで前回セーブした位置に移動する。
前回セーブした所持金「SaveMoney」をMoneyに渡す。
これでプレイしてみよう!
まず、所持金を50まで減らして、好きな位置でセーブしてみよう!
スタートした位置からかなり離れた位置まで移動し、所持金を50まで減らしてセーブをした。
その後、セーブした位置から遠く離れた場所に移動し、ロードした結果しっかりと前回セーブした位置に移動した。
これで自分の位置がしっかりセーブされているのが分かった!
だが、肝心の所持金はどうだろう??
50まで減らしてセーブしたところで、ロードしてからまた減らそうとしてもそのまま40、30、20・・・と減っていくのは当然なのだから、果たして所持金までしっかりセーブされているのか分からないだろう。
簡単に確かめられる。
もう一度、ゲームをプレイしてみよう。
先程のセーブした情報が、PCのフォルダにずっと残っているので、いきなりロードが可能。
なので、前回セーブした位置からいきなりロードできる。
普通、プレイ開始して所持金を減らしたら、デフォルト値は「100」なので90、80、70・・・と10ずつ減っていく。
だが、ロードしてから減らしてみると、いきなり40、30、20・・・と減っている。
これで所持金もしっかりセーブされているのが分かった!
それではまた!^^ノシ
ぷちコン奮闘記!~タイマー処理・スコア表示~
今回作るゲームには、タイマーとキルカウント(敵を殺した数)がスコアとして表示される。
タイマー処理もキルカウント処理も、どちらもGameModeBaseに処理を組んでいる
まず、どのようにしてキル数のカウント処理をしてるのかを紹介しよう。
GameModeBase
自分が敵を殺したという通知が、「KillCount」インターフェースを経由して送られてくる。
敵が殺された時、「KillNumber」というInteger型の変数に殺した数を格納していく。
「KillCount」インターフェースは、前回の記事にも書いてあるはずなので、確認してほしい。
次にタイマー処理だ。
イベントTickを使用。
Delayで1秒おきに「TimerSecond」というInteger型の変数を1足している。
「TimerSecond」は、秒数を格納する為の変数だ。
デフォルト値は「0」
これで、1、2、3、4・・・というように1秒ずつタイマーが加算されていく。
だが、Delayとセット「TimerSecond」変数の間に、ブランチを挟んである。
これは、キル数(KillNumber)が目標キル数(KillGoalNumber)と同じになったら、Trueに処理が流れ、クリアーリザルトを表示するために、ウィジェットBPにインターフェースで処理を送っている。
そうすれば、タイマー処理も止まってくれる。
「TimerSecond」が「60」に到達したら、「〇分」経ったかを格納する為に、「TimerMinute」というInteger型の変数を1足している。
「TimerMinute」のデフォルト値は「0」
つまり、「TimerSecond」が60秒に達したら、1分経ったという事で「TimerMinute」に1足している。
という感じだ。
その後、また「0」から秒数をカウントしていく為に、TimerSecondを「0」にセット。
そしてまたタイマーを加算していく・・・のループだ。
UMGはこんな感じ。
実際にやってみた結果。
キル数が目標値に到達した時、つまりステージにいる敵を全員鏖(みなごろし)にした時、しっかりタイマーが止まっていた!
同時にキル数もカウントされていた!
それではまた!^^ノシ
ぷちコン奮闘記!~ぷちぷち小人をぶち殺していくゲーム!!!!~
さて!ぷちコンのテーマがようやく解禁されましたね!
テーマは「ぷち」!
これまたよくわからないマニアックなテーマですw
このテーマに沿って、
「小人をぷちぷちぶち殺していくゲーム」!!!!!
を!作ることにした!
ステージはこの部屋丸ごと使った。
この部屋の中にうじゃうじゃいる小人たちを、左クリックでひたすら潰していくのだ。楽しいだろう??
今回は、「敵を殺す処理」を紹介する。
プレイヤー
「リアルなレンダリング」のアセットにデフォルトで入っている「FPS_Character」をそのまま使っている。
デフォルトだとカメラが入ってないので、カメラを追加。
「Z:90」の位置にカメラを設置した。
カメラの詳細パネル内の「CameraOption」項目にある赤枠で囲った部分にチェックを入れる。
チェックを入れないと、上下にカメラが動いてくれない。
イベントグラフ
カメラから5000の距離までトレースを飛ばす。
タグ判定でトレースが当たったアクターが指定したタグ持ちの敵かどうかを判定。
IsValidを入れないとエラーの嵐が起きる。
指定したタグ持ちのアクター(敵)にトレースがヒットした場合、Killインターフェースを経由して敵のBPに処理が送られる。
その後、殺した数、つまりスコア処理を行う為ゲームモードにも処理を送っている。
敵
敵の名前は分かりやすく「Enemy」にした。
イベントグラフ
血のパーティクル・デカールをスポーン。
死んだときの音・声を再生し、最後に敵を破壊。
Enemyにトレースがヒットするように、Capsulecomponentのコリジョン「Visibility」を「ブロック」にしてある。
何故なら、トレースのコリジョンはVisibilityに設定してあるからだ。
しっかり殺害されていた!
これからぷちコンの進捗を上げていこうと思う!
それではまた!^^ノシ
GroupActor(グループアクター)って??
つい最近買ったアセットで、気になるものを見つけた。
赤枠で囲った部分。「GroupActor」「なんだこれ??」と。
そういうクラスがあるのかと思いきやそういうわけでもなく、
色々調べた結果・・・
「複数のアクターを『1つのアクター』としてまとめる機能」
だというのが分かった。
(例)
1つの壁を複数積み上げて作ったビルがあったとする。
X方向に2枚
Y方向に2枚
Z方向に5枚積み上げたシンプルなビルだ。
例えばこのビルを、ある位置に全部丸ごと動かしたい。となった時、
まあ恐らく「1枚ずつ壁をマメに移動させる」か「壁を1枚ずつ複数選択して一気に運んでいく」かのどちらかだろう。
もちろんそれでも不可能ではないが、はっきり言って面倒だろう。
もし移動させる壁が更に多かったらどうなるだろうか。
1枚ずつマメにドラッグして移動させるのは考えたくもないし、
壁を複数選択して一気にドラッグで移動させたくても、複数選択する為に1枚ずつクリックして複数選択するのも面倒だ。
そういういった面倒を緩和してくれるのが「GroupActor」だ。
使用方法は簡単。
移動させたい壁を複数選択する。
ビューポート上、あるいはアウトライナ上で右クリックし、「グループ」を選択する。
ビューポート上の場合、指定のアクター(今回の場合だと壁)にカーソルを合わせた状態で右クリック。
アウトライナ上の場合、選択状態にしたアクターにカーソルを合わせた状態で右クリック。
「グループ」をクリックすると、以下の画像のように指定した壁が緑色の枠のようなもので囲われてるのが分かると思う。
指定したアクターを「1つのグループ」としてまとめた証拠だ。
アウトライナを確認すると、「GroupActor」というのが追加されてるはずだ。
この「GroupActor」を選択すれば、自動的に指定したアクターが複数選択される。
こうすれば、「ビルの位置を変更したい!」となった時も、「グループ」化してしまえば、簡単に指定した壁を複数一気に移動させることが可能なのだ。
ちなみに、この「グループ」化にはショートカットキーが存在する。
指定したアクターを複数選択し、「Ctrl+G」で「グループ」化が可能だ。
もちろん、「グループ」化を解除することだってできる。
「グループ」化したアクター上で右クリックし、「グループ化解除」を選択すればOKだ。
あるいは、ショートカットキー「Shift+G」でも解除可能だ。
この機能をうまく使えば、レベルデザインもなかなか楽になるかもしれない!(適当)
ぜひ活用していこう!
それではまた!^^ノシ