예제 #1
0
    // Use this for initialization
    void Start()
    {
        var textObj = GameObject.Find("InstructionsText");

        if (textObj != null)
        {
            textObj.GetComponent <Text>().text =
                "Instructions\n\n" +
                "B - Blended\n" +
                "Q - stop";
        }

        var redObj = GameObject.Find("Red");

        var initialCharacter = new DynamicCharacter(redObj)
        {
            MaxSpeed = MAX_SPEED,
            Drag     = DRAG
        };
        var obstacles = GameObject.FindGameObjectsWithTag("Obstacle");

        flock = new List <KinematicData> ();

        this.Characters = this.CloneSecondaryCharacters(redObj, Random.Range(MIN_NUMBER_OF_BOIDS, MAX_NUMBER_OF_BOIDS), obstacles);
        this.Characters.Add(initialCharacter);


        foreach (DynamicCharacter character in this.Characters)
        {
            this.InitializeCharacters(character, obstacles);
        }
    }
    // Use this for initialization
    void Awake()
    {
        this.character = new DynamicCharacter(characterAvatar);
        var clusterGraph = Resources.Load <ClusterGraph>("ClusterGraph");

        this.Initialize(NavigationManager.Instance.NavMeshGraphs[0], new NodeArrayAStarPathFinding(NavigationManager.Instance.NavMeshGraphs[0], new GatewayHeuristic(clusterGraph)));
    }
예제 #3
0
    // Use this for initialization
    void Awake()
    {
        this.draw      = false;
        this.navMesh   = NavigationManager.Instance.NavMeshGraphs[0];
        this.character = new DynamicCharacter(this.characterAvatar);
        this.enemies   = new List <DynamicCharacter>();
        for (int i = 0; i < enemiesAvatar.Length; i++)
        {
            DynamicCharacter    enemy    = new DynamicCharacter(this.enemiesAvatar[i]);
            DynamicBackAndForth movement = new DynamicBackAndForth()
            {
                Character       = enemy.KinematicData,
                MaxAcceleration = 10.0f,
                StopRadius      = 2.0f,
                SlowRadius      = 5.0f,
                MoveDistance    = 25.0f
            };
            movement.CalculatePositions();
            enemy.Movement = movement;
            this.enemies.Add(enemy);
        }

        this.aStarPathFinding = new NodeArrayAStarPathFinding(this.navMesh, new EuclideanDistanceHeuristic());
        this.aStarPathFinding.NodesPerSearch = 100;
    }
예제 #4
0
    //early initialization
    void Awake()
    {
        // Creating a new Dynamic Character
        this.character = new DynamicCharacter(this.gameObject);

        // Making sure we know all the possible destinations
        destinations = new List <Transform>();
        var goals = GameObject.Find("DestinationPoints").transform;

        for (int i = 0; i < goals.childCount; i++)
        {
            destinations.Add(goals.transform.GetChild(i));
        }

        // Initializing the Priority and Blended movements
        this.priorityMovement = new PriorityMovement
        {
            Character = this.character.KinematicData
        };

        this.blendedMovement = new BlendedMovement
        {
            Character = this.character.KinematicData
        };
    }
 public Decomposer(SteeringPipeline pipeline, NavMeshPathGraph navMesh, DynamicCharacter character)
 {
     Character        = character;
     Pipeline         = pipeline;
     aStarPathFinding = new NodeArrayAStarPathFinding(navMesh, new EuclideanDistanceHeuristic());
     aStarPathFinding.NodesPerSearch = 150;
 }
예제 #6
0
    // Use this for initialization
    void Awake()
    {
        this.currentClickNumber = 1;

        this.Initialize(NavigationManager.Instance.NavMeshGraphs[0], new NodeArrayAStarPathFinding(NavigationManager.Instance.NavMeshGraphs[0], new GatewayDistanceHeuristic()));

        this.dynamicCharacter = new DynamicCharacter(this.character);
    }
