# Question
Title: Comparing analog stick movements to predefined flick shapes
I want to create a control scheme similar to the EA Skate games, where flicking the right analog stick in various ways makes the character do various tricks:

I record the user input over a set amount of time or until the user moves the analog stick back to its resting position. The recording is a List of Vector2 Coordinates.

Depending on how fast the user flicks the analogue stick, I sometimes get a shorter (15) or longer (45) list of points.

Now I want to compare these lists of points to predefined shapes like the ones in the screenshot, to match which action the player intended to take.

My idea was to use some metric to compare the similarity of the recording to lists of arrays, however, I don't which metric I might use. I found the Hausdorff-Metric and it seems applicable, but I don't know how to implement it.
It might also be an overkill for the problem, so I wanted to ask, how other people would solve the problem.

# Answer
> 6 votes
It looks like all these gestures only care about which points you hit around the outside of the stick's range, and the order you hit them in, so we can take a very simplified approach.

Let's label each sector in the outer ring with a letter:

Each time the stick lands in a new one of these sectors, we'll add that letter to a string. We won't repeat a letter if you linger in the same sector, and we won't care about the exact path you took to get there, as long as you didn't hit another sector in-between.

Now each combo is just a string of letters:

* Ollie: EA (appropriately enough )
* Heelflip: EB
* Kickflip: EH
* Nollie FS 360 Pop Shuvit: GHABC

We'll set up a script that pairs up each combo with one or more letter strings that should trigger it. (Having some "synonymous" strings helps you handle slight overshoots/misalignments, making the tricks easier to do even if the player's a little sloppy)

Here's what that can look like:

An example gesture recognizer might then look like this:

```
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

public class AnalogFlick : MonoBehaviour {
    // How many segments to divide the ring into.
    const int BUCKET_COUNT = 8;

    // Data structure to define combos.
    // You can add to this things like animations, point values, etc.
    // Or make it a ScriptableObject that can live as a separate asset.
    [System.Serializable]
    public class Combo {
        public string name;
        public string[] patterns;
    }

    // Gesture detection parameters.
    public float deadzoneRadius = 0.2f;
    public float activationRadius = 0.8f;
    public float maxGestureDuration = 1f;

    public Combo[] combos;

    Dictionary<string, Combo> _patternMatch = new Dictionary<string, Combo>();
    StringBuilder _progress = new StringBuilder();

    float _gestureDuration = 0f;
    [SerializeField]
    int _lastBucket;
    int _framesInDeadzone;
    bool _readyToBegin;

    string _patternInProgress = "";

    void Start() {
        // Convert our Inspector list of combos into a dictionary for quick string lookups.
        foreach (var combo in combos) {
            foreach (var pattern in combo.patterns)
                _patternMatch.Add(pattern, combo);
        }
    }

    // Update is called once per frame
    void Update() {
        // Collect our input and magnitude.
        Vector2 stick = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));

#if UNITY_EDITOR
        _analogHistory[Time.frameCount & 31] = stick;
#endif

        float magnitude = stick.magnitude;

        // If we're mid-gesture and cross within the deadzone, the flick might be over.
        if (magnitude < deadzoneRadius) {
            // Give some tolerance to cross the deadzone during a zig-zag, before we cut off.
            if (_gestureDuration > 0f && _framesInDeadzone > 2)
                EndFlick();

            //Debug.Log("Grazed deadzone");
            _framesInDeadzone++;
            // We've returned to neutral, so we can start a new gesture if we're not already in one.
            _readyToBegin = true;
        } else {
            // Otherwise, reset our deadzone watch.
            _framesInDeadzone = 0;

            // If we've deflected far enough to start a flick...
            if (_readyToBegin == true && magnitude > activationRadius) {
                // Start a new flick if we're not already.
                if (_gestureDuration == 0f)
                    BeginFlick();

                // Abort the gesture if it's gone too long.
                _gestureDuration += Time.deltaTime;
                if (_gestureDuration > maxGestureDuration) {
                    EndFlick();

                    // Finally, try to progress the gesture using this input.
                } else if (ProgressFlick(stick)) {
                    // If we've completed a valid pattern, fire the combo and end the gesture.
                    if (CheckPattern())
                        EndFlick();
                }
            }
        }
    }

    // Initialize flick state.
    void BeginFlick() {
        _progress.Length = 0;
        _lastBucket = -1;
    }

    // Try appending a new entry to the combo.
    bool ProgressFlick(Vector2 stick) {
        const float BUCKETS_PER_RADIAN = BUCKET_COUNT / (2 * Mathf.PI);

        // Get the angle of the stick, and round it to one of a fixed number of buckets.
        float angle = Mathf.Atan2(-stick.x, -stick.y);
        int bucket = Mathf.RoundToInt(angle * BUCKETS_PER_RADIAN + BUCKET_COUNT / 2.0f) % BUCKET_COUNT;
        // If we've changed buckets, add a new letter to our combo.
        if (bucket != _lastBucket) {
            _progress.Append((char)('A' + bucket));
            _lastBucket = bucket;
            return true;
        }
        // Otherwise, nothing new to report.
        return false;
    }

    bool CheckPattern() {
        // Read out our pattern so far...
        _patternInProgress = _progress.ToString();

        // Check whether it matches any of our combos.
        if (_patternMatch.TryGetValue(_patternInProgress, out Combo combo)) {
            Debug.LogFormat("Combo: {0} ({1})", combo.name, _patternInProgress);
            // TODO: Do the combo's trick!

            _patternInProgress = "";
            return true;
        }

        return false;
    }

    void EndFlick() {
        // For debugging, it's useful to know what the algorithm "thought" you entered.
        if (_patternInProgress != "")
            Debug.LogFormat("Unknown Combo: {0}", _patternInProgress);

        // Mark the gesture as over.
        _gestureDuration = 0f;
        // But don't let us start a new gesture till we return to neutral.
        _readyToBegin = false;
        _patternInProgress = "";
    }

#if UNITY_EDITOR
    Vector2[] _analogHistory = new Vector2[32];
    private void OnDrawGizmos() {
        Gizmos.matrix = Matrix4x4.TRS(transform.position, Quaternion.identity, new Vector3(1, 1, 0));
        Gizmos.color = Color.white;
        Gizmos.DrawWireSphere(Vector3.zero, 1.0f);
        Gizmos.color = Color.grey;
        Gizmos.DrawWireSphere(Vector3.zero, activationRadius);
        Gizmos.color = Color.black;
        Gizmos.DrawWireSphere(Vector3.zero, deadzoneRadius);

        Gizmos.color = Color.grey;
        for(int i = 0; i < BUCKET_COUNT; i++) {
            Vector3 direction = Quaternion.Euler(0, 0, (360.0f / BUCKET_COUNT) * (i + 0.5f)) * Vector3.up;
            Gizmos.DrawLine( 1f * direction,  activationRadius * direction);
        }

        Gizmos.color = _gestureDuration == 0f ? Color.blue : Color.red;
        Vector3 lastPosition = _analogHistory[(Time.frameCount + 1) & 31];
        for (int x = 2; x <= 32; x++) {
            var next = _analogHistory[(Time.frameCount + x) & 31];
            Gizmos.DrawLine(lastPosition, next);
            lastPosition = next;
        }

        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(lastPosition, 0.1f);
    }
#endif
}

```

This script also comes with a handy input visualizer to help you see what different flicks look like, and adjust the tuning of your radii:

You can improve on this in various ways - adding a little hysteresis to reduce false positives when input is close to the edge of a sector, tuning the diagonal buckets so they're a bit wider to compensate for the cardinal directions being easier to hit, or keeping a running history buffer and checking multiple pattern lengths in that buffer so you don't need a hard return-to-neutral reset between gestures. But this basic idea should get you quite a long way. And the simplicity makes it easy to author gestures for, easy to debug when it's misbehaving, and rock-solid in terms of consistency & reliability for the player.

---
Tags: unity, c#, algorithm, input, gestures
---


# Question
Title: If I don't use PrefabUtility class, how can I save my changed prefabs and build without exception?
I'm designing a racing game for my graduation project. I used PrefabUtility.SaveAsPrefabAsset to save my color change on the car prefabs, I finished the codes and it work well in Unity, but when I want to build my project,the Unity give me a error:The name 'PrefabUtility' does not exist in the current context. I want to know can I not use PrefabUtility or UnityEditor to save my changed prefabs in assets directory, or are there someways to solve this problem?

# Answer
> 2 votes
I'm sorry, but the architecure you have built is not going to work.

All classes from the `using UnityEditor` namespace are only available when you run your game from the editor. Any game which relies on these classes at runtime will fail to build for any platform. This includes any classes which create assets. So you have to find a different solution for your problem.

If it is really just about storing the color preference of the player, then you might store the RGB values of the picked color using the `PlayerPrefs` class. When you instantiate the car prefab during the game, retrieve the values from `PlayerPrefs` and apply them to the material of the car.

If the customization options in your game are more extensive and you want the player to be able to save multiple customization setups, then you might want to look into inventing an own file format to store that information which you then read and write using the regular C# classes for file access (If you need some examples, then Stackoverflow will have you covered). But remember that you can not write files on platforms like WebGL which do not have access to a writeable filesystem. And when you decide where to save the files, you should make use of the property `Application.persistentDataPath` to get a savegame location which follows the best practices for the platform your game runs on.

If you don't even need to store the customization setups permanently and only want to communicate them from one scene to the next, then you might want to check out what other options are available for that situation.

---
Tags: unity, prefabs
---


# Question
Title: World space UI stretched too much instead of billboard in unity
I am scaling my world space UI element as my camera go far away from UI using this code snippet:

```
public class ZoomNamePlace : MonoBehaviour
{
    //public CameraController camContrller;
    public int Zoom_Factor;

    void LateUpdate()
    {
        Zoom();
    }

    void Zoom()
    {
        float size = (Camera.main.transform.position - transform.position).magnitude;
    }

}

```

It is working fine and my UI scale according to the distance of Camera and UI. Now i want to rotate/billboard my world space UI to the camera and here is my script:

```
public class Billboard : MonoBehaviour
{

    //Orient the camera after all movement is completed this frame to avoid jittering
    void LateUpdate()
    {
        Camera m_Camera = Camera.main;

        transform.LookAt(transform.position + m_Camera.transform.rotation * Vector3.forward,
            m_Camera.transform.rotation * Vector3.up);
    }
}

```

But the problem is instead of billboard my UI shape stretched too much maybe due to my canvas scale set to 0.01.

# Answer
When you parent object transform scale is not uniform (set to 1) then rotating the child object will deform the mesh. So Make sure your parent scale set to 1. In my case my canvas size were set to 0.01 and when my child object rotate its deform the shape.
> 0 votes

# Answer
You can use this script to enable a very strict billboarding, hopefully it works for you. Just attach it to the UI objects that should have this behaviour.

```
public class MyBillB : MonoBehaviour
    {
        private Transform cameraTrans;
        void Start()
        {
            cameraTrans  = Camera.main.transform;
        }
        void LateUpdate()
        {
            transform.forward = cameraTrans.forward;
        }
    }

```
> 0 votes

---
Tags: unity, html-canvas
---


# Question
Title: How can I make one of the agents to wait X seconds before start moving?
The same script is attached to some multiple agents. On one of them the flag waitToMove is set to true. And it does getting to the line :

```
StartCoroutine(WaitToMove(10));

```

But still all the agents including the one with the flag set to true start moving when starting the game.

How can I make that agents with the script that the flag waitToMove is set to true will wait X seconds one agent will wait 5 seconds other will wait 3 seconds and this one will wait 10 seconds ?

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class AgentControl : MonoBehaviour
{
    public List<Transform> points;
    public bool waitToMove = false;

    private int destPoint = 0;
    private NavMeshAgent agent;
    private Transform originalPos;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();

        // Disabling auto-braking allows for continuous movement
        // between points (ie, the agent doesn't slow down as it
        // approaches a destination point).
        agent.autoBraking = false;

        originalPos = transform;
        points.Add(originalPos);

        if (waitToMove == false)
        {
            GotoNextPoint();
        }
        else
        {
            StartCoroutine(WaitToMove(10));
        }
    }

    void GotoNextPoint()
    {
        // Returns if no points have been set up
        if (points.Count == 0)
            return;

        // Set the agent to go to the currently selected destination.
        agent.destination = points[destPoint].position;

        // Choose the next point in the array as the destination,
        // cycling to the start if necessary.
        destPoint = (destPoint + 1) % points.Count;
    }

    void Update()
    {
        // Choose the next destination point when the agent gets
        // close to the current one.
        if (!agent.pathPending && agent.remainingDistance < 1f)
            GotoNextPoint();
    }

    IEnumerator WaitToMove(int WaitTime)
    {
        yield return new WaitForSeconds(WaitTime);
    }
}

```

# Answer
> 0 votes
Can you do something like this instead?

```
   //two vars for handling timer
   float timer = 0;
   //notice WaitTime is a float now
   float WaitTime = 10f;
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();

        // Disabling auto-braking allows for continuous movement
        // between points (ie, the agent doesn't slow down as it
        // approaches a destination point).
        agent.autoBraking = false;

        originalPos = transform;
        points.Add(originalPos);

    }

void Update()
{
    // Choose the next destination point when the agent gets
    // close to the current one.
    if (!agent.pathPending && agent.remainingDistance < 1f)
    {
        //if wait to move is true
        if (waitToMove)
        {
            //if timer is less than 10
            if (timer < WaitTime)
            {
                //add Time.deltaTime each time we hit this point
                timer += Time.deltaTime;
            }
            //no longer waiting because timer is greater than 10
            else
            {

                waitTomove = false;
            }
        }
        //if we hit here waitToMove is false, so go ahead as usual
        else
        {
            GotoNextPoint();
        }
    }

}

```

If you want to make the agent wait again after the first time, you will need to set the timer equal to 0 again and set WaitToMove to true, but you can ofcourse add a small function that handles this, infact I'd recommend it.

If you are wanting to randomize the waitTime you can do something like this

```
//define min and max WaitTime
float waitMinTime = 1f;
float waitMaxTime = 10f;
void Start()
{
    agent = GetComponent<NavMeshAgent>();

    // Disabling auto-braking allows for continuous movement
    // between points (ie, the agent doesn't slow down as it
    // approaches a destination point).
    agent.autoBraking = false;
    //set WaitTime to equal a random number between min and max
    WaitTime = Random.Range(waitMinTime, waitMaxTime);
    originalPos = transform;
    points.Add(originalPos);

}

```

So you mentioned in the comments that you also want to add the Objects original position to the end of the list, so when it is finished it will return the its starting position, a patrol.

But you are not doing this you are adding the objects transform *reference* to the list, this transform is *attached* to the object so it will be wherever the object is, leading to mini stuttering as it arrives at the original position AND starts moving to it in between frames.

You can test this to see what I mean, leave your code as it is, take one of the transforms 'points' in your level and move it, the agent moves to where the point currently is right? Now Imagine that 'point' is attached to the Agent itself, you might be able to see why its stuttering!

You need to take a snap shot of the position *once*, and add that I would do it something like this.

Also because you are adding a list of transforms and not a list of positions (Vector3) we will need to create a new GameObject (with transform, they both exist together)

```
void Start()
{
    agent = GetComponent<NavMeshAgent>();

    // Disabling auto-braking allows for continuous movement
    // between points (ie, the agent doesn't slow down as it
    // approaches a destination point).
    agent.autoBraking = false;
    //set WaitTime to equal a random number between min and max
    WaitTime = Random.Range(waitMinTime, waitMaxTime);

    //transforms dont exist without A GameObject and a GameObject doesn't exist without a transform
    //create a new GameObject to hold our position
    GameObject originalPositionObject = new GameObject();
    //set the new gameobjects position equal to where the transform is right now
    originalPositionObject.transform.position = transform.position;
    //add this to the points list instead
    points.Add(originalPositionObject.transform);

}

```

I hope I've understood you correctly!

---
Tags: unity, c#
---


# Question
Title: Change value in the script that a Raycast hit
I have a script for a laser that can refract off mirrors, and the object of the game is to refract the lasers into the Receivers. Once the first room full of different lasers has connected with their corresponding receiver, the door will open.

I used a OnCollisionEnter in the Reciever script before I found out that `LineRenderer` cannot be detected by this.

So then to test it I compared the tag like this:

```
    if (gameObject.tag == "BLazer")
    {
         if (hit.collider.tag=="BTarget")
         {
                GameObject BR11 = GameObject.Find("BlueReceiver11");
                Receiver Receiver = BR11.GetComponent<Receiver>();
                string TEST= hit.collider.name;
                Receiver.HIT = true;

                break;
         }

```

Which works, however this would mean I would have to type out a check and bring in the objects for every single Receiver in the game in a script.

There has to be a better way than this.

I'll include the code here for the full scripts; ignore the random bools and ints, they're all for testing.

**LASER SCRIPT**

```
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

   [RequireComponent(typeof(LineRenderer))]
   public class Lazer : MonoBehaviour
   {
      public int reflections;
      public float maxLength;

    public static Lazer instance;

    private LineRenderer lineRenderer;
    private Ray ray;
    private RaycastHit hit;
    private Vector3 direction;
    public bool BL;
    public bool YL;
    public bool RL;
    public bool BL11;
    public bool BL12;
    public bool RL12;

    public int B;
    public int Y;
    public int R;

    private void Start()
    {
        instance = this;

    }

    private void Awake()
    {
        lineRenderer = GetComponent<LineRenderer>();
    }

    private void Update()
    {
        ray = new Ray(transform.position, transform.forward);

        lineRenderer.positionCount = 1;
        lineRenderer.SetPosition(0, transform.position);
        float remainingLength = maxLength;

        for (int i = 0; i < reflections; i++)
        {
            if (Physics.Raycast(ray.origin, ray.direction, out hit, remainingLength))
            {
                //Debug.Log("Transform Tag is: " + gameObject.tag);
                lineRenderer.positionCount += 1;
                lineRenderer.SetPosition(lineRenderer.positionCount - 1, hit.point);
                remainingLength -= Vector3.Distance(ray.origin,hit.point);
                ray = new Ray(hit.point, Vector3.Reflect(ray.direction, hit.normal));

                //BLUE LASER
                if (gameObject.tag == "BLazer")
                {
                    if (hit.collider.tag=="BTarget")
                    {
                        GameObject BR11 = GameObject.Find("BlueReceiver11");
                        Receiver Receiver = BR11.GetComponent<Receiver>();
                        string TEST= hit.collider.name;
                        Receiver.HIT = true;

                        break;
                    }
                    else
                    {
                        //BL = false;
                        Debug.Log("Blue false");
                        if (hit.collider.tag != "Mirror")
                        {
                            break;
                        }
                    }
                }

                //YELLOW LASER
                else if (gameObject.tag == "YLazer")
                {
                    if (hit.collider.tag == "YTarget")
                    {
                        if (YL == false)
                        {
                            Y++;
                            YL = true;

                            Debug.Log("Yellow hit Yellow! - " + Y);
                        }
                        break;

                    }
                    else
                    {
                        if (YL)
                        {
                            Y--;
                            YL = false;
                            Debug.Log("Yellow false - "+Y );
                        }

                        if (hit.collider.tag != "Mirror")
                        {
                            break;
                        }
                    }
                }

                //RED LASER
                else if (gameObject.tag == "RLazer")
                {
                    if (hit.collider.tag == "RTarget")
                    {
                        Debug.Log("Red hit Red! - " + gameObject.tag + " hit " + hit.collider.tag);
                        RL = true;
                        break;
                    }
                    else {
                        RL = false;
                        Debug.Log("Red false");
                        if (hit.collider.tag != "Mirror")
                        {
                            break;
                        }
                    }
                }

            }
            else
            {

                lineRenderer.positionCount += 1;
                lineRenderer.SetPosition(lineRenderer.positionCount - 1, ray.origin + ray.direction * remainingLength);
            }
        }
    }

 }

```

**My (pretty empty now) Receiver class**

```
    using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Receiver : MonoBehaviour
{
    public bool HIT;

    private void Update()
    {
        if (HIT) {
            Debug.Log("IT WORKED - " +gameObject.name);
        }
    }

```

**Room 1 Script**

```
 using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Room1 : MonoBehaviour
{
    public GameObject Door1;
    public GameObject RedReceiver11;
    public GameObject RedReceiver12;
    public GameObject YellowReceiver11;
    public GameObject YellowReceiver12;
    public GameObject BlueReceiver11;
    public GameObject BlueReceiver22;

    public GameObject gdgfdg;

    public bool RR11, RR12, YR11, YR12, BR11, BR12;
    /*
    void Start()
    {
        GameObject thePlayer = GameObject.Find("First Person Player");
        PlayerMovement playerScript = thePlayer.GetComponent<PlayerMovement>();
        Debug.Log(playerScript.jumpHeight);
    }
    */
    private void TEST() {

        //RedReceiver11
    }

    void Update()
    {
        //If all lasers hitting recievers then raise the door
       if (RR11 && RR12 && YR11 && YR12 && BR11 && BR12)
        {
            Debug.Log("R1 DONE");
            if (Door1.transform.position.y < 8)
            {
                Door1.transform.Translate(Vector3.up * Time.deltaTime, Space.World);
            }

        }
       //if not, keep it close or lower it
        else {

            if (Door1.transform.position.y > 2)
            {
                Door1.transform.Translate(Vector3.down * Time.deltaTime, Space.World);
            }
        }

    }
}

```

# Answer
> 0 votes
I forgot to come back to this, and the above answer is a great one. If anyone is looking for this in the future and is stuck, what I did is super inelegant and very non-scalable, but you're welcome to go for it if you're looking for a quick and dirty solution.

**Laser Changes**

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(LineRenderer))]
public class Lazer : MonoBehaviour
{
    public int reflections;
    public float maxLength;

    public static Lazer instance;

    private LineRenderer lineRenderer;
    private Ray ray;
    private RaycastHit hit;
    private Vector3 direction;

    private void Start()
    {
        instance = this;

    }

    private void Awake()
    {
        lineRenderer = GetComponent<LineRenderer>();
    }

    private void Update()
    {
        ray = new Ray(transform.position, transform.forward);

        lineRenderer.positionCount = 1;
        lineRenderer.SetPosition(0, transform.position);
        float remainingLength = maxLength;

        for (int i = 0; i < reflections; i++)
        {
            if (Physics.Raycast(ray.origin, ray.direction, out hit, remainingLength))
            {
                //Debug.Log("Transform Tag is: " + gameObject.tag);
                lineRenderer.positionCount += 1;
                lineRenderer.SetPosition(lineRenderer.positionCount - 1, hit.point);
                remainingLength -= Vector3.Distance(ray.origin,hit.point);
                ray = new Ray(hit.point, Vector3.Reflect(ray.direction, hit.normal));

                //Level 1
                GameObject BR1 = GameObject.Find("BR1");
                Receiver Receiver1 = BR1.GetComponent<Receiver>();

                //Level 2
                GameObject YR2 = GameObject.Find("YR2");
                Receiver Receiver2 = YR2.GetComponent<Receiver>();

                //Level 3
                GameObject RR3 = GameObject.Find("RR3");
                Receiver Receiver3 = RR3.GetComponent<Receiver>();

                //Level 4
                GameObject BR4 = GameObject.Find("BR4");
                Receiver Receiver4A = BR4.GetComponent<Receiver>();
                GameObject YR4 = GameObject.Find("YR4");
                Receiver Receiver4B = YR4.GetComponent<Receiver>();

                //BLUE LASER LEVEL 3
                if (gameObject.name == "BL1")
                {
                    if (hit.collider.tag=="BTarget")
                    {
                        Receiver1.HIT = true;
                        break;
                    }
                    else
                    {
                        Receiver1.HIT = false;
                        if (hit.collider.tag != "Mirror")
                        {
                            break;
                        }
                    }
                }

                //YELLOW LASER LEVEL 2
                else if (gameObject.name == "YL2")
                {
                    if (hit.collider.tag == "YTarget")
                    {
                        Receiver2.HIT = true;
                        break;
                    }
                    else
                    {
                        Receiver2.HIT = false;
                        if (hit.collider.tag != "Mirror")
                        {
                            break;
                        }
                    }
                }

                //RED LASER LEVEL 3
                else if (gameObject.name == "RL3")
                {
                    if (hit.collider.tag == "RTarget")
                    {
                        Receiver3.HIT = true;
                        break;
                    }
                    else
                    {
                        Receiver3.HIT = false;
                        if (hit.collider.tag != "Mirror")
                        {
                            break;
                        }
                    }
                }

                //BLUE AND YELLOW LASER - LEVEL 4
                else if (gameObject.name == "BL4")
                {
                    if (hit.collider.tag == "BTarget")
                    {
                        Receiver4A.HIT = true;
                        break;
                    }
                    else
                    {
                        Receiver4A.HIT = false;
                        if (hit.collider.tag != "Mirror")
                        {
                            break;
                        }
                    }
                }

                else if (gameObject.name == "YL4")
                {
                    if (hit.collider.tag == "YTarget")
                    {
                        Receiver4B.HIT = true;
                        break;
                    }
                    else
                    {
                        Receiver4B.HIT = false;
                        if (hit.collider.tag != "Mirror")
                        {
                            break;
                        }
                    }
                }

                else if (gameObject.tag == "BLazer"|| gameObject.tag == "YLazer" || gameObject.tag == "RLazer")
                {
                    if (hit.collider.tag != "Mirror")
                    {
                        break;
                    }

                }

            }
            else
            {

                lineRenderer.positionCount += 1;
                lineRenderer.SetPosition(lineRenderer.positionCount - 1, ray.origin + ray.direction * remainingLength);
            }
        }
    }

}

```

And then I used a GameManager for the levels:

**Game Manager**

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GM : MonoBehaviour
{
    public GameObject Gate1;
    public GameObject DoorL1;
    public GameObject BR1; //Level 1 Receiver
    public bool R1;

    public GameObject Gate2;
    public GameObject DoorL2;
    public GameObject YR2; //Level 2 Receiver
    public bool R2;

    public GameObject Gate3;
    public GameObject DoorL3;
    public GameObject RR3; //Level 3 Receiver
    public bool R3;

    public GameObject Gate4;
    public GameObject DoorL4A;
    public GameObject DoorL4B;
    public GameObject BR4; //Level 4 Receiver Blue
    public GameObject YR4; //Level 4 Receiver Yellow
    public bool R4;
    private bool L1Played;
    private bool L2Played;
    private bool L3Played;
    private bool L4Played;

    void Update()
    {

        //ROOM 1

        Receiver R1Script = BR1.GetComponent<Receiver>();
        //If all lasers hitting recievers then raise the door

        if (R1Script.HIT)
        {
            Debug.Log("R1 DONE");
            if (Gate1.transform.position.y < 8)
            {
                Gate1.transform.Translate(Vector3.up * Time.deltaTime, Space.World);
                if (L1Played == false)
                {
                    Gate1.GetComponent<AudioSource>().Play();
                    L1Played = true;
                }
                //FindObjectOfType<AudioManager>().Play("LevelComplete");
                DoorL1.SetActive(false);
            }

        }
       //if not, keep it close or lower it
        else {

            if (Gate1.transform.position.y > 2)
            {
                Gate1.transform.Translate(Vector3.down * Time.deltaTime, Space.World);
                DoorL1.SetActive(true);
            }
        }

        //ROOM 2

        Receiver R2Script = YR2.GetComponent<Receiver>();
        //If all lasers hitting recievers then raise the door

        if (R2Script.HIT)
        {
            Debug.Log("R2 DONE");
            if (Gate2.transform.position.y < 8)
            {
                Gate2.transform.Translate(Vector3.up * Time.deltaTime, Space.World);
                //FindObjectOfType<AudioManager>().Play("LevelComplete");
                if (L2Played == false)
                {
                    Gate2.GetComponent<AudioSource>().Play();
                    L2Played = true;
                }
                DoorL2.SetActive(false);
            }

        }
        //if not, keep it close or lower it
        else
        {

            if (Gate2.transform.position.y > 2)
            {
                Gate2.transform.Translate(Vector3.down * Time.deltaTime, Space.World);
                DoorL2.SetActive(true);
            }
        }

        //ROOM 3

        Receiver R3Script = RR3.GetComponent<Receiver>();
        //If all lasers hitting recievers then raise the door

        if (R3Script.HIT)
        {
            Debug.Log("R3 DONE");
            if (Gate3.transform.position.y < 8)
            {
                Gate3.transform.Translate(Vector3.up * Time.deltaTime, Space.World);
                //FindObjectOfType<AudioManager>().Play("LevelComplete");
                if (L3Played == false)
                {
                    Gate3.GetComponent<AudioSource>().Play();
                    L3Played = true;
                }
                DoorL3.SetActive(false);
            }

        }
        //if not, keep it close or lower it
        else
        {

            if (Gate3.transform.position.y > 2)
            {
                Gate3.transform.Translate(Vector3.down * Time.deltaTime, Space.World);
                DoorL3.SetActive(true);
            }
        }

        //ROOM 4

        Receiver R4ScriptA = BR4.GetComponent<Receiver>();
        Receiver R4ScriptB = YR4.GetComponent<Receiver>();
        //If all lasers hitting recievers then raise the door

        if (R4ScriptA.HIT && R4ScriptB.HIT)
        {
            Debug.Log("R4 DONE");
            if (Gate4.transform.position.y < 8)
            {
                Gate4.transform.Translate(Vector3.up * Time.deltaTime, Space.World);
                //FindObjectOfType<AudioManager>().Play("LevelComplete");
                if (L4Played == false)
                {
                    Gate4.GetComponent<AudioSource>().Play();
                    L4Played = true;
                }
                DoorL4A.SetActive(false);
                DoorL4B.SetActive(false);
            }

        }
        //if not, keep it close or lower it
        else
        {

            if (Gate4.transform.position.y > 2)
            {
                Gate4.transform.Translate(Vector3.down * Time.deltaTime, Space.World);
                DoorL4A.SetActive(false);
                DoorL4B.SetActive(false);
            }
        }
    }
}

```

# Answer
> 0 votes
I would move your door opening logic to the receiver. On your receiver prefab, have a public member variable of either your laser object (if you know it) or a layer mask that you assign in the inspector.

Then in your collider OnCollision() check to see if the colliding object is the correct laser. If it is, then open the door.

# Answer
> 0 votes
First, let's make an enumeration to keep track of our different laser colours. This way you don't have to create a new tag for every one, and you can use your tags for other things. Plus, no string comparisons!

```
public enum LaserColor {
    Blue,
    Yellow,
    Red
}

```

Next, let's abstract the behaviour of turning a switch on/off. This might look weird right now, but it's going to help us avoid making a custom script for each different room. Instead, we can set up any action to be fired by any laser receiver, or any group of laser receivers, using this same building block. (You can even go as far as chaining these switches up like transistors to make a mini computer, like folks do with Redstone in Minecraft!)

```
public abstract class ToggleSwitch : MonoBehaviour {

    // Set up an event we can use to wire this to our door controls.
    [System.Serializable]
    public class SwitchEvent : UnityEvent<bool, ToggleSwitch> { }
    public SwitchEvent OnToggle;

    // This lets us fire a signal when we're first set, no matter whether we're turning on or off.
    bool _hasBeenSet;

    [SerializeField] // Show this in the inspector, to help debugging puzzles.
    bool _activated;
    public bool activated {
        // Let outside scripts read our active status, but not set it.
        get { return _hasBeenSet ? _activated : false; }

        // Whenever our activation state changes, automatically fire our event to listeners.
        protected set {
            if (_hasBeenSet && value == _activated)
                return;

            _activated = value;
            _hasBeenSet = true;
            if (OnToggle != null)
                OnToggle.Invoke(value, this);
        }
    }
}

```

Your receiver is one kind of switch, that responds to lasers:

```
public class LaserSwitch : ToggleSwitch {
    // What color does this receiver respond to?
    public LaserColor color;

    // Use this to check whether no lasers hit us for a whole frame.
    bool _activatedThisFrame;

    // When we're enabled, let all our listeners know that we exist.
    // (This helps when we want to check whether "all" have been hit)
    void OnEnable() {
        _activatedThisFrame = false;
        activated = false;
    }

    // When we're disabled, let all our listeners know we're off.
    void OnDisable() {
        activated = false;
    }

    // Expose a function for our laser to call.
    public void HitByLaser(LaserColor color) {
        // If it's the wrong laser colour, abort!
        if (color != this.color)
            return;

        // Set our active status.
        _activatedThisFrame = true;
        activated = true;
    }

    // After all the normal updates have run, check if anything hit us.
    void LateUpdate() {
        // If nothing hit us this frame, de-activate.
        activated = _activatedThisFrame;

        // Reset the flag to check again next frame.
        _activatedThisFrame = false;
    }
}

```

Here's how that looks in our Inspector. You can see we get to freely control which script this laser switch activates by populating one or more listeners in the `UnityEvent` widget - that lets us set up lots of different room puzzles with one script.

Here I have it sending its activation events to a "GatherSwitch" - that's another type of switch that will listen to multiple other switches, and activate or deactivate depending on the activation values of all its contributors. Here's that script:

```
public class GatherSwitch : ToggleSwitch
{
    // Allow switching between...
    public enum Mode {
        All, // Hit all receivers to activate this item.
        Any  // Hit any receiver to activate this item.
    }
    public Mode mode;

    // Keep track of all switches wired to this one.
    List<ToggleSwitch> _toggles = new List<ToggleSwitch>();

    // This caching lets us use the TrueForAll / Exists methods without allocations.
    static bool IsToggled(ToggleSwitch toggle) { return toggle.activated; }
    static readonly System.Predicate<ToggleSwitch> ACTIVE = IsToggled;

    public void OnChildToggled(bool activated, ToggleSwitch sender) {
        // Automatically include any receivers that send an event to us.
        if (_toggles.Contains(sender) == false)
            _toggles.Add(sender);

        switch (mode) {
            case Mode.All:
                this.activated = _toggles.TrueForAll(ACTIVE);
                break;
            case Mode.Any:
                this.activated = _toggles.Exists(ACTIVE);
                break;
        }
    }
}

```

That looks like this:

Here I have the door control `GatherSwitch` listening to all the switches wired to it, and activating only when *All* of its contributor switches are active. When that happens, it calls a method on the door like this:

```
public void OpenClose(bool open, ToggleSwitch source = null) { ... }

```

(Giving a default value there lets you also call this method as just `OpenClose(true);` if you want control its state with scripts other than switches)

Finally, our laser can just get the `LaserSwitch` receiver it hit with `GetComponent<LaserSwitch>()`, and call `HitByLaser()` to log its hit.

```
[RequireComponent(typeof(LineRenderer))]
public class Laser : MonoBehaviour {

    public LaserColor color;

    public int maxReflections = 8;
    public float maxLength = 50;

    LineRenderer _line;
    // We'll cache a buffer of points, so we can set them all at once for efficiency.
    Vector3[] _linePoints;

    void Start() {
        _line = GetComponent<LineRenderer>();
        _linePoints = new Vector3[maxReflections + 1];
    }

    void Update() {
        var ray = new Ray(transform.position, transform.forward);

        _linePoints[0] = ray.origin;

        float remainingLength = maxLength;

        int segmentCount = 0;
        for (int i = 1; i <= maxReflections; i++) {
            segmentCount++;

            // If we didn't hit anything,
            // place our last point at the end of the remaining length and abort.
            if (!Physics.Raycast(ray, out RaycastHit hit, remainingLength)) {
                _linePoints[i] = ray.GetPoint(remainingLength);
                break;
            }

            // Otherwise, put a point at the location of the hit.
            _linePoints[i] = hit.point;

            // If we hit a laser switch receiver, call that switch's OnHitByLaser method.
            var receiver = hit.collider.GetComponent<LaserSwitch>();
            if (receiver != null)
                receiver.HitByLaser(color);

            // If we didn't hit a mirror, stop here.
            if (hit.collider.CompareTag("Mirror") == false)
                break;

            // Otherwise, reflect our ray and fire again.
            remainingLength -= hit.distance;
            ray = new Ray(hit.point, Vector3.Reflect(ray.direction, hit.normal));
        }

        // Set all our points in one call. More efficient than doing it one by one.
        _line.positionCount = segmentCount + 1;
        _line.SetPositions(_linePoints);
    }
}

```

---
Tags: unity, c#, raycasting
---


# Question
Title: How does the use of marching square and wave function collapse differ in a auto tiling?
I am discovering the techniques of procedural generation. I struggle understanding on the usage of those two techniques:

* Wave Function Collapse
* Marching Squares

As I understand, both can be used to populate neighbourhood of a tile based on rules.

In the case of a game map editor where a user can "paint" a dungeon. When would you use one versus the other?

# Answer
> 1 votes
**Conventional auto-tiling** strategies aim to simplify the selection of individual tiles where two different terrain types adjoin, using rules that are local and deterministic:

* Local: only the tiles/edges/corners immediately adjacent to the one being selected can affect the decision, so the features it controls are small and don't have much internal structure.
* Deterministic: the same choice is made every time, predictably. If you have three surrounding grass tiles and one dirt, then the only tile that fits such a gap is the dirt-grass-dead-end, which is guaranteed to be selected. So it doesn't surprise or create/invent/propose anything "creative" on its own.

(This one can be bent sometimes: if we have two or more functionally-equivalent variants - like two grasses that can cover the same shapes, with slightly different weed patterns, the auto-tiler might include a coin flip to select one of the two randomly, to break up the obvious repetition.)

This means the level designer still has to manually choose where they want each terrain type, and what shapes it should form. "I want a 2-tile wide dirt road here, that turns 90 degrees left here, at a 5-tile wide river of water, and..."

The auto-tiling logic just replaces the tedium of selecting the grass-dirt 90-degree-left-outside-corner tile or the grass-dirt-90-degree-left-inside-corner tile or the grass-dirt-straight-vertical tile, letting the designer freely paint their intended terrain layout without stopping to swap selected tiles constantly.

These rules (of which there are many variants) are very simple and predictable to use, reason about, and implement - typically using simple bitmasking and indexing. For this reason they're pretty ubiquitous in tile-based game tools as a standard feature.

In these cases, the algorithm doesn't really "invent" anything creative itself. It just executes the designer's stated intention, within the limits of the tiles it has to work with.

---

**Wave Function Collapse** is a much newer algorithm, that's still finding novel and experimental uses. It allows you to fill in large chunks of tiles, even whole maps, using probability weights inspired by quantum states. That means it's:

* Non-Local: the state of a tile at one side of the map could influence the state of a tile at the far end of the map. Say you paint a river mouth at coastline, and WFC fills-in a path for that river all the way to the opposite edge of the map.
* Non-Deterministic/Unpredictable: the set of possible ways to fill in the space might be very large indeed, and we often want to use WFC to explore those options, by letting it run with different seeds and produce different outcomes. The choices it makes can sometimes be very surprising, or look similar to creative problem-solving.

Workflows for interacting with wave function collapse systems are not as standardized, but they often involve a degree of "co-creation": the level designer sets up the tiles for the parts of the level they care about, "I need an entrance here and a treasure room there," and then delegates to the algorithm the responsibility to propose one or more different ways to join these elements and fill in the connecting areas, from which they then choose the one they like, or modify it and re-run the algorithm to adapt to their change.

WFC can even run without a designer in the loop at runtime, drawing on a set of examples and constraints provided in advance to procedurally generate new levels, as seen in the game Bad North for example.

So the two approaches - although they both deal with automatic tile selection - serve very different roles in level creation. Auto-tiling is more like a convenient paintbrush, that flows smoothly and leaves an attractive edge as the artist paints on their canvas. Wave function collapse is more like an artist's assistant, to whom the creator can delegate chunks of their workload, while having slightly less direct control of the precise outcome.

---
Tags: 2d, algorithm, procedural-generation, tilemap
---


title: Unity editing List via Editor Script

text:
# Question
Title: Unity editing List via Editor Script
I am currently working on an editor script for a custom component I created, I am using UIElements to do this, the UI is constructed and working all apart from when I try to modify a list item of the component, I can add new list items just fine which is where my confusion is coming in.

The list in question is a list of "Reactions" a reaction is a class that contains an element(Eg:Fire, Water) definition and a list of actions to perform for that element, should it be affected by reactions element. It also contains a method for iterating over each action in the list and performing them.

```
[System.Serializable]
public class WidgetReaction
{
    public string reactionName;

    public BaseElement element;
    public WidgetAction currentAction;
    public List<WidgetAction> actions;
    public List<WidgetAction> Actions
    {
        get
        {
            if (actions != null)
            {
                return actions;
            }
            else
            {
                actions = new List<WidgetAction>();
                return actions;
            }
        }
    }
    public bool removeOnReact = false;
    [HideInInspector]
    public Widget affectorWidget = null;

    public IEnumerator DoActions(Widget _parentWidget)
    {
        foreach (var action in actions)
        {
            currentAction = action;

            if (currentAction != null)
            {
                yield return currentAction.Do(_parentWidget, this);
            }

        }
        yield break;
    }

    public void AddAction(WidgetAction action)
    {
        Actions.Add(action);
    }
}

```

And here is the code for Visual Element I generate for each reaction, there is another parent script that creates the rest of the UI, the reaction actions being the last one, this class is called for each 'Reaction'

```
public class ReactionsList : VisualElement
{
    Widget_Reaction_Component _Target;
    WidgetReaction_Inspector _Inspector;
    WidgetReaction _Reaction;
    SerializedObject serializedObject;

    public ReactionsList(WidgetReaction_Inspector _inspector, WidgetReaction widgetReaction, Widget_Reaction_Component target)
    {
        this._Inspector = _inspector;
        this._Reaction = widgetReaction;
        this._Target = target;

        this.serializedObject = new SerializedObject(_Target);
        this.serializedObject.Update();

        var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/ReactionsList.uxml");
        visualTree.CloneTree(this);

        var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/ReactionsList.uss");
        this.styleSheets.Add(styleSheet);

        #region Each Reaction's UI
        TextField reactionName = this.Query("ReactionName").First() as TextField;
        reactionName.value = _Reaction.reactionName;
        reactionName.RegisterCallback<ChangeEvent<string>>(
            e =>
            {
                this._Reaction.reactionName = e.newValue;

            }
        );

        ObjectField reactionElement = this.Query("ReactionElementField").First() as ObjectField;
        reactionElement.value = _Reaction.element;
        reactionElement.objectType = typeof(BaseElement);
        reactionElement.RegisterCallback<ChangeEvent<UnityEngine.Object>>(
            e =>
            {
                this._Reaction.element = (BaseElement)e.newValue;

            }
        );

        //container for actions
        VisualElement actionsContainer = this.Query("ActionsContainer").First() as VisualElement;

        if (this._Reaction.element)
        {
            this.style.backgroundColor = this._Reaction.element.color;
        }

        #endregion

        #region Each Reaction's Actions

        DisplayActions(actionsContainer);
       // DisplaySerializedActions(actionsContainer);

        #endregion

        #region End of Widget Reaction UI
        Button newActionButton = new Button();
        newActionButton.text = "Add Action";
        newActionButton.clicked += () => CreateNewActionFields();

        Button removeAllActionsButton = new Button();
        removeAllActionsButton.text = "Clear Reactions Action";
        removeAllActionsButton.clicked += () => _Reaction.Actions.Clear();

        this.Add(newActionButton);
        this.Add(removeAllActionsButton);
        #endregion

    }

    private void DisplayActions(VisualElement container)
    {

        for (int i = 0; i < this._Reaction.Actions.Count; i++)
        {
            ObjectField ObjectFieldForAction = new ObjectField();
            ObjectFieldForAction.objectType = typeof(WidgetAction);
            ObjectFieldForAction.value = this._Reaction.Actions[i];
            ObjectFieldForAction.RegisterCallback<ChangeEvent<UnityEngine.Object>>(
                e =>
                {

                    ObjectFieldForAction.value = (WidgetAction)e.newValue;
       //throws ArguementOutOfRange error, maybe because the call back is being fired at a time when the list doesnt exist?
                    this._Reaction.Actions[i] = ObjectFieldForAction.value as System.Object as WidgetAction;
                    EditorUtility.SetDirty(_Inspector);
                }
            );

            container.Add(ObjectFieldForAction);
        }
    }

    //Display the serialized actions of this objects widgetReactions list
    private void DisplaySerializedActions(VisualElement container)
    {
        //get widget reactions list from target of inspector (Widget Reaction Component)
        SerializedProperty seraliziedWidgetReactions = serializedObject.FindProperty("widgetReactions");

        for (int i = 0; i < seraliziedWidgetReactions.arraySize; i++)
        {

            //we only care about information on the current reaction
            if (seraliziedWidgetReactions.GetArrayElementAtIndex(i).exposedReferenceValue == _Reaction.element)
            {
                //get the WidgetActions list for this reaction
                SerializedProperty actionsForReaction = seraliziedWidgetReactions.GetArrayElementAtIndex(i).FindPropertyRelative("actions");

                //get each action from the list
                for (int y = 0; y < actionsForReaction.arraySize; y++)
                {
                    //this *should* be each item in the list for the current inspector target
                    SerializedProperty reactionAction = seraliziedWidgetReactions.GetArrayElementAtIndex(i).FindPropertyRelative("actions").GetArrayElementAtIndex(y);
                    WidgetAction action = reactionAction as System.Object as WidgetAction;

                    ObjectField actionField = new ObjectField();
                    actionField.objectType = typeof(WidgetAction);
                    actionField.value = action;
                    actionField.RegisterCallback<ChangeEvent<UnityEngine.Object>>(
                        e =>
                        {
                            //whenver field is updated, set the new value
                            actionField.value = (WidgetAction)e.newValue;
                            //try do same for list
                            action = (WidgetAction)e.newValue;
                            EditorUtility.SetDirty(_Inspector);
                        }
                    );

                    //add each action field to the container
                    container.Add(actionField);
                }
            }
        }

        //applying changes to parent serialized object (Widget_Reaction_Component)
        serializedObject.ApplyModifiedProperties();
    }

    //Function for Create New Action Button
    private void CreateNewActionFields()
    {
        VisualElement container = new VisualElement();
        container.style.flexGrow = 1;
        container.style.flexDirection = FlexDirection.Row;

        ObjectField newObjectField = new ObjectField();
        newObjectField.EnableInClassList("row", true);
        newObjectField.objectType = typeof(WidgetAction);
        newObjectField.value = ScriptableObject.CreateInstance<WAction_DoNothing>();
        newObjectField.RegisterCallback<ChangeEvent<UnityEngine.Object>>(
                    e =>
                    {
                        newObjectField.value = (WidgetAction)e.newValue;
                        //also add new action to objects list when field is changed
                        //this works correctly add adds a new list item serializing properly.
                        this._Reaction.Actions.Add((WidgetAction)newObjectField.value);
                        EditorUtility.SetDirty(_Inspector);
                    }
                );

        //Does nothing for now
        Button newObjectDeleteButton = new Button();
        newObjectDeleteButton.EnableInClassList("row", true);
        newObjectDeleteButton.text = "Delete Action";
        newObjectDeleteButton.style.backgroundColor = Color.red;
        newObjectDeleteButton.style.color = Color.white;

        container.Add(newObjectField);
        container.Add(newObjectDeleteButton);
        this.Add(container);
    }
}

```

As you may notice I have created two functions "DisplayActions" which iterates over the \_Reactions array for this particular editor 'target' and "DisplaySerialisedActions" to do the same for the targets SerializedObject(Widget\_Reaction\_Comp) properties (widgetReactions list).

As I said above, the code works when adding a new action (CreateNewActionFields), it serializes as it should etc, but when I try to edit an existing 'Reaction' action from the list either by directly editing the list or through ObjectField call back (DisplayActions or DisplaySerialisedActions) I get error ArguementOutOfRange and it does nothing.

Why am I getting this behaviour when every other part of the UI has worked fine, including the reaction itself(that is I can change edit/remove reactions themselves just fine), it's just the reactions action list that is causing me problems.

I am also adding a picture of the component itself incase that helps provide some context.

Edit: Incase there is any confusion over the two functions for displaying actions, I am simply trying to get the UI to react, in reality ill only be using whichever I need.

Thank you

# Answer
So I ended up figuring out what has changed I wasn't accessing the correct variable when doing my loop for one, **BUT MORE IMPORTANTLY**, If you've ever done any editor work of any kind you learn to slap EditorUtility.SetDirty(object) almost everywhere you make a change but in 5.3 this no longer works, it throws an error to console and does nothing.

Now it seems to get Unity to save the changes you need to call `Undo.RecordObject(Object);`.

So for me thats `Undo.RecordObject(_target, "Adding Reaction");` "\_target" being the currently targetted game object and the second parameter just a string describing the action.

Now this should be enough if you are editing a **prefab** but if you are editing a **prefab instance** like me then you also need to call `PrefabUtility.RecordPrefabInstancePropertyModifications(_target);`

If anyone needs I can edit with fully working script.

Here for example is where I add a reaction, to the prefabs list

```
    private void CreateNewReaction(BaseElement element)
    {
        var newReaction = new WidgetReaction();
        newReaction.reactionName = "New Reaction";
        newReaction.element = element;
        _target.widgetReactions.Add(newReaction);
        //THIS SAVES IT
        Undo.RecordObject(_target, "Adding Reaction");
        //THIS NEEDS TO BE CALLED ALSO IF YOURE WORKING WITH AN INSTANCE OF A PREFAB
        PrefabUtility.RecordPrefabInstancePropertyModifications(_target);
    }

```
> 1 votes

---
Tags: unity, c#, serialization
---


# Question
Title: Getting Parser Error: The identifier "delta" isn't declared in the current scope. in godot
this is the whole code

```
extends KinematicBody

signal health_updated(health)
signal killed()

var speed = 10
var acceleration = 10
var gravity = 0.2
var jump = 5

var mouse_sensitivity = 0.3

var direction = Vector3()
var velocity = Vector3()
var fall = Vector3()
export (float) var max_health = 100

onready var health = max_health setget _set_health
onready var head = $Head

func _ready():
    Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

func _input(event):

    if event is InputEventMouseMotion:
        rotate_y(deg2rad(-event.relative.x * mouse_sensitivity))
        head.rotate_x(deg2rad(-event.relative.y * mouse_sensitivity))
        head.rotation.x = clamp(head.rotation.x, deg2rad(-90), deg2rad(90))

func _physics_process(delta):

    direction = Vector3()

    move_and_slide(fall, Vector3.UP)

    if not is_on_floor():
        fall.y -= gravity
onready var invulnerability_timer = $invulnerabilitytimer
func damage(amount):
    if invulnerability_timer.is_stopped():
        invulnerability_timer.start()
        _set_health(health - amount)
func kill():
    pass
func _set_health(value):
    var prev_health = health
    health = clamp(value, 0, max_health)
    if health != prev_health:
        emit_signal ("health_updated", health)
        if health == 0:
            kill()
            emit_signal("killed")

    if Input.is_action_just_pressed("jump") and is_on_floor():
        fall.y = jump

    if Input.is_action_pressed("move_forward"):

        direction -= transform.basis.z

    elif Input.is_action_pressed("move_backward"):

        direction += transform.basis.z

    if Input.is_action_pressed("move_left"):

        direction -= transform.basis.x

    elif Input.is_action_pressed("move_right"):

        direction += transform.basis.x

    direction = direction.normalized()
    velocity = velocity.linear_interpolate(direction * speed, acceleration * delta)
    velocity = move_and_slide(velocity, Vector3.UP)

```

# Answer
> 2 votes
You have a lot of code in the function `func _set_health` which does not appear to be about health. It looks more like physics code, which would make more sense in `func _physics_process`.

That code also refers to a variable "delta" in this line:

```
velocity = velocity.linear_interpolate(direction * speed, acceleration * delta)

```

But a variable by that name does not seem to exist within the scope of the function `_set_health` which is the reason for that parser error. However, the function `_physics_process` has such a variable in form of a parameter which gets passed to it. So it seems like that section of code definitely belongs there instead.

---
Tags: godot, gdscript
---


# Question
Title: How to physically move a rigid body up the stairs?
When an object is controlled by a CharacterController, it is easy to make it climb ramps with a certain slope, or climb steps with a certain height.

When the object is controlled by a RigidBody instead, it can still climb ramps naturally - I just use AddForce and it walks on ramps just like on any other surface. I do not have to add any special logic for a ramp. However, it does not climb stairs. Is there a natural "physical" way to make the RigidBody climb stairs, without explicitly checking that there are stairs ahead?

# Answer
> 1 votes
In order to lift a capsule up the stair's riser, the normal force exerted by the stair corner against the rounded bottom must meet or exceed the force of gravity pulling it down.

Given a particular capsule radius \\$r\\$ and riser height \\$h\\$, both sitting on the same floor plane, the corner hits the capsule at a point relative to its center of curvature:

$$ \vec p\_{contact} = \left( \sqrt{r^2 - h^2}, h - r\right)$$

Which means the normal force will act in the direction given by the unit normal:

$$\vec n = \frac {-1} r \left( \sqrt{r^2 - h^2}, h - r\right)$$

To lift off the ground, the vertical component of this force has to equal or exceed the force of gravity, given by an acceleration \\$a\_g \< 0\\$:

$$\begin{align} f \cdot \frac {h - r} r &= m \cdot a\_g\\ f &=\frac { m \cdot a\_g \cdot r} {h - r} \end{align}$$

This will then try to push your capsule backward away from the stair by the horizontal component of the force:

$$f\_{horizontal} = \frac { m \cdot a\_g} {h - r} \sqrt{r^2 - h^2}$$

So you'll need to drive your capsule into the stair with a force greater than or equal to this amount to achieve lifting. Plus some extra to overcome losses to friction.

---
Tags: unity, physics
---


# Question
Title: How to distort an image using perlin noise?
I'm trying to generate a 2D map and currently I'm doing so by the use of voronoi diagram. The problem I found is that all biomes have really hard edges and I would like to smooth them out a bit.

Initially I was thinking smoothing out voronoi curves, which appears to be far more complex as I imagined. Then I thought about perlin distorion, which seems far more doable. Although, I'm not sure what is the best way to implement this.

This is the function I use to generate a voronoi diagram:

```
void Generate()
{
    Vector2Int[] centroids = new Vector2Int[regions.Length];
    Color[] regColors = new Color[regions.Length];
    for (int i = 0; i < regions.Length; i++)
    {
        centroids[i] = new Vector2Int(Rand.Range(0, map), Rand.Range(0, map));
        regColors[i] = regions[i].color;
    }
    Color[] colors = new Color[map * map];
    for (int x = 0; x < map; x++)
    {
        for (int y = 0; y < map; y++)
        {
            int index = x * map + y;
            colors[index] = regColors[GetClosestCentroidIndex(new Vector2Int(x, y), centroids)];
        }
    }
}
int GetClosestCentroidIndex(Vector2Int pixelPos, Vector2Int[] centroids)
{
    float smallestDst = float.MaxValue;
    int index = 0;
    for (int i = 0; i < centroids.Length; i++)
    {
        if (Vector2.Distance(pixelPos, centroids[i]) < smallestDst)
        {
            smallestDst = Vector2.Distance(pixelPos, centroids[i]);
            index = i;
        }
    }
    return index;
}

```

While doing some research I stumbled upon this website, which shows the exact result I'm trying to achieve: https://observablehq.com/@kerryrodden/image-distortion-with-perlin-noise

Can someone help me with this problem? Thank you

\[**Solved**\]

By the help of the user DMGregory, the map is now looking much better! This is the new voronoi diagram, after the distortion had been applied.

Currently, I'm using these settings, but I will probably tweak them later.
**Scale**: *10*
**Octave Count**: *1*
**Amplitude**: *4*
**Lacunarity**: *1*
**Persistence**: *1*
And for the seed, currently, I'm using just a randomly generated seed.

# Answer
First, give yourself a 2D turbulence function with parameters you can adjust to shape the noise the way you want:

```
public float baseScale = 50.0f;
public int octaveCount = 4;
public float amplitude = 5.0f;
public float lacunarity = 2.0f;
public float persistence = 0.5f;

// Arbitrary numbers to break up visible correlation between octaves / x & y
public Vector2 seed = new Vector2(-71, 37);

Vector2 Get2DTurbulence(Vector2 input) {

    input = input/baseScale + seed;
    float a = 2f * amplitude;

    Vector2 noise = Vector2.zero;

    for(int octave = 0; octave < octaveCount; octave++) {
        noise.x += a * (Mathf.PerlinNoise(input.x, input.y) - 0.5f);
        noise.y += a * (Mathf.PerlinNoise(input.x + seed.y, input.y + seed.y) - 0.5f);
        input = input * lacunarity + seed;
        a *= persistence;
    }

    return noise
}

```

Then add turbulence to your position before you use it to find the closest centroid:

```
int GetClosestCentroidIndex(Vector2Int pixelPos, Vector2Int[] centroids)
{
    Vector2 warpedPos = pixelPos + Get2DTurbulence(pixelPos);

    float smallestDst = float.MaxValue;
    int index = 0;
    for (int i = 0; i < centroids.Length; i++)
    {
        float distance = Vector2.Distance(warped, centroids[i]);
        if (distance < smallestDst)
        {
            smallestDst = distance;
            index = i;
        }
    }
    return index;
}

```
> 0 votes

---
Tags: unity, c#, perlin-noise, image-processing
---


# Question
Title: Draw animating grid with terrain deformation and variable colors
I'm trying to draw a grid around the cursor that represents buildable area.

this cursor grid, aligns to the global grid. all building placements must be on the grid and so this visual queue must aid in understanding that.

I also will have deforming terrain.

here's what I got so far, this is a grid drawing method that uses GL.Lines :

(by the way I'm using the Cartesian Coordinate system so that's why I iterated over x and y instead of x and z don't let that throw you off, y is not 3D height in the following)

```
private void drawSize50Grid(int entryX, int entryY)
{
    if (!mat)
    {
        Debug.LogError("Please Assign a material on the inspector");
        return;
    }
    int amountOfGridToDraw = 50;

    GL.Begin(GL.LINES);
    mat.SetPass(0);

    float currentX = entryX;
    float currentY = entryY;

    for (int x = 0; x < amountOfGridToDraw; x++)
    {
        for (int y = 0; y < amountOfGridToDraw; y++)
        {
            //divisionFactor is float which makes the grid the size I want (smaller than the unity visual queue when you have nothing in a scene)
            float nextX = divisionFactor/100f + currentX;
            float nextY = divisionFactor/100f + currentY;

                           // fixed height of 0.0001f, this is temporary, I'll pass height when I get there.
            var point = new Vector3(currentX, 0.0001f, currentY);
            var drawPoint2 = new Vector3(nextX, 0.0001f, currentY);
            var drawPoint3 = new Vector3(currentX, 0.0001f, nextY);

            GL.Color(Color.red);
            GL.Vertex(point);
            GL.Vertex(drawPoint2);
            if (currentY != amountOfGridToDraw)
            {
                GL.Vertex(point);
                GL.Vertex(drawPoint3);
                currentY += divisionFactor/100f;
            }
        }

        currentY = 0f;
        currentX += divisionFactor/100f;
    }
    GL.End();
}

```

here's my point conversion methods :

```
public Vector3 GetNearestPointOn3DGrid(Vector3 position)
{
    position -= transform.position;

    Vector3 result = new Vector3(
        // width
        magicFormula(position.x),
        // length
        magicFormula(position.z));

    result += transform.position;

    return result;
}

private float magicFormula (float entryPoint)
{
    float decimalPart = entryPoint % 1;
    float intergerPart = entryPoint - decimalPart;
    return Mathf.RoundToInt(decimalPart / (1 / divisionFactor)) * (1 / divisionFactor) + intergerPart;
};

```

If I call my grid in this way :

```
void OnRenderObject()
{
     drawSize50Grid(100f, 100f);
}

```

Then, when I run the game, my grid shows up starting at (LeftHand coordinate system) point 100f,0.0001f, 100f.

But `OnRenderObject()` is called only once.

This lifecycle will not allow me to have a grid that follows the cursor.

Also it seems that this is a GL.Line hard limit : they cannot be redrawn at runtime.

I realize drawing and redrawing tons of segments as the mouse zooms around is bound to be taxing to the CPU & GPU but I've tampered my expectations :

```
// I guess I would call drawGridAroundCursor() inside Update()?
// right now doing this does nothing because GL.Lines refuse to draw after OnRenderObject()
public void drawGridAroundCursor()
{
    if (camera.GetCurrentDistanceToGround() < 60f && isShiftCurrentlyHeldDown)
    {
        gridAdjustedCursor = GetNearestPointOn3DGrid(cursorRayHit);
        drawSize50Grid(gridAdjustedCursor.x, gridAdjustedCursor.z)
    }
}

```
* I'm only doing 50x50 grid (that's 4950 lines) (actually I'm willing to go down further than that 15x15 might cut it)
* I'm only rendering the grid if the camera is close to the ground (where it shows up)
* and only showing it when holding down shift.

that should limit the load.

But if there's even more things I can do to optimize I'm open to ideas, so long as it doesn't involve sacrificing correct placement of the lines.

here's what my above code WOULD look like if it rendered at real time : (camera viewing **straight** down at the terrain, also not at all to scale, the cursor is GIGANTIC in this mock-up)

And in the end here's what I'm going to do (draw from -25 -25 relative to grid-adjusted to cursorRayHit and chose a more and more transparent color the further the point are to the center of the grid) :

so obviously when the cursor moves the faded out borders follow it around but the grid points will stay in place (and go transparent when the cursor is too far away)

This effect was inspired by this :

And after I get to that step I want to add height variation to match the terrain and then add color input per cell of the grid depending on whether or not the terrain is constructible or not.

So the final solution would look something like this :

# Answer
> 3 votes
When this question was just about drawing a plain grid of lines, I said...

---

I'd be tempted to draw this with a shader on a single quad, using the world coordinates of the vertices to snap the lines to your desired intervals, no matter if the parent quad is moving in sub-grid increments.

Here's a quick shader that does this, with parameters to control the exact density of the grid lines, their offset relative to the world origin, their thickness and colour. You can control the size of the fade-out just by scaling the quad that you draw it on.

```
Shader "Unlit/WorldGrid"
{
    Properties
    {
        _ScaleShift ("Lines per Unit & Shift", Vector) = (10, 10, 0, 0)
        _Color ("Colour", Color) = (1, 0, 0, 1)
        _Thickness ("Thickness", float) = 0.5
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector"="True" }
        LOD 100

        Lighting Off
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float2 worldPos : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };

            float4 _ScaleShift;
            fixed4 _Color;
            float _Thickness;

            v2f vert (appdata v)
            {
                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);

                float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
                o.uv = 2.0f * (v.uv - 0.5f);
                o.worldPos = worldPos.xz * _ScaleShift.xy + _ScaleShift.zw;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float2 distanceFromLine = abs(frac(i.worldPos + 0.5f) - 0.5f);
                float2 speedPerPixel = fwidth(i.worldPos);

                float2 pixelsFromLine = abs(distanceFromLine / speedPerPixel);

                float opacity = 1.0f - saturate(min(pixelsFromLine.x, pixelsFromLine.y) - 0.5f * (_Thickness - 0.5f));

                float radiusSquared = dot(i.uv, i.uv);
                float falloff = max(1.0f - radiusSquared, 0.0f);

                fixed4 col = _Color;
                col.a *= opacity * falloff * falloff;

                return col;
            }
            ENDCG
        }
    }
}

