Пример #1
0
 /// <summary>
 /// Changes the theme of all child IChangeTheme components that were attached at the start of the game to the players theme.
 /// </summary>
 /// <param name="user">The character that caused the hit.</param>
 /// <param name="hitPlanet">The planet that was hit.</param>
 /// <param name="hitPoint">The world coordinates of the hit.</param>
 /// <param name="hitNormal">The world normal of the hit.</param>
 public void OnHit(PlayerStats stats, PlanetStats hitPlanet, Vector3 hitPoint, Vector3 hitNormal)
 {
     if (stats != null)
     {
         SetTheme(stats.theme);
     }
 }
Пример #2
0
        /// <summary>
        /// Finds the attached planet stats. Planet Stats are not required for use but is highly recommended and may
        /// become a future requirement.
        /// </summary>
        protected void Awake()
        {
            myPlanet = GetComponentInParent <PlanetStats>();

            if (!myPlanet)
            {
                Debug.LogWarning("Warning: Destroyer script not associated with a planet.");
            }
        }
        /// <summary>
        /// Update players current state variables.
        /// </summary>
        protected void Update()
        {
            isGrounded = Physics.CheckBox(groundCheck.position - transform.up * groundCheckDistance / 2.0f,
                                          Vector3.one * groundCheckDistance / 2.0f, groundCheck.rotation, groundMask, QueryTriggerInteraction.Ignore);

            if (isGrounded)
            {
                RaycastHit downHit;

                if (Physics.Raycast(groundCheck.position, gravity.GravityDirection, out downHit, groundCheckDistance, groundMask, QueryTriggerInteraction.Ignore))
                {
                    transform.parent = downHit.transform;

                    if (isUsingGroundPound)
                    {
                        PlanetStats       hitPlanet     = downHit.transform.GetComponentInParent <PlanetStats>();
                        IOnHitBehaviour[] hitBehaviours = downHit.transform.GetComponentsInParent <IOnHitBehaviour>();

                        foreach (IOnHitBehaviour onHitBehaviour in hitBehaviours)
                        {
                            onHitBehaviour.OnHit(stats, hitPlanet, downHit.point, downHit.normal);
                        }

                        groundPoundRecoveryTimer = groundPoundRecoveryTime;
                    }

                    isUsingGroundPound = false; // ground pound or jump has finished
                }

                gravity.CanChangeGravityDirection = !overrideGravity;
            }
            else
            {
                airTimeTimer    += Time.deltaTime;
                transform.parent = null;
            }

            if (MoveDirection.magnitude > 0.1f)
            {
                Quaternion targetRotation = Quaternion.LookRotation(lookDirection, Vector3.up);
                graphics.localRotation = Quaternion.Slerp(graphics.localRotation, targetRotation, Time.deltaTime * rotationSpeed);
            }

            if (groundPoundRecoveryTimer > 0.0f)
            {
                groundPoundRecoveryTimer -= Time.deltaTime;
            }
        }
