This is an old revision of the document!


Interactiuni cu obiecte

Cerinte

TBU

Documentatie video

TBU

Documentatie extinsa text

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);
}	

Referinta globala la player

O problema in programarea interactiunilor este detectarea player-ului, in sensul de referinta. Astfel, avem mai multe variante:

  • putem cauta un obiect dupa tag/nume etc.
  • intr-o variabila target putem referentia direct player-ul (dar asta inseamna ca la fiecare agent trebuie mapat)
  • putem folosi un singleton in care se tine referentiaza playerul si poate fi accesat de oriunde
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);
	}

Inamici

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:

  • inamicii de obicei incep sa interactioneze atunci cand player-ul intra intr-o anumita raza de actiune
  • NPC-urile interactoneaza la fel, bazate pe o raza de actiune sau efectiv interactiune directa (click)
pjv/laboratoare/2023/06.1698044786.txt.gz ยท Last modified: 2023/10/23 10:06 by alexandru.gradinaru
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0