Added grenade blast radius visual

I added an animated blast radius for grenade, a line path for the throw, and icons for inventory switching and action selection.

6 Likes

Good job! That looks really polished.

1 Like

I LOVE the line/ghost.

Can i ask what you are using to actually draw the line? I can picture the pathfinding being used to calculate where to draw it, but are you using a prefab of something to draw the line in play mode?

1 Like

You can use the line renderer to draw lines. What Jonathan has done here is really nice and would probably not be the first thing you achieve, but the line renderer is quite powerful and with a but of practice you’d get there

1 Like

This is the functional?

Yup, that’s the one.

I have used the line renderer in many different ways. It is quite versatile.

Perhaps @Jonathan_Borchardt will give more details on exactly what he did to achieve his effect.

1 Like

I’ve actually never seen/used line renderer. So much of this is ‘you don’t know what you don’t know’, got a direction to play with it now.

Thanks very much.

1 Like

Correct. I use the line renderer for both the ghost line and the projectile arc. If you want some code, I can post.

1 Like

For the ghost line, I do this on mousemove:

                        List<GridPosition> path =
                            Pathfinding
                                .Instance
                                .FindPath(selectedUnit.GetGridPosition(),
                                mouseGridPosition,
                                out int pathLength);
                        if (path == null || path.Count() < 2)
                        {
                            return;
                        }

                        CopyUnitAsGhostIfNew (selectedUnit);
                        PositionGhost(path[path.Count() - 1].ToVector3(),
                        path[path.Count() - 2].ToVector3());
                        pathLineRenderer.positionCount = path.Count();
                        pathLineRenderer
                            .SetPositions(path
                                .Select(p =>
                                {
                                    var v = p.ToVector3();
                                    v.y += 0.1f;
                                    return v;
                                })
                                .ToArray());

where pathLineRenderer is a serialized reference to a styled linerederer.

1 Like

And for grenade arc:

        public void PositionGrenadeSphere(
            Vector3 start,
            Vector3 end,
            float size
        )
        {
            isActive = true;
            grenadeSphere.gameObject.SetActive(true);
            grenadeSphere.transform.position = new Vector3(end.x, 0.25f, end.z);
            grenadeSphere.localScale =
                new Vector3(size * 2, size * 2, size * 2);

            var pathPoints = new List<Vector3>();
            var pointCount = 20f;
            var endToStart = (end - start);
            var dist = endToStart.magnitude + 0.5f;
            var piece = endToStart / pointCount;
            float maxHeight =
                dist /
                (1.93f + (-0.0714f * dist) + 0.0204f * Mathf.Pow(dist, 2));
            for (int i = 0; i <= pointCount; i++)
            {
                var inner = start + piece * i;

                // simple math for an arc that goes from 1 to 1 on x and y, starts a bit above the ground
                inner.y =
                    Explosion
                        .Parabla(maxHeight, i / pointCount, 1f / maxHeight);
                pathPoints.Add (inner);
            }

            grenadeLineRenderer.positionCount = pathPoints.Count;
            grenadeLineRenderer.SetPositions(pathPoints.ToArray());
        }

with:

    public static float
        Parabla(
            float maxHeight,
            //0-1 over time... this is x
            float percentTraveled,
            // allows starting a bit higher... 0.2f is waist high
            float startHeightFactor = 0f
        )
        {
            return maxHeight *
            (
            -Mathf
                .Pow((
                (percentTraveled * (2f - startHeightFactor)) -
                (1f - startHeightFactor)
                ),
                2) +
            1
            );
        }

Where grenadesphere is a gameobject that rotates its texture.

1 Like

The grenade ghost looks awesome, great job!

Not to ask you for reveal ALL your secrets, but how in the world do you get the outline around your range, is that also with the line renderer?

Are you doing it mathematically in the code?

i use line renderer to draw an arc using math to show where the grenade will fly.
i use a sphere to show the blast radius
i use the tile boundary as a game object to show the bounds ow where i could throw.

Is tile boundary a unity tool?

Like the outline around the edge of your walkable/throwable range?

ah…
the tile game object has 4 hidden sub objects that get turned on or off depending on if the tile next to it is inside or outside the range…

   foreach (var gridPosition in boundsGridPositionList)
            {
                // adding +1's to shift to middle of array to deal with out of bounds
                bool showTop =
                    gridPositionArray[gridPosition.x + 1, gridPosition.z + 2] ==
                    GridPositionContent.Empty;
                bool showRight =
                    gridPositionArray[gridPosition.x + 2, gridPosition.z + 1] ==
                    GridPositionContent.Empty;
                bool showBottom =
                    gridPositionArray[gridPosition.x + 1, gridPosition.z] ==
                    GridPositionContent.Empty;
                bool showLeft =
                    gridPositionArray[gridPosition.x, gridPosition.z + 1] ==
                    GridPositionContent.Empty;

                bool isTarget =
                    gridPositionArray[gridPosition.x + 1, gridPosition.z + 1] ==
                    GridPositionContent.Target;

                gridSystemVisualSingleArray
                    .value[gridPosition.x,
                    gridPosition.z]
                    .Show(isTarget,
                    targetMaterial,
                    targetColor,
                    boundsMaterial,
                    boundsColor,
                    showTop,
                    showRight,
                    showBottom,
                    showLeft);
            }

where show and hide are on sub objects of the tile object

public void Show(
            bool isTarget,
            Material targetMaterial,
            Color targetColor,
            Material boundsMaterial,
            Color boundsColor,
            bool showTop = false,
            bool showRight = false,
            bool showBottom = false,
            bool showLeft = false
        )
        {
            if (isTarget)
            {
                if (targetMaterial)
                {
                    meshRenderer.material = targetMaterial;
                }

                meshRenderer.material.SetColor("_BaseColor", targetColor);
                /*var targetParticleSystemMain = targetParticleSystem.main;
                targetParticleSystemMain.startColor = targetColor;
                targetParticleSystem.Play();
                targetParticleSystem
                    .GetComponent<ParticleSystemRenderer>()
                    .renderMode = ParticleSystemRenderMode.Billboard;*/
            }
            else
            {
                if (boundsMaterial)
                {
                    meshRenderer.material = boundsMaterial;
                }
                meshRenderer
                    .material
                    .SetColor("_BaseColor", boundsColor / 1.9f);
            }
            meshRenderer.enabled = true;

            this.boundsColor = boundsColor;
            top.gameObject.SetActive (showTop);
            right.gameObject.SetActive (showRight);
            bottom.gameObject.SetActive (showBottom);
            left.gameObject.SetActive (showLeft);
        }

        public void Hide()
        {
            meshRenderer.enabled = false;
            targetParticleSystem.Stop();
            targetParticleSystem
                .GetComponent<ParticleSystemRenderer>()
                .renderMode = ParticleSystemRenderMode.None;
            top.gameObject.SetActive(false);
            right.gameObject.SetActive(false);
            bottom.gameObject.SetActive(false);
            left.gameObject.SetActive(false);
        }
    }

but there are many ways you can do this

Privacy & Terms