예제 #7
0
        public void Update()
        {
            if (Time.time > this.nextUpdateTime)
            {
                this.nextUpdateTime      = Time.time + UPDATE_INTERVAL;
                this.characterData.Time += UPDATE_INTERVAL;
            }

            if (enemyCharacter != null && currentEnemy != null && currentEnemy.activeSelf)
            {
                this.enemyCharacter.Movement.Target.position = this.character.transform.position;
                this.enemyCharacter.Update();
                this.SwordAttack(currentEnemy);
            }
            else
            {
                foreach (var enemy in this.enemies)
                {
                    if ((enemy.transform.position - this.character.transform.position).sqrMagnitude <= 400)
                    {
                        this.currentEnemy   = enemy;
                        this.enemyCharacter = new DynamicCharacter(enemy)
                        {
                            MaxSpeed = 100
                        };
                        enemyCharacter.Movement = new DynamicSeek()
                        {
                            Character       = enemyCharacter.KinematicData,
                            MaxAcceleration = 100,
                            Target          = new IAJ.Unity.Movement.KinematicData()
                        };

                        break;
                    }
                }
            }


            this.HPText.text    = "HP: " + this.characterData.HP;
            this.XPText.text    = "XP: " + this.characterData.XP;
            this.LevelText.text = "Level: " + this.characterData.Level;
            this.TimeText.text  = "Time: " + this.characterData.Time;
            this.ManaText.text  = "Mana: " + this.characterData.Mana;
            this.MoneyText.text = "Money: " + this.characterData.Money;

            if (this.characterData.HP <= 0 || this.characterData.Time >= 200)
            {
                this.GameEnd.SetActive(true);
                this.GameEnd.GetComponentInChildren <Text>().text = "Game Over";
                this.GameOver = true;
            }
            else if (this.characterData.Money >= 25)
            {
                this.GameEnd.SetActive(true);
                this.GameEnd.GetComponentInChildren <Text>().text = "Victory";
                this.GameOver = false;
            }
        }
예제 #8
0
 private void UpdateMovingGameObject(DynamicCharacter movingCharacter)
 {
     if (movingCharacter.Movement != null)
     {
         movingCharacter.Update();
         movingCharacter.KinematicData.ApplyWorldLimit(X_WORLD_SIZE, Z_WORLD_SIZE);
         movingCharacter.GameObject.transform.position = movingCharacter.Movement.Character.position;
     }
 }
    //early initialization
    void Awake()
    {
        this.character = new DynamicCharacter(this.gameObject);

        this.blendedMovement = new BlendedMovement
        {
            Character = this.character.KinematicData
        };
    }
예제 #10
0
    // Use this for initialization
    void Awake()
    {
        this.character = new DynamicCharacter(characterAvatar);
        var clusterGraph = Resources.Load <ClusterGraph>("ClusterGraph");

        this.draw             = false;
        this.navMesh          = NavigationManager.Instance.NavMeshGraphs[0];
        this.AStarPathFinding = new NodeArrayAStarPathFinding(NavigationManager.Instance.NavMeshGraphs[0], new GatewayHeuristic(clusterGraph));
        this.AStarPathFinding.NodesPerSearch = 100;
    }
예제 #11
0
 // Use this for initialization
 void Awake()
 {
     this.currentClickNumber = 1;
     this.Initialize(NavigationManager.Instance.NavMeshGraphs[0], new NodeArrayAStarPathFinding(NavigationManager.Instance.NavMeshGraphs[0], new GatewayHeuristic()));
     //this.Initialize(NavigationManager.Instance.NavMeshGraphs[0], new AStarPathfinding(NavigationManager.Instance.NavMeshGraphs[0], new SimpleUnorderedNodeList(), new ClosedDict(), new EuclideanHeuristic()));
     this.character         = new DynamicCharacter(this.gameObject);
     this.dynamicFollowPath = new DynamicFollowPath
     {
         Character       = this.character.KinematicData,
         Target          = new KinematicData(),
         MaxAcceleration = 90.0f
     };
 }
    // Use this for initialization
    void Awake()
    {
        this.character = new DynamicCharacter(characterAvatar);
        var clusterGraph = Resources.Load <ClusterGraph>("ClusterGraph");

        this.draw    = false;
        this.navMesh = NavigationManager.Instance.NavMeshGraphs[0];
        //this.AStarPathFinding = new AStarPathfinding(this.navMesh, new NodePriorityHeap(), new NodeHashTable(), new EuclidianHeuristic());
        //this.AStarPathFinding = new NodeArrayAStarPathFinding(this.navMesh, new EuclidianHeuristic());
        this.AStarPathFinding = new NodeArrayAStarPathFinding(this.navMesh, new GatewayHeuristic(clusterGraph));

        this.AStarPathFinding.NodesPerSearch = 100;
    }
