Forum Archive

Removing missile, when goes off screen

mrcoxall

I am using the scene module to make a game. When I hit a button, I have a missile moving up the screen. When it goes off the screen, I would like to remove it from my array and memory, to clear up memory and since in the game the missile is gone.

I have tried many things and it does not seem to remove it right away, and then tries to remove more than one. Not sure what I am doing wrong. At line 80.

Here is the Gist: https://gist.github.com/cb0ac079b7351e2b59e980237a546152

```

Created by: Mr. Coxall

Created on: Sep 2016

Created for: ICS3U

This program is the first file in a multi-scene game template

This template is meant to be used with the Xcode

from scene import *
import ui
from numpy import random
from copy import deepcopy

class FirstScene(Scene):
def setup(self):
# this method is called, when user moves to this scene

    self.size_of_screen = deepcopy(self.size)
    self.center_of_screen = deepcopy(self.size/2)
    self.left_button_down = False
    self.right_button_down = False
    self.ship_move_speed = 40.0
    self.missiles = []
    self.aliens = []
    self.alien_attack_rate = 1
    self.alien_attack_speed = 20.0

    # add blue background color
    self.background = SpriteNode(position = self.size / 2, 
                                 color = (0.61, 0.78, 0.87), 
                                 parent = self, 
                                 size = self.size)

    spaceship_position = deepcopy(self.center_of_screen)
    spaceship_position.y = 100
    self.spaceship = SpriteNode('spc:PlayerShip1Orange',
                                parent = self,
                                position = spaceship_position)

    left_button_position = deepcopy(self.center_of_screen)
    left_button_position.x = 75
    left_button_position.y = 75
    self.left_button = SpriteNode('iob:arrow_left_a_256',
                                  parent = self,
                                  scale = 0.5,
                                  position = left_button_position,
                                  alpha = 0.5)

    right_button_position = deepcopy(self.center_of_screen)
    right_button_position.x = 200
    right_button_position.y = 75
    self.right_button = SpriteNode('iob:arrow_right_a_256',
                                   parent = self,
                                   scale = 0.5,
                                   position = right_button_position,
                                   alpha = 0.5)

    fire_button_position = deepcopy(self.size)
    fire_button_position.x = fire_button_position.x - 75
    fire_button_position.y = 75
    self.fire_button = SpriteNode('iob:disc_256',
                                  parent = self,
                                  scale = 0.5,
                                  position = fire_button_position,
                                  alpha = 0.5)

def update(self):
    # this method is called, hopefully, 60 times a second

    # move spaceship if button down
    if self.left_button_down == True:
        spaceshipMove = Action.move_by(-1*self.ship_move_speed, 
                                       0.0, 
                                       0.1)
        self.spaceship.run_action(spaceshipMove)
    if self.right_button_down == True:
        spaceshipMove = Action.move_by(self.ship_move_speed, 
                                       0.0, 
                                       0.1)
        self.spaceship.run_action(spaceshipMove)

    # check every update if a missile is off screen
    print('A: ' + str(range(len(self.missiles))))
    for missile_index in range(len(self.missiles)):

       if self.missiles[missile_index].position.y > self.size_of_screen.y - 100:
           #self.missiles[missile_index].remove_all_actions()
           #self.missiles[missile_index].remove_from_parent()
           print('B: ' + str(missile_index) + ' ' + str(len(self.missiles)))
           #print(missile_index)
           self.missiles.remove(missile_index)
           #print('one success')
           break
           #print(len(self.missiles))

def touch_began(self, touch):
    # this method is called, when user touches the screen

    # check if left or right button is down
    if self.left_button.frame.contains_point(touch.location):
        self.left_button_down = True

    if self.right_button.frame.contains_point(touch.location):
        self.right_button_down = True

def touch_moved(self, touch):
    # this method is called, when user moves a finger around on the screen
    pass

def touch_ended(self, touch):
    # this method is called, when user releases a finger from the screen

    # if I removed my finger, then no matter what spaceship
    #    should not be moving any more
    self.left_button_down = False
    self.right_button_down = False

    # if fire button pressed, create a new missile
    if self.fire_button.frame.contains_point(touch.location):
        self.create_new_missile()

def create_new_missile(self):
    # when the user hits the fire button

    missile_start_position = deepcopy(self.spaceship.position)
    missile_start_position.y = 100

    missile_end_position = deepcopy(self.size)
    missile_end_position.x = missile_start_position.x

    self.missiles.append(SpriteNode('spc:Fire1',
                         position = missile_start_position,
                         parent = self))

    # make missile move forward
    missileMoveAction = Action.move_to(missile_end_position.x, 
                                       missile_end_position.y + 100, 
                                       1.0)
    self.missiles[len(self.missiles)-1].run_action(missileMoveAction)

..use when deploying app for Xcode and the App Store

main_view = ui.View()
scene_view = SceneView(frame = main_view.bounds, flex = 'WH')
main_view.add_subview(scene_view)
scene_view.scene = FirstScene()
main_view.present(hide_title_bar = True, animated = False)

~~~

Thanks

Cethric

If you are really concerned about memory there is a lot more in your code that can be cleaned up, mainly unnecessary variables, etc. But if you need help with that then we can go over it after.
As to the rockets not deleting correctly, I get an error before it can even delete due to non-existent indecies in the list (due to the list being modified from in the loop that is not really friendly with your code). To resolve that I completely changed your for-loop to the following:

for i, missile in enumerate(self.missiles):
            print(i, missile.position)
            if missile.position.y > self.size_of_screen.y - 100:
                missile.remove_from_parent()
                self.missiles.remove(missile)

Also Node.remove_from_parent() needs to be called for the object to be removed from the render list.

mrcoxall

@Cethric
Works great.
Thanks

ccc

You might also run "Check Style" and "Analyze (PyFlakes)" from the run menu. Those two tools mention a few items that would be worth fixing.

ccc

Another take...

# Created by: Mr. Coxall
# Created on: Sep 2016
# Created for: ICS3U
# This program is the first file in a multi-scene game template
#    This template is meant to be used with the Xcode

import scene
import ui
Action = scene.Action


class FirstScene(scene.Scene):
    def setup(self):
        # this method is called, when user moves to this scene
        self.left_button_down = False
        self.right_button_down = False
        self.ship_move_speed = 40.0
        self.missiles = []
        # self.aliens = []
        # self.alien_attack_rate = 1
        # self.alien_attack_speed = 20.0

        # add blue background color
        scene.SpriteNode(position=self.size / 2,
                         color=(0.61, 0.78, 0.87),
                         parent=self,
                         size=self.size)

        position = scene.Point(self.size.x / 2, 100)
        self.spaceship = scene.SpriteNode('spc:PlayerShip1Orange',
                                          parent=self,
                                          position=position)

        self.left_button = scene.SpriteNode('iob:arrow_left_a_256',
                                            parent=self,
                                            scale=0.5,
                                            position=scene.Point(75, 75),
                                            alpha=0.5)

        self.right_button = scene.SpriteNode('iob:arrow_right_a_256',
                                             parent=self,
                                             scale=0.5,
                                             position=scene.Point(200, 75),
                                             alpha=0.5)

        position = scene.Point(self.size.x - 75, 75)
        self.fire_button = scene.SpriteNode('iob:disc_256',
                                            parent=self,
                                            scale=0.5,
                                            position=position,
                                            alpha=0.5)

    def update(self):
        # this method is called, hopefully, 60 times a second
        # move spaceship if button down
        if self.left_button_down:
            self.spaceship.run_action(Action.move_by(-self.ship_move_speed,
                                                     0.0,
                                                     0.1))
        if self.right_button_down:
            self.spaceship.run_action(Action.move_by(self.ship_move_speed,
                                                     0.0,
                                                     0.1))

        # check every update if a missile is off screen
        print('A: {}'.format(len(self.missiles)))
        for i, missile in enumerate(self.missiles):
            print(i, missile.position)
            if missile.position.y > self.size.y - 100:
                missile.remove_from_parent()
                self.missiles.remove(missile)
                break

    def touch_began(self, touch):
        # this method is called, when user touches the screen

        # check if left or right button is down
        self.left_button_down = touch.location in self.left_button.frame
        self.right_button_down = touch.location in self.right_button.frame

    def touch_moved(self, touch):
        # this method is called, when user moves a finger around on the screen
        pass

    def touch_ended(self, touch):
        # this method is called, when user releases a finger from the screen

        # if I removed my finger,
        # then no matter what spaceship should not be moving any more
        self.left_button_down = False
        self.right_button_down = False

        # if fire button pressed, create a new missile
        if touch.location in self.fire_button.frame:
            self.create_new_missile()

    def create_new_missile(self):
        # when the user hits the fire button
        missle = scene.SpriteNode('spc:Fire1',
                                  position=self.spaceship.position,
                                  parent=self)
        missle.run_action(Action.move_to(self.spaceship.position.x,
                                         self.size.y + 100,
                                         1.0))
        self.missiles.append(missle)


#  ..use when deploying app for Xcode and the App Store
if __name__ == '__main__':
    main_view = ui.View()
    scene_view = scene.SceneView(frame=main_view.bounds, flex='WH')
    scene_view.scene = FirstScene()
    main_view.add_subview(scene_view)
    main_view.present(hide_title_bar=True, animated=False)

    # scene_view = scene.SceneView()
    # scene_view.scene = FirstScene()
    # scene_view.present(hide_title_bar = True, animated = False)

    # scene.run(FirstScene())