Problemas con el disparo enemigo automatico (SOLUCIONADO)

Buenas, que tal?
Estoy creando mi primer juego con pilasengine, y tengo un pequeño problema con el disparo de los enemigos, que quiero que sea cada n segundos. He probado todo lo que he podido encontrar por los ejemplos y por google, pero no consigo crear esa tarea de manera satisfactoria. Si coloco la tarea en def iniciar(self): los enemigos siguen disparando aún despues de ser eliminados (!!!???). Si coloco esa tarea en la def actualizar(self): el disparo es continuo tipo metralleta (!!!???). Lo he solucionado como he podido con una chapucilla, pero no creo que sea lo correcto.

Otro problema es que el juego se ralentiza casi de inmediato, cayendo de 60 a 2 fps a la que hay 2 o 3 actores en escena. (No creo que tenga que ver, pero lo menciono por si acaso: mi SO es LinuxMint)

Les agradeceria mucho me ayudaran con estos dos problemas. Gracias de antemano.
agrego el codigo para que puedan revisar posibles fallos.

# -*- encoding: utf-8 -*-
#OVNIGUNNER. v 1.0 

import pilasengine
#import sys
#sys.path.insert(0, "..")
pilas = pilasengine.iniciar()



class Ovnis_Enemigos(pilasengine.actores.Actor):
    vida=10 #tenemos que clicarle 10 veces para matarlo

    def iniciar(self):
        self.x = self.pilas.azar(-280, 280)
        self.altura = self.pilas.azar(50, 200)
        self.imagen = "ovni.png"
        self.y = self.pilas.azar(-50, 0)
        self.z = 1
        self.escala = 0.1
        self.aprender("puedeexplotar")
        self.aprender("disparar", control=None, municion= 'MiMunicion', angulo_salida_disparo=pilas.azar(250,290)) #, frecuencia_de_disparo =1)
        #pilas.tareas.siempre(3,self.disparar) #Si uso esto sigue disparando despues de ser eliminado
    def actualizar(self):
		pilas.utils.interpolar(self,'rotacion', 360, duracion=3)
		pilas.utils.interpolar(self, 'escala', 1.5, duracion=20)
		pilas.utils.interpolar(self, 'y', self.altura, duracion=15)
		if self.escala >= 0.7:
			self.imagen = "ovni2.png"
		
		#Esta es la unica manera que he encontrado de disparar
		#pero no es lo que necesito:
		if self.escala >= 0.899 and self.escala < 0.900:
			self.disparar()
		elif self.escala >= 1.189 and self.escala < 1.190:
			self.disparar()
		elif self.escala >= 1.489 and self.escala < 1.490:
			self.disparar()
				
		# Elimina al actor si sale de la pantalla
		if self.y > 250 or self.y < -150:
			self.eliminar()
		# El ovni intenta evitar nuestros disparos
		if self.vida < 7 and self.vida >2:
			pilas.utils.interpolar(self,'y', pilas.azar(-160,240), duracion =2)
			pilas.utils.interpolar(self,'x', pilas.azar(-250,250), duracion =2)		
    
    def dispararconclick(self):
		#"Se invoca cuando se hace click sobre el ovni."
        self.vida -=1
        #print(self.vida)
        if self.vida == 0:
            self.eliminar()
            self.pilas.camara.vibrar(1, 0.3)
            self.pilas.actores.Ovni_Abatido(self.x, self.y)
            
	

class MiMunicion(pilasengine.actores.Actor):

    def iniciar(self):
        self.imagen = "disparos/bola_amarilla.png"
        self.escala= 0.1
        self.aprender("puedeexplotar")
    
    def actualizar(self):
        self.escala_y += 0.1
        if self.y == -140:
			self.eliminar()


class Ovni_Abatido(pilasengine.actores.Actor):
	
	def iniciar(self, x, y):
		self.imagen = "ovni.png"
		self.x = x
		self.y = y
		self.transparencia = [10]		
		self.dx = self.pilas.azar(-3, 3)
		self.escala = 1.2
		self.aprender("puedeexplotar")
		
	def actualizar(self):
		self.x += self.dx
		self.y -= 3 
		self.rotacion += 5
		
		if self.y < -180:
			self.pilas.camara.vibrar(2, 0.3)
			self.eliminar()