Пример #4
0
        /// <summary>
        /// Destories any planet that enters this ones trigger if and only if it is either destroyable and is not this planet itself.
        /// </summary>
        /// <param name="other"></param>
        protected void OnTriggerEnter(Collider other)
        {
            PlanetStats otherPlanet = other.GetComponentInParent <PlanetStats>();

            if (otherPlanet && otherPlanet.isDestroyable && (!myPlanet || myPlanet != otherPlanet))
            {
                PlayerStats[] players = otherPlanet.GetComponentsInChildren <PlayerStats>();

                foreach (PlayerStats player in players)
                {
                    player.transform.parent = null;
                }

                otherPlanet.gameObject.SetActive(false); // TODO: Disable and spawn destroyed mesh.
            }
        }
        /// <summary>
        /// Computes the target rotation direction based on where the hit planet was hit and from which direction. The target rotation direcition
        /// will be along the axis perpendicular to the hit normal that is furthest from the galaxy origin. The affected blocks will also be calculated
        /// based on the target rotation axis and the maximum check distance from the axis. After a rotation is calculate it is started in a
        /// coroutine if none of the affected blocks are currently being rotated.
        /// </summary>
        /// <param name="user">The character that caused the hit.</param>
        /// <param name="hitPlanet">The planet that was hit.</param>
        /// <param name="hitPoint">The world coordinates of the hit.</param>
        /// <param name="hitNormal">The world normal of the hit.</param>
        private void Rotate(PlayerStats stats, PlanetStats hitPlanet, Vector3 hitPoint, Vector3 hitNormal)
        {
            Vector3 galaxyLocalHit    = transform.InverseTransformPoint(hitPoint);
            Vector3 galaxyLocalNormal = transform.InverseTransformDirection(hitNormal);

            Vector3 columnRowOffset  = Vector3.zero;
            Vector3 overLapSize      = Vector3.zero;
            bool    positiveRotation = true;

            // if X greatest, rotate based on Y and Z
            if (Mathf.Abs(galaxyLocalNormal.x) > Mathf.Abs(galaxyLocalNormal.y) && Mathf.Abs(galaxyLocalNormal.x) > Mathf.Abs(galaxyLocalNormal.z))
            {
                if (Mathf.Abs(galaxyLocalHit.y) > Mathf.Abs(galaxyLocalHit.z)) // rotate on the Z axis
                {
                    overLapSize     = new Vector3(maxDistanceFromAxis, maxDistanceFromAxis, 0.1f);
                    columnRowOffset = new Vector3(0.0f, 0.0f, galaxyLocalHit.z);
                }
                else // rotate on the Y axis
                {
                    overLapSize     = new Vector3(maxDistanceFromAxis, 0.1f, maxDistanceFromAxis);
                    columnRowOffset = new Vector3(0.0f, galaxyLocalHit.y, 0.0f);
                }
            }
            // if Y greatest, rotate based on X and Z
            else if (Mathf.Abs(galaxyLocalNormal.y) > Mathf.Abs(galaxyLocalNormal.z))
            {
                if (Mathf.Abs(galaxyLocalHit.z) > Mathf.Abs(galaxyLocalHit.x)) // rotate on the X axis
                {
                    overLapSize     = new Vector3(0.1f, maxDistanceFromAxis, maxDistanceFromAxis);
                    columnRowOffset = new Vector3(galaxyLocalHit.x, 0.0f, 0.0f);
                }
                else // rotate on the Z axis
                {
                    overLapSize     = new Vector3(maxDistanceFromAxis, maxDistanceFromAxis, 0.1f);
                    columnRowOffset = new Vector3(0.0f, 0.0f, galaxyLocalHit.z);
                }
            }
            // if Z greatest, rotate based on X and Y
            else
            {
                if (Mathf.Abs(galaxyLocalHit.x) > Mathf.Abs(galaxyLocalHit.y)) // rotate on the y axis
                {
                    overLapSize     = new Vector3(maxDistanceFromAxis, 0.1f, maxDistanceFromAxis);
                    columnRowOffset = new Vector3(0.0f, galaxyLocalHit.y, 0.0f);
                }
                else // rotate on the X axis
                {
                    overLapSize     = new Vector3(0.1f, maxDistanceFromAxis, maxDistanceFromAxis);
                    columnRowOffset = new Vector3(galaxyLocalHit.x, 0.0f, 0.0f);
                }
            }

            Vector3 rotationAxis = transform.TransformDirection(columnRowOffset.normalized);

            columnRowOffset = transform.rotation * columnRowOffset;

            Vector3 playerDirection = hitPoint - transform.position;

            positiveRotation = Vector3.Dot(Vector3.Cross(hitNormal, playerDirection), rotationAxis) > 0;

            Vector3 absDifference = new Vector3(Mathf.Abs(currentRotationAxis.x) - Mathf.Abs(rotationAxis.x),
                                                Mathf.Abs(currentRotationAxis.y) - Mathf.Abs(rotationAxis.y),
                                                Mathf.Abs(currentRotationAxis.z) - Mathf.Abs(rotationAxis.z));

            if (activeRotations == 0 || 0.01f > absDifference.magnitude)
            {
                currentRotationAxis = rotationAxis;
                StartCoroutine(RotateCluster(columnRowOffset, overLapSize, positiveRotation));
            }
        }
 /// <summary>
 /// Begins the rotation logic.
 /// </summary>
 /// <param name="user">The character that caused the hit.</param>
 /// <param name="hitPlanet">The planet that was hit.</param>
 /// <param name="hitPoint">The world coordinates of the hit.</param>
 /// <param name="hitNormal">The world normal of the hit.</param>
 public void OnHit(PlayerStats stats, PlanetStats hitPlanet, Vector3 hitPoint, Vector3 hitNormal)
 {
     Rotate(stats, hitPlanet, hitPoint, hitNormal);
 }
        /// <summary>
        /// Rotates along the column row offset direction in either the positive or negative direction. The rotation will be canceled
        /// if any of the affected planets (determined by overlap size and column row offset) are currently in motion.
        /// </summary>
        /// <param name="columnRowOffset">Rotation axis multiplied by the distance on the axis of the hit point.</param>
        /// <param name="overlapSize">The distance used to check for affected planets.</param>
        /// <param name="positiveRotation">True if we should rotate in the positive direction.</param>
        /// <returns>Returns a single frame delay during the rotation effects.</returns>
        private IEnumerator RotateCluster(Vector3 columnRowOffset, Vector3 overlapSize, bool positiveRotation)
        {
            Collider[]         affectedPlanetColliders = Physics.OverlapBox(transform.position + columnRowOffset, overlapSize / 2.0f, transform.rotation, groundMask, QueryTriggerInteraction.Ignore);
            List <PlanetStats> affectedPlanets         = new List <PlanetStats>();
            List <int>         friendGroupIds          = new List <int>();

            friendGroupIds.Add(myStats.PhysicsGroupId);
            Vector3 cachedRotationAxis = currentRotationAxis;

            foreach (GalaxyStats friend in friendGroups)
            {
                friendGroupIds.Add(friend.PhysicsGroupId);
            }

            // verify can rotate
            foreach (Collider planetCollider in affectedPlanetColliders)
            {
                PlanetStats planet = planetCollider.GetComponentInParent <PlanetStats>();
                if (planet != null && friendGroupIds.Contains(planet.PhysicsGroupId))
                {
                    if (!affectedPlanets.Contains(planet))
                    {
                        affectedPlanets.Add(planet);
                    }

                    if (planet.IsInMotion)
                    {
                        yield break;
                    }
                }
            }

            // initialize rotation data
            activeRotations++;
            float remainingRotation = 90.0f;

            foreach (PlanetStats planet in affectedPlanets)
            {
                planet.transform.parent = transform;
                planet.IsInMotion       = true;
            }

            // rotate
            while (remainingRotation > 0.0f)
            {
                float rotationAmount = (positiveRotation ? 1 : -1) * Mathf.Min(Time.deltaTime * rotationSpeed, remainingRotation);

                foreach (PlanetStats planet in affectedPlanets)
                {
                    planet.transform.RotateAround(transform.position, cachedRotationAxis, rotationAmount);
                }

                remainingRotation -= Mathf.Abs(rotationAmount);
                yield return(new WaitForFixedUpdate());
            }

            // uninitialize rotation data
            foreach (PlanetStats planet in affectedPlanets)
            {
                planet.IsInMotion = false;
            }

            activeRotations--;
        }
 /// <summary>
 /// Beings the movement logic. A movement request could be canceled if this group is already moving.
 /// </summary>
 /// <param name="user">The character that caused the hit.</param>
 /// <param name="hitPlanet">The planet that was hit.</param>
 /// <param name="hitPoint">The world coordinates of the hit.</param>
 /// <param name="hitNormal">The world normal of the hit.</param>
 public void OnHit(PlayerStats stats, PlanetStats hitPlanet, Vector3 hitPoint, Vector3 hitNormal)
 {
     StartCoroutine(MoveAlongCurve());
 }
