BITFALL/Assets/Artists/Scripts/Scenes/PhysicsDoor.cs

130 lines
3.8 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Configuration;
using BITFALL.Scene;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.AI;
namespace BITKit
{
public class PhysicsDoor : MonoBehaviour, IAction, IDescription, ISceneBlockArea
{
public enum State
{
Close,
Open,
HalfOpen,
Locked,
}
[SerializeField] private string description;
[SerializeField] private bool allowPhysics = true;
[SerializeField] private Rigidbody root;
[SerializeField] private new Collider collider;
[SerializeField] private NavMeshObstacle obstacle;
[SerializeField] private Vector3 openEuler;
[SerializeField] private Vector3 closeEuler;
[SerializeField] private State state;
[SerializeField] private Collider[] ignoreColliders;
[SerializeReference, SubclassSelector] private IReference envName;
private Vector3 _initialPosition;
private void Start()
{
var selfColliders = GetComponentsInChildren<Collider>(true);
var parentCollider = GetComponentInParent<Collider>(true);
foreach (var self in selfColliders)
{
foreach (var ignore in ignoreColliders)
{
Physics.IgnoreCollision(self, ignore, true);
}
if (parentCollider is not null)
Physics.IgnoreCollision(self, parentCollider, true);
}
_initialPosition = root.transform.localPosition;
UpdateState();
}
public void Execute()
{
switch (state)
{
case State.Open:
state = State.Close;
UpdateState();
break;
case State.Close:
state = State.Open;
UpdateState();
break;
}
}
public void UpdateState(bool isClosed)
{
state = isClosed ? State.Close : State.Open;
//root.transform.localPosition = _initialPosition;
root.transform.localEulerAngles = isClosed ? closeEuler : openEuler;
if (allowPhysics)
root.isKinematic = isClosed;
if (envName is not null)
{
Data.Set<bool>(envName.Value, isClosed);
}
}
private void UpdateState()
{
switch (state)
{
case State.Close:
case State.Open:
var isClosed = state switch
{
State.Locked => true,
State.Close => true,
State.Open => false,
_ => true
};
UpdateState(isClosed);
if (obstacle)
{
obstacle.enabled = isClosed;
}
break;
}
}
public string Name => state is State.Locked ? "锁住了" : description;
public bool IsBlocked => state is not State.Open;
public bool InRange(float3 position)
{
return collider.bounds.Contains(position);
}
public bool InRange(float3 position, float3 direction)
{
if (direction is { x: 0, y: 0, z: 0 }) return false;
var ray = new Ray(position, ((Vector3)direction).normalized);
if (collider.Raycast(ray, out var hit, 1))
{
Debug.DrawLine(position, hit.point, Color.red, 1);
return true;
}
Debug.DrawLine(position, position + direction, Color.blue, 1);
return false;
}
}
}