skip to Main Content

My question is as titled. I’m playing around with unity to get back into it to return to school, and I’ve decided to make a little risk type game.

Basically I have my map, and when I click one of my territories (which I have a polygon collider around, with an on click method attached that currently just toggles a small box sprite to test) I’d like to highlight the edge around the territory I’ve selected (the edge of witch the polygon collider covers). So I’m wondering if its possible to make a highlight effect based around the collider, or something like that.

My current plan is to just Photoshop the edges of all the territories into sprites and toggle them like the test sprite in order to create the effect, but if I can do it in a much simpler time effective way that would be great!

enter image description here

Thanks for the help if you can, and ask if you need more info!

4

Answers


  1. While this wont outline the collider (unless it’s a mesh collider), this shader will outline the mesh with a chosen color:

    Shader "Custom/OutlineDiffuseShader"
    {
        Properties{
            _Color("Main Color", Color) = (.5,.5,.5,1)
            _OutlineColor("Outline Color", Color) = (0,0,0,1)
            _Outline("Outline width", Range(.002, 0.03)) = .002
            _MainTex("Base (RGB)", 2D) = "white" { }
        }
    
            CGINCLUDE
    #include "UnityCG.cginc"
    
            struct appdata {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
        };
    
        struct v2f {
            float4 pos : POSITION;
            float4 color : COLOR;
        };
    
        uniform float _Outline;
        uniform float4 _OutlineColor;
    
        v2f vert(appdata v) {
            // just make a copy of incoming vertex data but scaled according to normal direction
            v2f o;
            o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    
            float3 norm = normalize(mul((float3x3)UNITY_MATRIX_IT_MV, v.normal));
            float2 offset = TransformViewToProjection(norm.xy);
    
            o.pos.xy += offset * o.pos.z * _Outline;
            o.color = _OutlineColor;
            return o;
        }
        ENDCG
    
            SubShader{
            //Tags {"Queue" = "Geometry+100" }
            CGPROGRAM
    #pragma surface surf Lambert
    
            sampler2D _MainTex;
        fixed4 _Color;
    
        struct Input {
            float2 uv_MainTex;
        };
    
        void surf(Input IN, inout SurfaceOutput o) {
            fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    
            // note that a vertex shader is specified here but its using the one above
            Pass{
            Name "OUTLINE"
            Tags{ "LightMode" = "Always" }
            Cull Front
            ZWrite On
            ColorMask RGB
            Blend SrcAlpha OneMinusSrcAlpha
            //Offset 50,50
    
            CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
            half4 frag(v2f i) :COLOR{ return i.color; }
            ENDCG
        }
        }
    
            SubShader{
            CGPROGRAM
    #pragma surface surf Lambert
    
            sampler2D _MainTex;
        fixed4 _Color;
    
        struct Input {
            float2 uv_MainTex;
        };
    
        void surf(Input IN, inout SurfaceOutput o) {
            fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    
            Pass{
            Name "OUTLINE"
            Tags{ "LightMode" = "Always" }
            Cull Front
            ZWrite On
            ColorMask RGB
            Blend SrcAlpha OneMinusSrcAlpha
    
    //      CGPROGRAM
    //#pragma vertex vert
    //#pragma exclude_renderers gles xbox360 ps3
    //      ENDCG
            SetTexture[_MainTex]{ combine primary }
        }
        }
    
            Fallback "Diffuse"
    }
    

    I did not write this shader; it’s one of many variations that you can find floating around.

    You can apply it to your gameobject by setting the shader for the material, so something like this:

    gameObject.renderer.material.shader = SelectedShader;

    Where SelectedShader is a public field (not property), such that you can bind the outline shader to that variable through the inspector. Be sure to keep a reference to the previous shader so you can go back when unselected.

    You can choose the color of the outline by setting it on the material:

    gameObject.renderer.material.SetColor("_OutlineColor", outlineColor);

    Hopefully this is close enough!

    Login or Signup to reply.
  2. enter image description here

    I did very similar thing months ago. It can be done with LineRenderer and PolygonCollider2D. You have to know how do read the documentation as a new user because it has a-lot of information you don’t know about.

    Steps on how to do this:

    1.Create new LineRenderer from code.

    2.Assign Material to the new Line Renderer, set the width and color.

    3.Get the points from the PolygonCollider2D which returns arrays of the points in the PolygonCollider2D.

    4.Loop over the points and convert each one from local to world space with the TransformPoint function..

    5.Set the SetVertexCount of the LineRenderer to be the Length of the points plus 1. We need that extra 1 in order to close what we are drawing.

    DRAW LINES:

    6.Finally, Loop over the points and draw the Line by changing the position of the LineRenderer with the SetPosition function.

    LineRenderer.SetPosition(currentLoop, pointsArray[currentLoop]);
    

    Since this is 2D, you may want to modify the Z axis of the pointsArray to make sure that the Object is displayed in front of every GameObject.

    7.Close the line by drawing a new Line from the last(pointsArray.Length) point position to the first( pointsArray[0]) points.

    LineRenderer.SetPosition(pointsArray.Length, pointsArray[0]);
    

    Below is a function that can do this completely. You can extend it to support other 2D Colliders as-well. Just create a script and cop the code inside it. Drag the Sprite that has PolygonCollider2D attached to it to the myGameObject slot then click Play. It will draw line on that sprite.

    The highlightAroundCollider(pColider, Color.yellow, Color.red, 0.1f); function gives you option when calling it such as setting the size and color of it.

    using UnityEngine;
    using System.Collections;
    
    public class LineDrawerTest : MonoBehaviour
    {
        public GameObject myGameObject;
        private PolygonCollider2D pColider;
    
        protected void Start()
        {
            pColider = myGameObject.GetComponent<PolygonCollider2D>();
            highlightAroundCollider(pColider, Color.yellow, Color.red, 0.1f);
        }
    
    
        void highlightAroundCollider(Component cpType, Color beginColor, Color endColor, float hightlightSize = 0.3f)
        {
            //1. Create new Line Renderer
            LineRenderer lineRenderer = gameObject.GetComponent<LineRenderer>();
            if (lineRenderer == null)
            {
                lineRenderer = cpType.gameObject.AddComponent<LineRenderer>();
    
            }
    
            //2. Assign Material to the new Line Renderer
            lineRenderer.material = new Material(Shader.Find("Particles/Additive"));
    
            float zPos = 10f;//Since this is 2D. Make sure it is in the front
    
            if (cpType is PolygonCollider2D)
            {
                //3. Get the points from the PolygonCollider2D
                Vector2[] pColiderPos = (cpType as PolygonCollider2D).points;
    
                //Set color and width
                lineRenderer.SetColors(beginColor, endColor);
                lineRenderer.SetWidth(hightlightSize, hightlightSize);
    
                //4. Convert local to world points
                for (int i = 0; i < pColiderPos.Length; i++)
                {
                    pColiderPos[i] = cpType.transform.TransformPoint(pColiderPos[i]);
                }
    
                //5. Set the SetVertexCount of the LineRenderer to the Length of the points
                lineRenderer.SetVertexCount(pColiderPos.Length + 1);
                for (int i = 0; i < pColiderPos.Length; i++)
                {
                    //6. Draw the  line
                    Vector3 finalLine = pColiderPos[i];
                    finalLine.z = zPos;
                    lineRenderer.SetPosition(i, finalLine);
    
                    //7. Check if this is the last loop. Now Close the Line drawn
                    if (i == (pColiderPos.Length - 1))
                    {
                        finalLine = pColiderPos[0];
                        finalLine.z = zPos;
                        lineRenderer.SetPosition(pColiderPos.Length, finalLine);
                    }
                }
            }
    
             //Not Implemented. You can do this yourself
            else if (cpType is BoxCollider2D)
            {
    
            }
        }
    
        void Update()
        {
    
        }
    }
    
    Login or Signup to reply.
  3. Here is a solution I use. It uses Line Renderer, witch will finally be beatifull in Unity 5.5.

    I got object that i use as button. It have PoligonCollider2D, a LineRenderer and this sript. Also line renderer has to redraw itself after resolution changes. So I configure my poligon colliders at the specific resolution, that you can config in Game window. In my script I use 689*500, that is 16/9 resolution. Canvas is Screen Space – Camera and have Aspect Ratio Fitter with 1.7777778 value.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PolygonButton : MonoBehaviour {
    
        public string param;
    
        public System.Action onClick;
    
        float animSpeed = 1.5f;
        IEnumerator anim;
        bool animating;
        Rect res; 
        Camera mainCam;
        float theWidth = 689;
    
        void Start()
        {
            mainCam = GameObject.FindObjectOfType<Camera>();
            res = mainCam.pixelRect;
            anim = buttonAnimation();
            animating = false;
            GetComponent<LineRenderer>().material.SetColor("_Color", new Color32(255, 255, 0, 0));
    
            LineRenderer lr = GetComponent<LineRenderer>();
            PolygonCollider2D polColliedr = GetComponent<PolygonCollider2D>();
            int i = 0;
            lr.numPositions = polColliedr.points.Length + 1;
            foreach (Vector2 point in polColliedr.points)
            {
                lr.SetPosition(i, point);
                i++;
            }
            lr.SetPosition(i, lr.GetPosition(0));
    
            //change scale for different aspect ratio
    
            float currWidth = GetComponentInParent<Canvas>().GetComponent<RectTransform>().sizeDelta.x;
    
            GetComponent<RectTransform>().localScale = new Vector3(currWidth / theWidth, currWidth / theWidth, currWidth / theWidth);
        }
    
        void Update()
        {
            //If resolution changes - we must change button scale
            if(mainCam.pixelRect.height != res.height || mainCam.pixelRect.width != res.width)
            {
                res = mainCam.pixelRect;
    
                float currWidth = GetComponentInParent<Canvas>().GetComponent<RectTransform>().sizeDelta.x;
                GetComponent<RectTransform>().localScale = new Vector3(currWidth / theWidth, currWidth / theWidth, currWidth / theWidth);
            }
        }
    
        void OnMouseEnter()
        {
            CoroutineExecutor.instance.Execute(anim);
        }
    
        void OnMouseExit()
        {
            ResetAnim();
        }
    
        void OnMouseUpAsButton()
        {
            ResetAnim();
            if(onClick != null)
                onClick();
        }
    
        void OnDestroy()
        {
            CoroutineExecutor.instance.StopExecution(anim);
        }
    
        void ResetAnim()
        {
            CoroutineExecutor.instance.StopExecution(anim);
            anim = null;
            anim = buttonAnimation();
            GetComponent<LineRenderer>().material.SetColor("_Color", new Color32(255, 255, 0, 0));
            animating = false;
        }
    
        IEnumerator buttonAnimation()
        {
            //Debug.Log("Start animation!");
            if (animating)
                yield break;
            GetComponent<LineRenderer>().material.SetColor("_Color", new Color32(255, 255, 0, 0));
    
            animating = true;
            LineRenderer lr = GetComponent<LineRenderer>();
            while (true)
            {
                float t = 0;
                while(t < 1)
                {
                    t += Time.deltaTime * animSpeed;
                    lr.material.SetColor("_Color", Color.Lerp(new Color32(255, 255, 0, 0), new Color32(255, 255, 0, 255), t));
                    yield return new WaitForEndOfFrame();
                }
                t = 0;
    
                while (t < 1)
                {
                    t += Time.deltaTime * animSpeed;
                    lr.material.SetColor("_Color", Color.Lerp(new Color32(255, 255, 0, 255), new Color32(255, 255, 0, 0), t));
                    yield return new WaitForEndOfFrame();
                }
                yield return new WaitForEndOfFrame();
            }
        }
    }
    

    Thats all looks like this:

    Example

    Login or Signup to reply.
  4. I think, this way is mush more simple

    public static void DrawPolygonCollider(PolygonCollider2D collider)
    {
        LineRenderer _lr = collider.gameObject.AddComponent<LineRenderer>();
        _lr.startWidth = 0.025f;
        _lr.endWidth = 0.025f;
        _lr.useWorldSpace = false;
        _lr.positionCount = collider.points.Length + 1;
        for (int i = 0; i < collider.points.Length; i++)
        {
            _lr.SetPosition(i,new Vector3(collider.points[i].x,collider.points[i].y));
        }
        _lr.SetPosition(collider.points.Length, new Vector3(collider.points[0].x, collider.points[0].y));
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search