Пример #9
0
        /// <summary>
        /// Computes the target rotation direction based on where the hit planet was hit and from which direction. The target rotation direcition
        /// will be along the axis perpendicular to the hit normal that is furthest from the hit point. The affected blocks will also be calculated
        /// based on the target rotation axis and the maximum check distance from the axis. After a rotation is calculate it is started in a
        /// coroutine if none of the affected blocks are currently being rotated.
        /// </summary>
        /// <param name="user">The character that caused the hit.</param>
        /// <param name="hitPlanet">The planet that was hit.</param>
        /// <param name="hitPoint">The world coordinates of the hit.</param>
        /// <param name="hitNormal">The world normal of the hit.</param>
        private void Rotate(PlayerStats stats, PlanetStats hitPlanet, Vector3 hitPoint, Vector3 hitNormal)
        {
            Vector3 galaxyLocalHit    = transform.InverseTransformPoint(hitPoint);
            Vector3 galaxyLocalNormal = transform.InverseTransformDirection(hitNormal);
            Vector3 planetLocalHit    = transform.rotation * (hitPoint - hitPlanet.transform.position); //hitPlanet.transform.InverseTransformPoint(hitPoint);

            Vector3 columnRowOffset  = Vector3.zero;
            Vector3 overLapSize      = Vector3.zero;
            bool    positiveRotation = true;

            // if X greatest, rotate based on Y and Z
            if (Mathf.Abs(galaxyLocalNormal.x) > Mathf.Abs(galaxyLocalNormal.y) && Mathf.Abs(galaxyLocalNormal.x) > Mathf.Abs(galaxyLocalNormal.z))
            {
                bool rotateOnZ = false;

                if (Mathf.Abs(planetLocalHit.y) > Mathf.Abs(planetLocalHit.z))
                {
                    Vector3 testDirection = transform.TransformDirection(Mathf.Sign(planetLocalHit.y) * transform.up);
                    if (!Physics.Raycast(hitPlanet.transform.position, testDirection, hitPlanet.boundingBoxSize.y / 2.0f + 0.1f, groundMask, QueryTriggerInteraction.Ignore))
                    {
                        rotateOnZ = Mathf.Sign(galaxyLocalHit.y) == Mathf.Sign(planetLocalHit.y);
                    }
                    else
                    {
                        rotateOnZ = Mathf.Abs(galaxyLocalHit.z) < Mathf.Abs(galaxyLocalHit.y);
                    }
                }
                else
                {
                    Vector3 testDirection = transform.TransformDirection(Mathf.Sign(planetLocalHit.z) * Vector3.forward);
                    if (!Physics.Raycast(hitPlanet.transform.position, testDirection, hitPlanet.boundingBoxSize.z / 2.0f + 0.1f, groundMask, QueryTriggerInteraction.Ignore))
                    {
                        rotateOnZ = Mathf.Sign(galaxyLocalHit.z) != Mathf.Sign(planetLocalHit.z);
                    }
                    else
                    {
                        rotateOnZ = Mathf.Abs(galaxyLocalHit.y) > Mathf.Abs(galaxyLocalHit.z);
                    }
                }

                if (rotateOnZ) // rotate on the Z axis
                {
                    overLapSize     = new Vector3(maxDistanceFromAxis, maxDistanceFromAxis, 0.1f);
                    columnRowOffset = new Vector3(0.0f, 0.0f, galaxyLocalHit.z);
                }
                else // rotate on the Y axis
                {
                    overLapSize     = new Vector3(maxDistanceFromAxis, 0.1f, maxDistanceFromAxis);
                    columnRowOffset = new Vector3(0.0f, galaxyLocalHit.y, 0.0f);
                }
            }
            // if Y greatest, rotate based on X and Z
            else if (Mathf.Abs(galaxyLocalNormal.y) > Mathf.Abs(galaxyLocalNormal.z))
            {
                bool rotateOnX = false;

                if (Mathf.Abs(planetLocalHit.z) > Mathf.Abs(planetLocalHit.x))
                {
                    Vector3 testDirection = transform.TransformDirection(Mathf.Sign(planetLocalHit.z) * Vector3.forward);
                    if (!Physics.Raycast(hitPlanet.transform.position, testDirection, hitPlanet.boundingBoxSize.z / 2.0f + 0.1f, groundMask, QueryTriggerInteraction.Ignore))
                    {
                        rotateOnX = Mathf.Sign(galaxyLocalHit.z) == Mathf.Sign(planetLocalHit.z);
                    }
                    else
                    {
                        rotateOnX = Mathf.Abs(galaxyLocalHit.x) < Mathf.Abs(galaxyLocalHit.z);
                    }
                }
                else
                {
                    Vector3 testDirection = transform.TransformDirection(Mathf.Sign(planetLocalHit.x) * Vector3.right);
                    if (!Physics.Raycast(hitPlanet.transform.position, testDirection, hitPlanet.boundingBoxSize.x / 2.0f + 0.1f, groundMask, QueryTriggerInteraction.Ignore))
                    {
                        rotateOnX = Mathf.Sign(galaxyLocalHit.x) != Mathf.Sign(planetLocalHit.x);
                    }
                    else
                    {
                        rotateOnX = Mathf.Abs(galaxyLocalHit.z) > Mathf.Abs(galaxyLocalHit.x);
                    }
                }

                if (rotateOnX) // rotate on X axis
                {
                    overLapSize     = new Vector3(0.1f, maxDistanceFromAxis, maxDistanceFromAxis);
                    columnRowOffset = new Vector3(galaxyLocalHit.x, 0.0f, 0.0f);
                }
                else // rotate on Z axis
                {
                    overLapSize     = new Vector3(maxDistanceFromAxis, maxDistanceFromAxis, 0.1f);
                    columnRowOffset = new Vector3(0.0f, 0.0f, galaxyLocalHit.z);
                }
            }
            // if Z greatest, rotate based on X and Y
            else
            {
                bool rotateOnY = false;

                if (Mathf.Abs(planetLocalHit.x) > Mathf.Abs(planetLocalHit.y))
                {
                    Vector3 testDirection = transform.TransformDirection(Mathf.Sign(planetLocalHit.x) * Vector3.right);
                    if (!Physics.Raycast(hitPlanet.transform.position, testDirection, hitPlanet.boundingBoxSize.x / 2.0f + 0.1f, groundMask, QueryTriggerInteraction.Ignore))
                    {
                        rotateOnY = Mathf.Sign(galaxyLocalHit.x) == Mathf.Sign(planetLocalHit.x);
                    }
                    else
                    {
                        rotateOnY = Mathf.Abs(galaxyLocalHit.y) < Mathf.Abs(galaxyLocalHit.x);
                    }
                }
                else
                {
                    Vector3 testDirection = transform.TransformDirection(Mathf.Sign(planetLocalHit.y) * Vector3.up);
                    if (!Physics.Raycast(hitPlanet.transform.position, testDirection, hitPlanet.boundingBoxSize.y / 2.0f + 0.1f, groundMask, QueryTriggerInteraction.Ignore))
                    {
                        rotateOnY = Mathf.Sign(galaxyLocalHit.y) != Mathf.Sign(planetLocalHit.y);
                    }
                    else
                    {
                        rotateOnY = Mathf.Abs(galaxyLocalHit.x) > Mathf.Abs(galaxyLocalHit.y);
                    }
                }

                if (rotateOnY) // rotate on the y axis
                {
                    overLapSize     = new Vector3(maxDistanceFromAxis, 0.1f, maxDistanceFromAxis);
                    columnRowOffset = new Vector3(0.0f, galaxyLocalHit.y, 0.0f);
                }
                else // rotate on the X axis
                {
                    overLapSize     = new Vector3(0.1f, maxDistanceFromAxis, maxDistanceFromAxis);
                    columnRowOffset = new Vector3(galaxyLocalHit.x, 0.0f, 0.0f);
                }
            }

            Vector3 rotationAxis = transform.TransformDirection(columnRowOffset.normalized);

            columnRowOffset = transform.rotation * columnRowOffset;

            Vector3 playerDirection = hitPoint - transform.position;

            positiveRotation = Vector3.Dot(Vector3.Cross(hitNormal, playerDirection), rotationAxis) > 0;

            Vector3 absDifference = new Vector3(Mathf.Abs(currentRotationAxis.x) - Mathf.Abs(rotationAxis.x),
                                                Mathf.Abs(currentRotationAxis.y) - Mathf.Abs(rotationAxis.y),
                                                Mathf.Abs(currentRotationAxis.z) - Mathf.Abs(rotationAxis.z));

            if (activeRotations == 0 || 0.01f > absDifference.magnitude)
            {
                currentRotationAxis = rotationAxis;
                StartCoroutine(RotateCluster(columnRowOffset, overLapSize, positiveRotation));
            }
        }