class EscenaMenu(pilasengine.escenas.Escena):

    def iniciar(self):
        self.pilas.fondos.FondoMozaico('azul.png')
        actor_texto = self.pilas.actores.Actor()
        actor_texto.imagen = "click.png"
        self._aplicar_animacion(actor_texto)
        self.pilas.eventos.click_de_mouse.conectar(self._iniciar_el_juego)
        self._crear_el_titulo_del_juego()
        self._crear_indicador_creditos()
        
		
    def _aplicar_animacion(self, texto):
        texto.y = -500
        texto.escala = 4
        texto.escala = [1], 1.5
        texto.y = [-100], 1

    def _iniciar_el_juego(self, evento):
        self.pilas.escenas.EscenaJuego()

    def _crear_el_titulo_del_juego(self):
        titulo = self.pilas.actores.Actor()
        titulo.imagen = "titulo.png"
        titulo.y = 300
        titulo.rotacion = 30
        titulo.y = [100], 1
        titulo.rotacion = [0], 1.2

    def _crear_indicador_creditos(self):
        actor = self.pilas.actores.Actor()
        actor.imagen = "creditos.png"
        actor.x = 400
        actor.y = -200
        actor.x = [400, 400, 270], 0.5


class BotonVolver(pilasengine.actores.Actor):

    def iniciar(self):
        self.imagen = "boton_volver.png"
        self.cuando_hace_click = self._volver_a_la_escena_inicial
        self.y = [230]
        self.x = -270
        self.escala =0.5
        
    def _volver_a_la_escena_inicial(self, evento):
        self.pilas.escenas.EscenaMenu()


class EscenaPerdido(pilasengine.escenas.Escena):
	
	def iniciar(self):
		self.pilas.fondos.FondoMozaico('azul.png')
		self.pilas.eventos.click_de_mouse.conectar(self._ir_al_menu)
		#falta cargar una imagen y un texto
		
	def _ir_al_menu(self):
		self.pilas.escenas.EscenaMenu()	
		




class EscenaJuego(pilasengine.escenas.Escena):
	
	
	def _crear_un_ovni(self):
		self.pilas.actores.Ovnis_Enemigos()
		#pilas.avisar("Enemigo localizado")
		
	
	def _cuando_hace_click(self, evento):
		explosion = pilas.actores.Animacion(imagen_explosion)
		explosion.escala = 0.5
		explosion.x = evento.x
		explosion.y = evento.y
		sonido_explosion.reproducir()
		
		
		#obtenemos las colisiones con el mouse	
		colisiona = self.obtener_actores_en(evento.x, evento.y)
		for actor in colisiona:
			if isinstance(actor, Ovnis_Enemigos):
					if actor.escala >= 0.7:
						actor.dispararconclick()
					else:
						None
						#print("No se puede")
	
	
	
	def findejuego(self):
		self.pilas.escenas.EscenaPerdido()
	
	def iniciar(self):
		self.fondo = pilas.fondos.Noche()
		self._crear_boton_volver()
		pingu = pilas.actores.Pingu(y= -240)
		pingu.escala =0.5
		pingu.aprender('limitadoabordesdepantalla')
		
		#fondo.imagen = pilas.imagenes.cargar('snow2.png')
		                 
		pilas.tareas.siempre(3, self._crear_un_ovni)
		
		pilas.eventos.click_de_mouse.conectar(self._cuando_hace_click)
		
		pilas.colisiones.agregar('pingu','MiMunicion',self.findejuego)
		

	def _crear_boton_volver(self):
		pilas.actores.BotonVolver()




imagen_explosion = pilas.imagenes.cargar_grilla("explosion.png", 7)
sonido_explosion = pilas.sonidos.cargar("explosion.wav")


		
## Vinculamos todas las escenas.
pilas.escenas.vincular(EscenaMenu)
pilas.escenas.vincular(EscenaJuego)
pilas.escenas.vincular(EscenaPerdido)

## Vinculamos los actores Personalizados
pilas.actores.vincular(BotonVolver)
pilas.actores.vincular(MiMunicion)
pilas.actores.vincular(Ovnis_Enemigos)
pilas.actores.vincular(Ovni_Abatido)


