Esempio n. 1
0
    /// <summary>
    /// Deprecated! Use GunGeneralStats.Shoot() instead.
    /// </summary>
    /// <param name="prefab"></param>
    /// <param name="count"></param>
    /// <param name="spread"></param>
    /// <param name="range"></param>
    /// <param name="origin"></param>
    /// <param name="aimOrigin"></param>
    /// <param name="forward"></param>
    /// <param name="up"></param>
    /// <param name="muzzle"></param>
    public static void ShootProjectile(Projectile prefab, int count, float spread, float range, Character origin, Vector3 aimOrigin, Vector3 forward, Vector3 up, Vector3 muzzle)
    {
        for (int i = 0; i < count; i++)
        {
            #region Calculate initial variables
            // Declare RaycastHit
            RaycastHit targetFound;
            // Declare direction in which to fire projectile
            Vector3 direction = new Vector3(Random.Range(-spread, spread), Random.Range(-spread, spread), Random.Range(-spread, spread));
            direction = Misc.AngledDirection(direction, forward, up);
            #endregion

            #region Launch raycast to determine where to shoot projectile
            if (Physics.Raycast(aimOrigin, direction, out targetFound, range, prefab.hitDetection)) // To reduce the amount of superfluous variables, I re-used the 'target' Vector3 in the same function as it is now unneeded for its original purpose
            {
                direction = targetFound.point;
            }
            else
            {
                direction = aimOrigin + direction.normalized * range;
            }
            #endregion

            #region Instantiate projectile
            Projectile p = prefab;

            p.origin = origin;

            // Checks that the position 'processedDirection' is actually further away than the muzzle and that the bullets will not travel in the complete wrong direction
            if (Vector3.Angle(forward, direction - muzzle) < 90)
            {
                Object.Instantiate(p, muzzle, Quaternion.LookRotation(direction - muzzle, up));
            }
            else
            {
                // Otherwise, the gun barrel is probably clipping into a wall. Directly spawn the projectiles at the appropriate hit points.
                Object.Instantiate(p, direction, Quaternion.LookRotation(direction - aimOrigin, up));
                p.OnHit(targetFound);
            }
            #endregion

            Debug.DrawLine(aimOrigin, direction, Color.magenta, 1f);
        }
    }
