- Floor map markers now react to round end much more consistently and reliably.
317 lines
6.6 KiB
C#
317 lines
6.6 KiB
C#
|
|
using UdonSharp;
|
|
using UnityEngine;
|
|
using VRC.SDK3.Components;
|
|
using VRC.SDK3.Data;
|
|
using VRC.SDK3.UdonNetworkCalling;
|
|
using VRC.SDKBase;
|
|
using VRC.Udon.Common.Interfaces;
|
|
|
|
|
|
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
|
|
public class FloorMapMarker : UdonSharpBehaviour
|
|
{
|
|
[SerializeField] private GameManagerRound3 _GameManager;
|
|
|
|
[SerializeField] private Material _UnlitLampMaterial;
|
|
[SerializeField] private Material _LitLampMaterial;
|
|
|
|
[UdonSynced, SerializeField, FieldChangeCallback(nameof(Active))] private bool _Active = false;
|
|
[UdonSynced, FieldChangeCallback(nameof(IsGrabbed))] private bool _IsGrabbed = false;
|
|
[UdonSynced, FieldChangeCallback(nameof(IsLit))] private bool _IsLit = false;
|
|
|
|
[UdonSynced] private bool _EnableCollisionChecks = false;
|
|
|
|
[UdonSynced] private bool _UsedUp = false;
|
|
private int _CollisionCheckCounter = 0;
|
|
private int _NoCollisionCounter = 0;
|
|
private DataList _CollidingLocations = new DataList();
|
|
|
|
private Rigidbody _RigidBodyComponent;
|
|
private VRCPickup _PickupComponent;
|
|
private MeshRenderer _MarkerMesh;
|
|
|
|
private VRCPlayerApi _CurrentOwner;
|
|
|
|
private const int MAX_REPEAT_COLLISION_CHECKS = 3;
|
|
private const int MAX_CHECKS_WITH_NO_COLLISIONS = 6;
|
|
private const float TIME_BETWEEN_REPEAT_COLLISION_CHECKS = 0.15f;
|
|
|
|
|
|
void Start()
|
|
{
|
|
_RigidBodyComponent = GetComponent<Rigidbody>();
|
|
_PickupComponent = GetComponent<VRCPickup>();
|
|
_MarkerMesh = GetComponent<MeshRenderer>();
|
|
|
|
_CurrentOwner = Networking.GetOwner(gameObject);
|
|
}
|
|
|
|
public override void OnOwnershipTransferred(VRCPlayerApi Player)
|
|
{
|
|
_CurrentOwner = Player;
|
|
base.OnOwnershipTransferred(Player);
|
|
}
|
|
|
|
|
|
[NetworkCallable]
|
|
public void Initialise()
|
|
{
|
|
_RigidBodyComponent.constraints = RigidbodyConstraints.None;
|
|
transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
|
|
SetPickupable(false);
|
|
|
|
Active = false;
|
|
IsGrabbed = false;
|
|
IsLit = false;
|
|
|
|
_EnableCollisionChecks = false;
|
|
_UsedUp = false;
|
|
|
|
_CollisionCheckCounter = 0;
|
|
_NoCollisionCounter = 0;
|
|
_CollidingLocations.Clear();
|
|
|
|
RequestSerialization();
|
|
}
|
|
|
|
[NetworkCallable]
|
|
public void SetPickupable(bool Pickupable)
|
|
{
|
|
_PickupComponent.pickupable = Pickupable;
|
|
}
|
|
|
|
|
|
public void OnTriggerEnter(Collider OtherCollider)
|
|
{
|
|
FloorMapLocation Location = OtherCollider.GetComponent<FloorMapLocation>();
|
|
if (Location != null)
|
|
{
|
|
_CollidingLocations.Add(Location);
|
|
_NoCollisionCounter = 0;
|
|
}
|
|
}
|
|
|
|
public void OnTriggerExit(Collider OtherCollider)
|
|
{
|
|
FloorMapLocation Location = OtherCollider.GetComponent<FloorMapLocation>();
|
|
if (Location != null)
|
|
{
|
|
_CollidingLocations.Remove(Location);
|
|
}
|
|
}
|
|
|
|
public override void OnPickup()
|
|
{
|
|
IsGrabbed = true;
|
|
|
|
base.OnPickup();
|
|
}
|
|
|
|
public override void OnDrop()
|
|
{
|
|
IsGrabbed = false;
|
|
|
|
base.OnDrop();
|
|
}
|
|
|
|
private void SwapLampMaterial()
|
|
{
|
|
Material[] Materials = _MarkerMesh.materials;
|
|
Materials[2] = IsLit ? _LitLampMaterial : _UnlitLampMaterial;
|
|
_MarkerMesh.materials = Materials;
|
|
}
|
|
|
|
private void ReactToGrab()
|
|
{
|
|
if (IsGrabbed)
|
|
{
|
|
_RigidBodyComponent.constraints = RigidbodyConstraints.None;
|
|
|
|
if (Active) _EnableCollisionChecks = true;
|
|
_NoCollisionCounter = 0;
|
|
_CollidingLocations.Clear();
|
|
}
|
|
else
|
|
{
|
|
if (!_CurrentOwner.IsUserInVR())
|
|
{
|
|
transform.eulerAngles = new Vector3(0.0f, transform.eulerAngles.y, 0.0f);
|
|
}
|
|
|
|
_RigidBodyComponent.constraints = RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezePositionZ;
|
|
|
|
_NoCollisionCounter = 0;
|
|
}
|
|
|
|
RequestSerialization();
|
|
}
|
|
|
|
|
|
public void CheckCollisionsLoop()
|
|
{
|
|
if (_EnableCollisionChecks && !IsGrabbed)
|
|
{
|
|
if (_CollidingLocations.Count > 0 && IsUpright())
|
|
{
|
|
_NoCollisionCounter = 0;
|
|
|
|
for (int i = 0; i < _CollidingLocations.Count; i++)
|
|
{
|
|
FloorMapLocation Location = (FloorMapLocation)_CollidingLocations[i].Reference;
|
|
if (Location != null)
|
|
{
|
|
bool FoundCorrectResponse = ConfirmChoice(Location.Country, Location.City);
|
|
if (FoundCorrectResponse)
|
|
{
|
|
SendCorrectResponse(Location.transform.position);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
_CollisionCheckCounter++;
|
|
if (_CollisionCheckCounter >= MAX_REPEAT_COLLISION_CHECKS)
|
|
{
|
|
SendIncorrectResponse();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_NoCollisionCounter++;
|
|
if (_NoCollisionCounter >= MAX_CHECKS_WITH_NO_COLLISIONS)
|
|
{
|
|
SendIncorrectResponse();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Active)
|
|
{
|
|
SendCustomEventDelayedSeconds(nameof(CheckCollisionsLoop), TIME_BETWEEN_REPEAT_COLLISION_CHECKS);
|
|
}
|
|
}
|
|
|
|
|
|
public bool ConfirmChoice(string Country, string City)
|
|
{
|
|
if (Country == _GameManager.GetCurrentCountry() &&
|
|
City == _GameManager.GetCurrentCity())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void SendCorrectResponse(Vector3 CorrectLocation)
|
|
{
|
|
DisableMovementCompletely(CorrectLocation);
|
|
|
|
Active = false;
|
|
_EnableCollisionChecks = false;
|
|
_UsedUp = true;
|
|
|
|
RequestSerialization();
|
|
|
|
if (_CurrentOwner == Networking.LocalPlayer)
|
|
{
|
|
_GameManager.SendCustomNetworkEvent(NetworkEventTarget.Owner, "CorrectResponse");
|
|
}
|
|
}
|
|
|
|
private void SendIncorrectResponse()
|
|
{
|
|
DisableMovementCompletely();
|
|
|
|
_CollisionCheckCounter = 0;
|
|
_CollidingLocations.Clear();
|
|
|
|
_EnableCollisionChecks = false;
|
|
|
|
if (_CurrentOwner == Networking.LocalPlayer)
|
|
{
|
|
_GameManager.SendCustomNetworkEvent(NetworkEventTarget.Owner, "IncorrectResponse");
|
|
}
|
|
|
|
RequestSerialization();
|
|
}
|
|
|
|
[NetworkCallable]
|
|
public void Activated(bool SetActive)
|
|
{
|
|
Active = SetActive;
|
|
}
|
|
private void ReactToActivation()
|
|
{
|
|
_PickupComponent.pickupable = Active;
|
|
if (IsGrabbed) _EnableCollisionChecks = true;
|
|
|
|
SendCustomEventDelayedSeconds(nameof(CheckCollisionsLoop), TIME_BETWEEN_REPEAT_COLLISION_CHECKS);
|
|
}
|
|
|
|
[NetworkCallable]
|
|
public void SetLit(bool Lit)
|
|
{
|
|
IsLit = Lit;
|
|
RequestSerialization();
|
|
}
|
|
|
|
|
|
public bool IsUsedUp()
|
|
{
|
|
return _UsedUp;
|
|
}
|
|
|
|
|
|
private void DisableMovementCompletely(Vector3 CorrectLocation = new Vector3())
|
|
{
|
|
_RigidBodyComponent.constraints = RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezePositionZ | RigidbodyConstraints.FreezeRotation;
|
|
transform.eulerAngles = new Vector3(0.0f, transform.eulerAngles.y, 0.0f);
|
|
|
|
if (CorrectLocation != Vector3.zero)
|
|
{
|
|
transform.position = CorrectLocation;
|
|
}
|
|
|
|
RequestSerialization();
|
|
}
|
|
|
|
private bool IsUpright()
|
|
{
|
|
return (Vector3.Dot(transform.up, Vector3.up) >= 0.8f);
|
|
}
|
|
|
|
|
|
private bool Active
|
|
{
|
|
set
|
|
{
|
|
_Active = value;
|
|
ReactToActivation();
|
|
RequestSerialization();
|
|
}
|
|
get => _Active;
|
|
}
|
|
|
|
private bool IsGrabbed
|
|
{
|
|
set
|
|
{
|
|
_IsGrabbed = value;
|
|
ReactToGrab();
|
|
}
|
|
get => _IsGrabbed;
|
|
}
|
|
|
|
private bool IsLit
|
|
{
|
|
set
|
|
{
|
|
_IsLit = value;
|
|
SwapLampMaterial();
|
|
}
|
|
get => _IsLit;
|
|
}
|
|
}
|