예제 #13
0
파일: Flock.cs 프로젝트: IAJ-g04/Lab8
        public void AddFlockMember(GameObject gameObject)
        {
            var member = new DynamicCharacter(gameObject)
            {
                Drag     = this.Drag,
                MaxSpeed = this.MaximumSpeed
            };

            member.KinematicData.velocity = new Vector3(Random.Range(0, this.MaximumSpeed), 0, Random.Range(0, this.MaximumSpeed));


            member.Movement = this.GenerateBlendingMovementFor(member);
            this.FlockMembers.Add(member);
        }
    private void InitializeSecondaryCharacter(DynamicCharacter character, GameObject[] obstacles)
    {
        var priority = new PriorityMovement
        {
            Character = character.KinematicData
        };

        foreach (var obstacle in obstacles)
        {
            var avoidObstacleMovement = new DynamicAvoidObstacleWhiskers(obstacle)
            {
                MaxAcceleration    = MAX_ACCELERATION,
                AvoidMargin        = AVOID_MARGIN,
                MaxLookAhead       = MAX_LOOK_AHEAD,
                Character          = character.KinematicData,
                MovementDebugColor = Color.magenta
            };

            priority.Movements.Add(avoidObstacleMovement);
        }

        foreach (var otherCharacter in this.Characters)
        {
            if (otherCharacter != character)
            {
                var avoidCharacter = new DynamicAvoidCharacter(otherCharacter.KinematicData)
                {
                    Character          = character.KinematicData,
                    MaxAcceleration    = MAX_ACCELERATION,
                    CollisionRadius    = COLLISION_RADIUS,
                    MaxTimeLookAhead   = MAX_TIME_LOOK_AHEAD,
                    MovementDebugColor = Color.cyan
                };

                priority.Movements.Add(avoidCharacter);
            }
        }

        var straightAhead = new DynamicStraightAhead
        {
            Character          = character.KinematicData,
            MaxAcceleration    = MAX_ACCELERATION,
            MovementDebugColor = Color.yellow
        };

        priority.Movements.Add(straightAhead);

        character.Movement = priority;
    }
예제 #15
0
    //early initialization
    void Awake()
    {
        this.character        = new DynamicCharacter(this.gameObject);
        this.movementTextText = this.movementText.GetComponent <Text>();

        this.priorityMovement = new PriorityMovement
        {
            Character = this.character.KinematicData
        };

        this.blendedMovement = new BlendedMovement
        {
            Character = this.character.KinematicData
        };
    }
예제 #16
0
    private void InitializeCharacter(DynamicCharacter character, GameObject[] obstacles, GameObject[] dynamicObstacles)
    {
        this.Blended = new BlendedMovement
        {
            Character = character.KinematicData
        };

        var seek = new DynamicSeek
        {
            Target = new KinematicData(new StaticData(character.KinematicData.Goal))
        };

        this.Blended.Movements.Add(new MovementWithWeight(seek, 1f));
        character.Movement = this.Blended;
    }
예제 #17
0
        private static void CapCharacterVelocity(DynamicCharacter character)
        {
            var charSpeed = character.KinematicData.velocity.sqrMagnitude;

            if (charSpeed >= 900f) // 900 = 30^2
            {
                character.KinematicData.velocity *= 0.95f;
            }
            else if (charSpeed >= 400f) // 400 = 20^2
            {
                character.KinematicData.velocity *= 0.97f;
            }
            else if (charSpeed >= 100f) // 100 = 10^2
            {
                character.KinematicData.velocity *= 0.99f;
            }
        }
    //early initialization
    void Awake()
    {
        this.character = new DynamicCharacter(this.gameObject)
        {
            MaxSpeed = MAX_SPEED,
            Drag     = DRAG
        };


        this.priorityMovement = new PriorityMovement
        {
            Character = this.character.KinematicData
        };

        this.blendedMovement = new BlendedMovement
        {
            Character = this.character.KinematicData
        };
    }
