Manejar el tiempo para los enemigos

Hola a todos,lo primero pongo el enlace a este video

Bueno la pregunta es si os fijais en el juego del video la salida de las naves enemigas lo hace cada sierto tiempo pero no se como hacerlo igual,yo he intentado con contadores y con random pero no queda igual.

Si veis el juego del video parece que controla el tiempo de salida de las naves de manera manual,como que salgan en el segundo 5 para despues salir en el segundop 20,pero no todas hacen eso,y bueno agradeceria que me comentarais como hacen esta rutina para que mi juego de naves quede medio bien.

Bueno por ultimo se que todavia no me han contestado a la otra pergunta y no se si esta bien hacer otra pregunta hasta que se me conteste a la otra,pero yo la dejo hay por que si no se me olivida.Bueno contestarme cuando podais yo me despido.Hasta pronto

solo escribo esto para que la pregunta suba hasta arriba y la puedan ver mejor,porque ya a pasado mucho desde que la escribi

Amigo, por l oque veo parece que salen de acuerdo a la energia que le queda a las naves que estan en la pantalla

no se a que energia te refieres,yo solo veo la puntuacion y la otra parece una puntuacion de lo que van soltando las naves enemigas

Hola @hokuto!! mil disculpas por la demora.

En muchos juegos de naves que ví los niveles están diseñados casi manualmente. Es decir, siempre se repite el mismo patrón cuando el jugador vuelve a jugar el mismo nivel. Así que creo que lo mejor es implementarlo igual, sin usar rutinas aleatorias o temporizadores.

Ojo, hay juegos en donde las naves enemigas aparecen aleatoriamente; no reconozco muy bien si en el juego que muestras esto es aleatorio o pre-diseñado… pero, vamos a suponer que es pre-diseñado, vas a ver que se puede construir un juego interesante incluso asumiendo eso:

En un nivel pre-diseñado se suelen definir de antemano los enemigos que van a aparecer en el juego y en qué momento van a aprecer. Por ejemplo, en este caso, se me ocurrió que podría haber tres tipos de enemigos:

  • enemigoDesdeDerecha
  • ernemigoDiagonal
  • enemigoElastico

Cada uno de estos enemigos debería entrar en la escena con un movimiento característico, movimientos que incluso podemos bocetar antes de comenzar a escribir código. Mirá como me imagino estos tres tipos de enemigos:

El EnemigoDesdeDerecha podría entrar en la escena con un moviento de derecha a izquierda, subiendo y bajando suavemente.

El EnemigoDiagonal puede entrar de arriba hacia abajo, moviéndose un poquito a la derecha cuando está bajando.

Y el último tipo de enemigo, llamado EnemigoElastico, baja y sube. Es más agresivo que los demás, podría tomar desprevenido al jugador. Imaginá que en una situación de juego normal, el jugador va a estar moviéndose entre disparos, acorralado, sin poder detenerse en prestar atención al movimiento pre-diseñado de los enemigos.

En fin, con ese diseño, una vez prediseñados los enemigos, podrías comenzar a implementar estos actores en pilas creando tres clases de actores, uno para cada tipo de enemigo:

class EnemigoDesdeDerecha(pilasengine.actores.Actor):
    
    def iniciar(self, x, y, velocidad):
        self.aprender('puedeExplotar')
        self.imagen = "aceituna.png"
        self.velocidad = velocidad
        self.x = 400
        self.y_inicial = y
        self.contador = 0
        
    def actualizar(self):
        self.x -= self.velocidad
        self.contador += 0.1
        # Hace un movimiento suave de arriba hacia abajo
        self.y = self.y_inicial + math.sin(self.contador) * 50
            
        # Si sale de la pantalla
        if self.x < -400:
            self.eliminar()


class EnemigoDiagonal(pilasengine.actores.Actor):

    def iniciar(self, x, y, velocidad):
        self.aprender('puedeExplotar')
        self.imagen = "aceituna.png"
        self.velocidad = velocidad
        self.x = x
        self.y = 300
        self.y_para_cambiar_direccion = y
        self.direccion = "hacia_abajo"
        
    def actualizar(self):
        
        if self.direccion is "hacia_abajo":
            self.y -= self.velocidad
            
            # Si llega abajo, regresa arriba
            if self.y < self.y_para_cambiar_direccion:
                self.direccion = "hacia_arriba"
        else:
            self.y += self.velocidad
            
            # Si esta subiendo, y sale de la pantalla se elimina
            if self.y > 400:
                self.eliminar()
            
        self.x += self.velocidad / 2.0


