Skip to content

Instantly share code, notes, and snippets.

@hyakugei
Created October 16, 2020 13:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hyakugei/9e5647c283236ad37149ad0aec00972b to your computer and use it in GitHub Desktop.
Save hyakugei/9e5647c283236ad37149ad0aec00972b to your computer and use it in GitHub Desktop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class Repulser : MonoBehaviour
{
[SerializeField]
Collider[] colliderList;
[SerializeField]
Rigidbody rb;
[SerializeField]
float overlapRadius = 1f;
[SerializeField]
LayerMask layerMask;
[SerializeField]
LayerMask finalLayer;
[SerializeField]
float repulseForce = 1f;
[SerializeField]
float spawnStateTime = .1f;
enum State
{
Spawn,
Disperse,
Solid
}
State state = State.Spawn;
static Collider[] items = new Collider[10];
static int overlappingItemCount;
static int itemCounter = 0;
static Vector3 force = Vector3.zero;
float accumulator;
int initialLayer;
private void Awake()
{
initialLayer = gameObject.layer;
}
private void OnEnable()
{
gameObject.layer = initialLayer;
// reset object layer.
state = State.Spawn;
}
// Update is called once per frame
void FixedUpdate()
{
if (state == State.Spawn)
{
accumulator += Time.deltaTime;
if (accumulator >= spawnStateTime)
{
accumulator = 0;
state = State.Disperse;
}
return;
}
else if (state == State.Disperse)
{
overlappingItemCount = Physics.OverlapSphereNonAlloc(this.transform.position, overlapRadius, items, layerMask, QueryTriggerInteraction.Collide);
if (overlappingItemCount > 0)
{
// still intersecting
force = Vector3.zero;
itemCounter = 0;
for(int i = 0; i < overlappingItemCount; i++)
{
if (Contains(colliderList, items[i])) continue;
itemCounter++;
force += (this.transform.position - items[i].transform.position);
}
if(itemCounter == 0)
{
// no valid colliders.
state = State.Solid;
return;
}
// bit of randomness
force += Random.insideUnitSphere;
rb.AddForce(force.normalized * repulseForce * Time.deltaTime, ForceMode.Force);
accumulator = 0;
}
else
{
state = State.Solid;
}
return;
}
else if (state == State.Solid)
{
this.gameObject.layer = finalLayer;
this.enabled = false; // stop getting updates.
}
}
private void OnDrawGizmos()
{
Color c = Color.white;
if (state == State.Spawn) c = Color.red;
else if (state == State.Disperse) c = Color.yellow;
else if (state == State.Solid) c = Color.green;
Gizmos.color = c;
Gizmos.DrawSphere(this.transform.position, overlapRadius);
}
static bool Contains(Collider[] list, Collider toCheck)
{
for(int i = 0; i < list.Length; i++)
{
if (list[i] == toCheck) return true;
}
return false;
}
}
@hyakugei
Copy link
Author

Used to allow items (rigidbody items) to be spawned overlapping, but then to separate and become fully solid and interacting again. Requires a physics layer which interacts with the "world", but not itself. This is what the spawned item would start with for its layer. Once it is no longer in touch with other objects of its own layer, it then transitions to the "world" layer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment