Skip to content

Commit

Permalink
1) rewrite assets loader
Browse files Browse the repository at this point in the history
2) fix a bug: enemy plane won't be clear when it was in outside of screen.
3) player auto fire
  • Loading branch information
cupen committed Jun 7, 2015
1 parent 2898116 commit 4081db5
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 106 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ double click the `lancher.exe` file on Windows.
```
Type w/s/a/d on the keyboard to move plane.

Type j on the keyboard to fire.

# Build a executable file
[cx-Freeze document](http://cx-freeze.readthedocs.org/en/latest/distutils.html#distutils)
```bash
Expand Down
83 changes: 55 additions & 28 deletions engine.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# coding:utf-8
__author__ = 'cupen'
import event
import random
from pygame.constants import USEREVENT
import pygame
import resource
from resource import Assets
from sprites import Background, Bullet, Enemy

ENEMY_REFRESH = USEREVENT + 1

__author__ = 'cupen'

class GameEngine:
STATUS_RUNNING = 0
Expand All @@ -16,18 +16,47 @@ class GameEngine:
def __init__(self):
pygame.init()
self.__listener = {}
self.__userEventDict = {}
self.__userEventCode = 0
self.__status = GameEngine.STATUS_RUNNING
self.planeGroup = pygame.sprite.Group()
self.bulletGroup = pygame.sprite.Group()
self.background = None
self.screen = None
self.srcLoader = resource
self.__spriteGroups = (self.planeGroup, self.bulletGroup)
self.player = None
self.__spriteGroups = (self.planeGroup, self.bulletGroup)
pass

def set_enemy_count_per_seconds(self, count):
pygame.time.set_timer(ENEMY_REFRESH, int(1000 / count))
def addTimer(self, delay, callback):
if self.__userEventCode == 0:
self.__userEventCode = event.TIMER[0]
else:
self.__userEventCode += 1

if self.__userEventCode > event.TIMER[1]:
raise Exception("Invalide anonymity userevent:%s"%self.__userEventCode)

self.__userEventDict[self.__userEventCode] = callback
pygame.time.set_timer(self.__userEventCode, delay)
pass

def setEnemyCountPerSeconds(self, count):
self.addTimer(
int(1000 / count),
lambda :self.refresh_enemy()
)
pass

def setPlayerBulletCountPerSeconds(self, count = 1):
self.addTimer(
int(1000 / count),
lambda :self.bulletGroup.add(
self.player.create_bullet(
Assets.loadImage("plane.png#bullet_0"),
self.screen.get_rect()
)
)
)
pass

def add_player(self, plane):
Expand All @@ -43,33 +72,30 @@ def add_enemy(self, plane):

def handle_event(self, e):
if e.key == pygame.K_j:
bullet = self.player.create_bullet(self.srcLoader.getSurface("bullet_0"), self.screen.get_rect())
image = Assets.loadImage("plane.png#bullet_0")
bullet = self.player.create_bullet(image, self.screen.get_rect())
self.bulletGroup.add(bullet)
pass

def set_background(self, imageNameList, width, height):
self.screen = pygame.display.set_mode((width, height))
resource.load()
pygame.display.set_icon(resource.getSurface("icon48x48.png"))
pygame.display.set_icon(Assets.loadImage("icon48x48.png"))
_list = []
for tmp in imageNameList:
image = resource.getSurface(tmp)
image = Assets.loadImage(tmp)
_list.append(image)
self.background = Background(_list, width=width, height=height)
self.screen.blit(self.background.image, (self.background.rect.x, self.background.rect.y) )
pass

def create_sprite(self, imageName, spriteClass = pygame.sprite.Sprite):
surface = self.srcLoader.getSurface(imageName)
surface = Assets.loadImage(imageName)
return spriteClass(surface)

def add_plane(self, sprite):
self.planeGroup.add(sprite)
pass

def add_bullet(self, bullet):
pass

def play_music(self, musicFile):
pygame.mixer.music.stop()
pygame.mixer.music.load(musicFile)
Expand All @@ -79,7 +105,7 @@ def play_music(self, musicFile):
for i in range(30):
pygame.mixer.music.queue(musicFile)

pygame.mixer.music.set_endevent(pygame.USEREVENT + 2)
pygame.mixer.music.set_endevent(event.MUSIC_IS_STOP)
pass

