/// <summary> /// 最下段の空ブロックを取得 /// </summary> public PPPanelBlock GetMostUnderEmptyBlock(ref int depth) { // 真下にブロックがある PPPanelBlock under = GetLink(Dir.Down) as PPPanelBlock; if (under != null) { // 真下が空なら更に下へ if (under.AttachedPanel == null) { ++depth; return((GetLink(Dir.Down) as PPPanelBlock).GetMostUnderEmptyBlock(ref depth)); } // // 真下のパネルがロック中 // else if (under.AttachedPanel.IsLoced()) // { // return null; // } // 真下にパネルがある else { return(this); } } // 真下にブロックがない else { return(this); } }
/// <summary> /// パネル落下時の通過ブロックを取得 /// </summary> public bool GetFallPassBlock(ref List <PPPanelBlock> blocks) { // 真下にブロックがある PPPanelBlock under = GetLink(Dir.Down) as PPPanelBlock; if (under != null) { // 真下が空なら更に下へ if (under.AttachedPanel == null) { blocks.Add(under); return((GetLink(Dir.Down) as PPPanelBlock).GetFallPassBlock(ref blocks)); } // 真下のパネルがロック中 else if (under.AttachedPanel.IsLocked()) { return(false); // 落下不可 } // 真下にパネルがある else { return(blocks.Count > 0); } } // 真下にブロックがない else { return(blocks.Count > 0); } }
/// <summary> /// 落下可能? /// </summary> public bool IsValidFall() { if (IsDisturbance && Block != null) { // 最下段の水平方向の連結妨害パネルブロックを取得 List <PPPanel> links; List <PPPanel> horizontal = new List <PPPanel>(); PPPanel mostUnderDisturb = GetEndDisturb(PlayAreaBlock.Dir.Down); horizontal.Add(mostUnderDisturb); mostUnderDisturb.GetDisturbLinks(out links, PlayAreaBlock.Dir.Left); horizontal.AddRange(links); mostUnderDisturb.GetDisturbLinks(out links, PlayAreaBlock.Dir.Right); horizontal.AddRange(links); // 最下段の連結妨害パネルの直下が空ブロックか調べる foreach (PPPanel disturb in horizontal) { if (disturb.Block != null) { PPPanelBlock underBlock = disturb.Block.GetLink(PlayAreaBlock.Dir.Down) as PPPanelBlock; if (underBlock != null && underBlock.AttachedPanel != null) { return(false); } } } } return(true); }
/// <summary> /// 初期化 /// </summary> public void Initialize(PPPlayArea area, List <Type> ignoreTypes) { gameObject.SetActive(true); m_Area = area; m_Block = null; m_State = State.None; m_Active = false; m_IsChainSource = false; IgnoreChainSource = false; m_PlayingCoroutine = null; IsDisturbance = false; for (int i = 0; i < m_DisturbLinks.Length; i++) { m_DisturbLinks[i] = null; } List <Type> validTypes = new List <Type>(); for (int i = (int)Type.ColorA; i <= (int)Type.ColorF; i++) { if (!ignoreTypes.Contains((Type)i)) { validTypes.Add((Type)i); } } m_Type = validTypes[area.Game.Controller.SyncRand.Next(validTypes.Count)]; m_SpriteRenderer.enabled = true; m_SpriteRenderer.sprite = Resources.Load("PanelDePon/Panel_0" + ((int)m_Type - 1).ToString(), typeof(Sprite)) as Sprite; m_SpriteRenderer.color = Color.gray; }
/// <summary> /// 交換開始 /// </summary> public void BeginSwap(PPPanelBlock target) { if (m_State == State.None) { m_State = State.Move; StartCoroutine(m_PlayingCoroutine = Swaping(target)); } }
/// <summary> /// 落下待機開始 /// </summary> public void BeginFallReady(PPPanelBlock startBlock) { if (m_State == State.None) { m_State = State.FallReady; StartCoroutine(m_PlayingCoroutine = FallReady(startBlock)); } }
/// <summary> /// パネル交換 /// </summary> public PPPanelBlock SwapPanel(PPPanelBlock block, PlayAreaBlock.Dir dir) { if (block != null && !block.IsLoced() && block.AttachedPanel != null && !block.AttachedPanel.IsDisturbance) { PPPanelBlock target = block.GetLink(dir) as PPPanelBlock; if (target != null && !target.IsLoced() && !target.GetIsUpperBlockFallWait() && (target.AttachedPanel == null || !target.AttachedPanel.IsDisturbance)) { // 対象ブロックを落下中のパネルが通過中ならキャンセル foreach (PPPanel panel in m_UsingPanels) { if (panel.IsFalling()) { if ((block.TestInsideY(panel.transform.position.y, BlockSize) && block.TestInsideX(panel.transform.position.x, BlockSize, false)) || (target.TestInsideY(panel.transform.position.y, BlockSize) && target.TestInsideX(panel.transform.position.x, BlockSize, false))) { return(null); } } } // 交換 PPPanel t = block.AttachedPanel; block.Attach(target.AttachedPanel); target.Attach(t); // スワップ開始 if (block.AttachedPanel != null) { block.AttachedPanel.BeginSwap(block); } if (target.AttachedPanel != null) { target.AttachedPanel.BeginSwap(target); } // 移動先の下が空ブロックなら連鎖無効 PPPanelBlock tempBlock = target.GetLink(PlayAreaBlock.Dir.Down) as PPPanelBlock; if (tempBlock != null && tempBlock.AttachedPanel == null) { target.AttachedPanel.IgnoreChainSource = true; } // 空ブロックとの交換なら移動元から上を連鎖無効 if (block.AttachedPanel == null) { tempBlock = block; while ((tempBlock = tempBlock.GetLink(PlayAreaBlock.Dir.Up) as PPPanelBlock) != null && tempBlock.AttachedPanel != null && !tempBlock.AttachedPanel.IsDisturbance) { tempBlock.AttachedPanel.IgnoreChainSource = true; } } return(target); } } return(null); }
/// <summary> /// パネル入れ替え /// </summary> private void SwapPanel(PPPanelBlock block, PlayAreaBlock.Dir dir) { PlayerController.CommandData command = new PlayerController.CommandData(); command.type = (byte)PlayerController.CommandType.PP_Swap; command.values = new sbyte[2]; Vector2i grid = (Game as PPGame).PlayArea.GetBlockGrid(block); command.values[0] = (sbyte)(grid.y * PPGame.Config.PlayAreaWidth + grid.x); command.values[1] = (sbyte)dir; SetNextCommand(command); }
/// <summary> /// 指定方向に連続した同タイプのパネル数を取得 /// </summary> public int GetMatchPanelCountDir(Dir dir) { int count = 0; if (AttachedPanel != null) { count = 1; PPPanel.Type type = AttachedPanel.PanelType; PPPanelBlock block = this; while ((block = block.GetLink(dir) as PPPanelBlock) != null && block.AttachedPanel != null && block.AttachedPanel.PanelType == type) { ++count; } } return(count); }
/// <summary> /// ブロックのグリッド座標を取得 /// </summary> public Vector2i GetBlockGrid(PPPanelBlock block) { for (int y = 0; y < m_Lines.Count; y++) { for (int x = 0; x < m_Lines[y].Length; x++) { if (m_Lines[y][x] == block) { return(new Vector2i(x, y)); } } } Debug.LogWarning(block.ToString() + " is not found"); return(Vector2i.zero); }
/// <summary> /// 交換中 /// </summary> public IEnumerator Swaping(PPPanelBlock target) { while (true) { Vector3 dir = target.Position - transform.position; Vector3 move = dir.normalized * GameManager.TimeStep * PPGame.Config.PanelSwapSpeed; transform.position += move; if (dir.magnitude - move.magnitude < 0) { transform.position = target.Position; break; } yield return(null); } m_State = State.None; m_PlayingCoroutine = null; }
/// <summary> /// パネル落下 /// </summary> public void FallPanel() { PPPanelBlock fallTarget = null; // 下から2行目から上をチェック for (int i = m_Lines.Count - 2; i >= 0; i--) { foreach (PPPanelBlock block in m_Lines[i]) { if (!block.IsLoced() && block.AttachedPanel != null && block.AttachedPanel.IsValidFall()) { // 落下地点取得 if ((fallTarget = block.GetMostUnderEmptyBlock()) != null && fallTarget != block) { // 落下待機開始 block.AttachedPanel.BeginFallReady(block); } } } } }
/// <summary> /// 落下待機 /// </summary> public IEnumerator FallReady(PPPanelBlock startBlock) { // 連鎖ソース if (!IgnoreChainSource) { m_IsChainSource = true; } IgnoreChainSource = false; float waitTime = PPGame.Config.PanelFallWaitTime; while (waitTime >= 0f) { waitTime -= GameManager.TimeStep; yield return(null); } m_State = State.None; m_PlayingCoroutine = null; BeginFall(startBlock); }
/// <summary> /// 落下中止 /// </summary> private void StopFall(PPPanelBlock fallTarget) { if (m_State == State.Fall) { m_State = State.None; // 連結妨害パネルも落下中止 if (IsDisturbance) { for (int i = 0; i < m_DisturbLinks.Length; i++) { if (m_DisturbLinks[i] != null) { m_DisturbLinks[i].StopFall(fallTarget.GetLink((PlayAreaBlock.Dir)i) as PPPanelBlock); } } } // 落下地点にアタッチ fallTarget.Attach(this, true); // 下の落下待機パネルに連鎖ソースを伝搬 if (m_IsChainSource) { for (int i = 0; i < 2; i++) { PPPanelBlock vertBlock = fallTarget.GetLink(i == 0 ? PlayAreaBlock.Dir.Down : PlayAreaBlock.Dir.Up) as PPPanelBlock; if (vertBlock != null && vertBlock.AttachedPanel != null && vertBlock.AttachedPanel.CurrentState == State.FallReady) { vertBlock.AttachedPanel.m_IsChainSource = true; } } } StopCoroutine(m_PlayingCoroutine); m_PlayingCoroutine = null; } }
/// <summary> /// コマンド実行 /// </summary> public override void ExecuteCommand(PlayerController.CommandData command) { PPPlayArea playArea = (Game as PPGame).PlayArea; switch ((PlayerController.CommandType)command.type) { case PlayerController.CommandType.PP_Swap: if (command.values != null) { Vector2i grid = new Vector2i(command.values[0] % PPGame.Config.PlayAreaWidth, command.values[0] / PPGame.Config.PlayAreaWidth); PPPanelBlock result = playArea.SwapPanel(playArea.GetBlock(grid), (PlayAreaBlock.Dir)command.values[1]); if (result != null) { m_TouchedBlock = result; } } break; case PlayerController.CommandType.PP_Add: playArea.ElevateValue = PPGame.Config.ManualElevateSpeed; playArea.MaxElevateWaitTime = PPGame.Config.ManualElevateInterval; playArea.SkipElevateWait(); break; } // ダメージ DamageTable.DamageData damage = GetDamageData((PlayerController.DamageType)command.damageType, command.damageValue); if (damage != null) { foreach (var disturbData in damage.PPDisturb) { for (int i = 0; i < disturbData.count; i++) { (Game as PPGame).PlayArea.CreateDisturbPanel(disturbData.width, disturbData.height); } } } }
/// <summary> /// 落下中 /// </summary> public IEnumerator Falling(PPPanelBlock startBlock) { // 開始地点からデタッチ startBlock.Detach(); PPPanelBlock curBlock = startBlock; PPPanelBlock fallTarget = startBlock; PPPanelBlock bottom = null; while (true) { // 移動 Vector3 move = -Vector3.up * GameManager.TimeStep * PPGame.Config.PanelFallSpeed; transform.position += move; // 移動先を超えたら移動先を再設定 if (transform.position.y <= fallTarget.Position.y) { curBlock = fallTarget; bottom = curBlock.GetLink(PlayAreaBlock.Dir.Down) as PPPanelBlock; if (bottom != null && bottom.AttachedPanel == null) { fallTarget = bottom; } else { transform.position = curBlock.Position; break; } } yield return(null); } StopFall(curBlock); }
/// <summary> /// 落下開始 /// </summary> public void BeginFall(PPPanelBlock startBlock) { if (m_State == State.None) { m_State = State.Fall; // 最下段なら連結妨害パネルも落下 if (IsDisturbance && m_DisturbLinks[(int)PlayAreaBlock.Dir.Down] == null) { if (m_DisturbLinks[(int)PlayAreaBlock.Dir.Left] != null) { m_DisturbLinks[(int)PlayAreaBlock.Dir.Left].BeginFall(startBlock.GetLink(PlayAreaBlock.Dir.Left) as PPPanelBlock); } if (m_DisturbLinks[(int)PlayAreaBlock.Dir.Right] != null) { m_DisturbLinks[(int)PlayAreaBlock.Dir.Right].BeginFall(startBlock.GetLink(PlayAreaBlock.Dir.Right) as PPPanelBlock); } } StartCoroutine(m_PlayingCoroutine = Falling(startBlock)); // 1つ上のパネルも落下 PPPanelBlock upBlock = startBlock.GetLink(PlayAreaBlock.Dir.Up) as PPPanelBlock; if (upBlock != null && !upBlock.IsLoced() && upBlock.AttachedPanel != null && upBlock.AttachedPanel.IsValidFall()) { // 連鎖ソース if (!upBlock.AttachedPanel.IgnoreChainSource) { upBlock.AttachedPanel.m_IsChainSource = true; } upBlock.AttachedPanel.IgnoreChainSource = false; upBlock.AttachedPanel.BeginFall(upBlock); } } }
/// <summary> /// 新規行追加 /// </summary> public PPPanelBlock[] AddNewLine(bool empty, bool insertHead, List <int> emptyRow = null) { // 現在の最上段/最下段の行を取得 PPPanelBlock[] sideLine = null; if (m_Lines.Count > 0) { sideLine = insertHead ? m_Lines[0] : m_Lines[m_Lines.Count - 1]; } PPPanelBlock[] line = new PPPanelBlock[Width]; PPPanel panel; PPPanelBlock block; Vector3 pos; List <PPPanel.Type> ignoreTypes = new List <PPPanel.Type>(); // パネル生成 for (int i = 0; i < line.Length; i++) { // ブロック生成 block = new PPPanelBlock(); block.BaseTransform = m_BlockParent.transform; // 座標登録 pos = Vector3.zero; pos.x = i * BlockSize - m_Size.x / 2f + BlockHalfSize; pos.y = sideLine != null ? sideLine[0].LocalPosition.y + (BlockSize * (insertHead ? 1 : -1)) : 0; block.LocalPosition = pos; // パネル作成 if (!empty && (emptyRow == null || !emptyRow.Contains(i))) { // 使わなくなったパネルを再利用 if (m_UnusedPanels.Count > 0) { panel = m_UnusedPanels[0]; m_UnusedPanels.RemoveAt(0); } // パネル生成 else { panel = Instantiate(PanelTemplate).GetComponent <PPPanel>(); panel.gameObject.transform.SetParent(m_BlockParent.transform, false); m_Panels.Add(panel); } // 無効タイプ設定のため左側だけ接続 if (i > 0) { block.SetLink(line[i - 1], PlayAreaBlock.Dir.Left); } // 無効タイプ設定 ignoreTypes.Clear(); if (i > 0 && line[i - 1].GetMatchPanelCountDir(PlayAreaBlock.Dir.Left) >= PPGame.Config.MinVanishMatchCount - 1) { ignoreTypes.Add(line[i - 1].AttachedPanel.PanelType); } if (!insertHead && sideLine != null && sideLine[i].GetMatchPanelCountDir(PlayAreaBlock.Dir.Up) >= PPGame.Config.MinVanishMatchCount - 1) { ignoreTypes.Add(sideLine[i].AttachedPanel.PanelType); } // パネル初期化 panel.Initialize(this, ignoreTypes); if (insertHead) { panel.Activate(); } block.Attach(panel, true); m_UsingPanels.Add(panel); } line[i] = block; } // 隣接するブロックを登録 for (int i = 0; i < line.Length; i++) { if (i < line.Length - 1) { line[i].SetLink(line[i + 1], PlayAreaBlock.Dir.Right); } if (i > 0) { line[i].SetLink(line[i - 1], PlayAreaBlock.Dir.Left); } if (sideLine != null) { line[i].SetLink(sideLine[i], insertHead ? PlayAreaBlock.Dir.Down : PlayAreaBlock.Dir.Up); if (sideLine[i] != null) { sideLine[i].SetLink(line[i], insertHead ? PlayAreaBlock.Dir.Up : PlayAreaBlock.Dir.Down); if (!insertHead && sideLine[i].AttachedPanel != null) { sideLine[i].AttachedPanel.Activate(); } } } } // 行を追加 if (insertHead) { m_Lines.Insert(0, line); } else { m_Lines.Add(line); } return(line); }
/// <summary> /// 更新 /// </summary> public override void Play() { base.Play(); PPPlayArea playArea = (Game as PPGame).PlayArea; if (Input.GetKeyDown(KeyCode.D)) { (Game as PPGame).PlayArea.CreateDisturbPanel(6, 2); } // タッチした瞬間 if (InputManager.IsTouchDown()) { // タッチブロック保持 m_TouchedBlock = playArea.GetBlock(Camera.main.ScreenToWorldPoint(InputManager.GetTouchPosition())); } // タッチ中 if (InputManager.IsTouch()) { // せり上げ if (InputManager.IsTouchDouble()) { Elevate(); } // 入れ替え else if (m_TouchedBlock != null) { Vector3 worldTouchPos = Camera.main.ScreenToWorldPoint(InputManager.GetTouchPosition()); // 移動先グリッド Vector2i target = playArea.ConvertWorldToGrid(worldTouchPos); // 移動元グリッド Vector2i current = playArea.GetBlockGrid(m_TouchedBlock); if (target != current) { Vector2i dif = target - current; PlayAreaBlock.Dir dir; if (dif.x < 0) { dir = PlayAreaBlock.Dir.Left; } else if (dif.x > 0) { dir = PlayAreaBlock.Dir.Right; } else if (dif.y > 0) { dir = PlayAreaBlock.Dir.Down; } else { dir = PlayAreaBlock.Dir.Up; } // 交換 PPPanelBlock targetBlock = playArea.GetBlock(target); Vector3 distance = targetBlock != null ? targetBlock.Position - worldTouchPos : Vector3.zero; if (targetBlock == null || ((dir == PlayAreaBlock.Dir.Left || dir == PlayAreaBlock.Dir.Right) && Mathf.Abs(distance.x) < PPGame.Config.PanelSwapStartDistance) || ((dir == PlayAreaBlock.Dir.Up || dir == PlayAreaBlock.Dir.Down) && Mathf.Abs(distance.y) < PPGame.Config.PanelSwapStartDistance)) { SwapPanel(m_TouchedBlock, dir); } } } } }
/// <summary> /// パネル消滅 /// </summary> private void VanishPanel() { List <PPPanelBlock> blocks; if (GetAllMatchPanelBlocks(out blocks)) { // ソート blocks.Sort((a, b) => { int dif = (int)Mathf.Ceil(b.Position.y - a.Position.y); return(dif != 0 ? dif : (int)Mathf.Ceil(a.Position.x - b.Position.x)); }); // 消滅 float delay = PPGame.Config.PanelVanishDelay; float totalDelay = delay * blocks.Count; bool existChainSource = false; foreach (PPPanelBlock block in blocks) { if (block.AttachedPanel != null) { block.VanishPanel(delay, totalDelay); delay += PPGame.Config.PanelVanishDelay; // 連鎖ソースチェック if (block.AttachedPanel.IsChainSource && block.AttachedPanel.CurrentState != PPPanel.State.FallReady) { existChainSource = true; } // 妨害パネル解凍 for (int i = 0; i < block.AllLink.Length; i++) { PPPanelBlock side = block.AllLink[i] as PPPanelBlock; if (side != null && side.AttachedPanel != null && side.AttachedPanel.IsDisturbance) { side.DissolveDisturbance(); } } } } // 連鎖カウント if (existChainSource) { ++m_ChainCount; } } // 連鎖ソースフラグを折る foreach (PPPanelBlock[] line in m_Lines) { foreach (PPPanelBlock block in line) { if (block.AttachedPanel != null) { block.AttachedPanel.IsChainSource = false; } } } // パネル消滅イベント (Game.Player as PPPlayer).OnVanishPanel(blocks.Count); }
/// <summary> /// 上のパネルが落下待機中? /// </summary> public bool GetIsUpperBlockFallWait() { PPPanelBlock upper = GetLink(Dir.Up) as PPPanelBlock; return(upper != null && upper.AttachedPanel != null && upper.AttachedPanel.CurrentState == PPPanel.State.FallReady); }