Forum Archive

Help with actions for SpriteNodes

jpotrebic

I'm working on a space shooter game and I can't figure out how to get the 'enemy' spaceship to wrap around to the other side of the screen. Here's my code so far. Hope someone can give some suggestions.

from scene import *

class MyScene (Scene):
    def setup(self):
        self.background_color = 'midnightblue'
        self.ship = SpriteNode('spc:PlayerShip1Orange')
        self.ship.position = self.size/2
        self.add_child(self.ship)
        self.badGuy = SpriteNode('spc:EnemyBlack4')
        self.bx,self. by = self.size
        self.by -= 50
        self.bx += 50
        self.badGuy.position = (self.bx, self.by)
        self.add_child(self.badGuy)

    def update(self):
        x,y,z = gravity()
        pos = self.ship.position
        pos += (x * 15, y * 15)
        pos.x = max(0, min(self.size.w, pos.x))
        pos.y = max(0, min(self.size.h, pos.y))
        self.ship.position = pos

    def resetBad(self):
            self.badGuy.position = (self.bx, self.by)

    def touch_began(self, touch):
        resetBadGuy = Action.call(self.resetBad())
        laser = SpriteNode('spc:LaserBlue9', position=self.ship.position, z_position=-1, parent=self)
        laser.run_action(Action.sequence(Action.move_by(0,1000), Action.remove()))
        self.badGuy.run_action(Action.repeat(Action.sequence(Action.move_by(-818, 0, 5), resetBad), -1))
        print self.badGuy.position.x
        #self.badGuy.position = (self.bx, self.by)



run(MyScene(), PORTRAIT)
ccc

I am not sure if this is what you wanted but in update(self), comment out two lines and two new ones:

        #pos.x = max(0, min(self.size.w, pos.x))
        #pos.y = max(0, min(self.size.h, pos.y))
        pos.x %= self.size.w
        pos.y %= self.size.h

EDIT: Oops.. That changes the good guy. Still interesting to see how to wrap around.

The first line of touch_begin() is throwing an exception so change that line to remove ().

Then a few lines further down, change resetBad to self.resetBad. That helps a little bit.

jpotrebic

I made your changes, you're right, I'm not getting anymore errors but still am not able to get it to wrap around. I think maybe I could use another action.move_to() with a timing mode that will get it there instantly, so no one could see it but I'm not sure where to find documentation on the different timing modes. Any help?

from scene import *

class MyScene (Scene):
def setup(self):
self.background_color = 'midnightblue'
self.ship = SpriteNode('spc:PlayerShip1Orange')
self.ship.position = self.size/2
self.add_child(self.ship)
self.badGuy = SpriteNode('spc:EnemyBlack4')
self.bx,self. by = self.size
self.by -= 50
self.bx += 50
self.badGuy.position = (self.bx, self.by)
self.add_child(self.badGuy)

def update(self):
    x,y,z = gravity()
    pos = self.ship.position
    pos += (x * 15, y * 15)
    pos.x = max(0, min(self.size.w, pos.x))
    pos.y = max(0, min(self.size.h, pos.y))
    self.ship.position = pos

def resetBad(self):
        self.badGuy.position = (self.bx, self.by)

def touch_began(self, touch):
    resetBadGuy = Action.call(self.resetBad)
    laser = SpriteNode('spc:LaserBlue9', position=self.ship.position, z_position=-1, parent=self)
    laser.run_action(Action.sequence(Action.move_by(0,1000), Action.remove()))
    self.badGuy.run_action(Action.repeat(Action.sequence(Action.move_by(-818, 0, 5), self.resetBad), -1))
    print self.badGuy.position.x
    #self.badGuy.position = (self.bx, self.by)

run(MyScene(), PORTRAIT)

jpotrebic

Yay! I finally figured out how to get the ship to wrap around. Now I need to figure out how to detect collisions...

from scene import *

class MyScene (Scene):
def bad_guy(self):
self.badGuy.run_action(Action.repeat(Action.sequence(Action.move_by(-818, 0, 5), Action.move_by(818, 0, 0.001)), -1))

def setup(self):
    self.background_color = 'midnightblue'
    self.ship = SpriteNode('spc:PlayerShip1Orange')
    self.ship.position = self.size/2
    self.add_child(self.ship)
    self.badGuy = SpriteNode('spc:EnemyBlack4')
    self.bx,self. by = self.size
    self.by -= 50
    self.bx += 50
    self.badGuy.position = (self.bx, self.by)
    self.add_child(self.badGuy)
    self.bad_guy()

def update(self):
    x,y,z = gravity()
    pos = self.ship.position
    pos += (x * 15, y * 15)
    pos.x = max(0, min(self.size.w, pos.x))
    pos.y = max(0, min(self.size.h, pos.y))
    self.ship.position = pos

def touch_began(self, touch):
    laser = SpriteNode('spc:LaserBlue9', position=self.ship.position, z_position=-1, parent=self)
    laser.run_action(Action.sequence(Action.move_by(0,1000), Action.remove()))

run(MyScene(), PORTRAIT)

ccc

Add this code to the bottom of update():

    for child in self.children:
        if child not in (self.ship, self.badGuy) and child.frame in self.badGuy.frame:
            exit("It's a hit!")

The last paragraph of http://omz-software.com/pythonista/docs/ios/scene.html#geometry talks about a better approach to hit detection. My code above requires that the bullet is completely inside the bad guy's frame. It is the difference between Rect.contains_rect() and Rect.intersects().

jpotrebic

Thanks so much. It works perfectly.