Unity 3D – Come sparare con un fucile, visualizzando i fori del proiettile

In questo articolo vedremo come aggiungere una texture che simulerà un foro su una superfice di un oggetto che è stato “colpito da un proiettile”.

( Pulsante sinistro mouse = SPARA   Frecce= spostati )

Procuriamoci una scena di base in cui ci sono i nostri oggetti da colpire.
Nel mio caso ho creato a partire da una scena vuota un piano (plane)  che fa da pavimento ( aggiungendo una texture per l’erba ) e quattro cubi (cube), a cui ho aggiunto una texture di legno.
Ho importato dagli asset standard il First Person Controller.
Ho impilato i cubi.
Ottenendo la scena nell’immagine:
tut_bulletholes_01

A questo punto per simulare uno sparo di un fucile aggiungiamo uno script all’oggetto First Person Controller, utilizzando un RayCast per identificare l’oggetto colpito.

void Update () {
        // If the Button “Fire1” is pressed down it will return true and so we enter the if condition
        if(Input.GetButton("Fire1") && Time.time > nextFire)
        {
      // è stato premuto il bottone "Fire1", che per default è associato al bottone sinistro del mouse.
  
            nextFire = Time.time + fireRate; // piccolo filtro di tempo per evitare che ad ogni frame venga sparato un raggio

            // Vector2 è usato per avere le coordinate del puntatore sullo schermo al momento della pressione del muose sinistro.
            // Il centro dello schermo è calcolato dividendo per due le dimensioni dello schermo
            Vector2 screenCenterPoint = new Vector2(Screen.width/2, Screen.height/2);
            
            // Camera.main è la camera di default della scena ( deve avere il Tag MainCamera )
            ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            if(Physics.Raycast(ray, out hit, Camera.main.farClipPlane)) // spara il raggio dalla camera
            {
                // E' stata rilevata la collisione del raggio con un oggetto dotato di Collider
                // qui possiamo gestire la collisione
                Debug.DrawLine (transform.position, hit.point, Color.red);
                Debug.Log("hit the object:" + hit.transform.name);
            }
        }
    }

Premendo play vedremo il raggio ROSSO uscire dalla camera e colpire un cubo.

Ora, procuriamoci una texture che faccia da “foro”:
bullethole

Io l’ho creata velocemente con un programma di grafica qualsiasi.
Aggiungiamo un quad alla scena e trasciniamoci sopra la texture del foro di proiettile.tut_bulletholes_02tut_bulletholes_03

Costruiamo un prefab con questo quad, chiamandolo ad esmpio: BulletHole.

Quindi aggiungiamo allo script che gestisce il raycast una variabile public per assegnargli il prefab appena creato.

public GameObject bulletHolePrefab; // bullet hole prefab to instantiate

e aggiungiamo il codice di gestione:

if(Physics.Raycast(ray, out hit, Camera.main.farClipPlane)) { // spara il raggio dalla camera

  // E' stata rilevata la collisione del raggio con un oggetto dotato di Collider
  // qui possiamo gestire la collisione
  Debug.DrawLine (transform.position, hit.point, Color.red);
  Debug.Log("hit the object:" + hit.transform.name);
  
  Vector3 bulletHolePosition = hit.point + hit.normal * 0.01f;  // posizione di collisione del raycast sull'oggetto colpito
  // notare la normale all'oggetto è l'offset di 0.01f per non avere intersecazioni di textures.

  // ci serve una variabile per salvarci la rotazione del prefab
  // La rotazione sarà data dall'unione del vettore forward e la normale al punto di impartto
  Quaternion bulletHoleRotation = Quaternion.FromToRotation(-Vector3.forward, hit.normal);

  // instanziamo il prefab
  GameObject hole = (GameObject)GameObject.Instantiate(bulletHolePrefab, bulletHolePosition, bulletHoleRotation);
  hole.transform.parent = hit.transform; // assegniamo anche il parent del foro per fare in modo che l'oggetto colpito, 
                                         // se si sposta, ha sempre il foro posizionato correttamente.

  // chicca: se ho un rigdbody sull'aggotto applico una forza per simulare l'impatto del proiettile
  if ( hit.rigidbody != null ) {
    hit.rigidbody.AddForceAtPosition (150 * ray.direction, hit.point);

    // riproduzione dell'audio attaccato all'aggetto.
    if ( audio != null ) {
      audio.Play();
    }

  }

}

Scarica da qui il progetto demo Unity3D

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *