Buenas, en mi juego tengo mis variables globales de vida y armadura.
El daño que hacen mis 2 objetos de enemigos (2 bolas de colores) es en uno 10 y en otro 26, lo que quiero hacer es que la armadura me ayude a protegerme del daño causado por los ataques enemigos, entonces, tengo este codigo cuando una bola de 100 de daño colisiona con el jugador:

if (global.salud >= 10)

{
if (global.armadura <=9)

{
global.salud -= (10 - global.armadura)
instance_destroy();
instance_create(other.x,other.y,o_Bluud1);

}

else if (global.armadura >= 10)

{
instance_destroy();
}


}


else if (global.salud <= 9)
{
if (global.armadura <=8)
{
instance_destroy();
show_message("Haz muerto");
game_restart();
}

else if (global.armadura >= 9)
{
instance_destroy();
}
}


El odigo funciona muy bien y hace lo que quiero, que es comprobar si la salud esta a 10 o mas y luego comprobar la armadura ( si esta a 9 o menos comprueba armadura de nuevo y asi)
Pero lo que pasa es que con este codigo la armadura me vuelve practicamente invencible contra los ataques de a 10, y si obtengo mas armadura y me aumentan el global.armadura a mas de 25 también sere invencible contra los ataques de 26.
Entonces, queria saber como podria hacer que mi armadura me proteja, por ejemplo solo un 16%? recibiendo solo un 84% de daño del ataque de 10 o del de 26?
Espero haberme explicado bien.

Amigo mañana te voy a contestar bien con un código completo nuevo. Ahora justo debo irme a dormir porque es muy tarde. Pero déjame sugerirte unas cosas para poder mejorar tu juego:

1) Si en el juego se crean normalmente unas cuantas instancias de bolas "10" y otras cuantas de bolas "26" NO te conviene meter el código en la "bola" porque Game Maker debería verificar las colisiones de cada bola para ver si ha colisionado con el objeto del jugador. Si hubiera 5 bolas las haría con las 5. Lo correcto es que este código esté dentro del objeto "jugador" (con las adaptaciones necesarias) porque de esta forma Game  Maker solo debería procesar las colisiones del objeto "jugador" solamente y no la de cada bola. Esto es importante porque el manejo de colisiones es relativamente lento. Si hay pocos objetos quizás no se note pero al aumentar se hace mas notorio. De todas formas lo mismo hay que tratar de hacer siempre lo más óptimo.

2) Deberías hacer un código genérico dentro del objeto jugador que funcione para todos los tipos de "bola" incluso para nuevas "bolas" que puedas hacer en el futuro y que esto no te lleve a cambiar código sino que simplemente funcione. Por ejemplo: dentro de cada bola podés tener una variable que indica su "fuerza" o "potencia" (como 10, 26 u otro valor)
Cuando una bola colisione con el jugador, el jugador acceda al other.potencia y en función de eso haga todos los cálculos. En lugar de if (global.salud >= 10) quedaria if (global.salud >= other.potencia) etc. es decir códigos genéricos.

3) Puedes tener diversos objetos "bola" distintos con distintos sprite, etc.y esto te puede llevar a pensar que tienes que hacer un evento colision por cada uno de esos objetos, pero esto no es así, porque en estos casos se hace un objeto padre, es decir, creas un objeto "bola_generico" y a todos los objetos bola le indicas que tienen como padre al objeto "bola_generico" (esto se hace seleccionando "bola genérico" en la opción parent del objeto). Entonces en el objeto jugador tendría un solo evento colision con "bola_generico".
Entonces puedes agregar todos los objetos bolas distintos que quieras y con solo definir su parent como "bola_genérico" sería suficiente para que el objeto "jugador" lo verifique en las colisiones.

Si todos los objetos bolas son similares en su comportamiento podrías tener un solo objeto bola y al momento de crearlo le asignas un sprite y le cambias la variable "potencia" y con esto no necesitarias nada de lo dicho anteriormente. Con un solo objeto tenes todos los tipos de bola que quieras con tan solo cambiarle el sprite y los datos internos al momento de crear la instancia (sin necesidad de definir parent ni nada porque es un solo objeto)

4) Podrías incorporar la idea de que si bien la armadura protege pero se va deteriorando.

