Exemplo n.º 1
0
		/// <summary>
		/// Picks an action for the character to do every tick.
		/// </summary>
		/// <param name="controller">The controller for the character.</param>
		public void ChooseAction(AIController controller)
		{
			foreach (IPolicy policy in policies)
			{
				policy.ChooseAction(controller);
			}
		}
Exemplo n.º 2
0
		/// <summary>
		/// Picks an action for the character to do every tick.
		/// </summary>
		/// <param name="controller">The controller for the character.</param>
		public void ChooseAction(AIController controller)
		{
			if (shootTarget == null)
			{
				// Find a new target to attack.
				Controller closestOpponent = null;
				float closestDistance = Mathf.Infinity;
				foreach (Controller opponent in GameManager.instance.AllPlayers)
				{
					if (opponent != controller && opponent.LifeComponent.Health > 0)
					{
						float opponentDistance = Vector3.Distance(opponent.transform.position, controller.transform.position);
						if (opponentDistance < closestDistance)
						{
							closestDistance = opponentDistance;
							closestOpponent = opponent;
						}
					}
				}
				foreach (GameObject token in TokenSpawner.instance.Tokens)
				{
					// See if any tokens are close enough to bother with.
					if (token.activeSelf)
					{
						float tokenDistance = Vector3.Distance(token.transform.position, controller.transform.position);
						if (tokenDistance < closestDistance)
						{
							closestDistance = tokenDistance;
							targetToken = token;
							rushPolicy.target = token.gameObject;
							rushPolicy.targetDistance = 0;
						}
					}
				}
				if (targetToken == null && closestOpponent != null)
				{
					rushPolicy.target = closestOpponent.gameObject;
					rushPolicy.targetDistance = TARGETDISTANCE;
				}
				shootPolicy.target = closestOpponent;
			}

			rushPolicy.ChooseAction(controller);
			shootPolicy.ChooseAction(controller);

			if (!controller.aiming || (shootTarget != null && shootTarget.LifeComponent.Health <= 0))
			{
				shootTarget = null;
			}
			if (targetToken != null && !targetToken.activeSelf)
			{
				targetToken = null;
				if (shootPolicy.target != null) {
					rushPolicy.target = shootPolicy.target.gameObject;
				} else {
					shootTarget = null;
				}
			}
		}
Exemplo n.º 3
0
		/// <summary>
		/// Picks an action for the character to do every tick.
		/// </summary>
		/// <param name="controller">The controller for the character.</param>
		public void ChooseAction(AIController controller)
		{
			if (controller.opponent.LifeComponent.Health <= 0) {
				controller.aiming = false;
				return;
			}

			// Calculate the needed angle and strength to hit the opponent.
			Vector3 distance = controller.opponent.transform.position - controller.transform.position;
			float x = distance.x;
			float y = distance.y;
			float g = Physics.gravity.y;

			// Minimum speed at 45 degrees.
			float v = Mathf.Sqrt(x * x * g / (x + 2 * y * ROOT22 * ROOT22));
			//Debug.Log(v);
			float minStrength = (-4 + Mathf.Sqrt(8 + 160 * v)) / 80;
			minStrength = Mathf.Sqrt(4 * minStrength * minStrength - minStrength * ROOT2 / 5 + 0.01f) / 2;
			float strength = Mathf.Max(power, minStrength);
			float angle = Mathf.PI / 4;

			// Change angle if the required power is greater than the minimum.
			/*
			if (strength != minStrength)
			{
				v = strength * 40 * (strength + 0.1f);
				float v2 = v * v;

				float discriminant = v2 * v2 - g * (g * x * x - 2 * y * v2);
				if (discriminant < 0)
				{
					discriminant = 0;
				}
				discriminant = 0;
				angle = Mathf.Atan((v2 - Mathf.Sqrt(discriminant)) / (g * x));
				Debug.Log(angle + " " + v + " " + x + " " + y);
			}*/

			controller.aim = Quaternion.Euler(0, 0, angle * 180 / Mathf.PI) * Vector3.up;

			//controller.aim = Vector3.Normalize(controller.opponent.transform.position - controller.transform.position);

			if (controller.aiming)
			{
				if (controller.ArcheryComponent.StrengthPercentage > strength - Time.deltaTime / 2f)
				{
					Debug.Log(v);
					controller.aiming = false;
				}
			}
			else
			{
				if (fireCooldown++ > cooldownTime)
				{
					controller.aiming = true;
					fireCooldown = 0;
				}
			}
		}
Exemplo n.º 4
0
		public void ChooseAction(AIController controller)
		{
			Vector3 opponentDistance = controller.GetOpponentDistance();
			if (Mathf.Abs(opponentDistance.x) > targetDistance) 
			{
				controller.SetRunInDirection(opponentDistance.x);
				// Don't chase an opponent off the map.
				RaycastHit hit = new RaycastHit();
				Vector3 offsetPosition = controller.transform.position;
				offsetPosition.x += controller.runSpeed;
				if (!Physics.Raycast(offsetPosition, Vector3.down, out hit, 100, 1 << 13)) {
					controller.runSpeed = 0;
				}
			} else {
				controller.runSpeed = 0;
			}
		}