class EnemigoElastico(pilasengine.actores.Actor):

    def iniciar(self, x, y, velocidad):
        self.aprender('puedeExplotar')
        self.imagen = "aceituna.png"
        self.velocidad = velocidad
        self.x = x
        self.y = 400
        self.y_inicial = 400
        self.contador = 0
        
    def actualizar(self):
        self.contador += 0.01
        
        self.y = self.y_inicial - math.sin(self.contador * self.velocidad) * 600
                
        if self.y > self.y_inicial:
            self.eliminar()

Al principio el código puede parece mucho, pero no te preocupes, generalmente el código se escribe poco a poco; escribí tres clases juntas para que el juego parezca más interesante, solo por eso. Con una clase alcanzaba sinceramente.

Ahora bien, con tres tipos de enemigos, es fácil pensar en un nivel desafiante para el jugador de juego; este paso dependen mucho de vos; de hacer pruebas y errores, hacer que algún amigo juegue a tu juego y ver si realmente está bien o mal…

Acá voy a imaginar un nivel muy simple:

  • primero aparecen tres actores desde la derecha.
  • luego otros tres un poco más arriba.
  • después 3 en diagonal
  • y muy cerca de esos 3 agresivos, de arriba hacia abajo.
  • por último si el jugador sobrevivió, un mensaje que diga “esto se solo el comienzo”.

Para llevar eso al juego lo mejor es crear una lista con todos los pasos, y luego crear un temporizador que lo ponga en funcionamiento.

Este es un video de cómo quedaría lo que me imagino, luego vemos el código:

Mirá como los personajes aparecen, siempre siguiendo el mismo patrón. Esto es así porque en realidad los actores se lanzan a la escena usando un diseño pre-diseñado así:

enemigos = pilas.actores.Grupo()


def agregar_enemigo(clase, x, y, velocidad):
    enemigos.agregar(clase(x=x, y=y, velocidad=velocidad))




nivel = [


    {'tiempo': 2, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 0, 'velocidad': 2},
    {'tiempo': 3, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 0, 'velocidad': 2},
    {'tiempo': 4, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 0, 'velocidad': 2},

    {'tiempo': 6, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 100, 'velocidad': 2},
    {'tiempo': 7, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 100, 'velocidad': 2},
    {'tiempo': 8, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 100, 'velocidad': 2},            
            
            
    {'tiempo': 10, 'actor': pilas.actores.EnemigoDiagonal, 'x': -200, 'y': 0, 'velocidad': 4},
    {'tiempo': 11, 'actor': pilas.actores.EnemigoDiagonal, 'x': -200, 'y': 0, 'velocidad': 4},
    {'tiempo': 12, 'actor': pilas.actores.EnemigoDiagonal, 'x': -200, 'y': 0, 'velocidad': 4},
            


            
    {'tiempo': 14, 'actor': pilas.actores.EnemigoElastico, 'x': -100, 'y': 0, 'velocidad': 1},
    {'tiempo': 15, 'actor': pilas.actores.EnemigoElastico, 'x': 0, 'y': 0, 'velocidad': 1},
    {'tiempo': 16, 'actor': pilas.actores.EnemigoElastico, 'x': 100, 'y': 0, 'velocidad': 1},
            
            
    {'tiempo': 20, 'actor': pilas.actores.Terminado, 'x':0, 'y': 0, 'velocidad': 0},
]

for x in nivel:
    pilas.tareas.agregar(x['tiempo'], agregar_enemigo, x['actor'], x['x'], x['y'], x['velocidad'])
    

Hay dos partes importantes en este código, por un lado está la lista nivel. En esa lista debería colocar cada aparición de actores en la escena, especificando el tiempo de aparición (en segundos), luego qué actor tiene que aparecer, y por último algunos parámetros de posición (para no hacerlo tan monótono).

Armar esta lista es parte del diseño de nivel, es esa parte de la construcción del juego que implica pruebas y más pruebas, hacer que la gente juegue y ver qué tan divertido es el juego. El 80% del juego está ahí digamos :slight_smile:

La segunda parte de ese código consiste en esa llamada a pilas.tareas.agregar, que básicamente le dice a la computadora en qué momento tiene que crear el actor.

Para resumir, te dejo el código completo que escribí mientras pensaba en escribirte. Podés pegar este código directamente en el editor de pilas para verlo funcionar:

# coding: utf-8
import pilasengine
import math

pilas = pilasengine.iniciar()


