def resolve(self): """ Return combined result of all steering behaviours. """ acc=Vector(0,0) #if type(self.player.state) == Player.RxAttack: # pdb.set_trace() if self._avoid_defenders_on: acc += self.avoid_defenders() * self.w_avoid_defenders if self._seek_on: acc += self.seek() * self.w_seek if self._seek_end_zone_on: acc += self.seek_end_zone() * self.w_seek_end_zone if self._avoid_walls_on: acc += self.avoid_walls() * self.w_avoid_walls if self._pursue_on: acc += self.pursue() * self.w_pursue if self._block_on: acc += self.block() * self.w_block if self._avoid_friends_on: acc += self.avoid_friends() * self.w_avoid_friends if self._zone_defend_on: acc += self.zone_defend() * self.w_zone_defend if self._guard_on: acc += self.guard() * self.w_guard if self._stay_in_range_on: acc += self.stay_in_range() * self.w_stay_in_range if self._avoid_end_zone_on: acc += self.avoid_end_zone() * self.w_avoid_end_zone if self._arrive_at_speed_on: acc += self.arrive_at_speed() * self.w_arrive_at_speed return acc.truncate(self.player.top_acc)
class Player(Entity.Entity): """ Player base class. Implements a general all-rounder position. """ def __init__(self,message_handler,role,pitch,xstart,ystart,top_speed=10.,acc=10.,strength=5.,throw_power=30.,\ stamina=100.,tough=100.,block_skill=5.,catch_skill=70.,mass=1.): super(Player,self).__init__(message_handler) self.team=None self.role=role self.pitch=pitch self.size=1. self.xstart=xstart self.ystart=ystart self.top_speed=top_speed self.top_acc=acc self.stamina=stamina self.tough=tough self.strength=strength self.throw_power=throw_power self.block_skill=block_skill self.catch_skill=catch_skill self.mass=mass # Experimental linear drag locomotion model self.drag = self.top_acc/self.top_speed # Damage and exhaustion counters self.puff = self.stamina self._health = self.tough self._state = None self._move_state = None def setup(self): """ Call to reset to neutral state at starting position. """ self.pos = Vector(self.xstart,self.ystart) self.vel = Vector(0.,0.) self.acc = Vector(0.,0.) self.standing=True self._prone=-1. # Are we trying to catch the ball? self.want_to_catch=True self._state=None self._move_state=None @property def move_state(self): return self._move_state @move_state.setter def move_state(self,new_state): try: self._move_state.exit() except: pass finally: self._move_state=new_state self._move_state.enter() @property def prone(self): return self._prone @prone.setter def prone(self,value): if value < 0.: self.standing = True else: self.standing = False if self.has_ball: self.drop_ball() if self.in_contact: self.pitch.remove_all_contact(self) self._prone=value @property def health(self): return self._health @health.setter def health(self,value): if value < 0.: msg = (self.team,self,'tap_out') self.message_handler.add(msg) def get_message(self,msg): """ Only messages content looked at for the moment. """ if msg.subject == "ball_flying": self.state = self.role['ball_flying'](self) elif msg.subject == "ball_loose": self.state = self.role['ball_loose'](self) elif msg.subject == "ball_held": if self.has_ball: self.state = self.role['ball_carrier'](self) elif self.team_in_possession: self.state = self.role['attack'](self) else: self.state = self.role['defence'](self) elif msg.subject == "setup": self.setup() else: if not self.state.get_message(msg): if not self.move_state.get_message(msg): print("Uncaught message " + msg.subject) @property def attack_end_zone_x(self): return self.team.attack_end_zone_x @property def defend_end_zone_x(self): return self.team.defend_end_zone_x @property def dist_to_attack_end_zone(self): return (self.attack_end_zone_x - self.x)*self.team.direction @property def dist_to_defend_end_zone(self): return (self.x - self.defend_end_zone_x)*self.team.direction @property def opposite_team(self): return self.team.opposite_team @property def direction(self): return self.team.direction @property def has_ball(self): return self.pitch.ball.carrier == self @property def in_contact(self): return self in self.pitch.contacts.keys() @property def team_name(self): if self.team.direction > 0: return('home') else: return('away') @property def team_in_possession(self): return self.team.in_possession def x_from_defend_end_zone(self,x): if self.team.direction > 0: return x else: return self.pitch.xsize-x def move(self): # NOTE: Ignores mass! (assumes m=1 I guess) # Don't move if we are prone if not self.standing: # Prone players might still be moving, but they rapidly deccelerate! # Magic numbers prone_acc = 20. prone_top_speed = 5. desired_acc = self.vel.norm() * prone_acc * self.pitch.dt * -1. if self.vel.mag() < desired_acc.mag(): self.vel=Vector(0,0) else: self.vel += desired_acc self.vel = self.vel.truncate(prone_top_speed) self.pos += self.vel * self.pitch.dt return elif self.in_contact: # Push resolved seperately return acc = self.current_acc() # Check current puff reduced acc # NOTE HACK: Current states consider current vel in providing desired acc # We undo this so that they return the actual desired velocity state_vel = self.move_state.execute() desired_vel = state_vel + self.vel drag_limited_acc = acc * (1. - desired_vel.angle_factor(self.vel) * self.vel.mag() / self.top_speed) desired_acc = (desired_vel - self.vel).truncate(drag_limited_acc) self.vel += desired_acc * self.pitch.dt self.vel = self.vel.truncate(self.top_speed) self.pos += self.vel * self.pitch.dt # It costs puff to move self.puff -= desired_acc.mag() * self.pitch.dt * self.pitch.puff_fac def push(self): if not self.in_contact: return # NOTE: Pushing forwards always, but we don't always want to do that. Need to have hook # into state and define in states the push directions ( a parrallel steering behaviours). def current_acc(self): " Current puff reduced max accel." cut_in=0.5 ability_floor=0.5 #NOTE: Turned off for now to allow easier state debugging return self.top_acc # Reduce ability linearily after cut in, down to floor ratio = self.puff/self.stamina if ratio < cut_in: fac = ratio*(1.-ability_floor)/cut_in + ability_floor else: fac = 1. return fac*self.top_acc def standup(self): """ Check if player is prone and if so whether they can stand yet. """ # Done via property now (but is it working?) #if self.prone > 0.: self.prone -= self.pitch.dt # if self.prone <= 0.: # self.standing=True def drop_ball(self): self.send(self.pitch.ball,'ball_loose')