# Se inicia la escena principal.
pilas.escenas.EscenaMenu()
#pilas.escenas.EscenaJuego()
pilas.ejecutar()

Hola @jordinur, ¡que buena pinta tiene el juego!, si bien no pude verlo con las imágenes tuyas, se nota que es jugable y tiene varios efectos de cámara que pintan muy bien.

Te comento lo que pude encontrar:

  1. El rendimiento del juego se va deteriorando porque se generan varias tareas al mismo tiempo, cuando generamos una interpolación usando algo como pilas.utils.interpolar(self,'rotacion', 360, duracion=3) pilas construye un objeto en memoria y lo va procesando, cuantos más objetos generamos más lento se pone.

En el juego noté que esta interpolación se estaba generando en el método actualizar, así que pilas estaba queriendo hacer 60 interpolaciones por segundo, y de ahí que se volvía lento.

La solución es muy sencilla, tendrías que mover las lineas que realizan la interpolación dentro del método “actualizar” al método “iniciar”, para que se ejecuten una sola vez:

Por cierto, ahora que lo pienso, en pilas no incluímos un indicador que nos muestre la cantidad de interpolaciones… es algo que se nos pasó por alto :sweat: voy a agregarlo para realizar en el próxima versión de pilas.

  1. Para que el ovni dispare podrías usar tareas, que es una forma muy sencilla de poder llamar a una función de forma temporizada. Por ejemplo, si quisieras disparar cada 2 segundos podrías agregar algo así:

Creo que con eso quedaría 10 puntos. ¡Abrazo!

PD: ah, otro detalle, noté que el código usa tabs y espacios; fijate que tu editor debe necesitar algo de configuración para que solo use un solo sistema de identación. Cualquier sistema de identación estará bien para python, pero cuando se mezclan comienza a dar problemas…

Ante todo muchas gracias por la molestia de revisar mi juego y por darme tan buenos consejos. Voy a probarlos todos, y cuando tenga los resultados comento como me ha ido.
A decir verdad lo de los efectos y todo eso no es bien merito mio, ya que mucho del codigo lo copie del juego del tiro a los patitos de los ejemplos de pilas. He de decir que soy MUY novato, tanto en Python como en Pilas y de momento más que crear me dedico a adaptar (al menos mientras no tenga una base más sólida…)
Y si, necesito condicionar la escala del ovni_enemigo, para dar sensacion de que se esta acercando y de que hasta que no está cerca no lo alcanzan nuestros disparos. De hecho, en mi juego cuando el ovni está a una escala de 0,7 cambia la imagen y le aparece un punto de mira que indica que está a tiro y se le puede matar.
En cuanto a los espacios y tabulaciones, es que al principio lo edité desde pilas, pero luego preferí seguir desde Geany, al que estoy más acostumbrado. Yo tambien me vuelvo loco a veces buscando los fallos de indexación… :slight_smile:
De nuevo muchas gracias, y mis felicitaciones por vuestra gran labor.

PD: Estoy intentando montar un “taller colaborativo” de Python + PilasEngine en mi localidad. A ver si consigo que se apunten unas pocas personas y entre todos aprendemos de todos!!!

Hola de nuevo,
ya he hecho las modificaciones sugeridas, y la verdad es que no tiene punto de comparación… ES MUCHO MAS RAPIDO !!!
Muchas gracias por todos esos buenos consejos,
El tema del tiro automatico de los enemigos tambien va de lujo, ahora disparan cada 2 segundos y no se dan errores ni “ovnis fantasmas disparando”.
Lo único que podria mejorarse es que el ángulo de tiro fuera diferente en cada disparo, ya que ahora cada uno de los ovnis tiene un único ángulo de tiro y se veria mejor si cada tiro tuviera un angulo diferente (tambien haria más difícil el juego)
De nuevo MIL GRACIAS.

Bueno, ya consegui el angulo de tiro aleatorio, para mi esta terminado… Dejo el codigo completo por si a alguien mas le sirviera de ejemplo

