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
-
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)
-
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 <=.
-
@JonB thanks I did not think of that, will try to fix it Thank you
-
Thousands of bosses... Nightmare!!
-
-
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 fromupdate()
since the boss is a class and not in the gamefield,
My question: Is there a way inupdate()
to point tospawn: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? -
@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 alast_shot_time
property, you check that inupdate
, and if it's bigger than, say, 1 second, you setlast_shot_time
to the current time, and fire a shot. -
@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? -
def spawn_boss(self): self.boss = Boss(parent=self, position = (100, 600))
-
Haven't been able to get it to work yet, but Im currently trying a different approach that could work.
-
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.
-
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.