Exemplo n.º 5
0
		/// <summary>
		/// Picks an action for the character to do every tick.
		/// </summary>
		/// <param name="controller">The controller for the character.</param>
		public void ChooseAction(AIController controller)
		{
			float totalOppDistance = Vector3.Distance(controller.opponent.transform.position, controller.transform.position);
			int shotChanceModifier = 0;

			// Experiment with 3 distance groups (determines if the bot shoots)

			//Choose the distance modifier
			if (totalOppDistance < 5)
			{
				shotChanceModifier = spacingReinforcement[0];
			}
			else if (totalOppDistance < 9)
			{
				shotChanceModifier = spacingReinforcement[1];
			}
			else
			{
				shotChanceModifier = spacingReinforcement[2];
			}


			//Check to see if CPU will shoot given the modifier
			int randShotChance = random.Next(200000);
			if (shotChanceModifier * chanceToShoot < randShotChance)
			{
				shotInst.ChooseAction(controller);
			}

			//Experiment with 3 distance groups (determines favorite distance)
			int randMoveChance = random.Next(100);
			if (randMoveChance < distanceReinforcement[0])
			{
				rushInst.targetDistance = 3;
			}
			else if (randMoveChance < (distanceReinforcement[0] + distanceReinforcement[1]))
			{
				rushInst.targetDistance = 4;
			}
			else if (randMoveChance < (distanceReinforcement[0] + distanceReinforcement[1] + distanceReinforcement[2]))
			{
				rushInst.targetDistance = 5;
			}
			rushInst.ChooseAction(controller);
		}
Exemplo n.º 6
0
		/// <summary>
		/// Picks an action for the character to do every tick.
		/// </summary>
		/// <param name="controller">The controller for the character.</param>
		public void ChooseAction(AIController controller)
		{
			Vector3 opponentDistance = controller.GetOpponentDistance();
			float horizontalDistance = Mathf.Abs(opponentDistance.x);
			if (horizontalDistance > targetDistance)
			{
				controller.SetRunInDirection(opponentDistance.x);
			}
			else if (horizontalDistance < targetDistance - 1f)
			{
				controller.SetRunInDirection(-opponentDistance.x);
			}
			else
			{
				controller.runSpeed = 0;
			}
			if (controller.runSpeed != 0) {
				// Don't chase an opponent off the map.
				RaycastHit hit = new RaycastHit();
				Vector3 offsetPosition = controller.transform.position;
				offsetPosition.x += controller.runSpeed;
				offsetPosition.y += 0.5f;
				if (!Physics.Raycast(offsetPosition, Vector3.down, out hit, 100, 1 << 13))
				{
					if (controller.ParkourComponent.Sliding)
					{
						controller.SetRunInDirection(-opponentDistance.x);
					}
					else
					{
						controller.runSpeed = 0;
					}
					controller.slide = false;
				}
				else
				{
					controller.slide = horizontalDistance > targetDistance * 2;
				}
			}
		}
Exemplo n.º 7
0
		public void ChooseAction(AIController controller)
		{
			if (controller.opponent.LifeComponent.Health <= 0) {
				controller.aiming = false;
				return;
			}
			controller.aim = Vector3.Normalize(controller.opponent.transform.position - controller.transform.position);
			if (controller.aiming)
			{
				if (controller.ArcheryComponent.StrengthPercentage > power)
				{
					controller.aiming = false;
				}
			}
			else
			{
				if (fireCooldown++ > cooldownTime)
				{
					controller.aiming = true;
					fireCooldown = 0;
				}
			}
		}
Exemplo n.º 8
0
		/// <summary>
		/// Picks an action for the character to do every tick.
		/// </summary>
		/// <param name="controller">The controller for the character.</param>
		public void ChooseAction(AIController controller)
		{
			if (target == null || target.LifeComponent.Health <= 0) {
				controller.aiming = true;
				return;
			}

			Vector3 positionOffset = target.transform.position - controller.transform.position;
			positionOffset.y += 0.25f;
			bool left = false;
			if (positionOffset.x < 0)
			{
				left = true;
				positionOffset.x = -positionOffset.x;
			}

			float angle = Vector3.Angle(Vector3.right, positionOffset) * Mathf.PI / 180;
			angle = Mathf.Max(angle, minAngle);

			float x = positionOffset.x;
			float y = positionOffset.y;
			float g = -Physics.gravity.y;

			// Find the minimum power for the required angle.
			float v = Mathf.Sqrt((x * x * g) / (x * Mathf.Sin(2 * angle) - 2 * y * Mathf.Pow(Mathf.Cos(angle), 2)));
			float power = (Mathf.Sqrt(10 * v + 1) - 1) / 20;

			// If the minimum power is less than the required power, find the needed angle for the power.
			if (power < minPower)
			{
				power = minPower;
				v = 40 * power * (power + 0.1f);
				float root = Mathf.Sqrt(Mathf.Pow(v, 4) - g * (g * x * x + 2 * y * v * v));
				angle = Mathf.Atan((v * v - root) / (g * x));
				if (angle < minAngle)
				{
					angle = Mathf.Atan((v * v + root) / (g * x));
				}
			}
			power = Mathf.Min(power, 0.95f);

			if (left)
			{
				angle = Mathf.PI - angle;
			}

			controller.aim = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0);

			// Keep the bow drawn without shooting if there isn't a clear shot.
			if (left)
			{
				positionOffset.x = -positionOffset.x;
			}
			RaycastHit hit;
			if (!controller.HasClearShot(positionOffset, out hit))
			{
				controller.aiming = true;
				return;
			}

			if (controller.aiming)
			{
				if (controller.ArcheryComponent.StrengthPercentage >= power)
				{
					controller.ArcheryComponent.StrengthPercentage = power;
					controller.aiming = false;
				}
			}
			else
			{
				fireCooldown += Time.deltaTime;
				if (fireCooldown > cooldownTime)
				{
					controller.aiming = true;
					fireCooldown = 0;
				}
			}
		}