# -*- encoding: utf-8 -*-
#OVNIGUNNER. v 1.0 
# Creado por Jordi Mestres (Alfons del Pou), julio de 2016, con PilasEngine
#Este juego es considerado "Free Software" a todos los efectos, y se aplican
#las cuatro leyes fundamentales del software libre, sin ninguna restriccion de uso,
#acceso al codigo, modificacion o distribucion

import pilasengine
pilas = pilasengine.iniciar(titulo="Ovni Gunner")


class Ovnis_Enemigos(pilasengine.actores.Actor):

    def iniciar(self):
        self.x = self.pilas.azar(-280, 280)
        self.altura = self.pilas.azar(50, 200)
        self.imagen = "ovni.png"
        self.y = self.pilas.azar(-50, 0)
        self.z = 1
        self.escala = 0.1
        self.aprender("puedeexplotar")
        #self.aprender("disparar", control=None, municion= 'MiMunicion')#, angulo_salida_disparo = pilas.azar(235,305)) #, frecuencia_de_disparo =1)
        self.vida = 10 # Hay que clicarlo 10 veces para matarlo
        pilas.utils.interpolar(self,'rotacion', 360, duracion=3)
        pilas.utils.interpolar(self, 'escala', 1.5, duracion=20)
        pilas.utils.interpolar(self, 'y', self.altura, duracion=15)
		
        self.tarea_disparar= pilas.tareas.siempre(3, self.realizar_disparo)
    
    def actualizar(self):
		if self.escala >= 0.7: #Elovni tiene un punto de mira que indica que se puede matar
			self.imagen = "ovni2.png"
			
		# El ovni intenta evitar nuestros disparos
		if self.vida < 7 and self.vida >2:
			pilas.utils.interpolar(self,'y', pilas.azar(-160,240), duracion =3)
			pilas.utils.interpolar(self,'x', pilas.azar(-250,250), duracion =3)		
    
    def dispararconclick(self):
		#"Se invoca cuando se hace click sobre el ovni."
        if self.vida>0:
			self.vida -=1
        
        elif self.vida <= 0:
            self.eliminar()
            self.pilas.camara.vibrar(1, 0.3)
            self.tarea_disparar.terminar()
            self.pilas.actores.Ovni_Abatido(self.x, self.y)
            
    def realizar_disparo(self):
		if self.escala >= 0.8:
			#Esto hace que cada disparo tenga un angulo de tiro diferente
			self.aprender("disparar", control=None, municion= 'MiMunicion', angulo_salida_disparo = pilas.azar(250,290)) #, frecuencia_de_disparo =1)
			self.disparar()

class MiMunicion(pilasengine.actores.Actor):

    def iniciar(self):
        self.imagen = "disparos/bola_amarilla.png"
        self.escala= 0.1
        self.aprender("puedeexplotar")
    
    def actualizar(self):
        self.escala_y += 0.1
        if self.y == -140:
			self.eliminar()


class Ovni_Abatido(pilasengine.actores.Actor):
	# Cuando matamos el ovni cae girando hasta tocar suelo y explotar
	def iniciar(self, x, y):
		self.imagen = "ovni.png"
		self.x = x
		self.y = y
		self.transparencia = [10]		
		self.dx = self.pilas.azar(-3, 3)
		self.escala = 1.2
		self.aprender("puedeexplotar")
		
	def actualizar(self):
		self.x += self.dx
		self.y -= 3 
		self.rotacion += 3
		
		if self.y < -220:
			self.pilas.camara.vibrar(2, 0.3)
			self.eliminar()