예제 #19
0
    private List <DynamicCharacter> CloneCharacters(GameObject objectToClone, int numberOfCharacters, GameObject[] obstacles)
    {
        var characters = new List <DynamicCharacter>();

        for (int i = 0; i < numberOfCharacters; i++)
        {
            var clone = GameObject.Instantiate(objectToClone);
            clone.transform.position = this.GenerateRandomClearPosition(obstacles);
            var character = new DynamicCharacter(clone)
            {
                MaxSpeed = MAX_SPEED,
                Drag     = DRAG
            };
            character.KinematicData.orientation = Random.Range(0, 360);
            characters.Add(character);
        }

        return(characters);
    }
    private List <DynamicCharacter> CloneSecondaryCharacters(GameObject objectToClone, int numberOfCharacters, GameObject[] obstacles)
    {
        var characters = new List <DynamicCharacter> ();

        for (int i = 0; i < numberOfCharacters; i++)
        {
            var clone = GameObject.Instantiate(objectToClone);
            //clone.transform.position = new Vector3(30,0,i*20);
            clone.transform.position = this.GenerateRandomClearPosition(obstacles);
            var character = new DynamicCharacter(clone)
            {
                MaxSpeed = MAX_SPEED,
                Drag     = DRAG
            };
            //character.KinematicData.orientation = (float)Math.PI*i;
            characters.Add(character);
        }

        return(characters);
    }
        public HumanActuator(DynamicCharacter character)
        {
            SeekMovement = new DynamicSeek
            {
                MaxAcceleration = 60f,
                Character       = character.KinematicData,
                StopRadius      = 49f // 49 = 7^2
            };

            this.Character          = character;
            this.Character.MaxSpeed = 30f;

            FollowPathMovement = new DynamicFollowPath(character.KinematicData)
            {
                MaxAcceleration = 40f,
                MaxSpeed        = 30f,
                SlowRadius      = 3.5f,
                StopRadius      = 3f,
                GoalPosition    = GoalPosition
            };
        }
예제 #22
0
        public CarActuator(DynamicCharacter character)
        {
            SeekMovement = new DynamicSeek()
            {
                MaxAcceleration = 80f,
                Character       = character.KinematicData,
                StopRadius      = 49f // 49 = 7^2
            };

            this.Character           = character;
            this.Character.BackingUp = false;
            //setting character MaxSpeed according to actuator
            this.Character.MaxSpeed = 40f;
            this.FollowPathMovement = new DynamicFollowPath(character.KinematicData)
            {
                MaxAcceleration = 60f,
                MaxSpeed        = 50f,
                SlowRadius      = 15f,
                StopRadius      = 7f,
                GoalPosition    = GoalPosition
            };
        }
        protected MovementOutput GetOutput(GlobalPath suggestedPath, DynamicCharacter character)
        {
            DynamicMovement movement;

            if (suggestedPath != null)
            {
                SeekMovement.Target = new KinematicData()
                {
                    position = suggestedPath.LocalPaths[0].EndPosition
                };
                //Debug.DrawLine(character.KinematicData.position, SeekMovement.Target.position, Color.black);
                movement = SeekMovement;

                return(movement.GetMovement());
            }
            else
            {
                movement = FollowPathMovement;
            }

            return(FilterMovementOutput(movement.GetMovement(), Character));
        }
    // Use this for initialization
    private void Awake()
    {
        this.draw = true;
        NavMeshPathGraph navMesh = NavigationManager.Instance.NavMeshGraphs[0];

        this.character   = new DynamicCharacter(this.characterAvatar);
        this.Pedestrians = new List <GameObject>(GameObject.FindGameObjectsWithTag("Pedestrian")).ConvertAll(p => new Pedestrian(p));

        // Targeter
        TargeterComponent = new Targeter(this);

        // Decomposer
        DecomposerComponent = new Decomposer(this, navMesh, this.character);

        // TargetCollisionConstraint
        PathConstraints = new List <IConstraint>();
        PathConstraints.Add(new PedestrianAvoidanceConstraint(this, character, this.Pedestrians));
        PathConstraints.Add(new AvoidObstacleConstraint(this.character));

        // Movement Constraints
        MovementConstraints = new List <IConstraint>();
        StaticObstacleConstraint obsConstraint = new StaticObstacleConstraint(character)
        {
            AvoidMargin = 10f
        };

        MovementConstraints.Add(obsConstraint);

        if (CharacterInUse.Equals(CharacterType.Car))
        {
            Actuator = new CarActuator(this.character);
        }
        else if (CharacterInUse.Equals(CharacterType.Human))
        {
            Actuator = new HumanActuator(this.character);
        }
    }
예제 #25
0
        protected override MovementOutput FilterMovementOutput(MovementOutput output, DynamicCharacter character)
        {
            Vector3 charOrientation = MathHelper.ConvertOrientationToVector(character.KinematicData.orientation);
            float   charSpeed       = character.KinematicData.velocity.sqrMagnitude;
            float   angleDiff       = Mathf.Deg2Rad * (Vector3.Angle(charOrientation, output.linear));
            float   angleDiffAbs    = Math.Abs(angleDiff);

            float distance = (GoalPosition - character.KinematicData.position).sqrMagnitude;

            if (character.BackingUp || angleDiffAbs >= MathConstants.MATH_PI - MathConstants.MATH_PI / 3f && charSpeed <= 1 && distance < 900f) // 900 = 30^2
            {
                character.BackingUp = true;

                Vector3 contraryVector =
                    MathHelper.ConvertOrientationToVector(MathHelper.ConvertVectorToOrientation((GoalPosition - character.KinematicData.position)) + MathConstants.MATH_PI);

                character.KinematicData.orientation = MathHelper.ConvertVectorToOrientation(Vector3.Lerp(charOrientation, contraryVector, 0.1f));
                return(output);
            }

            if (!character.BackingUp)
            {
                if (Physics.Raycast(character.KinematicData.position, character.KinematicData.velocity, 30f))
                {
                    //Debug.DrawLine(character.KinematicData.position, character.KinematicData.velocity.normalized*30f+character.KinematicData.position, Color.black);

                    CapCharacterVelocity(character);
                }

                if (angleDiff > MathConstants.MATH_PI_2 / 6f && charSpeed >= 4900) // 4900 = 70^2
                {
                    output.linear = MathHelper.ConvertOrientationToVector(MathConstants.MATH_PI_2 / 6f).normalized;
                    character.KinematicData.velocity = character.KinematicData.velocity.normalized * 40f;
                    return(output);
                }
                if (angleDiff > MathConstants.MATH_PI_2 / 3f && charSpeed >= 3600) // 3600 = 60^2
                {
                    output.linear = MathHelper.ConvertOrientationToVector(MathConstants.MATH_PI_2 / 3f).normalized;
                    character.KinematicData.velocity = character.KinematicData.velocity.normalized * 30f;
                    return(output);
                }
                if (angleDiff > MathConstants.MATH_PI_4 && charSpeed >= 2500) // 2500 = 50^2
                {
                    output.linear = MathHelper.ConvertOrientationToVector(MathConstants.MATH_PI_4).normalized;
                    character.KinematicData.velocity = character.KinematicData.velocity.normalized * 25f;
                    return(output);
                }

                if (angleDiffAbs >= MathConstants.MATH_PI_2 / 3f && charSpeed <= 100) // 100 = 10^2
                {
                    // aqui altera apenas a direcção em que em que o carro vira
                    if (angleDiff < 0)
                    {
                        output.linear = MathHelper.ConvertOrientationToVector(character.KinematicData.orientation - MathConstants.MATH_PI_2 / 48f);
                        character.KinematicData.velocity *= 2f;
                    }
                    else if (angleDiff >= 0)
                    {
                        output.linear = MathHelper.ConvertOrientationToVector(character.KinematicData.orientation + MathConstants.MATH_PI_2 / 48f);
                        character.KinematicData.velocity *= 2f;
                    }
                    return(output);
                }
            }

            return(output);
        }
예제 #26
0
 public MovementOutput GetOutput(GlobalPath suggestedPath, DynamicCharacter character)
 {
     return(base.GetOutput(suggestedPath, character));
 }