Пример #10
0
        /// <summary>
        /// Begins the rotation logic.
        /// </summary>
        /// <param name="user">The character that caused the hit.</param>
        /// <param name="hitPlanet">The planet that was hit.</param>
        /// <param name="hitPoint">The world coordinates of the hit.</param>
        /// <param name="hitNormal">The world normal of the hit.</param>
        public void OnHit(PlayerStats user, PlanetStats hitPlanet, Vector3 hitPoint, Vector3 hitNormal)
        {
            Vector3 galaxyHitPoint = hitPoint - transform.position;
            Vector3 planetHitPoint = hitPoint - hitPlanet.transform.position;

            // 1.) Find the normal axis
            float distUp      = Vector3.Project(hitNormal, transform.up).magnitude;
            float distForward = Vector3.Project(hitNormal, transform.forward).magnitude;
            float distRight   = Vector3.Project(hitNormal, transform.right).magnitude;

            Vector3 normalAxis;
            Vector3 closestRotationAxis;
            Vector3 furthestRotationAxis;
            Vector3 rotationAxis;
            Vector3 unusedRotationAxis; //

            if (distUp > distForward && distUp > distRight)
            {
                normalAxis           = transform.up;
                closestRotationAxis  = transform.forward; // default, may not be correct
                furthestRotationAxis = transform.right;   // default, may not be correct
            }
            else if (distForward > distRight)
            {
                normalAxis           = transform.forward;
                closestRotationAxis  = transform.up;    // default, may not be correct
                furthestRotationAxis = transform.right; // default, may not be correct
            }
            else
            {
                normalAxis           = transform.right;
                closestRotationAxis  = transform.forward; // default, may not be correct
                furthestRotationAxis = transform.up;      // default, may not be correct
            }

            // 2.) Find which axis we are most likely to rotate around (the furthest) and which one we are least likely to rotate around (closest)
            if (Vector3.Project(galaxyHitPoint, furthestRotationAxis).magnitude >
                Vector3.Project(galaxyHitPoint, closestRotationAxis).magnitude) // projecting on to the opposite axis
            {
                Vector3 temp = closestRotationAxis;
                closestRotationAxis  = furthestRotationAxis;
                furthestRotationAxis = temp;
            }

            // 3.) Determine the true rotation axis. If there is no planet next to this one in the furthest rotation axis direction (i.e. we are on the edge),
            //     Then we rotate around the closest axis if an only if we are closer to the closest rotation axis than the furthest rotation axis. Otherwise,
            //     we rotate around the furthest axis.
            RaycastHit hitTest;
            bool       isPositive = Vector3.Angle(furthestRotationAxis, Vector3.ProjectOnPlane(planetHitPoint, normalAxis)) < 90.0f;

            if (!Physics.Raycast(hitPlanet.transform.position, isPositive ? furthestRotationAxis : -furthestRotationAxis,
                                 out hitTest, 26.0f, groundMask, QueryTriggerInteraction.Ignore) &&
                Vector3.Project(planetHitPoint, closestRotationAxis).magnitude < Vector3.Project(planetHitPoint, furthestRotationAxis).magnitude)
            {
                rotationAxis       = closestRotationAxis;
                unusedRotationAxis = furthestRotationAxis;
            }
            else
            {
                rotationAxis       = furthestRotationAxis;
                unusedRotationAxis = closestRotationAxis;
            }

            // 4.) Determine if we should rotate in a positive or negative direction.
            isPositive = AngleDirection(rotationAxis, galaxyHitPoint, normalAxis) < 1.0f;

            // 5.) Determine how to find the affected planets.
            Vector3 overlapSize    = maxDistanceFromAxis * (Quaternion.Inverse(transform.rotation) * unusedRotationAxis + Quaternion.Inverse(transform.rotation) * normalAxis).normalized;
            Vector3 rotationCenter = transform.position + Vector3.Project(galaxyHitPoint, rotationAxis);

            // 6.) Rotate if we are not currently rotating or if we are rotating on the same axis (positive and negative doesn't matter)
            Vector3 absDifference = new Vector3(Mathf.Abs(currentRotationAxis.x) - Mathf.Abs(rotationAxis.x),
                                                Mathf.Abs(currentRotationAxis.y) - Mathf.Abs(rotationAxis.y),
                                                Mathf.Abs(currentRotationAxis.z) - Mathf.Abs(rotationAxis.z));

            if (activeRotations == 0 || 0.01f > absDifference.magnitude)
            {
                currentRotationAxis = rotationAxis;
                StartCoroutine(RotateCluster(rotationCenter, overlapSize, isPositive));
            }
        }