Exemplo n.º 9
0
		/// <summary>
		/// Picks an action for the character to do every tick.
		/// </summary>
		/// <param name="controller">The controller for the character.</param>
		public void ChooseAction(AIController controller)
		{
			if (DEBUGLINES)
			{
				foreach (LedgeNode ledge in ledges)
				{
					foreach (LedgeNode adjacent in ledge.adjacentEdges)
					{
						Debug.DrawLine(ledge.transform.position, adjacent.transform.position, Color.yellow);
					}
				}
			}
			if (target == null) {
				controller.SetRunInDirection(0);
				return;
			}
			Controller targetController = target.GetComponent<Controller>();
			if (targetController != null && targetController.LifeComponent.Health <= 0)
			{
				controller.SetRunInDirection(0);
				return;
			}

			lastSpeed = controller.runSpeed;

			controller.jump = false;
			float currentTargetDistance = targetDistance;
			Vector3 opponentOffset = target.transform.position - controller.transform.position;
			Vector3 targetOffset = opponentOffset;
			float distanceTolerance = targetDistance - 1;
			Vector3 playerCenter = controller.transform.position + Vector3.up * 0.75f;

			RaycastHit under;
			Physics.Raycast(playerCenter, Vector3.down, out under, 30, AIController.LAYERMASK);

			// Check if there is a platform in the way of shooting.
			RaycastHit hit;
			// Find a ledge path to get to the target.
			replanTimer -= Time.deltaTime;
			if (pathTarget != target && currentNode == null)
			{
				replanTimer = 0;
			}
			if (OnSamePlatform(controller.transform, target.transform))
			{
				if (Mathf.Abs(opponentOffset.y) < 5 && (Mathf.Abs(opponentOffset.y) < 0.1f || under.distance < 1))
				{
					currentNode = null;
				}
			}
			else if (replanTimer <= 0)
			{
				replanTimer = REPLANTIME;
				pathTarget = target;
				currentPath = GetPath(GetClosestLedgeNode(controller.transform), GetClosestLedgeNode(target.transform));
				if (currentPath.Count > 0)
				{
					currentPath.Last.Value.YOffset = target.transform.position.y - currentPath.Last.Value.transform.position.y;
					LoadNextLedge();
					currentNode.YOffset = currentNode.transform.position.y - controller.transform.position.y;
					if (currentPath.Count > 0)
					{
						if (GetLedgePlatform(currentPath.First.Value) == GetPlatformUnderneath(controller.transform))
						{
							LoadNextLedge();
						}
						else if (currentPath.Count == 1 && Mathf.Abs(currentNode.transform.position.y - currentPath.First.Value.transform.position.y) < 0.2f)
						{
							currentNode = null;
						}
					}
				}
				else
				{
					currentNode = null;
				}
			}

			if (currentNode != null)
			{
				// Move towards the nearest ledge, jumping if needed.
				Vector3 currentOffset = currentNode.transform.position - controller.transform.position;

				// Go to the next ledge node if possible.
				if (currentNode.YOffset >= 0 && Math.Abs(currentOffset.x) <= LEDGEGRABDISTANCE / 3 && currentOffset.y <= 0  ||
					currentNode.YOffset < 0 && currentOffset.y >= 1.5f)
				{
					LoadNextLedge();
				}
				if (currentNode != null)
				{
					currentOffset = currentNode.transform.position - controller.transform.position;

					currentTargetDistance = 0;
					distanceTolerance = 0.1f;

					if (Mathf.Abs(currentOffset.y) < distanceTolerance)
					{
						currentOffset.y = 0;
					}

					Vector3 platformOffset = currentNode.transform.position - GetLedgePlatform(currentNode).transform.position;

					float ledgeOffset = -0.1f;
					if (currentNode.YOffset > 0 && currentOffset.y > -0.5f ||
						currentNode.YOffset < 0)
					{
						ledgeOffset = LEDGEGRABDISTANCE;
					}
					if (platformOffset.x > 0)
					{
						currentOffset.x += ledgeOffset;
					}
					else
					{
						currentOffset.x -= ledgeOffset;
					}

					controller.jump = currentNode.YOffset >= 0 && Math.Abs(currentOffset.x) <= LEDGEGRABDISTANCE / 2;
					 
					targetOffset = currentOffset;
				}
			}

			if (DEBUGLINES)
			{
				Debug.DrawRay(controller.transform.position, targetOffset, Color.red);
				if (currentNode != null)
				{
					LedgeNode c = currentNode;
					foreach (LedgeNode l in currentPath)
					{
						Debug.DrawLine(c.transform.position, l.transform.position, Color.red);
						c = l;
					}
					Debug.DrawLine(c.transform.position, target.transform.position, Color.red);
				}
			}
				
			LedgeNode closestLedge = null;

			// Check if the AI is falling to its death.
			if (under.collider == null)
			{
				// Find the closest ledge to go to.
				float closestLedgeDistance = Mathf.Infinity;
				foreach (LedgeNode ledge in ledges)
				{
                    if (ledge != null)
                    {
                        float currentDistance = Mathf.Abs(ledge.transform.position.x - controller.transform.position.x);
                        if (currentDistance < closestLedgeDistance && ledge.transform.position.y < controller.transform.position.y + 1)
                        {
                            closestLedge = ledge;
                            closestLedgeDistance = currentDistance;
                        }
                    }
				}
				bool awayFromLedge = false;
				if (closestLedge == null)
				{
					controller.SetRunInDirection(-controller.transform.position.x);
				}
				else {
					float ledgeOffsetX = closestLedge.transform.position.x - controller.transform.position.x;
					if (Mathf.Abs(ledgeOffsetX) > LEDGEGRABDISTANCE)
					{
						controller.SetRunInDirection(ledgeOffsetX);
						awayFromLedge = true;
					}
				}
				controller.jump = true;
				if (awayFromLedge)
				{
					return;
				}
			}

			// Move towards the opponent.
			float horizontalDistance = Mathf.Abs(targetOffset.x);
			if (horizontalDistance > currentTargetDistance)
			{
				controller.SetRunInDirection(targetOffset.x);
			}
			else if (horizontalDistance < currentTargetDistance - distanceTolerance)
			{
				controller.SetRunInDirection(-targetOffset.x);
			}
			else if (opponentOffset == targetOffset && under.collider != null && (controller.ParkourComponent.FacingRight ^ opponentOffset.x > 0))
			{
				controller.ParkourComponent.FacingRight = opponentOffset.x > 0;
			}
			else
			{
				controller.runSpeed = 0;
			}
			if (controller.runSpeed != 0)
			{
				// Don't chase an opponent off the map.
				Vector3 offsetPosition = controller.transform.position;
				offsetPosition.x += controller.runSpeed / 3;
				offsetPosition.y += 0.5f;
				Vector3 offsetPosition3 = offsetPosition;
				offsetPosition3.x += controller.runSpeed;
				if (!Physics.Raycast(offsetPosition, Vector3.down, out hit, 30, AIController.LAYERMASK) &&
					!Physics.Raycast(offsetPosition3, Vector3.down, out hit, 30, AIController.LAYERMASK))
				{
					if (controller.ParkourComponent.Sliding)
					{
						controller.SetRunInDirection(-opponentOffset.x);
					}
					else if (closestLedge == null)
					{
						controller.runSpeed = 0;
					}
					controller.slide = false;
				}
				else
				{
					// Slide if the opponent is far enough away for sliding to be useful.
					controller.ParkourComponent.FacingRight = opponentOffset.x > 0;
					controller.slide = horizontalDistance > 10 && currentNode == null && OnSamePlatform(controller.transform, target.transform);
				}
			}

			if (controller.runSpeed == 0 && Mathf.Abs(opponentOffset.x) < 1 && opponentOffset.y < 0 && target.GetComponent<Controller>() && controller.GetComponent<Rigidbody>().velocity.y <= Mathf.Epsilon)
			{
				// Don't sit on top of the opponent.
				controller.SetRunInDirection(-controller.transform.position.x);
			}

			if (controller.runSpeed > 0 && lastSpeed < 0 || controller.runSpeed < 0 && lastSpeed > 0)
			{
				// Check if the AI turned very recently to avoid thrashing.
				turnTimer -= Time.deltaTime;
				if (turnTimer <= 0) {
					turnTimer = TURNCOOLDOWN;
				} else {
					controller.runSpeed = 0;
				}
			}

			// Jump to reach some tokens.
			if (targetDistance == 0 && controller.runSpeed == 0 && target.GetComponent<ArrowToken>() && opponentOffset == targetOffset) {
				controller.jump = true;
			}

			controller.fastFall = targetOffset.y < -1f;
		}
