V-MAGE-DEMO / game /flappybird_game.py
Fengx1n's picture
Initial DEMO
e53fda1
import sys, os
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/..")
import argparse
from typing import Dict
from game.pygame_base import PygameBase
import logging
import threading
import time
import pygame, random
from utils.config import Config
from utils.game_utils import capture
from utils.dict_utils import get_with_warning
from game.flappybird.settings import get_settings
game_path = './game/flappybird/'
# pygame.mixer.pre_init(frequency = 44100, size = 16, channels = 1, buffer = 512)
# pygame.init()
config = Config()
class FlappyBirdGame(PygameBase):
def __init__(
self,
output_dir,
):
super(FlappyBirdGame, self).__init__(output_dir, "Flappy Bird")
self.screen = pygame.display.set_mode((576,1024))
self.game_font = pygame.font.Font(os.path.join(game_path, '04B_19.ttf'), 40)
self.bg_surface = pygame.image.load(game_path + 'assets/background-day.png').convert()
self.bg_surface = pygame.transform.scale2x(self.bg_surface)
self.floor_surface = pygame.image.load(game_path + 'assets/base.png').convert()
self.floor_surface = pygame.transform.scale2x(self.floor_surface)
self.bird_downflap = pygame.transform.scale2x(pygame.image.load(game_path + 'assets/bluebird-downflap.png').convert_alpha())
self.bird_midflap = pygame.transform.scale2x(pygame.image.load(game_path + 'assets/bluebird-midflap.png').convert_alpha())
self.bird_upflap = pygame.transform.scale2x(pygame.image.load(game_path + 'assets/bluebird-upflap.png').convert_alpha())
self.bird_frames = [self.bird_downflap,self.bird_midflap,self.bird_upflap]
self.bird_index = 0
self.bird_surface = self.bird_frames[self.bird_index]
bird_center = (100,512)
self.bird_rect = self.bird_surface.get_rect(center = bird_center)
self.floor_x_pos = 0
self.pipe_surface = pygame.image.load(game_path + 'assets/pipe-green.png')
self.pipe_surface = pygame.transform.scale2x(self.pipe_surface)
self.pipe_list = []
self.bird_movement = 0
self.create_pipe_count = 100
self.bird_flip_count = 0
def draw_floor(self):
self.screen.blit(self.floor_surface,(self.floor_x_pos,900))
self.screen.blit(self.floor_surface,(self.floor_x_pos + 576,900))
def set_level_config(self, level_config: Dict):
self.current_level = self.level_config.get("level", 1)
self.settings = get_settings(self.current_level)
self.jump_height = get_with_warning(self.settings, "jump_height", 7)
self.gravity = get_with_warning(self.settings, "gravity", 0.25)
self.move_speed = get_with_warning(self.settings, "move_speed", 5)
self.pipe_gap = get_with_warning(self.settings, "pipe_gap", 500)
self.pipe_frequency = get_with_warning(self.settings, "pipe_frequency", 100)
self.rotate = get_with_warning(self.settings, "rotate", True)
self.valid_actions = get_with_warning(self.settings, "valid_actions", ["UP", "KEEP"])
self.sample_frames = get_with_warning(self.settings, "sample_frame", 3)
def create_pipe(self):
if not self.pipe_list:
random_pipe_pos = random.randint(self.pipe_gap + 50, 850)
else:
# 获取上一个管道的位置
last_pipe_pos = self.pipe_list[-2]['rect'].midtop[1]
# 确保新管道与上一个管道的差距不会太大
print("last_pipe_pos:", last_pipe_pos)
min_pipe_pos = max(self.pipe_gap + 50, last_pipe_pos - 300)
max_pipe_pos = min(850, last_pipe_pos + 300)
print("min_pipe_pos:", min_pipe_pos, ", max_pipe_pos:", max_pipe_pos)
random_pipe_pos = random.randint(min_pipe_pos, max_pipe_pos)
bottom_pipe = {'rect': self.pipe_surface.get_rect(midtop=(700, random_pipe_pos)), 'counted': False}
top_pipe = {'rect': self.pipe_surface.get_rect(midbottom=(700, random_pipe_pos - self.pipe_gap)), 'counted': False}
return bottom_pipe, top_pipe
def move_pipes(self, pipes):
for pipe in pipes:
pipe['rect'].centerx -= self.move_speed
return pipes
def draw_pipes(self, pipes):
for idx, pipe in enumerate(pipes):
if idx % 2 == 0:
self.screen.blit(self.pipe_surface, pipe['rect'])
else:
flip_pipe = pygame.transform.flip(self.pipe_surface, False, True)
self.screen.blit(flip_pipe, pipe['rect'])
def remove_pipes(self, pipes):
while pipes[0]['rect'].centerx <= -600:
pipes.pop(0)
pipes.pop(0)
return pipes
def check_collision(self, pipes):
for pipe in pipes:
if self.bird_rect.colliderect(pipe['rect']):
return False
if self.bird_rect.top <= -100 or self.bird_rect.bottom >= 900:
return False
return True
def rotate_bird(self, bird, movement):
# new_bird = pygame.transform.rotozoom(bird,-self.bird_movement * 3,1)
new_bird = pygame.transform.rotozoom(bird,-movement * 3,1)
return new_bird
def bird_animation(self):
new_bird = self.bird_frames[self.bird_index]
new_bird_rect = new_bird.get_rect(center = (100, self.bird_rect.centery))
return new_bird,new_bird_rect
def score_display(self, game_state):
if game_state == 'main_game':
score_surface = self.game_font.render(str(int(self.score)),True,(255,255,255))
score_rect = score_surface.get_rect(center = (288,100))
self.screen.blit(score_surface,score_rect)
def get_score(self):
return {
"score" : self.score, # win or lose
"frames" : len(self.game_frames),
"valid rate" : len(self.game_frames) / ( len(self.game_frames) + self.invalid_action_count ),
}
def step(self, action, dt=None):
self.screen.blit(self.bg_surface,(0,0))
if action == "UP":
self.bird_movement = -self.jump_height
elif action == "DOWN":
self.bird_movement = self.jump_height
elif action == "KEEP":
self.bird_movement = 0
self.create_pipe_count += 1
if self.create_pipe_count >= self.pipe_frequency:
self.create_pipe_count = 0
pipe_pair = self.create_pipe()
self.pipe_list.extend(pipe_pair)
self.bird_flip_count += 1
if self.bird_flip_count >= 6:
self.bird_flip_count = 0
if self.bird_index < 2:
self.bird_index += 1
else:
self.bird_index = 0
self.bird_surface, self.bird_rect = self.bird_animation()
# Bird
if self.rotate:
rotated_bird = self.rotate_bird(self.bird_surface, self.bird_movement)
else:
rotated_bird = self.rotate_bird(self.bird_surface, 0)
self.bird_rect.centery += self.bird_movement
self.screen.blit(rotated_bird, self.bird_rect)
game_active = self.check_collision(self.pipe_list)
if not game_active:
self.over = True
return True, "Game over!"
if self.gravity == 0:
self.bird_movement = 0
else:
self.bird_movement += self.gravity
# Pipes
self.pipe_list = self.move_pipes(self.pipe_list)
self.pipe_list = self.remove_pipes(self.pipe_list)
self.draw_pipes(self.pipe_list)
for pipe in self.pipe_list:
if pipe['rect'].centerx <= 100 and not pipe['counted']:
self.score += 0.5
pipe['counted'] = True
self.score_display('main_game')
# screen.blit(game_over_surface,game_over_rect)
# high_score = update_score(score,high_score)
# score_display('game_over')
# Floor
self.floor_x_pos -= 1
self.draw_floor()
if self.floor_x_pos <= -576:
self.floor_x_pos = 0
pygame.display.update()
return False, "Game continues."
def human_mode_action(self, event):
action = None
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP or event.key == pygame.K_SPACE:
action = "UP"
elif event.key == pygame.K_DOWN:
action = "DOWN"
elif event.key == pygame.K_LCTRL:
action = "KEEP"
elif event.key == pygame.K_LEFT:
action = "NONE"
return action
if __name__ == '__main__':
print(os.path.dirname(os.path.abspath(__file__)) + "/..")
parser = argparse.ArgumentParser()
# parser.add_argument("--levelConfig", type=str, default="./config/level_config/flappybirdgame/level1.json", help="The path to the level config file.")
parser.add_argument("--level", type=int, default=1, help="The level of the game.")
args = parser.parse_args()
level = args.level
levelConfig = f"./config/level_config/flappybirdgame/level{level}.json"
config.load_level_config(levelConfig)
flappybird_game = FlappyBirdGame("")
flappybird_game.run(None, human_mode=True)
# python game/flappybird_game.py --level 4