【Unity】RPG制作 その22-トラップイベント、扉のスイッチイベント実装
今回は探索時のトラップイベントやスイッチで開く扉の処理を実装していきます。
まずはじめに、DangeonController.csのInformDangeonEventコルーチンで、各々のイベントが配置されていることを知らせる処理を追加します。
クリックで展開
public IEnumerator InformDangeonEvent() { eventID = GetCurrentPosDangeonEventID(); DangeonEvent dangeonEvent = new DangeonEvent(); switch (eventID) { case -1://何もなし yield break; case 0://採掘イベントを知らせる StartCoroutine(dangeonEvent.IEInformMineEvent()); yield break; case 1://釣りイベントを知らせる StartCoroutine(dangeonEvent.IEInformFishingEvent()); yield break; case 2: //アイテムイベントを知らせる StartCoroutine(dangeonEvent.IEInformItemEvent()); yield break; case 3: //伐採イベントを知らせる StartCoroutine(dangeonEvent.IEInformLoggingEvent()); yield break; case 4: //金貨イベントを知らせる StartCoroutine(dangeonEvent.IEInformGoldEvent()); yield break; case 5: //下階段イベントを知らせる StartCoroutine(dangeonEvent.IEInformDownFloorEvent()); yield break; case 6: //上階段イベントを知らせる StartCoroutine(dangeonEvent.IEInformUpFloorEvent()); yield break; //---------------------New------------- case 7: //トラップイベントを実行する yield return StartCoroutine(dangeonEvent.IETrapEvent(5,questManager)); DeleteEvent(); yield break; case 8: //スイッチで開く扉イベントを知らせる StartCoroutine(dangeonEvent.IEInformSwitchDoorEvent()); yield break; case 9://青いスイッチ(OFF)イベント StartCoroutine(dangeonEvent.IEInformOffBlueSwitchEvent()); yield break; case 10://青いスイッチ(ON)イベント StartCoroutine(dangeonEvent.IEInformONBlueSwitchEvent()); yield break; //------------------Newここまで---------- } }
case7~10で実行されるイベントをdangeonEvent.csで実装します。
クリックで展開
public IEnumerator IETrapEvent(int damage,QuestManager questManager) //New { DialogTextManager.instance.SetScenarios(new string[] { PlayerManager.instance.pname + "は罠にかかった!"}); SoundManager.instance.PlaySE(19); yield return new WaitForSeconds(2f); DialogTextManager.instance.SetScenarios(new string[] { PlayerManager.instance.pname + "は" + damage +"のダメージを受けた!"}); PlayerManager.instance.hp -= damage; if(PlayerManager.instance.hp <= 0) { PlayerManager.instance.hp = 0; yield return questManager.PlayerDeath(); } yield return new WaitForSeconds(2f); } public IEnumerator IEInformSwitchDoorEvent() //New { DialogTextManager.instance.SetScenarios(new string[] { "次の階層への扉がある"}); yield return new WaitForSeconds(2f); } public IEnumerator IEInformOffBlueSwitchEvent() //New { DialogTextManager.instance.SetScenarios(new string[] { "青いスイッチ(OFFになっている)がある"}); yield return new WaitForSeconds(2f); } public IEnumerator IEInformOnBlueSwitchEvent() //New { DialogTextManager.instance.SetScenarios(new string[] { "青いスイッチ(ONになっている)がある"}); yield return new WaitForSeconds(2f); }
今度はDangeonController.csのIEDangeonEventProcessコルーチンで現在位置のイベントを実行する処理を追加します。
クリックで展開
public IEnumerator IEDangeonEventProcess() { stageUIManager.SetActionButton(false); stageUIManager.SetArrowsButton(false); eventID = GetCurrentPosDangeonEventID(); DangeonEvent dangeonEvent = new DangeonEvent(); switch (eventID) { case -1://何もなし break; case 0://採掘イベント yield return dangeonEvent.IEMineEvent(mineItemGroup); RegistryEventMemory(dangeonEvent,3,5,playerPos.x,playerPos.y,0); break; case 1://釣りイベント yield return dangeonEvent.IEFishingEvent(fisingItemGroup); RegistryEventMemory(dangeonEvent, 3,5, playerPos.x, playerPos.y, 1); break; case 2: //アイテムイベント yield return dangeonEvent.IEItemEvent(itemEventGroup); RegistryEventMemory(dangeonEvent, 3, 5, playerPos.x, playerPos.y, 2); DeleteEvent(); break; case 3: //伐採イベント yield return dangeonEvent.IELoggingEvent(loggingItemGroup); RegistryEventMemory(dangeonEvent, 3, 5, playerPos.x, playerPos.y, 3); break; case 4: //金貨イベント yield return dangeonEvent.IEGetGoldEvent(Random.Range(minGold, maxGold + 1)); playerUIManager.UpdateUI(PlayerManager.instance); DeleteEvent(); break; case 5: //階段を降りるイベント yield return dangeonEvent.IEDownFloorEvent(dangionMap, questManager,stageUIManager,this); break; case 6: //階段を上がるイベント yield return dangeonEvent.IEUpFloorEvent(dangionMap, questManager, stageUIManager,this); break; //---------------New------------- case 7://7はトラップイベントだが配置された位置に到達した時に実行されるのでここでは何もしない(というかここには処理が来ない) break; case 8: //スイッチで開く扉イベント yield return dangeonEvent.IEUpSwitchDoorEvent(); break; case 9: ////青いスイッチ(OFF)イベント yield return dangeonEvent.IEOFFBlueSwitchEvent(); break; case 10: ////青いスイッチ(ON)イベント yield return dangeonEvent.IEONBlueSwitchEvent(); break; //---------------Newここまで------------- } if (!shouldActiveActionButton) { shouldActiveActionButton = true; } else if(shouldActiveActionButton) { stageUIManager.actionButton.SetActive(true); } stageUIManager.SetArrowsButton(true); yield return null; }
IEDangeonEventProcessコルーチンで追加した各々のイベントの処理のコルーチンをDangeonEvent.csで定義します。
クリックで展開
public IEnumerator IEUpSwitchDoorEvent() //New { DialogTextManager.instance.SetScenarios(new string[] { "扉は開きそうにもない。仕掛けを解く必要があるようだ。"}); yield return new WaitForSeconds(2f); } public IEnumerator IEOFFBlueSwitchEvent(DangionMap dangionMap, QuestManager questManager, DangionController dangionController) //New { SoundManager.instance.PlaySE(29); DialogTextManager.instance.SetScenarios(new string[] { PlayerManager.instance.pname + "はスイッチを押した"}); yield return new WaitForSeconds(2f); int floor = questManager.currentFloor - 1; int py = dangionController.playerPos.y; int px = dangionController.playerPos.x; dangionMap.posOfEvent[floor, py, px] = 10;//イベントの種類を青スイッチ(ON)にする bool pushAllBlueSwitch = true; for (int j = 0; j < dangionController.dangion_height; j++) { for (int i = 0; i < dangionController.dangion_width; i++) { if (dangionMap.posOfEvent[floor, j, i] == 9)//一つでもOFFの青スイッチがあったらフラグをfalseにする { pushAllBlueSwitch = false; } } } if (pushAllBlueSwitch) //OFFの青スイッチが一つもなければ { for (int j = 0; j < dangionController.dangion_height; j++) { for (int i = 0; i < dangionController.dangion_width; i++) { if (dangionMap.posOfEvent[floor, j, i] == 8)//スイッチで開く扉のイベントを探し出して { dangionMap.posOfEvent[floor, j, i] = 5; //イベントを下り階段に変更する dangionMap.DeleteEventIcon(i,j);//アイコンを削除 SoundManager.instance.PlaySE(30); DialogTextManager.instance.SetScenarios(new string[] { "扉が開いた"}); yield return new WaitForSeconds(2f); } } } } } public IEnumerator IEONBlueSwitchEvent() //New { DialogTextManager.instance.SetScenarios(new string[] { "既に押してある"}); yield return new WaitForSeconds(2f); }
スイッチで開く扉イベントは同一フロアにある青いスイッチをすべて押した時に下り階段にイベントに変わるようになっています。
実際にうまくイベントが動くかどうか試すために、新しくダンジョン第5層を作成します。DangeonMap.csのstructOfDangeonの3次元配列とposOfEventの3次元配列に5層のデータを追加します。
クリックで展開
public int[,,] structOfDangeon = new int[5,5,5]{ { { 4, 1, 5, 4, 1 }, {14,12, 9,14,12 }, {14, 0, 0, 0,12 }, {14, 0, 0, 0,12 }, { 3,13,13,13, 2 }, }, { { 4,10,10,10, 1 }, { 9,-1,-1,-1, 9 }, { 9,-1, 4,11,12 }, { 9,-1,14, 0,12 }, { 3,10,13,13, 2 }, }, { { 4,11,11,11, 1 }, {14, 0, 0, 0,12 }, {14, 0, 0, 0,12 }, {14, 0, 0, 0,12 }, { 3,13,13,13, 2 }, }, { { 4,11, 1,-1,-1 }, {14, 0, 0, 1,-1 }, { 3, 0, 0, 0, 1 }, {-1, 3, 0, 0,12 }, {-1,-1, 3,13, 2 }, }, //------------New--------------- { { 4,10, 1,-1, 5 }, { 7,-1, 9,-1, 9 }, { 1,10, 0,11, 1 }, { 9,-1,14, 0,12 }, { 3,10,13,13, 2 }, }, //------------Newここまで----------- }; public int[,,] posOfEvent = new int[5,5, 5] { { { -1,-1,-1,-1, 5 }, { -1,-1,-1,-1,-1 }, { -1,-1,-1,-1,-1 }, { -1,-1,-1,-1,-1 }, { 6,-1,-1,-1,-1 }, }, { { -1,-1,-1,-1, 6 }, { -1,-1,-1,-1,-1 }, { -1,-1,-1,-1,-1 }, { -1,-1,-1,-1,-1 }, { 5,-1,-1,-1,-1 }, }, { { 5,-1,-1,-1,-1 }, { -1,-1,-1,-1, 1 }, { -1,-1,-1,-1,-1 }, { -1,-1,-1,-1,-1 }, { -1,-1,-1,-1, 6 }, }, { { 6,-1,-1,-1,-1 }, { -1,-1,-1,-1, 1 }, { -1,-1,-1,-1,-1 }, { -1,-1,-1,-1,-1 }, { -1,-1,-1,-1, 5 }, }, //------------New--------------- { { -1,-1,-1,-1, 9 }, { 8,-1,-1,-1, 1 }, { -1,-1, 6,-1,-1 }, { -1,-1,-1,-1,-1 }, { -1,-1,-1,-1, 9 }, }, //------------Newここまで--------------- }; public int [,,]isViewRoom = new int[5, 5, 5] { //0;見えない 1:見える { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }, { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }, { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }, { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }, //------------New------------ { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }, //------------Newここまで------------ }; public int[,,] isViewEvent = new int[5, 5, 5] { //0;見えない 1:見える { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }, { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }, { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }, { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }, //------------New------------ { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }, //------------Newここまで------------ };
structOfDangeonに5層のダンジョンの部屋構造のデータ、posOfEventに5層のイベント配置(上り階段1つと青スイッチ(OFF)2つ)、isViewRoomとisViewEventにもそれぞれ5層のデータを追加しました。
あと、新しいフロアをに入った時に一定確率でトラップイベントを生成するようにします。イベントのランダム生成はDangionMap.csのSetEventNowFloorAtRandam関数で行っているので、この関数の処理を変更します。
クリックで展開
public List<int> eventIDList = new List<int>() {0,1,2,3,4,7 }; //ランダムで生成させるイベントIDのリスト public void SetEventNowFloorAtRandam(int currentFloor,int minCountOfEvent, int maxCountOfEvent) { int normaOfSetEvent = 0; int countOfSetEvent = 0; normaOfSetEvent = UnityEngine.Random.Range(minCountOfEvent, maxCountOfEvent); while (countOfSetEvent < normaOfSetEvent) { int x = UnityEngine.Random.Range(0,dangionController.dangion_width); int y = UnityEngine.Random.Range(0,dangionController.dangion_height); if (posOfEvent[currentFloor - 1, y, x] == -1 && structOfDangeon[currentFloor - 1, y, x] != -1) { posOfEvent[currentFloor - 1, y, x] = eventIDList[UnityEngine.Random.Range(0,eventIDList.Count)];//eventIDのランダム配置 countOfSetEvent++; } } }
もともとposOfEventに0~4のランダムなIDを入れていたのを、新たにeventIDListを作成して、ListのIDの中からランダムに代入するように変更しました。
このまま実行するとトラップイベントが実行される前にダンジョンマップとボタンなどが表示されてしまうので、それを直します。QuestManagerに新たに処理を追加します。
クリックで展開
public bool nowEvent = false; //探索イベント中か? [SerializeField] UnityEvent OnCompleteMoveRoom2;//部屋を移動した時にバトル、イベントあるなしに関わらず呼び出す処理 New public IEnumerator MoveOnRoom() { if(OnCompleteMoveRoom == null) OnCompleteMoveRoom = new UnityEvent();//イベント・インスタンスの生成 SoundManager.instance.PlaySE(0); stageUI.HideButtons(); yield return StartCoroutine(Searching()); OnCompleteMoveRoom2.Invoke(); if (!nowBattle && !nowEvent) //New { OnCompleteMoveRoom.Invoke(); //イベント発行 (ダンジョンマップ再表示) } }
部屋の移動を完了した時に呼び出す処理を二つに分けました。OnCompleteMoveRoom2はバトル、イベントに突入していても呼び出す関数で、OnCompleteMoveRoomはバトル、イベントに突入しなかった時に呼び出す関数です。バトル、イベントに突入した場合はボタンとマップを表示したくないので、これらの表示関数はOnCompleteMoveRoom2に登録するようにします。
現状QuestManager.csのSerachingの後半でプレイヤーがイベントが配置されている位置に来た時の処理を描いているので、ここにトラップイベントの座標に来た時の処理を追加します。
クリックで展開
IEnumerator Searching() { DialogTextManager.instance.SetScenarios(new string[] { "探索中..." }); //背景を大きく questBG.transform.DOScale(new Vector3(1.5f, 1.5f, 1.5f), 2f) .OnComplete(() => questBG.transform.localScale = new Vector3(1, 1, 1)); //フェードアウト SpriteRenderer questBGSpriteRenderer = questBG.GetComponent<SpriteRenderer>(); questBGSpriteRenderer.DOFade(0, 2f) .OnComplete(() => questBGSpriteRenderer.DOFade(1, 0)); //2秒間処理を待機 yield return new WaitForSeconds(2f); if (encountRate >= UnityEngine.Random.Range(1, 101)) { DialogTextManager.instance.SetScenarios(new string[] { "敵と遭遇した!!" }); yield return new WaitForSeconds(1.2f); SoundManager.instance.PlaySE(8); nowBattle = true; yield return StartCoroutine(EncountEnemy()); //コルーチン呼び出し 変更 } StartCoroutine(dangionController.InformDangeonEvent()); //プレイヤーがイベントの配置されている座標に到達したらダイアログに表示する if(dangionController.eventID != -1) //何かイベントが配置されていれば { stageUI.SetActionButton(true); //ActionButtonをActiveにする stageUI.isEventPosition = true; if(dangionController.eventID == 7)//トラップイベントの場合は { stageUI.SetActionButton(false);//ActionButtonをActiveにしない nowEvent = true; //イベント中のフラグをたてる } } }
トラップイベントの場合のみ処理を分岐させています。個々の処理は後々変更があると思います。
さらにトラップイベントが終わったあとにマップの表示と、ボタンの表示、nowEventフラグをfalseにします。
クリックで展開
public IEnumerator InformDangeonEvent() { eventID = GetCurrentPosDangeonEventID(); DangeonEvent dangeonEvent = new DangeonEvent(); switch (eventID) { case -1://何もなし yield break; case 0://採掘イベントを知らせる StartCoroutine(dangeonEvent.IEInformMineEvent()); yield break; case 1://釣りイベントを知らせる StartCoroutine(dangeonEvent.IEInformFishingEvent()); yield break; case 2: //アイテムイベントを知らせる StartCoroutine(dangeonEvent.IEInformItemEvent()); yield break; case 3: //伐採イベントを知らせる StartCoroutine(dangeonEvent.IEInformLoggingEvent()); yield break; case 4: //金貨イベントを知らせる StartCoroutine(dangeonEvent.IEInformGoldEvent()); yield break; case 5: //下階段イベントを知らせる StartCoroutine(dangeonEvent.IEInformDownFloorEvent()); yield break; case 6: //上階段イベントを知らせる StartCoroutine(dangeonEvent.IEInformUpFloorEvent()); yield break; case 7: //トラップイベントを実行する yield return StartCoroutine(dangeonEvent.IETrapEvent(5,questManager)); DeleteEvent(); //------------------New---------- stageUIManager.isEventPosition = false; dangionMap.ShowDangeonMapForSearching(); stageUIManager.ShowButtonsForSearching(); questManager.nowEvent = false; //------------------Newここまで---------- yield break; case 8: //スイッチで開く扉イベントを知らせる StartCoroutine(dangeonEvent.IEInformSwitchDoorEvent()); yield break; case 9://青いスイッチ(OFF)イベント StartCoroutine(dangeonEvent.IEInformOffBlueSwitchEvent()); yield break; case 10://青いスイッチ(ON)イベント StartCoroutine(dangeonEvent.IEInformOnBlueSwitchEvent()); yield break; } }
DangeonMap.csにイベントのアイコンを更新する関数を作成します。
クリックで展開
public void UpdateEventIcon(int posX, int posY) //New { if(posOfEvent[questManager.currentFloor -1,posY,posX] == -1) { eventIcons[posX, posY].GetComponent<Image>().color = new Color(1, 1, 1, 0); } else { eventIcons[posX, posY].GetComponent<Image>().sprite = dangionMapSystem.GetComponent<DangionData>().eventIcons[posOfEvent[questManager.currentFloor - 1, posX, posY]]; } }
UpdateEventIcon関数をスイッチで開く扉が開いた後と青いスイッチイベント(OFF)完了後に呼び出します。
クリックで展開
public IEnumerator IEDangeonEventProcess() { stageUIManager.SetActionButton(false); stageUIManager.SetArrowsButton(false); eventID = GetCurrentPosDangeonEventID(); DangeonEvent dangeonEvent = new DangeonEvent(); switch (eventID) { case -1://何もなし break; case 0://採掘イベント yield return dangeonEvent.IEMineEvent(mineItemGroup); RegistryEventMemory(dangeonEvent,3,5,playerPos.x,playerPos.y,0); break; case 1://釣りイベント yield return dangeonEvent.IEFishingEvent(fisingItemGroup); RegistryEventMemory(dangeonEvent, 3,5, playerPos.x, playerPos.y, 1); break; case 2: //アイテムイベント yield return dangeonEvent.IEItemEvent(itemEventGroup); RegistryEventMemory(dangeonEvent, 3, 5, playerPos.x, playerPos.y, 2); DeleteEvent(); break; case 3: //伐採イベント yield return dangeonEvent.IELoggingEvent(loggingItemGroup); RegistryEventMemory(dangeonEvent, 3, 5, playerPos.x, playerPos.y, 3); break; case 4: //金貨イベント yield return dangeonEvent.IEGetGoldEvent(Random.Range(minGold, maxGold + 1)); playerUIManager.UpdateUI(PlayerManager.instance); DeleteEvent(); break; case 5: //階段を降りるイベント yield return dangeonEvent.IEDownFloorEvent(dangionMap, questManager,stageUIManager,this); break; case 6: //階段を上がるイベント yield return dangeonEvent.IEUpFloorEvent(dangionMap, questManager, stageUIManager,this); break; case 7://7はトラップイベントだが配置された位置に到達した時に実行されるのでここでは何もしない(というかここには処理が来ない) break; case 8: //スイッチで開く扉イベント yield return dangeonEvent.IEUpSwitchDoorEvent(); break; case 9: ////青いスイッチ(OFF)イベント yield return dangeonEvent.IEOFFBlueSwitchEvent(dangionMap,questManager,this); dangionMap.UpdateEventIcon(playerPos.x,playerPos.y); //New break; case 10: ////青いスイッチ(ON)イベント yield return dangeonEvent.IEONBlueSwitchEvent(); break; } if (!shouldActiveActionButton) { shouldActiveActionButton = true; } else if(shouldActiveActionButton) { stageUIManager.actionButton.SetActive(true); } stageUIManager.SetArrowsButton(true); yield return null; }
クリックで展開
public IEnumerator IEOFFBlueSwitchEvent(DangionMap dangionMap, QuestManager questManager, DangionController dangionController) //New { SoundManager.instance.PlaySE(29); DialogTextManager.instance.SetScenarios(new string[] { PlayerManager.instance.pname + "はスイッチを押した"}); yield return new WaitForSeconds(2f); int floor = questManager.currentFloor - 1; int py = dangionController.playerPos.y; int px = dangionController.playerPos.x; dangionMap.posOfEvent[floor, py, px] = 10;//イベントの種類を青スイッチ(ON)にする bool pushAllBlueSwitch = true; for (int j = 0; j < dangionController.dangion_height; j++) { for (int i = 0; i < dangionController.dangion_width; i++) { if (dangionMap.posOfEvent[floor, j, i] == 9)//一つでもOFFの青スイッチがあったらフラグをfalseにする { pushAllBlueSwitch = false; } } } if (pushAllBlueSwitch) //OFFの青スイッチが一つもなければ { for (int j = 0; j < dangionController.dangion_height; j++) { for (int i = 0; i < dangionController.dangion_width; i++) { if (dangionMap.posOfEvent[floor, j, i] == 8)//スイッチで開く扉のイベントを探し出して { dangionMap.posOfEvent[floor, j, i] = 5; //イベントを下り階段に変更する dangionMap.DeleteEventIcon(i,j);//アイコンを削除 SoundManager.instance.PlaySE(30); DialogTextManager.instance.SetScenarios(new string[] { "扉が開いた"}); yield return new WaitForSeconds(2f); dangionMap.UpdateEventIcon(i,j); } } } } }
これで実行すると以下の動画のようになります
次回はワープイベントを作成しようと思います。