【Unity】RPG制作 その18-探索時のイベント処理
今回は探索時にイベントを発生させる処理を作っていきます。探索時にDangeon関連の処理を実行できるようにQuestManager.csでDangeonController型の変数を定義します。
次に、DangeonController.csに現在のプレイヤーの座標に配置されているイベントのIDを取得する関数を定義します。
クリックで展開
public int GetCurrentPosDangeonEventID() //New { int id = dangionMap.posOfEvent[playerPos.y, playerPos.x]; return id; }
イベントが配置されている地点に到達したらダイアログを表示する関数を宣言します。
クリックで展開
public void InformDangeonEvent() { eventID = GetCurrentPosDangeonEventID(); DangeonEvent dangeonEvent = new DangeonEvent(); switch (eventID) { case -1://何もなし break; case 0://採掘イベントを知らせる dangeonEvent.IEInformMineEvent(); break; case 1://釣りイベントを知らせる dangeonEvent.IEInformFishingEvent(); break; case 2: //アイテムイベントを知らせる dangeonEvent.IEInformItemEvent(); break; case 3: //伐採イベントを知らせる dangeonEvent.IEInformLoggingEvent(); break; case 4: //金貨イベントを知らせる dangeonEvent.IEInformGoldEvent(); break; } }
eventIDは関数の外でint型で定義しておきます。次に、イベントを発動させるActionButtonを作成します。
StageUIManager.csでActionButtonを制御できるようにしておきます。
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; //StageUIを管理(ステージ数のUI/進行ボタン/街に戻るボタン)の管理 public class StageUIManager : MonoBehaviour { public Text stageText; public GameObject nextButton; public GameObject toTownButton; public GameObject stageClearImage; public GameObject itemButton; public GameObject statusButton; public GameObject cancelButton; public GameObject mapButton; public GameObject debugButton; public GameObject arrowsButtons; public GameObject actionButton; //New public GameObject itemUI; public GameObject itemUsePanel; public DangionMap dangionMap; public bool isEventPosition = false; //プレイヤーの現在地がイベントのは位置されている座標かどうか New private void Start() { stageClearImage.SetActive(false); cancelButton.SetActive(false); } public void InitUI() { stageClearImage.SetActive(false); stageText.text = string.Format("ステージ:{0}", 1); cancelButton.SetActive(false); } public void UpdateUI(int currentStage) { stageText.text = string.Format("ステージ:{0}", currentStage); } public void HideButtons() { nextButton.SetActive(false); toTownButton.SetActive(false); itemButton.SetActive(false); statusButton.SetActive(false); mapButton.SetActive(false); debugButton.SetActive(false); arrowsButtons.SetActive(false); cancelButton.SetActive(false); actionButton.SetActive(false); //New } public void ShowButtons() { nextButton.SetActive(true); toTownButton.SetActive(true); itemButton.SetActive(true); statusButton.SetActive(true); mapButton.SetActive(true); debugButton.SetActive(true); arrowsButtons.SetActive(true); if (isEventPosition) //New { actionButton.SetActive(true); } } public void ShowButtons(bool isTrue) { nextButton.SetActive(isTrue); toTownButton.SetActive(isTrue); itemButton.SetActive(isTrue); statusButton.SetActive(isTrue); mapButton.SetActive(isTrue); debugButton.SetActive(isTrue); arrowsButtons.SetActive(isTrue); } public void ShowButtonsForSearching() { if (dangionMap.isOpenDangeonMap) { cancelButton.SetActive(true); arrowsButtons.SetActive(true); } else { ShowButtons(); } } public void PushItemButton() { nextButton.SetActive(false); toTownButton.SetActive(false); itemButton.SetActive(false); statusButton.SetActive(false); cancelButton.SetActive(true); mapButton.SetActive(false); debugButton.SetActive(false); arrowsButtons.SetActive(false); actionButton.SetActive(false); //New } public void PushMapButton() { nextButton.SetActive(false); toTownButton.SetActive(false); itemButton.SetActive(false); statusButton.SetActive(false); cancelButton.SetActive(true); mapButton.SetActive(false); debugButton.SetActive(false); arrowsButtons.SetActive(true); actionButton.SetActive(false); //New } public void PushStatusButton() { nextButton.SetActive(false); toTownButton.SetActive(false); itemButton.SetActive(false); statusButton.SetActive(false); cancelButton.SetActive(true); mapButton.SetActive(false); debugButton.SetActive(false); arrowsButtons.SetActive(false); actionButton.SetActive(false); //New } public void PushCancelButton() { if (itemUsePanel.activeInHierarchy) { itemUsePanel.gameObject.SetActive(false); itemUI.GetComponent<ItemUI>().canTapItemUI = true; return; } nextButton.SetActive(true); toTownButton.SetActive(true); itemButton.SetActive(true); statusButton.SetActive(true); cancelButton.SetActive(false); mapButton.SetActive(true); debugButton.SetActive(true); arrowsButtons.SetActive(true); if (isEventPosition) //New { actionButton.SetActive(true); } } public void PushDebugButton() { nextButton.SetActive(false); toTownButton.SetActive(false); itemButton.SetActive(false); statusButton.SetActive(false); cancelButton.SetActive(true); mapButton.SetActive(false); debugButton.SetActive(false); arrowsButtons.SetActive(false); actionButton.SetActive(false); //New } public void ShowClearText() { stageClearImage.SetActive(true); nextButton.SetActive(false); toTownButton.SetActive(true); itemButton.SetActive(false); statusButton.SetActive(false); mapButton.SetActive(false); debugButton.SetActive(true); arrowsButtons.SetActive(false); actionButton.SetActive(false); //New } public void SetActionButton(bool isActive) //New { actionButton.SetActive(isActive); }
ActionButtonはイベントが配置されている座標でのみ表示したいので、bool型のisEventPosition変数で処理の分岐をさせています。Questmanager.csのSearchingコルーチンで以下の処理を追加して探索後にボタンをアクティブにするかどうかを判定させて、フラグの変更も行います。
クリックで展開
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); currentFloor++; // 進行度をUIに反映 stageUI.UpdateUI(currentFloor); if(stageLength <= currentFloor) { QuestClear(); }else 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()); //コルーチン呼び出し 変更 } else { stageUI.ShowButtonsForSearching(); } //--------------ここからNew----------- dangionController.InformDangeonEvent(); //プレイヤーがイベントの配置されている座標に到達したらダイアログに表示する if(dangionController.eventID != -1) //何かイベントが配置されていれば { stageUI.SetActionButton(true); //ActionButtonをActiveにする stageUI.isEventPosition = true; } else { stageUI.isEventPosition = false; } //--------------Newここまで----------- }
クリックで展開
public IEnumerator IEDangeonEventProcess() //New { eventID = GetCurrentPosDangeonEventID(); DangeonEvent dangeonEvent = new DangeonEvent(); dangeonEvent.stageUIManager = this.stageUIManager; 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; } Debug.Log("ActionButtonアクティブ前"); if (!shouldActiveActionButton) { shouldActiveActionButton = true; } else if(shouldActiveActionButton) { Debug.Log("shouldActive"); stageUIManager.actionButton.SetActive(true); } yield return null; } public void RegistryEventMemory(DangeonEvent dangeonEvent,int minCount,int maxCount,int posX, int posY,int eventID) //New { bool doneRegistry = CheckAlreadyRegiEventFromPos(); if (!doneRegistry) { //登録されていない場合は新規登録 for (int i = 0; i < danGeonEventMemories.Length; i++) { if (danGeonEventMemories[i].isRegistry == false)//登録できる場所があったら { danGeonEventMemories[i].dEvent = dangeonEvent; danGeonEventMemories[i].lastCount = Random.Range(minCount, maxCount + 1); danGeonEventMemories[i].posX = posX; danGeonEventMemories[i].posY = posY; danGeonEventMemories[i].isRegistry = true; dangeonEvent.memoryID = i;//memory用のidをeventに保持させておく dangeonEvent.eventID = eventID; } } DecreaseEventsLastCount(dangeonEvent); } else { //登録されている場合は登録されているDangeonEventに対して処理を行う int memoryID = GetRegiEventFromPos(posX, posY); DecreaseEventsLastCount(danGeonEventMemories[memoryID].dEvent); } } /// <summary> /// dangeonEventのmemoryIDを使ってそのdangeonEventがすでに登録されているかどうかチェックし、bool型の値を返します。 /// </summary> public int GetRegiEventFromPos(int posX, int posY) //New { for (int i = 0; i < danGeonEventMemories.Length; i++) { if (danGeonEventMemories[i].posX == playerPos.x && danGeonEventMemories[i].posY == playerPos.y) { return i; } } return 0; } public bool CheckAlreadyRegiEventFromPos() //New { Debug.Log("danGeonEventMemories=" + danGeonEventMemories); for (int i = 0; i < danGeonEventMemories.Length; i++) { Debug.Log("danGeonEventMemories[i]=" + danGeonEventMemories[i]); Debug.Log("danGeonEventMemories[i].posX=" + danGeonEventMemories[i].posX); if (danGeonEventMemories[i].posX == playerPos.x && danGeonEventMemories[i].posY == playerPos.y) { return true; } } return false; } public void DecreaseEventsLastCount(DangeonEvent dangeonEvent) //New { danGeonEventMemories[dangeonEvent.memoryID].lastCount--; if(danGeonEventMemories[dangeonEvent.memoryID].lastCount == 0) { DeleteRegiEvent(dangeonEvent); } } public void DeleteRegiEvent(DangeonEvent dangeonEvent) //New { if(dangeonEvent.memoryID != -1) { danGeonEventMemories[dangeonEvent.memoryID] = new DangeonEventMemory(); dangionMap.posOfEvent[playerPos.y, playerPos.x] = -1; dangionMap.DeleteEventIcon(playerPos.y,playerPos.x); shouldActiveActionButton = false; } } public void DeleteEvent()//単にイベントを消す処理(登録なしで処理するイベントの場合に使用) { dangionMap.posOfEvent[playerPos.y, playerPos.x] = -1; dangionMap.DeleteEventIcon(playerPos.y, playerPos.x); shouldActiveActionButton = false; } public void InitDangeonEventmemories() //New { for(int i=0;i < danGeonEventMemories.Length; i++) { danGeonEventMemories[i] = new DangeonEventMemory(); } } } public class DangeonEventMemory//New { public DangeonEvent dEvent; public int lastCount = 0; //このイベントが後何回じっこうされたら消滅するか public int posX = -1, posY = -1; public bool isRegistry = false; public DangeonEventMemory() { dEvent = new DangeonEvent(); posX = -1; posY = -1; isRegistry = false; } }
イベントを4種類作成しました。IEDangeonEventProcessの処理に入ったら現在地のeventIDを取得し、IDが1~4の場合は各イベントを実行します。イベントはdangeonEventクラスで処理を行っていくのですが、イベントを数回発生させるタイプのイベントの場合(ここでは採掘イベント、伐採イベント、釣りイベント)、RegistryEvent関数でDangeonEventMemory型の配列にEventのデータを登録しておきます。DangeonEventMemoryクラスでは、イベントの残り回数やX,Y座標、dangeonEventクラスを保持できるのですが、これらの情報を使用して、イベントをマップ上に残しておくか、消すべきかを判定させます。
ちなみにIEDangionEventProcessのスイッチ内イベント処理の中身はこんな感じです。
クリックで展開
public IEnumerator IEMineEvent(ItemGroup itemGroup) { stageUIManager.SetActionButton(false); if(ItemManager.instance.itemCountDictionary[ItemManager.Item.Pickaxe] > 0) { int skillLevel = PlayerManager.instance.SkillLevelDic[PlayerManager.SKILL.Mining]; if(skillLevel == 0) { DialogTextManager.instance.SetScenarios(new string[] { PlayerManager.instance.pname + "は採掘のやり方を知らない"}); yield return new WaitForSeconds(1.2f); } else { SoundManager.instance.PlaySE(25); yield return new WaitForSeconds(0.6f); SoundManager.instance.PlaySE(25); yield return new WaitForSeconds(0.6f); SoundManager.instance.PlaySE(25); yield return new WaitForSeconds(0.6f); if (ItemManager.instance.itemDatas[37].probabilityOfBreak > Random.Range(0, 101)) { SoundManager.instance.PlaySE(26); DialogTextManager.instance.SetScenarios(new string[] { ItemManager.instance.itemDatas[37].itemName + "が壊れた"}); yield return new WaitForSeconds(1.2f); ItemManager.instance.itemCountDictionary[ItemManager.Item.Pickaxe]--; } getItem = itemGroup.DecideItemData(); if(getItem != null) { DialogTextManager.instance.SetScenarios(new string[] { getItem.itemName + "を手に入れた!"}); ItemManager.instance.itemCountDictionary[getItem.itemID]++; yield return new WaitForSeconds(1.2f); } else { DialogTextManager.instance.SetScenarios(new string[] { "??何もない??"}); yield return new WaitForSeconds(1.2f); } } } else { DialogTextManager.instance.SetScenarios(new string[] { "つるはしを持っていない。"}); yield return new WaitForSeconds(1.2f); } }
採掘イベントのコードだけ書いています。(全部載せると膨大な量になるので・・・)採掘イベントの場合は採掘スキルとつるはしが必要になるのでつるはしの所持個数と採掘スキルを所持しているかで処理を分けています。
実際に動かし見ると以下の動画のようになります。
これで探索時にイベントを実行できるようになりました。このイベントを自動的に配置できるようにしたいですが、次回は先にダンジョンの次の階層に進む処理を実装していきたいと思います。