Exemplo n.º 10
0
        /// <summary>
        /// Picks an action for the character to do every tick.
        /// </summary>
        /// <param name="controller">The controller for the character.</param>
        public void ChooseAction(AIController controller)
        {
            if (DEBUGLINES)
            {
                foreach (LedgeNode ledge in ledges)
                {
                    foreach (LedgeNode adjacent in ledge.adjacentEdges)
                    {
                        Debug.DrawLine(ledge.transform.position, adjacent.transform.position, Color.yellow);
                    }
                }
            }
            if (target == null)
            {
                controller.SetRunInDirection(0);
                return;
            }
            Controller targetController = target.GetComponent <Controller>();

            if (targetController != null && targetController.LifeComponent.Health <= 0)
            {
                controller.SetRunInDirection(0);
                return;
            }

            lastSpeed = controller.runSpeed;

            controller.jump = false;
            float   currentTargetDistance = targetDistance;
            Vector3 opponentOffset        = target.transform.position - controller.transform.position;
            Vector3 targetOffset          = opponentOffset;
            float   distanceTolerance     = targetDistance - 1;
            Vector3 playerCenter          = controller.transform.position + Vector3.up * 0.75f;

            RaycastHit under;

            Physics.Raycast(playerCenter, Vector3.down, out under, 30, AIController.LAYERMASK);

            // Check if there is a platform in the way of shooting.
            RaycastHit hit;

            // Find a ledge path to get to the target.
            replanTimer -= Time.deltaTime;
            if (pathTarget != target && currentNode == null)
            {
                replanTimer = 0;
            }
            if (OnSamePlatform(controller.transform, target.transform))
            {
                if (Mathf.Abs(opponentOffset.y) < 5 && (Mathf.Abs(opponentOffset.y) < 0.1f || under.distance < 1))
                {
                    currentNode = null;
                }
            }
            else if (replanTimer <= 0)
            {
                replanTimer = REPLANTIME;
                pathTarget  = target;
                currentPath = GetPath(GetClosestLedgeNode(controller.transform), GetClosestLedgeNode(target.transform));
                if (currentPath.Count > 0)
                {
                    currentPath.Last.Value.YOffset = target.transform.position.y - currentPath.Last.Value.transform.position.y;
                    LoadNextLedge();
                    currentNode.YOffset = currentNode.transform.position.y - controller.transform.position.y;
                    if (currentPath.Count > 0)
                    {
                        if (GetLedgePlatform(currentPath.First.Value) == GetPlatformUnderneath(controller.transform))
                        {
                            LoadNextLedge();
                        }
                        else if (currentPath.Count == 1 && Mathf.Abs(currentNode.transform.position.y - currentPath.First.Value.transform.position.y) < 0.2f)
                        {
                            currentNode = null;
                        }
                    }
                }
                else
                {
                    currentNode = null;
                }
            }

            if (currentNode != null)
            {
                // Move towards the nearest ledge, jumping if needed.
                Vector3 currentOffset = currentNode.transform.position - controller.transform.position;

                // Go to the next ledge node if possible.
                if (currentNode.YOffset >= 0 && Math.Abs(currentOffset.x) <= LEDGEGRABDISTANCE / 3 && currentOffset.y <= 0 ||
                    currentNode.YOffset < 0 && currentOffset.y >= 1.5f)
                {
                    LoadNextLedge();
                }
                if (currentNode != null)
                {
                    currentOffset = currentNode.transform.position - controller.transform.position;

                    currentTargetDistance = 0;
                    distanceTolerance     = 0.1f;

                    if (Mathf.Abs(currentOffset.y) < distanceTolerance)
                    {
                        currentOffset.y = 0;
                    }

                    Vector3 platformOffset = currentNode.transform.position - GetLedgePlatform(currentNode).transform.position;

                    float ledgeOffset = -0.1f;
                    if (currentNode.YOffset > 0 && currentOffset.y > -0.5f ||
                        currentNode.YOffset < 0)
                    {
                        ledgeOffset = LEDGEGRABDISTANCE;
                    }
                    if (platformOffset.x > 0)
                    {
                        currentOffset.x += ledgeOffset;
                    }
                    else
                    {
                        currentOffset.x -= ledgeOffset;
                    }

                    controller.jump = currentNode.YOffset >= 0 && Math.Abs(currentOffset.x) <= LEDGEGRABDISTANCE / 2;

                    targetOffset = currentOffset;
                }
            }

            if (DEBUGLINES)
            {
                Debug.DrawRay(controller.transform.position, targetOffset, Color.red);
                if (currentNode != null)
                {
                    LedgeNode c = currentNode;
                    foreach (LedgeNode l in currentPath)
                    {
                        Debug.DrawLine(c.transform.position, l.transform.position, Color.red);
                        c = l;
                    }
                    Debug.DrawLine(c.transform.position, target.transform.position, Color.red);
                }
            }

            LedgeNode closestLedge = null;

            // Check if the AI is falling to its death.
            if (under.collider == null)
            {
                // Find the closest ledge to go to.
                float closestLedgeDistance = Mathf.Infinity;
                foreach (LedgeNode ledge in ledges)
                {
                    if (ledge != null)
                    {
                        float currentDistance = Mathf.Abs(ledge.transform.position.x - controller.transform.position.x);
                        if (currentDistance < closestLedgeDistance && ledge.transform.position.y < controller.transform.position.y + 1)
                        {
                            closestLedge         = ledge;
                            closestLedgeDistance = currentDistance;
                        }
                    }
                }
                bool awayFromLedge = false;
                if (closestLedge == null)
                {
                    controller.SetRunInDirection(-controller.transform.position.x);
                }
                else
                {
                    float ledgeOffsetX = closestLedge.transform.position.x - controller.transform.position.x;
                    if (Mathf.Abs(ledgeOffsetX) > LEDGEGRABDISTANCE)
                    {
                        controller.SetRunInDirection(ledgeOffsetX);
                        awayFromLedge = true;
                    }
                }
                controller.jump = true;
                if (awayFromLedge)
                {
                    return;
                }
            }

            // Move towards the opponent.
            float horizontalDistance = Mathf.Abs(targetOffset.x);

            if (horizontalDistance > currentTargetDistance)
            {
                controller.SetRunInDirection(targetOffset.x);
            }
            else if (horizontalDistance < currentTargetDistance - distanceTolerance)
            {
                controller.SetRunInDirection(-targetOffset.x);
            }
            else if (opponentOffset == targetOffset && under.collider != null && (controller.ParkourComponent.FacingRight ^ opponentOffset.x > 0))
            {
                controller.ParkourComponent.FacingRight = opponentOffset.x > 0;
            }
            else
            {
                controller.runSpeed = 0;
            }
            if (controller.runSpeed != 0)
            {
                // Don't chase an opponent off the map.
                Vector3 offsetPosition = controller.transform.position;
                offsetPosition.x += controller.runSpeed / 3;
                offsetPosition.y += 0.5f;
                Vector3 offsetPosition3 = offsetPosition;
                offsetPosition3.x += controller.runSpeed;
                if (!Physics.Raycast(offsetPosition, Vector3.down, out hit, 30, AIController.LAYERMASK) &&
                    !Physics.Raycast(offsetPosition3, Vector3.down, out hit, 30, AIController.LAYERMASK))
                {
                    if (controller.ParkourComponent.Sliding)
                    {
                        controller.SetRunInDirection(-opponentOffset.x);
                    }
                    else if (closestLedge == null)
                    {
                        controller.runSpeed = 0;
                    }
                    controller.slide = false;
                }
                else
                {
                    // Slide if the opponent is far enough away for sliding to be useful.
                    controller.ParkourComponent.FacingRight = opponentOffset.x > 0;
                    controller.slide = horizontalDistance > 10 && currentNode == null && OnSamePlatform(controller.transform, target.transform);
                }
            }

            if (controller.runSpeed == 0 && Mathf.Abs(opponentOffset.x) < 1 && opponentOffset.y < 0 && target.GetComponent <Controller>() && controller.GetComponent <Rigidbody>().velocity.y <= Mathf.Epsilon)
            {
                // Don't sit on top of the opponent.
                controller.SetRunInDirection(-controller.transform.position.x);
            }

            if (controller.runSpeed > 0 && lastSpeed < 0 || controller.runSpeed < 0 && lastSpeed > 0)
            {
                // Check if the AI turned very recently to avoid thrashing.
                turnTimer -= Time.deltaTime;
                if (turnTimer <= 0)
                {
                    turnTimer = TURNCOOLDOWN;
                }
                else
                {
                    controller.runSpeed = 0;
                }
            }

            // Jump to reach some tokens.
            if (targetDistance == 0 && controller.runSpeed == 0 && target.GetComponent <ArrowToken>() && opponentOffset == targetOffset)
            {
                controller.jump = true;
            }

            controller.fastFall = targetOffset.y < -1f;
        }
