changeset 172:ea2ad94c33a0

Implement player death.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 21 Oct 2011 09:29:16 -0700
parents 2f3665a77f11
children 35d850502d1f
files pytouhou/game/game.py pytouhou/game/player.py
diffstat 2 files changed, 98 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/game/game.py
+++ b/pytouhou/game/game.py
@@ -33,7 +33,7 @@ class Game(object):
         self.item_types = item_types
         self.characters = characters
 
-        self.players = [Player(player_state, characters[player_state.character]) for player_state in player_states]
+        self.players = [Player(player_state, characters[player_state.character], self) for player_state in player_states]
         self.enemies = []
         self.effects = []
         self.bullets = []
@@ -54,12 +54,12 @@ class Game(object):
         self.ecl_runner = ECLMainRunner(ecl, self)
 
 
-    def drop_bonus(self, x, y, _type):
+    def drop_bonus(self, x, y, _type, end_pos=None):
         player = self.players[0] #TODO
         if _type > 6:
             return
         item_type = self.item_types[_type]
-        item = Item((x, y), item_type, self)
+        item = Item((x, y), item_type, self, end_pos=end_pos)
         self.items.append(item)
 
 
@@ -121,6 +121,9 @@ class Game(object):
         # 4. Check for collisions!
         #TODO
         for player in self.players:
+            if not player.state.touchable:
+                continue
+
             px, py = player.x, player.y
             phalf_size = player.hitbox_half_size
             px1, px2 = px - phalf_size, px + phalf_size
@@ -135,7 +138,8 @@ class Game(object):
                 if not (bx2 < px1 or bx1 > px2
                         or by2 < py1 or by1 > py2):
                     bullet.collide()
-                    player.collide()
+                    if player.state.invulnerable_time == 0:
+                        player.collide()
 
             for enemy in self.enemies:
                 half_size_x, half_size_y = enemy.hitbox_half_size
@@ -146,7 +150,8 @@ class Game(object):
                 if enemy.touchable and not (bx2 < px1 or bx1 > px2
                                             or by2 < py1 or by1 > py2):
                     enemy.on_collide()
-                    player.collide()
+                    if player.state.invulnerable_time == 0:
+                        player.collide()
 
             for item in self.items:
                 half_size = item.hitbox_half_size
@@ -174,6 +179,7 @@ class Game(object):
                         or by2 < ey1 or by1 > ey2):
                     bullet.collide()
                     enemy.on_attack(bullet)
+                    player.state.score += 90 # found experimentally
 
         # 5. Cleaning
         self.cleanup()
--- a/pytouhou/game/player.py
+++ b/pytouhou/game/player.py
@@ -14,6 +14,7 @@
 
 
 from pytouhou.game.sprite import Sprite
+from pytouhou.game.enemy import Effect
 from pytouhou.vm.anmrunner import ANMRunner
 
 
@@ -35,11 +36,15 @@ class PlayerState(object):
         self.x = 192.0
         self.y = 384.0
 
+        self.invulnerable_time = 60
+        self.touchable = True
+
 
 class Player(object):
-    def __init__(self, state, character):
+    def __init__(self, state, character, game):
         self._sprite = None
         self._anmrunner = None
+        self._game = game
 
         self.hitbox_half_size = character.hitbox_size / 2.
 
@@ -50,6 +55,8 @@ class Player(object):
 
         self.set_anim(0)
 
+        self.death_time = 0
+
 
     @property
     def x(self):
@@ -68,11 +75,10 @@ class Player(object):
 
 
     def collide(self):
-        self.state.lives -= 1
-        self.state.x = 192.0
-        self.state.y = 384.0
-        #TODO: animation
-        #TODO: set invulnerability.
+        if not self.state.invulnerable_time and not self.death_time and self.state.touchable: # Border Between Life and Death
+            self.death_time = self._game.frame
+            eff00 = self._game.resource_loader.get_anm_wrapper(('eff00.anm',))
+            self._game.effects.append(Effect((self.state.x, self.state.y), 2, eff00))
 
 
     def collect(self, item):
@@ -82,29 +88,83 @@ class Player(object):
 
 
     def update(self, keystate):
