So I have this helper script that I use to move points around manually while debugging:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class MovablePoints : MonoBehaviour
{
public List<Vector2> points = new List<Vector2>();
public List<int> moveablePoints = new List<int>();
[Range(.01f, 1f)] public float selectionRadius = .05f;
public bool selectionActive;
public Vector2 clickedPos;
public List<Vector2> offsets = new List<Vector2>();
private void Update()
{
Vector2 mosPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Input.GetMouseButtonDown(0))
{
clickedPos = mosPos;
for (int i = 0; i < points.Count; i++)
{
Vector2 point = points[i];
if (IsPointInRange(point, mosPos))
{
if (!moveablePoints.Contains(i))
{
offsets.Add(point - clickedPos);
moveablePoints.Add(i);
}
}
}
}
if (Input.GetMouseButton(0))
{
for (int i = 0; i < moveablePoints.Count; i++)
{
Vector2 offset = offsets[i];
points[moveablePoints[i]] = mosPos + offset;
}
}
if (Input.GetMouseButtonUp(0))
{
offsets.Clear();
moveablePoints.Clear();
}
}
[Range(.001f, .1f)] public float gizmoSize = .05f;
void OnDrawGizmos()
{
if (selectionActive)
{
Color selectionColor = Color.white;
selectionColor.a = 0.65f;
Handles.color = selectionColor;
if (Input.GetAxis("Mouse ScrollWheel") > 0f && selectionRadius < 1)
selectionRadius += .01f;
if (Input.GetAxis("Mouse ScrollWheel") < 0f && selectionRadius > 0)
selectionRadius -= .01f;
Vector2 mosPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Handles.DrawWireDisc(mosPos, new Vector3(0, 0, 1), selectionRadius);
for (int i = 0; i < points.Count; i++)
{
Vector2 point = points[i];
if (IsPointInRange(point, mosPos))
{
if (Input.GetMouseButton(0) && moveablePoints.Contains(i))
Gizmos.color = Color.green;
else
Gizmos.color = Color.red;
}
else
Gizmos.color = Color.white;
Gizmos.DrawSphere(point, gizmoSize);
}
}
}
bool IsPointInRange(Vector2 point, Vector2 mosPos)
{
float dx = Mathf.Abs(point.x - mosPos.x);
float dy = Mathf.Abs(point.y - mosPos.y);
if (dx > selectionRadius)
return false;
if (dy > selectionRadius)
return false;
if (dx + dy <= selectionRadius)
return true;
if (Mathf.Pow(dx, 2) + Mathf.Pow(dy, 2) <= Mathf.Pow(selectionRadius, 2))
return true;
return false;
}
}
This an example of how I use and subscribe points to the "Moveable Points"
public Vector2 A = new Vector2();
public Vector2 B = new Vector2();
public Vector2 C = new Vector2();
private void Start()
{
movablePoints.points.Add(A);
movablePoints.points.Add(B);
movablePoints.points.Add(C);
}
void Update()
{
A = movablePoints.points[0];
B = movablePoints.points[1];
C = movablePoints.points[2];
}
However, if multiple scripts are adding points to the MoveablePoints Script, it gets quite hard to remember what index is where. Is there a way to have the MoveablePoints script update the values of the subscriber automatically? Perhaps through reference?
1 Answer 1
I don't have experience with unity but what is the problem if you make a class represent a point to collect information about each point (position, offset, color,... etc.)
public class Point
{
public Vector2 Position { get; set; } = new(0, 0);
public Vector2 Offset { get; set; } = new(0, 0);
public Color Color { get; set; } = Color.white;
public bool IsMoving { get; set; } = false;
}
now you can git ride of this three lists
public List<Vector2> points = new List<Vector2>();
public List<int> moveablePoints = new List<int>();
public List<Vector2> offsets = new List<Vector2>();
and only have single list that hold information you need
public List<Point> points = new();
simplify code
Due to Point
class now you can get more readable update method
private void Update()
{
Vector2 mosPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Input.GetMouseButtonDown(0))
{
foreach(var point in points)
{
if (IsPointInRange(point.Position, mosPos))
{
point.IsMoving = true;
point.Offset = point.Position - mosPos;
}
}
}
if (Input.GetMouseButton(0))
{
foreach(var point in points)
{
if (point.IsMoving)
point.Position += mosPos + point.Offset;
}
}
if (Input.GetMouseButtonUp(0))
{
foreach (var point in points)
{
point.IsMoving = false;
}
}
}
for the following code
void OnDrawGizmos()
{
if (selectionActive)
{
//.. all the code
}
}
it would be cleaner if you use Inverted "if" statement to reduce nesting (one less indentation)
void OnDrawGizmos()
{
if (!selectionActive) return;
//.. all the code
}
for the following pice of code
for (int i = 0; i < points.Count; i++)
{
Vector2 point = points[i];
if (IsPointInRange(point, mosPos))
{
if (Input.GetMouseButton(0) && moveablePoints.Contains(i))
Gizmos.color = Color.green;
else
Gizmos.color = Color.red;
}
else
Gizmos.color = Color.white;
Gizmos.DrawSphere(point, gizmoSize);
}
you can drop the nesting because they are not good for readability as following
foreach (var point in points)
{
bool IsUnderSelectedArea = IsPointInRange(point.Position, mosPos);
if (point.IsMoving)
Gizmos.color = Color.green;
else if (IsUnderSelectedArea)
Gizmos.color = Color.red;
else
Gizmos.color = Color.white;
Gizmos.DrawSphere(point. Position, gizmoSize);
}
final advice
you shoud move IsPointInRange
to Be in the Point
class
public class Point
{
public Vector2 Position { get; set; } = new(0, 0);
public Vector2 Offset { get; set; } = new(0, 0);
public Color Color { get; set; } = Color.white;
public bool IsMoving { get; set; } = false;
public bool IsInRangeOfmose(Vector2 mosPos, float radiusRange)
{
float dx = Mathf.Abs(Position.x - mosPos.x);
float dy = Mathf.Abs(Position.y - mosPos.y);
if (dx > radiusRange)
return false;
if (dy > radiusRange)
return false;
if (dx + dy <= radiusRange)
return true;
if (Mathf.Pow(dx, 2) + Mathf.Pow(dy, 2) <= Mathf.Pow(radiusRange, 2))
return true;
return false;
}
}
this will lead to the following syntex
point.IsInRangeOfmose(mosPos, selectionRadius);
Explore related questions
See similar questions with these tags.