예제 #1
0
    // プレイヤーの行動
    private void ExecutePlayerMove(Dir dir)
    {
        Assert.IsTrue(_acts.Count == 0);

        Loc to = _player.Loc.Forward(dir);

        if (_floor.CanAdvance(_player.Loc, dir) && !ExistsEnemy(to))
        {
            _player.ShowDirection(dir);
            _acts.Add(new ActPlayerMove(_player, dir, FindFieldItem(to)));

            // 移動先にトラップがあるなら、トラップイベントを発生させる
            Trap trap = _floor.FindTrap(to);
            if (trap != null)
            {
                // TODO:Fire確率
                _acts.Add(new ActTrap(_player, trap));
            }

            _acts.AddRange(DetectEnemyAct(to));
            ChangeGameState(GameState.Act);
        }
        else
        {
            // Debug.Log("進めません");
            _player.ChangeDir(dir);
        }
    }
예제 #2
0
 private static bool CanDirectAttack(Loc fm, Loc to, Floor floor)
 {
     if (fm.IsNeighbor(to))
     {
         Dir dir = fm.Toward(to);
         return(floor.CanAdvance(fm, dir));
     }
     return(false);
 }
예제 #3
0
    public static List <Act> Detect(List <Enemy> enemies, Player player, Loc playerNextLoc, Floor floor)
    {
        // プレイヤーが見えない場合の行動
        if (player.IsInvisible())
        {
            return(Detect2(enemies, player, playerNextLoc, floor));
        }

        // 敵をプレイヤーに近い距離順にソートする
        // TODO:プレイヤーから逃げる行動をとる場合は、プレイヤーから遠い順に行動を決める
        enemies.Sort((a, b) => {
            var x = a.Loc.SquareDistance(playerNextLoc);
            var y = b.Loc.SquareDistance(playerNextLoc);

            if (x == y)   // 距離が等しい場合は、row の大きい方を優先する
            {
                return(b.Row.CompareTo(a.Row));
            }
            return(x.CompareTo(y));
        });

        var q = new List <Act>();

        var locs = new bool[floor.Rows, floor.Cols]; // キャラクターの位置
        Func <Loc, bool> existsEnemy = (loc) => {
            int rows = locs.GetLength(0);
            int cols = locs.GetLength(1);
            if (0 <= loc.Row && loc.Row < rows && 0 <= loc.Col && loc.Col < cols)
            {
                return(locs[loc.Row, loc.Col]);
            }
            return(false);
        };

        var used = new bool[enemies.Count];

        for (int i = 0; i < enemies.Count; i++)
        {
            if (enemies[i].ActCount <= 0) // 行動済み
            {
                used[i] = true;           // 行動済み
            }
            else if (enemies[i].IsBehavioralIncapacitation())
            {
                used[i] = true;
            }
            Loc loc = enemies[i].Loc;
            locs[loc.Row, loc.Col] = true;
        }
        locs[playerNextLoc.Row, playerNextLoc.Col] = true;

        // 遠距離攻撃をする敵
        // - プレイヤーと同じ部屋にいる
        // - プレイヤーは直線上に位置する
        // - プレイヤーとの間に障害物や敵は存在しない
        for (int i = 0; i < enemies.Count; i++)
        {
            if (used[i])
            {
                continue;
            }
            if (!enemies[i].CanLongDistanceAttack)
            {
                continue;
            }

            if (floor.InSight(enemies[i].Loc, playerNextLoc))
            {
                if (enemies[i].Loc.Row == playerNextLoc.Row ||
                    enemies[i].Loc.Col == playerNextLoc.Col ||
                    Math.Abs(enemies[i].Loc.Row - playerNextLoc.Row) == Math.Abs(enemies[i].Loc.Col - playerNextLoc.Col))
                {
                    Dir front = enemies[i].Loc.Toward(playerNextLoc);
                    Loc loc   = enemies[i].Loc.Forward(front);

                    bool ok = true;
                    while (loc != playerNextLoc)
                    {
                        // 敵が存在する。障害物があるなら遠距離攻撃しない
                        if (locs[loc.Row, loc.Col] || floor.ExistsObstacle(loc) || floor.IsWall(loc))
                        {
                            ok = false;
                            break;
                        }

                        loc = loc.Forward(front);
                    }

                    Debug.Log("ok = " + ok);
                    if (ok)   // 遠距離攻撃を行う
                    {
                        q.Add(new ActEnemyLongDistanceAttack(enemies[i], player, playerNextLoc));
                        used[i] = true;
                    }
                }
            }
        }

        // 移動するキャラ
        bool updated = true;

        while (updated)
        {
            updated = false;
            for (int i = 0; i < enemies.Count; i++)
            {
                if (used[i])
                {
                    continue;
                }

                var enemy = enemies[i];
                Assert.IsTrue(locs[enemy.Loc.Row, enemy.Loc.Col]);

                if (CanDirectAttack(enemy.Loc, playerNextLoc, floor))
                {
                    continue;
                }

                // 移動先を決める
                if (floor.InSight(enemy.Loc, playerNextLoc))   // プレイヤーが視界内

                // 敵が部屋にいて、プレイヤーが部屋の入り口にいるならターゲットとして追尾
                {
                    if (floor.IsRoom(enemy.Loc) && floor.IsEntrance(playerNextLoc))
                    {
                        enemy.LockOn(playerNextLoc);
                    }
                    else
                    {
                        enemy.CancelTarget();
                    }

                    // プレイヤーに近づく
                    foreach (var loc in Approach(enemy.Loc, playerNextLoc))
                    {
                        Dir dir = enemy.Loc.Toward(loc);
                        if (!existsEnemy(loc) && floor.CanAdvance(enemy.Loc, dir))
                        {
                            q.Add(new ActEnemyMove(enemy, loc));
                            locs[loc.Row, loc.Col]     = true;
                            locs[enemy.Row, enemy.Col] = false;
                            updated = true;
                            used[i] = true;
                            break;
                        }
                    }
                }
                else   // プレイヤーが視界にいない
                       // 巡回モード

                {
                    if (enemy.IsLockedOn)
                    {
                        foreach (var loc in Approach(enemy.Loc, enemy.Target))
                        {
                            Dir dir = enemy.Loc.Toward(loc);
                            if (!existsEnemy(loc) && floor.CanAdvance(enemy.Loc, dir))
                            {
                                q.Add(new ActEnemyMove(enemy, loc));
                                locs[loc.Row, loc.Col]     = true;
                                locs[enemy.Row, enemy.Col] = false;
                                updated = true;
                                used[i] = true;
                                break;
                            }
                        }
                    }
                    else if (floor.IsPassage(enemy.Loc))   // 通路にいるなら前進する
                    {
                        enemy.CancelTarget();

                        foreach (var loc in Advance(enemy.Loc, enemy.Dir))
                        {
                            Dir dir = enemy.Loc.Toward(loc);
                            if (!existsEnemy(loc) && floor.CanAdvance(enemy.Loc, dir))
                            {
                                q.Add(new ActEnemyMove(enemy, loc));
                                locs[loc.Row, loc.Col]     = true;
                                locs[enemy.Row, enemy.Col] = false;
                                updated = true;
                                used[i] = true;
                                break;
                            }
                        }
                    }
                    else if (floor.IsRoom(enemy.Loc))   // 部屋にいるなら入り口に向かう
                    {
                        Room room = floor.FindRoom(enemy.Loc);
                        Debug.Log("room = " + room);
                        Debug.Log("room.Entrances.Length = " + room.Entrances.Length);
                        if (room.Entrances.Length == 0)   // 入り口がないなら何もしない
                        {
                            updated = true;
                            used[i] = true;
                            break;
                        }

                        Assert.IsTrue(room != null && room.Entrances.Length > 0);
                        Loc[] entrances = room.Entrances;
                        if (entrances.Length > 1)
                        {
                            // 隣接する入り口には向かわない(通路から部屋に入って、また通路に戻るパターンは除外)
                            entrances = entrances.Where(e => !e.IsNeighbor(enemy.Loc)).ToArray();
                        }

                        Loc target = entrances.Choice();
                        enemy.LockOn(target);
                        foreach (var loc in Approach(enemy.Loc, enemy.Target))
                        {
                            Dir dir = enemy.Loc.Toward(loc);
                            if (!existsEnemy(loc) && floor.CanAdvance(enemy.Loc, dir))
                            {
                                q.Add(new ActEnemyMove(enemy, loc));
                                locs[loc.Row, loc.Col]     = true;
                                locs[enemy.Row, enemy.Col] = false;
                                updated = true;
                                used[i] = true;
                                break;
                            }
                        }
                    }
                }
            }
        }

        // 攻撃(移動以外)するキャラ
        for (int i = 0; i < enemies.Count; i++)
        {
            if (used[i])
            {
                continue;
            }
            if (CanDirectAttack(enemies[i].Loc, playerNextLoc, floor))
            {
                q.Add(new ActEnemyAttack(enemies[i], player, playerNextLoc));
                used[i] = true;
            }
        }

        // 移動も行動も出来ないキャラは待機
        for (int i = 0; i < enemies.Count; i++)
        {
            if (used[i])
            {
                continue;
            }
            // q.Add(new ActEnemyWait(enemies[i]));
            used[i] = true;
        }

        return(q);
    }