Esempio n. 2
0
    public void Shoot(Character origin, Vector3 aimOrigin, Vector3 forward, Vector3 up)
    {
        for (int i = 0; i < projectileCount; i++)
        {
            RaycastHit targetFound; // Declare RaycastHit
            // Declare direction in which to fire projectile
            Vector3 direction = new Vector3(Random.Range(-projectileSpread, projectileSpread), Random.Range(-projectileSpread, projectileSpread), Random.Range(-projectileSpread, projectileSpread));
            direction = Misc.AngledDirection(direction, forward, up);
            // To reduce the amount of superfluous variables, I re-used the 'target' Vector3 in the same function as it is now unneeded for its original purpose
            if (Physics.Raycast(aimOrigin, direction, out targetFound, range, projectilePrefab.hitDetection))
            {
                // If the raycast hits, store the point where it hit.
                direction = targetFound.point;
                Debug.DrawLine(aimOrigin, direction, Color.green, 2f);
            }
            else
            {
                // If the raycast didn't hit, store the point at the raycast's maximum reach.
                direction = aimOrigin + direction.normalized * range;
            }

            Projectile p = Instantiate(projectilePrefab);
            p.gameObject.SetActive(true);
            p.origin = origin;

            // Checks that the position 'processedDirection' is actually further away than the muzzle and that the bullets will not travel in the complete wrong direction
            if (Vector3.Angle(forward, direction - muzzle.position) < 90)
            {
                p.transform.position = muzzle.position;
                p.transform.rotation = Quaternion.LookRotation(direction - muzzle.position, up);
            }
            else
            {
                // Otherwise, the gun barrel is probably clipping into a wall. Directly spawn the projectiles at the appropriate hit points.
                p.transform.position = direction;
                p.transform.rotation = Quaternion.LookRotation(direction - aimOrigin, up);
                p.OnHit(targetFound);
            }
        }

        effectsOnFire.Invoke();
    }
    void GenerateCollisionMesh()
    {
        float attackWidthFromCentre = swingWidth / 2;
        float segmentAngleWidth     = swingLengthInDegrees / numberOfSegmentsForDetection;

        Vector3 topBack     = Vector3.forward * minRange;
        Vector3 topFront    = Vector3.forward * maxRange;
        Vector3 bottomBack  = Misc.AngledDirection(new Vector3(-segmentAngleWidth, 0, 0), Vector3.forward, Vector3.up).normalized *minRange;
        Vector3 bottomFront = Misc.AngledDirection(new Vector3(-segmentAngleWidth, 0, 0), Vector3.forward, Vector3.up).normalized *maxRange;

        Vector3 topBackLeft      = topBack + Vector3.left * attackWidthFromCentre;
        Vector3 topBackRight     = topBack + Vector3.right * attackWidthFromCentre;
        Vector3 topFrontLeft     = topFront + Vector3.left * attackWidthFromCentre;
        Vector3 topFrontRight    = topFront + Vector3.right * attackWidthFromCentre;
        Vector3 bottomBackLeft   = bottomBack + Vector3.left * attackWidthFromCentre;
        Vector3 bottomBackRight  = bottomBack + Vector3.right * attackWidthFromCentre;
        Vector3 bottomFrontLeft  = bottomFront + Vector3.left * attackWidthFromCentre;
        Vector3 bottomFrontRight = bottomFront + Vector3.right * attackWidthFromCentre;

        Vector3[] vertices = new Vector3[]
        {
            // Back
            topBackLeft,
            topBackRight,
            bottomBackLeft,
            bottomBackRight,
            // Front
            topFrontRight,
            topFrontLeft,
            bottomFrontRight,
            bottomFrontLeft,
            // Top
            topFrontLeft,
            topFrontRight,
            topBackLeft,
            topBackRight,
            // Bottom
            bottomFrontLeft,
            bottomFrontRight,
            bottomBackLeft,
            bottomBackRight,
            // Left
            topFrontLeft,
            topBackLeft,
            bottomFrontLeft,
            bottomBackLeft,
            // Right
            topBackRight,
            topFrontRight,
            bottomBackRight,
            bottomFrontRight,
        };
        int[] triangles = new int[]
        {
            // Back
            0, 2, 1, 2, 3, 1,
            // Front
            4, 6, 5, 6, 7, 5,
            // Top
            8, 10, 9, 10, 11, 9,
            // Bottom
            12, 13, 14, 14, 13, 15,
            // Left
            16, 18, 17, 18, 19, 17,
            // Right
            20, 22, 21, 22, 23, 21

            /*
             * // Back
             * 0,1,2,2,1,3,
             * // Front
             * 4,5,6,6,5,7,
             * // Top
             * 8,9,10,10,9,11,
             * // Bottom
             * 12,13,14,14,13,15,
             * // Left
             * 16,17,18,18,17,19,
             * // Right
             * 20,21,22,22,21,23
             */
        };

        Mesh hitDetectionMesh = new Mesh();

        hitDetectionMesh.vertices = vertices;
        //hitDetectionMesh.uv = uv;
        hitDetectionMesh.triangles = triangles;

        GameObject meshObject = new GameObject("Hit Detection Mesh", typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider));

        meshObject.GetComponent <MeshFilter>().mesh         = hitDetectionMesh;
        meshObject.GetComponent <MeshCollider>().sharedMesh = hitDetectionMesh;
        meshObject.GetComponent <MeshRenderer>().material   = meshMaterial;

        meshObject.transform.SetParent(transform);

        meshObject.transform.localPosition = Vector3.zero;
        meshObject.transform.localRotation = Quaternion.identity;
    }
    void GenerateSquare()
    {
        /*
         * Vector3[] vertices = new Vector3[]
         * {
         *  new Vector3(0, 1, 0),
         *  new Vector3(1, 1, 0),
         *  new Vector3(0, 0, 0),
         *  new Vector3(1, 0, 0)
         * };
         *
         * Vector2[] uv = new Vector2[]
         * {
         *  new Vector2(0, 1),
         *  new Vector2(1, 1),
         *  new Vector2(0, 0),
         *  new Vector2(1, 0)
         * };
         *
         * int[] triangles = new int[]
         * {
         *  0,
         *  1,
         *  2,
         *  2,
         *  1,
         *  3
         * };
         */

        /*
         * Vector3[] vertices = new Vector3[]
         * {
         *  new Vector3(0, 1, 0),
         *  new Vector3(1, 1, 0),
         *  new Vector3(0, 0, 0),
         *  new Vector3(1, 0, 0),
         *  new Vector3(0, 1, 1),
         *  new Vector3(1, 1, 1),
         *  new Vector3(0, 0, 1),
         *  new Vector3(1, 0, 1)
         * };
         * Vector2[] uv = new Vector2[]
         * {
         *  new Vector2(0, 1),
         *  new Vector2(1, 1),
         *  new Vector2(0, 0),
         *  new Vector2(1, 0),
         *
         *  new Vector2(0, 1),
         *  new Vector2(1, 1),
         *  new Vector2(0, 0),
         *  new Vector2(1, 0),
         *
         *  new Vector2(0, 1),
         *  new Vector2(1, 1),
         *  new Vector2(0, 0),
         *  new Vector2(1, 0),
         *
         *  new Vector2(0, 1),
         *  new Vector2(1, 1),
         *  new Vector2(0, 0),
         *  new Vector2(1, 0),
         *
         *  new Vector2(0, 1),
         *  new Vector2(1, 1),
         *  new Vector2(0, 0),
         *  new Vector2(1, 0),
         *
         *  new Vector2(0, 1),
         *  new Vector2(1, 1),
         *  new Vector2(0, 0),
         *  new Vector2(1, 0)
         * };
         * int[] triangles = new int[]
         * {
         *  // Front
         *  0,
         *  1,
         *  2,
         *  2,
         *  1,
         *  3,
         *
         *  // Back
         *  6,
         *  5,
         *  8,
         *  8,
         *  5,
         *  7,
         *
         *  // Top
         *  0,
         *  5,
         *  6,
         *  6,
         *  1,
         *  0,
         *
         *  // Bottom
         *  2,
         *  3,
         *  7,
         *  7,
         *  3,
         *  8,
         *
         *  // Left
         *  5,
         *  0,
         *  7,
         *  7,
         *  0,
         *  2,
         *
         *  // Right
         *  1,
         *  6,
         *  3,
         *  3,
         *  6,
         *  8
         * };
         */

        float minRange = 2;
        float maxRange = 5;


        float attackWidthInDegrees  = 10;
        float attackLengthInDegrees = 75;
        float angle;
        float numberOfSegmentsForDetection = 10;


        float attackWidthFromCentre = attackWidthInDegrees / 2;
        float segmentAngleWidth     = attackLengthInDegrees / numberOfSegmentsForDetection;

        Vector3 topBack     = Vector3.forward * minRange;
        Vector3 topFront    = Vector3.forward * maxRange;
        Vector3 bottomBack  = Misc.AngledDirection(new Vector3(segmentAngleWidth, 0, 0), Vector3.forward, Vector3.up).normalized *minRange;
        Vector3 bottomFront = Misc.AngledDirection(new Vector3(segmentAngleWidth, 0, 0), Vector3.forward, Vector3.up).normalized *maxRange;

        /*
         * Vector3 topBackLeft = topBack + Vector3.left * attackWidthFromCentre;
         * Vector3 topBackRight = topBack + Vector3.right * attackWidthFromCentre;
         * Vector3 topFrontLeft = topFront + Vector3.left * attackWidthFromCentre;
         * Vector3 topFrontRight = topFront + Vector3.right * attackWidthFromCentre;
         * Vector3 bottomBackLeft = bottomBack + Vector3.left * attackWidthFromCentre;
         * Vector3 bottomBackRight = bottomBack + Vector3.right * attackWidthFromCentre;
         * Vector3 bottomFrontLeft = bottomFront + Vector3.left * attackWidthFromCentre;
         * Vector3 bottomFrontRight = bottomFront + Vector3.right * attackWidthFromCentre;
         */

        Vector3 topBackLeft      = new Vector3(-0.5f, 0.5f, -0.5f);
        Vector3 topBackRight     = new Vector3(0.5f, 0.5f, -0.5f);
        Vector3 topFrontLeft     = new Vector3(-0.5f, 0.5f, 0.5f);
        Vector3 topFrontRight    = new Vector3(0.5f, 0.5f, 0.5f);
        Vector3 bottomBackLeft   = new Vector3(-0.5f, -0.5f, -0.5f);
        Vector3 bottomBackRight  = new Vector3(0.5f, -0.5f, -0.5f);
        Vector3 bottomFrontLeft  = new Vector3(-0.5f, -0.5f, 0.5f);
        Vector3 bottomFrontRight = new Vector3(0.5f, -0.5f, 0.5f);

        Vector3[] vertices = new Vector3[]
        {
            // Back
            topBackLeft,
            topBackRight,
            bottomBackLeft,
            bottomBackRight,
            // Front
            topFrontRight,
            topFrontLeft,
            bottomFrontRight,
            bottomFrontLeft,
            // Top
            topFrontLeft,
            topFrontRight,
            topBackLeft,
            topBackRight,
            // Bottom
            bottomFrontLeft,
            bottomFrontRight,
            bottomBackLeft,
            bottomBackRight,
            // Left
            topFrontLeft,
            topBackLeft,
            bottomFrontLeft,
            bottomBackLeft,
            // Right
            topBackRight,
            topFrontRight,
            bottomBackRight,
            bottomFrontRight,
        };
        int[] triangles = new int[]
        {
            // Back
            0, 2, 1, 2, 3, 1,
            // Front
            4, 6, 5, 6, 7, 5,
            // Top
            8, 10, 9, 10, 11, 9,
            // Bottom
            12, 13, 14, 14, 13, 15,
            // Left
            16, 18, 17, 18, 19, 17,
            // Right
            20, 22, 21, 22, 23, 21

            /*
             * // Back
             * 0,1,2,2,1,3,
             * // Front
             * 4,5,6,6,5,7,
             * // Top
             * 8,9,10,10,9,11,
             * // Bottom
             * 12,13,14,14,13,15,
             * // Left
             * 16,17,18,18,17,19,
             * // Right
             * 20,21,22,22,21,23
             */
        };


        /*
         * // Figure out cube mesh data
         * Mesh cm = GameObject.CreatePrimitive(PrimitiveType.Cube).GetComponent<MeshFilter>().mesh;
         * Mesh cubeMesh = new Mesh();
         * cubeMesh.vertices = cm.vertices;
         * cubeMesh.triangles = cm.triangles;
         * string verts = "Vertices = ";
         * for (int i = 0; i < cubeMesh.vertices.Length; i++)
         * {
         *  verts += cubeMesh.vertices[i] + ", ";
         * }
         * Debug.Log(verts);
         * string tris = "Triangles = ";
         * for (int i = 0; i < cubeMesh.triangles.Length; i++)
         * {
         *  tris += cubeMesh.triangles[i] + ", ";
         * }
         * Debug.Log(tris);
         */


        Mesh hitDetectionMesh = new Mesh();

        hitDetectionMesh.vertices = vertices;
        //hitDetectionMesh.uv = uv;
        hitDetectionMesh.triangles = triangles;

        GameObject meshObject = new GameObject("Hit Detection Mesh", typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider));

        meshObject.GetComponent <MeshFilter>().mesh         = hitDetectionMesh;
        meshObject.GetComponent <MeshCollider>().sharedMesh = hitDetectionMesh;
        meshObject.GetComponent <MeshRenderer>().material   = meshMaterial;



        meshObject.transform.position = transform.position;
    }
