From 1b38b21cbb6f9714f0de651ba232c845bd2afe3b Mon Sep 17 00:00:00 2001 From: Kylin_on_Mac Date: Sat, 23 Sep 2023 17:02:21 +0800 Subject: [PATCH 01/10] fix: revise blockly.json --- blockly.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockly.json b/blockly.json index 922740c..291f20c 100644 --- a/blockly.json +++ b/blockly.json @@ -11,7 +11,7 @@ ["scene_info['status']", "game status", "遊戲狀態"], ["scene_info['ball_x']", "x coordinate of ball", "球的 x 座標"], ["scene_info['ball_y']", "y coordinate of ball", "球的 y 座標"], - ["scene_info['score']", "x coordinate of platform", "平台的 x 座標"], + ["scene_info['score']", "score", "目前的分數"], ["scene_info['foods']", "list of foods positions", "點點的位置清單"], ["scene_info", "dictionary of all information", "包含所有資訊的字典"] ], From af3fd41f008cbd7b1a535f7e65ef7bb939cf3bc3 Mon Sep 17 00:00:00 2001 From: Kylin_on_Mac Date: Sat, 23 Sep 2023 17:17:55 +0800 Subject: [PATCH 02/10] doc: add key "green_food_list","black_food_list" in template.json --- levels/template.json | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/levels/template.json b/levels/template.json index 3d76644..487a087 100644 --- a/levels/template.json +++ b/levels/template.json @@ -1,7 +1,13 @@ { - "time_to_play": 1200, + "time_to_play": 300, "playground_size": [ - 500, + 100, 200 - ] + ], + "score_to_pass": 10, + "green_food_count": 3, + "black_food_count": 0, + "green_food_list": [3,2,1], + "black_food_list": [5,2,0] + } \ No newline at end of file From 42adfd907a8ac0d73f65722561dffd20e3b48d0e Mon Sep 17 00:00:00 2001 From: Kylin_on_Mac Date: Tue, 10 Oct 2023 22:20:22 +0800 Subject: [PATCH 03/10] feat:remove some game arguments --- game_config.json | 67 ++---------------------------------------------- src/env.py | 1 + src/game.py | 34 +++++++++--------------- 3 files changed, 15 insertions(+), 87 deletions(-) diff --git a/game_config.json b/game_config.json index 3bcc2d2..91c9875 100644 --- a/game_config.json +++ b/game_config.json @@ -12,76 +12,13 @@ "max": 1 }, "game_params": [ - { - "name": "time_to_play", - "verbose": "遊戲總幀數", - "type": "int", - "max": 2000, - "min": 600, - "default": 600, - "help": "set the limit of frame count , actually time will be revised according to your FPS ." - }, - { - "name": "green_food_count", - "verbose": "綠色食物數量", - "type": "int", - "choices": [ - 5, - 10, - 15, - 20, - 25, - 30, - 35, - 40, - 45, - 50 - ], - "help": "set the total number of points", - "default": 10 - }, - { - "name": "red_food_count", - "verbose": "紅色食物數量", - "type": "int", - "choices": [ - 5, - 10, - 15, - 20, - 25, - 30, - 35, - 40, - 45, - 50 - ], - "help": "set the total number of points", - "default": 10 - }, - { - "name": "score_to_pass", - "verbose": "通關分數", - "type": "int", - "min": 1, - "max": 30, - "default": 10, - "help": "set the score to win this game " - }, - { - "name": "playground_size", - "verbose": "場地尺寸", - "type": "list", - "default": "400,400", - "help": "set the size of playground " - }, { "name": "level", "verbose": "內建關卡編號", "type": "int", "min": -1, - "max": 5, - "default": "-1", + "max": 100, + "default": -1, "help": "選定內建關卡,請注意,使用此設定將會覆蓋掉其他關卡設定,預設為 -1 不選擇任何關卡。" }, { "name": "level_file", diff --git a/src/env.py b/src/env.py index 82de125..43d280c 100644 --- a/src/env.py +++ b/src/env.py @@ -17,6 +17,7 @@ BALL_W = 30 # food class FoodTypeEnum(StringEnum): + # TODO add good_lv1~good_lv3 GREEN = auto() RED = auto() FOOD_COLOR_MAP = {FoodTypeEnum.GREEN: "#009688", diff --git a/src/game.py b/src/game.py index 3b916df..119b726 100644 --- a/src/game.py +++ b/src/game.py @@ -20,19 +20,18 @@ class EasyGame(PaiaGame): """ def __init__( - self, time_to_play, score_to_pass, green_food_count, red_food_count, - playground_size: list, + self, level: int = -1, level_file: str = None, sound: str = "off", *args, **kwargs): super().__init__(user_num=1) - + # TODO reduce game config and use level file self.game_result_state = GameResultState.FAIL self.scene = Scene(width=WIDTH, height=HEIGHT, color=BG_COLOR, bias_x=0, bias_y=0) self._level = level self._level_file = level_file - if self._level_file is not None or level == "": + if path.isfile(self._level_file) or self._level_file == "": # set by injected file self.set_game_params_by_file(self._level_file) pass @@ -41,25 +40,13 @@ class EasyGame(PaiaGame): self.set_game_params_by_level(self._level) pass else: - # set by game params - self._playground_w = int(playground_size[0]) - self._playground_h = int(playground_size[1]) - self.playground = pygame.Rect( - 0, 0, - self._playground_w, - self._playground_h - ) - self._green_food_count = green_food_count - self._red_food_count = red_food_count - self._score_to_pass = score_to_pass - self._frame_limit = time_to_play - self.playground.center = (WIDTH / 2, HEIGHT / 2) + self.set_game_params_by_level(1) self.foods = pygame.sprite.Group() self.sound_controller = SoundController(sound) - self.init_game() + self._init_game() - def set_game_params_by_level(self, level): + def set_game_params_by_level(self, level:int): level_file_path = os.path.join(LEVEL_PATH, f"{level:03d}.json") self.set_game_params_by_file(level_file_path) @@ -92,7 +79,7 @@ class EasyGame(PaiaGame): self._frame_limit = int(game_params["time_to_play"]) self.playground.center = (WIDTH / 2, HEIGHT / 2) - def init_game(self): + def _init_game(self): self.ball = Ball() self.foods.empty() self.score = 0 @@ -120,6 +107,7 @@ class EasyGame(PaiaGame): if hits: for food in hits: + # TODO add food score to function if food.type == FoodTypeEnum.GREEN: self.sound_controller.play_eating_good() self.score += 1 @@ -146,7 +134,9 @@ class EasyGame(PaiaGame): to_players_data = {} foods_data = [] for food in self.foods: - foods_data.append({"x": food.rect.x, "y": food.rect.y}) + # TODO add good food and bad food + + foods_data.append({"x": food.rect.x, "y": food.rect.y,"type":food.type}) data_to_1p = { "frame": self.frame_count, "ball_x": self.ball.rect.centerx, @@ -183,7 +173,7 @@ class EasyGame(PaiaGame): self._level += 1 self.set_game_params_by_level(self._level) - self.init_game() + self._init_game() pass From 87335c3b345ca92130b3d123194d19002b42327a Mon Sep 17 00:00:00 2001 From: Kylin_on_Mac Date: Tue, 10 Oct 2023 22:36:46 +0800 Subject: [PATCH 04/10] refac: add collision method --- src/foods.py | 30 ++++++++++++++++++++++++++++++ src/game.py | 34 +++++++++++++++++++--------------- src/game_object.py | 26 ++------------------------ 3 files changed, 51 insertions(+), 39 deletions(-) create mode 100644 src/foods.py diff --git a/src/foods.py b/src/foods.py new file mode 100644 index 0000000..4455668 --- /dev/null +++ b/src/foods.py @@ -0,0 +1,30 @@ +import pygame.sprite + +from games.easy_game.src.env import FoodTypeEnum, FOOD_COLOR_MAP +from mlgame.view.view_model import create_rect_view_data + + +class Food(pygame.sprite.Sprite): + def __init__(self, group, type: FoodTypeEnum): + pygame.sprite.Sprite.__init__(self, group) + self.image = pygame.Surface([8, 8]) + self.type = type + self.score = 0 + self.color = FOOD_COLOR_MAP[type] + + self.rect = self.image.get_rect() + self.angle = 0 + + def update(self) -> None: + pass + + @property + def game_object_data(self): + return create_rect_view_data( + "food", + self.rect.x, + self.rect.y, + self.rect.width, + self.rect.height, + self.color + ) diff --git a/src/game.py b/src/game.py index 119b726..926742e 100644 --- a/src/game.py +++ b/src/game.py @@ -10,7 +10,8 @@ from mlgame.view.decorator import check_game_progress, check_game_result from mlgame.view.view_model import * from .env import * from .env import FoodTypeEnum -from .game_object import Ball, Food +from .game_object import Ball +from .foods import Food from .sound_controller import SoundController @@ -103,20 +104,8 @@ class EasyGame(PaiaGame): self.foods.update() # handle collision - hits = pygame.sprite.spritecollide(self.ball, self.foods, True) - if hits: - for food in hits: - # TODO add food score to function - if food.type == FoodTypeEnum.GREEN: - self.sound_controller.play_eating_good() - self.score += 1 - self._create_foods(1, FoodTypeEnum.GREEN) - - elif food.type == FoodTypeEnum.RED: - self.sound_controller.play_eating_bad() - self._create_foods(1, FoodTypeEnum.RED) - self.score -= 1 + self._check_foods_collision() # self._timer = round(time.time() - self._begin_time, 3) self.frame_count += 1 @@ -126,6 +115,21 @@ class EasyGame(PaiaGame): if not self.is_running: return "RESET" + def _check_foods_collision(self): + hits = pygame.sprite.spritecollide(self.ball, self.foods, True) + if hits: + for food in hits: + self.score+= food.score + # TODO add food score to function + if food.type == FoodTypeEnum.GREEN: + self.sound_controller.play_eating_good() + self._create_foods(1, FoodTypeEnum.GREEN) + + elif food.type == FoodTypeEnum.RED: + self.sound_controller.play_eating_bad() + self._create_foods(1, FoodTypeEnum.RED) + + def get_data_from_game_to_player(self): """ send something to game AI @@ -136,7 +140,7 @@ class EasyGame(PaiaGame): for food in self.foods: # TODO add good food and bad food - foods_data.append({"x": food.rect.x, "y": food.rect.y,"type":food.type}) + foods_data.append({"x": food.rect.x, "y": food.rect.y,"type":food.type,"score":food.score}) data_to_1p = { "frame": self.frame_count, "ball_x": self.ball.rect.centerx, diff --git a/src/game_object.py b/src/game_object.py index e7c316a..bf0e9c9 100644 --- a/src/game_object.py +++ b/src/game_object.py @@ -1,6 +1,7 @@ import pygame.sprite -from games.easy_game.src.env import FoodTypeEnum, FOOD_COLOR_MAP, BALL_COLOR, BALL_VEL, BALL_H, BALL_W +from games.easy_game.src.env import BALL_COLOR, BALL_VEL, BALL_H, BALL_W +from games.easy_game.src.foods import Food from mlgame.view.view_model import create_rect_view_data @@ -44,26 +45,3 @@ class Ball(pygame.sprite.Sprite): ) -class Food(pygame.sprite.Sprite): - def __init__(self, group, type: FoodTypeEnum): - pygame.sprite.Sprite.__init__(self, group) - self.image = pygame.Surface([8, 8]) - self.type = type - self.color = FOOD_COLOR_MAP[type] - - self.rect = self.image.get_rect() - self.angle = 0 - - def update(self) -> None: - pass - - @property - def game_object_data(self): - return create_rect_view_data( - "food", - self.rect.x, - self.rect.y, - self.rect.width, - self.rect.height, - self.color - ) From ba349a610485d39dcecb8ce8266ec3a8b16e40c9 Mon Sep 17 00:00:00 2001 From: Kylin_on_Mac Date: Tue, 10 Oct 2023 22:52:05 +0800 Subject: [PATCH 05/10] refac: add good food class and bad food class --- src/env.py | 20 +++++++++++++++----- src/foods.py | 28 +++++++++++++++++++++++++--- src/game.py | 30 ++++++++++++------------------ 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/env.py b/src/env.py index 43d280c..484a2e9 100644 --- a/src/env.py +++ b/src/env.py @@ -17,11 +17,21 @@ BALL_W = 30 # food class FoodTypeEnum(StringEnum): - # TODO add good_lv1~good_lv3 - GREEN = auto() - RED = auto() -FOOD_COLOR_MAP = {FoodTypeEnum.GREEN: "#009688", - FoodTypeEnum.RED: "#FF1744"} + GOOD_1 = auto() + GOOD_2 = auto() + GOOD_3 = auto() + BAD_1 = auto() + BAD_2 = auto() + BAD_3 = auto() + +FOOD_COLOR_MAP = { + FoodTypeEnum.GOOD_1: "#009688", + FoodTypeEnum.GOOD_2: "#009688", + FoodTypeEnum.GOOD_3: "#009688", + FoodTypeEnum.BAD_1: "#FF1744", + FoodTypeEnum.BAD_2: "#FF1744", + FoodTypeEnum.BAD_3: "#FF1744" +} # path of assets ASSET_PATH = path.join(path.dirname(__file__), "..", "asset") diff --git a/src/foods.py b/src/foods.py index 4455668..368692b 100644 --- a/src/foods.py +++ b/src/foods.py @@ -5,12 +5,12 @@ from mlgame.view.view_model import create_rect_view_data class Food(pygame.sprite.Sprite): - def __init__(self, group, type: FoodTypeEnum): + def __init__(self, group): pygame.sprite.Sprite.__init__(self, group) self.image = pygame.Surface([8, 8]) - self.type = type + self.type = None self.score = 0 - self.color = FOOD_COLOR_MAP[type] + self.color = None self.rect = self.image.get_rect() self.angle = 0 @@ -28,3 +28,25 @@ class Food(pygame.sprite.Sprite): self.rect.height, self.color ) + + +class GoodFoodLv1(Food): + def __init__(self, group): + super().__init__(group) + self.image = pygame.Surface([8, 8]) + self.type = FoodTypeEnum.GOOD_1 + self.color = FOOD_COLOR_MAP[self.type] + self.score = 1 + self.rect = self.image.get_rect() + self.angle = 0 + + +class BadFoodLv1(Food): + def __init__(self, group): + super().__init__(group) + self.image = pygame.Surface([8, 8]) + self.type = FoodTypeEnum.BAD_1 + self.color = FOOD_COLOR_MAP[self.type] + self.score = -1 + self.rect = self.image.get_rect() + self.angle = 0 diff --git a/src/game.py b/src/game.py index 926742e..822d126 100644 --- a/src/game.py +++ b/src/game.py @@ -9,9 +9,8 @@ from mlgame.utils.enum import get_ai_name from mlgame.view.decorator import check_game_progress, check_game_result from mlgame.view.view_model import * from .env import * -from .env import FoodTypeEnum +from .foods import GoodFoodLv1, BadFoodLv1 from .game_object import Ball -from .foods import Food from .sound_controller import SoundController @@ -47,7 +46,7 @@ class EasyGame(PaiaGame): self.sound_controller = SoundController(sound) self._init_game() - def set_game_params_by_level(self, level:int): + def set_game_params_by_level(self, level: int): level_file_path = os.path.join(LEVEL_PATH, f"{level:03d}.json") self.set_game_params_by_file(level_file_path) @@ -63,7 +62,7 @@ class EasyGame(PaiaGame): with open(os.path.join(LEVEL_PATH, "001.json")) as f: game_params = json.load(f) self._level = 1 - self._level_file=None + self._level_file = None self._set_game_params(game_params) def _set_game_params(self, game_params): @@ -84,8 +83,8 @@ class EasyGame(PaiaGame): self.ball = Ball() self.foods.empty() self.score = 0 - self._create_foods(self._green_food_count, FoodTypeEnum.GREEN) - self._create_foods(self._red_food_count, FoodTypeEnum.RED) + self._create_foods(GoodFoodLv1, self._green_food_count) + self._create_foods(BadFoodLv1, self._red_food_count) self.frame_count = 0 self._frame_count_down = self._frame_limit self.sound_controller.play_music() @@ -119,16 +118,13 @@ class EasyGame(PaiaGame): hits = pygame.sprite.spritecollide(self.ball, self.foods, True) if hits: for food in hits: - self.score+= food.score + self.score += food.score + self._create_foods(food.__class__, 1) # TODO add food score to function - if food.type == FoodTypeEnum.GREEN: + if isinstance(food, (GoodFoodLv1,)): self.sound_controller.play_eating_good() - self._create_foods(1, FoodTypeEnum.GREEN) - - elif food.type == FoodTypeEnum.RED: + elif isinstance(food, (BadFoodLv1,)): self.sound_controller.play_eating_bad() - self._create_foods(1, FoodTypeEnum.RED) - def get_data_from_game_to_player(self): """ @@ -140,7 +136,7 @@ class EasyGame(PaiaGame): for food in self.foods: # TODO add good food and bad food - foods_data.append({"x": food.rect.x, "y": food.rect.y,"type":food.type,"score":food.score}) + foods_data.append({"x": food.rect.x, "y": food.rect.y, "type": food.type, "score": food.score}) data_to_1p = { "frame": self.frame_count, "ball_x": self.ball.rect.centerx, @@ -193,7 +189,6 @@ class EasyGame(PaiaGame): """ Get the initial scene and object information for drawing on the web """ - # TODO add music or sound # bg_path = path.join(ASSET_PATH, "img/background.jpg") # background = create_asset_init_data( # "background", WIDTH, HEIGHT, bg_path, @@ -274,11 +269,10 @@ class EasyGame(PaiaGame): cmd_1p.append("NONE") return {get_ai_name(0): cmd_1p} - def _create_foods(self, count: int = 5, type: FoodTypeEnum = FoodTypeEnum.GREEN): + def _create_foods(self, FOOD_TYPE, count: int = 5): for i in range(count): # add food to group - food = Food(self.foods, type) - + food = FOOD_TYPE(self.foods) food.rect.centerx = random.randint(self.playground.left, self.playground.right) food.rect.centery = random.randint(self.playground.top, self.playground.bottom) pass From d7252f60d63a68aade2f4be4184cdb85d2ad838b Mon Sep 17 00:00:00 2001 From: Kylin_on_Mac Date: Tue, 10 Oct 2023 23:07:29 +0800 Subject: [PATCH 06/10] feat: change level format --- blockly.json | 2 ++ levels/001.json | 4 +-- src/game.py | 76 ++++++++++++++++++++++++++----------------------- 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/blockly.json b/blockly.json index 291f20c..6075ea8 100644 --- a/blockly.json +++ b/blockly.json @@ -13,6 +13,7 @@ ["scene_info['ball_y']", "y coordinate of ball", "球的 y 座標"], ["scene_info['score']", "score", "目前的分數"], ["scene_info['foods']", "list of foods positions", "點點的位置清單"], +// TODO 通關分數 ["scene_info", "dictionary of all information", "包含所有資訊的字典"] ], "CONSTANT": [ @@ -22,6 +23,7 @@ [600, "bottom boundary", "下邊界"], [30, "ball width", "球身的寬度"], [30, "ball height", "球身的高度"], +// TODO [8, "food width", "食物的寬度"], [8, "food height", "食物的高度"] ], diff --git a/levels/001.json b/levels/001.json index a948b2c..6a4bd26 100644 --- a/levels/001.json +++ b/levels/001.json @@ -5,6 +5,6 @@ 200 ], "score_to_pass": 10, - "green_food_count": 3, - "black_food_count": 0 + "green_food_count": [3,0,0], + "black_food_count": [1,0,0] } \ No newline at end of file diff --git a/src/game.py b/src/game.py index 822d126..812006b 100644 --- a/src/game.py +++ b/src/game.py @@ -31,30 +31,28 @@ class EasyGame(PaiaGame): self.scene = Scene(width=WIDTH, height=HEIGHT, color=BG_COLOR, bias_x=0, bias_y=0) self._level = level self._level_file = level_file + self.foods = pygame.sprite.Group() + self.sound_controller = SoundController(sound) + if path.isfile(self._level_file) or self._level_file == "": # set by injected file - self.set_game_params_by_file(self._level_file) + self._init_game_by_file(self._level_file) pass elif self._level != -1: # set by level number - self.set_game_params_by_level(self._level) + self._init_game_by_level(self._level) pass else: - self.set_game_params_by_level(1) + self._init_game_by_level(1) - self.foods = pygame.sprite.Group() - self.sound_controller = SoundController(sound) - self._init_game() - - def set_game_params_by_level(self, level: int): + def _init_game_by_level(self, level: int): level_file_path = os.path.join(LEVEL_PATH, f"{level:03d}.json") - self.set_game_params_by_file(level_file_path) + self._init_game_by_file(level_file_path) - def set_game_params_by_file(self, level_file_path: str): + def _init_game_by_file(self, level_file_path: str): try: with open(level_file_path) as f: game_params = json.load(f) - self._set_game_params(game_params) except: # If the file doesn't exist, use default parameters print("此關卡檔案不存在,遊戲將會會自動使用第一關檔案 001.json。") @@ -63,31 +61,39 @@ class EasyGame(PaiaGame): game_params = json.load(f) self._level = 1 self._level_file = None - self._set_game_params(game_params) + finally: + # set game params + self._playground_w = int(game_params["playground_size"][0]) + self._playground_h = int(game_params["playground_size"][1]) + self.playground = pygame.Rect( + 0, 0, + self._playground_w, + self._playground_h + ) + self._green_food_count = game_params["green_food_count"] + self._red_food_count = game_params["black_food_count"] + self._score_to_pass = int(game_params["score_to_pass"]) + self._frame_limit = int(game_params["time_to_play"]) + self.playground.center = (WIDTH / 2, HEIGHT / 2) + + # init game + self.ball = Ball() + self.foods.empty() + self.score = 0 + + # todo validate food count + self._create_foods(GoodFoodLv1, self._green_food_count[0]) + # self._create_foods(GoodFoodLv1, self._green_food_count[1]) + # self._create_foods(GoodFoodLv1, self._green_food_count[2]) + self._create_foods(BadFoodLv1, self._red_food_count[0]) + # self._create_foods(BadFoodLv1, self._red_food_count[1]) + # self._create_foods(BadFoodLv1, self._red_food_count[2]) + + self.frame_count = 0 + self._frame_count_down = self._frame_limit + self.sound_controller.play_music() - def _set_game_params(self, game_params): - self._playground_w = int(game_params["playground_size"][0]) - self._playground_h = int(game_params["playground_size"][1]) - self.playground = pygame.Rect( - 0, 0, - self._playground_w, - self._playground_h - ) - self._green_food_count = int(game_params["green_food_count"]) - self._red_food_count = int(game_params["black_food_count"]) - self._score_to_pass = int(game_params["score_to_pass"]) - self._frame_limit = int(game_params["time_to_play"]) - self.playground.center = (WIDTH / 2, HEIGHT / 2) - def _init_game(self): - self.ball = Ball() - self.foods.empty() - self.score = 0 - self._create_foods(GoodFoodLv1, self._green_food_count) - self._create_foods(BadFoodLv1, self._red_food_count) - self.frame_count = 0 - self._frame_count_down = self._frame_limit - self.sound_controller.play_music() def update(self, commands): # handle command @@ -171,7 +177,7 @@ class EasyGame(PaiaGame): elif self.is_passed and self._level != -1: # win and use level will enter next level self._level += 1 - self.set_game_params_by_level(self._level) + self._init_game_by_level(self._level) self._init_game() From a6fcbbe55f7c476905becadddb2ed1253df84a3f Mon Sep 17 00:00:00 2001 From: Kylin_on_Mac Date: Tue, 10 Oct 2023 23:13:56 +0800 Subject: [PATCH 07/10] fix:update level file format --- blockly.json | 8 ++++---- levels/001.json | 2 +- levels/002.json | 4 ++-- levels/003.json | 4 ++-- levels/004.json | 4 ++-- levels/005.json | 4 ++-- levels/006.json | 4 ++-- levels/007.json | 4 ++-- levels/008.json | 4 ++-- levels/009.json | 4 ++-- levels/010.json | 4 ++-- levels/template.json | 6 ++---- src/game.py | 1 + 13 files changed, 26 insertions(+), 27 deletions(-) diff --git a/blockly.json b/blockly.json index 6075ea8..0435f5a 100644 --- a/blockly.json +++ b/blockly.json @@ -13,7 +13,7 @@ ["scene_info['ball_y']", "y coordinate of ball", "球的 y 座標"], ["scene_info['score']", "score", "目前的分數"], ["scene_info['foods']", "list of foods positions", "點點的位置清單"], -// TODO 通關分數 + ["scene_info['score_to_pass']", "the score for next level", "通關分數"], ["scene_info", "dictionary of all information", "包含所有資訊的字典"] ], "CONSTANT": [ @@ -23,9 +23,9 @@ [600, "bottom boundary", "下邊界"], [30, "ball width", "球身的寬度"], [30, "ball height", "球身的高度"], -// TODO - [8, "food width", "食物的寬度"], - [8, "food height", "食物的高度"] + [8, "food lv1 size", "等級一食物的寬高度"], + [12, "food lv2 size", "等級二食物的高度"], + [16, "food lv3 size", "等級三食物的高度"] ], "ACTION": [ ["['UP']", "moving up", "向上移動"], diff --git a/levels/001.json b/levels/001.json index 6a4bd26..2a5c36c 100644 --- a/levels/001.json +++ b/levels/001.json @@ -6,5 +6,5 @@ ], "score_to_pass": 10, "green_food_count": [3,0,0], - "black_food_count": [1,0,0] + "black_food_count": [0,0,0] } \ No newline at end of file diff --git a/levels/002.json b/levels/002.json index bb34c84..1d7ad96 100644 --- a/levels/002.json +++ b/levels/002.json @@ -5,6 +5,6 @@ 200 ], "score_to_pass": 15, - "green_food_count": 5, - "black_food_count": 0 + "green_food_count": [5,0,0], + "black_food_count": [0,0,0] } \ No newline at end of file diff --git a/levels/003.json b/levels/003.json index af6dd30..db4160f 100644 --- a/levels/003.json +++ b/levels/003.json @@ -5,6 +5,6 @@ 300 ], "score_to_pass": 15, - "green_food_count": 10, - "black_food_count": 0 + "green_food_count": [10,0,0], + "black_food_count": [0,0,0] } \ No newline at end of file diff --git a/levels/004.json b/levels/004.json index 34d2278..2c642fd 100644 --- a/levels/004.json +++ b/levels/004.json @@ -5,6 +5,6 @@ 300 ], "score_to_pass": 15, - "green_food_count": 7, - "black_food_count": 3 + "green_food_count": [7,0,0], + "black_food_count": [3,0,0] } \ No newline at end of file diff --git a/levels/005.json b/levels/005.json index cee2f71..a3da067 100644 --- a/levels/005.json +++ b/levels/005.json @@ -5,6 +5,6 @@ 300 ], "score_to_pass": 15, - "green_food_count": 7, - "black_food_count": 7 + "green_food_count": [7,0,0], + "black_food_count": [7,0,0] } \ No newline at end of file diff --git a/levels/006.json b/levels/006.json index ef06d11..0f3bc6f 100644 --- a/levels/006.json +++ b/levels/006.json @@ -5,6 +5,6 @@ 400 ], "score_to_pass": 15, - "green_food_count": 7, - "black_food_count": 10 + "green_food_count": [7,0,0], + "black_food_count": [10,0,0] } \ No newline at end of file diff --git a/levels/007.json b/levels/007.json index 49c8e26..b6c5251 100644 --- a/levels/007.json +++ b/levels/007.json @@ -5,6 +5,6 @@ 400 ], "score_to_pass": 20, - "green_food_count": 7, - "black_food_count": 13 + "green_food_count": [7,0,0], + "black_food_count": [13,0,0] } \ No newline at end of file diff --git a/levels/008.json b/levels/008.json index 61a8a29..ddc3b55 100644 --- a/levels/008.json +++ b/levels/008.json @@ -5,6 +5,6 @@ 500 ], "score_to_pass": 20, - "green_food_count": 10, - "black_food_count": 15 + "green_food_count": [10,0,0], + "black_food_count": [15,0,0] } \ No newline at end of file diff --git a/levels/009.json b/levels/009.json index bda3f34..167c95f 100644 --- a/levels/009.json +++ b/levels/009.json @@ -5,6 +5,6 @@ 500 ], "score_to_pass": 25, - "green_food_count": 15, - "black_food_count": 30 + "green_food_count": [15,0,0], + "black_food_count": [30,0,0] } \ No newline at end of file diff --git a/levels/010.json b/levels/010.json index 845f344..4caa335 100644 --- a/levels/010.json +++ b/levels/010.json @@ -5,6 +5,6 @@ 600 ], "score_to_pass": 25, - "green_food_count": 20, - "black_food_count": 40 + "green_food_count": [20,0,0], + "black_food_count": [40,0,0] } \ No newline at end of file diff --git a/levels/template.json b/levels/template.json index 487a087..3b9a69a 100644 --- a/levels/template.json +++ b/levels/template.json @@ -5,9 +5,7 @@ 200 ], "score_to_pass": 10, - "green_food_count": 3, - "black_food_count": 0, - "green_food_list": [3,2,1], - "black_food_list": [5,2,0] + "green_food_count": [3,0,0], + "black_food_count": [0,0,0] } \ No newline at end of file diff --git a/src/game.py b/src/game.py index 812006b..170c3e8 100644 --- a/src/game.py +++ b/src/game.py @@ -149,6 +149,7 @@ class EasyGame(PaiaGame): "ball_y": self.ball.rect.centery, "foods": foods_data, "score": self.score, + "score_to_pass":self._score_to_pass, "status": self.get_game_status() } From 46e655930dc980ed2033b1cdb71cb845e9cba230 Mon Sep 17 00:00:00 2001 From: Kylin_on_Mac Date: Tue, 10 Oct 2023 23:25:54 +0800 Subject: [PATCH 08/10] refac: update level file --- levels/003.json | 4 ++-- levels/004.json | 4 ++-- levels/005.json | 4 ++-- levels/006.json | 4 ++-- levels/007.json | 4 ++-- levels/008.json | 4 ++-- levels/009.json | 4 ++-- levels/010.json | 4 ++-- src/env.py | 3 +++ src/foods.py | 48 ++++++++++++++++++++++++++++++++++++++++++++---- src/game.py | 15 +++++++-------- 11 files changed, 70 insertions(+), 28 deletions(-) diff --git a/levels/003.json b/levels/003.json index db4160f..1e7af2e 100644 --- a/levels/003.json +++ b/levels/003.json @@ -5,6 +5,6 @@ 300 ], "score_to_pass": 15, - "green_food_count": [10,0,0], - "black_food_count": [0,0,0] + "green_food_count": [6,0,0], + "black_food_count": [2,0,0] } \ No newline at end of file diff --git a/levels/004.json b/levels/004.json index 2c642fd..61f4ddd 100644 --- a/levels/004.json +++ b/levels/004.json @@ -5,6 +5,6 @@ 300 ], "score_to_pass": 15, - "green_food_count": [7,0,0], - "black_food_count": [3,0,0] + "green_food_count": [8,0,0], + "black_food_count": [4,0,0] } \ No newline at end of file diff --git a/levels/005.json b/levels/005.json index a3da067..09e99fc 100644 --- a/levels/005.json +++ b/levels/005.json @@ -5,6 +5,6 @@ 300 ], "score_to_pass": 15, - "green_food_count": [7,0,0], - "black_food_count": [7,0,0] + "green_food_count": [8,3,0], + "black_food_count": [4,0,0] } \ No newline at end of file diff --git a/levels/006.json b/levels/006.json index 0f3bc6f..bac42f3 100644 --- a/levels/006.json +++ b/levels/006.json @@ -5,6 +5,6 @@ 400 ], "score_to_pass": 15, - "green_food_count": [7,0,0], - "black_food_count": [10,0,0] + "green_food_count": [8,4,0], + "black_food_count": [5,2,0] } \ No newline at end of file diff --git a/levels/007.json b/levels/007.json index b6c5251..84ee5bf 100644 --- a/levels/007.json +++ b/levels/007.json @@ -5,6 +5,6 @@ 400 ], "score_to_pass": 20, - "green_food_count": [7,0,0], - "black_food_count": [13,0,0] + "green_food_count": [8,4,2], + "black_food_count": [4,4,0] } \ No newline at end of file diff --git a/levels/008.json b/levels/008.json index ddc3b55..c94adc3 100644 --- a/levels/008.json +++ b/levels/008.json @@ -5,6 +5,6 @@ 500 ], "score_to_pass": 20, - "green_food_count": [10,0,0], - "black_food_count": [15,0,0] + "green_food_count": [6,4,2], + "black_food_count": [6,4,2] } \ No newline at end of file diff --git a/levels/009.json b/levels/009.json index 167c95f..9ee974f 100644 --- a/levels/009.json +++ b/levels/009.json @@ -5,6 +5,6 @@ 500 ], "score_to_pass": 25, - "green_food_count": [15,0,0], - "black_food_count": [30,0,0] + "green_food_count": [10,5,3], + "black_food_count": [12,7,4] } \ No newline at end of file diff --git a/levels/010.json b/levels/010.json index 4caa335..d7450e3 100644 --- a/levels/010.json +++ b/levels/010.json @@ -5,6 +5,6 @@ 600 ], "score_to_pass": 25, - "green_food_count": [20,0,0], - "black_food_count": [40,0,0] + "green_food_count": [12,8,4], + "black_food_count": [25,10,5] } \ No newline at end of file diff --git a/src/env.py b/src/env.py index 484a2e9..82274ce 100644 --- a/src/env.py +++ b/src/env.py @@ -32,6 +32,9 @@ FOOD_COLOR_MAP = { FoodTypeEnum.BAD_2: "#FF1744", FoodTypeEnum.BAD_3: "#FF1744" } +FOOD_LV1_SIZE = 8 +FOOD_LV2_SIZE = 12 +FOOD_LV3_SIZE = 16 # path of assets ASSET_PATH = path.join(path.dirname(__file__), "..", "asset") diff --git a/src/foods.py b/src/foods.py index 368692b..3833d8c 100644 --- a/src/foods.py +++ b/src/foods.py @@ -1,6 +1,6 @@ import pygame.sprite -from games.easy_game.src.env import FoodTypeEnum, FOOD_COLOR_MAP +from games.easy_game.src.env import FoodTypeEnum, FOOD_COLOR_MAP, FOOD_LV1_SIZE, FOOD_LV2_SIZE, FOOD_LV3_SIZE from mlgame.view.view_model import create_rect_view_data @@ -33,20 +33,60 @@ class Food(pygame.sprite.Sprite): class GoodFoodLv1(Food): def __init__(self, group): super().__init__(group) - self.image = pygame.Surface([8, 8]) + self.image = pygame.Surface([FOOD_LV1_SIZE, FOOD_LV1_SIZE]) self.type = FoodTypeEnum.GOOD_1 self.color = FOOD_COLOR_MAP[self.type] self.score = 1 self.rect = self.image.get_rect() - self.angle = 0 +class GoodFoodLv2(Food): + def __init__(self, group): + super().__init__(group) + + self.image = pygame.Surface([FOOD_LV2_SIZE, FOOD_LV2_SIZE]) + self.type = FoodTypeEnum.GOOD_2 + self.color = FOOD_COLOR_MAP[self.type] + self.score = 2 + self.rect = self.image.get_rect() + +class GoodFoodLv3(Food): + def __init__(self, group): + super().__init__(group) + + self.image = pygame.Surface([FOOD_LV3_SIZE, FOOD_LV3_SIZE]) + self.type = FoodTypeEnum.GOOD_3 + self.color = FOOD_COLOR_MAP[self.type] + self.score = 4 + self.rect = self.image.get_rect() + + class BadFoodLv1(Food): def __init__(self, group): super().__init__(group) - self.image = pygame.Surface([8, 8]) + self.image = pygame.Surface([FOOD_LV1_SIZE, FOOD_LV1_SIZE]) self.type = FoodTypeEnum.BAD_1 self.color = FOOD_COLOR_MAP[self.type] self.score = -1 self.rect = self.image.get_rect() self.angle = 0 + +class BadFoodLv2(Food): + def __init__(self, group): + super().__init__(group) + + self.image = pygame.Surface([FOOD_LV2_SIZE, FOOD_LV2_SIZE]) + self.type = FoodTypeEnum.BAD_2 + self.color = FOOD_COLOR_MAP[self.type] + self.score = -2 + self.rect = self.image.get_rect() + +class BadFoodLv3(Food): + def __init__(self, group): + super().__init__(group) + + self.image = pygame.Surface([FOOD_LV3_SIZE, FOOD_LV3_SIZE]) + self.type = FoodTypeEnum.BAD_3 + self.color = FOOD_COLOR_MAP[self.type] + self.score = -4 + self.rect = self.image.get_rect() diff --git a/src/game.py b/src/game.py index 170c3e8..1db17cd 100644 --- a/src/game.py +++ b/src/game.py @@ -9,7 +9,7 @@ from mlgame.utils.enum import get_ai_name from mlgame.view.decorator import check_game_progress, check_game_result from mlgame.view.view_model import * from .env import * -from .foods import GoodFoodLv1, BadFoodLv1 +from .foods import * from .game_object import Ball from .sound_controller import SoundController @@ -83,11 +83,11 @@ class EasyGame(PaiaGame): # todo validate food count self._create_foods(GoodFoodLv1, self._green_food_count[0]) - # self._create_foods(GoodFoodLv1, self._green_food_count[1]) - # self._create_foods(GoodFoodLv1, self._green_food_count[2]) + self._create_foods(GoodFoodLv2, self._green_food_count[1]) + self._create_foods(GoodFoodLv3, self._green_food_count[2]) self._create_foods(BadFoodLv1, self._red_food_count[0]) - # self._create_foods(BadFoodLv1, self._red_food_count[1]) - # self._create_foods(BadFoodLv1, self._red_food_count[2]) + self._create_foods(BadFoodLv2, self._red_food_count[1]) + self._create_foods(BadFoodLv3, self._red_food_count[2]) self.frame_count = 0 self._frame_count_down = self._frame_limit @@ -126,10 +126,9 @@ class EasyGame(PaiaGame): for food in hits: self.score += food.score self._create_foods(food.__class__, 1) - # TODO add food score to function - if isinstance(food, (GoodFoodLv1,)): + if isinstance(food, (GoodFoodLv1,GoodFoodLv2,GoodFoodLv3,)): self.sound_controller.play_eating_good() - elif isinstance(food, (BadFoodLv1,)): + elif isinstance(food, (BadFoodLv1,BadFoodLv2,BadFoodLv3,)): self.sound_controller.play_eating_bad() def get_data_from_game_to_player(self): From fec545bfe0a86f4c10576d0eefac2cddd39567e3 Mon Sep 17 00:00:00 2001 From: Kylin_on_Mac Date: Tue, 10 Oct 2023 23:36:52 +0800 Subject: [PATCH 09/10] doc: update README.md --- README.md | 29 +++++++++++++---------------- game_config.json | 4 ++-- src/game.py | 40 +++++++++++++++++++--------------------- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 8f962db..0eeddc8 100644 --- a/README.md +++ b/README.md @@ -22,20 +22,11 @@ ```python # main.py game = EasyGame( - time_to_play, score_to_pass, - green_food_count, red_food_count, - playground_size: list, - level: int = -1, + level: int = 1, level_file: str = None, sound: str = "off") ``` - -- `time_to_play`:遊戲執行的終止時間,單位是 frame,也就是遊戲內部更新畫面的次數,每更新一次 frame +1 -- `green_food_count`:遊戲中綠色食物的數量。 -- `red_food_count`:遊戲中紅色食物的數量。 -- `score_to_pass`:遊戲通關的點數,要超過這個分數才算過關。 -- `playground_size`:可移動區域的大小。 使用逗號將數字隔開 `width,height` `100,200` -- `level`: 選定內建關卡,請注意,使用此設定將會覆蓋掉上述其他關卡參數設定,預設為 -1 不選擇任何關卡。 +- `level`: 選定內建關卡,預設為 1 選擇第一關。 - `level_file`: 使用外部檔案作為關卡,請注意,使用此設定將會覆蓋掉關卡編號,並且不會自動進入下一關。 - `sound`: 音效。 @@ -83,10 +74,10 @@ python -m mlgame -i ./ml/ml_play_template.py ./ --time_to_play 1200 --green_food import random class MLPlay: - def __init__(self): + def __init__(self,ai_name,*args, **kwargs): print("Initial ml script") - def update(self, scene_info: dict): + def update(self, scene_info: dict,,*args, **kwargs): # print("AI received data from game :", scene_info) @@ -114,12 +105,16 @@ class MLPlay: "foods": [ { "x": 656, - "y": 210 + "y": 210, + "type": "GOOD_1", + "score": 1 }, ..., { "x": 371, - "y": 217 + "y": 217, + "type": "BAD_1", + "score": -1 } ], @@ -131,8 +126,10 @@ class MLPlay: - `frame`:遊戲畫面更新的編號 - `ball_x`:主角方塊的X座標,表示方塊的左邊座標值。 - `ball_y`:主角方塊的Y座標,表示方塊的上方座標值。 -- `foods`:食物的清單,清單內每一個物件都是一個食物的左上方座標值 +- `foods`:食物的清單,清單內每一個物件都是一個食物的左上方座標值,也會提供此食物是什麼類型和分數多少。 + - `type` 食物類型: `GOOD_1`, `GOOD_2`, `GOOD_3`, `BAD_1`, `BAD_2`, `BAD_3` - `score`:目前得到的分數 +- `score_to_pass`:通關分數 - `status`: 目前遊戲的狀態 - `GAME_ALIVE`:遊戲進行中 - `GAME_PASS`:遊戲通關 diff --git a/game_config.json b/game_config.json index 91c9875..6579291 100644 --- a/game_config.json +++ b/game_config.json @@ -18,8 +18,8 @@ "type": "int", "min": -1, "max": 100, - "default": -1, - "help": "選定內建關卡,請注意,使用此設定將會覆蓋掉其他關卡設定,預設為 -1 不選擇任何關卡。" + "default": 1, + "help": "選定內建關卡,預設為 1 選擇第一關。" }, { "name": "level_file", "verbose": "匯入關卡檔案", diff --git a/src/game.py b/src/game.py index 1db17cd..9f063ef 100644 --- a/src/game.py +++ b/src/game.py @@ -14,6 +14,21 @@ from .game_object import Ball from .sound_controller import SoundController +def revise_ball(ball: Ball, playground: pygame.Rect): + ball_rect = copy.deepcopy(ball.rect) + if ball_rect.left < playground.left: + ball_rect.left = playground.left + elif ball_rect.right > playground.right: + ball_rect.right = playground.right + + if ball_rect.top < playground.top: + ball_rect.top = playground.top + elif ball_rect.bottom > playground.bottom: + ball_rect.bottom = playground.bottom + ball.rect = ball_rect + pass + + class EasyGame(PaiaGame): """ This is a Interface of a game @@ -21,7 +36,7 @@ class EasyGame(PaiaGame): def __init__( self, - level: int = -1, + level: int = 1, level_file: str = None, sound: str = "off", *args, **kwargs): @@ -38,12 +53,9 @@ class EasyGame(PaiaGame): # set by injected file self._init_game_by_file(self._level_file) pass - elif self._level != -1: - # set by level number - self._init_game_by_level(self._level) - pass + else: - self._init_game_by_level(1) + self._init_game_by_level(self._level) def _init_game_by_level(self, level: int): level_file_path = os.path.join(LEVEL_PATH, f"{level:03d}.json") @@ -104,7 +116,7 @@ class EasyGame(PaiaGame): action = "NONE" self.ball.update(action) - self.revise_ball(self.ball, self.playground) + revise_ball(self.ball, self.playground) # update sprite self.foods.update() @@ -282,17 +294,3 @@ class EasyGame(PaiaGame): food.rect.centerx = random.randint(self.playground.left, self.playground.right) food.rect.centery = random.randint(self.playground.top, self.playground.bottom) pass - - def revise_ball(self, ball: Ball, playground: pygame.Rect): - ball_rect = copy.deepcopy(ball.rect) - if ball_rect.left < playground.left: - ball_rect.left = playground.left - elif ball_rect.right > playground.right: - ball_rect.right = playground.right - - if ball_rect.top < playground.top: - ball_rect.top = playground.top - elif ball_rect.bottom > playground.bottom: - ball_rect.bottom = playground.bottom - ball.rect = ball_rect - pass From 07dcc299b45d768abd79faec95db78056fbd9396 Mon Sep 17 00:00:00 2001 From: Kylin_on_Mac Date: Tue, 10 Oct 2023 23:40:13 +0800 Subject: [PATCH 10/10] doc: update version --- README.md | 2 +- game_config.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0eeddc8..1635685 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![easy_game](https://img.shields.io/github/v/tag/PAIA-Playful-AI-Arena/easy_game) [![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/) -[![MLGame](https://img.shields.io/badge/MLGame->9.5.3-.svg)](https://github.com/PAIA-Playful-AI-Arena/MLGame) +[![MLGame](https://img.shields.io/badge/MLGame->10.3.2-.svg)](https://github.com/PAIA-Playful-AI-Arena/MLGame) [![pygame](https://img.shields.io/badge/pygame-2.0.1-.svg)](https://github.com/pygame/pygame/releases/tag/2.0.1) diff --git a/game_config.json b/game_config.json index 6579291..6ed2edf 100644 --- a/game_config.json +++ b/game_config.json @@ -1,6 +1,6 @@ { "game_name": "easy_game", - "version": "2.2.1-beta", + "version": "2.3.1-alpha", "url": "https://github.com/PAIA-Playful-AI-Arena/easy_game", "description": "這是一個吃東西小遊戲,除了讓你熟習所有基本操作,也是 PAIA 的遊戲教學範例", "logo": [