def is_stop(self):
Expand All @@ -90,9 +116,9 @@ def is_pause(self):

def refresh_enemy(self):
enemyList = (
self.srcLoader.getSurface("enemy_b"),
self.srcLoader.getSurface("enemy_m"),
self.srcLoader.getSurface("enemy_s"),
Assets.loadImage("plane.png#enemy_b"),
Assets.loadImage("plane.png#enemy_m"),
Assets.loadImage("plane.png#enemy_s"),
)
enemyImage = enemyList[ random.randint(0, len(enemyList) -1) ]
x = random.randint(0, self.screen.get_width() + enemyImage.get_width() - 1)
Expand All @@ -103,7 +129,7 @@ def refresh_enemy(self):

def listen_keyboard(self, keyCode, callback):
if keyCode in self.__listener:
print("Dumplicate key:", keyCode)
print("Duplicate key:", keyCode)
return
self.__listener[keyCode] = callback
pass
Expand All @@ -113,9 +139,9 @@ def update(self):
# print(e)
if e.type == pygame.QUIT:
self.__status = GameEngine.STATUS_STOP
if e.type == ENEMY_REFRESH:
self.refresh_enemy()
if e.type == pygame.USEREVENT + 2:
elif event.isTimer(e.type):
self.__userEventDict[e.type]()
elif e.type == event.MUSIC_IS_STOP:
pygame.mixer.music.rewind()
elif e.type == pygame.KEYDOWN or e.type == pygame.KEYUP:
self.call_listener(e)
Expand All @@ -133,11 +159,13 @@ def update(self):
if enemy == self.player:
continue

if not bullet.rect.colliderect(enemy.rect):
if not self.screen.get_rect().colliderect(enemy.rect):
enemy.kill()
continue

bullet.kill()
enemy.kill()
if bullet.rect.colliderect(enemy.rect):
enemy.kill()
bullet.kill()
pass

def call_listener(self, event):
Expand All @@ -150,7 +178,6 @@ def call_listener(self, event):
return

def run(self, fps = 70):
fps = 70
delayMiliSeconds = int(1000 / fps)

while not self.is_stop():
Expand Down
12 changes: 12 additions & 0 deletions event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# coding:utf-8
__author__ = 'cupen'
from pygame.constants import USEREVENT


ENEMY_REFRESH = USEREVENT + 1
MUSIC_IS_STOP = USEREVENT + 2
PLAYER_FIRE = USEREVENT + 3
TIMER = (USEREVENT + 4, USEREVENT + 100)

def isTimer(eventType):
return TIMER[0] <= eventType <= TIMER[1]
17 changes: 8 additions & 9 deletions lancher.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pygame.constants import USEREVENT
# coding:utf-8

__author__ = 'cupen'
from resource import Assets
import pygame
from sprites import Plane
from engine import GameEngine
Expand All @@ -9,19 +10,17 @@
game.set_background(['bg_01.jpg', 'bg_02.jpg'], width=640, height=480)
game.play_music('assets/Devil May Cry - Vergil Battle 2.mp3')

playerImage = game.srcLoader.getSurface("player.png")
playerImage = Assets.loadImage("player.png")

player = Plane(playerImage, animConfig=((4,4), (12,13,14,15)))
game.add_player(player)
game.set_enemy_count_per_seconds(3)
game.setEnemyCountPerSeconds(3)
game.setPlayerBulletCountPerSeconds(10)
game.listen_keyboard( pygame.K_w, lambda e:player.handleEvent(e) )
game.listen_keyboard( pygame.K_s, lambda e:player.handleEvent(e) )
game.listen_keyboard( pygame.K_a, lambda e:player.handleEvent(e) )
game.listen_keyboard( pygame.K_d, lambda e:player.handleEvent(e) )
game.listen_keyboard( pygame.K_j, lambda e:game.handle_event(e) )
game.listen_keyboard( pygame.K_j, lambda e:game.handle_event(e) )
game.listen_keyboard( pygame.K_j, lambda e:game.handle_event(e) )


# game.listen_keyboard( pygame.K_j, lambda e:game.handle_event(e) )

game.run(fps = 70)
game.run(fps = 100)
game.close()
90 changes: 47 additions & 43 deletions resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,30 @@
import pygame
import sys
from pygame.rect import Rect
from xml.dom import minidom

