import sys import pygame import pymunk from common.game.billiards.baseBilliard import BaseBilliard from common.game.billiards.colorBall import ColorBall from common.game.billiards.cueBall import CueBall from common.game.billiards.fakeCueball import FakeCueBall from common.game.billiards.redBall import RedBall from common.game.cue import Cue from common.game.gameData import GameData from common.game.ruleManager import RuleManager from common.game.table import Table from config.sys import * from enums.color import * from enums.category import * class Game(object): def __init__(self): self.__game_data = GameData() self.__table = Table(self.__game_data) self.__cue_ball = CueBall((TABLE_WIDTH * 7 / 8, TABLE_HEIGHT / 4)) self.__game_data.balls.append(self.__cue_ball) self.__cue = Cue(self.__cue_ball, self.__game_data) self.__space = pymunk.Space() self.__clock = pygame.time.Clock() self.__space.gravity = (0, 0) self.__rule = RuleManager(self.__game_data) self.__hitting = False self.__window = pygame.display.set_mode(SCREEN_SIZE) self.__fake_ball = FakeCueBall((99999, 99999)) pass def add_ball(self, ball: BaseBilliard): self.__game_data.balls.append(ball) self.__space.add(ball.rigid_body, ball.shape) def init_table(self): self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS, TABLE_HEIGHT / 2))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 2, TABLE_HEIGHT / 2 - BALL_RADIUS / 2))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 2, TABLE_HEIGHT / 2 + BALL_RADIUS / 2))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 3, TABLE_HEIGHT / 2))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 3, TABLE_HEIGHT / 2 - BALL_RADIUS))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 3, TABLE_HEIGHT / 2 + BALL_RADIUS))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 4, TABLE_HEIGHT / 2 - BALL_RADIUS / 2))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 4, TABLE_HEIGHT / 2 + BALL_RADIUS / 2))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 4, TABLE_HEIGHT / 2 - BALL_RADIUS))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 4, TABLE_HEIGHT / 2 + BALL_RADIUS))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 5, TABLE_HEIGHT / 2))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 5, TABLE_HEIGHT / 2 - BALL_RADIUS))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 5, TABLE_HEIGHT / 2 + BALL_RADIUS))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 5, TABLE_HEIGHT / 2 - BALL_RADIUS * 2))) self.add_ball(RedBall((TABLE_WIDTH / 4 - BALL_RADIUS * 5, TABLE_HEIGHT / 2 + BALL_RADIUS * 2))) self.add_ball(ColorBall(2, YELLOW_BALL, YELLOW, (TABLE_WIDTH * 3 / 4, TABLE_HEIGHT / 3))) self.add_ball(ColorBall(3, COFFEE_BALL, COFFEE, (TABLE_WIDTH * 3 / 4, TABLE_HEIGHT / 2))) self.add_ball(ColorBall(4, CLAN_BALL, CLAN, (TABLE_WIDTH * 3 / 4, TABLE_HEIGHT * 2 / 3))) self.add_ball(ColorBall(5, BLUE_BALL, BLUE, (TABLE_WIDTH / 2, TABLE_HEIGHT / 2))) self.add_ball(ColorBall(6, PINK_BALL, PINK, (TABLE_WIDTH / 4 + BALL_RADIUS * 3, TABLE_HEIGHT / 2))) self.add_ball(ColorBall(7, BLACK_BALL, BLACK, (TABLE_WIDTH / 8, TABLE_HEIGHT / 2))) pass def print_score(self, left_score, right_score): font = pygame.font.Font("./src/fonts/PingFang.ttc", 24) left_surface = font.render("left: " + str(left_score), True, BLACK, None) right_surface = font.render("right: " + str(right_score), True, BLACK, None) round_surface = font.render("round: " + ("left" if self.__rule.round == 1 else "right"), True, BLACK, None) self.__window.blit(left_surface, (SCREEN_WIDTH / 8, SCREEN_HEIGHT * 7 / 8)) self.__window.blit(right_surface, (SCREEN_WIDTH * 7 / 8 - right_surface.get_width(), SCREEN_HEIGHT * 7 / 8)) self.__window.blit(round_surface, (SCREEN_WIDTH / 2 - round_surface.get_width() / 2, SCREEN_HEIGHT * 7 / 8)) def hit(self, x, y): self.__hitting = True self.__game_data.last_goal_balls = [_ for _ in self.__game_data.goal_balls] self.__rule.get_should_hit() self.__game_data.collide_log.clear() self.__game_data.goal_balls.clear() pos_x = x - (SCREEN_WIDTH - TABLE_WIDTH) / 2 pos_y = y - (SCREEN_HEIGHT - TABLE_HEIGHT) / 2 self.__cue_ball.rigid_body.velocity = pymunk.Vec2d( pos_x - self.__game_data.balls[0].rigid_body.position.x, pos_y - self.__game_data.balls[0].rigid_body.position.y).scale_to_length(512) def start(self): def new_ball(space, pos): ball = RedBall(pos) body = ball.rigid_body shape = ball.shape space.add(body, shape) self.__game_data.balls.append(ball) return shape def post_collision_ball_ball(arbiter, space, data): self.__game_data.collide_log.append(arbiter.shapes[0].collision_type) pygame.init() pygame.display.set_caption(TITLE) self.init_table() for _ in range(1, 9): self.__space.add_collision_handler(_, CUE_BALL).post_solve = post_collision_ball_ball for _ in range(6): self.__space.add(self.__table.cushing_body[_], self.__table.cushing_shape[_]) self.__space.add(self.__game_data.balls[0].rigid_body, self.__game_data.balls[0].shape) force = 5 add_force = False while True: if self.__rule.settlement: self.__rule.judge() if self.__game_data.is_stable() and self.__hitting: self.__rule.settlement = True self.__hitting = False for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() if not self.__game_data.is_stable(): continue if event.type == pygame.MOUSEMOTION: self.__cue.mouse_pos = event.pos if self.__rule.need_reset_cue_ball: self.__fake_ball.pos = event.pos if event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: add_force = True if event.type == pygame.MOUSEBUTTONUP: if event.button == 1: if self.__rule.need_reset_cue_ball: pos_x = - (SCREEN_WIDTH - TABLE_WIDTH) / 2 + event.pos[0] pos_y = - (SCREEN_HEIGHT - TABLE_HEIGHT) / 2 + event.pos[1] self.__cue_ball.pos = (pos_x + 1, pos_y + 1) self.__fake_ball.pos = (99999, 99999) self.__rule.need_reset_cue_ball = False else: self.hit(event.pos[0], event.pos[1]) add_force = False force = 5 if event.button == 3: pos_x = event.pos[0] - (SCREEN_WIDTH - TABLE_WIDTH) / 2 pos_y = event.pos[1] - (SCREEN_HEIGHT - TABLE_HEIGHT) / 2 new_ball(self.__space, (pos_x, pos_y)) if add_force: force += 5 if force >= 512: force = 512 self.__window.fill(WHITE) self.__table.goal(self.__space, self.__game_data.balls) self.__table.draw(self.__window) self.__fake_ball.draw(self.__window) if not self.__rule.need_reset_cue_ball: self.__cue.draw(self.__window) for _ in self.__game_data.balls: _.resistance() _.draw(self.__window) self.print_score(self.__game_data.left_score, self.__game_data.right_score) self.__space.step(1 / FPS) pygame.display.update() self.__clock.tick(FPS) pass pass