Exemplo n.º 11
0
        /// <summary>
        /// Picks an action for the character to do every tick.
        /// </summary>
        /// <param name="controller">The controller for the character.</param>
        public void ChooseAction(AIController controller)
        {
            fireCooldown += Time.deltaTime;
            if (target == null || target.LifeComponent.Health <= 0)
            {
                controller.aiming = false;
                return;
            }

            Vector3 positionOffset = target.transform.position - controller.transform.position;

            positionOffset.y += 0.25f;
            bool left = false;

            if (positionOffset.x < 0)
            {
                left             = true;
                positionOffset.x = -positionOffset.x;
            }

            float angle = Vector3.Angle(Vector3.right, positionOffset) * Mathf.PI / 180;

            angle = Mathf.Max(angle, minAngle);

            float x = positionOffset.x;
            float y = positionOffset.y;
            float g = -Physics.gravity.y;

            // Find the minimum power for the required angle.
            float v     = Mathf.Sqrt((x * x * g) / (x * Mathf.Sin(2 * angle) - 2 * y * Mathf.Pow(Mathf.Cos(angle), 2)));
            float power = (Mathf.Sqrt(10 * v + 1) - 1) / 20;

            // If the minimum power is less than the required power, find the needed angle for the power.
            if (power < minPower)
            {
                power = minPower;
                v     = 40 * power * (power + 0.1f);
                float root = Mathf.Sqrt(Mathf.Pow(v, 4) - g * (g * x * x + 2 * y * v * v));
                angle = Mathf.Atan((v * v - root) / (g * x));
                if (angle < minAngle)
                {
                    angle = Mathf.Atan((v * v + root) / (g * x));
                }
            }
            power = Mathf.Min(power, 0.95f);

            if (left)
            {
                angle = Mathf.PI - angle;
            }

            controller.aim = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0);

            // Keep the bow drawn without shooting if there isn't a clear shot.
            if (left)
            {
                positionOffset.x = -positionOffset.x;
            }
            RaycastHit hit;

            if (!controller.HasClearShot(positionOffset, out hit))
            {
                controller.aiming = false;
                return;
            }

            if (controller.aiming)
            {
                if (controller.ArcheryComponent.StrengthPercentage >= power && Mathf.Abs(Vector3.Angle(controller.aim, Vector3.right) - controller.ArcheryComponent.GetAimAngle()) < 7)
                {
                    controller.ArcheryComponent.StrengthPercentage = power;
                    controller.aiming = false;
                }
            }
            else
            {
                if (fireCooldown > cooldownTime)
                {
                    controller.aiming = true;
                    fireCooldown      = 0;
                }
            }
        }