-        try:
-            dx, dy = {16: (0.0, -1.0), 32: (0.0, 1.0), 64: (-1.0, 0.0), 128: (1.0, 0.0),
-                      16|64: (-SQ2, -SQ2), 16|128: (SQ2, -SQ2),
-                      32|64: (-SQ2, SQ2), 32|128:  (SQ2, SQ2)}[keystate & (16|32|64|128)]
-        except KeyError:
-            speed = 0.0
-            dx, dy = 0.0, 0.0
-        else:
-            speed = self.character.focused_speed if keystate & 4 else self.character.speed
-            dx, dy = dx * speed, dy * speed
+        if self.death_time == 0 or self._game.frame - self.death_time > 60:
+            try:
+                dx, dy = {16: (0.0, -1.0), 32: (0.0, 1.0), 64: (-1.0, 0.0), 128: (1.0, 0.0),
+                          16|64: (-SQ2, -SQ2), 16|128: (SQ2, -SQ2),
+                          32|64: (-SQ2, SQ2), 32|128:  (SQ2, SQ2)}[keystate & (16|32|64|128)]
+            except KeyError:
+                speed = 0.0
+                dx, dy = 0.0, 0.0
+            else:
+                speed = self.character.focused_speed if keystate & 4 else self.character.speed
+                dx, dy = dx * speed, dy * speed
+
+            if dx < 0 and self.direction != -1:
+                self.set_anim(1)
+                self.direction = -1
+            elif dx > 0 and self.direction != +1:
+                self.set_anim(3)
+                self.direction = +1
+            elif dx == 0 and self.direction is not None:
+                self.set_anim({-1: 2, +1: 4}[self.direction])
+                self.direction = None
+
+            self.state.x += dx
+            self.state.y += dy
+
+            if self.state.invulnerable_time > 0:
+                self.state.invulnerable_time -= 1
+
+                m = self.state.invulnerable_time % 8
+                if m == 0:
+                    self._sprite.color = (255, 255, 255)
+                    self._sprite._changed = True
+                elif m == 2:
+                    self._sprite.color = (64, 64, 64)
+                    self._sprite._changed = True
 
-        if dx < 0 and self.direction != -1:
-            self.set_anim(1)
-            self.direction = -1
-        elif dx > 0 and self.direction != +1:
-            self.set_anim(3)
-            self.direction = +1
-        elif dx == 0 and self.direction is not None:
-            self.set_anim({-1: 2, +1: 4}[self.direction])
-            self.direction = None
+        if self.death_time:
+            time = self._game.frame - self.death_time
+            if time == 6: # too late, you are dead :(
+                self._game.drop_bonus(self.state.x, self.state.y, 2, end_pos=None) #TODO: find the formula
+                for i in range(5):
+                    self._game.drop_bonus(self.state.x, self.state.y, 0, end_pos=None) #TODO: find the formula
+                self.state.lives -= 1
+
+            elif time == 7:
+                self.state.touchable = False
+                self._sprite.mirrored = False
+                self._sprite.fade(24, 128, lambda x: x)
+                self._sprite.blendfunc = 1
+                self._sprite.scale_in(24, 0., 2., lambda x: x)
+
+            elif time == 31:
+                self.state.x = 192.0
+                self.state.y = 384.0
+                self.direction = None
 
-        self.state.x += dx
-        self.state.y += dy
+                self._sprite = Sprite()
+                self._anmrunner = ANMRunner(self.anm_wrapper, 0, self._sprite)
+                self._sprite.alpha = 128
+                self._sprite.rescale = 0., 2.
+                self._sprite.fade(30, 255, lambda x: x)
+                self._sprite.blendfunc = 1
+                self._sprite.scale_in(30, 1., 1., lambda x: x)
+                self._anmrunner.run_frame()
+
+            elif time == 60: # respawned
+                self.state.touchable = True
+                self.state.invulnerable_time = 240
+                self._sprite.blendfunc = 0
+
+            if time > 30:
+                for bullet in self._game.bullets:
+                    bullet.cancel()
+
+            if time > 90: # start the bullet hell again
+                self.death_time = 0
+
 
         self._anmrunner.run_frame()