def load(n): " Different levels, the initialization file is not the same, 'n' means the first few levels, 'openres' is to load the corresponding configuration file, and step as initialize" portals = openres(f'levels/{n}/portals.json') portals = [Portal(**p) for p in portals] bg = openres(f'levels/{n}/background.jpg') return Level(n, portals, bg.convert())
class DueEssay(Skill): name = 'Due Essay' image = pg.transform.scale(openres(f'imgs/items/due.jpg'), (200, 200)) def __call__(self, sponsor, target): target.health -= 40 return min(40, target.health)
class Enemy: " Enemy data" img = openres('images/enemy/goast.png').convert_alpha() exp = 10 attack = 10 health = 100 name = 'Ghost'
class Final(Skill): name = 'Final' image = pg.transform.scale(openres(f'imgs/items/final.jpg'), (200, 200)) def __call__(self, sponsor, target): harm = target.health - target.health * 0.1 target.health *= 0.1 return harm
class Npc: image = openres(f'imgs/npc.png').convert_alpha() def __init__(self, dialog): self.dialog = dialog def __call__(self, pos): from scene import SceneM, Dialog Game().map.triggers.pop(pos, None) SceneM().call(Dialog, self.dialog)
class RoleView(Scene): surf = openres('imgs/roleview.png').convert_alpha() @property def image(self): role = Game().role surf = self.surf.copy() title = pg.font.Font(None, 28) text = pg.font.Font(None, 24) color = 200, 200, 200 x, y = 32, 32 health = title.render(f'{role.health}/{role.health_full}', True, color) surf.blit(role.image, (x, y)) surf.blit(health, (x + 48, y + 12)) y += 48 for i, (cls, equip) in enumerate(role.equips.items()): surf.blit(equip.image, (x + i * 32, y)) y += 48 skill = title.render('Skills:', True, color) surf.blit(skill, (x, y)) y += 32 x += 16 for i, skill in enumerate(role.skills): if isinstance(skill, BasicSkill): continue s = text.render(str(skill), True, color) surf.blit(s, (x, y)) y += 32 x -= 32 return surf def handle_event(self, e): if e.type == pg.KEYDOWN: SceneM().back() def render(self, screen): self.prev.render(screen) screen.blit(self.image, (224, 48))
class EnemyTrigger: image = openres(f'imgs/npc.png').convert_alpha() def __init__(self, enemy, poses=()): self.enemy = enemy self.poses = poses def __call__(self, pos): game.map.triggers.pop(pos, None) for pos in self.poses: game.map.triggers.pop(pos, None) if len(game.role.equips) < 2: SceneM().call(Gameover) def onback(): SceneM().call(YouWin) SceneM().call(Combat, self.enemy, onback=onback)
class WeaponTrigger: image = openres(f'imgs/npc.png').convert_alpha() def __init__(self): self.acc = 0 self.triggers = { (7, 8): Npc(['Village was attacked by monsters!!']), (11, 18): self.final, (18, 12): self.due } def __call__(self, pos): self.acc += 1 if self.acc == 3: game.map.triggers.update({ (2, 3): Pick(Sword('iron sword', 30, 5)), (1, 16): Pick(Shield('wooden shield', 0, 20)) }) self.triggers[pos](pos) def final(self, pos): result = snake.main() if result: Pick(Final())(pos) Game().role.base_attack += 4 Game().role.base_defense += 4 SceneM().call(DialogGetFinal, ['Get skill Final']) else: SceneM().call(Dialog, ['You lose the game']) def due(self, pos): Game().map.triggers.pop(pos, None) result = tankwar_main() if result: Pick(DueEssay())(pos) Game().role.base_attack += 4 Game().role.base_defense += 4 SceneM().call(DialogGetDueEssay, ['Get skill Due Essay']) else: SceneM().call(Dialog, ['You lose the game'])
class Key(pg.Rect): " Keys img" img = openres('images/key.png') " '__*__'' function is a type of python's function" def __init__(self, pos, id): rect = self.img.get_rect() rect.center = pos super().__init__(rect) self.id = id " Data reconstruction is used to cater to .json" " Don't have to return the .json format then can do it without conflicts" " For game load and save" def __hash__(self): return self.id.__hash__()
class Dialog(Scene): surf = openres('imgs/dialog.png').convert_alpha() def __init__(self, prev, dialog): super().__init__(prev) self.dialog = dialog or ['...'] def render(self, screen): self.prev.render(screen) surf = self.surf.copy() black = (255, 255, 255) s = pg.font.Font(None, 32).render(self.dialog[-1], True, black) surf.blit(s, (10, 10)) screen.blit(surf, (0, 400)) def handle_event(self, e): if e.type == pg.KEYDOWN or e.type == pg.MOUSEBUTTONDOWN: self.dialog.pop() if not self.dialog: SceneM().back()
def render(self, screen): help = openres('images/help.png') screen.blit(help, (0, 0))
def surf_top(self): return openres(f'maps/{self.iid}/top.png').convert_alpha()
def surf(self): return openres(f'imgs/role/{self.name}.png').convert_alpha()
def image(self): return openres(f'imgs/enemy/{self.name}.png').convert_alpha()
class Player: " Player img reading" frames = { dir: openres(f'images/player/{dir}.png').convert_alpha() for dir in ['up', 'down', 'left', 'right'] } " Python custom constructor, the initial variable defined by itself." " Based on python is a dynamic language, so renew variable without need to redefine it again." def __init__(self, dir, rect, speed, health, exp, attack, items): self.dir = dir self.exp = exp self.rect = rect # pygame.Rect self.speed = speed self.health = health self.attack = attack self.items = items # set def run(self, elapse): rect = self.rect.copy() keys = pg.key.get_pressed() " Control method" if keys[pg.K_LEFT]: rect.x -= self.speed self.dir = 'left' elif keys[pg.K_RIGHT]: rect.x += self.speed self.dir = 'right' elif keys[pg.K_UP]: rect.y -= self.speed self.dir = 'up' elif keys[pg.K_DOWN]: rect.y += self.speed self.dir = 'down' " Renew the coordinates without conflict with the map" if not game.level.check_collide(rect): self.rect = rect " Screen rendering (print out the window)" def render(self, screen): screen.blit(self.frames[self.dir], self.rect) " Rect the type of PyGame.Rect and Items are of type set (line 71 and 75)" " Since the game needs to be saved as readable text, all entity objects that need to be saved should be available. Data structure that can be expressed by conversion to json" " This two method is for converted into a data structure that json can express" def to_data(self): data = self.__dict__.copy() data['rect'] = list(self.rect) data['items'] = list(self.items) return data @staticmethod def load(data): data['rect'] = pg.Rect(data['rect']) data['items'] = set(data['items']) return Player(**data) " '__str__' is the method to call when converting a type to a string" " Change .json type structure into character then printout" def __str__(self): return f'Speed: {self.speed} Health: {self.health} Attack: {self.attack} EXP: {self.exp}'
def surf(self): return openres(f'maps/{self.iid}/bottom.png').convert_alpha()
def image(self): name = self.name.replace(' ', '-') return openres(f'imgs/items/{name}.png').convert_alpha()
def func(): Game._instance = openres(fn, 'rb') SceneM().switch(Main())