【RPG風バトル】シーン間でデータを渡してみた【Unity】(後編)
前回の記事の続きになります。
marutoko.hatenablog.com
参考にした記事はこちら。
note.com
!注意!
前回の記事にも書きましたが、この方法で「確実に安全」にデータを渡せているか
自信がないので、参考にされる際は各自検証の上やってみてくださいm(_ _)m
今回のテーマ
さて、前回は戦闘シーンでHPが減った状態から、ダンジョンシーンに残りHPを
引き継ぐということをやってみました。
それだけだと、ダンジョンシーンから戦闘シーンに残りHPが引き継がれない、
つまり再び戦闘シーンに入ったときにHPが初期化(全回復)されてしまう!
ということになるので、今回は
「ダンジョンシーンの残りHPを戦闘シーンに引き継ぐ」というのを
やってみようと思います。
やることは前回と似たような作業になります。
BattleController.cs を編集
BattleSceneのBattleController.cs をちょこっと編集します。
今回は、前回の逆でDungeonSceneからBattleSceneへ残りHPを渡す、
つまりGameManagerScript内のPhpremの値をBattleController内のPhpに渡す
ことになるので、private int にしていたPhpを、外からアクセスできるように
public int へと書き換えます。
BattleController.cs書き換え
冒頭部分
public int Php = 100; //プレイヤーHP 他シーンから値を受け取るためpublicにする
これでPhpに外からアクセスできるようになりました。
GameManagerScript.cs を編集
ここから追記 〜 追記ここまで の部分を追記します。
using System.Collections; using System.Collections.Generic; using UnityEngine.SceneManagement; using UnityEngine; public class GameManagerScript : MonoBehaviour { public int Phprem = 100; //プレイヤーの残りHP private void Start() { Debug.Log("ダンジョンシーンに切り替わった"); Debug.Log("プレイヤーの残りHP " + Phprem); } // ここから追記 void Update() { if (Input.GetKeyDown(KeyCode.Return)) { // イベントにメソッドを登録 SceneManager.sceneLoaded += GameSceneLoaded2; // バトルシーンに切り替え SceneManager.LoadScene("BattleScene"); void GameSceneLoaded2(Scene next, LoadSceneMode mode) { // シーン切り替え後のスクリプトを取得 var battleController = GameObject.FindWithTag("BattleController").GetComponent<BattleController>(); // データを渡す処理 battleController.Php = Phprem; //次のシーンにプレイヤーの残りHPを渡す // イベントからメソッドを削除 SceneManager.sceneLoaded -= GameSceneLoaded2; } } } // 追記ここまで }
Update関数を追加して、Returnが押されたら残りHPを引き渡して戦闘シーンに
切り替わるようにします。
やっていることは前回と同様です。
GameSceneLoaded2メソッドをシーン切り替え時に呼ばれるメソッドとして追加し、
GameSceneLoaded2メソッド内でBattleControllerスクリプトを見つけて
その中のPhpにPhpremの値を渡します。
最後にイベントからメソッドを削除しておきます。
再生してみる
シーンを再生してみます!
BattleSceneを開き、再生します。
BattleSceneからDungeonSceneへのHPの引き渡しは前回できたので、
確認するべきなのはBattleScene → DungeonScene → BattleScene に遷移
したとき、ダンジョンシーンから戦闘シーンへHPが引き継がれているかどうかです。
具体的には2回目の戦闘シーンに入ったときに、「プレイヤーHP40」と出れば
うまくいっていることになります。
どうでしょうか?
BattleScene → DungeonScene → BattleScene と遷移した結果の
最初のBattleSceneの途中から表示されています。
はじめの戦闘シーンで残りHPが40になり、
遷移後のダンジョンシーンで残りHPが40と引き継がれていて、
その後「バトルスタート」で二回目の戦闘シーンに切り替わり、
ちゃんとプレイヤーHPが40になっています。
うまくいきました!
おまけ
ゲーム画面でもHPが表示されるようにしてみました。
方法については今までの応用でできるので割愛させていただきます。
工夫した点としては、敵を倒した時敵のHP表示がマイナスになってしまうので、
Ehp<=0のときは0と表示されるようにif文を使って書き直しました。
(もっとスマートな方法あるかも)
他は、バトル終了時、クリア画像が出るアニメーションが終わる前に
次のシーンへ遷移してしまっていたので、
DOTweenの.OnCompleteを使ってアニメーション終了後に
シーンを遷移させるように変更しました。
心配な点
Unityの実行画面ではうまくいきましたが、不安もあります。
参考記事では「シーンA → B にデータをセットする」ことで
安全にデータを渡していましたが、今回は
BattleScene → DungeonScene → BattleScene と2シーン間で
データを渡し合っています。
もしかしたらこの点で何か不具合が出てくるかもしれません。
参考にされる際は吟味してやってみてください。
それではまた〜!
【RPG風バトル】シーン間でデータを渡してみた【Unity】(前編)
!注意!
今回の方法で本当に安全にデータを引き渡せているか確証が得られていないので、
参考にされる際は各自検証の上ご使用ください。
やってみたいこと
前回、RPG風の戦闘シーンを作りましたが、戦闘シーンから他のシーンに
データを渡せたらいいなと思ったのでやってみました。
前回の記事はこちら
marutoko.hatenablog.com
一般的なRPGの場合、フィールドやダンジョンで敵にエンカウントしたら
戦闘シーンになって、戦闘でダメージを負い戦闘が終わったら
HPが減った状態でフィールドなどに戻りますよね。
それを簡単な形で再現できたらいいなと思ったわけです。
シーン間でデータをやりとりする方法はいろいろあるようですが・・・
こんな記事を見つけました。
note.com
うーん、グローバルなオブジェクトを持つ方法は簡単だけど危険もあるんですね。
初心者の私的には危険はなるべく避けたいので、この記事での
「シーンAがシーンBにデータをセットをする」方法を試してみました。
具体的には「戦闘シーンからダンジョンシーンにプレイヤーHPを渡す」
というのをやってみようと思います。
シーンを追加
ダンジョンシーンを追加します。
File → New Sceneで「DungeonScene」を追加。
スクリプトをアタッチするための空オブジェクトをHierarchy→Create Emptyで
作成、名前を「GameManager」とします。
参考記事内では"GameObject.FindWithTag"を使いタグでゲームオブジェクトを
見つけているので、GameManagerにタグを設定しておきます。
余談ですが、オブジェクトを見つける場合、GameObject.Find は処理が重いんですね...!
Hierarchyから直接参照するか、Tagを使って参照するのが良いそうです。
参考はこちら
squmarigames.com
さて、オブジェクトにタグを追加する方法は
GameManagerのInspectorのTagの右のプルダウンを押して Add Tag をクリック。
Tagsの+を押してNew Tag Name に「GameManager」と入力すると
GameManagerという名前のタグを追加できるので、
その後Tag右のプルダウンからGameManagerを選ぶことで
GameManagerオブジェクトにGameManagerタグを追加することができます。
スクリプトを追加
GameManagerオブジェクトにアタッチするスクリプトを作ります。
スクリプト名は「GameManagerScript」にしました。
ここでプレイヤーの残りHPを受け取るための変数(Phprem)を用意します。
戦闘シーンでプレイヤーの初期HPを100にしていたので、
最大HPは100ということにしてPhpremも100に設定し、
Start内のDebug.LogでPhpremの数値を表示するようにします。
GameManagerScript.cs
using System.Collections; using System.Collections.Generic; using UnityEngine.SceneManagement; using UnityEngine; public class GameManagerScript : MonoBehaviour { public int Phprem = 100; //プレイヤーの残りHP private void Start() { Debug.Log("ダンジョンシーンに切り替わった"); Debug.Log("プレイヤーの残りHP " + Phprem); } }
このスクリプトをGameManagerにアタッチします。
このまま再生すると、Consoleには「プレイヤーの残りHP 100」と表示されますね。
戦闘前のHPは100ということで、これが戦闘シーンでダメージを受けて
ダンジョンシーンに戻ってくると残りHPが減って表示されるように、
BattleControllerスクリプトを編集していきます。
BattleControllerスクリプトを編集
戦闘シーンを開き、 File → Save As で名前を「BattleScene」として
保存しておきます。
次にBattleControllerスクリプトを編集します。
シーンが切り替わるタイミングで次のシーンに残りHPを渡したいのですが、
具体的には「デリゲート」という仕組みを使います。
デリゲートとはどんなものかというと、シーンの遷移を検知して、
シーン遷移のタイミングで登録したメソッドが呼び出される仕組みということです。
便利!!!(今知った
デリゲートについては「Unityの教科書」の作者様が簡単に説明して
くださってますのでご参考まで。
というわけで、さっそくスクリプトを編集します。
その前に下準備。
シーンの遷移をする場合、Build Settings にシーンを登録しておく必要があります。
現在開いているシーンを保存できるので、シーンを開いてから
File → Build Settings → Add Open Scenes より
「DungeonScene」と「BattleScene」を追加しておきます。
さて、どのタイミングで戦闘シーン → ダンジョンシーンに切り替えるかですが、
戦闘に勝利したときだと思うので、全ての敵を倒した時に呼ばれる
「AllEnemyDead」メソッドの最後にシーン遷移の記述をしていくことにします。
BattleController.cs(途中部分)
// 冒頭部分 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; // ←シーン遷移をするために追加 // 中略 void AllEnemyDead() { clear = GameObject.Find("Clear"); script = clear.GetComponent<ClearTween>(); script.Clear(); Debug.Log("ゲームクリア"); // ここから追加 NextScene(); void NextScene() { // イベントにメソッドを登録 SceneManager.sceneLoaded += GameSceneLoaded; // ダンジョンシーンに切り替え SceneManager.LoadScene("DungeonScene"); void GameSceneLoaded(Scene next, LoadSceneMode mode) { // シーン切り替え後のスクリプトを取得 var gameManager = GameObject.FindWithTag("GameManager").GetComponent<GameManagerScript>(); // データを渡す処理 gameManager.Phprem = Php; //次のシーンにプレイヤーの残りHPを渡す // イベントからメソッドを削除 SceneManager.sceneLoaded -= GameSceneLoaded; // 追加ここまで } } }
全ての敵を倒した時に呼ばれるAllEnemyDeadメソッドの最後に、データを次のシーンに
渡しつつシーン遷移させるNextSceneメソッドを追加します。
その中でデータ引き渡しをするGameSceneLoadedメソッドを作成し、
シーン切り替え時に実行することにします。
SceneManager.sceneLoaded += (メソッド名); と書くことでシーンが読まれるときに
実行されるメソッドを登録できるので、その後
SceneManager.LoadScene("DungeonScene"); でダンジョンシーンをロードさせます。
そうすると、ダンジョンシーンがロードされるときにGameSceneLoadedメソッドが実行されます。
GameSceneLoaded内でvar gameManagerを宣言し、"GameManager"タグが付いている
オブジェクトを見つけてアタッチされているGameManagerScriptを取得します。
gameManager.Phprem = Php; で
GameManagerScriptの中のPhprem(ダンジョンシーンで表示される残りHP)に
Php(戦闘シーンでバトル終了後に残ったプレイヤーのHP)を渡します。
最後にSceneManager.sceneLoaded -= GameSceneLoaded; でイベントから
メソッドの登録を解除しておく必要があります。
"これを忘れてしまうとシーン切り替えのたびにこのメソッドが呼ばれてしまう"とのことです。
(ここは理解がまだ曖昧です)
実行してみる
ひとまずこれで、戦闘シーンからダンジョンシーンに残りHPを渡す処理を作ることが
できたと思うので実行してみます。
戦闘シーン後半〜ダンジョンシーンに切り替わった後までの実行結果です。
戦闘シーンでプレイヤーがダメージを受けて残りHPが40になり、クリア後
ダンジョンシーンが切り替わっても残りHPが40になっていて、無事残りHPを
引き渡せたことがわかります。
戦闘シーンからダンジョンシーンに残りHPを引き継がせることができました!
やった!!!と喜びたいところですが、まだ冒険は続きます。
ダンジョンシーンから戦闘シーンへも残りHPを渡さないと、再び戦闘になったときに
HPが全回復してしまします。
これではヌルゲーになってしまいますので、次回、今回と同様に
ダンジョンシーンから戦闘シーンに残りHPを引き渡してみたいと思います。
〜後編に続く〜
RPG風ターン制バトルを作ってみた【Unity】
*素人がこうやってみたよっていう記事なので参考程度にお願いします。
Unityバージョン2019.4.18f1
UnityでRPGの戦闘のようなターン制バトルを作ってみたいなあと思っていたところ、
こんな記事を見つけたので参考にして試しに作ってみました。
boolを使ってプレイヤーターンと敵ターンを切り替えます。
できあがりはこんな感じ。
*イラスト素材は「いらすとや」からお借りしています。
かわいいフリー素材集 いらすとや
パラメータはHPと攻撃力のみのシンプルな戦闘シーンです。
敵HPが0になるとクリア画像、プレイヤーHPが0になるとゲームオーバー画像が出ます。
下準備
オブジェクトをアニメーションさせるのにアセット「DOTween」(無料版)を使いました。
DOTween Asset Store
assetstore.unity.com
DOTweenの入手・セットアップはこちらが参考になります。
qiita.com
Unityでオブジェクトを配置
画像素材を配置します。
ヒエラルキーからUI→imageで草原(BackGround)、勇者(Player1)、モンスター(Enemy1)を配置。
クリア画像(Clear)とゲームオーバー画像(GameOver)は右からスライドインさせて表示するため、
初期位置はCanvasの範囲の外に置きました。
ダメージ数値はUI→Textから、P1DamageとE1Damageをそれぞれ勇者の上とモンスターの上に配置しました。
ダメージ値はスクリプトで表示させるので、Text内の文字は空にしています。
正しく表示されるように、適当に数字を入れてみてあらかじめ位置を調整してから
文字を消すとスムーズかと思います。
戦闘シーンを動かすスクリプトを貼り付けるための空オブジェクトを用意しておきます。
ヒエラルキーからCreate Emptyでオブジェクト作成、名前を「BattleController」に変更。
スクリプト作成
スクリプトを書きます。
BattleController.cs(メインのスクリプト)
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class BattleController : MonoBehaviour { public bool playerTurn; //trueのときプレイヤーのターン public bool enemyalive; //敵が生きているか public bool playeralive; //プレイヤーが生きているか public GameObject clear; //ゲームクリアの画像 ClearTween script; //クリア画像を動かすスクリプト public GameObject gameover; //ゲームオーバーの画像 GameOverTween scriptGO; //ゲームオーバー画像を動かすスクリプト public GameObject player1; //プレイヤーオブジェクト public GameObject enemy1; //敵オブジェクト P1Tween scriptP; //プレイヤーを動かすスクリプト E1Tween scriptE; //敵を動かすスクリプト public GameObject p1dmgtxt; //プレイヤーダメージ表記オブジェクト public GameObject e1dmgtxt; //敵ダメージ表記オブジェクト private Text P1DamageText; //プレイヤーダメージ表記テキスト private Text E1DamageText; //敵ダメージ表記テキスト E1dmgTween scriptE1dmg; //敵ダメージ表記を動かすスクリプト P1dmgTween scriptP1dmg; //プレイヤーダメージ表記を動かすオブジェクト int Php = 100; //プレイヤーHP int Ehp = 100; //敵HP int Patk = 40; //プレイヤー攻撃力 int Eatk = 30; //敵攻撃力 void Start() { playerTurn = true; enemyalive = true; playeralive = true; player1 = GameObject.Find("Player1"); enemy1 = GameObject.Find("Enemy1"); p1dmgtxt = GameObject.Find("P1Damage"); p1dmgtxt.SetActive(false); e1dmgtxt = GameObject.Find("E1Damage"); e1dmgtxt.SetActive(false); Debug.Log("バトルスタート"); Debug.Log("敵HP" + Ehp); Debug.Log("プレイヤーHP" + Php); } void Update() { if (playerTurn == true && playeralive == true) { if (Input.GetKeyDown(KeyCode.Return)) { Debug.Log("プレイヤーターン"); Invoke("Player1Move", 0.5f); //プレイヤー動かす Ehp -= Patk; //敵のHPを減らす Debug.Log("敵HP" + Ehp); E1DamageText = e1dmgtxt.GetComponent<Text>(); //敵ダメージ表記オブジェクトからテキストを取得 E1DamageText.text = "-" + Patk; //テキストにダメージを入れる scriptE1dmg = e1dmgtxt.GetComponent<E1dmgTween>(); //E1Damageにアタッチされているスクリプトを取得 scriptE1dmg.E1dmg(); //ダメージを動かしながら表示 if (Ehp <= 0) //敵HPが0以下のとき { enemyalive = false; Invoke("Enemy1Dead", 1f); //敵を非アクティブにする Invoke("AllEnemyDead", 1f); //ゲームクリア画面表示 } playerTurn = false; } } if (playerTurn == false && enemyalive == true) { if (Input.GetKeyDown(KeyCode.Return)) { Debug.Log("敵ターン"); Invoke("Enemy1Move", 1.5f); //敵動かす Php -= Eatk; //プレイヤーのHPを減らす Debug.Log("プレイヤーHP" + Php); P1DamageText = p1dmgtxt.GetComponent<Text>(); //プレイヤーダメージ表記オブジェクトからテキストを取得 P1DamageText.text = "-" + Eatk; //テキストにダメージを入れる scriptP1dmg = p1dmgtxt.GetComponent<P1dmgTween>(); //P1Damageにアタッチされているスクリプトを取得 scriptP1dmg.P1dmg(); //ダメージを動かしながら表示 if (Php <= 0) //プレイヤーHPが0以下のとき { playeralive = false; Invoke("Player1Dead", 1f); //プレイヤーを非アクティブにする Invoke("GameOver", 1f); //ゲームオーバー画面表示 } playerTurn = true; } } } void Player1Move() { scriptP = player1.GetComponent<P1Tween>(); scriptP.P1Move(); } void Enemy1Move() { scriptE = enemy1.GetComponent<E1Tween>(); scriptE.E1Move(); } void Player1Dead() { player1.SetActive(false); } void Enemy1Dead() { enemy1.SetActive(false); } void GameOver() { gameover = GameObject.Find("GameOver"); scriptGO = gameover.GetComponent<GameOverTween>(); scriptGO.GameOver1(); Debug.Log("ゲームオーバー"); } void AllEnemyDead() { clear = GameObject.Find("Clear"); script = clear.GetComponent<ClearTween>(); script.Clear(); Debug.Log("ゲームクリア"); } }
BattleController.csをUnityで先ほど作った空オブジェクトBattleControllerにアタッチ。
続いて、DOTweenを使ってプレイヤーオブジェクトを動かすスクリプトを書きます。
P1Tween.cs(プレイヤーをアニメーションさせるスクリプト)
using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; //DOTweenを使うために追加 public class P1Tween : MonoBehaviour { public void P1Move() { MoveGo(); } private void MoveGo() //プレイヤーを敵に向かって移動 { transform.DOLocalMove(new Vector3(-389f, 0, 0), 0.1f) .SetRelative() //相対座標で動かす .OnComplete(() => MoveBack()); //終わったらMoveBackを実行 } private void MoveBack() //プレイヤーを元の位置に戻す { transform.DOLocalMove(new Vector3(389f, 0, 0), 0.1f) .SetRelative(); } }
P1Tween.csはUnityのPlayer1オブジェクトにアタッチします。
続いて同様に、敵を動かすスクリプトを書きます。
E1Tween.cs(敵をアニメーションさせるスクリプト)
using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; public class E1Tween : MonoBehaviour { public void E1Move() { EMoveGo(); } private void EMoveGo() { transform.DOLocalMove(new Vector3(391, 0, 0), 0.1f) .SetRelative() .OnComplete(() => EMoveBack()); } private void EMoveBack() { transform.DOLocalMove(new Vector3(-391, 0, 0), 0.1f) .SetRelative(); } }
E1Tween.csをEnemy1オブジェクトにアタッチ。
次は、ダメージを与えた/受けた時にキャラクターの上にダメージ数値を表示させるスクリプトを書いていきます。
まずは敵の上にダメージを表示させるスクリプトから。
E1dmgTween.cs(敵に与えたダメージを表示させるスクリプト)
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class E1dmgTween : MonoBehaviour { public void E1dmg() { Invoke("E1dmgjump", 0.5f); } private void E1dmgjump() //ダメージ値を表示してジャンプさせる { this.gameObject.SetActive(true); //ダメージ値を表示 transform.DOJump(new Vector3(0, 0, 0), 15f, 1, 0.3f) //ジャンプさせる(移動終了地点, ジャンプ力, ジャンプ回数, アニメーション時間) .SetEase(Ease.Linear) //滑らかに .SetRelative() //相対座標で .OnComplete(() => Endfunc()); //終わったらEndfunc実行 } private void Endfunc() { this.gameObject.SetActive(false); //ダメージ値を非表示 } }
E1dmgTween.csはE1Damageオブジェクトにアタッチしておきます。
続いて同様に、プレイヤーの上にダメージ表示させるスクリプトを書きます。
P1dmgTween.cs(敵に与えたダメージを表示させるスクリプト)
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class P1dmgTween : MonoBehaviour { public void P1dmg() { Invoke("E1dmgjump", 1.5f); } private void E1dmgjump() { this.gameObject.SetActive(true); transform.DOJump(new Vector3(0, 0, 0), 15f, 1, 0.3f) .SetRelative() .OnComplete(() => Endfunc()); } private void Endfunc() { this.gameObject.SetActive(false); } }
P1dmgTween.csをP1Damageオブジェクトにアタッチ。
長くなってきましたがもうすぐ完成です!
最後に、敵を倒した場合とプレイヤーが倒された場合に、
それぞれ「GAME CLEAR」画像と「GAME OVER」画像を表示させるためのスクリプトを書きます。
まずはゲームクリア画像から。
ClearTween.cs(ゲームクリア画像を表示させるスクリプト)
using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; public class ClearTween : MonoBehaviour { public void Clear() { Invoke("Move", 0.5f); } private void Move() { transform.DOLocalMove(new Vector3(-14f, -18f, 0), 0.5f); //オブジェクトをローカル座標で移動(座標,アニメーション時間) } }
ClearTween.csはClearオブジェクトにアタッチします。
同様にゲームオーバー画像を動かすスクリプトを書きます。
GameOverTween.cs(ゲームオーバー画像を表示させるスクリプト)
using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; public class GameOverTween : MonoBehaviour { public void GameOver1() { Invoke("GameOverMove", 0.5f); } private void GameOverMove() { transform.DOLocalMove(new Vector3(-14f, -18f, 0), 0.5f); } }
GameOverTween.csをGameOverオブジェクトにアタッチ。
やっと完成です!
注意点
参考にしていただく場合、スクリプト内の座標はプロジェクトによると思いますので
オブジェクトの位置に合わせて調整してみてください。
プレイヤーと敵のHPと攻撃力を変えたりパラメータを追加したり色々遊ぶと面白いかも。
ずらずらっと書いていきましたが実際にゲームとして完成させるには
ここからさらに工夫が必要だと思います。
また、簡易的にタイミングを合わせるために、設定した時間後(単位/秒)にメソッドを呼び出す
「Invoke」を使いましたが、いろいろな理由から非推奨のようです。
より汎用性の高い「コルーチン」に書き換えたほうがいいかもしれません。
・InvokeのデメリットとCoroutineの使い方についての参考記事
www.wwwmaplesyrup-cs6.work
忘備録的な記事になりますが、少しでも役にたてば嬉しいです。
まだUnityの入門書をやっていない方は「Unityの教科書」がおすすめです!
私はC#,Unityともに初めてで、この本の2019年度版を読みましたが
解説がとても丁寧で、猫の可愛いイラストを挟みつつわかりやすく書かれています。
簡単にスマホで作ったゲームを動かしてみることができるのも良かったです。
(iPhoneの場合はMacが必要なので注意)
ではではこの辺で〜!
はじめまして!
見てくださってありがとうございます!まるとこと申します。
昨年(2020年)秋からUnityを使って個人でゲームを作っています。
まだ入門書一冊終えて、アプリを一つ出した程度ですが、学んだことを残したいという思いではてなブログを始めることにしました。
Unityの記事を中心に書いていきたいと思っています。
よろしくお願いします!
◆リリースしたゲームアプリ「どうぶつなぞときダンジョン」
女の子とダンジョンを探検する短編アドベンチャーゲームです。
どうぶつなぞときダンジョン
無料posted withアプリーチ
◆まるとこTwitter
◆ゲーム製作個人サークルOSAKANA GAMES Webサイト