Mañana te lo armo. Me gustaría hacerte un código renovado. Lo bueno de eso es que después es muy fácil agregar nuevas "bolas" distintas porque se pueden agregar y funcionarían sin modificar el código, o al menos mucho menos código que modificar. Saludos



Vale, gracias por los tips, los tendre en cuenta ya que aun soy desordenado con los codigos y funciones como "other" aun no las domino bien a pesar de que he leido que son basicas, espero que puedas armar un codigo mejor que el mio  :P
Saludos

Lo de dañar la armadura tambien lo habia pensado, pero pensaba en algo como que va reduciendo su durabilidad con cada ataque, y en vez de bajar la calidad de defensa simplemente se destruya cuando su durabilidad llegue a 0.

#3 Agosto 09, 2015, 05:50:48 AM Ultima modificación: Agosto 09, 2015, 06:01:10 AM por fasst007
Acá te hice un codigo. Además de lo que vos me pediste hice otras cositas

1) Implementé algo nuevo (al menos para mi, porque se me ocurrio hoy) para la declaración de las variables globales y es usando la estructura ds_map. Trae algunas ventajas, por ejemplo yo necesitaba armar un nombre de variable por medio del manejo de cadena textos y luego decirle a Game Maker que esa cadena de texto es en realidad una variable. Con ds_map esto es posible, porque usa cadenas como "clave" y luego el valor que querramos. Pero para que no sea aburrido usar ds_map hice dos script: cod_set_global y cod_get_global para guardar un valor global y para leerlo. Algunos piensan que el manejo de ds_map es algo lento pero no creo que lo sea porque hice miles de lecturas simuladas y no vi demoras considerables.

2) Una recomendacion de Game Maker es usar prefijos para los recursos del juego. Yo traté de hacer esto a modo de ejemplo: en los script use el prefijo "cod_", en los fondos el prefijo: "bck", en los sprites el prefijo: "spr" y esto es para esclarecer el código cuando hacemos referencia a uno de estos objetos sabiendo en un golpe de vista de que se trata. También para evitar nombres repetidos. Yo a los objetos no les pongo prefijo.

3) También es útil organizar los recursos en carpetas y subcarpetas para poder tenerlo más organizado porque el tema es cuando dejes el código y el año que viene lo quieras modificar
y se puede complicar la cosa. Por eso puse un ejemplo de esto sobre todo en los sprites.

4) Puse un objeto controlador llamado chip_principal que es el que crea las variables globales del juego, y también controla otras cosas como por ejemplo la salida por pantalla de los valores de las variables, la deteccion de los clic del mouse. Este tipo de objetos son útiles y lo puedes implementar, yo lo puse como objeto persistente que si bien no cambia nada en este gmz que te mandé si lo haría en un juego real para que siga existiendo a pesar que se cambie de room, por eso lo puse en persistente como ejemplo.

5) A ese objeto controlador lo ordeno al principio con el boton "instance_order"  que está en la ficha "settings" de las propiedades del room para que la primera instancia que se cree sea este controlador, después fijate que esto se puede manipular desde esa ventana.

6) Hice un solo objeto bola que luego se le asignará el sprite y la velocidad que la saca de un valor global mediante las funciones que incorporé para ello. Entonces ese objeto "bola" funciona como comodín para todas las bolas.

7) Si quieres agregar otro tipo de bola, lo único que debes hacer es crear un sprite con el nombre: "spr_bola_" y el número de su potencia, por ejemplo: sprite_bola_15;
en el evento "create" del "chip_principal" asignarle una velocidad con cod_set_global("bola_15_vel", 30); por citar un ejemplo. Lo que olvidé es poner una velocidad por defecto en caso de que no se asigne ninguna. Luego en algún lado con cod_bola_crear(15);
sería todo, y no habría que modificar nada porque los códigos son genéricos.

8) Hice un evento en las balas que si salen del room sean destruidos, esto es muy importante porque si tiras 100 balas y no las destruyes al salir del room seguirían existiendo haciendo pesado el juego

