void Update() { accumulatedDeltaTime += Time.deltaTime * simulationSpeedFactor; if (accumulatedDeltaTime >= vehicleDt) { accumulatedDeltaTime = 0.0f; // Get positions of virtual structure edges PointInfo[] edges = formationRectangle.getEdges(); Vector3 targetPosition = agents [0].transform.position; List <int> failedAgents = new List <int> (); if (winnerIdx == agents.Length - 1 || !moveNearestAgent(targetPosition, winnerIdx)) { failedAgents.Add(winnerIdx); for (int t = 1; t < agents.Length - 1; t++) { // Get closest player to opponent float minDistance = float.MaxValue; for (int i = 1; i < agents.Length - 1; i++) { // If this agent has failed moving before, due to moving the formation out of the polygon if (failedAgents.Contains(i)) { continue; } float distance = Vector2.Distance(new Vector2(targetPosition.x, targetPosition.z), getDesiredPosition(i - 1)); if (distance < minDistance) { minDistance = distance; winnerIdx = i; } } // If movement of agent succeeds without collision of the formation with the boundary polygon if (moveNearestAgent(targetPosition, winnerIdx)) { break; } failedAgents.Add(winnerIdx); winnerIdx = agents.Length - 1; } } //If noone can move if (winnerIdx == agents.Length - 1) { setRelativeFormationPositions(this.relativeFormationPositions, winnerIdx - 1); this.desiredRelativePositions = getDesiredPositions(winnerIdx, false, false); this.desiredAbsolutePositions = getDesiredPositions(winnerIdx, false, true); FootballPlayerController virtualCenterController = agents[agents.Length - 1].GetComponent <FootballPlayerController>(); virtualCenterController.setPlay(false); } } }
private bool moveNearestAgent(Vector3 target, int nearestAgentIdx) { // Get next position information of the nearestAgentIdx FootballPlayerController nearestAgentController = agents[nearestAgentIdx].GetComponent <FootballPlayerController>(); PointInfo lastPos = nearestAgentController.getLastPosInfo(); BaseModel model = nearestAgentController.getMotionModel(); PointInfo nextPoint; if (formationDecreasingGoalVelocity) { PointInfo goalPointInfo = new PointInfo(target, Vector3.zero, Vector3.forward, lastPos.currentTime + vehicleDt); nextPoint = model.moveTowardsWithDecreasingVelocity(lastPos, goalPointInfo, nearestAgentController.getWorld(), false); } else { PointInfo goalPointInfo = new PointInfo(target, getAgentVelocity(0), getAgentOrientation(0), lastPos.currentTime + vehicleDt); List <PointInfo> path = model.completePath(lastPos, goalPointInfo, nearestAgentController.getWorld(), false); if (path != null && path.Count > 0) { nextPoint = path [0]; } else { return(false); } } nearestAgentController.getWorld().currentVelocities[nearestAgentIdx - 1] = nextPoint.vel; setCurrentVelocity(nearestAgentIdx, nextPoint.vel); // Get previous position of agent Vector3 prevPos = new Vector3(agents[nearestAgentIdx].transform.position.x, agents[nearestAgentIdx].transform.position.y, agents[nearestAgentIdx].transform.position.z); agents[nearestAgentIdx].transform.position = nextPoint.pos; Vector2[] tmpDesiredRelativePositions = getDesiredPositions(winnerIdx, false, false); // Store previous positional information Vector2[] prevRelativeFormationPositions = new Vector2[this.relativeFormationPositions.Length]; for (int i = 0; i < prevRelativeFormationPositions.Length; i++) { prevRelativeFormationPositions [i] = new Vector2(this.relativeFormationPositions[i].x, this.relativeFormationPositions[i].y); } Vector2[] prevDesiredRelative = getDesiredPositions(winnerIdx, false, false); Vector2[] prevDesiredAbsolute = getDesiredPositions(winnerIdx, false, true); // Calculate new positional information setRelativeFormationPositions(this.relativeFormationPositions, nearestAgentIdx - 1); this.desiredRelativePositions = getDesiredPositions(winnerIdx, false, false); this.desiredAbsolutePositions = getDesiredPositions(winnerIdx, false, true); // Get virtual center controller and its last position FootballPlayerController virtualCenterController = agents[agents.Length - 1].GetComponent <FootballPlayerController>(); PointInfo lastCenterPos = virtualCenterController.getLastPosInfo(); // Move center in the same way the nearest agent moves, anchoring the formation to the agent Vector2 desiredCenterPosition = getDesiredPosition(agents.Length - 2); Vector3 desiredCenter3D = new Vector3(desiredCenterPosition.x, agentHeight, desiredCenterPosition.y); // Get copy of formation rectangle VirtualStructureRectangle tmp = new VirtualStructureRectangle(formationRectangle); // Update rectangle with new desired center tmp.updateRectangle(desiredCenter3D); // Check if new rectangle gets out of the bounding polygon in case the agent is not already near the boundary if (lastPos.currentTime > 30.0f && !tmp.isInPolygon(nearestAgentController.getWorld().boundingPolygon)) { // If it is not entirely inside, restore changes and return false agents[nearestAgentIdx].transform.position = prevPos; this.relativeFormationPositions = prevRelativeFormationPositions; this.desiredAbsolutePositions = prevDesiredAbsolute; this.desiredRelativePositions = prevDesiredRelative; return(false); } // Otherwise make all necessary changes to variables of the closest agent and formation center agents[nearestAgentIdx].transform.position = prevPos; agents [nearestAgentIdx].transform.LookAt(agents[nearestAgentIdx].transform.position + (target - agents[nearestAgentIdx].transform.position).normalized); PointInfo nextPos = new PointInfo(nextPoint.pos, Vector3.zero, nextPoint.orientation, nextPoint.currentTime + vehicleDt); nearestAgentController.setNextPosInfo(nextPoint); agents [agents.Length - 1].transform.position = desiredCenter3D; lastCenterPos.pos = desiredCenter3D; lastCenterPos.vel = nextPoint.vel; lastCenterPos.orientation = nextPoint.orientation; lastCenterPos.currentTime = nextPoint.currentTime; formationRectangle = tmp; agents [agents.Length - 1].transform.LookAt(agents[agents.Length - 1].transform.position + (target - agents[agents.Length - 1].transform.position).normalized); virtualCenterController.setLastPosInfo(lastCenterPos); nextPos = new PointInfo(lastCenterPos.pos, Vector3.zero, lastCenterPos.orientation, lastCenterPos.currentTime + vehicleDt); virtualCenterController.setNextPosInfo(nextPos); virtualCenterController.setPlay(false); return(true); }