class Road(Ground): def __init__(self, x, y): self.angle = 0 self.timer = Timer(settings.FPS*settings.EXTINCT_ROAD_YEAR) super(Road, self).__init__(x, y) def update(self): self.timer.tick() if self.timer.is_over(): return 1 def rotate(self, deg): u""" deg=1のとき時計回りに、deg=-1のとき反時計回りに回転させる self.nodeのbit列を 右循環シフト=時計回り 左循環シフト=反時計回り """ if deg==1: self.angle = (self.angle+1)%4 self.node = (self.node & 1) << 3 | (self.node & 14) >> 1 elif deg==-1: self.angle = (self.angle+3)%4 self.node = (self.node & 7) << 1 | (self.node & 8) >> 3 def is_road(self): return True def on_attach(self): self.timer.play()
class ResultSequence(Sequence): def ready(self): self.win = Animation(u"../resources/image/main/text/win.png", AnimationInfo(-1, 0, 1, 360, 225, 1)) finish_sound = Sound("../resources/sound/finish.wav") finish_sound.play() self.win.animation_enable = False self.win.x = settings.SCREENWIDTH/2-180 self.win.y = settings.SCREENHEIGHT/2-180 self.text.ainfo.index = 3 self.winner = self.scene.world.get_winner() self.result_timer = Timer(settings.FPS*2.5) self.result_timer.play() def update(self): self.result_timer.tick() if self.result_timer.is_active() and self.result_timer.is_over(): self.text.ainfo.index = -1 self.scene.bgm.change(u"../resources/music/fanfare_intro.wav", -1, u"../resources/music/fanfare_loop.wav", 100) self.win.ainfo.index = self.winner.number self.result_timer.stop() for player in self.scene.world.players: p = player.poll() u"""p=3のとき、リプレイ""" if not self.result_timer.is_active() and p == 3: self.scene.bgm.change(u"../resources/music/main_intro.wav", -1, u"../resources/music/main_loop.wav") self.scene.sequence_manager.change_scene('ready') #ToDo Retry or Title def draw(self): rect = self.scene.world.draw() map(lambda n: n.draw(), self.scene.navigations) self.scene.timer.draw() self.text.draw() self.win.draw() return rect
class LogoScene(Scene): BACKGROUND = (255, 255, 255) def ready(self, *args, **kwargs): super(LogoScene, self).ready() self.background = Image("../resources/image/menu/whiteback.png", alpha=False) self.logo = Image("../resources/image/menu/kawaz.png", alpha=False) self.logo.x = 340 self.logo.y = 230 self.sprites.add(self.background) self.sprites.add(self.logo) self.timer = Timer(210) self.mouse = Mouse(0) self.joypads = [] for i in xrange(0, JoyPad.get_num_joypads()): self.joypads.append(JoyPad(i)) def update(self): self.timer.tick() self.timer.play() skip = self.mouse.is_press(Mouse.LEFT) for joypad in self.joypads: skip |= joypad.is_press(4) if self.timer.is_over() or skip: Game.get_scene_manager().change_scene('mainmenu') elif self.timer.now < 60: self.logo.alpha = 255 * self.timer.now / 60 elif 120 < self.timer.now: self.logo.alpha = 255 * (180 - self.timer.now) / 60
class Building(Panel): u"""建物クラス""" LEVEL = 0 OFFSET = (0, 0) def __init__(self, x, y): u""" x, y : マップ座標 """ self.timer = Timer(settings.FPS*settings.EXTINCT_BUILDING_YEAR) self.level = self.LEVEL self.timer.play() super(Building, self).__init__(x, y) def draw(self, surface=Game.get_screen()): self.x = settings.ROOT_POSITION[0] - self.point.y*37 + self.point.x*37 - self.OFFSET[0] self.y = settings.ROOT_POSITION[1] + self.point.x*19 + self.point.y*19 - self.OFFSET[1] super(Panel, self).draw(surface) def update(self): u"""建物が消えるとき、-1を返す""" self.timer.tick() if self.timer.is_over(): return -1 return 0 @property def size(self): if self.level <= 2: return 1 elif self.level <= 4: return 2 else: return 4
class Road(Ground): def __init__(self, x, y): self.angle = 0 self.timer = Timer(settings.FPS*settings.EXTINCT_ROAD_YEAR) super(Road, self).__init__(x, y) def update(self): self.timer.tick() if self.timer.is_over(): return 1 def rotate(self, deg): u""" deg=1のとき時計回りに、deg=-1のとき反時計回りに回転させる self.nodeのbit列を 右循環シフト=時計回り 左循環シフト=反時計回り """ if deg==1: self.angle = (self.angle+1)%4 self.node = (self.node & 1) << 3 | (self.node & 14) >> 1 elif deg==-1: self.angle = (self.angle+3)%4 self.node = (self.node & 7) << 1 | (self.node & 8) >> 3 def is_road(self): return True def on_attach(self): self.timer.play() def can_attach_road(self): return settings.CAN_ATTACH_ON_ROAD
class NPC(Player): def __init__(self, n): super(NPC, self).__init__(n) self.act_timer = Timer(1) self.goal = LocalPoint(0,0) self.interfaces = ['npc'] self.rotate = False def update(self): self.act_timer.tick() if self.point == self.goal: self.goal = LocalPoint(random.randint(0,settings.STAGE_WIDTH),random.randint((1-self.number)*settings.STAGE_WIDTH/2,(1-self.number)*settings.STAGE_WIDTH/2+settings.STAGE_WIDTH/2-3)) self.rotate = True else: if not self.act_timer.is_over(): return sub = self.goal - self.point if sub.x >0: self.point.x +=1 elif sub.x < 0: self.point.x -=1 if sub.y >0: self.point.y +=1 elif sub.y < 0: self.point.y -=1 self.move_pointer() self.act_timer.reset() self.act_timer.play() def poll(self): if self.rotate: self.rotate = False return random.choice([-1,1])
class LogoScene(Scene): BACKGROUND = (255,255,255) def ready(self, *args, **kwargs): super(LogoScene, self).ready() self.background = Image("../resources/image/menu/whiteback.png", alpha=False) self.logo = Image("../resources/image/menu/kawaz.png", alpha=False) self.logo.x = 340 self.logo.y = 230 self.sprites.add(self.background) self.sprites.add(self.logo) self.timer = Timer(210) self.mouse = Mouse(0) self.joypads = [] for i in xrange(0, JoyPad.get_num_joypads()): self.joypads.append(JoyPad(i)) def update(self): self.timer.tick() self.timer.play() skip = self.mouse.is_press(Mouse.LEFT) for joypad in self.joypads: skip |= joypad.is_press(4) if self.timer.is_over() or skip: Game.get_scene_manager().change_scene('mainmenu') elif self.timer.now < 60: self.logo.alpha = 255*self.timer.now/60 elif 120 < self.timer.now: self.logo.alpha = 255*(180-self.timer.now)/60
class Panel(Image): disable = False rotation = False unit = False def __init__(self, x=0, y=0, owner=0): u""" x,y: マップ上の相対座標 """ self.point = LocalPoint(x,y) self.color = random.randint(0,3) self.owner = owner self.disable_timer = Timer(120) self.redraw = True super(Panel,self).__init__("../resources/image/main/panel/panel%d_%d.png" % (owner, self.color), x=x*settings.PANELSIZE+settings.STAGE_OFFSET[0], y=y*settings.PANELSIZE+settings.STAGE_OFFSET[1]) def __eq__(self, p): return self.point == p.point def update(self): if self.disable: self.disable_timer.tick() if self.disable_timer.is_over(): self.set_disable(False) self.x = self.point.x*settings.PANELSIZE+settings.STAGE_OFFSET[0] self.y = self.point.y*settings.PANELSIZE+settings.STAGE_OFFSET[1] return False def get_point(self): return self.point def can_unit(self): return not self.rotation and not self.disable and not self.unit def can_rotate(self): return not self.rotation def can_through(self): return not self.unit and not self.rotation def is_dummy(self): return False def change_owner(self, owner): if not self.owner == owner: self.owner = owner self.change_image("../resources/image/main/panel/panel%d_%d.png" % (owner, self.color)) def change_color(self): color = random.randint(0,3) if not self.color == color: self.color = color if not self.disable: self.change_image("../resources/image/main/panel/panel%d_%d.png" % (self.owner, self.color)) def set_disable(self, disable): if not self.disable == disable: self.disable = disable if disable: self.disable_timer.play() if settings.EFFECTENABLE: Effect(u'../resources/effect/disable.png', AnimationInfo(0,0,60,64,64,1), x=self.x-22, y=self.y-22) self.change_image(u"../resources/image/main/panel/disable.png") else: self.disable_timer.stop() self.change_image(u"../resources/image/main/panel/panel%d_%d.png" % (self.owner, self.color)) def rotate(self): if self.disable: self.disable_timer.move(5)
class PanelSet(object): def __init__(self, panels, degree=0): u""" panels 左上から時計回りに4枚のパネルを渡す degree 回転方向を渡す。1なら反時計回り、-1なら時計回り """ self.degree = degree self.panels = panels self.timer = Timer(settings.ROTATE_SPEED) panels[0].center = Vector(settings.PANELSIZE,settings.PANELSIZE) panels[1].center = Vector(0, settings.PANELSIZE) panels[2].center = Vector(0,0) panels[3].center = Vector(settings.PANELSIZE,0) map(lambda panel: panel.rotate(), self.panels) self.timer.play() def update(self): self.timer.tick() if not self.timer.is_over(): for panel in self.panels: panel.rotation = True if self.timer.now < self.timer.max: panel.angle = self.timer.now*90/(self.timer.max-1)*self.degree def is_over(self): return self.timer.is_over()
class GameTimer(Number): def __init__(self): self.timer = Timer(settings.FPS * settings.YEARS) super(GameTimer, self).__init__(u"../resources/image/main/navigation/timer.png", w=36, h=90) self.x, self.y = settings.TIMER_POSITON self.align = Number.TEXTALIGNCENTER self.n = int((self.timer.max - self.timer.now) / settings.FPS) def update(self): self.timer.tick() self.n = int((self.timer.max - self.timer.now) / settings.FPS) def play(self): self.timer.play() def is_over(self): return self.timer.is_over()
class GameTimer(Number): def __init__(self): self.timer = Timer(settings.FPS*settings.YEARS) super(GameTimer, self).__init__(u"../resources/image/main/navigation/timer.png", w=36, h=90) self.x, self.y = settings.TIMER_POSITON self.align = Number.TEXTALIGNCENTER self.n = int((self.timer.max-self.timer.now)/settings.FPS) def update(self): self.timer.tick() self.n = int((self.timer.max-self.timer.now)/settings.FPS) def play(self): self.timer.play() def is_over(self): return self.timer.is_over() def reset(self): self.timer.reset() @property def now(self): return self.n
class LogoScene(Scene): BACKGROUND = (255,255,255) def ready(self, *args, **kwargs): super(LogoScene, self).ready() self.background = Image("../resources/image/menu/whiteback.png", alpha=False) self.logo = Image("../resources/image/menu/kawaz-full.png", alpha=False) self.sprites.add(self.background) self.sprites.add(self.logo) self.timer = Timer(210) def update(self): self.timer.tick() self.timer.play() if self.timer.is_over() or Mouse.is_press('LEFT'): Game.get_scene_manager().change_scene('title') elif self.timer.now < 60: self.logo.alpha = 255*self.timer.now/60 elif 120 < self.timer.now: self.logo.alpha = 255*(180-self.timer.now)/60
class Building(Panel): u"""建物クラス""" LEVEL = 0 OFFSET = (0, 0) def __init__(self, x, y): u""" x, y : マップ座標 """ self.timer = Timer(settings.FPS * settings.EXTINCT_BUILDING_YEAR) self.level = self.LEVEL self.timer.play() super(Building, self).__init__(x, y) def draw(self, surface=Game.get_screen()): self.x = settings.ROOT_POSITION[ 0] - self.point.y * 37 + self.point.x * 37 - self.OFFSET[0] self.y = settings.ROOT_POSITION[ 1] + self.point.x * 19 + self.point.y * 19 - self.OFFSET[1] super(Panel, self).draw(surface) def update(self): u"""建物が消えるとき、-1を返す""" self.timer.tick() if self.timer.is_over(): return -1 return 0 @property def size(self): if self.level <= 2: return 1 elif self.level <= 4: return 2 else: return 4
class City(object): u"""街クラス。人口や発展状況などを管理する""" def __init__(self, owner, world): u""" owner : この街を所持するプレイヤー world : Worldクラスインスタンス """ self.owner = owner self.world = world self.levelup_sound = Sound("../resources/sound/levelup.wav") self.increase_sound = Sound("../resources/sound/increase.wav") self.population = 0 self.level = 1 self.buildings = [] self.territories = [] self.flow_timer = Timer(settings.FPS * settings.FLOW_POPULATION_YEAR) self.building_matrix = [[None for col in range(settings.STAGE_HEIGHT)] for row in range(settings.STAGE_WIDTH) ] # 二次配列を生成してNoneで初期化 #self._constract_building(Laputa, 0, 0) def increase_population(self, p=None): u"""人口を増やす。その後、レベルアップの判定をする 増える人口はレベルに依存する。 p*2^(lv-1) """ self.flow_timer.reset() self.flow_timer.play() if not p: self.population += self._calc_population() else: self.population += p if self.level < 5 and settings.LEVELUP_BORDERLINES[ self.level] < self.population: self.levelup_sound.play() self.level += 1 else: self.increase_sound.play() def decrease_population(self, p): u""" p人人口を減らす 実際に減った人数を返す """ self.flow_timer.reset() self.flow_timer.play() if self.population < p: p = self.population self.population = 0 else: self.population -= p return p def _pop_building(self): u"""ビルを建てる""" if self.population <= 0: return if random.randint(0, settings.BUILDING_POP_RATE) != 0: return buildings = LEVEL_BUILDINGS[self.level - 1] if len(buildings) == 0: return if self.level <= 2: x = random.randint(0, 3) y = random.randint(0, 3) elif self.level <= 4: x, y = random.choice(((0, 0), (2, 0), (0, 2), (2, 2))) elif self.level == 5: x, y = (0, 0) if not self.building_matrix[x][y] or ( self.building_matrix[x][y] and self.building_matrix[x][y].level != self.level): building = random.choice(buildings) self._constract_building(building, x, y) def _constract_building(self, cls, x, y): building = cls(self.root_point.x + x, self.root_point.y + y) for sx in xrange(x, x + building.size): for sy in xrange(y, y + building.size): self.building_matrix[sx][sy] = building self.buildings.append(building) def _calc_population(self): u"""レベルに応じた増減する人口を算出する""" p = random.randint(8000, 12000) return p * 2**(self.level - 1) def update(self): self.flow_timer.tick() if self.flow_timer.is_over() and self.population > 0: u"""人を流出させる""" bottom_territories = self._get_bottom_territories() for territory in bottom_territories: u"""最も手前にある領土の一覧を取ってきて、繋がっているかどうか調査する""" front = self.world.get_panel_from(territory, 2) if territory.is_connect_with(front): self._flow_immigration(territory, front) self._pop_building() updated = [] for x in xrange(0, 4): for y in xrange(0, 4): b = self.building_matrix[x][y] if b and not b in updated: b.update() updated.append(b) def draw(self): rendered = [] for x in xrange(0, 4): for y in xrange(0, 4): b = self.building_matrix[x][y] if b and not b in rendered: b.draw() rendered.append(b) def _flow_immigration(self, territory, front): u"""移民を流出させる""" immigrant = self.world.i_manager.create_immigrant( territory.point.x, territory.point.y) p = self._calc_population() p = self.decrease_population(p) immigrant.population = p immigrant.direction = 2 immigrant.ainfo.index = 2 immigrant.current_ground = territory immigrant.x, immigrant.y = territory.surface_bottom_edge.to_pos() immigrant.goal_ground = front self.flow_timer.reset() def _get_bottom_territories(self): u"""領土最下層のTerritoryのみを取ってくる""" list = [] for territory in self.territories: if territory.point.y == 3: list.append(territory) return list @property def root_point(self): u"""街の左上の座標を返す""" pc = self.world.player_count if pc == 1: return Vector(6, 0) elif pc == 2: return (Vector(2, 0), Vector(10, 0))[self.owner.number] elif pc == 3: return (Vector(1, 0), Vector(6, 0), Vector(11, 0))[self.owner.number] elif pc == 4: return Vector(self.owner.number * 4, 0)
class Unit(object): animation_enable = False offset = (0,0) parameter = ATTACK name = 'unit' degree = LocalPoint(0,0) def __init__(self, panels, stage): self.panels = panels self.stage = stage self.owner = panels[0].owner self.color = panels[0].color self.degree = LocalPoint(0, -1+self.owner*2) self.image = Animation(self.parameter['image'], AnimationInfo(self.owner,0,0,self.parameter['width'],self.parameter['height'],0)) self.hp = self.parameter['hp'] self.attack = self.parameter['attack'] self.limit = self.parameter['limit'] self.count = 0 self.timer = Timer(self.parameter['frequency']) appear_sound = Sound(u'../resources/sound/appear.wav') appear_sound.play() self.image.x, self.image.y = (self.panels[0].point + LocalPoint(self.offset)).to_global().to_pos() self.delay = Timer() if self.parameter['effect']['enable'] and settings.EFFECTENABLE: ef = self.parameter['effect'] Effect(ef['appear'], AnimationInfo(0,0,ef['frame'],ef['width'],ef['height'],1), x=self.image.x-ef['offset'][0], y=self.image.y-ef['offset'][1]) self.delay.set(self.parameter['delay']) self.delay.play() @classmethod def generate(cls, panels, map): raise NotImplementedError @staticmethod def check(panels): color = panels[0].color owner = panels[0].owner for panel in panels: if not panel.can_unit() or not color == panel.color or not owner == panel.owner: return False else: return True def update(self): u"""1のとき進める、-1のとき消す""" for panel in self.panels: if panel.disable or not panel.owner == self.owner: return -1 self.image.x, self.image.y = (self.panels[0].point + LocalPoint(self.offset)).to_global().to_pos() self.delay.tick() if self.delay.is_over(): self.timer.play() self.timer.tick() if self.timer.is_over(): if self.count < self.limit: self.timer.reset() self.count+=1 return 1 else: return -1 return def move(self, panels): pass def draw(self): if self.delay.is_over(): self.image.draw() def get_front(self, vector): x, y = vector.to_pos() if x is 0 and y is -1: return self.panels.sort(cmp=lambda x, y: cmp(x.y,y.y))[0] elif x is 1 and y is 0: return self.panels.sort(cmp=lambda x, y: cmp(x.x,y.x), reverse=True)[0] elif x is 0 and y is 1: return self.panels.sort(cmp=lambda x, y: cmp(x.y,y.y), reverse=True)[0] elif x is -1 and y is 0: return self.panels.sort(cmp=lambda x, y: cmp(x.x,y.x))[0] def has(self, panel): return panel in self.panels def disappear(self): if not self.name == 'bomb': disappear_sound = Sound(u'../resources/sound/disappear.wav') disappear_sound.play() for panel in self.panels: panel.change_color() panel.unit = False
class MainMenuScene(Scene): BACKGROUND = (255,255,255) CURSOR_BORDER = 10 # カーソルを表す画像が、選択肢を表す画像からどれだけずらして配置されるか IMAGE_PATH = r"../resources/image/menu" KEY_REPEAT_TIME = 0.2 # 何秒以内の間なら、キーが押され続けていても連打とみなさないか # 2Players, 3Players, 4Playersの画像を読み込む def load_player_selection(self, joypad_number): fail = ("" if joypad_number >= 2 else "x") self.player2 = Image(os.path.join(self.IMAGE_PATH, "player2%s.png" % fail), alpha=False) fail = ("" if joypad_number >= 3 else "x") self.player3 = Image(os.path.join(self.IMAGE_PATH, "player3%s.png" % fail), alpha=False) fail = ("" if joypad_number >= 4 else "x") self.player4 = Image(os.path.join(self.IMAGE_PATH, "player4%s.png" % fail), alpha=False) # カーソルをx方向にdir_x、y方向にdir_yだけ動かす def set_cursor_pos(self, dir_x, dir_y): target_option = False while not target_option: # y方向 self.cursor_logical_y += dir_y if self.cursor_logical_y < 0: self.cursor_logical_y += len(self.options) if self.cursor_logical_y >= len(self.options): self.cursor_logical_y -= len(self.options) # x方向 self.cursor_logical_x += dir_x if self.cursor_logical_x < 0: self.cursor_logical_x += len(self.options[self.cursor_logical_y]) if self.cursor_logical_x >= len(self.options[self.cursor_logical_y]): self.cursor_logical_x -= len(self.options[self.cursor_logical_y]) # 描画位置の計算 target_option = self.options[self.cursor_logical_y][self.cursor_logical_x] self.cursor.x = target_option.x - self.CURSOR_BORDER self.cursor.y = target_option.y - self.CURSOR_BORDER # ゲームを始める def start_game(self, player_number): self.decide_timer.play() self.decide_sound.play() self.player_number = player_number def ready(self, *args, **kwargs): super(MainMenuScene, self).ready() self.bgm = BGM(u'../resources/music/title.wav', -1) self.cursor_sound = Sound("../resources/sound/cursor.wav") self.decide_sound = Sound('../resources/sound/decide.wav') self.decide_timer = Timer(settings.FPS*2.5) self.num_joypads = JoyPad.get_num_joypads() self.joypads = [] for i in xrange(0, self.num_joypads): self.joypads.append(JoyPad(i)) self.background = Image(os.path.join(self.IMAGE_PATH, "background3.png"), alpha=False) self.logo = Image(os.path.join(self.IMAGE_PATH, "logo.png")) self.config = Image(os.path.join(self.IMAGE_PATH, "config.png"), alpha=False) self.exit = Image(os.path.join(self.IMAGE_PATH, "exit.png"), alpha=False) self.cursor = Image(os.path.join(self.IMAGE_PATH, "cursor.png"), alpha=True) self.cursor_threshold = [[0, 0], ] * self.num_joypads # ジョイスティックを倒したときに、axisがどれくらい倒れたかの総量 self.cursor_move = [False] * self.num_joypads self.load_player_selection(self.num_joypads) self.logo.x = 280; self.logo.y = 20 self.player2.x = 160; self.player2.y = 400 self.player3.x = 380; self.player3.y = 400 self.player4.x = 600; self.player4.y = 400 self.config.x = 380; self.config.y = 460 self.exit.x = 600; self.exit.y = 460 # カーソル位置を初期化 self.options = ((self.player2, self.player3, self.player4), (None, self.config, self.exit)) self.actions = ((lambda:self.start_game(2), # self.player2 lambda:self.start_game(3), # self.player3 lambda:self.start_game(4),)# self.player4 , (lambda:0, # None lambda:Game.get_scene_manager().change_scene('keysetting'), #self.config lambda:sys.exit()) # self.exit ) self.cursor_logical_x = 0; self.cursor_logical_y = 0; self.set_cursor_pos(0, 0) self.sprites.add(self.background) self.sprites.add(self.logo) self.sprites.add(self.player2) self.sprites.add(self.player3) self.sprites.add(self.player4) self.sprites.add(self.config) self.sprites.add(self.exit) self.sprites.add(self.cursor) self.last_press_key = [{}] for dummy in self.joypads: self.last_press_key.append({}) def update(self): self.decide_timer.tick() if self.decide_timer.is_over(): Game.get_scene_manager().change_scene('game', players=self.player_number) self.bgm.fadeout(100) if self.decide_timer.is_active(): return self.bgm.play() for id, joypad in enumerate(self.joypads): xaxis = joypad.get_axis(0) yaxis = joypad.get_axis(1) length = sum(map(lambda x: x*x, list(self.cursor_threshold[id]))) if abs(xaxis) > 0.5: self.cursor_threshold[id][0] += xaxis if not self.cursor_move[id] or abs(length) > 16: self.cursor_sound.play() self.set_cursor_pos(1 if xaxis > 0 else - 1, 0) if abs(yaxis) > 0.5: self.cursor_threshold[id][1] += yaxis if not self.cursor_move[id] or abs(length) > 16: self.cursor_sound.play() self.set_cursor_pos(0, 1 if yaxis > 0 else - 1) if abs(xaxis) > 0.5 or abs(yaxis) > 0.5: self.cursor_move[id] = True else: self.cursor_move[id] = False self.cursor_threshold[id] = [0, 0] if joypad.is_press(11): self.actions[self.cursor_logical_y][self.cursor_logical_x]()
class MainMenuScene(Scene): BACKGROUND = (255, 255, 255) CURSOR_BORDER = 10 # カーソルを表す画像が、選択肢を表す画像からどれだけずらして配置されるか IMAGE_PATH = r"../resources/image/menu" KEY_REPEAT_TIME = 0.2 # 何秒以内の間なら、キーが押され続けていても連打とみなさないか # 2Players, 3Players, 4Playersの画像を読み込む def load_player_selection(self, joypad_number): fail = ("" if joypad_number >= 2 else "x") self.player2 = Image(os.path.join(self.IMAGE_PATH, "player2%s.png" % fail), alpha=False) fail = ("" if joypad_number >= 3 else "x") self.player3 = Image(os.path.join(self.IMAGE_PATH, "player3%s.png" % fail), alpha=False) fail = ("" if joypad_number >= 4 else "x") self.player4 = Image(os.path.join(self.IMAGE_PATH, "player4%s.png" % fail), alpha=False) # カーソルをx方向にdir_x、y方向にdir_yだけ動かす def set_cursor_pos(self, dir_x, dir_y): target_option = False while not target_option: # y方向 self.cursor_logical_y += dir_y if self.cursor_logical_y < 0: self.cursor_logical_y += len(self.options) if self.cursor_logical_y >= len(self.options): self.cursor_logical_y -= len(self.options) # x方向 self.cursor_logical_x += dir_x if self.cursor_logical_x < 0: self.cursor_logical_x += len( self.options[self.cursor_logical_y]) if self.cursor_logical_x >= len( self.options[self.cursor_logical_y]): self.cursor_logical_x -= len( self.options[self.cursor_logical_y]) # 描画位置の計算 target_option = self.options[self.cursor_logical_y][ self.cursor_logical_x] self.cursor.x = target_option.x - self.CURSOR_BORDER self.cursor.y = target_option.y - self.CURSOR_BORDER # ゲームを始める def start_game(self, player_number): self.decide_timer.play() self.decide_sound.play() self.player_number = player_number def ready(self, *args, **kwargs): super(MainMenuScene, self).ready() self.bgm = BGM(u'../resources/music/title.wav', -1) self.cursor_sound = Sound("../resources/sound/cursor.wav") self.decide_sound = Sound('../resources/sound/decide.wav') self.decide_timer = Timer(settings.FPS * 2.5) self.num_joypads = JoyPad.get_num_joypads() self.joypads = [] for i in xrange(0, self.num_joypads): self.joypads.append(JoyPad(i)) self.background = Image(os.path.join(self.IMAGE_PATH, "background3.png"), alpha=False) self.logo = Image(os.path.join(self.IMAGE_PATH, "logo.png")) self.config = Image(os.path.join(self.IMAGE_PATH, "config.png"), alpha=False) self.exit = Image(os.path.join(self.IMAGE_PATH, "exit.png"), alpha=False) self.cursor = Image(os.path.join(self.IMAGE_PATH, "cursor.png"), alpha=True) self.cursor_threshold = [ [0, 0], ] * self.num_joypads # ジョイスティックを倒したときに、axisがどれくらい倒れたかの総量 self.cursor_move = [False] * self.num_joypads self.load_player_selection(self.num_joypads) self.logo.x = 280 self.logo.y = 20 self.player2.x = 160 self.player2.y = 400 self.player3.x = 380 self.player3.y = 400 self.player4.x = 600 self.player4.y = 400 self.config.x = 380 self.config.y = 460 self.exit.x = 600 self.exit.y = 460 # カーソル位置を初期化 self.options = ((self.player2, self.player3, self.player4), (None, self.config, self.exit)) self.actions = ( ( lambda: self.start_game(2), # self.player2 lambda: self.start_game(3), # self.player3 lambda: self.start_game(4), ) # self.player4 , ( lambda: 0, # None lambda: Game.get_scene_manager().change_scene('keysetting' ), #self.config lambda: sys.exit()) # self.exit ) self.cursor_logical_x = 0 self.cursor_logical_y = 0 self.set_cursor_pos(0, 0) self.sprites.add(self.background) self.sprites.add(self.logo) self.sprites.add(self.player2) self.sprites.add(self.player3) self.sprites.add(self.player4) self.sprites.add(self.config) self.sprites.add(self.exit) self.sprites.add(self.cursor) self.last_press_key = [{}] for dummy in self.joypads: self.last_press_key.append({}) def update(self): self.decide_timer.tick() if self.decide_timer.is_over(): Game.get_scene_manager().change_scene('game', players=self.player_number) self.bgm.fadeout(100) if self.decide_timer.is_active(): return self.bgm.play() for id, joypad in enumerate(self.joypads): xaxis = joypad.get_axis(0) yaxis = joypad.get_axis(1) length = sum(map(lambda x: x * x, list(self.cursor_threshold[id]))) if abs(xaxis) > 0.5: self.cursor_threshold[id][0] += xaxis if not self.cursor_move[id] or abs(length) > 16: self.cursor_sound.play() self.set_cursor_pos(1 if xaxis > 0 else -1, 0) if abs(yaxis) > 0.5: self.cursor_threshold[id][1] += yaxis if not self.cursor_move[id] or abs(length) > 16: self.cursor_sound.play() self.set_cursor_pos(0, 1 if yaxis > 0 else -1) if abs(xaxis) > 0.5 or abs(yaxis) > 0.5: self.cursor_move[id] = True else: self.cursor_move[id] = False self.cursor_threshold[id] = [0, 0] if joypad.is_press(11): self.actions[self.cursor_logical_y][self.cursor_logical_x]()
class City(object): u"""街クラス。人口や発展状況などを管理する""" def __init__(self, owner, world): u""" owner : この街を所持するプレイヤー world : Worldクラスインスタンス """ self.owner = owner self.world = world self.levelup_sound = Sound("../resources/sound/levelup.wav") self.increase_sound = Sound("../resources/sound/increase.wav") self.population = 0 self.level = 1 self.buildings = [] self.territories = [] self.flow_timer = Timer(settings.FPS*settings.FLOW_POPULATION_YEAR) self.building_matrix = [[None for col in range(settings.STAGE_HEIGHT)] for row in range(settings.STAGE_WIDTH)] # 二次配列を生成してNoneで初期化 #self._constract_building(Laputa, 0, 0) def increase_population(self, p=None): u"""人口を増やす。その後、レベルアップの判定をする 増える人口はレベルに依存する。 p*2^(lv-1) """ self.flow_timer.reset() self.flow_timer.play() if not p: self.population += self._calc_population() else: self.population += p if self.level < 5 and settings.LEVELUP_BORDERLINES[self.level] < self.population: self.levelup_sound.play() self.level +=1 else: self.increase_sound.play() def decrease_population(self, p): u""" p人人口を減らす 実際に減った人数を返す """ self.flow_timer.reset() self.flow_timer.play() if self.population < p: p = self.population self.population = 0 else: self.population -= p return p def _pop_building(self): u"""ビルを建てる""" if self.population <= 0: return if random.randint(0, settings.BUILDING_POP_RATE) != 0: return buildings = LEVEL_BUILDINGS[self.level-1] if len(buildings) == 0: return if self.level <= 2: x = random.randint(0, 3) y = random.randint(0, 3) elif self.level <= 4: x, y = random.choice(((0, 0), (2, 0), (0, 2), (2, 2))) elif self.level == 5: x, y = (0, 0) if not self.building_matrix[x][y] or (self.building_matrix[x][y] and self.building_matrix[x][y].level != self.level): building = random.choice(buildings) self._constract_building(building, x, y) def _constract_building(self, cls, x, y): building = cls(self.root_point.x+x, self.root_point.y+y) for sx in xrange(x, x+building.size): for sy in xrange(y, y+building.size): self.building_matrix[sx][sy] = building self.buildings.append(building) def _calc_population(self): u"""レベルに応じた増減する人口を算出する""" p = random.randint(8000, 12000) return p*2**(self.level-1) def update(self): self.flow_timer.tick() if self.flow_timer.is_over() and self.population > 0: u"""人を流出させる""" bottom_territories = self._get_bottom_territories() for territory in bottom_territories: u"""最も手前にある領土の一覧を取ってきて、繋がっているかどうか調査する""" front = self.world.get_panel_from(territory, 2) if territory.is_connect_with(front): self._flow_immigration(territory, front) self._pop_building() updated = [] for x in xrange(0, 4): for y in xrange(0, 4): b = self.building_matrix[x][y] if b and not b in updated: b.update() updated.append(b) def draw(self): rendered = [] for x in xrange(0, 4): for y in xrange(0, 4): b = self.building_matrix[x][y] if b and not b in rendered: b.draw() rendered.append(b) def _flow_immigration(self, territory, front): u"""移民を流出させる""" immigrant = self.world.i_manager.create_immigrant(territory.point.x, territory.point.y) p = self._calc_population() p = self.decrease_population(p) immigrant.population = p immigrant.direction = 2 immigrant.ainfo.index = 2 immigrant.current_ground = territory immigrant.x, immigrant.y = territory.surface_bottom_edge.to_pos() immigrant.goal_ground = front self.flow_timer.reset() def _get_bottom_territories(self): u"""領土最下層のTerritoryのみを取ってくる""" list = [] for territory in self.territories: if territory.point.y == 3: list.append(territory) return list @property def root_point(self): u"""街の左上の座標を返す""" pc = self.world.player_count if pc == 1: return Vector(6, 0) elif pc == 2: return (Vector(2, 0), Vector(10, 0))[self.owner.number] elif pc == 3: return (Vector(1, 0), Vector(6, 0), Vector(11, 0))[self.owner.number] elif pc == 4: return Vector(self.owner.number*4, 0)
class City(object): u"""街クラス。人口や発展状況などを管理する""" def __init__(self, owner, world): u""" owner : この街を所持するプレイヤー world : Worldクラスインスタンス """ self.owner = owner self.world = world self.population = 0 self.level = 1 self.buildings = [] self.territories = [] self.flow_timer = Timer(settings.FPS*settings.FLOW_POPULATION_YEAR) self.building_matrix = [] for x in xrange(0, 4): row = [] for y in xrange(0, 4): u"""領土内相対座標の二次配列作成""" row.append(None) self.building_matrix.append(row) def increase_population(self, p=None): u"""人口を増やす。その後、レベルアップの判定をする 増える人口はレベルに依存する。 p*2^(lv-1) """ self.flow_timer.reset() self.flow_timer.play() if not p: self.population += self._calc_population() else: self.population += p if self.level < 5 and settings.LEVELUP_BORDERLINES[self.level] < self.population: self.level +=1 print "LevelUp! %d" % self.level def decrease_population(self, p): u""" p人人口を減らす 実際に減った人数を返す """ self.flow_timer.reset() self.flow_timer.play() if self.population < p: p = self.population self.population = 0 else: self.population -= p return p def _create_building(self): if self.population <= 0: return if random.randint(0, settings.BUILDING_POP_RATE) != 0: return x = random.randint(0, 3) y = random.randint(0, 3) if not self.building_matrix[x][y] or (self.building_matrix[x][y] and self.building_matrix[x][y].level != self.level): bs = LEVEL_BUILDINGS[self.level-1] if len(bs) == 0: return building = random.choice(bs)(self.root_point.x+x, self.root_point.y+y) for sx in xrange(x, x+building.size): for sy in xrange(y, y+building.size): self.building_matrix[sx][sy] = building def _calc_population(self): u"""レベルに応じた増減する人口を算出する""" p = random.randint(8000, 12000) return p*2**(self.level-1) def update(self): self.flow_timer.tick() if self.flow_timer.is_over() and self.population > 0: u"""人を流出させる""" bottom_territories = self._get_bottom_territories() for territory in bottom_territories: u"""最も手前にある領土の一覧を取ってきて、繋がっているかどうか調査する""" front = self.world.get_panel_from(territory, 2) if territory.is_connect_with(front): self._flow_immigration(territory, front) self._create_building() updated = [] for x in xrange(0, 4): for y in xrange(0, 4): b = self.building_matrix[x][y] if b and not b in updated: b.update() updated.append(b) def draw(self): rendered = [] for x in xrange(0, 4): for y in xrange(0, 4): b = self.building_matrix[x][y] if b and not b in rendered: b.draw() rendered.append(b) def _flow_immigration(self, territory, front): immigrant = self.world.i_manager.create_immigrant(territory.point.x, territory.point.y) p = self._calc_population() p = self.decrease_population(p) immigrant.population = p immigrant.direction = 2 immigrant.ainfo.index = 2 immigrant.current_ground = territory immigrant.x, immigrant.y = territory.surface_bottom_edge.to_pos() immigrant.goal_ground = front self.flow_timer.reset() def _get_bottom_territories(self): u"""領土最下層のTerritoryのみを取ってくる""" list = [] for territory in self.territories: if territory.point.y == 3: list.append(territory) return list @property def root_point(self): return Vector(self.owner.number*4, 0)