__author__ = 'cupen'
from xml.dom import minidom

ROOT_PATH = None
if getattr(sys, 'frozen', False):
ROOT_PATH = os.path.dirname(sys.executable)
else:
ROOT_PATH = os.path.dirname(__file__)

ASSETS_DIR = os.path.join(ROOT_PATH, 'assets')

class TextureConfig:
def __init__(self, configFile):
self.xmldoc = minidom.parse(configFile)

def loadConfig(self, configFile):
self.xmldoc = minidom.parse(os.path.join(ASSETS_DIR, configFile))
self.imageDict = {}
for i in self.xmldoc.getElementsByTagName("TextureAtlas"):
imageName = i.getAttribute('imagePath')
if imageName not in self.imageDict:
self.imageDict[imageName] = {}
for ttAtlas in self.xmldoc.getElementsByTagName("TextureAtlas"):
imageName = ttAtlas.getAttribute('imagePath')
if imageName in self.imageDict:
raise ValueError("Duplicate image name:%s"%imageName)

for subtt in i.getElementsByTagName("SubTexture"):
self.imageDict[imageName] = {}
for subtt in ttAtlas.getElementsByTagName("SubTexture"):
_subttData = {}
for _tmp in ('name','x','y','width','height'):
_subttData[_tmp] = subtt.getAttribute(_tmp)
Expand All @@ -33,41 +43,35 @@ def getSubTexture(self, imageName, subImageName):

return self.imageDict[imageName].get(subImageName, None)

imageDict = {}
tConfig = None

def find_data_file(filename):
if getattr(sys, 'frozen', False):
datadir = os.path.dirname(sys.executable)
else:
datadir = os.path.dirname(__file__)

return os.path.join(datadir, filename)

def load():
global imageDict, tConfig
tConfig = TextureConfig(find_data_file("assets/plane.xml"))
planeImage = pygame.image.load(find_data_file("assets/plane.png")).convert_alpha()
# TODO:待重构,改为懒加载(change to lazy load)
for i in ('hero_1','hero_2', 'bullet_0', 'bullet_0', 'enemy_b', 'enemy_m', 'enemy_s', 'explosion_01', 'explosion_02', 'explosion_03'):
subimageData = tConfig.getSubTexture('plane.png', i)
if not subimageData:
print("Unexist sub-image:plane.png,",i)
sys.exit()

tmpRect = Rect(subimageData['x'], subimageData['y'], subimageData['width'], subimageData['height'])
imageDict[i] = planeImage.subsurface(tmpRect).convert_alpha()
pass

def getSurface(imageName):
global imageDict
if imageName not in imageDict:
imageDict[imageName] = pygame.image.load(find_data_file("assets/"+ imageName)).convert_alpha()
return imageDict[imageName]

def getSound():
pass

class Assets:
__tconfig = TextureConfig()
__imageDict = {}

@classmethod
def init(cls):
cls.__tconfig.loadConfig("plane.xml")
pass

@classmethod
def loadImage(cls, name):
if name in cls.__imageDict:
return cls.__imageDict[name]

pathList = name.split("#")
if len(pathList) == 1:
cls.__imageDict[name] = pygame.image.load(os.path.join(ASSETS_DIR,name)).convert_alpha()
elif len(pathList) == 2:
parrentImage = cls.loadImage(pathList[0])
subttData = cls.__tconfig.getSubTexture(pathList[0], pathList[1])
tmpRect = Rect(subttData['x'], subttData['y'], subttData['width'], subttData['height'])
cls.__imageDict[name] = parrentImage.subsurface(tmpRect).convert_alpha()
else:
raise ValueError("Invalid image name:%s"%name)

return cls.__imageDict[name]

@classmethod
def loadMP3(cls, name):
pass

Assets.init()
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
base = "Win32GUI"

project = "pygame-plane"
version = "0.0.1"
version = "0.0.2"
build_exe_options = {}
build_exe_options["packages"] = ["pygame"]
build_exe_options["include_files"] = ["assets/"]
build_exe_options["excludes"] = ["tkinter", "socket"]
build_exe_options["excludes"] = ["tkinter", "socket", "multiprocessing", "ssl"]

setup(
name=project,
Expand Down
Loading

0 comments on commit 4081db5

Please sign in to comment.