# HG changeset patch # User Thibaut Girka # Date 1315687736 -7200 # Node ID 11ab06f4c4c6fb216b670d5e1795d8219a9359f3 # Parent 284ac8f97a96b53d99b1254079528ed0b6542393 Introduce characters! diff --git a/eclviewer.py b/eclviewer.py --- a/eclviewer.py +++ b/eclviewer.py @@ -20,14 +20,14 @@ from pytouhou.resource.loader import Loa from pytouhou.game.background import Background from pytouhou.opengl.gamerenderer import GameRenderer from pytouhou.game.games import EoSDGame -from pytouhou.game.player import Player +from pytouhou.game.player import PlayerState def main(path, stage_num): resource_loader = Loader() resource_loader.scan_archives(os.path.join(path, name) for name in ('CM.DAT', 'ST.DAT')) - game = EoSDGame(resource_loader, [Player()], stage_num, 3, 16) + game = EoSDGame(resource_loader, [PlayerState()], stage_num, 3, 16) # Load stage data stage = resource_loader.get_stage('stage%d.std' % stage_num) diff --git a/pytouhou/game/character.py b/pytouhou/game/character.py new file mode 100644 --- /dev/null +++ b/pytouhou/game/character.py @@ -0,0 +1,6 @@ +class Character(object): + def __init__(self, anm_wrapper, speed, focused_speed, hitbox_size): + self.anm_wrapper = anm_wrapper + self.speed = speed + self.focused_speed = focused_speed + self.hitbox_size = hitbox_size diff --git a/pytouhou/game/enemy.py b/pytouhou/game/enemy.py --- a/pytouhou/game/enemy.py +++ b/pytouhou/game/enemy.py @@ -13,10 +13,6 @@ ## -from itertools import chain -from io import BytesIO -import os -from struct import unpack, pack from pytouhou.utils.interpolator import Interpolator from pytouhou.vm.eclrunner import ECLRunner from pytouhou.vm.anmrunner import ANMRunner diff --git a/pytouhou/game/game.py b/pytouhou/game/game.py --- a/pytouhou/game/game.py +++ b/pytouhou/game/game.py @@ -17,16 +17,19 @@ from pytouhou.utils.random import Random from pytouhou.vm.eclrunner import ECLMainRunner +from pytouhou.game.player import Player from pytouhou.game.enemy import Enemy class GameState(object): __slots__ = ('resource_loader', 'bullets', 'players', 'rank', 'difficulty', 'frame', - 'stage', 'boss', 'prng', 'bullet_types') - def __init__(self, resource_loader, players, stage, rank, difficulty, bullet_types): + 'stage', 'boss', 'prng', 'bullet_types', 'characters') + def __init__(self, resource_loader, players, stage, rank, difficulty, + bullet_types, characters): self.resource_loader = resource_loader self.bullet_types = bullet_types + self.characters = characters self.bullets = [] @@ -41,9 +44,13 @@ class GameState(object): class Game(object): - def __init__(self, resource_loader, players, stage, rank, difficulty, bullet_types): - self.game_state = GameState(resource_loader, players, stage, rank, difficulty, bullet_types) + def __init__(self, resource_loader, player_states, stage, rank, difficulty, + bullet_types, characters): + self.game_state = GameState(resource_loader, player_states, stage, + rank, difficulty, + bullet_types, characters) + self.players = [Player(player_state, characters[player_state.character]) for player_state in player_states] self.enemies = [] self.bonuses = [] @@ -68,6 +75,17 @@ class Game(object): self.enemies = [enemy for enemy in self.enemies if not enemy._removed] # 3. Let's play! + for player in self.players: + player.update(keystate) #TODO: differentiate keystates + if player.state.x < 8.: + player.state.x = 8. + if player.state.x > 384.-8: #TODO + player.state.x = 384.-8 + if player.state.y < 16.: + player.state.y = 16. + if player.state.y > 448.-16: #TODO + player.state.y = 448.-16 + for enemy in self.enemies: enemy.update() diff --git a/pytouhou/game/games.py b/pytouhou/game/games.py --- a/pytouhou/game/games.py +++ b/pytouhou/game/games.py @@ -13,6 +13,7 @@ ## from pytouhou.game.game import Game +from pytouhou.game.character import Character from pytouhou.game.bullettype import BulletType class EoSDGame(Game): @@ -30,4 +31,13 @@ class EoSDGame(Game): BulletType(etama3, 8, 13, 20, 20, 20), BulletType(etama4, 0, 1, 2, 2, 2)] - Game.__init__(self, resource_loader, players, stage, rank, difficulty, bullet_types) + player00 = resource_loader.get_anm_wrapper(('player00.anm',)) + player01 = resource_loader.get_anm_wrapper(('player01.anm',)) + characters = [Character(player00, 4., 2., 4.), + Character(player00, 4., 2., 4.), + Character(player01, 5., 2.5, 5.), + Character(player01, 5., 2.5, 5.)] + + Game.__init__(self, resource_loader, players, stage, rank, difficulty, + bullet_types, characters) + diff --git a/pytouhou/game/player.py b/pytouhou/game/player.py --- a/pytouhou/game/player.py +++ b/pytouhou/game/player.py @@ -13,13 +13,84 @@ ## -class Player(object): - def __init__(self): +from math import cos, sin, atan2, pi + +from pytouhou.game.sprite import Sprite +from pytouhou.vm.anmrunner import ANMRunner + + +SQ2 = 2. ** 0.5 / 2. + + +class PlayerState(object): + def __init__(self, character=0, score=0, power=0, lives=0, bombs=0): + self.character = character # ReimuA/ReimuB/MarisaA/MarisaB/... + + self.score = score + self.lives = lives + self.bombs = bombs + self.power = power + + self.graze = 0 + self.points = 0 + self.x = 192.0 self.y = 384.0 - self.score = 0 - self.graze = 0 - self.power = 0 - self.lives = 0 - self.bombs = 0 - self.character = 0 # ReimuA/ReimuB/MarisaA/MarisaB/... + + +class Player(object): + def __init__(self, state, character): + self._sprite = None + self._anmrunner = None + + self.state = state + self.character = character + self.anm_wrapper = character.anm_wrapper + self.direction = None + + self.set_anim(0) + + + @property + def x(self): + return self.state.x + + + @property + def y(self): + return self.state.y + + + def set_anim(self, index): + self._sprite = Sprite() + self._anmrunner = ANMRunner(self.anm_wrapper, index, self._sprite) + self._anmrunner.run_frame() + + + 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 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 + + self._anmrunner.run_frame() + diff --git a/pytouhou/opengl/gamerenderer.py b/pytouhou/opengl/gamerenderer.py --- a/pytouhou/opengl/gamerenderer.py +++ b/pytouhou/opengl/gamerenderer.py @@ -35,7 +35,7 @@ class GameRenderer(pyglet.window.Window) self.texture_manager = TextureManager(resource_loader) - self.fps_display = pyglet.clock.ClockDisplay() + self.fps_display = pyglet.clock.ClockDisplay() self.game = game self.background = background @@ -65,27 +65,54 @@ class GameRenderer(pyglet.window.Window) ctypes.byref(buff, 3 * 4), ctypes.byref(buff, 3 * 4 + 2 * 4)) - pyglet.clock.schedule_interval(self.update, 1./120.) - pyglet.app.run() + # Use our own loop to ensure 60 (for now, 120) fps + pyglet.clock.set_fps_limit(120) + while not self.has_exit: + pyglet.clock.tick() + self.dispatch_events() + self.update() + self.on_draw() + self.flip() def on_resize(self, width, height): glViewport(0, 0, width, height) - def update(self, dt): + def on_key_press(self, symbol, modifiers): + if symbol == pyglet.window.key.ESCAPE: + self.has_exit = True + # XXX: Fullscreen will be enabled the day pyglet stops sucking + elif symbol == pyglet.window.key.F11: + self.set_fullscreen(not self.fullscreen) + + + def update(self): if self.background: self.background.update(self.game.game_state.frame) if self.game: - self.game.run_iter(0) #TODO: self.keys... - - - def on_key_press(self, symbol, modifiers): - if symbol == pyglet.window.key.ESCAPE: - pyglet.app.exit() - # XXX: Fullscreen will be enabled the day pyglet stops sucking - elif symbol == pyglet.window.key.F11: - self.set_fullscreen(not self.fullscreen) + #TODO: allow user settings + keystate = 0 + if self.keys[pyglet.window.key.W]: + keystate |= 1 + if self.keys[pyglet.window.key.X]: + keystate |= 2 + #TODO: on some configurations, LSHIFT is Shift_L when pressed + # and ISO_Prev_Group when released, confusing the hell out of pyglet + # and leading to a always-on LSHIFT... + if self.keys[pyglet.window.key.LSHIFT]: + keystate |= 4 + if self.keys[pyglet.window.key.UP]: + keystate |= 16 + if self.keys[pyglet.window.key.DOWN]: + keystate |= 32 + if self.keys[pyglet.window.key.LEFT]: + keystate |= 64 + if self.keys[pyglet.window.key.RIGHT]: + keystate |= 128 + if self.keys[pyglet.window.key.LCTRL]: + keystate |= 256 + self.game.run_iter(keystate) #TODO: self.keys... def render_elements(self, elements): @@ -197,6 +224,7 @@ class GameRenderer(pyglet.window.Window) glDisable(GL_FOG) self.render_elements(game.enemies) self.render_elements(game.game_state.bullets) + self.render_elements(game.players) glEnable(GL_FOG) #TODO