Files
FueraDeEscala/Assets/Game Kit Controller/Scripts/Gravity/artificialObjectGravity.cs
Robii Aragon fd87a6ffd5 add ckg
plantilla base para movimiento básico
2026-02-05 05:07:55 -08:00

355 lines
8.6 KiB
C#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class artificialObjectGravity : MonoBehaviour
{
[Header ("Main Settings")]
[Space]
public LayerMask layer;
public float rayDistance;
public PhysicsMaterial highFrictionMaterial;
public float gravityForce = 9.8f;
[Space]
[Header ("Debug")]
[Space]
public bool onGround;
public bool active = true;
public Vector3 normal;
public Vector3 hitPoint;
public Vector3 auxNormal;
public bool normalAssigned;
public bool zeroGravityActive;
[Space]
[Header ("Center Point Settings")]
[Space]
public bool useCenterPointActive;
public Transform currentCenterPoint;
public bool useInverseDirectionToCenterPoint;
public bool useCenterPointListForRigidbodies;
public List<Transform> centerPointList = new List<Transform> ();
RaycastHit hit;
bool onGroundChecked;
float groundAdherence = 10;
Rigidbody mainRigidbody;
Collider mainCollider;
bool objectActivated;
float originalGravityForce;
Vector3 currentNormalDirection;
float minDistance;
float currentDistance;
float downVelocity;
bool useGravityActive;
Vector3 currentPosition;
bool mainRigidbodyLocated;
public void getComponents ()
{
if (!objectActivated) {
if (mainRigidbody == null) {
mainRigidbody = GetComponent<Rigidbody> ();
}
if (mainRigidbody != null) {
mainRigidbodyLocated = true;
}
if (mainCollider == null) {
mainCollider = GetComponent<Collider> ();
}
objectActivated = true;
originalGravityForce = gravityForce;
}
}
//this script is added to an object with a rigidbody, to change its gravity, disabling the useGravity parameter, and adding force in a new direction
//checking in the object is in its new ground or not
void FixedUpdate ()
{
//if nothing pauses the script and the gameObject has rigidbody and it is not kinematic
if (active && mainRigidbodyLocated) {
if (!mainRigidbody.isKinematic) {
//check if the object is on ground or in the air, to apply or not force in its gravity direction
currentNormalDirection = normal;
currentPosition = transform.position;
if (useCenterPointActive) {
if (useCenterPointListForRigidbodies) {
minDistance = Mathf.Infinity;
for (int i = 0; i < centerPointList.Count; i++) {
currentDistance = GKC_Utils.distance (currentPosition, centerPointList [i].position);
if (currentDistance < minDistance) {
minDistance = currentDistance;
currentCenterPoint = centerPointList [i];
}
}
}
if (useInverseDirectionToCenterPoint) {
currentNormalDirection = currentPosition - currentCenterPoint.position;
} else {
currentNormalDirection = currentCenterPoint.position - currentPosition;
}
currentNormalDirection = currentNormalDirection / currentNormalDirection.magnitude;
}
if (zeroGravityActive) {
if (onGround) {
onGround = false;
onGroundChecked = false;
mainCollider.material = null;
}
} else {
if (onGround) {
if (!onGroundChecked) {
onGroundChecked = true;
mainCollider.material = highFrictionMaterial;
}
} else {
if (onGroundChecked) {
onGroundChecked = false;
mainCollider.material = null;
}
mainRigidbody.AddForce (gravityForce * mainRigidbody.mass * currentNormalDirection);
if (useGravityActive) {
mainRigidbody.useGravity = false;
useGravityActive = false;
}
}
//use a raycast to check the ground
if (Physics.Raycast (currentPosition, currentNormalDirection, out hit, (rayDistance + transform.localScale.x / 2), layer)) {
if (!hit.collider.isTrigger && hit.rigidbody == null) {
onGround = true;
downVelocity = transform.InverseTransformDirection (mainRigidbody.linearVelocity).y;
if (downVelocity > .5f) {
mainRigidbody.position = Vector3.MoveTowards (mainRigidbody.position, hit.point, Time.deltaTime * groundAdherence);
}
if (downVelocity < .01f) {
mainRigidbody.linearVelocity = Vector3.zero;
}
}
} else {
onGround = false;
}
}
}
}
//if the gameObject has not rigidbody, remove the script
if (!mainRigidbodyLocated) {
gameObject.layer = LayerMask.NameToLayer ("Default");
Destroy (this);
}
}
//when the object is dropped, set its forward direction to move until a surface will be detected
public void enableGravity (LayerMask layer, PhysicsMaterial frictionMaterial, Vector3 normalDirection)
{
getComponents ();
this.layer = layer;
highFrictionMaterial = frictionMaterial;
mainRigidbody.useGravity = false;
useGravityActive = false;
normal = normalDirection;
normalAssigned = false;
}
public void setActiveState (bool state)
{
active = state;
}
public void removeGravity ()
{
//set the layer again to default, active the gravity and remove the script
gameObject.layer = LayerMask.NameToLayer ("Default");
if (mainRigidbody != null) {
mainRigidbody.useGravity = true;
useGravityActive = true;
}
Destroy (this);
}
public void removeGravityComponent ()
{
gameObject.layer = LayerMask.NameToLayer ("Default");
Destroy (this);
}
public void removeJustGravityComponent ()
{
Destroy (this);
}
void OnCollisionEnter (Collision collision)
{
//when the objects collides with anything, use the normal of the collision
if (active && collision.gameObject.layer != LayerMask.NameToLayer ("Ignore Raycast") && !normalAssigned && !mainRigidbody.isKinematic) {
//get the normal of the collision
Vector3 direction = collision.contacts [0].normal;
//Debug.DrawRay (transform.position,-direction, Color.red, 200,false);
if (Physics.Raycast (transform.position, -direction, out hit, 3, layer)) {
if (!hit.collider.isTrigger && hit.rigidbody == null) {
normal = -hit.normal;
//the hit point is used for the turret rotation
hitPoint = hit.point;
// @todo Tag doesn't exist, layer used now in stead. Fix me when refactoring this code.
bool isTurret = gameObject.CompareTag ("turret");
//check the type of object
if (isTurret) {
//if the direction is the actual ground, remove the script to set the regular gravity
if (normal == -Vector3.up) {
removeGravity ();
return;
}
normalAssigned = true;
}
//if the object is an ally turret, call a function to set it kinematic when it touch the ground
if (isTurret) {
if (!mainRigidbody.isKinematic) {
StartCoroutine (rotateToSurface ());
}
}
}
}
}
}
//when an ally turret hits a surface, rotate the turret to that surface, so the player can set a turret in any place to help him
IEnumerator rotateToSurface ()
{
mainRigidbody.useGravity = true;
mainRigidbody.isKinematic = true;
useGravityActive = true;
//it rotates the turret in the same way that the player rotates with his gravity power
Quaternion rot = transform.rotation;
Vector3 myForward = Vector3.Cross (transform.right, -normal);
Quaternion dstRot = Quaternion.LookRotation (myForward, -normal);
for (float t = 0; t < 1;) {
t += Time.deltaTime * 3;
transform.rotation = Quaternion.Slerp (rot, dstRot, t);
transform.position = Vector3.MoveTowards (transform.position, hitPoint + 0.5f * transform.up, t);
yield return null;
}
gameObject.layer = LayerMask.NameToLayer ("Default");
//if the surface is the regular ground, remove the artificial gravity, and make the turret stays kinematic when it will touch the ground
if (-normal == Vector3.up) {
SendMessage ("enabledKinematic", false);
removeGravity ();
}
}
public void setZeroGravityActiveState (bool state)
{
getComponents ();
zeroGravityActive = state;
if (zeroGravityActive) {
mainRigidbody.useGravity = false;
}
}
//set directly a new normal
public void setCurrentGravity (Vector3 newNormal)
{
getComponents ();
mainRigidbody.useGravity = false;
normal = newNormal;
normalAssigned = true;
useGravityActive = false;
}
public void setUseCenterPointActiveState (bool state, Transform newCenterPoint)
{
useCenterPointActive = state;
currentCenterPoint = newCenterPoint;
}
public void setUseInverseDirectionToCenterPointState (bool state)
{
useInverseDirectionToCenterPoint = state;
}
public void setGravityForceValue (bool setOriginal, float newValue)
{
if (setOriginal) {
gravityForce = originalGravityForce;
} else {
gravityForce = newValue;
}
}
public void setUseCenterPointListForRigidbodiesState (bool state, List<Transform> newCenterPointList)
{
useCenterPointListForRigidbodies = state;
centerPointList = newCenterPointList;
}
}