```

---

But now that I have your full requirements:

* Deforms to fit terrain
* LWRP/URP Shader Graph
* Colour-coded cells based on buildable/non-buildable sites

...well, it's doable:

But we need something more complicated:

So let's unpack that, starting with a bit of prep work:

* In your camera's settings, set "Depth Texture" to "On" - that will force the camera to render the scene's depth, which we'll need for the terrain-hugging decal effect.
* Create a cube that we'll use for drawing the effect. Make it as wide in each direction as the amount of grid you want to show, and tall enough to span changes in terrain height.
* Create a new Unlit shader graph, and a material to put it on.
* Set your Unlit Master node to use Additive blending if you want glowy lines like in the gif above.
* Set up shader parameters for...

+ Grid Density (Vector 2) - how many grid cells per world unit (here I used 5, 5)
    + Grid Offset (Vector 2) - how much to shift the grid relative to Unity's grid (I used -0.5, -0.5)
    + Thickness (Vector 1) - how thick to draw the lines (0 for hairline, 1 for a bit bolder)
    + Buildable Mask (Texture 2D) - a texture as large as your building grid, containing 0/black for obstructed cells, and 1/white for open cells. You can update this in your scripts with SetPixel/SetPixels or blit quads into it as a RenderTexture to keep it up to date as your buildings change.
    + Buildable Colour / Blocked Colour (Colour) - the colours to draw the lines.

Now let's attack the graph in pieces:

**Finding our place in the world**

We start by taking a ray from the camera, through our screen pixel, and extending it as far as the stored depth in the camera's depth texture. That tells us the world-space coordinates of the terrain surface behind this part of the cube.

Then we take the xz components of this world position, and scale and shift them by our grid density/offset to convert into our building coordinate space.

**Fading Away**

The top section does the same math from the text fragment shader above, taking the building-space point, working out how far this pixel is from the nearest grid edge, and turning that into a brightness/opacity value for our line according to our thickness parameter.

The bottom section takes the worldspace point (before conversion to building space) and transforms it by the inverse of our model matrix to get it into the cube's local coordinates. Then we fade it out radially so you don't see the edges of the cube.

We multiply these two effects to get the resulting brightness/opacity of the line.

**A place to stand, a place to grow...**

The top section takes our building-space position and rounds it to an integer, so all pixels in the square sample the same building mask tile (technically point filtering should do this too, but I have sometimes found discrepancies between the hardware filter's rounding and what I get in the shader, so I like to err on the side of caution)

We then divide this by the size of our building mask texture to get a texture coordinate inside the building mask, and sample from that to find out whether we should draw this tile as green/buildable, or red/blocked.

If we just left it there though, we'd get these ugly/speckly/half-and-half lines where a buildable cell borders a blocked cell. To fix that, the group on the bottom figures out which edge we're closest to, then steps across that edge to sample the neighbouring cell on that side. We'll draw this edge red if *either* this cell *or* our closest neighbour is non-buildable.

Note that the lines headed to that Vector2 node on the bottom cross-over. This means we're doing `step(pixelsFromEdge.xy, pixelsFromEdge.yx)` \- so we get (1, 0) if we're closest to an edge between cells with an x separation, and (0, 1) if we're closest to an edge between cells with a y (z) separation.

---

By default, this will want to draw over all opaque content in your scene, but you can use Custom Render Queue setting to wedge it between your terrain and your buildings. I found setting the grid to render in queue 2501 (AlphaTest+51), and my buildings to render in 2502+ did the trick. If you're using a built-in shader, you may need to create your own material that references it, then put the Inspector in Debug mode to see the Custom Render Queue field:

---
Tags: unity, c#, grid
---


# Question
Title: Unity shader to pick 1 of 2 base colors for individual instances (picture)
I am building this scene in 3D using Unity 2019.3.13's Universal Render Pipeline. I have a block prefab that I want to instance, but I want to choose which are yellow and which are blue (you can see the materials are basically the same). How can I write a shader that will allow me to pick either yellow or blue in the editor for each one? Is this possible? What is the most optimal way to make dozens of identical blocks where the color is different for specific instances?

(I would prefer a script to a graph, something with a simple switch/boolean input and hex values: yellow: e4c658 blue: 32676a

# Answer
If you just want chequerboard alternation, we can do this with a single material, and save you making/positioning/rendering individual cubes.

You can see from the selection wireframe in this screenshot, we're drawing far fewer triangles this way than if every cube was a separate mesh with a distinct material from its neighbours. That also means less overdraw from interior faces that we never see.

Here I assume that each of your cubes is 1 unit wide, and they're placed at integer coordinates in world space. We can scale/shift the effect if you need a different grid alignment though.

```
Shader "Custom/Chequer Volume"
{
    Properties
    {
        _Color ("Color", Color) = (0.8941,0.7764,0.3450,1)
        _OtherColor("Other Color", Color) = (0.1960,0.4039,0.4156,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.7
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
            float3 worldPos;
            float3 worldNormal;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;
        fixed4 _OtherColor;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            float3 inside = round(IN.worldPos - 0.1f * IN.worldNormal);
            float parity = abs(fmod(inside.x + inside.y + inside.z, 2.0f));

            fixed4 color = lerp(_Color, _OtherColor, parity);

            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

```
> 1 votes

---
Tags: unity, shaders, materials
---


# Question
Title: When setting Stage as inputProcessor, Shaperenderer shapes are drawn stretched
I am working on making a falling sand simulation using libgdx. For drawing the individual elements I am using a ShapeRenderer and drawing rectangles.

I have begun to implement a dropdown menu to allow selection of elements to place. The functionality of the dropdown menu is working. I am able to set the inputProcessor as the stage and upon selecting the element type set the inputProcessor back to CreatorInputProcessor and I am able to successfully place elements again. The functionality is all working as expected.

However, when I set the stage with the dropdown as inputProcessor, the element rectangles become stretched. The resolution and pixel width of the window stays the same. It is not zooming in or anything. When the inputProcessor is set back to the CreatorInputProcessor the rectangles stay stretched.

Here are the things I have tried to fix this issue:

* Use every kind of ViewPort passing in both a new OrthographicCamera and also the same camera used for the game view
* Disposing of the stage after input processor is set back to CreatorInputProcessor
* Setting the projection matrix on the camera every frame just before drawing or after drawing.

I found this stack exchange question which is similar to my issue but the marked answer does not solve my problem (setting the projection matrix every frame): LibGDX - why are the shapes from my ShapeRenderer resizing with my viewport?

I am looking for some advice on how I can resolve this issue. Thanks!

Here is the relevant code snippet: https://github.com/DavidMcLaughlin208/FallingSandJava/blob/master/core/src/com/gdx/cellular/InputManager.java#L357-L399

# Answer
> 0 votes
I still am not sure exactly what this issue was. But to fix this I moved the drawing of the elements into a separate stage and actor with a custom draw function:

```
public class MatrixActor extends Actor {

    private ShapeRenderer shapeRenderer;
    private CellularMatrix matrix;

    public MatrixActor(ShapeRenderer shapeRenderer, CellularMatrix matrix) {
        this.shapeRenderer = shapeRenderer;
        this.matrix = matrix;
    }

    @Override
    public void draw (Batch batch, float parentAlpha) {
        batch.end();
        shapeRenderer.setProjectionMatrix(getStage().getCamera().combined);
        matrix.drawAll(shapeRenderer);
        batch.begin();
    }
}

```

The key part was to end the batch then draw with the ShapeRenderer and then start the batch again.

I don't know why this resolved the issue but it has. There must have been something conflicting with the batch and the shaperenderer.

---
Tags: libgdx, rendering
---


# Question
Title: Unity Shader Graph combine textures with transparency
I have two transparent textures. border.png and text png. They are both white images with transparency for the parts I dont want to affect. What I want to achieve in shadergraph is to:

1: Put both textures on top of each other.
2: Be able to adjust each textures color, including the textures to be white or black.

What I get is point 1, but if I try to put the color as black the texture becomes invisible (probably has something to do with transparency and how it is processed with black and white ...)

This is the best I managed to achieve with shadergraph but I still cant get the text color to be black. I have pretty much guessed my way till here so would appreciate if anyone can tell me if this is even the correct path to continue on...

# Answer
Looks like you're just using the wrong blend mode and ordering in your last Blend node. Just do the same thing you did you draw the border over the background, to draw the text over them both:
> 1 votes

---
Tags: unity, textures, unity-shader-graph
---


# Question
Title: How to find the client's monitor valid refresh rates with Unreal Blueprints?
I am making a settings menu. This includes a `combo box` where you can change the refresh rate setting.

How do I find out the maximum allowable refresh rate of the current user's monitor, using Blueprints?

# Answer
Upon consultation with external sources, I came across this code for a C++ function library that exposes the functionality in DMGregory's answer to Blueprints:

https://nerivec.github.io/old-ue4-wiki/pages/get-available-screen-resolutions-in-blueprints.html

The post reads:

---

Get Available Screen Resolutions in Blueprints

Contents

1. Overview
2. Code

2.1. Header File

2.2. Cpp File

**Overview**

The following Blueprint Node is based on the function provided by Rama, see . The provided function has the limitation that you cannot use it in your own Blueprint Library. The reason is because the FScreenResolutionRHI Type is not a BlueprintType. As I required such a function for my options UMG widget I wrote it, tested it and decided to share it.

**Code**

The following code is meant to be included in your own Blueprint Library. If you do not know how to make a Blueprint Library I recommend you read

**Header File**

First you declare the new FScreenResolutionRHI type. As mentioned in the comments it is not an exact duplicate of FScreenResolutionRHI. The reason is that when I used uint32 I was not able to use break or make nodes. My guess is that the Blueprint's Integer Type is defined as int32 in c++ and thus is not compatible with uint32. If someone can confirm this feel free to do.

```
/**
 * Screen Resolution
 * @remark Engine type is not meant for blueprints so we replicate the type.
 * @remark The Engine type uses uint32 but we need to use int32. Otherwise it won't be possible to break/make this type.
 */
USTRUCT(BlueprintType)
struct FScreenResolutionRHIBP
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ScreenResolution)
    int32 Width;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ScreenResolution)
    int32 Height;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ScreenResolution)
    int32 RefreshRate;

    FScreenResolutionRHIBP()
    {
        Width = Height = RefreshRate = 0;
    }
};

/**
 * Retrieve a sorted list of all screen resolutions supported by the player's display adapter.
 *
 * @returns the array of all supported screen resolutions.
 */
UFUNCTION(BlueprintPure, Category = Utility)
static TArray<struct FScreenResolutionRHIBP> GetDisplayAdapterScreenResolutions();

```

**Cpp File**

```
#include "RHI.h"

...

TArray<FScreenResolutionRHIBP> YourBlueprintLibrary::GetDisplayAdapterScreenResolutions()
{
    TArray<FScreenResolutionRHIBP> ResolutionsToReturn;
    FScreenResolutionArray Resolutions;
    if (RHIGetAvailableResolutions(Resolutions, false))
    {
        // Preallocate just enough memory to store all elements
        ResolutionsToReturn.Reserve(Resolutions.Num());

        for (const FScreenResolutionRHI& EachResolution : Resolutions)
        {
            FScreenResolutionRHIBP resolution;
            resolution.Width = EachResolution.Width;
            resolution.Height = EachResolution.Height;
            resolution.RefreshRate = EachResolution.RefreshRate;

            ResolutionsToReturn.Add(resolution);
        }
    }

    return ResolutionsToReturn;
}

```

Enjoy!

-- ( ) 13:27, 18 January 2015 (UTC)
> 1 votes

# Answer
From the docs, it looks like you can use the FScreenResolutionRHI data structures fetched by RHIGetAvailablrResolutions, each of which reports a refresh rate.

There's a code sample on this wiki page that looks useful:

```
static FORCEINLINE void GetDisplayAdapterScreenResolutions(FScreenResolutionArray& Resolutions) {
    if (RHIGetAvailableResolutions(Resolutions, false)) {
        for (const FScreenResolutionRHI& EachResolution : Resolutions) {
            UE_LOG(YourLog, Warning, TEXT("DefaultAdapter - %4d x %4d @ %d"), EachResolution.Width, EachResolution.Height, EachResolution.RefreshRate);
        }
    } else {
        UE_LOG(YourLog, Error, TEXT("Screen Resolutions could not be obtained"));
    }
}

```
> 2 votes

---
Tags: unreal-4, unreal, frame-rate, blueprints
---