Fixed smart unit movement with planetary surface movement & cohesion rules

This commit is contained in:
2024-12-16 08:18:19 -06:00
parent 66cf832743
commit 9fc858fb81
5 changed files with 129 additions and 41 deletions

View File

@@ -4,6 +4,7 @@ using UnityEngine;
using DataStructures.ViliWonka.KDTree;
using System;
using System.Text;
using UnityEditor.Search;
public class Planet : MonoBehaviour
{
@@ -11,6 +12,7 @@ public class Planet : MonoBehaviour
private LineRenderer _lineRenderer;
private CircleCollider2D _circleCollider;
private Network _network;
public KDQuery Query => _query;
private KDQuery _query;
public KDTree Tree => _tree;
private KDTree _tree;
@@ -35,10 +37,8 @@ public class Planet : MonoBehaviour
void Start()
{
while (_units.Count < 10)
while (_units.Count < 16)
SpawnUnit();
InvokeRepeating("ChangeUnits", 0.0f, 1f);
}
void OnMouseDown()
@@ -53,9 +53,9 @@ public class Planet : MonoBehaviour
return (Vector2)transform.position + new Vector2(Mathf.Cos(theta), Mathf.Sin(theta)) * radius;
}
public float GetUnitAngle(Unit unit)
public float GetAngle(Vector2 position)
{
var angle = Mathf.Atan2(unit.transform.position.y, unit.transform.position.x) * Mathf.Rad2Deg;
var angle = Mathf.Atan2(position.y - transform.position.y, position.x - transform.position.x) * Mathf.Rad2Deg;
return angle < 0 ? angle + 360 : angle;
}

View File

