Reputation: 31
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!
Thanks for the help if you can, and ask if you need more info!
Upvotes: 2
Views: 7103
Reputation: 19
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));
}
Upvotes: 1
Reputation: 1
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:
Upvotes: 0
Reputation: 125305
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()
{
}
}
Upvotes: 3
Reputation: 2425
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!
Upvotes: 1