// In this function we actually move each assigned unit of a grid point towards that moving (in most cases) grid point // We use the Rigidbody velocity and the velocity is calculated based on the distance from the unit to the grid point. public void MoveUnitsRigidBodyMode(int gridPointIndex, FormationGridPoint fgp, Vector3 vlcity, float endReachedDistance) { Rigidbody rigidbody = fgp.GetRigidbody(); if (!rigidbody) { Debug.LogError("FormationGrid.MoveUnitsRigidBodyMode(): Rigidbody missing on assigned unit."); } Vector3 acceleration = fgp.GetPosition() - fgp.GetAssignedUnit().transform.position; acceleration.y = 0; acceleration.Normalize(); acceleration *= maximumAcceleration; //DebugPanel.Log("Acceleration "+gridPointIndex, "Rigidbody", acceleration.magnitude); rigidbody.velocity += acceleration * Time.deltaTime; if (rigidbody.velocity.magnitude > maximumVelocity) { rigidbody.velocity = rigidbody.velocity.normalized * maximumVelocity; } //DebugPanel.Log("Rgb velocity "+gridPointIndex, "Rigidbody", rigidbody.velocity.magnitude); fgp.SetAssignedVelocity(rigidbody.velocity); }
// In this function we actually move each assigned unit of a grid point towards that moving (in most cases) grid point // We use the Move function of the CharacterController and the motion is calculated based on the distance from the unit to the grid point. public void MoveUnitsCharacterControllerMode(int gridPointIndex, FormationGridPoint fgp, Vector3 vlcity, float endReachedDistance) { CharacterController controller = fgp.GetCharacterController(); if (!controller) { Debug.LogError("FormationGrid.MoveUnitsCharacterControllerMode(): Character Controller missing on assigned unit."); } float distanceToGridPoint = fgp.CalculateDistanceUnitToGridPoint(); //if (gridPointIndex == 0) DebugPanel.Log("GridPoint [" + gridPointIndex + "] unittogrid", "Grid", distanceToGridPoint); // default acceleration multiplier float acceleration = 1.0F; if (distanceToGridPoint > endReachedDistance * 5) { // takeover acceleration = accelerationStraggler; } else if ((distanceToGridPoint > endReachedDistance) && ((distanceToGridPoint < endReachedDistance * 5))) { // slowdown float slope = 1 / (4 * endReachedDistance); // 1 / ((5-1) * endReachedDistance) float intercept = -1 * (slope * endReachedDistance); // acceleration = slope * distanceToGridPoint + intercept; // a = 0 at endReachedDistance and a = 1 at 5*endReachedDistance //acceleration = distanceToGridPoint / 0.5F; } else if (distanceToGridPoint < endReachedDistance) { acceleration = 0.0f; } //if (gridPointIndex == 0) DebugPanel.Log("GridPoint [" + gridPointIndex + "] acceleration", "Grid", acceleration); Vector3 direction = fgp.GetPosition() - fgp.GetAssignedUnit().transform.position; Vector3 fgp_velocity = direction * acceleration; if (useGravity) { // Use gravity and calculate vertical velocity down float vSpeed = fgp.GetUnitVerticalSpeed(); if (controller.isGrounded) { vSpeed = 0; } vSpeed -= gravity * Time.deltaTime; fgp.SetUnitVerticalSpeed(vSpeed); fgp_velocity.y = vSpeed; } controller.Move(fgp_velocity * Time.deltaTime); fgp.SetAssignedVelocity(fgp_velocity); }
// Change the movement state of the units assigned to a grid point: // False = stop moving // True = start moving public void ChangeMoveStateOnGridObjects(bool state) { for (int i = 0; i < gridPoints.Count; i++) { FormationGridPoint fgp = gridPoints[i]; GameObject go = fgp.GetAssignedUnit(); if (go) { #if T7T_ASTAR AIPath aip = go.GetComponent <AIPath>(); if (aip) { aip.target = fgp.GetTransform(); aip.canSearch = state; aip.canMove = state; } else { Debug.LogError("FormationGrid.EnableMoveOnGridObjects(): no assigned unit found for gridpoint."); } #else NavMeshAgent nma = go.GetComponent <NavMeshAgent>(); if (nma) { if (state) { nma.destination = fgp.GetPosition(); nma.Resume(); } else { nma.Stop(); Rigidbody rigidbody = fgp.GetRigidbody(); if (rigidbody) { rigidbody.velocity = Vector3.zero; } } } else { Debug.LogError("FormationGrid.EnableMoveOnGridObjects(): no nav mesh agent found for assigned unit."); } #endif } } }
// Change the animation state of each unit assigned to a grid point: // False = go to Idle state // True = go to movement state public void ChangeAnimationStateOnGridObjects(bool state) { for (int i = 0; i < gridPoints.Count; i++) { FormationGridPoint fgp = gridPoints[i]; GameObject go = fgp.GetAssignedUnit(); if (go) { FormationUnitAnimation formationUnitAnimation = fgp.GetFormationUnitAnimation(); if (formationUnitAnimation) { if (state) { formationUnitAnimation.StartAnimations(); } else { formationUnitAnimation.StopAnimations(); } } } } }
// Update is called once per frame void Update() { if (anchor == null) { return; } if (state == FormationStates.Form) { for (int i = 0; i < gridPoints.Count; i++) { FormationGridPoint fgp = gridPoints[i]; if (fgp != null) { if (fgp.IsUnitAssigned()) { FormationUnitAnimation formationUnitAnimation = fgp.GetFormationUnitAnimation(); if (formationUnitAnimation) { GameObject go = fgp.GetAssignedUnit(); if (go) { #if T7T_ASTAR AIPath aip = go.GetComponent <AIPath>(); formationUnitAnimation.velocity = aip.CalculateVelocity(Vector3.zero); // obselete but velocity property is not available. #else NavMeshAgent nma = go.GetComponent <NavMeshAgent>(); formationUnitAnimation.velocity = nma.velocity; #endif } } } } } } if (state == FormationStates.Move) { if ((oldPosition - anchorPosition).sqrMagnitude > 0.001f * 0.001f) // TODO: potentially we can do this by checking if target has been reached { positionDirty = true; } else { positionDirty = false; } if (Mathf.Abs(anchorRotation.eulerAngles.y - oldRotation) > 0.01f) { rotationDirty = true; } else { rotationDirty = false; } Quaternion target = anchorRotation; if (rotationDirty) { transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime * smoothRotation); } // Rotate the units at grid points to align with anchor rotation: // TODO: can we check when not to run this by means of "fully rotated" units? if (formationAnchor != null) { // Vector3 velocity = formationAnchor.GetVelocity(); for (int i = 0; i < gridPoints.Count; i++) { FormationGridPoint fgp = gridPoints[i]; if (fgp != null) { if (fgp.IsUnitAssigned()) { GameObject au = fgp.GetAssignedUnit(); au.transform.rotation = Quaternion.Slerp(au.transform.rotation, target, Time.deltaTime * smoothRotation); } } } } if (positionDirty) { transform.position = anchorPosition; // Move the Formation to Anchor position. TODO: If dampening needed, do Lerp here. if (randomizeOffset > 0.0F) { // Randomize the positions slightly if enabled reRandomizeOffsets += Time.deltaTime; if (reRandomizeOffsets > reRandomizeNextTime) // ReRandomize the gridpoints every 3 seconds { reRandomizeOffsets = 0.0F; reRandomizeNextTime = reRandomizeTimeMin + (reRandomizeTimeMax - reRandomizeTimeMin) * Random.value; for (int i = 0; i < gridPoints.Count; i++) { FormationGridPoint fgp = gridPoints[i]; fgp.RandomizePosition(); } } } CalculatePositionsAllGridPoints(); // Calculate all Grid Points relative to the Anchor which has moved by means of A*Pathfinfing. } // Now move the units (assigned to grid positions) towards their grid position: // TODO: Add a check here to stop if all units have arrived. if (formationAnchor != null) { float endReachedDistance = formationAnchor.endReachedDistance; Vector3 vlcity = formationAnchor.GetVelocity(); //DebugPanel.Log("Anchor velocity", "Anchor", vlcity.magnitude); for (int i = 0; i < gridPoints.Count; i++) { FormationGridPoint fgp = gridPoints[i]; if (fgp != null) { if (fgp.IsUnitAssigned()) { switch (movementType) { case MovementType.RigidBody: // Do nothing since in case of rigidbody we use FixedUpdate() instead of Update() //MoveUnitsRigidBodyMode(i, fgp, vlcity, endReachedDistance); break; case MovementType.CharacterController: MoveUnitsCharacterControllerMode(i, fgp, vlcity, endReachedDistance); break; default: Debug.LogError("FormationGrid.Update(): Unknown movementType"); break; } FormationUnitAnimation formationUnitAnimation = fgp.GetFormationUnitAnimation(); if (formationUnitAnimation) { formationUnitAnimation.velocity = fgp.GetAssignedVelocity(); //DebugPanel.Log("FUA.velocity", "Unit Animation", fgp.GetAssignedVelocity()); } } } oldPosition = anchorPosition; oldRotation = transform.rotation.eulerAngles.y; } } } if (state == FormationStates.Disband) { if (disbandTimer == 0.0f) { // set the directions for each assigned unit for (int i = 0; i < gridPoints.Count; i++) { FormationGridPoint fgp = gridPoints[i]; if (fgp != null) { if (fgp.IsUnitAssigned()) { fgp.SetDisbandDesitination(disbandRadius, mask); fgp.SetPositionToDisband(mask); } } } ChangeMoveStateOnGridObjects(true); disbanded = false; } // start a timer, for x seconds have the assigned units move into a random direction disbandTimer += Time.deltaTime; if (disbandTimer < disbandDuration) { // Move them //DebugPanel.Log("disbandtimer", "disband", disbandTimer); } else { if (!disbanded) { ChangeMoveStateOnGridObjects(false); ChangeAnimationStateOnGridObjects(false); disbanded = true; } } } }
/* Change the grid to a new type: * If the grid already has existing FormationGridPoints then * Collect the assigned units * Destroy the spheres in the FormationGridPoints to cleanup memory * Clear the grid points list * Setup the new grid points list * Setup the new grid * Assign the previously assigned units to the FormationGridPoints * Calculate the new positions */ public void ChangeGridTo(GridTypes gridtype) { gridType = gridtype; // Create the list for collecting the already assigned units List <GameObject> units = new List <GameObject>(); Debug.Log("FormationGrid.ChangeGridTo(): change state to " + gridType); if (gridPoints != null) { if (gridPoints.Count > 0) { // collect units assigned to gridpoint so we can reassign automatically after grid change Debug.Log("FormationGrid.ChangeGridTo(): grid exists so check if it has assigned units"); for (int i = 0; i < gridPoints.Count; i++) { FormationGridPoint fgp = gridPoints[i]; GameObject go = fgp.GetAssignedUnit(); if (go) { units.Add(go); Debug.Log("FormationGrid.ChangeGridTo(): found one unit " + go.name); } } // destroy list items first: cleanup the spheres for (int i = 0; i < gridPoints.Count; i++) { FormationGridPoint fgp = gridPoints[i]; fgp.DestroySphere(); } } gridPoints.Clear(); } // Create a new list to completely start a new grid from scratch. gridPoints = new List <FormationGridPoint>(); if (gridPoints == null) { Debug.LogError("FormationGrid.ChangeGridTo(): gridPoints not initialized"); return; } // Setup the new grid for the new gridtype bool result = SetupGrid(gridtype); // Now add the units we has assigned to the previous grid if (units.Count > 0) { AssignObjectsToGrid(units); } // Calculate the real positions of the grid based on the offsets in the grid definition CalculatePositionsAllGridPoints(); Debug.Log("FormationGrid.ChangeGridTo(): result SetupGrid()=" + result); }