@@ -1,74 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Quaternion = UnityEngine.Quaternion;
using Random = UnityEngine.Random;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;
public class Unit : MonoBehaviour
{
private Planet planet;
private Vector2 planetaryVelocity; // X: rotational, Y: altitude
public float edgeWidth;
public Color fillColor = Color.white;
public Color edgeColor = Color.white;
public float Size;
public int TreeIndex;
private float RotationSpeed;
private float BobbingOffset;
private Vector2 _velocity = Vector3.up;
private float timeOffset;
void Start()
{
Render();
_velocity = Random.insideUnitCircle.normalized;
planet = GetComponentInParent<Planet>();
planetaryVelocity = new Vector2(0, 0)
timeOffset = Random.Range(0, (float)(2 * Math.PI));
}
private Vector2 SteerTowards(Vector2 vector)
{
x = (Random.value > 0.5f ? 1 : -1) * 32 * Random.Range(0.8f, 1.2f),
};
RotationSpeed = Random.value > 0.5f ? 1 : -1 * Random.Range(0.8f, 1.2f) * 4f;
BobbingOffset = Random.Range(0, (float)(2 * Math.PI));
Vector2 v = vector.normalized * 1 - _velocity;
var clamped = Vector2.ClampMagnitude(v, 1);
Debug.Log($"SteerTowards {planet.name}/{name} Vector: {vector}, Modified Vector: {v}, Cur Velocity: {_velocity}, Clamped Vector: {clamped}");
return clamped;
}
void Update()
{
// Rotate itself slightly
transform.Rotate(new Vector3(0, 0, Time.deltaTime * RotationSpeed));
var acceleration = Vector2.zero;
transform.Translate(Vector3.up * Time.deltaTime);
// var upcomingAngle = planet.GetAngle(transform.position + (Vector3)_velocity);
// var angleTarget = planet.GetSurfacePosition(upcomingAngle, 0.4f);
// acceleration -= angleTarget;
// Get distance from planet
var targetDistance = (Mathf.Sin(Time.time * 0.5f + timeOffset) + 1) / 2f;
var surfaceTarget = planet.GetSurfacePosition(planet.GetAngle((Vector2)transform.position + _velocity), targetDistance);
var surfaceTargetVector = ((Vector2)transform.position - surfaceTarget).normalized;
var distance = Vector2.Distance(transform.position, planet.transform.position) - planet.Size / 100f;
var maxDistance = 1f;
var minDistance = 0.2f;
// var vectorMultiplier = Mathf.LerpUnclamped(1f, 1.5f, 2f * Math.Abs(targetDistance - distance) / targetDistance);
// var vectorMultiplier = Mathf.LerpUnclamped(0.5f, 1f, distance < targetDistance ? 0.3f / distance : distance / 0.2f);
surfaceTargetVector *= 1.5f;
acceleration -= surfaceTargetVector;
bool isTooFar = distance > maxDistance;
bool isTooClose = distance < minDistance;
// If incorrect distance, rotate
if (isTooFar || isTooClose)
if (TreeIndex == 0)
{
var directionToPlanet = (planet.transform.position - transform.position).normalized;
var projectionOnRight = Vector3.Dot(directionToPlanet, transform.right);
var planetOnRight = projectionOnRight < 0;
var direction = planetOnRight == isTooFar ? 1 : -1;
var turningSpeed = 200f;
if (isTooClose) turningSpeed *= 3;
else if (isTooFar) turningSpeed *= (distance - maxDistance);
transform.Rotate(new Vector3(0, 0, direction * turningSpeed * Time.deltaTime));
// var angle = Mathf.Atan2(transform.position.y, transform.position.x) * Mathf.Rad2Deg;
// angle += Random.Range(-10, 10);
// transform.rotation = Quaternion.Euler(0, 0, angle);
Debug.Log($"{planet.name} Acceleration: {acceleration}, Velocity: {_velocity}");
}
Vector2 newVelocity = _velocity + acceleration * Time.deltaTime;
float speed = newVelocity.magnitude;
Vector2 dir = newVelocity / speed;
speed = Mathf.Clamp(speed, 0.5f, 1.5f);
_velocity = dir * speed;
var results = new List<int>();
planet.Query.Radius(planet.Tree, transform.position, 0.1f, results);
Vector2 away = Vector2.zero;
foreach (var unitIndex in results)
{
if (unitIndex == TreeIndex) continue;
var diff = (Vector2)(planet.Tree.Points[unitIndex] - transform.position);
away -= diff.normalized;
}
acceleration += away * 0.5f;
transform.eulerAngles = new Vector3(0, 0, Mathf.Rad2Deg * -Mathf.Atan2(_velocity.x, _velocity.y));
transform.position += (Vector3)_velocity * Time.deltaTime;
planet.Tree.Points[TreeIndex] = transform.position;
// var angle = planet.GetAngle(transform.position);
// var forwardAngle = planet.GetAngle(transform.forward);
// Get distance from planet
// var distance = Vector2.Distance(transform.position, planet.transform.position) - planet.Size / 100f;
// var maxDistance = 1f;
// var minDistance = 0.2f;
// bool isTooFar = distance > maxDistance;
// bool isTooClose = distance < minDistance;
// var steerTarget = Vector3.zero;
// If incorrect distance, rotate
// if (isTooFar || isTooClose)
// {
// var directionToPlanet = (planet.transform.position - transform.position).normalized;
// var projectionOnRight = Vector3.Dot(directionToPlanet, transform.right);
// var planetOnRight = projectionOnRight < 0;
// steerTarget = planetOnRight ? transform.right : -transform.right;
// var direction = planetOnRight == isTooFar ? 1 : -1;
// var turningSpeed = 200f;
// if (isTooClose) turningSpeed *= 3;
// else if (isTooFar) turningSpeed *= (distance - maxDistance);
// transform.Rotate(new Vector3(0, 0, direction * turningSpeed * Time.deltaTime));
// if (steerTarget == Vector3.zero)
// steerTarget = transform.up;
// var angle = new Vector3(0, 0, Mathf.Rad2Deg * -Mathf.Atan2(steerTarget.x, steerTarget.y));
// transform.eulerAngles = Vector3.Lerp(transform.eulerAngles, angle, Time.deltaTime * 2f);
// transform.position += transform.up * Time.deltaTime;
}
public void OnDrawGizmos()
{
// Draw a line forward
Gizmos.color = Color.red;
Gizmos.DrawLine(transform.position, transform.position + transform.up);
var surfaceTarget = planet.GetSurfacePosition(planet.GetAngle((Vector2)transform.position + _velocity), 0.4f);
Gizmos.color = Color.blue;
Gizmos.DrawLine(transform.position, surfaceTarget);
var velocityPosition = transform.position + (Vector3)_velocity;
Gizmos.color = Color.green;
Gizmos.DrawLine(transform.position, velocityPosition);
// Draw the angle from the planet center to the unit
// var angle = planet.GetAngle(transform.position);
// // Draw the angle from the unit's immediate forward to the planet center
// var forwardAngle = planet.GetAngle(transform.position - transform.up);
// var distance = Vector2.Distance(transform.position, planet.transform.position) - planet.Size / 100f;
// Gizmos.color = Color.red;
// Gizmos.DrawLine(planet.transform.position, planet.GetSurfacePosition(angle, distance));
// Gizmos.color = Color.green;
// Gizmos.DrawLine(planet.transform.position, planet.GetSurfacePosition(forwardAngle, distance));
// // Draw a line forward
// Gizmos.color = Color.red;
// Gizmos.DrawLine(transform.position, transform.position + transform.up);
}
private void OnDestroy()
@@ -131,4 +202,6 @@ public class Unit : MonoBehaviour
lineRenderer.positionCount = mesh.vertices.Length;
lineRenderer.SetPositions(mesh.vertices);
}
}

View File

@@ -13,3 +13,18 @@ A simple puzzle game about growth.
- Scroll to lower/raise the total percentage of units.
- Drag to another planet, release to send units.
- Until units arrive, they won't be selectable or part of the usable population on a planet.
## Planet Selection
1. Click on a Planet
2. Planet emits signal to Network
3. Network pulls Selection GameObject into view, overhead planet
4. Network takes all scroll key inputs, re-renders Selection gameobject to fit percentage
5. Click on another planet (to send units), or same one (to cancel)
6. Network sends signal to Planet to send units
7. Or if cancelled, Selection gameObject is hidden
8. If sent, Planet tells units to start moving to another planet
## Unit Combat
All units are placed inside datastructure