class EscenaMenu(pilasengine.escenas.Escena):

    def iniciar(self):
        self.pilas.fondos.FondoMozaico('azul.png')
        actor_texto = self.pilas.actores.Actor()
        actor_texto.imagen = "click.png"
        self._aplicar_animacion(actor_texto)
        self.pilas.eventos.click_de_mouse.conectar(self._iniciar_el_juego)
        self._crear_el_titulo_del_juego()
        self._crear_indicador_creditos()
        ovnimenu=pilas.actores.Ovnis_Enemigos()*5
        ovnimenu.z=1
    
    def _aplicar_animacion(self, texto):
        texto.y = -500
        texto.escala = 4
        texto.escala = [1], 1.5
        texto.y = [-100], 1

    def _iniciar_el_juego(self, evento):
        self.pilas.escenas.EscenaJuego()

    def _crear_el_titulo_del_juego(self):
        titulo = self.pilas.actores.Actor()
        titulo.imagen = "sensetitol.png"
        titulo.y = 300
        titulo.rotacion = 30
        titulo.y = [100], 1
        titulo.rotacion = [0], 1.2
        titulo.z=2

    def _crear_indicador_creditos(self):
        actor = self.pilas.actores.Actor()
        actor.imagen = "creditos.png"
        actor.x = 400
        actor.y = -200
        actor.x = [400, 400, 270], 0.5
	pilas.avisar("Alfons del Pou, julio de 2016")

class BotonVolver(pilasengine.actores.Actor):

    def iniciar(self):
        self.imagen = "boton_volver.png"
        self.cuando_hace_click = self._volver_a_la_escena_inicial
        self.y = [230]
        self.x = -270
        self.escala =0.5
        
    def _volver_a_la_escena_inicial(self, evento):
        self.pilas.escenas.EscenaMenu()


class EscenaPerdido(pilasengine.escenas.Escena):
	# Se activa cuando matan a Pingu
	def iniciar(self):
		self.pilas.fondos.FondoMozaico('azul.png')
		pilas.actores.BotonVolver()
		pingu=pilas.actores.Pingu()
		pingu.y=-200
		pingu.escala= 3
		pingu.aprender("puedeexplotar")
		pingu.decir("Adios, Mundo cruel!!!")
		pilas.tareas.agregar(5, pingu.eliminar)
		pilas.avisar("Lo siento, no has podido salvar a Pingu...")
		
class EscenaJuego(pilasengine.escenas.Escena):
	#Escena principal del juego

	def _crear_un_ovni(self):
		self.pilas.actores.Ovnis_Enemigos()
		#pilas.avisar("Enemigo localizado")
	
	def _cuando_hace_click(self, evento):
		explosion = pilas.actores.Animacion(imagen_explosion)
		explosion.escala = 0.5
		explosion.x = evento.x
		explosion.y = evento.y
		sonido_explosion.reproducir()
		
		#obtenemos las colisiones con el mouse	
		colisiona = self.obtener_actores_en(evento.x, evento.y)
		for actor in colisiona:
			if isinstance(actor, Ovnis_Enemigos):
					if actor.escala >= 0.6:
						actor.dispararconclick()
					else:
						None
						#print("No se puede")
	
	def findejuego(self):
		self.pilas.escenas.EscenaPerdido()
	
	
	def iniciar(self):
		self.fondo = pilas.fondos.Noche()
		self._crear_boton_volver()
		pingu = pilas.actores.Pingu(y= -240)
		pingu.escala =0.5
		pingu.aprender('limitadoabordesdepantalla')
		                 
		pilas.tareas.siempre(5, self._crear_un_ovni)
		pingu.decir("Socorroooo...! MATA LOS OVNIS!!!")
		pilas.eventos.click_de_mouse.conectar(self._cuando_hace_click)
		
		pilas.colisiones.agregar('pingu','MiMunicion',self.findejuego)
		pilas.colisiones.agregar('pingu','Ovni_Abatido',self.findejuego)

	def _crear_boton_volver(self):
		pilas.actores.BotonVolver()


imagen_explosion = pilas.imagenes.cargar_grilla("explosion.png", 7)
sonido_explosion = pilas.sonidos.cargar("explosion.wav")
		
## Vinculamos todas las escenas.
pilas.escenas.vincular(EscenaMenu)
pilas.escenas.vincular(EscenaJuego)
pilas.escenas.vincular(EscenaPerdido)

## Vinculamos los actores Personalizados
pilas.actores.vincular(BotonVolver)
pilas.actores.vincular(MiMunicion)
pilas.actores.vincular(Ovnis_Enemigos)
pilas.actores.vincular(Ovni_Abatido)


# Se inicia la escena principal.
pilas.escenas.EscenaMenu()
pilas.ejecutar()

Ahí logré agregar el indicador de interpolaciones a la nueva versión de pilas:

1 Like