예제 #27
0
        public bool WillViolate(GlobalPath path, out Vector3 suggestedPosition)
        {
            var targetsToAvoid             = false;
            var shortestTime               = float.MaxValue;
            var closestMinSeparation       = 0f;
            var closestDistance            = 0f;
            var closestDeltaPos            = Vector3.zero;
            var closestDeltaVel            = Vector3.zero;
            DynamicCharacter closestTarget = null;

            foreach (var target in this.Pedestrians)
            {
                var deltaPos   = target.KinematicData.position - this.Character.KinematicData.position;
                var deltaVel   = target.KinematicData.velocity - this.Character.KinematicData.velocity;
                var deltaSpeed = deltaVel.magnitude; // can't be optimized to sqrMagnitude with no side effects

                if (deltaSpeed < 0.005f)
                {
                    continue;
                }

                var timeToClosest = -Vector3.Dot(deltaPos, deltaVel) / (deltaSpeed * deltaSpeed);

                if (timeToClosest > MaxTimeLookAhead)
                {
                    continue;
                }

                var distance      = deltaPos.magnitude; // can't be optimized to sqrMagnitude with no side effects
                var minSeparation = distance - deltaSpeed * timeToClosest;

                if (minSeparation > 2 * CollisionRadius)
                {
                    continue;
                }

                if (timeToClosest > 0 && timeToClosest < shortestTime)
                {
                    targetsToAvoid       = true;
                    shortestTime         = timeToClosest;
                    closestTarget        = target;
                    closestMinSeparation = minSeparation;
                    closestDistance      = distance;
                    closestDeltaPos      = deltaPos;
                    closestDeltaVel      = deltaVel;
                }
            }

            if (!targetsToAvoid)
            {
                suggestedPosition = Vector3.zero;
                return(false);
            }

            Vector3 avoidanceDirection;

            if (closestMinSeparation <= 0 || closestDistance < 2 * CollisionRadius)
            {
                avoidanceDirection = this.Character.KinematicData.position - closestTarget.KinematicData.position;
            }
            else
            {
                avoidanceDirection = (closestDeltaPos + closestDeltaVel * shortestTime) * -1;
            }

            suggestedPosition = this.Character.KinematicData.position + avoidanceDirection.normalized * AvoidMargin;
            return(true);
        }
예제 #28
0
 public PedestrianAvoidanceConstraint(SteeringPipeline pipeline, DynamicCharacter character, List <Pedestrian> pedestrians)
 {
     this.Pedestrians = pedestrians;
     this.Character   = character;
 }
예제 #29
0
    private void InitializeCharacter(DynamicCharacter character)
    {
        var blended = new BlendedMovement
        {
            Character          = character.KinematicData,
            MovementDebugColor = Color.black
        };


        var priority = new PriorityMovement
        {
            Character = character.KinematicData
        };

        // VELOCITY MATCHING
        var flockVelocityMatching = new FlockVelocityMatching()
        {
            Character          = character.KinematicData,
            Flock              = this.getCharactersKinematicData(this.Characters),
            MaxAcceleration    = MAX_ACCELERATION,
            MovementDebugColor = Color.green
        };

        // SEPARATION
        var flockSeparation = new FlockSeparation()
        {
            Character          = character.KinematicData,
            Flock              = this.getCharactersKinematicData(this.Characters),
            MaxAcceleration    = MAX_ACCELERATION,
            MovementDebugColor = Color.grey
        };

        // COHESION
        var flockCohesion = new FlockCohesion()
        {
            Character          = character.KinematicData,
            Flock              = this.getCharactersKinematicData(this.Characters),
            MaxAcceleration    = MAX_ACCELERATION,
            MovementDebugColor = Color.cyan
        };

        // OBSTACLE AVOIDANCE
        var obstacleAvoidMovement = new DynamicObstacleAvoid()
        {
            MaxAcceleration    = MAX_ACCELERATION / 2,
            Character          = character.KinematicData,
            MovementDebugColor = Color.magenta
        };

        // FLEE
        var flockFlee = new FlockFlee()
        {
            Character          = character.KinematicData,
            Flock              = this.getCharactersKinematicData(this.Characters),
            Target             = new KinematicData(),
            MaxAcceleration    = MAX_ACCELERATION * 3.0f,
            MovementDebugColor = Color.green
        };

        //TODO: ADD THE 3 MOVEMENTS
        blended.Movements.Add(new MovementWithWeight(flockSeparation, 1.5f));
        blended.Movements.Add(new MovementWithWeight(flockCohesion, 1.7f));
        blended.Movements.Add(new MovementWithWeight(flockVelocityMatching, 2.0f));
        blended.Movements.Add(new MovementWithWeight(flockFlee, 2.0f));

        priority.Movements.Add(obstacleAvoidMovement);
        priority.Movements.Add(blended);


        character.Movement = priority;
    }
 protected abstract MovementOutput FilterMovementOutput(MovementOutput output, DynamicCharacter character);