Juego en Unity para clase

RocKst3aDy

Buenas mediavideros, estoy empezando a usar el Unity, solo he terminado un tutorial de naves en 3D y me ha enamorado el programa. No tengo experiencia en desarrollar videojuegos pero si en jugarlos xD. En 2 semanas tengo que entregar aunque sea una beta de un juego diseñado por mi, y la idea que tengo es una especie de Tower Defense pero en el que controlamos una sola torre central con nuestro personaje arriba de la torre que disparará a los enemigos que vienen desde los lados. Sera 2.5D porque sera modelado 3D pero solo movimiento 2D. Espero seguir avanzando hasta el punto de que sea un juego divertido y vistoso y poder enseñarlo por aqui.

Ahora viene la primera duda: estoy atascado en la función de disparar donde hagas click con el ratón, bloqueando el eje Z y no se por donde empezar, ya he probado bastantes scripts de la red y no consigo que me funcione.

Ejemplo:

RPV: Quiero conseguir que el brazo siga al ratón y dispare en la dirección de donde hagas click.

B

Reservado para cuando llegue a casa y te explico!

Necesitas determinar la posición del ratón en la escena mediante un Raycast hacia un plano invisible creado por Script, en cuanto llegue a casa te lo explico y te pongo el ejemplo :)


Edit


Bueno, ya he llegado a casa así que te explico, estaba yo erróneo, no hace falta que calcules un Raycast para saber la posición, se hace directamente desde la MainCamera, te dejo el Script y te explico:

using UnityEngine;
using System.Collections;

public class playerHand : MonoBehaviour {

public GameObject bulletPrefab;

public Camera mainCamera;

public Vector3 mousePosition;

void Start()
{
    mainCamera = GameObject.FindGameObjectWithTag("MainCamera").camera;
}

void Update()
{
    mousePosition = Input.mousePosition;
    mousePosition.z = Vector3.Distance(mainCamera.transform.position, transform.position);
    transform.LookAt(mainCamera.ScreenToWorldPoint(mousePosition));

    if (Input.GetMouseButtonDown(0))
        Instantiate(bulletPrefab, transform.position, transform.rotation);
}
}

Bien, empecemos por partes:

    public GameObject bulletPrefab;

public Camera mainCamera;

public Vector3 mousePosition;

Ahí tenemos las variables que necesitamos para lo que quieres hacer, te explico;

La variable GameObject llamada bulletPrefab es simplemente un prefab de un objeto que debes crear, que será la bala que dispare el jugador (yo he usado un rigidbody y he aplicado fuerza sobre ella en la función Start() que se llama cuando el objeto se crea), no tiene mucha complicación, la defines en código y la referencia se la pones desde el mismo inspector de Unity, arrastrando el prefab a la variable.

La variable Camera es la más importante, pues basaremos la posición del ratón en su vista.

Y la variable Vector3 es para tener las coordenadas exactas de la posición del ratón, es decir, es para poder representarla en una variable que podamos modificar después.

Siguiente:

    void Start()
    {
        mainCamera = GameObject.FindGameObjectWithTag("MainCamera").camera;
    }

Ahí llamamos a la función Start() de Unity, como te he explicado arriba, ésta es llamada justo cuando el objeto es creado en la escena, justo ahí y sólo ahí, esa función es llamada.

En este caso la uso para devolver la Cámara que está en la escena a la variable que hemos creado para representarla en el Script, si te fijas, en la parte de GameObject.FindGameObjectWithTag("MainCamera").camera especifico que esa variable busque un objecto en la escena con el tag MainCamera, es el tag que se le pone por defecto a la cámara que se crea en todas las escenas nuevas automáticamente con Unity, si no tienes una cámara con ese tag, cambia el GameObject.FindGameObjectWithTag("MainCamera").camera a GameObject.Find("EL NOMBRE DE LA CÁMARA EN LA ESCENA").camera y listos.

Ahora vamos al grano:

    void Update()
    {
        mousePosition = Input.mousePosition;
        mousePosition.z = Vector3.Distance(mainCamera.transform.position, transform.position);
        transform.LookAt(mainCamera.ScreenToWorldPoint(mousePosition));

    if (Input.GetMouseButtonDown(0))
        Instantiate(bulletPrefab, transform.position, transform.rotation);
}