Esempio n. 5
0
    public static bool LineOfSightCheckForVisionCone(Collider c, Vector3 origin, Vector3 forward, Vector3 worldUp, float angle, out RaycastHit checkInfo, float range, LayerMask viewable, float raycastSpacing = 0.2f)
    {
        //float debugTime = 0.5f;

        #region Create raycast grid data
        // Finds the largest of the bounds' 3 size axes and produces a value that always exceeds that distance, regardless of the shape and angle.
        float maxBoundsSize = Mathf.Max(Mathf.Max(c.bounds.size.x, c.bounds.size.y), c.bounds.size.z) * 2;

        Vector3 originUp    = Misc.PerpendicularUp(forward, worldUp);
        Vector3 originRight = Misc.PerpendicularRight(forward, worldUp);

        // Use Bounds.ClosestPoint four times, with points to the left, right, up and down of the bounding box (relative to the cone centre). Then use Vector3.Distance to calculate the distances and produce a rectangle of certain dimensions.
        Vector3 upPoint    = c.bounds.center + originUp * maxBoundsSize;
        Vector3 downPoint  = c.bounds.center + -originUp * maxBoundsSize;
        Vector3 leftPoint  = c.bounds.center + -originRight * maxBoundsSize;
        Vector3 rightPoint = c.bounds.center + originRight * maxBoundsSize;
        upPoint    = c.bounds.ClosestPoint(upPoint);
        downPoint  = c.bounds.ClosestPoint(downPoint);
        leftPoint  = c.bounds.ClosestPoint(leftPoint);
        rightPoint = c.bounds.ClosestPoint(rightPoint);

        // Produces dimensions for a rectangular area to sweep with raycasts
        float scanAreaY = Vector3.Distance(upPoint, downPoint);
        float scanAreaX = Vector3.Distance(leftPoint, rightPoint);

        // Figures out actual diameter of the area that needs to be covered
        float   distanceToCollider = Vector3.Distance(origin, c.bounds.center);
        Vector3 l = origin + Misc.AngledDirection(new Vector3(0, -angle, 0), forward, worldUp).normalized *distanceToCollider;
        Vector3 r = origin + Misc.AngledDirection(new Vector3(0, angle, 0), forward, worldUp).normalized *distanceToCollider;

        /*
         #region Debugging cone
         * Vector3 u = origin + Misc.AngledDirection(new Vector3(-angle, 0, 0), forward, worldUp).normalized * distanceToCollider;
         * Vector3 d = origin + Misc.AngledDirection(new Vector3(angle, 0, 0), forward, worldUp).normalized * distanceToCollider;
         * Vector3[] debugConePositions = new Vector3[]
         * {
         *  origin, l, c.bounds.center, r, origin, u, c.bounds.center, d, origin
         * };
         * Misc.DrawMultipleDebugLines(debugConePositions, Colours.darkGreen, debugTime);
         #endregion
         */
        // Diameter of cone at required distance
        float coneDiameterAtDistance = Vector3.Distance(l, r);
        // Minimum spacing between raycasts so that there is always one inside the cone
        float maxSpacingWhileCoveringDiameter = (Vector2.one * coneDiameterAtDistance).x;
        // If the maximum allowed spacing is smaller than raycastSpacing, use that instead.
        // If the original value is smaller, keep it to have more precise scans for bigger objects
        raycastSpacing = Mathf.Min(maxSpacingWhileCoveringDiameter * 0.75f, raycastSpacing);
        // If the collider is close to the origin, area to cover can be smaller than default raycast spacing
        // Therefore it's possible for no raycasts to hit
        // The 1.2f variable is just for extra padding

        // Divide the rectangle dimensions by the sphereCastDiameter to obtain the amount of spherecasts necessary to cover the area.
        int raycastArrayLength = Mathf.CeilToInt(scanAreaX / raycastSpacing);
        int raycastArrayHeight = Mathf.CeilToInt(scanAreaY / raycastSpacing);

        // Creates variables to determine how far apart to space the raycasts on each axis
        float spacingX = scanAreaX / raycastArrayLength;
        float spacingY = scanAreaY / raycastArrayHeight;

        // Creates axes along which to align the raycasts
        Vector3 raycastGridAxisX = (rightPoint - c.bounds.center).normalized;
        Vector3 raycastGridAxisY = (upPoint - c.bounds.center).normalized;

        /*
         * Vector3[] gridSquare = new Vector3[]
         * {
         *  c.bounds.center + (raycastGridAxisX * (spacingX * 0 - scanAreaX / 2)) + (raycastGridAxisY * (spacingY * 0 - scanAreaY / 2)),
         *  c.bounds.center + (raycastGridAxisX * (spacingX * 0 - scanAreaX / 2)) + (raycastGridAxisY * (spacingY * 1 - scanAreaY / 2)),
         *  c.bounds.center + (raycastGridAxisX * (spacingX * 1 - scanAreaX / 2)) + (raycastGridAxisY * (spacingY * 1 - scanAreaY / 2)),
         *  c.bounds.center + (raycastGridAxisX * (spacingX * 1 - scanAreaX / 2)) + (raycastGridAxisY * (spacingY * 0 - scanAreaY / 2))
         * };
         * Misc.DrawMultipleDebugLines(gridSquare, Color.yellow, debugTime, true);
         */
        #endregion



        #region Perform raycast command batch processing
        // Creates a list of Vector3 directions
        List <Vector3> directions = new List <Vector3>();
        // Cast an array of rays to 'sweep' the square for line of sight.
        for (int y = 0; y < raycastArrayHeight; y++)
        {
            for (int x = 0; x < raycastArrayLength; x++)
            {
                // Creates coordinates along the sweep area for the raycast. 0,0 would be the centre, so for each axis I am taking away a value equivalent to half of that axis dimension, so I can use the bottom-left corner as 0,0
                float distanceX = spacingX * x - scanAreaX / 2;
                float distanceY = spacingY * y - scanAreaY / 2;

                // Starts with c.bounds.centre, then adds direction values multiplied by the appropriate distance value for each axis, to create the point that you want the raycast to hit.
                Vector3 raycastAimPoint = c.bounds.center + (raycastGridAxisX * distanceX) + (raycastGridAxisY * distanceY);

                // From that point, it creates a direction value for the raycast to aim in.
                Vector3 raycastAimDirection = raycastAimPoint - origin;

                // Checks if the raycast is still detecting a point that is actually inside the cone
                if (Vector3.Angle(forward, raycastAimDirection) < angle)
                {
                    //Debug.DrawLine(origin, raycastAimPoint, Color.white, debugTime);

                    directions.Add(raycastAimDirection);
                }
                else
                {
                    //Debug.DrawLine(origin, raycastAimPoint, Colours.scarlet, debugTime);
                }
            }
        }

        // Create RaycastCommand
        var results  = new NativeArray <RaycastHit>(directions.Count, Allocator.TempJob);
        var commands = new NativeArray <RaycastCommand>(directions.Count, Allocator.TempJob);

        // Assign directions to each RaycastCommand
        for (int i = 0; i < commands.Length; i++)
        {
            commands[i] = new RaycastCommand(origin, directions[i], range, viewable);
        }

        // Schedule the batch of raycasts, and wait for the batch processing job to complete
        JobHandle handle = RaycastCommand.ScheduleBatch(commands, results, 1);
        handle.Complete();

        // Converts the NativeArray of results to a regular array
        RaycastHit[] hits = results.ToArray();
        //Debug.Log("Results length = " + hits.Length);

        // Dispose the buffers
        results.Dispose();
        commands.Dispose();
        #endregion

        #region Evaluate results and determine true or false

        // Look through each result in the list of raycast hits
        for (int i = 0; i < hits.Length; i++)
        {
            Debug.DrawLine(origin, hits[i].point, Colours.turquoise, 10);
            // If a RaycastHit is found that matches the collider being checked for, store it and return true
            if (hits[i].collider == c)
            {
                checkInfo = hits[i];
                return(true);
            }
        }

        // In the event that no results were found, tokenly assign a redundant RaycastHit so the function completes properly
        if (Physics.Raycast(origin, forward, out checkInfo, range, viewable))
        {
        }

        return(false);

        #endregion
    }