【问题标题】:How to make a highlight around a PolygonCollider2D in unity?如何统一围绕 PolygonCollider2D 突出显示?
【发布时间】:2020-05-07 21:55:11
【问题描述】:

我的问题如标题所示。我正在和团结一起玩重新回到学校,我决定制作一个风险类型的小游戏。

基本上我有我的地图,当我点击我的一个领土时(我有一个多边形碰撞器,附加了一个点击方法,目前只是切换一个小盒子精灵来测试)我想突出显示我选择的区域周围的边缘(多边形对撞机覆盖的边缘)。所以我想知道是否可以基于对撞机或类似的东西制作高光效果。

我目前的计划是将所有区域的边缘用 Photoshop 制作成精灵,然后像测试精灵一样切换它们以创建效果,但如果我能以更简单、省时的方式完成,那就太好了!

如果可以的话,感谢您的帮助,如果您需要更多信息,请询问!

【问题讨论】:

  • 这可以用 C# 轻松完成。无需 Photoshop。你能上传一张它应该是什么样子的图片,以便我确保这是你正在寻找的东西吗?
  • 嗨!它看起来像这样:gyazo.com/53d76b924420d6b9294ba9aa2a3445c7这就是我用 Photoshop 完成的,但任何类似的效果都可以!

标签: c# unity3d collider


【解决方案1】:

几个月前我做过非常相似的事情。可以使用LineRendererPolygonCollider2D 完成。作为新用户,您必须知道如何阅读文档,因为其中包含很多您不知道的信息。

如何做到这一点的步骤:

1。从代码中创建新的LineRenderer

2.将Material分配给新的Line Renderer,设置宽度和颜色。

3.从PolygonCollider2D 中获取points,它返回PolygonCollider2D 中的点数组。

4.循环点并使用TransformPoint函数将每个点从本地空间转换为世界空间..

5。将LineRendererSetVertexCount 设置为点数加1 的Length。我们需要额外的1 来关闭我们正在绘制的内容。 p>

画线

6。最后,通过SetPosition函数改变LineRenderer的位置,循环点并绘制线。

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

由于这是 2D,您可能需要修改 pointsArray 的 Z 轴以确保 Object 显示在每个 GameObject 的前面。

7。通过从最后一个(pointsArray.Length)点位置到第一个(pointsArray[ 0]) 点。

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

下面是一个可以完全做到这一点的函数。您也可以扩展它以支持其他 2D 对撞机。只需创建一个脚本并复制其中的代码即可。将附加了 PolygonCollider2D 的 Sprite 拖到 myGameObject 插槽,然后单击 Play。它会在那个精灵上画线。

highlightAroundCollider(pColider, Color.yellow, Color.red, 0.1f); 函数在调用它时为您提供了选项,例如设置它的sizecolor

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()
    {

    }
}

【讨论】:

  • 嗨!非常感谢你做的这些!惊人!感谢您为我一步一步地解释它,它真的帮助我理解了。我用它来勾勒我的对撞机,虽然它不是我想要的确切效果,但它该死的接近!因此,对于我的项目,它将完美地工作:)。有时间我会继续玩它的!再次感谢您为我输入这些内容!
  • @harrisoncrazy 欢迎您!您可以对其进行更多改进并增加尺寸。如果您的问题得到解决,请不要忘记接受答案。
【解决方案2】:

虽然这不会勾勒出对撞机的轮廓(除非它是网格对撞机),但此着色器将使用选定的颜色勾勒出网格:

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"
}

这个着色器不是我写的;它是您可以找到的众多变体之一。

您可以通过设置材质的着色器将其应用于您的游戏对象,如下所示:

gameObject.renderer.material.shader = SelectedShader;

SelectedShader 是一个公共字段(不是属性),这样您就可以通过检查器将轮廓着色器绑定到该变量。请务必保留对前一个着色器的引用,以便在未选择时可以返回。

您可以通过在材质上设置来选择轮廓的颜色:

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

希望这已经足够接近了!

【讨论】:

  • 嗨,谢谢你,但这对我来说有点太复杂了!我刚刚进入游戏编程的第二年,所以大部分内容对我来说都是胡言乱语,我不知道把它放在哪里或类似的东西。
【解决方案3】:

这是我使用的解决方案。它使用 Line Renderer,女巫在 Unity 5.5 中最终会变得漂亮。

我得到了用作按钮的对象。它有 PoligonCollider2D、LineRenderer 和这个 sript。此外,线渲染器必须在分辨率更改后重新绘制自身。所以我以特定的分辨率配置我的 poligon 对撞机,您可以在游戏窗口中进行配置。在我的脚本中,我使用 689*500,即 16/9 分辨率。 Canvas 是 Screen Space - Camera 并且具有 1.7777778 值的 Aspect Ratio Fitter。

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();
        }
    }
}

看起来是这样的:

Example

【讨论】:

    【解决方案4】:

    我认为,这种方式要简单得多

    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));
    }
    

    【讨论】:

      猜你喜欢
      • 2012-04-13
      • 2010-09-17
      • 1970-01-01
      • 2012-08-02
      • 2011-09-13
      • 2013-07-24
      • 2011-12-01
      • 2023-03-29
      • 1970-01-01
      相关资源
      最近更新 更多