9) Hice un ejemplo de velocidad relativa y tiempo relativo. En el caso de la velocidad relativa me refiero a que si en un futuro en alguno de tus juegos modificas la velocidad del room al doble (por ejemplo), que esto no haga que todos tus personajes vayan el doble de rápido sino que su velocidad sea igual lo que debería cambiar es la fluidez, es decir, el doble de transiciones en los movimientos. Entonces puedes setear la velocidad del room dependiendo la potencia del dispositivo en el cual se corra y sin alterar las velocidades de los objetos.
El tiempo relativo quiere decir que si haces que una animacion dure 5 cuadros tardando 1/6 seg en un room de 30 step/seg, al  duplicar la velocidad del room esa animación no dure 1/12 seg sino que debería durar lo mismo (caso similar al de la velocidad)
Entonces en lugar de usar velocidades y duracion de step fijos (absolutos) los haces relativos.
También existe la posición relativa pero no lo incorporé en mi ejemplo porque ya estaba algo cansado ja.

10) Para aumentar la velocidad de las balas incorporé la variable "factor_velocidad" que al estar en 1.1 aumentaría un 10% de la velocidad normal de las bolas. al estar un 1.5 la aumentaria en un 50% al estar en 2 el doble, y en un 0.5 a la mitad, etc

11) El código del manejo de la armadura y la vida la hice como me pediste. No hay deterioro de la armadura sino que se "deteriora su vida util" o se reduce su vida útil, es decir, el hecho que esté dañada a la mitad no hace que proteja menos. Cuando se dañe totalmente se destruye, eso creo que era lo que querías.

12) La función del daño de las bolas a la vida y armaduras son en forma relativa a la protección de la armadura y la potencia de la bola y funcionaría también para todas las bolas creadas en el futuro sin tener que modificar nada de código para incorporarlas (esto es lo bueno de manejar datos relativos y no valores numericos fijos). La misma está explicada dentro del "evento" colisión del jugador.
La función no es lineal sino cuadrática está explicado en los comentarios, pero podría mejorarse con una variable que disminuya la pendiente cuadrática cosa que olvidé hacer para que no sea tan abrupto la diferencia con lo lineal.

13) Los valores de la vida del jugador y de la armadura como otros datos como la velocidad del room, etc. pueden verse en tiempo real porque los muestro en la esquina superior derecha.
También podes modificar algunas variables en tiempo real mediante unos botones que te dejé en la parte inferior, tan solo hay que hacerles clic.
Con clic izquierdo en cualquier lugar del room (excepto en los botones de la parte inferior) se dispara una bola 10 y con el clic derecho una bola 26.

14) No he tenido tiempo de testear esto, pero creo que funciona bien para ir probandolo.
Recuerda leer los comentarios del código.

Saludos. Te adjunto el fuente

P.D.: Hice que el daño recibido con una bola de la misma potencia que la calidad de defensa de la armadura, es decir, potencia de bola 10 con armadura = 10, el daño sea del 20% porque la armadura cubriría el 80%. Ese dato del 80% se toma como base (y se puede cambiar en el código). Cuando el valor de la armadura es distinto al valor de la potencia de la bala se hace una función cuadrática que amplifica las cosas. Si la bala es débil que la armadura aún más debil se hace y si la bola es más fuerte que la armadura más fuerte se hace. Esto porque 100 balas de potencia 0.5 no le hacen nada a una armadura de 10. Pero una sola bala de 50 haría mucho más daño, entonces la cosa no es lineal.

Los datos de vida y armadura del jugador no los hice globales sino que los definí dentro del mismo objeto (se puede hacer también de esta forma) lo bueno de esto es que si hay más de un objeto jugador cada uno llevaría su propia cuenta acerca de su vida y su armadura.


Vale, lo descarge pero no pude profundizar mucho en el codigo, eso si, cuando probe el juego funcionaba a la perfeccion, aproveche de darme el lujo de modificar algo simple y en vez de ir de 5 en 5 la armadura podia añadirle de a 1, solo para probar como andaba, y el resultado es justo lo que queria  :) ahora solo me falta profundizar en el codigo (le heche una mirada rapida y estoy un poco confundido xD) para entenderlo bien.

Ahora, no se si se puede modificar los valores, ya que los ataques en el futuro pienso hacerlos con cifras grandes (1600- a 2000 o incluso mucho mas altos, ya que los enemigos al subir de nivel iran atacando mas, ni que decir con los bosses) como tambien las armaduras (super armaduras de 480, 890, 1200, etc).

Saludos y muchas gracias, cualquier duda te informo por privado  :P