Exemplo n.º 12
0
        /// <summary>
        /// Picks an action for the character to do every tick.
        /// </summary>
        /// <param name="controller">The controller for the character.</param>
        public void ChooseAction(AIController controller)
        {
            if (controller.opponent.LifeComponent.Health <= 0)
            {
                controller.aiming = false;
                return;
            }

            // Calculate the needed angle and strength to hit the opponent.
            Vector3 distance = controller.opponent.transform.position - controller.transform.position;
            float   x        = distance.x;
            float   y        = distance.y;
            float   g        = Physics.gravity.y;

            // Minimum speed at 45 degrees.
            float v = Mathf.Sqrt(x * x * g / (x + 2 * y * ROOT22 * ROOT22));
            //Debug.Log(v);
            float minStrength = (-4 + Mathf.Sqrt(8 + 160 * v)) / 80;

            minStrength = Mathf.Sqrt(4 * minStrength * minStrength - minStrength * ROOT2 / 5 + 0.01f) / 2;
            float strength = Mathf.Max(power, minStrength);
            float angle    = Mathf.PI / 4;

            // Change angle if the required power is greater than the minimum.

            /*
             * if (strength != minStrength)
             * {
             *      v = strength * 40 * (strength + 0.1f);
             *      float v2 = v * v;
             *
             *      float discriminant = v2 * v2 - g * (g * x * x - 2 * y * v2);
             *      if (discriminant < 0)
             *      {
             *              discriminant = 0;
             *      }
             *      discriminant = 0;
             *      angle = Mathf.Atan((v2 - Mathf.Sqrt(discriminant)) / (g * x));
             *      Debug.Log(angle + " " + v + " " + x + " " + y);
             * }*/

            controller.aim = Quaternion.Euler(0, 0, angle * 180 / Mathf.PI) * Vector3.up;

            //controller.aim = Vector3.Normalize(controller.opponent.transform.position - controller.transform.position);

            if (controller.aiming)
            {
                if (controller.ArcheryComponent.StrengthPercentage > strength - Time.deltaTime / 2f)
                {
                    Debug.Log(v);
                    controller.aiming = false;
                }
            }
            else
            {
                if (fireCooldown++ > cooldownTime)
                {
                    controller.aiming = true;
                    fireCooldown      = 0;
                }
            }
        }
Exemplo n.º 13
0
        /// <summary>
        /// Picks an action for the character to do every tick.
        /// </summary>
        /// <param name="controller">The controller for the character.</param>
        public void ChooseAction(AIController controller)
        {
            if (shootTarget == null)
            {
                // Find a new target to attack.
                Controller closestOpponent = null;
                float      closestDistance = Mathf.Infinity;
                foreach (Controller opponent in GameManager.instance.AllPlayers)
                {
                    if (opponent != controller && opponent.LifeComponent.Health > 0)
                    {
                        float opponentDistance = Vector3.Distance(opponent.transform.position, controller.transform.position);
                        if (opponentDistance < closestDistance)
                        {
                            closestDistance = opponentDistance;
                            closestOpponent = opponent;
                        }
                    }
                }
                if (controller.ArcheryComponent.CanCollectToken())
                {
                    foreach (GameObject token in TokenSpawner.instance.Tokens)
                    {
                        // See if any tokens are close enough to bother with.
                        if (token.activeSelf)
                        {
                            float tokenDistance = Vector3.Distance(token.transform.position, controller.transform.position);
                            if (tokenDistance < closestDistance && !Util.Bitwise.IsBitOn(controller.ArcheryComponent.ArrowTypes, (int)token.GetComponent <ArrowToken>().Type))
                            {
                                closestDistance           = tokenDistance;
                                targetToken               = token;
                                rushPolicy.target         = token.gameObject;
                                rushPolicy.targetDistance = 0;
                            }
                        }
                    }
                }
                if (targetToken == null && closestOpponent != null)
                {
                    rushPolicy.target         = closestOpponent.gameObject;
                    rushPolicy.targetDistance = TARGETDISTANCE;
                }
                shootPolicy.target = closestOpponent;
                shootTarget        = closestOpponent;
            }

            rushPolicy.ChooseAction(controller);
            shootPolicy.ChooseAction(controller);

            if (!controller.aiming || (shootTarget != null && shootTarget.LifeComponent.Health <= 0))
            {
                shootTarget = null;
            }
            if (targetToken != null && !targetToken.activeSelf)
            {
                targetToken = null;
                if (shootPolicy.target != null)
                {
                    rushPolicy.target = shootPolicy.target.gameObject;
                }
            }
        }
