Source code for gobigger.balls.base_ball

import math
import logging
from abc import ABC, abstractmethod
from easydict import EasyDict
from pygame.math import Vector2
from functools import total_ordering

from gobigger.utils import format_vector, Border, deep_merge_dicts


[docs]@total_ordering class BaseBall(ABC): ''' Overview: Base class of all balls '''
[docs] @staticmethod def default_config(): ''' Overview: Default config ''' cfg = dict() return EasyDict(cfg)
def __init__(self, ball_id, position, score, border, **kwargs): ''' Parameters: vel <Vector2> : the direction of the ball's speed acc <Vector2> : the direction of the ball's acceleration ''' self.ball_id = ball_id self.position = position # init other kwargs kwargs = EasyDict(kwargs) cfg = BaseBall.default_config() cfg = deep_merge_dicts(cfg, kwargs) self.score = score self.border = border self.radius = self.score_to_radius(self.score) self.is_remove = False self.quad_node = None def set_score(self, score: float) -> None: self.score = score self.radius = self.score_to_radius(self.score) def radius_to_score(self, radius): return (math.pow(radius,2) - 0.15) / 0.042 * 100 def score_to_radius(self, score): return math.sqrt(score / 100 * 0.042 + 0.15)
[docs] def move(self, direction, duration): """ Overview: Realize the movement of the ball, pass in the direction and time parameters, and return the new position Parameters: direction <Vector2>: A point in the unit circle duration <float>: time Returns: position <Vector2>: position after moving """ raise NotImplementedError
[docs] def eat(self, ball): """ Overview: Describe the rules of eating and being eaten Parameters: ball <BaseBall>: Eaten ball """ raise NotImplementedError
[docs] def remove(self): """ Overview: Things to do when being removed from the map """ self.is_remove = True
[docs] def check_border(self): """ Overview: Check to see if the position of the ball exceeds the bounds of the map. If it exceeds, the speed and acceleration in the corresponding direction will be zeroed, and the position will be edged """ if self.position.x < self.border.minx or self.position.x > self.border.maxx: self.position.x = max(self.position.x, self.border.minx) self.position.x = min(self.position.x, self.border.maxx) if self.position.y < self.border.miny or self.position.y > self.border.maxy: self.position.y = max(self.position.y, self.border.miny) self.position.y = min(self.position.y, self.border.maxy)
[docs] def get_dis(self, ball): ''' Overview: Get the distance between the centers of the two balls Parameters: ball <BaseBall>: another ball ''' return (self.position - ball.position).length()
[docs] def judge_cover(self, ball): ''' Overview: Determine whether the center of the two balls is covered Parameters: ball <BaseBall>: another ball Returns: is_covered <bool>: covered or not ''' if ball.ball_id == self.ball_id: return False dis = self.get_dis(ball) if self.radius > dis or ball.radius > dis: return True else: return False
[docs] def judge_in_rectangle(self, rectangle): ''' Overview: Determine if the ball and rectangle intersect Parameters: rectangle <List>: left_top_x, left_top_y, right_bottom_x, right_bottom_y Returns: <bool> : intersect or not ''' dx = rectangle[0] - self.position.x if rectangle[0] > self.position.x \ else self.position.x - rectangle[2] if self.position.x > rectangle[2] else 0 dy = rectangle[1] - self.position.y if rectangle[1] > self.position.y \ else self.position.y - rectangle[3] if self.position.y > rectangle[3] else 0 return dx**2 + dy**2 <= self.radius**2
def __repr__(self) -> str: return 'position={}, score={:.3f}, radius={:.3f}'.format(self.position, self.score, self.radius) def __eq__(self, other): return self.score == other.score def __le__(self, other): return self.score < other.score def __gt__(self, other): return self.score > other.score