#5 Agosto 10, 2015, 06:21:28 PM Ultima modificación: Agosto 10, 2015, 06:54:03 PM por fasst007
No te preocupes, vamos a hacer un código mas simple para que se entienda y luego lo iremos mejorando si hace falta. No usaremos un solo objeto para todas las bolas ni la velocidad ni tiempo relativos por ahora.

1) Vamos a hacer un objeto bola por cada tipo de bola. Es decir, si existen 4 tipos de bola con potencia 10, 26, 50 y 100 entonces vamos a crear 4 objetos:

bola_10
bola_26
bola_50
bola_100

En cada uno de esos objetos le asignas su sprite correspondiente, vamos a hacer un evento "create" en cada uno de ellos y en el mismo le vamos a asignar valores, como por ejemplo su potencia y velocidad. Por ejemplo en la bola 10:

potencia = 10;
velocidad = (la que querramos)

asi bien simple, entonces al crear una instancia del objeto automáticamente se le asignan esos dos valores establecidos en el evento "create". La dirección se la deberíamos asignar después de crear la instancia según donde se quiera disparar en el juego y no en el objeto create.

luego creas un objeto llamado simplemente "bola" y no le asignas ningún sprite ni código ni nada. Luego de crear este objeto, procedes a definir en todos los objetos bola distintos (bola_10, bola_26.. etc) su "parent" (que esto se encuentra en las opciones del objeto cuando le haces "doble clic") y eliges el objeto "bola".

¿Para que sirve esto? Te lo explico. Como el evento de colisión no está en cada bola sino en el personaje mismo, sería muy impráctico que este personaje preguntara: ¿me toco una bola 10?, ¿me tocó una bola 26?, me tocó una bola 50?, ¿me tocó una bola_100?. Entonces le decimos a Game Maker que todos esos objetos: bola_10, bola_26, bola_50 y bola_100 (y los que haya en el juego) tienen la misma característica y es que todos son bolas. Entonces por eso definimos un objeto "bola" que los agrupe y todos tienen esa misma característica, el mismo objeto "parent" o "padre". Y entonces el objeto jugador, en el evento colisión, simplemente pregunta ¿colisioné con alguna bola? esto se logra poniendo el evento colisión con ese objeto "bola" que definimos.  Y ahí ponemos el código.

El cálculo del daño de la armadura y de la vida la haremos con una fórmula simple lineal, es decir, proporcional en lugar de la cuadrática que habíamos definido antes. De esta base simple haremos el código. Y ya te lo pasaré

Pero haré un cambio de concepto para hacerlo aún más simple. La armadura de valor x cubre todo daño de bolas de potencia x o inferior. Pero al recibir los impactos su vida útil se deteriora hasta que se destruye la armadura. Potencias superiores a la armadura el jugador recibe daño excedente a lo que cubre la armadura, y la armadura se deteriora también proporcionalmente. Es decir sencilla la cosa para comenzar







#6 Agosto 10, 2015, 09:06:47 PM Ultima modificación: Agosto 10, 2015, 09:27:19 PM por fasst007
Listo! aca te paso el fuente. Recuerda que no solo simplifiqué el código sino que también el algoritmo cambió como lo explico en mi comentario anterior. Por ello si tenés armadura 10 y recibís un impacto de bola_10 no recibís ningún daño a diferencia del algoritmo anterior que recibías un 20% de daño. Pero sin embargo la vida útil de la armadura se va reduciendo hasta que se destruye y te quedas sin armadura. Fijate si es más entendible el código luego en base a esto se puede ir modificando.

El fuente que te pasé tiene dos bolas como el fuente anterior: bola_10 y bola_26 pero podés agregar nuevas bolas creando un objeto para cada nuevo tipo de bola y definiendo su evento create como tienen las demás.
Para lanzarla usa el mismo código que tiene el chip_principal en el evento del mouse.

Pero ten en cuenta que para potencias de bola muy fuertes como 1000 o 2000 debes pensar en que un solo disparo de esos mataría al jugador en caso de que no tuviese armadura. Entonces o permanentemente tiene que tener una armadura puesta en estos niveles (y en caso que no la tenga esquivar todas las bolas porque una sola te mata) o fortalecer al jugador también (además de mejorar las armaduras, por supuesto, para estar a la altura de esos impactos eso lo damos por obvio).
 

Excelente, he estado examinando el codigo y es perfecto, bien facil y util! muchísimas gracias capo!