class EnemigoDesdeDerecha(pilasengine.actores.Actor):
    
    def iniciar(self, x, y, velocidad):
        self.aprender('puedeExplotar')
        self.imagen = "aceituna.png"
        self.velocidad = velocidad
        self.x = 400
        self.y_inicial = y
        self.contador = 0
        
    def actualizar(self):
        self.x -= self.velocidad
        self.contador += 0.1
        # Hace un movimiento suave de arriba hacia abajo
        self.y = self.y_inicial + math.sin(self.contador) * 50
            
        # Si sale de la pantalla
        if self.x < -400:
            self.eliminar()


class EnemigoDiagonal(pilasengine.actores.Actor):

    def iniciar(self, x, y, velocidad):
        self.aprender('puedeExplotar')
        self.imagen = "aceituna.png"
        self.velocidad = velocidad
        self.x = x
        self.y = 300
        self.y_para_cambiar_direccion = y
        self.direccion = "hacia_abajo"
        
    def actualizar(self):
        
        if self.direccion is "hacia_abajo":
            self.y -= self.velocidad
            
            # Si llega abajo, regresa arriba
            if self.y < self.y_para_cambiar_direccion:
                self.direccion = "hacia_arriba"
        else:
            self.y += self.velocidad
            
            # Si esta subiendo, y sale de la pantalla se elimina
            if self.y > 400:
                self.eliminar()
            
        self.x += self.velocidad / 2.0


class EnemigoElastico(pilasengine.actores.Actor):

    def iniciar(self, x, y, velocidad):
        self.aprender('puedeExplotar')
        self.imagen = "aceituna.png"
        self.velocidad = velocidad
        self.x = x
        self.y = 400
        self.y_inicial = 400
        self.contador = 0
        
    def actualizar(self):
        self.contador += 0.01
        
        self.y = self.y_inicial - math.sin(self.contador * self.velocidad) * 600
                
        if self.y > self.y_inicial:
            self.eliminar()


class Terminado(pilasengine.actores.Actor):

    def iniciar(self, x, y, velocidad):
        self.imagen = "invisible.png"
        self.pilas.actores.Texto("Esto es solo el principio ...")


pilas.actores.vincular(EnemigoDesdeDerecha)
pilas.actores.vincular(EnemigoDiagonal)
pilas.actores.vincular(EnemigoElastico)
pilas.actores.vincular(Terminado)


enemigos = pilas.actores.Grupo()


def agregar_enemigo(clase, x, y, velocidad):
    enemigos.agregar(clase(x=x, y=y, velocidad=velocidad))




nivel = [


    {'tiempo': 2, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 0, 'velocidad': 2},
    {'tiempo': 3, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 0, 'velocidad': 2},
    {'tiempo': 4, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 0, 'velocidad': 2},

    {'tiempo': 6, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 100, 'velocidad': 2},
    {'tiempo': 7, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 100, 'velocidad': 2},
    {'tiempo': 8, 'actor': pilas.actores.EnemigoDesdeDerecha, 'x': 0, 'y': 100, 'velocidad': 2},            
            
            
    {'tiempo': 10, 'actor': pilas.actores.EnemigoDiagonal, 'x': -200, 'y': 0, 'velocidad': 4},
    {'tiempo': 11, 'actor': pilas.actores.EnemigoDiagonal, 'x': -200, 'y': 0, 'velocidad': 4},
    {'tiempo': 12, 'actor': pilas.actores.EnemigoDiagonal, 'x': -200, 'y': 0, 'velocidad': 4},
            


            
    {'tiempo': 14, 'actor': pilas.actores.EnemigoElastico, 'x': -100, 'y': 0, 'velocidad': 1},
    {'tiempo': 15, 'actor': pilas.actores.EnemigoElastico, 'x': 0, 'y': 0, 'velocidad': 1},
    {'tiempo': 16, 'actor': pilas.actores.EnemigoElastico, 'x': 100, 'y': 0, 'velocidad': 1},
            
            
    {'tiempo': 20, 'actor': pilas.actores.Terminado, 'x':0, 'y': 0, 'velocidad': 0},
]

for x in nivel:
    pilas.tareas.agregar(x['tiempo'], agregar_enemigo, x['actor'], x['x'], x['y'], x['velocidad'])
    



nave = pilas.actores.NaveRoja(y=-200)
nave.definir_enemigos(enemigos)

pilas.ejecutar()

¡Abrazo!

muchas gracias por la respuesta tan detallda,me salvas la vida,ya casi tengo todo para armar el juego:heart_eyes: