本日のテーマは『スイカゲーム』風の落ちものパズルを作ろう です
本記事はゲームのコア部分「フルーツマージ」機能を作ります
URSuika UnrealEngine製のスイカゲーム風3D落ちものパズルゲーム – BOOTH
無料です(Windowsのみ)遊んでみてください。
合体する作戦案
フルーツ同士がぶつかったら合体する機能を作りましょう
2つのフルーツが合体するというとき、前回記事までのように、「Hit」ぶつかったイベントに追加で処理すればよさそうですね
では、何をすればよいでしょうか?
まず1つは、片方が相手を食べるアイデアで、
もう1つは、両方消えて新しいのが生まれるアイデアです
どちらもよい作戦だと思いますが、今回は新しく生まれる作戦にしてみます
では、BP_FruitのComponent Hit(Sphere)イベント フルーツがぶつかったイベントを改変していきましょう
ここの1回だけ持ち玉を作る処理は残しつつ、壁や床に当たったあとでも玉同士はぶつかったら合体させたいです
持ち玉を出すときも出さないときも
なのでこの処理のフラグが立っている側も立っていない側も両方で処理をしたいので、一旦分岐した線を合流させます
この合流させたり分岐させたりする点はリルートノードで、線を引っ張っているときにRキーで出せます
線のうえでダブルクリックでも出せますね
これで、初めてどこかにぶつかったら持ち玉を作りつつ、初回もそれ以外もまた違う処理をできる準備ができました
しかし、ここでもう一つ同じことをできる方法をお教えします
ここの分岐の手前にSキーでシーケンスノードをつなぐ方法です
シーケンスという言葉はUE内にたくさんあるので、検索するよりSキーを覚えたほうが早いかなと思います
通常は左から右に横向きに流れていく処理を、上が終わったら下の段に縦向きに繋ぐことができるノードです
直後のブランチが成立した場合はそのルートの処理が終わりますが、そのときシーケンスの処理は終わらずに、次の1番ピンが動きます
ピンを増やすと、上から順番に動いていきます
今後、いろいろなチュートリアルでビギンプレイに処理を追加しましょう などと言われます
が、すでにほかのチュートリアルでBeginPlayには処理があるけど? となるかと思います
そういうときは最初にシーケンスノードを追加してあげると大概はうまくいくのでぜひ覚えてください
さらに補足
BeginPlayに処理がすでにある時、Delayなどが挟まっている場合が考えられます。その場合、その後ろに追加した処理は開始直後ではなく、数秒後に動くことになるかもしれません。シーケンスを使うと必ず1フレーム目で追加処理部分も動くため、「うまくいく可能性が高い」ということです
合体
ではフルーツ同士が当たったときの判定を追加しましょう
HitイベントのOtherActorというピンからぶつかった相手の情報を得られるので、それと自分自身の種類の一致を確認すればよさそうですが、クラスつまり設計図の一致をみるには、すでに使ったキャストでできそうです
自分自身がBPフルーツ型なのは当たり前なので一致をみる必要はなくて、ぶつかった相手がBPフルーツなのかそうじゃないのかで分岐します
これをシーケンスの1番ピンにつなぎましょう
ここではキャストできなかった つまりフルーツじゃないものとぶつかったときは何もしません
そしてフルーツだったときが本番です
ぶつかった2人は消えて、新しいフルーツが生まれるようにしましょう
最初にやったように、スポーンアクターでよさそうですね
しかし、今回はここでスポーンはさせずに、すでに生産工場を担当しているプレイヤーに発注します
いまは面倒に感じますが、今後色や形、大きさに得点などいろいろな改良が加えられていくたびに2か所考えることになるより、生産者は1か所になっているほうがあとあと楽です
フルーツ製造に条件追加
単に同じ処理呼ぶだけだと持ち玉が増えるだけですね
では、生産機能に場所を指定できるオプションを追加しましょう
スポーンアクターの位置情報から線を引っ張って、カスタムイベントの真ん中あたりにドロップします
すると、そのデータ型の出力ピンができました
上で呼び出しているところには入力ピンが増えていますね
このピンから位置情報が来た時とこなかったときで処理分岐して、出す位置の指定がないときは持ち玉用としましょう
ここで「==」の一致判定です
a=2 は、プログラミングの世界では「同じ」ではなく「aに2を代入」(aという箱の中身はいまから2になります)の意味を持っています。
a==2は、これも「同じ」ではなく、これも「aと2が一致しているか」真偽の命題論理(〇×判定)を表します。
次に、一致した時としなかったときで次のスポーンノードに入力する位置を切り替えたいので、一時保存する箱が欲しいです
変数に昇格しましょう
まず受け取ったオプション入力を変数に書き込んでそれが000だったときだけGet Actor Location の自分の位置で上書きします
それで変数の値を入力に差し換えれば、指定されたときとされないときで合流できますね
こういうときに忘れて危ないのがブランチのFalse側のルートです
一致しなかったときは何もしない状態になってしまっているので、繋ぎ忘れないようにしましょう
さきほどのシーケンス作戦もありです
BP_Fruitクラスに戻って場所を計算しましょう
上は持ち玉用なので000のままでよいですね
フルーツ同士がぶつかったときは、真ん中に出てるかなと思います
なので、ぶつかったときの自分の位置 ではなく、ぶつかった位置の情報が欲しいですね
そんなときは「HitResult」
これはぶつかったときの詳しい情報が束になっている構造体というものです
トランスフォームは3つの情報でしたが、Hitにはたくさんの情報が詰まっています
Break*** でこの中身の一部を取り出すことができます
このなかでインパクトポイントというのが衝撃地点つまりぶつかった位置情報です
2つのフルーツがぶつかった地点が2つの真ん中なのでちょうどよいですね
これで新しく生まれる地点は指定できました
あとは、ぶつかったら「増える」んじゃなくて、「合体」なので、もとの二人は消えないといけません
まず自分が先に消えると、そのあとの仕事は誰がやるのか?となるのでさきにぶつかった相手を消しましょう
消すのはDestroy Actor デストロイアクター 破壊ですね
そして役目を終えた自分もデストロイアクターです
自分自身がゲームの世界から消えます
おっと、合体したようですが、再びプレイヤーについてくるようになりましたね
これはなぜかわかりますか?
プレイヤーにくっついてうごく件の対策は、Activate イベントでやっていましたね
これがスポーンフルーツの改変でおかしくなるでしょうか?そうではありませんね
スポーンする処理は出す位置を変えただけですなので、原因はもう少し先にありそうです
プレイヤーにくっついて動く問題
スポーンしたフルーツをここでプレイヤーに紐づけていますね
合体して新しくできたフルーツは、プレイヤーが操作する対象ではありません
なのですぐさま起動して自由行動してもらいたいです
ただし、手持ち用は自由行動してほしくありません
ということは再び処理分岐が必要そうです
一旦合流した処理を再び同じ条件で分岐することになりますが、そういうときの作戦としてもカスタムイベント化が使えます
どちらの条件でも共通で行うスポーン処理のメイン部分を別なカスタムイベントに切り出してこのイベントを分岐の中から呼び出します
これで分岐したまま共通の処理を行えるようになりました
あとは分岐の先で片方はプレイヤーに紐づけて離すのはスペースボタンのイベントで、もう一方は紐づけしないですぐさま起動ボタンポチリましょう
ここは検証済をゲットしなくてもスポーンした直後にやる処理なので大丈夫だと思いますが念のため検証済に変えておきました
勝手にポトポト落ちるようになりました。接続を間違えましたね
000じゃないときが合体時で000のときが持ち玉です
このくらい処理を書いたら、自分でもどこに何の処理があるのかわかりにくくなってきます。説明を付けたくなってきますね
説明つけたい範囲を選択してCキーでコメントを追加することができます
コメントで括り付けた範囲のノードはコメントと一緒に動くようになるので整理するときにも便利だったり、逆に気を付けないといけなかったりします
コメントはプログラム自体とは別なので日本語などもOKです
いや、変数名なども日本語でもいけなくはありません
日本語OKになって20年も経ってないと思うので、昔からあるライブラリなど、私はまだリスク高めかなと思っています
だいぶわかりやすくなった気がします
ついでにもう少し処理を整理しておこうと思います
たとえば変数にセットする処理は縦にそろえておいたほうが統一感があって理解しやすいかな とか英数字で書く普通のプログラミングでも、インデントを揃えるとか、似た処理を同じ順番で書くなど読みやすさが大事って話があります
あともう一つ問題ありました
自分自身を親子付けできない問題は、スポーン処理部分を切り出したときの接続漏れです
よさそうですが、よく確認すると、落ちたり落ちなかったりする不安定な動作になりました。F8でデバッグしましょう
どんどんアクタが増えているわけではないけど、2つの玉の名前の数字がどんどん入れ替わっていってます。つまりぶつかって合体しまくっています
ぶつかりまくり問題
手に持つフルーツと合体で生まれたフルーツを同じ変数で管理しているあたりで問題がありそうです
まずは起動させた後、カレントフルーツをクリアするようにしてプレイヤーの位置にスポーンするときにその場で重なっちゃうことを止めてみようと思います
IA_Jumpイベント
Setノードに何もつながないとクリアです
これは、一旦プレイヤーの手元で重なっちゃうとそこで合体して新しいのが生まれ続けちゃうのが、カレントフルーツを検証失敗させれば次のフルーツが連続してでないだろうという作戦です。
ちなみにこの場合検証済をゲットではなく、検証だけすればよいのでIsValid というのでもOKです
IsValidは2つありますが、
?のほうがやるかやらないかの実行ピンが分岐するものです
fのほうは関数で、中身入っているかをTrue・Falseで返します
これでプレイヤーの手元で入れ替わる対策はできそうですが、下に落としたものでもぶつかりまくり現象が発生していたので、スポーンさせたときに手持ち用と合体用を区別してないのもわけるようにします
一旦スポーンさせたものは新しいフルーツ変数に入れておいて、Current「現在の」ではなくHang「手持ちの」に改名し、手持ち側のルートでスポーンした直後に変数から変数に受け渡します
これで、下側のルートで合体したフルーツに、手持ちのフルーツが上書き更新されることがなくなりますね
ここは新しいフルーツにかえるのも忘れずに
検証済に変えなくても、必ずスポーン直後なのでよいでしょう
結構苦労しましたが、それらしい動きになってきましたね
コメント