class PySnake(MyGame): "贪吃蛇游戏" def __init__(self): super(PySnake, self).__init__(GAME_NAME, SCREEN_SIZE, FPS, "resources/Minecraft.ttf", 16, "resources/pysnake.png") self.background.fill(BACKGROUND_COLOR) for i in range(CELL_SIZE, SCREEN_WIDTH, CELL_SIZE): pygame.draw.line(self.background, GRID_COLOR, (i, 0), (i, SCREEN_HEIGHT)) for i in range(CELL_SIZE, SCREEN_HEIGHT, CELL_SIZE): pygame.draw.line(self.background, GRID_COLOR, (0, i), (SCREEN_WIDTH, i)) self.field = Field(self, COLUMNS, ROWS) self.apple_counter = 0 self.apple = Apple(self) # self.snake = Snake(self) self.snake = Snake(self, SNAKE_DEFAULT_X, SNAKE_DEFAULT_Y, SNAKE_DEFAULT_LENGTH, RIGHT, SNAKE_DEFAULT_SPEED, SNAKE_COLOR_SKIN, SNAKE_COLOR_BODY, SNAKE_COLOR_HEAD) # 控制按键设定 self.key_bind(KEY_EXIT, self.quit) self.key_bind(KEY_UP, self.snake.turn, direction=UP) self.key_bind(KEY_DOWN, self.snake.turn, direction=DOWN) self.key_bind(KEY_LEFT, self.snake.turn, direction=LEFT) self.key_bind(KEY_RIGHT, self.snake.turn, direction=RIGHT) self.key_bind(pygame.K_EQUALS, self.snake.speed_up) self.key_bind(pygame.K_MINUS, self.snake.speed_down) self.key_bind(KEY_RESPAWN, self.restart) self.add_draw_action(self.show_score) def restart(self): if not self.snake.alive: self.apple_counter = 0 self.field.clear() # 移除尸体 self.apple.drop() self.snake.respawn() def show_score(self): text = "Apple {}".format(self.apple_counter) output = self.font.render(text, True, (255, 255, 33)) self.screen.blit(output, (0, 0)) if not self.snake.alive: text = " GAME OVER" output = self.font.render(text, True, (255, 33, 33), WHITE) self.screen.blit(output, (320 - 54, 240 - 10)) text = " press R to restart" output = self.font.render(text, True, GREY, DARK_GREY) self.screen.blit(output, (320 - 94, 260 - 10)) if not self.running and self.snake.alive: text = " GAME PAUSED" output = self.font.render(text, True, LIGTH_GREY, DARK_GREY) self.screen.blit(output, (320 - 54, 240 - 10))
class Saver(): def __init__(self, balls=int(random.random() * 100), trail=" "): self.field = Field(title="Term Saver") self.balls = [Ball(x=int(random.random() * self.field.x-1)+1, y=int(random.random() * self.field.y-1)+1) for x in range(balls)] self.speed = 0.009 self.trail = trail return def update(self): for ball in self.balls: hitWall = self.walled(ball) if hitWall: # wall collision ball.bounce(hitWall) # ball collision self.clearTrail(ball, self.trail, True) ball.move() self.field.write_at(item=ball.image, coords=ball.getPosition()) # clear the field randomly (.1% chance) if random.choice(range(1000)) == 1: self.field.clear() self.field.deploy() return def walled(self, ball): direction = [] if ball.x < 1: direction.append('right') elif ball.x >= self.field.x-1: direction.append('left') if ball.y < 1: direction.append('down') elif ball.y >= self.field.y-1: direction.append('up') if len(direction): return ' '.join(direction) return None def run(self): run = 1 while run: c = self.field.display.getch() if c == ord('q'): run = 0 self.update() time.sleep(self.speed) self.field.destroy() return def clearTrail(self, obj, remains=" ", centered=False): for i in range(len(obj.image)): self.field.write_at(item=remains, coords=[obj.x+i, obj.y], centered=centered) return
class DiamondShift: def __init__(self): pygame.init() pygame.mouse.set_visible(0) self.screen = pygame.display.set_mode((320, 240), 0, 32) self.gems = pygame.image.load("gems.png").convert_alpha() self.bg = pygame.image.load("bg.png").convert_alpha() self.gems = self.separate_gems(self.gems) self.gemsize = self.gems[0].get_width() self.grey = (75, 75, 75) self.cursor = pygame.Surface((self.gemsize, self.gemsize)).convert_alpha() self.cursor.fill(self.grey) self.font = pygame.font.Font(None, 24) self.score = 0 self.field = Field(8, 8, len(self.gems) - 1) self.ctrl = Control(Point(7, 7)) self.state = 'standby' # | swap | swap-back | fill | check | score self.swap = None self.winners = None def run(self): while self.loop(): self.read() self.step() # self.draw() def loop(self): return not self.ctrl.quit def read(self): update(self.ctrl) def step(self): delay = 16 if self.state == 'standby': if self.ctrl.direction: self.swap = deepcopy((self.ctrl.pos, self.ctrl.direction)) self.state = 'swap' elif self.state == 'swap': self.field.swaps(self.swap[0].x, self.swap[0].y, self.swap[1]) self.winners = self.field.find_winners() if self.winners: self.state = 'score' else: self.state = 'swap-back' delay = 150 elif self.state == 'swap-back': self.field.swaps(self.swap[0].x, self.swap[0].y, self.swap[1]) self.state = 'standby' delay = 150 elif self.state == 'fill': again = self.field.fall() again = self.field.pour() or again if not again: self.state = 'check' delay = 150 elif self.state == 'check': self.winners = self.field.find_winners() if self.winners: self.state = 'score' else: self.state = 'standby' delay = 150 elif self.state == 'score': def score(n): return (n - 1)**2 self.score += score(len(self.winners)) self.field.clear(self.winners) self.state = 'fill' delay = 150 self.draw() pygame.time.delay(delay) def draw(self): xoffset = 11 yoffset = 24 size = self.gems[0].get_width() self.screen.blit(self.bg,(0,0)) self.screen.blit(self.cursor, (xoffset + self.gemsize * self.ctrl.pos.x, yoffset + self.gemsize * self.ctrl.pos.y)) for x in xrange(self.field.width): for y in xrange(self.field.height): self.screen.blit(self.gems[self.field.map.get((x, y), 0)],(xoffset + x * size, yoffset + y * size)) self.screen.blit(self.font.render("%d" % self.score, 1, (255, 255, 255)), (15, 3)) pygame.display.flip() def separate_gems(self, gems): ng = [] size = self.gems.get_height() count = self.gems.get_width()/gems.get_height() for c in xrange(count): s = pygame.Surface((size,size),pygame.SRCALPHA, 32).convert_alpha() s.blit(self.gems, (0, 0), pygame.Rect(c * size, 0, (c + 1) * size, size)) ng.append(s) return ng
class MaskSaver(Saver): def __init__(self, balls=int(random.random() * 100), trail=" ", mask=None): self.field = Field(title="Term Saver") self.balls = [Ball(x=int(random.random() * self.field.x-1)+1, y=int(random.random() * self.field.y-1)+1) for x in range(balls)] self.speed = 0.009 self.trail = trail self.addMask(mask) def addMask(self, mask): """ Given a 2D array depciting some image to mask out e.g. a box or a name or a picture of peeve shrink or fatten it up to fit the shape of our field/grid dimensions must be at least.... 4 x 4 ? e.g. . . . . . x x . . x x . . . . . The players on the field should never write to the 'x'd out areas. but our grid will probably be larger than this... so what is the maths behind making this fit properly? e.g. a 4 x 4 mask supplied for a 64 x 64 grid let's start small and just double it . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x x x x x x . . . . . . . . . . . . . . . . . . x x x x x x . . . x x x x . . . . . . . . . . . x x x x x x . . . x x x x . . . . . . . . . . => . x x x x x x . or . . x x x x . . . . . . . . . . . x x x x x x . . . x x x x . . . . . . . . . . . x x x x x x . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . bad good I think the result where we look at the proportionality works best. The first transformation has a single border like the original, and the second maintains the proportions (e.g. 50%). What happens when it's more awkward? . . . . . . . . . . . . . . . . . . . . . . . . => . x x x x . or . . x x . . . . . . . . . . . . . . . . . . . . bad good I still like the second transformation. So I guess when taking 1/2 of an odd, round down? """ pass def update(self): for ball in self.balls: hitWall = self.walled(ball) if hitWall: # wall collision ball.bounce(hitWall) # ball collision self.clearTrail(ball, self.trail, True) ball.move() self.field.write_at(item=ball.image, coords=ball.getPosition()) # clear the field randomly (.1% chance) if random.choice(range(1000)) == 1: self.field.clear() self.field.deploy()
class Game: def __init__(self): self.field = Field() self.walls = [] self.pongs = [] self.balls = [] self.fps = 15 self.__create_walls() self.__create_pong() self.__create_ball() self.snake = Snake(40, 15) self.__game_loop() def __game_loop(self): threading.Thread(target=self.__render, daemon=True).start() self.__update() def __update(self): while True: # update game logic every x seconds # TODO game_over = False # TODO process_keyboard_input() # TODO check collision_ball() # TODO check_collision_snake() # TODO check_collision_pong() self.__update_ball() self.__update_pong() self.snake.update() time.sleep(.150) def __render(self): stdscr = curses.initscr() curses.start_color() curses.use_default_colors() try: for i in range(0, curses.COLORS): curses.init_pair(i, i, -1) except Exception: pass while True: stdscr.scrollok(True) stdscr.clear() self.field.clear() for wall in self.walls: wall.render(self.field) for pong in self.pongs: pong.render(self.field) for ball in self.balls: ball.render(self.field) self.snake.render(self.field) self.field.render(stdscr) stdscr.refresh() time.sleep(1 / self.fps) def __create_walls(self): for y in range(self.field.get_height()): for x in range(self.field.get_width()): if (x == 0 or x == 1 or y == 0 or x > self.field.get_width() - 3 or y > self.field.get_height() - 2): self.walls.append(Wall(x, y)) def __create_pong(self): for y in range(self.field.get_height()): for x in range(self.field.get_width()): if ((x == 4 or x == 5) and (y >= 13 and y <= 17)): self.pongs.append(Pong(x, y)) def __create_ball(self): for y in range(self.field.get_height()): for x in range(self.field.get_width()): if ((x == 30) and (y == 15)): self.balls.append(Ball(x, y)) def __update_pong(self): up = self.pongs[2].get_y() >= self.balls[0].get_y() for pong in self.pongs: if up: pong.move_up() else: pong.move_down() def __update_ball(self): self.balls[0].move_left()
class DiamondShift: def __init__(self): pygame.init() pygame.mouse.set_visible(0) self.screen = pygame.display.set_mode((320, 240), 0, 32) self.gems = pygame.image.load("gems.png").convert_alpha() self.bg = pygame.image.load("bg.png").convert_alpha() self.gems = self.separate_gems(self.gems) self.gemsize = self.gems[0].get_width() self.grey = (75, 75, 75) self.cursor = pygame.Surface( (self.gemsize, self.gemsize)).convert_alpha() self.cursor.fill(self.grey) self.font = pygame.font.Font(None, 24) self.score = 0 self.field = Field(8, 8, len(self.gems) - 1) self.ctrl = Control(Point(7, 7)) self.state = 'fill' # | swap | swap-back | fill | check | score self.swap = None self.winners = None def run(self): while self.loop(): self.read() self.step() # self.draw() def loop(self): return not self.ctrl.quit def read(self): update(self.ctrl) def step(self): delay = 16 if self.state == 'standby': if self.ctrl.direction: self.swap = deepcopy((self.ctrl.pos, self.ctrl.direction)) self.state = 'swap' elif self.state == 'swap': self.field.swaps(self.swap[0].x, self.swap[0].y, self.swap[1]) self.winners = self.field.find_winners() if self.winners: self.state = 'score' else: self.state = 'swap-back' delay = 150 elif self.state == 'swap-back': self.field.swaps(self.swap[0].x, self.swap[0].y, self.swap[1]) self.state = 'standby' delay = 150 elif self.state == 'fill': again = self.field.fall() again = self.field.pour() or again if not again: self.state = 'check' delay = 150 elif self.state == 'check': self.winners = self.field.find_winners() if self.winners: self.state = 'score' else: self.state = 'standby' delay = 150 elif self.state == 'score': def score(n): return (n - 1)**2 self.score += score(len(self.winners)) self.field.clear(self.winners) self.state = 'fill' delay = 150 self.draw() pygame.time.delay(delay) def draw(self): xoffset = 11 yoffset = 24 size = self.gems[0].get_width() self.screen.blit(self.bg, (0, 0)) self.screen.blit(self.cursor, (xoffset + self.gemsize * self.ctrl.pos.x, yoffset + self.gemsize * self.ctrl.pos.y)) for x in xrange(self.field.width): for y in xrange(self.field.height): self.screen.blit(self.gems[self.field.map.get((x, y), 0)], (xoffset + x * size, yoffset + y * size)) self.screen.blit( self.font.render("%d" % self.score, 1, (255, 255, 255)), (15, 3)) pygame.display.flip() def separate_gems(self, gems): ng = [] size = self.gems.get_height() count = self.gems.get_width() / gems.get_height() for c in xrange(count): s = pygame.Surface((size, size), pygame.SRCALPHA, 32).convert_alpha() s.blit(self.gems, (0, 0), pygame.Rect(c * size, 0, (c + 1) * size, size)) ng.append(s) return ng
class Program: """The main class for playing a program""" def __init__(self, resolution=(1366, 768), fullscreen=True): fullscreen = pygame.FULLSCREEN if fullscreen else 0 self.resolution = resolution try: self.window = pygame.display.set_mode(resolution, fullscreen) except Exception as e: Tk().withdraw() messagebox.showerror('Ошибка!', e) raise e pygame.display.set_caption('Life by BUS410') self.cols = (resolution[0] - UI_WIDTH) // 10 self.rows = resolution[1] // 10 self.field = Field(resolution[0] - UI_WIDTH, resolution[1], self.cols, self.rows, count_put_food=32) self.field.update() self.update_iterator = UPDATE_FREQUENCY self.update_frequency = UPDATE_FREQUENCY self.clock = pygame.time.Clock() self.start = False self.next_update = True self.widgets = [ Widget(x=0, y=0, width=UI_WIDTH, height=WIDGET_HEIGHT, text='Старт/Стоп', background_color=BUTTON_COLOR, onclick=self.start_stop, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED), Widget(x=0, y=WIDGET_HEIGHT, width=UI_WIDTH, height=WIDGET_HEIGHT, text='Очистить', onclick=self.clear, background_color=BUTTON_COLOR, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED), Widget(x=0, y=WIDGET_HEIGHT * 2, width=UI_WIDTH, height=WIDGET_HEIGHT, text='Размер таблицы'), Widget(x=0, y=WIDGET_HEIGHT * 3, width=UI_WIDTH // 2, height=WIDGET_HEIGHT, text='-', onclick=lambda: self.change_field('-'), background_color=BUTTON_COLOR, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED), Widget(x=UI_WIDTH // 2, y=WIDGET_HEIGHT * 3, width=UI_WIDTH // 2, height=WIDGET_HEIGHT, text='+', onclick=lambda: self.change_field('+'), background_color=BUTTON_COLOR, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED), Widget(x=0, y=WIDGET_HEIGHT * 4, width=UI_WIDTH // 2, height=WIDGET_HEIGHT, text='-10', onclick=lambda: self.change_field('-', 10), background_color=BUTTON_COLOR, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED), Widget(x=UI_WIDTH // 2, y=WIDGET_HEIGHT * 4, width=UI_WIDTH // 2, height=WIDGET_HEIGHT, text='+10', onclick=lambda: self.change_field('+', 10), background_color=BUTTON_COLOR, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED), Widget(x=0, y=WIDGET_HEIGHT * 5, width=UI_WIDTH, height=WIDGET_HEIGHT, text='Частота обновл.'), Widget(x=0, y=WIDGET_HEIGHT * 6, width=UI_WIDTH // 2, height=WIDGET_HEIGHT, text='-', onclick=lambda: self.change_update_frequency('+'), background_color=BUTTON_COLOR, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED), Widget(x=UI_WIDTH // 2, y=WIDGET_HEIGHT * 6, width=UI_WIDTH // 2, height=WIDGET_HEIGHT, text='+', onclick=lambda: self.change_update_frequency('-'), background_color=BUTTON_COLOR, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED), Widget(x=0, y=WIDGET_HEIGHT * 7, width=UI_WIDTH, height=WIDGET_HEIGHT, text='Еды за раз'), Widget(x=0, y=WIDGET_HEIGHT * 8, width=UI_WIDTH // 2, height=WIDGET_HEIGHT, text='-', onclick=lambda: self.change_food_count('-'), background_color=BUTTON_COLOR, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED), Widget(x=UI_WIDTH // 2, y=WIDGET_HEIGHT * 8, width=UI_WIDTH // 2, height=WIDGET_HEIGHT, text='+', onclick=lambda: self.change_food_count('+'), background_color=BUTTON_COLOR, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED), Widget(x=0, y=WIDGET_HEIGHT * 9, width=UI_WIDTH, height=WIDGET_HEIGHT, text='Пищи: 1'), Widget(x=0, y=WIDGET_HEIGHT * 10, width=UI_WIDTH, height=WIDGET_HEIGHT, text='Организмов: 0'), Widget(x=0, y=WIDGET_HEIGHT * 11, width=UI_WIDTH, height=WIDGET_HEIGHT, text='Хищников: 0'), Widget(x=0, y=WIDGET_HEIGHT * 12, width=UI_WIDTH, height=WIDGET_HEIGHT, text='Поле: 36x64'), Widget(x=0, y=resolution[1] - WIDGET_HEIGHT, width=UI_WIDTH, height=WIDGET_HEIGHT, text='Выход', background_color=BUTTON_COLOR, background_color_cover=BUTTON_COVER, background_color_click=BUTTON_CLICKED, onclick=self.quit) ] def start_stop(self): if self.start: self.start = False else: self.start = True def quit(self): self.next_update = False def clear(self): self.field.clear() self.field.update() self.update_info() def change_food_count(self, action): if action == '+': self.field.count_put_food += 10 elif action == '-': if self.field.count_put_food > 0: self.field.count_put_food -= 10 def change_update_frequency(self, action): if action == '+': self.update_frequency += 1 if self.update_frequency >= FPS: self.update_frequency = FPS elif action == '-': self.update_frequency -= 1 if self.update_frequency <= 1: self.update_frequency = 1 def change_field(self, action, n=1): if action == '+': self.rows += n self.cols += n elif action == '-': if self.rows > MIN_ROWS_COLS + n - 1: self.rows -= n if self.cols > MIN_ROWS_COLS + n - 1: self.cols -= n self.field = Field(self.resolution[0] - UI_WIDTH, self.resolution[1], self.cols, self.rows, count_put_food=self.field.count_put_food) self.field.update() def update_info(self): self.widgets[-2].text = f'Поле: {self.rows}x{self.cols}' self.widgets[-3].text = f'Хищников: {self.field.predators}' self.widgets[-4].text = f'Организмов: {self.field.organisms}' self.widgets[-5].text = f'Пищи: {self.field.foods}' def main(self): while True: if not self.update(): break self.clock.tick(FPS) pygame.quit() def update(self): self.next_update = True events = pygame.event.get() for e in events: if e.type == pygame.QUIT: self.next_update = False elif e.type == pygame.KEYUP and e.key == pygame.K_ESCAPE: self.next_update = False elif e.type == pygame.MOUSEBUTTONUP: if e.button == 1: pos = pygame.mouse.get_pos() if pos[0] > UI_WIDTH: pos = (pos[0] - UI_WIDTH, pos[1]) self.field.put_live(1, pos) self.field.update() self.update_info() for widget in self.widgets: widget.update(events) if self.start and not self.update_iterator: self.update_iterator = self.update_frequency self.field.update() self.update_info() if self.update_iterator: self.update_iterator -= 1 self.draw() return self.next_update def draw(self): self.window.fill(WINDOW_BACKGROUND) for widget in self.widgets: widget.show(self.window) self.field.draw(self.window, (UI_WIDTH, 0)) pygame.display.update()