Exemplo n.º 14
0
		/// <summary>
		/// Picks an action for the character to do every tick.
		/// </summary>
		/// <param name="controller">The controller for the character.</param>
		public void ChooseAction(AIController controller)
		{
			if (target == null) {
				return;
			}

			lastSpeed = controller.runSpeed;

			controller.jump = false;
			float currentTargetDistance = targetDistance;
			Vector3 opponentOffset = target.transform.position - controller.transform.position;
			Vector3 targetOffset = opponentOffset;
			float distanceTolerance = 1f;


			// Check if there is a platform in the way of shooting.
			RaycastHit hit;
			controller.HasClearShot(opponentOffset, out hit);

			Transform blockingLedge = null;
			if (hit.collider != null)
			{
				// If an obstacle is in the way, move around it.
				float closestDistance = Mathf.Infinity;
				// Find ledges on the obstructing platform.
				BoxCollider[] children = hit.collider.GetComponentsInChildren<BoxCollider>();
				bool foundBetween = false;
				foreach (BoxCollider child in children)
				{
					if (child.tag == "Ledge")
					{
						Vector3 ledgeOffset = child.transform.position - controller.transform.position;
						if (Mathf.Sign(ledgeOffset.y) == Mathf.Sign(targetOffset.y)) {
							// Look for the closest ledge to grab or fall from.
							float currentDistance = Mathf.Abs(child.transform.position.x - controller.transform.position.x);
							bool between = BetweenX(child.transform, controller.transform, target.transform);
							if (!(foundBetween && !between) && currentDistance < closestDistance || !foundBetween && between)
							{
								foundBetween = foundBetween || between;
								// Make sure the edge isn't off the side of the map.
								float edgeMultiplier = 3;
								if (Physics.Raycast(child.transform.position + Vector3.down * 0.5f + Vector3.left * edgeMultiplier, Vector3.down, 30, AIController.LAYERMASK) ||
									Physics.Raycast(child.transform.position + Vector3.down * 0.5f + Vector3.right * edgeMultiplier, Vector3.down, 30, AIController.LAYERMASK))
								{
									// Don't target ledges that have already been jumped over.
									if (currentDistance > LEDGEGRABDISTANCE || child.transform.position.y >= controller.transform.position.y)
									{
										blockingLedge = child.transform;
										closestDistance = currentDistance;
									}
								}
							}
						}
					}
				}
			}

			Transform gapLedge = null;
			RaycastHit under;
			Physics.Raycast(controller.transform.position + Vector3.up * 0.5f, Vector3.down, out under, 30, AIController.LAYERMASK);
			if (hit.collider == null)
			{
				// If the ranger and its target are not on the same platform, go to a nearby ledge.
				RaycastHit underTarget;
				Physics.Raycast(target.transform.position + Vector3.up * 0.5f, Vector3.down, out underTarget, 30, AIController.LAYERMASK);
				if (under.collider != null && underTarget.collider != null && under.collider.gameObject != underTarget.collider.gameObject)
				{
					float closestLedgeDistance = Mathf.Infinity;
					foreach (GameObject ledge in ledges)
					{
						float currentDistance = Mathf.Abs(ledge.transform.position.x - controller.transform.position.x);
						if (currentDistance < closestLedgeDistance && ledge.transform.position.y > controller.transform.position.y + 1 &&
							BetweenX(ledge.transform, controller.transform, target.transform))
						{
							gapLedge = ledge.transform;
							closestLedgeDistance = currentDistance;
						}
					}
				}
			}

			Transform closestLedge;
			if (blockingLedge == null)
			{
				closestLedge = gapLedge;
			}
			else if (gapLedge == null)
			{
				closestLedge = blockingLedge;
			}
			else
			{
				if (Vector3.Distance(blockingLedge.position, controller.transform.position) <= Vector3.Distance(gapLedge.position, controller.transform.position))
				{
					closestLedge = blockingLedge;
				}
				else
				{
					closestLedge = gapLedge;
				}
			}

			if (closestLedge != null)
			{
				// Move towards the nearest ledge, jumping if needed.
				Vector3 closestVector = closestLedge.position - controller.transform.position;
				if (closestLedge.position.x - closestLedge.parent.position.x > 0)
				{
					closestVector.x += LEDGEGRABDISTANCE;
				}
				else
				{
					closestVector.x -= LEDGEGRABDISTANCE;
				}
				if (Math.Abs(closestVector.x) < 1f)
				{
					controller.jump = opponentOffset.y > 0 || gapLedge != null;
				}
				else
				{
					controller.jump = false;
				}
				currentTargetDistance = 0;
				distanceTolerance = 0.1f;
				targetOffset = closestVector;
			}
			Debug.DrawRay(controller.transform.position, targetOffset);

			// Check if the AI is falling to its death.
			if (under.collider == null)
			{
				// Find the closest ledge to go to.
				closestLedge = null;
				float closestLedgeDistance = Mathf.Infinity;
				foreach (GameObject ledge in ledges)
				{
					float currentDistance = Mathf.Abs(ledge.transform.position.x - controller.transform.position.x);
					if (currentDistance < closestLedgeDistance && ledge.transform.position.y < controller.transform.position.y + 1)
					{
						closestLedge = ledge.transform;
						closestLedgeDistance = currentDistance;
					}
				}
				bool awayFromLedge = false;
				if (closestLedge == null)
				{
					controller.SetRunInDirection(-controller.transform.position.x);
				}
				else {
					float ledgeOffsetX = closestLedge.position.x - controller.transform.position.x;
					if (Mathf.Abs(ledgeOffsetX) > LEDGEGRABDISTANCE)
					{
						controller.SetRunInDirection(ledgeOffsetX);
						awayFromLedge = true;
					}
				}
				controller.jump = true;
				if (awayFromLedge)
				{
					return;
				}
			}

			if (currentTargetDistance > 0 && targetOffset.y < -1 && (closestLedge != null || Mathf.Abs(opponentOffset.x) > 1))
			{
				// Move onto a platform if a ledge was just negotiated.
				currentTargetDistance = 0;
			}

			// Move towards the opponent.
			float horizontalDistance = Mathf.Abs(targetOffset.x);
			if (horizontalDistance > currentTargetDistance)
			{
				controller.SetRunInDirection(targetOffset.x);
			}
			else if (horizontalDistance < currentTargetDistance - distanceTolerance)
			{
				controller.SetRunInDirection(-targetOffset.x);
			}
			else
			{
				controller.runSpeed = 0;
			}
			if (controller.runSpeed != 0)
			{
				// Don't chase an opponent off the map.
				Vector3 offsetPosition = controller.transform.position;
				offsetPosition.x += controller.runSpeed;
				offsetPosition.y += 0.5f;
				Vector3 offsetPosition3 = offsetPosition;
				offsetPosition3.x += controller.runSpeed * 2;
				if (!Physics.Raycast(offsetPosition, Vector3.down, out hit, 30, AIController.LAYERMASK) &&
					!Physics.Raycast(offsetPosition3, Vector3.down, out hit, 30, AIController.LAYERMASK))
				{
					if (controller.ParkourComponent.Sliding)
					{
						controller.SetRunInDirection(-opponentOffset.x);
					}
					else if (closestLedge == null)
					{
						controller.runSpeed = 0;
					}
					controller.slide = false;
				}
				else
				{
					// Slide if the opponent is far enough away for sliding to be useful.
					controller.slide = horizontalDistance > targetDistance * 2;
				}
			}

			if (controller.runSpeed == 0 && Mathf.Abs(opponentOffset.x) < 1 && opponentOffset.y < 0 && target.GetComponent<Controller>() && controller.GetComponent<Rigidbody>().velocity.y <= Mathf.Epsilon)
			{
				// Don't sit on top of the opponent.
				controller.SetRunInDirection(-controller.transform.position.x);
			}

			if (controller.runSpeed > 0 && lastSpeed < 0 || controller.runSpeed < 0 && lastSpeed > 0)
			{
				// Check if the AI turned very recently to avoid thrashing.
				if (turnTimer-- <= 0) {
					turnTimer = TURNCOOLDOWN;
				} else {
					controller.runSpeed = 0;
				}
			}

			// Jump to reach some tokens.
			if (targetDistance == 0 && controller.runSpeed == 0) {
				controller.jump = true;
			}
		}