This is an old revision of the document!
TBU
TBU
Interactiunea cu obiectele in spatiul 3D poate fi extrem de complexa, intrucat exista foarte multe forme de interactiuni: inamici, obiecte de pickup, deschidere de usi, activare de manivele etc. Fiecare dintre aceste interactiuni are specificul ei, dar abstractizand, putem deduce ca fiecare interactiune se intampla intr-o anumita raza si cu un anumit punct de interactiune. Pentru a defini usor aceste lucruri, putem crea o clasa generica denumita InteractionObject cu o metoda abstracta (virtuala) ce defineste interactiunea in detaliu.
public class InteractionObject : MonoBehaviour {
public float radius = 1f;
public Transform interactionPoint;
Transform interactionObject;
bool done = false;
//metoda abstracta, speficica fiecarui tip de interactiuni
public virtual void Interaction ()
{
}
void Update ()
{
float distance = Vector3.Distance(interactionObject.position, interactionPoint.position);
if (distance <= radius && !done) // avem interactiune cu obiectul, pot sa afisez informatii: de ex "Press E to use"
{
done = true;
Interaction();
}
}
}
}
La fel de bine aceste interactiuni pot fi detectate folosind sistemul de colizuni din Unity
Physics Events
/* Both objects have to have a Collider and one object has to have a Rigidbody for these Events to work */ private void OnCollisionEnter(Collision hit) { Debug.Log(gameObject.name + " just hit " + hit.gameObject.name); } private void OnCollisionStay(Collision hit) { Debug.Log(gameObject.name + " is hitting " + hit.gameObject.name); } private void OnCollisionExit(Collision hit) { Debug.Log(gameObject.name + " stopped hitting " + hit.gameObject.name); } /* Trigger must be checked on one of the Colliders */ private void OnTriggerEnter(Collider hit) { Debug.Log(gameObject.name + " just hit " + hit.name); } private void OnTriggerStay(Collider hit) { Debug.Log(gameObject.name + " is hitting " + hit.name); } private void OnTriggerExit(Collider hit) { Debug.Log(gameObject.name + " stopped hitting " + hit.name); } /* For 2D Colliders just add 2D to the Method name and the Parameter Type */ private void OnCollisionEnter2D(Collision2D hit) { } private void OnCollisionStay2D(Collision2D hit) { } private void OnCollisionExit2D(Collision2D hit) { } private void OnTriggerEnter2D(Collider2D hit) { } private void OnTriggerStay2D(Collider2D hit) { } private void OnTriggerExit2D(Collider2D hit) { }
Astfel, toate obiectele ce vor avea interactiuni, vor mosteni aceasta clasa. Spre exemplu pentru un obiect de pickup putem avea urmatoarea secventa:
public class PickupObject : InteractionObject {
public override void Interaction()
{
base.Interaction(); // se apeleaza metoda parinte, in caz ca avem ceva generic
//mecanica
...
PlayerManager.instance.score += value;
//distrugem obiectul
Destroy(gameObject);
}
}
Pentru a controla mai bine zona de actiune (radius) si punctul de interes pentru un obiect de interactiune (InteractionObject), se poate defini o functie de editor, atunci cand obiectul este selectat. In exemplul de mai jos, la selectarea obiectului se va afisa o sfera wireframe de culoare alba.
void OnDrawGizmosSelected ()
{
Gizmos.color = Color.white;
Gizmos.DrawWireSphere(interactionPoint.position, radius);
}
O problema in programarea interactiunilor este detectarea player-ului, in sensul de referinta. Astfel, avem mai multe variante:
public class PlayerManager : MonoBehaviour {
public static PlayerManager instance;
public GameObject player;
void Awake()
{
instance = this;
}
}
Folosind varianta simpla cu singleton, putem lua pozitia player-ului de interes:
target = PlayerManager.instance.player.transform;
Astfel, putem efectua usor operatii care tin de player - de exemplu putem orienta inamicii sau un npc cu fata catre player, in momentul unei interactiuni.
//Roteste cu 90 grade
void RotateN() {
Vector3 currentRotation = transform.rotation;
Vector3 wantedRotation = currentRotation * Quaternion.AngleAxis(-90, Vector3.up);
transform.rotation = Quaternion.Slerp(currentRotation, wantedRotation, Time.deltaTime * rotationSpeed);
}
//Roteste inamicul cu fata catre player
void FaceTarget ()
{
Vector3 direction = (target.position - transform.position).normalized;
Quaternion lookRotation = Quaternion.LookRotation(new Vector3(direction.x, 0, direction.z));
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5f);
}
Astfel, pentru inamici putem defini un controller cu un radius de actiune, si un gizmos pentru vizualizare usoara a acestuia in editor.
public class EnemyController : MonoBehaviour {
public float radius = 2;
void OnDrawGizmosSelected() {
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, radius);
}
}
Diferenta este ca acesti agenti vor raspunde automat la anumite evenimente: