Source code for gobigger.players.human_player

import uuid
from pygame.math import Vector2
import logging

from .base_player import BasePlayer
from gobigger.balls import FoodBall, ThornsBall, CloneBall, SporeBall
from gobigger.utils import SequenceGenerator


[docs]class HumanPlayer(BasePlayer): def __init__(self, cfg, team_id, player_id, border, spore_settings, sequence_generator=None): self.team_id = team_id self.player_id = player_id self.border = border self.balls = {} self.ball_settings = cfg self.spore_settings = spore_settings self.first_respawn = True if sequence_generator is not None: self.sequence_generator = sequence_generator else: self.sequence_generator = SequenceGenerator()
[docs] def get_clone_num(self): ''' Overview: Get how many avatars the current player has ''' return len(self.balls)
[docs] def get_balls(self): ''' Overview: Get all the balls of the current player ''' return list(self.balls.values())
[docs] def add_balls(self, balls): ''' Overview: Add new avatars Parameters: balls <List[CloneBall] or CloneBall>: It can be a list or a single doppelganger ''' if isinstance(balls, list): for ball in balls: self.balls[ball.ball_id] = ball elif isinstance(balls, CloneBall): self.balls[balls.ball_id] = balls return True
[docs] def move(self, direction=None, duration=0.05): ''' Overview: Move all balls controlled by the player The main logic is 1. Processing stopped state 2. If it is stopping, control all balls to move closer to the center of mass Parameters: direction <Vector2>: A point in the unit circle duration <float>: time Returns: position <Vector2>: position after moving ''' if self.get_clone_num() == 0: return True if self.get_clone_num() == 1: for ball in self.balls.values(): ball.move(given_acc=direction, duration=duration) elif self.get_clone_num() >= 2: centroid = self.cal_centroid() for ball in self.balls.values(): given_acc_center = centroid - ball.position ball.move(given_acc=direction, given_acc_center=given_acc_center, duration=duration) self.score_decay()
[docs] def score_decay(self): ''' Overview: The player’s balls' scor will decay over time ''' for ball in self.balls.values(): ball.score_decay() return True
[docs] def eject(self, direction=None): ''' Overview: All clones controlled by the player perform the spore-spitting action Return: <list>: list of new spores ''' ret = [] ball_ids = list(self.balls.keys()) for ball_id in ball_ids: if ball_id in self.balls: ball = self.balls[ball_id] ret.append(ball.eject(direction=direction)) return ret
[docs] def get_keys_sort_by_balls(self): ''' Overview: Sort by ball score from largest to smallest Return: <list>: list of names ''' items = self.balls.items() backitems=[[v[1],v[0]] for v in items] backitems.sort(reverse=True) return [ backitems[i][1] for i in range(0,len(backitems))]
[docs] def split(self, direction=None): ''' Overview: All avatars controlled by the player perform splits, from large to small ''' balls_keys = self.get_keys_sort_by_balls() for k in balls_keys: if k in self.balls: ret = self.balls[k].split(self.get_clone_num(), direction=direction) if ret and isinstance(ret, CloneBall): self.add_balls(ret) return True
[docs] def eat(self, ball): raise NotImplementedError
def remove_balls(self, ball): ball.remove() if ball.ball_id in self.balls: try: del self.balls[ball.ball_id] except: pass return True def respawn(self, position): ball_id = self.sequence_generator.get() if self.first_respawn: score = self.ball_settings.score_init self.first_respawn = False else: score = self.ball_settings.score_respawn ball = CloneBall(ball_id=ball_id, position=position, border=self.border, score=score, team_id=self.team_id, player_id=self.player_id, spore_settings=self.spore_settings, sequence_generator=self.sequence_generator, **self.ball_settings) direction = Vector2(1, 0) # ball.stop() self.balls = {} self.balls[ball.ball_id] = ball return True
[docs] def cal_centroid(self): ''' Overview: Calculate the centroid ''' x = 0 y = 0 total_score = 0 for ball in self.get_balls(): x += ball.score * ball.position.x y += ball.score * ball.position.y total_score += ball.score return Vector2(x, y) / total_score
[docs] def adjust(self): ''' Overview: Adjust all the balls controlled by the player, including two parts 1. Possible Rigid Body Collision 2. Possible ball-ball fusion ''' eats = 0 balls = self.get_balls() balls = sorted(balls, reverse=True) balls_num = len(balls) to_remove_balls = [] for i in range(balls_num-1): if not balls[i].is_remove: for j in range(i+1, balls_num): if not balls[j].is_remove: dis = balls[i].get_dis(balls[j]) if dis < balls[i].radius + balls[j].radius: if balls[i].judge_rigid(balls[j]): balls[i].rigid_collision(balls[j]) # Rigid body collision else: if dis < balls[i].radius or dis < balls[j].radius: eats += 1 if balls[i].score > balls[j].score: # without eat_ratio balls[i].eat(balls[j]) balls[j].remove() to_remove_balls.append(balls[j]) else: balls[j].eat(balls[i]) balls[i].remove() to_remove_balls.append(balls[i]) balls[i].flush_frame_since_last_split() for ball in to_remove_balls: self.remove_balls(ball) return eats
[docs] def get_total_score(self): ''' Overview: Get the total score of all balls of the current player ''' total_score = 0 for ball in self.get_balls(): total_score += ball.score return total_score
def get_info(self): total_score = 0 can_eject = False can_split = False for ball in self.get_balls(): total_score += ball.score if ball.score > self.ball_settings.eject_score_min: can_eject = True if self.get_clone_num() < self.ball_settings.part_num_max \ and ball.score > self.ball_settings.split_score_min: can_split = True return total_score, can_split, can_eject