예제 #4
0
    public static List <Act> Detect2(List <Enemy> enemies, Player player, Loc playerNextLoc, Floor floor)
    {
        // 敵をプレイヤーに近い距離順にソートする
        // TODO:プレイヤーから逃げる行動をとる場合は、プレイヤーから遠い順に行動を決める
        enemies.Sort((a, b) => {
            var x = a.Loc.SquareDistance(playerNextLoc);
            var y = b.Loc.SquareDistance(playerNextLoc);
            return(x.CompareTo(y));
        });

        var q = new List <Act>();

        var locs = new bool[floor.Rows, floor.Cols]; // キャラクターの位置
        Func <Loc, bool> existsEnemy = (loc) => {
            int rows = locs.GetLength(0);
            int cols = locs.GetLength(1);
            if (0 <= loc.Row && loc.Row < rows && 0 <= loc.Col && loc.Col < cols)
            {
                return(locs[loc.Row, loc.Col]);
            }
            return(false);
        };

        var used = new bool[enemies.Count];

        for (int i = 0; i < enemies.Count; i++)
        {
            if (enemies[i].ActCount <= 0) // 行動済み
            {
                used[i] = true;           // 行動済み
            }
            else if (enemies[i].IsBehavioralIncapacitation())
            {
                used[i] = true;
            }
            Loc loc = enemies[i].Loc;
            locs[loc.Row, loc.Col] = true;
        }
        locs[playerNextLoc.Row, playerNextLoc.Col] = true;

        // 移動するキャラ
        bool updated = true;

        while (updated)
        {
            updated = false;
            for (int i = 0; i < enemies.Count; i++)
            {
                if (used[i])
                {
                    continue;
                }

                var enemy = enemies[i];
                Assert.IsTrue(locs[enemy.Loc.Row, enemy.Loc.Col]);


                { // プレイヤーが視界にいない
                  // 巡回モード

                    if (enemy.IsLockedOn)
                    {
                        foreach (var loc in Approach(enemy.Loc, enemy.Target))
                        {
                            Dir dir = enemy.Loc.Toward(loc);
                            if (!existsEnemy(loc) && floor.CanAdvance(enemy.Loc, dir))
                            {
                                q.Add(new ActEnemyMove(enemy, loc));
                                locs[loc.Row, loc.Col]     = true;
                                locs[enemy.Row, enemy.Col] = false;
                                updated = true;
                                used[i] = true;
                                break;
                            }
                        }
                    }
                    else if (floor.IsPassage(enemy.Loc))   // 通路にいるなら前進する
                    {
                        enemy.CancelTarget();

                        foreach (var loc in Advance(enemy.Loc, enemy.Dir))
                        {
                            Dir dir = enemy.Loc.Toward(loc);
                            if (!existsEnemy(loc) && floor.CanAdvance(enemy.Loc, dir))
                            {
                                q.Add(new ActEnemyMove(enemy, loc));
                                locs[loc.Row, loc.Col]     = true;
                                locs[enemy.Row, enemy.Col] = false;
                                updated = true;
                                used[i] = true;
                                break;
                            }
                        }
                    }
                    else if (floor.IsRoom(enemy.Loc))   // 部屋にいるなら入り口に向かう
                    {
                        Room room = floor.FindRoom(enemy.Loc);
                        if (room.Entrances.Length == 0)   // 入り口がないなら何もしない
                        {
                            updated = true;
                            used[i] = true;
                            break;
                        }

                        Assert.IsTrue(room != null && room.Entrances.Length > 0);

                        Loc[] entrances = room.Entrances;
                        if (entrances.Length > 1)
                        {
                            // 隣接する入り口には向かわない(通路から部屋に入って、また通路に戻るパターンは除外)
                            entrances = entrances.Where(e => !e.IsNeighbor(enemy.Loc)).ToArray();
                        }

                        Loc target = entrances.Choice();
                        enemy.LockOn(target);
                        foreach (var loc in Approach(enemy.Loc, enemy.Target))
                        {
                            Dir dir = enemy.Loc.Toward(loc);
                            if (!existsEnemy(loc) && floor.CanAdvance(enemy.Loc, dir))
                            {
                                q.Add(new ActEnemyMove(enemy, loc));
                                locs[loc.Row, loc.Col]     = true;
                                locs[enemy.Row, enemy.Col] = false;
                                updated = true;
                                used[i] = true;
                                break;
                            }
                        }
                    }
                }
            }
        }

        // 移動も行動も出来ないキャラは待機
        for (int i = 0; i < enemies.Count; i++)
        {
            if (used[i])
            {
                continue;
            }
            // q.Add(new ActEnemyWait(enemies[i]));
            used[i] = true;
        }

        return(q);
    }