La función Update() es llamada cada frame en Unity, y como necesitamos que la posición del ratón se actualice sin parar para que el brazo siga al ratón siempre debemos escribir el siguiente código en esta función tan maravillosa.

Primero hacemos que la posición del ratón se devuelva a la variable mousePosition (Vector3).

Después, simplemente calculamos la distancia en el Vector.z dentro del Vector3 de la posición del ratón entre la Cámara que usamos y la posición actual del ratón.

Ahora hacemos que nuestro brazo mire al ratón en el siguiente fragmento de código:

        transform.LookAt(mainCamera.ScreenToWorldPoint(mousePosition));

Aquí estamos haciendo que la rotación de nuestro brazo cambie justo hacia la posición exacta del ratón, para hacerlo, llamamos a una función de la Cámara, que simplemente nos devuelve la posición exacta del ratón en la escena, para así saber a dónde debe mirar nuestro brazo, y tachán, el brazo girará exactamente hacia donde esté el ratón.

Y ahora el último fragmento de código:

        if (Input.GetMouseButtonDown(0))
            Instantiate(bulletPrefab, transform.position, transform.rotation);

Lo que hacemos es comprobar cuándo se presiona el botón izquierdo del ratón (0 = botón izquierdo, 1 = botón derecho) y hacer una copia del Prefab de la bala que hemos creado antes, en la posición del brazo y en la rotación que tiene el brazo (que casualmente es la posición del ratón), y tachán, ya tienes lo que querías!

No sé si estás familiarizado con los Prefabs en Unity, los Prefabs son Objetos que se pueden reciclar, es decir, que los creamos, dejamos el código como queremos, y lo convertimos en un Objeto Original, para que luego si queremos por ejemplo disparar balas, tengamos una fuente interminable de balas, porque lo único que haremos es copiar el Objeto Original y ponerlo en nuestra escena.

Un saludo, espero que te haya servido de ayuda.

PD: Si no te funciona o quieres trastear puedes mirar el prototipo que te he hecho en mi dropbox: https://www.dropbox.com/sh/9y9196e7jbicnul/1EtlIq1isP

1 2 respuestas
JackSparow

#1 Creo que no deberías tener problemas en eso si he entendido bien la duda.

Tienes que castear un Raycast con:
Origen: transform.position del jugador.
Dirección: new Vector3(posRatonX, posRatonY, Z) - transform.position del jugador.

Luego el método Raycast te puede devolver:
null si no ha colisionado con nada el rayo instantaneo.
un objeto si ha colisionado con algo (te da información de con qué ha colisionado y tal).

PD: Todo esto es en caso de que lo que disparos sean instantáneos. (llega la destino nada mas disparar).
En caso que sean proyectiles "lentos". Pues calculas la dirección inicial dell proyectil de la misma manera, pero aplicas un script al proyectil para detectar futuras colisiones, etc.

doc: http://docs.unity3d.com/Documentation/ScriptReference/Physics.Raycast.html

1 respuesta
MaikelOrtega

Yo desde luego optaría por la opción del plano invisible, para que el código te sirva aunque cambies la orientación del juego. Sin embargo como bien ha puesto #2 en este caso te sirve con sumarle la distancia entre cámara y personaje.

Si quisieras hacer ésto fuera de un entorno 2D (en un juego tipo Tombi o Klonoa, en el que giraba el escenario, o tipo Bastion, con la cámara no perpendicular al suelo), tendrías que hacer el Raycast contra un plano invisible, desde el punto de la cámara. El plano invisible lo situas en la posición del jugador y haces que el transform mire al punto devuelto en RaycastHit.point.

Pero desde luego la solución de #2 es la más simple y elegante para tu problema.

1 respuesta
RocKst3aDy

#2 #3 #4 IMPRESIONANTE chicos muchas gracias! esta mañana consegui algo muy cercano a lo que queria pero seguro que es a lo chapuzas xD ahora estoy liado con otras cosas (semanas finales) pero esta noche probare vuestros metodos aunq sea para entender las distintas formas de hacerlo. Otra vez Muchas Gracias!

Usuarios habituales