- Home /
Is there a way to optimize this else ifs tree? If there is, what would be the best?
Hello, I'm new to Unity and C# and currently making a stealth sim.
This is a part of a script that makes it's sprite match it's npc's walk direction. It is being called in Update() and what it does it taking npc's position a frame before and at the moment and compares them, deciding which coordinate has changed more and how. I can't seem to figure out how to make this another way, if you know how to, please, help me. Thanks in advance!
void SpriteUpdate()
{
nowPos = transform.position;
/* Code below is made in case
if coordinates are negative, since
otherwise it would return reversed
direction
*/
if(prevPos.x <= 0)
{
xDiff = Mathf.Abs(prevPos.x) - Mathf.Abs(nowPos.x);
}
else
{
xDiff = Mathf.Abs(nowPos.x) - Mathf.Abs(prevPos.x);
}
if(prevPos.y <= 0)
{
yDiff = Mathf.Abs(prevPos.y) - Mathf.Abs(nowPos.y);
}
else
{
yDiff = Mathf.Abs(nowPos.y) - Mathf.Abs(prevPos.y);
}
// Sprite changing part
if(Mathf.Abs(xDiff) > Mathf.Abs(yDiff))
{
if(xDiff > 0)
{
GetComponent<SpriteRenderer>().sprite = sprites[0]; //Right look sprite
VisionField.transform.localPosition = new Vector2(3, 0);
}
else if(xDiff < 0)
{
GetComponent<SpriteRenderer>().sprite = sprites[1]; //Left look sprite
VisionField.transform.localPosition = new Vector2(-3, 0);
}
}
else if(Mathf.Abs(yDiff) > Mathf.Abs(xDiff))
{
if(yDiff > 0)
{
GetComponent<SpriteRenderer>().sprite = sprites[2]; //Up look sprite
VisionField.transform.localPosition = new Vector2(0, 3);
}
else if(yDiff < 0)
{
GetComponent<SpriteRenderer>().sprite = sprites[3]; //Down look sprite
VisionField.transform.localPosition = new Vector2(0, -3);
}
}
else
{
GetComponent<SpriteRenderer>().sprite = sprites[4]; // Idle sprite
VisionField.transform.localPosition = new Vector2(0, 0);
}
}
Answer by xxmariofer · Nov 24, 2020 at 11:33 AM
I have tried to reuse your code so its easier for you to understand, but it is untested could have someerrors
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyPatrolingScript : MonoBehaviour
{
public bool shouldMove = false;
public float speed;
public float waitTime;
private float waitingTime;
public GameObject VisionField;
[HideInInspector]
public bool isAlive = true;
public Transform[] points;
public bool reverseOnLoop;
[SerializeField]
private int currentPoint;
public Sprite[] sprites;
private Vector2 prevPos;
private Vector2 nowPos;
private float xDiff;
private float yDiff;
private SpriteRenderer renderer;
void Start()
{
waitingTime = waitTime;
renderer = GetComponent<SpriteRenderer>();
}
void Update()
{
if (isAlive && shouldMove)
{
prevPos = transform.position;
transform.position = Vector2.MoveTowards(transform.position, points[currentPoint].position,
speed * Time.deltaTime);
GetNextPoint();
}
if (!isAlive)
{
Death();
}
}
void Death()
{
Destroy(VisionField.gameObject);
//TODO: add animator controller
}
void GetNextPoint()
{
if (Vector2.Distance(transform.position, points[currentPoint].position) < 0.2f) //if close to point
{ // get next point
if (waitingTime <= 0)
{
waitingTime = waitTime;
Vector3 prevPoint = points[currentPoint].position;
if (currentPoint < points.Length - 1)
{
currentPoint += 1;
}
else
{
if (reverseOnLoop)
{
System.Array.Reverse(points); //reversing to go all the way back
currentPoint = 0;
}
else
{
currentPoint = 0;
}
}
Vector3 point = points[currentPoint].position;
if (prevPoint.x <= 0)
{
xDiff = Mathf.Abs(prevPoint.x) - Mathf.Abs(point.x);
}
else
{
xDiff = Mathf.Abs(point.x) - Mathf.Abs(prevPoint.x);
}
if (prevPos.y <= 0)
{
yDiff = Mathf.Abs(prevPoint.y) - Mathf.Abs(point.y);
}
else
{
yDiff = Mathf.Abs(point.y) - Mathf.Abs(prevPoint.y);
}
if (Mathf.Abs(xDiff) > Mathf.Abs(yDiff))
{
if (xDiff > 0)
{
//To be replaced with animation
renderer.sprite = sprites[0]; //Right look sprite
VisionField.transform.rotation = Quaternion.Euler(new Vector3(0f, 0f, 180f));
//rotation field of view
}
else if (xDiff < 0)
{
renderer.sprite = sprites[1]; //Left look sprite
VisionField.transform.rotation = Quaternion.Euler(new Vector3(0f, 0f, 0f));
}
}
else if (Mathf.Abs(yDiff) > Mathf.Abs(xDiff))
{
if (yDiff > 0)
{
renderer.sprite = sprites[2]; //Up look sprite
VisionField.transform.rotation = Quaternion.Euler(new Vector3(0f, 0f, -90f));
}
else if (yDiff < 0)
{
renderer.sprite = sprites[3]; //Down look sprite
VisionField.transform.rotation = Quaternion.Euler(new Vector3(0f, 0f, 90f));
}
}
}
else
{
renderer.sprite = sprites[4];
waitingTime -= Time.deltaTime; //idling after reaching the point
}
}
}
}
Answer by Happy-Zomby · Nov 23, 2020 at 02:02 PM
Hi, I'm not sure why your sprite is not just a child object of your NPC? Just drag and drop it the sprite on the NPC in the project window. Remove this script and see if that works.
Hi, the script is not about moving the sprite, but changing its appearance to match moving direction. Sorry if that wasn't clear
you should change the sprite when you get the input for the npc not comparing how much it did move, also catch references as @Happy-Zomby sugested
Hello, thanks for answering. Again, sorry for not being clear. This is my first time asking for help so I may be super bad at making up precise questions.
NPC just patrols the area from point1 to point2 and so on with Vector2.$$anonymous$$oveTowards(). It doesn't have input from the player. Original player in-game instance has this system implemented using animator's blend tree. Btw this script is slightly outdated since I changed a lot, but the core else ifs tree, sadly, is still there. I'm currently adding a animator for npcs, but this wouldn't solve this else ifs problem.
For some reason you gave me the idea of calculating not the npc's positions between frames, but the position difference between the points after npc reaches one. Would this make sence?
EDIT: corrected some grammar
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
One big script or lots of small ones? 0 Answers
How many objects is too many? 2 Answers
Too much Instantiate! 0 Answers