omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    fps drops rapid when "boss" SpriteNode appears

    Pythonista
    spritenode scene
    5
    12
    6882
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Bjucha
      Bjucha last edited by

      Hello, so I gotten pretty far with my "game", And I thought that now would be the time to make it a bit more challenge by adding a boss. But for some reason when the boss arrives the fps in the game drops more and more, and I don't understand way since all that is happening is that when a timer enter 0 (The distance to the boss in the game) the boss appears.

      Here is the whole code:

      from scene import *
      from math import sin, cos, pi
      import random, ui, time
      
      A = Action
      
      #Timme = 100
      
      class Boss (SpriteNode):
      	def __init__(self, **kwargs):
      		SpriteNode.__init__(self, 'spc:UFOBlue', **kwargs)
      		self.scale = 2.5
      		self.destroyed = False
      
      
      class Enemy (SpriteNode):
      	def __init__(self, **kwargs):
      		img = random.choice(['spc:EnemyBlack1', 'spc:EnemyRed1', 'spc:EnemyBlue1' ])
      		SpriteNode.__init__(self, img, **kwargs)
      		self.destroyed = False
      	
      class SuperEnemy (SpriteNode):
      	def __init__(self, **kwargs):
      		SpriteNode.__init__(self, 'spc:EnemyBlack4', **kwargs)
      		self.scale = 1.5
      		self.destroyed = False
      
      class PowerUp (SpriteNode):
      	def __init__(self, **kwargs):
      		SpriteNode.__init__(self, 'spc:PowerupRedStar', **kwargs)
      
      class Gamefield (Scene):
      	def setup (self):
      		self.items = []
      		self.bossfire = []
      		self.background_color = '#0c1037'
      		score_font = ('Futura', 20)
      		self.distance_label = LabelNode('Distance to boss', score_font, parent=self)
      		self.lasers = []
      		#self.timme = LabelNode('1000', font=('Helvetica', 20),parent=self)
      		self.distance_label.position = (self.size.w/3.9, self.size.h - 20)
      		self.distance = 500
      		self.blasers = []
      		
      		self.ship = SpriteNode('spc:PlayerShip3Red')
      		self.ship.position = (100,40)
      		self.add_child(self.ship) 
      
      	def touch_began(self, touch):
      		x, y = touch.location
      		move_action = Action.move_to(x, y , 0.8, TIMING_SINODIAL)
      		self.ship.run_action(move_action)
      		self.shoot_laser()
      	
      	def check_laser_collisions(self):
      		for laser in list(self.lasers):
      			if not laser.parent:
      				self.lasers.remove(laser)
      				continue
      			for item in self.items:
      				if not isinstance(item, Enemy):
      					continue
      				if item.destroyed:
      					continue
      				if laser.position in item.frame:
      					self.enemy_smash(item)
      					self.lasers.remove(laser)
      					
      					laser.remove_from_parent()
      					break
      			
      			
      	
      	def enemy_smash(self, enemy):
      		
      		
      		enemy.destroyed = True				
      		
      		enemy.remove_from_parent()
      		#self.score += 1
      		debree = SpriteNode('spc:PlayerShip1Damage1', parent=self)
      		debree.position = enemy.position
      		debree.z_position = - 1
      		debree.run_action(A.move_by(10, 10, 1.6, TIMING_EASE_OUT))
      		debree.run_action(A.sequence(A.wait(1), A.remove()))
      
      	def enemy_hit(self, super_enemy):											
      		super_enemy.remove_from_parent()
      		super_enemy.destroyed = True				
      		debree = SpriteNode('spc:PlayerShip3Damage1', parent=self)
      		debree.position = super_enemy.position
      		debree.z_position = - 1
      		debree.run_action(A.move_by(10, 10, 1.6, TIMING_EASE_OUT))
      		debree.run_action(A.sequence(A.wait(1), A.remove()))	
      	#	self.score += 1
      
      
      	def update(self):
      		
      		self.evil_laser_hit()
      		self.check_item_collisions()
      	
      		if random.random() < 0.009:
      			self.spawn_item()
      		
      		self.check_laser_collisions()	
      		self.check_laser_hit()
      		if random.random() < 0.004:
      			self.spawn_enemy()
      		#	self.evil_laser()
      		
      		self.distance -= 1
      		self.distance_label.text = str(self.distance)
      		if self.distance <= 0:
      			
      			self.distance_label.text = 'Boss appears!'
      			self.spawn_boss()
      			
      	
      	def spawn_boss(self):
      		boss = Boss(parent=self)	
      		
      		boss.position = (100,600)
      		
      		
      			
      				
      
      	def spawn_enemy(self):
      		super_enemy = SuperEnemy(parent=self)
      		super_enemy.position = (random.uniform(10, self.size.w-10), self.size.h + 30) 
      		h = random.uniform(2.0, 19.0)
      		actions = [A.move_to(random.uniform(0, self.size.w), -100, h), A.remove()]
      		super_enemy.run_action(A.sequence(actions))
      	
      		self.items.append(super_enemy)
      		blasers = SpriteNode('spc:LaserBlue11', parent=self)
      		blasers.position = super_enemy.position + (0, 30)
      		blasers.z_position = -1
      		b = random.uniform(10.0, 250)
      		actions = [A.move_to(b, 100, 2 * 5), A.remove()]													
      		blasers.run_action(A.sequence(actions))
      		self.blasers.append(blasers)
      		
      	
      				
      	def check_laser_hit(self):
      		for laser in list(self.lasers):
      			if not laser.parent:
      				self.lasers.remove(laser)
      				continue
      			for item in self.items:
      				if not isinstance(item, SuperEnemy):
      					continue
      				if item.destroyed:
      					continue
      				if laser.position in item.frame:
      					self.enemy_hit(item)
      					self.lasers.remove(laser)
      					laser.remove_from_parent()
      					
      					break
      					
      						
      					
      	def spawn_item(self):
      	
      		enemy = Enemy(parent=self)
      		enemy.position = (random.uniform(10, self.size.w-10), self.size.h + 30) 
      		
      		d = random.uniform(2.0, 19.0) 
      		
      		actions = [A.move_by(0, -(self.size.h + 60), d), A.remove()]
      		enemy.run_action(A.sequence(actions))
      		
      		self.items.append(enemy)
      		if self.distance <= 0:
      			enemy.remove_from_parent() # Working?
      		
      		
      
      	def check_item_collisions(self):
      		
      		for item in list(self.items):
      			distance = abs(item.position - self.ship.frame.center())
      			if item.parent == None: # Working!!!
      				continue
      			
      			if distance < 60:
      				exit()
      				
      	def evil_laser_hit(self):
      		for blaser in list(self.blasers):
      			if not blaser.parent:
      				self.blasers.remove(blaser)
      				continue
      			
      			if blaser.position in self.ship.frame:
      				exit()
      				blaser.remove_from_parent()
      					
      					#break
      																																				
      	def shoot_laser(self):
      	
      		lasers = SpriteNode('spc:LaserRed10', parent=self)
      		lasers.position = self.ship.position + (0, 30)
      		lasers.z_position = -1
      		actions = [A.move_by(0, self.size.h, 1.3 * self.speed), A.remove()]
      		lasers.run_action(A.sequence(actions))
      		self.lasers.append(lasers)
      	
      
      run(Gamefield(), PORTRAIT, show_fps = True)
      
      1 Reply Last reply Reply Quote 0
      • JonB
        JonB last edited by JonB

        you are spawning the boss whenever distance <=0 . distance counts down every update(). but I don't see you resetting distance. Meaning when distance goes to 0, boss is spawned every update(), or 60 bosses per second. pretty soon you have thousands of Boss nodes attached to your scene!

        I think you either need to reset distance, or set a flag that the boss is already spawned, etc. or only spawn the boss when distance==0, not <=.

        Bjucha 1 Reply Last reply Reply Quote 3
        • Bjucha
          Bjucha @JonB last edited by

          @JonB thanks I did not think of that, will try to fix it Thank you

          1 Reply Last reply Reply Quote 0
          • ccc
            ccc last edited by

            Thousands of bosses... Nightmare!!

            1 Reply Last reply Reply Quote 0
            • Bjucha
              Bjucha last edited by

              @JonB Thanks the solution was simple, I just didn't see it, @ccc yeah one big bad boss is enough
              But now He needs some cool firepower. Will update you when he is ready for a fight

              1 Reply Last reply Reply Quote 0
              • Bjucha
                Bjucha last edited by

                Ok so now the fps is fixed and the boss is just one big UFO.
                But now I have a new problem(No suprise there) When the boss appears he fires one laser shot,
                but no more. What I'm trying to do is to make him fire lasers all the time (after all he is the boss) but I cant call such a function from update() since the boss is a class and not in the gamefield,
                My question: Is there a way in update() to point to spawn:boss() function (or is there a way inside the that function to create something that update all the time)
                Sorry for the long post, basically: how do my boss keep firing until he is removed from scene?

                1 Reply Last reply Reply Quote 0
                • omz
                  omz last edited by

                  @Bjucha You could make the boss a property of your scene (i.e. set self.boss = ... when you spawn it). That way, the boss could have a last_shot_time property, you check that in update, and if it's bigger than, say, 1 second, you set last_shot_time to the current time, and fire a shot.

                  Bjucha 1 Reply Last reply Reply Quote 0
                  • Bjucha
                    Bjucha @omz last edited by

                    @omz hmm I really sorry but I don't really understand. what do you mean with property of my scene? and shall that property be inside the spawn_boss()
                    function? or in the gamefield?

                    1 Reply Last reply Reply Quote 0
                    • ccc
                      ccc last edited by ccc

                      def spawn_boss(self):
                          self.boss = Boss(parent=self, position = (100, 600))
                      
                      1 Reply Last reply Reply Quote 0
                      • Bjucha
                        Bjucha last edited by

                        Haven't been able to get it to work yet, but Im currently trying a different approach that could work.

                        1 Reply Last reply Reply Quote 0
                        • flight_714
                          flight_714 last edited by

                          I realize this is a few weeks old, but had a few thoughts.

                          I typically add scene objects of a shared type to a list and then iterate over a method of their class in update.

                          So at the end up the enemy class init I would add 'enemies.append(self)' and then in the scene update method add 'for enemy in enemies': enemy.cooldown() or something to that to that effect.

                          Obviously, you'd have to write a bit more AI methods for the enemy ships, so you'd probably want to subclass them to save space.

                          Bjucha 1 Reply Last reply Reply Quote 0
                          • Bjucha
                            Bjucha @flight_714 last edited by

                            @flight_714

                            Thanks for the tip. I did get it to work by using

                            counter = 10 
                            		while counter != 0:
                            			Action.wait(2)
                            			self.items.append(boss)
                            			bossfires = SpriteNode('spc:BoltBronze', parent=self)
                            			bossfires.position = boss.position + (-50, 30)
                            			bossfires.z_position = -1
                            			b = random.uniform(10.0, 2500)
                            			actions = [A.move_to(b, 100, 2 * 2), A.remove()]
                            																
                            			bossfires.run_action(A.sequence(actions))
                            			self.bossfires.append(bossfires)
                            			Action.wait(2)
                            			counter = counter - 1```
                            
                            This works but is not really "perfect" for me. But will look at what you suggested and see if I can use it.
                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post
                            Powered by NodeBB Forums | Contributors