def new(self): self.dragging_camera = False self.all_sprites = pg.sprite.LayeredUpdates() self.items = pg.sprite.Group() self.imps = pg.sprite.Group() self.woods = pg.sprite.Group() self.map = Map(self) self.map.generate(200, 200) self.map.light(vec(10, 10), 20, 1) self.camera = Camera(self) self.game_speed = 200 self.pause = False self.mode = None self.dragging = 0 # 0: False, 1: add, -1:remove pg.mixer.music.load(path.join(self.snd_dir, 'ObservingTheStar.ogg')) Imp(self, vec(10, 10)) self.camera.focus(vec(10 * config.TILESIZE, 10 * config.TILESIZE)) self.resource = { 'woods': 0, 'iron': 0, }
def draw_mode_icon(self, mode): if mode == 'dig&cut': image = self.img['axe_iron'] mode_name = 'Dig&Cut' elif mode == 'resource': image = self.map.image['greystone_sand'] mode_name = 'Set Resource Area' elif mode == 'imp': image = self.img['imp'] mode_name = 'Minion' elif mode == 'ladder': image = self.map.image['ladder'].copy() mode_name = 'Ladder' elif mode == 'torch': image = self.map.image['torch'] mode_name = 'Torch' elif mode == 'shelf': image = self.map.image['shelf'] mode_name = 'Library' elif mode == 'bed': image = self.map.image['bed'] mode_name = 'Bed' else: image = self.map.image['table'] mode_name = 'Nothing' self.screen.blit(pg.transform.scale(image, (64, 64)), vec(WIDTH - 96, HEIGHT - 96)) self.draw_text(mode_name, 46, WHITE, vec(WIDTH - 104, HEIGHT - 90), align='right')
def __init__(self): super().__init__() self.pos = vec(0, 0) self.vel = vec(0, 0) self.direction = random.randint(0, 1) self.hp = 20 self.stunned = False if self.direction == 0: self.pos.x = 0 self.pos.y = 260 if self.direction == 1: self.pos.x = 700 self.pos.y = 260
def move(self): self.acc = vec(0, 0) if abs(self.vel.x) > 0.15: self.running = True else: self.running = False pressed_keys = pygame.key.get_pressed() if pressed_keys[K_a]: self.acc.x = -ACC elif pressed_keys[K_d]: self.acc.x = ACC if pressed_keys[K_w]: self.acc.y = -ACC elif pressed_keys[K_s]: self.acc.y = ACC self.acc.x += self.vel.x * FRIC self.acc.y += self.vel.y * FRIC self.vel += self.acc self.pos += self.vel + self.acc / 2 if self.pos.x > WIDTH: self.pos.x = 0 if self.pos.x < 0: self.pos.x = WIDTH self.rect.midbottom = self.pos
def __init__(self): super().__init__() self.image = pygame.image.load( "assets/Player_Movement_Animations/Player_Sprite_R.png") self.rect = self.image.get_rect() self.vx = 0 self.pos = vec((340, 240)) self.vel = vec(0, 0) self.acc = vec(0, 0) self.direction = "RIGHT" self.move_frame = 0 self.attacking = False self.attack_frame = 0 self.hp = 100 self.iframe = False self.normal_attack_frames = 10
def consume_woods(self, n): for i, wood_in_res in enumerate([ wood for wood in self.woods if vec2int(wood.pos + vec(0, 1)) in self.map.groups['resource_mark'] ]): if i < n: wood_in_res.kill()
def update(self): self.rect.topleft = config.TILESIZE * self.pos self.float_pos = vec2int(config.TILESIZE * self.pos) if self.owner: self.pos = vec(self.owner.pos) # 掉落,用来临时解决脚下方块消失的问题 while not self.game.map.can_stand(self.pos): self.pos.y += 1 self.v = config.TILESIZE * self.pos - self.rect.topleft
def generate(self, w, h): self.width, self.height = w, h self.data = {(x, y): None for x in range(self.width) for y in range(self.height)} self.path_cache = {} noise = OpenSimplex(seed=random.randint(-100000, 100000)) base = 20 last_tree_x = 0 for col in range(w): hh = base + int(noise.noise2d(0, col / 10) * 10) hh = max(10, hh) hh = min(self.height - 10, hh) r = random.random() if r < .3: if col - last_tree_x >= 3: Tree(self, vec(col, hh - 1)) last_tree_x = col elif .3 < r < .6: Grass(self, vec(col, hh - 1)) elif .6 < r < .7: Rock(self, vec(col, hh - 1)) for row in range(hh, h): if row == hh: last_tile = Dirt(self, vec(col, row)) last_tile.image_name = 'dirt_grass' elif row < hh + 4: last_tile = Dirt(self, vec(col, row)) else: r = noise.noise2d(col / 10, row / 10) # r = noise.noise3d(col/10, row/10, noise.noise2d(col/10, row/10)) if -1 < r < -.8: last_tile = EmeraldOre(self, vec(col, row)) elif -.8 < r < -.5: last_tile = RedStone(self, vec(col, row)) elif .15 < r < .2: last_tile = Dirt(self, vec(col, row)) elif .6 < r < 1: last_tile = IronOre(self, vec(col, row)) else: last_tile = Stone(self, vec(col, row))
def __init__(self, game, pos): self._layer = 1 self.groups = game.all_sprites, game.items, game.woods pg.sprite.Sprite.__init__(self, self.groups) self.game = game self.origin_image = self.game.img['wood'] self.image = self.origin_image self.rect = self.image.get_rect() self.pos = pos self.float_pos = vec2int(pos) self.v = vec() self.rect.topleft = self.pos * config.TILESIZE self.owner = None
def light(self, pos, view_radius=5, skip=6): # TODO light fade for angle in range(0, 360, skip): v = vec(math.cos(angle * 0.01745), math.sin(angle * 0.01745)) o = pos + (0.5, 0.5) block = False for i in range(view_radius): if not block: tile = self.data[vec2int(o)] self.groups['visible'][vec2int(o)] = tile self.groups['visited'][vec2int(o)] = tile # if tile and tile.in_group('block'): # block = True o += v if not self.in_map(o): block = True
def __init__(self, game, pos): self._layer = 2 self.groups = game.all_sprites, game.imps pg.sprite.Sprite.__init__(self, self.groups) self.game = game self.standing_image_l = self.game.img['imp'] self.standing_image_r = pg.transform.flip(self.standing_image_l, True, False) self.origin_image = random.choice( (self.standing_image_l, self.standing_image_r)) self.image = self.origin_image self.rect = self.image.get_rect() self.pos = pos self.float_pos = pos self.v = vec() self.rect.topleft = self.pos * config.TILESIZE self.task = None self.hp = 5 self.inventories = list()
def update(self): # Control # keys = pg.key.get_pressed() # if keys[pg.K_LEFT]: # self.move(x = -1) # elif keys[pg.K_RIGHT]: # self.move(x = 1) # elif keys[pg.K_UP]: # self.move(y = -1) # elif keys[pg.K_DOWN]: # self.move(y = 1) self.rect.topleft = config.TILESIZE * self.pos self.float_pos = vec2int(config.TILESIZE * self.pos) pos = vec(self.pos) # 拷贝原坐标,用于后面更新朝向 if isinstance(self.task, Dig) or isinstance(self.task, Cut): if vec2int(self.task.target ) not in self.game.map.groups['dig&cut_mark']: self.task = None else: find_res = self.find(self.task.dest) if find_res == 2: # 到达目的地,开始敲 # random.choice(self.game.snd['digging']).play() if isinstance(self.task, Dig): random.choice(self.game.snd['digging']).play() elif isinstance(self.task, Cut): self.game.snd['cut_tree'].play() if self.game.map.data[vec2int( self.task.target)].hit(-1) <= 0: if isinstance(self.task, Cut): self.game.snd['tree_down'].play() neighbors = self.game.map.find_neighbors( self.task.target, (self.game.map.can_stand, )) neighbors.append(self.task.target) for i, neighbor in enumerate(neighbors): if i < 3: Wood(self.game, neighbor) elif find_res == 1: # 在路上 pass elif find_res == 0: # 无法到达,游荡 self.task = None elif isinstance(self.task, Carry): if not self.task.item_to_find: # 去放木头 if vec2int(self.task.target + (0, 1)) not in self.game.map.groups['resource_mark']: self.task = None else: find_res = self.find(self.task.dest) if find_res == 2: wood = [ i for i in self.inventories if isinstance(i, Wood) ][0] self.inventories.remove(wood) wood.owner = None self.task = None elif find_res == 1: pass elif find_res == 0: self.task = None # if find_res != 1: self.state = Hangout() 用这个简练点? else: # 去捡木头 if self.task.item_to_find.owner is not None: self.task = None else: find_res = self.find(self.task.dest) if find_res == 2: self.task.item_to_find.owner = self self.inventories.append(self.task.item_to_find) self.task = None elif find_res == 1: pass elif find_res == 0: self.task = None elif isinstance(self.task, Build): if vec2int(self.task.target ) not in self.game.map.groups['build_mark']: self.task = None else: find_res = self.find(self.task.dest) if find_res == 2: # 到达目的地,开始敲 random.choice(self.game.snd['build']).play() tile_to_built = self.game.map.data[vec2int( self.task.target)] hp = tile_to_built.hit(+1) if tile_to_built.image_name == 'ladder' and hp >= 3: tile_to_built.kill() Ladder(self.game.map, tile_to_built.pos) self.game.consume_woods(1) elif tile_to_built.image_name == 'shelf' and hp >= 6: tile_to_built.kill() Shelf(self.game.map, tile_to_built.pos) self.game.consume_woods(3) elif tile_to_built.image_name == 'bed' and hp >= 6: tile_to_built.kill() Bed(self.game.map, tile_to_built.pos) self.game.consume_woods(4) elif tile_to_built.image_name == 'torch' and hp >= 1: tile_to_built.kill() Torch(self.game.map, tile_to_built.pos) elif find_res == 1: # 在路上 pass elif find_res == 0: # 无法到达,游荡 self.task = None elif self.task is None: self.hangout() # 掉落,用来临时解决脚下方块消失的问题 while not self.game.map.can_stand(self.pos): self.pos.y += 1 # repair image orient if self.pos.x != pos.x: if self.pos.x < pos.x: self.origin_image = self.standing_image_l elif self.pos.x > pos.x: self.origin_image = self.standing_image_r self.v = config.TILESIZE * self.pos - self.rect.topleft
def draw(self): # draw debug HUD pg.display.set_caption("{:.2f}".format(self.clock.get_fps())) # pg.display.set_caption("camera({}, {})".format(self.camera.offset.x, self.camera.offset.y)) # pg.display.set_caption( # "({},{},{})".format(self.cursor_pos.x, self.cursor_pos.y, # (type(self.map.data[vec2int(self.cursor_pos)])))) self.screen.blit(pg.transform.scale(self.img['sky_top'], (WIDTH, 100)), (0, 0)) self.screen.blit(self.img['sky'], (0, 100)) self.screen.blit(self.img['sky'], (512, 100)) self.screen.blit( pg.transform.scale(self.img['sky_bottom'], (WIDTH, 512)), (0, 612)) tiles = self.map.draw(self.camera) # pg.display.set_caption(str(tiles)) # self.all_sprites.draw(self.screen) for sprite in self.all_sprites: if isinstance(sprite, Wood) and sprite.owner: # 隐藏被捡起来的木头 continue self.screen.blit(sprite.image, self.camera.apply(sprite)) # draw target box and mouse cursor target = pg.Rect( self.cursor_pos.x * config.TILESIZE + self.camera.offset.x, self.cursor_pos.y * config.TILESIZE + self.camera.offset.y, config.TILESIZE, config.TILESIZE) pg.draw.rect(self.screen, WHITE, target, 2) self.draw_mode_icon(self.mode) # draw game speed if self.pause: self.draw_text('PAUSE', 32, RED, vec(WIDTH / 2, 16), align='mid') else: self.draw_text('SPEED:', 32, WHITE, vec(WIDTH / 2 - 130, 16), align='mid') for i in range(1, 5): if 1000 - (200 * i) == self.game_speed: self.draw_text('x' + str(i), 38, BROWN, vec(WIDTH / 2 - 100 + 56 * i, 16), align='mid') else: self.draw_text('x' + str(i), 32, WHITE, vec(WIDTH / 2 - 100 + 56 * i, 16), align='mid') # draw resource # count woods self.resource['woods'] = 0 for wood in self.woods: if vec2int(wood.pos + vec(0, 1)) in self.map.groups['resource_mark']: self.resource['woods'] += 1 count_woods = self.resource['woods'] for bm in self.map.groups['build_mark']: bm = self.map.data[bm] if bm.image_name == 'ladder': count_woods -= 1 elif bm.image_name == 'shelf': count_woods -= 3 elif bm.image_name == 'bed': count_woods -= 4 self.screen.blit(pg.transform.scale(self.img['wood'], (24, 24)), (16, HEIGHT - 30)) if count_woods >= 0: self.draw_text('x' + str(count_woods), 24, WHITE, (40, HEIGHT - 24)) else: self.draw_text('x' + str(count_woods), 24, RED, (40, HEIGHT - 24)) self.screen.blit(self.img['cursor'], self.last_mouse_pos - (15, 10)) pg.display.flip()
def next_turn(self): # ----- 遍历标记,为标记雇佣 imp ----- for mark in union_dicts(self.map.groups['dig&cut_mark'], self.map.groups['build_mark_noworker']): tile = self.map.data[mark] neighbors = self.map.find_neighbors(tile.pos, (self.map.can_stand, )) found = False for dest in neighbors: if not found: path = self.map.path_finding(dest) for imp in self.imps: if not found: if imp.task is None and vec2int(imp.pos) in path: if tile and (tile.in_group('diggable') or tile.in_group('destroyable')): imp.task = Dig(self.map, tile.pos, dest) found = True elif tile and tile.in_group('cuttable'): imp.task = Cut(self.map, tile.pos, dest) found = True elif isinstance(tile, BuildMark): if (tile.image_name == 'torch') or \ (tile.image_name == 'ladder' and self.resource['woods'] >= 1) or \ (tile.image_name == 'shelf' and self.resource['woods'] >= 3) or \ (tile.image_name == 'bed' and self.resource['woods'] >= 4): imp.task = Build( self.map, tile.pos, dest) tile.worker = imp tile.remove_from_group( 'build_mark_noworker') found = True # # ----- 更新小弟目的地 ----- # for imp in self.imps: # if isinstance(imp.task, Dig) or isinstance(imp.task, Cut): # imp.task.path = {} # neighbors = self.map.find_neighbors(imp.task.target, (self.map.can_stand,)) # found = False # for dest in neighbors: # if not found: # path = self.map.path_finding(dest) # if vec2int(imp.pos) in path: # imp.task.path = path # found = True for wood in self.woods: tile_below = self.map.data[vec2int(wood.pos + (0, 1))] if not wood.owner and tile_below and not tile_below.in_group( 'resource_mark'): path = self.map.path_finding(wood.pos) found = False for imp in self.imps: if not found: if imp.task is None and vec2int(imp.pos) in path and \ len([i for i in imp.inventories if isinstance(i, Wood)]) < 1: imp.task = Carry(self.map, wood.pos, wood.pos, item_to_find=wood) for mark in self.map.groups['resource_mark']: path = self.map.path_finding(vec(mark) + (0, -1)) for wood in self.woods: if wood.owner and vec2int(wood.owner.pos) in path: wood.owner.task = Carry(self.map, vec(mark) + (0, -1), vec(mark) + (0, -1), item_to_find=None) self.all_sprites.update() self.map.groups['visible'] = {} for imp in self.imps: self.map.light(imp.pos) self.map.light_torch()
def update(self): if not self.pause: now = pg.time.get_ticks() if now - self.last_update > self.game_speed: self.last_update = now self.next_turn() for sprite in self.all_sprites: sprite.float_pos += sprite.v / ( (self.game_speed - 14) / 1000) / config.FPS sprite.rect.topleft = sprite.float_pos mouse_pos = vec(pg.mouse.get_pos()) self.cursor_pos = vec( vec2int((mouse_pos - self.camera.offset) / config.TILESIZE)) tile = self.map.data[vec2int(self.cursor_pos)] # drag camera if self.dragging_camera: mouse_vector = mouse_pos - self.last_mouse_pos self.camera.update(mouse_vector) # game stuff if self.map.in_bounds(self.cursor_pos) and self.map.in_view( self.cursor_pos): if self.mode == 'dig&cut' and tile and ( tile.in_group('destroyable') or tile.in_group('diggable') or tile.in_group('cuttable')): if self.dragging == 1: if not tile.in_group('dig&cut_mark'): tile.add_to_group('dig&cut_mark') self.snd['mark'].play() elif self.dragging == -1: if tile.in_group('dig&cut_mark'): tile.remove_from_group('dig&cut_mark') elif self.mode == 'ladder': if self.dragging == 1: if tile is None or isinstance(tile, BgTile): # Ladder(self.map, self.cursor_pos) BuildMark(self.map, self.cursor_pos, 'ladder') elif self.dragging == -1: if isinstance(tile, BuildMark) and tile.image_name == 'ladder': tile.kill() elif self.mode == 'shelf': if self.dragging == 1: if tile is None or isinstance(tile, BgTile): BuildMark(self.map, self.cursor_pos, 'shelf') elif self.dragging == -1: if isinstance(tile, BuildMark) and tile.image_name == 'shelf': tile.kill() elif self.mode == 'bed': if self.dragging == 1: if tile is None or isinstance(tile, BgTile): BuildMark(self.map, self.cursor_pos, 'bed') elif self.dragging == -1: if isinstance(tile, BuildMark) and tile.image_name == 'bed': tile.kill() elif self.mode == 'resource' and tile and tile.in_group('earth'): if self.dragging == 1: if not tile.in_group('resource_mark') and \ self.map.can_stand(tile.pos + (0, -1)): tile.add_to_group('resource_mark') self.snd['mark'].play() elif self.dragging == -1: if tile.in_group('resource_mark'): tile.remove_from_group('resource_mark') self.snd['unmark'].play() self.last_mouse_pos = mouse_pos
def __init__(self): pg.mixer.pre_init(44100, -16, 1, 512) pg.init() pg.mixer.init() pg.display.set_caption(TITLE) pg.mouse.set_visible(False) self.screen = pg.display.set_mode((WIDTH, HEIGHT)) self.clock = pg.time.Clock() # game self.running = True self.playing = False self.game_speed = 0 self.last_update = 0 self.dt = 0 self.cursor_pos = vec() self.last_mouse_pos = vec() self.dragging_camera = False self.dragging_camera = False # Groups self.all_sprites = [] self.items = [] self.imps = [] self.woods = [] # Switcher self.map = None self.camera = None self.pause = False self.mode = None self.modes = [ None, 'dig&cut', 'resource', 'imp', 'ladder', 'torch', 'shelf', 'bed' ] self.dragging = 0 # 0: False, 1: add, -1:remove # ----- load data ----- self.dir = path.dirname(__file__) self.img_dir = path.join(self.dir, 'img') self.snd_dir = path.join(self.dir, 'snd') self.map_dir = path.join(self.dir, 'map') # load font self.font_name = path.join(self.dir, 'old_evils.ttf') # load images self.img = { 'sky': pg.image.load(path.join(self.img_dir, 'Other/skybox_sideHills.png')).convert(), 'sky_top': pg.image.load(path.join(self.img_dir, 'Other/skybox_top.png')).convert(), 'sky_bottom': pg.image.load(path.join(self.img_dir, 'Other/skybox_bottom.png')).convert(), 'dig_mark': pg.image.load(path.join(self.img_dir, 'dig_mark.png')).convert_alpha(), 'dig_mark_hammer': pg.image.load(path.join(self.img_dir, 'dig_mark_hammer.png')).convert_alpha(), 'imp': pg.image.load(path.join(self.img_dir, 'imp.png')).convert_alpha(), 'wood': pg.image.load(path.join(self.img_dir, 'wood.png')).convert_alpha(), 'cursor': pg.image.load(path.join(self.img_dir, 'cursor.png')).convert_alpha(), 'axe_iron': pg.image.load(path.join(self.img_dir, 'Items/axe_iron.png')).convert_alpha(), } self.img['wood'].set_colorkey(BLACK) # load musics and sounds self.snd = { 'mark': pg.mixer.Sound(path.join(self.snd_dir, 'mark1.ogg')), 'unmark': pg.mixer.Sound(path.join(self.snd_dir, 'unmark1.ogg')), 'digging': list(), 'cut_tree': pg.mixer.Sound(path.join(self.snd_dir, 'qubodupImpactWood.ogg')), # 'dig_stone': [pg.mixer.Sound(path.join(self.snd_dir, 'qubodupImpactStone.ogg')), # pg.mixer.Sound(path.join(self.snd_dir, 'qubodupImpactMetal.ogg'))], 'shift': pg.mixer.Sound(path.join(self.snd_dir, 'UI_Click_Organic_mono.ogg')), 'tree_down': pg.mixer.Sound(path.join(self.snd_dir, 'crack01.mp3.flac')), 'build': [ pg.mixer.Sound( path.join(self.snd_dir, 'qubodupImpactMeat01.ogg')), pg.mixer.Sound( path.join(self.snd_dir, 'qubodupImpactMeat02.ogg')) ] } for i in range(1, 9): self.snd['digging'].append( pg.mixer.Sound(path.join(self.snd_dir, 'tool{}.ogg'.format(i))))
def draw(self, camera): # 返回绘制的地图块数量 drawn = 0 # 计算屏幕笼罩区域 row_start = int(-camera.offset.y / config.TILESIZE) row_end = int((-camera.offset.y + HEIGHT) / config.TILESIZE) + 1 col_start = int(-camera.offset.x / config.TILESIZE) col_end = int((-camera.offset.x + WIDTH) / config.TILESIZE) + 1 for row in range(row_start, row_end): for col in range(col_start, col_end): pos = vec(col, row) scr_pos = pos * config.TILESIZE + camera.offset tile = self.data[vec2int(pos)] if vec2int( pos) in self.data else None # 防止渲染出界 if vec2int(pos) in self.groups['visited'] or True: if tile is not None: if hasattr(tile, 'bg_name'): image = self.resize(self.image[tile.bg_name]) if hasattr(tile, 'bg_grey') and tile.bg_grey: image = self.set_grey(image, 100) fg_image = self.image[tile.image_name].copy() if hasattr(tile, 'alpha'): fg_image.set_alpha(tile.alpha) image.blit(self.resize(fg_image), (0, 0)) else: image = self.resize(self.image[tile.image_name]) if hasattr(tile, 'alpha'): image.set_alpha(tile.alpha) if hasattr(tile, 'grey') and tile.grey: image = self.set_grey(image, 100) self.game.screen.blit(image, scr_pos) drawn += 1 # draw forbidden area if not self.in_bounds(pos): fbd_tile = self.resize(self.fbd_tile) self.game.screen.blit(fbd_tile, scr_pos) # draw resource area if tile and tile.in_group('resource_mark'): image = self.resize(self.image['resource_mark']) self.game.screen.blit(image, scr_pos) if vec2int(pos) not in self.groups['visible']: image = self.black_tile.copy() image.set_alpha(180) self.game.screen.blit(self.resize(image), scr_pos) else: image = self.black_tile.copy() self.game.screen.blit(self.resize(image), scr_pos) # draw mark if tile and tile.in_group('dig&cut_mark'): dirs = [ vec(x, y) for x in range(-1, 2) for y in range(-1, 2) ] dirs.remove(vec(0, 0)) found = 0 for neighbor in [tile.pos + dir for dir in dirs]: neighbor = self.data[vec2int(neighbor)] if neighbor and self.can_stand(neighbor.pos): found += 1 if found: self.game.screen.blit( self.resize(self.game.img['dig_mark_hammer']), scr_pos) else: self.game.screen.blit( self.resize(self.game.img['dig_mark']), scr_pos) return drawn
def __init__(self, game): self.game = game self.offset = vec(0, 0)
def light_torch(self): for torch_pos in self.groups['torch']: self.light(vec(torch_pos), self.groups['torch'][torch_pos].range)