def markShot(self, puck): puckPos = self.getRelativePos(puck.position) puckVel = self.getRelativeVector(puck.velocity) if puckVel.x < 0: return 0 shotLine = Line(puckPos, puckPos + puckVel) goalLine = Line(Vector2(FIELD_WIDTH, 0), Vector2(FIELD_WIDTH, 1)) intersection = shotLine.getIntersectPoint(goalLine) if intersection is None: return 0 distFromCenter = abs(intersection.y) bounces = 0 afterBounceDist = distFromCenter while afterBounceDist > FIELD_HEIGHT / 2: bounces += 1 afterBounceDist -= FIELD_HEIGHT afterBounceDist = abs(afterBounceDist) if bounces > 3: return 0 if afterBounceDist > GOAL_SPAN / 2: accuracy = min(1, ((GOAL_SPAN / 2) / afterBounceDist)**2) else: accuracy = 1 return round(puck.velocity.magnitude_squared() / 100000 * accuracy)
def defendTrajectory(self): if len(self.puck.trajectory) > 0: vector = Vector2(-self.puck.vector.y, self.puck.vector.x) secondPoint = self.striker.position + vector self.debugString = "basic.defendTrajectory" self.debugLines.append(self.puck.trajectory[0]) self.debugLines.append(Line(self.striker.position, secondPoint)) self.setDesiredPosition(self.puck.trajectory[0].getIntersectPoint( Line(self.striker.position, secondPoint)))
def calculateTrajectory(self): self.puck.trajectory = [] yBound = (FIELD_HEIGHT / 2 - PUCK_RADIUS) myLine = Line(self.puck.position, self.puck.position) tempVector = Vector2(self.puck.vector) self.goalLineIntersection = -10000 for i in range(self.noOfBounces + 1): if not tempVector.x == 0: a = tempVector.y / tempVector.x b = myLine.start.y - a * myLine.start.x else: a = 0 b = 0 if tempVector.x == 0: # not a function - vertical line myLine.end.x = myLine.start.x myLine.end.y = sign(tempVector.y) * yBound elif a == 0: # no slope - horizontal line myLine.end.x = sign(tempVector.x) * FIELD_WIDTH myLine.end.y = myLine.start.y else: # normal linear line myLine.end.x = (sign(tempVector.y) * yBound - b) / a myLine.end.y = sign(tempVector.y) * yBound tempVector.y *= -1 if myLine.end.x < PUCK_RADIUS: myLine.end.x = PUCK_RADIUS myLine.end.y = a * myLine.end.x + b tempVector.x *= -1 tempVector.y *= -1 # Set goal interection self.goalLineIntersection = myLine.end.y elif myLine.end.x > FIELD_WIDTH - PUCK_RADIUS: myLine.end.x = FIELD_WIDTH - PUCK_RADIUS myLine.end.y = a * myLine.end.x + b tempVector.x *= -1 tempVector.y *= -1 self.puck.trajectory.append(myLine.copy()) # If puck aims at goal, break if abs(myLine.end.y) < FIELD_HEIGHT / 2 - PUCK_RADIUS: break myLine.start.x = myLine.end.x myLine.start.y = myLine.end.y if len(self.puck.trajectory) > 1: self.willBounce = True else: self.willBounce = False
def bounce(self, damp, boundaries): # Define bounce lines bounceLines = [] for i in range(len(boundaries) - 1): bounceLines.append(Line(boundaries[i], boundaries[i + 1])) bounceLines.append(Line(boundaries[-1], boundaries[0])) # Bounce from them for line in bounceLines: if self.intersectsLine(line): self.bounceFromLine(line, damp) # ----------- Position corection ----------- percent = 0.8 # usually 20% to 80% slop = 0.03 # usually 0.01 to 0.1 # Top if self.position.y + self.radius > FIELD_HEIGHT / 2: if self.velocity.y > 0: self.velocity.y = -self.velocity.y * damp penetration = max( self.position.y - (FIELD_HEIGHT / 2 - self.radius), 0) correctionMag = max(penetration - slop * self.radius, 0) * percent self.position.y -= correctionMag # Bottom if self.position.y - self.radius < -FIELD_HEIGHT / 2: if self.velocity.y < 0: self.velocity.y = -self.velocity.y * damp penetration = max( -(self.position.y - self.radius - -FIELD_HEIGHT / 2), 0) correctionMag = max(penetration - slop * self.radius, 0) * percent self.position.y += correctionMag # Left if (self.position.x < 0 + self.radius) and abs( self.position.y) > GOAL_SPAN / 2: if (self.velocity.x < 0): self.velocity.x = -self.velocity.x * damp penetration = max(self.radius - self.position.x, 0) correctionMag = max(penetration - slop * self.radius, 0) * percent self.position.x += correctionMag # Right if self.position.x > FIELD_WIDTH - self.radius and abs( self.position.y) > GOAL_SPAN / 2: if (self.velocity.x > 0): self.velocity.x = -self.velocity.x * damp penetration = max(self.position.x - (FIELD_WIDTH - self.radius), 0) correctionMag = max(penetration - slop * self.radius, 0) * percent self.position.x -= correctionMag
def clampDesired(self, fromPos, step): desiredPos = fromPos + step line = Line(fromPos, desiredPos) self.debugLines.append(line) if desiredPos.x > STRIKER_AREA_WIDTH: desiredPos = line.getBothCoordinates(x=STRIKER_AREA_WIDTH) if abs(desiredPos.y) > YLIMIT: desiredPos = line.getBothCoordinates(y=sign(desiredPos.y) * YLIMIT) if desiredPos.x < XLIMIT: desiredPos = line.getBothCoordinates(x=XLIMIT) self.setDesiredPosition(desiredPos)
def _process(self): def case(state): return state == self.state def subCase(state): return state == self.subState if case(DEFEND): if self.isPuckBehingStriker(): self.defendGoalLastLine() elif not self.isPuckDangerous( ) and self.puck.position.x < STRIKER_AREA_WIDTH: self.subState = WAITING self.state = ATTACK elif self.shouldIntercept(): self.defendTrajectory() else: self.defendGoalDefault() elif case(ATTACK): if self.puck.velocity.x > self.maxSpeed * 0.7 or self.puck.position.x > STRIKER_AREA_WIDTH: self.subState = WAITING self.state = DEFEND if subCase(WAITING): if abs( self.goalLineIntersection ) < GOAL_SPAN / 2 and self.puck.state == ACURATE or self.puck.speedMagnitude > 200: self.subState = ATTACK_SHOOT else: self.subState = ATTACK_INIT elif subCase(ATTACK_INIT): self.lineToGoal = Line(self.puck.position, Vector2(FIELD_WIDTH * 1, 0)) vectorFromGoal = self.lineToGoal.start - self.lineToGoal.end vectorFromGoal.scale_to_length(STRIKER_RADIUS * 4) self.setDesiredPosition(self.puck.position + vectorFromGoal) if self.striker.position.distance_squared_to( self.striker.desiredPosition ) < CLOSE_DISTANCE**2 or self.isPuckDangerous(): self.subState = ATTACK_SHOOT elif subCase(ATTACK_SHOOT): step = (self.puck.position - self.striker.position) step.scale_to_length(PUCK_RADIUS * 3) self.setDesiredPosition(self.puck.position + step) if self.isPuckBehingStriker(): self.subState = WAITING self.state = DEFEND else: self.subState = WAITING else: pass
def __init__(self): super().__init__() self.description = "Slightly advanced game mechanics. No puck position prediction." self.actionState = 0 self.lineToGoal = Line() self.state = DEFEND self.subState = DEFEND
def __init__(self): super().__init__() self.description = "Combination of A and B. Slightly advanced mechanics with puck prediction." self.actionState = 0 self.lineToGoal = Line() self.state = DEFEND self.subState = DEFEND
def __init__(self): super().__init__() self.description = "Advanced game mechanics with puck prediction and advanced aiming algoritms." self.actionState = 0 self.lineToGoal = Line() self.state = DEFEND self.subState = DEFEND self.lastPuckStop = 0
def defendGoalDefault(self): if self.willBounce and self.puck.state == ACURATE\ and (self.puck.vector.x < -0.5 or (self.puck.vector.x < 0 and self.puck.trajectory[-1].end.x <= PUCK_RADIUS))\ and not (self.puck.position.x > FIELD_WIDTH*.6 and self.puck.speedMagnitude < 500): if self.puck.trajectory[-1].end.x > XLIMIT + STRIKER_RADIUS: fromPoint = self.puck.trajectory[-1].end else: fromPoint = self.puck.trajectory[-1].start else: fromPoint = self.puck.position a = Line(fromPoint, Vector2(0, 0)) b = Line(Vector2(DEFENSE_LINE, -FIELD_HEIGHT / 2), Vector2(DEFENSE_LINE, FIELD_HEIGHT / 2)) desiredPosition = a.getIntersectPoint(b) self.debugLines.append(a) self.debugLines.append(b) self.debugString = "basic.defendGoalDefault" if desiredPosition is not None: self.setDesiredPosition(Vector2(desiredPosition))
def _process(self): def case(state): return state == self.state def subCase(state): return state == self.subState self.getPredictedPuckPosition(self.puck.position, 1) if case(DEFEND): # 3 Main decisions self.debugString = "Deffending" if self.isPuckBehingStriker(): # IF puck is behing striker self.defendGoalLastLine() elif self.canAttack(): # If striker can attack self.subState = WAITING if self.shouldStop(): self.state = STOP_PUCK else: self.state = ATTACK elif self.shouldIntercept(): # If it is good idea to try to intercept current trajectory of the puck self.defendTrajectory() else: self.defendGoalDefault() elif case(ATTACK): if self.puck.velocity.x > self.maxSpeed*0.8 or self.getPredictedPuckPosition(self.puck.position).x > STRIKER_AREA_WIDTH: self.subState = WAITING self.state = DEFEND self.getPredictedPuckPosition(self.puck.position) if subCase(WAITING): self.debugString = "Attacking" self.lineToGoal = Line(self.predictedPosition, Vector2(FIELD_WIDTH*1.2, 0)) if self.puck.vector.x > -.2: self.subState = ATTACK_STAND_BEHIND elif abs(self.goalLineIntersection) < GOAL_SPAN/2 and self.puck.state == ACURATE or self.puck.speedMagnitude > 200: self.subState = ATTACK_SHOOT self.debugString = "Attacking: Without init" else: if self.puck.speedMagnitude < 100: self.lastPuckStop = self.gameTime self.subState = ATTACK_INIT elif subCase(ATTACK_STAND_BEHIND): self.debugString = "Attacking: Standing behind puck" if self.puck.state == ACURATE: desiredY = self.getPredictedPuckPosition(self.puck.position, 1).y maxPos = FIELD_HEIGHT/2 - PUCK_RADIUS if abs(desiredY) > maxPos: desiredY = sign(desiredY) * (maxPos - (abs(desiredY) - maxPos)) else: desiredY = self.puck.position.y self.setDesiredPosition(Vector2(self.puck.position.x - 4*STRIKER_RADIUS, desiredY)) if self.puck.speedMagnitude < 100 or self.puck.state == ACURATE and abs(self.puck.velocity.y) < self.maxSpeed*.8\ and sign(self.puck.velocity.y)*(self.striker.position.y - self.puck.position.y) > 20: self.subState = ATTACK_SHOOT elif subCase(ATTACK_INIT): # this should be done only if puck is almost still (will need a prepare time afted decision) # wait a bit for decision if self.gameTime > self.lastPuckStop + 0.15: randomNum = random() chosen = False #----------------------------- Decision how should striker aim at goal ----------------------------- if not self.puck.state == ACURATE and self.puck.speedMagnitude < 30: # try wall bounce only if puck is almost still topBounce = Line(self.predictedPosition, Vector2(FIELD_WIDTH*0.9, FIELD_HEIGHT)) vectorFromGoal = topBounce.start - topBounce.end vectorFromGoal.scale_to_length(STRIKER_RADIUS*6) if self.puck.position.y > YLIMIT - STRIKER_RADIUS*2 or (not self.striker.position.y < -FIELD_HEIGHT*0.3 and randomNum < 0.4): self.debugString = "Attacking: Top bounce" self.lineToGoal = topBounce finalVector = vectorFromGoal chosen = True bottomBounce = Line(self.predictedPosition, Vector2(FIELD_WIDTH*0.9, FIELD_HEIGHT)) vectorFromGoal = bottomBounce.start - bottomBounce.end vectorFromGoal.scale_to_length(STRIKER_RADIUS*6) if self.puck.position.y < -YLIMIT + STRIKER_RADIUS*2 or (not self.striker.position.y > FIELD_HEIGHT*0.3 - STRIKER_RADIUS*4 and randomNum > 0.6): self.debugString = "Attacking: Bottom bounce" self.lineToGoal = bottomBounce finalVector = vectorFromGoal chosen = True if not chosen: self.debugString = "Attacking: Straight shot" center = Line(self.predictedPosition, Vector2(FIELD_WIDTH*1.15, 0)) vectorFromGoal = center.start - center.end vectorFromGoal.scale_to_length(STRIKER_RADIUS*6) finalVector = vectorFromGoal self.lineToGoal = center # print("center") self.setDesiredPosition(self.predictedPosition + finalVector) self.subState = ATTACK_INIT_STEP2 elif subCase(ATTACK_INIT_STEP2): self.debugString = "Attacking: Preparing position" if self.striker.position.distance_squared_to(self.striker.desiredPosition) < CLOSE_DISTANCE**2 or self.isPuckDangerous() or self.isInGoodPosition(self.lineToGoal) or self.puck.speedMagnitude > 100: self.subState = ATTACK_SHOOT elif subCase(ATTACK_SHOOT): stepToPuck = (self.puck.position - self.striker.position) # Accurate shot if len(self.puck.trajectory) > 0 and self.puck.trajectory[0].getPointLineDist(self.striker.position) < STRIKER_RADIUS/3 or (stepToPuck.magnitude() < 3*STRIKER_RADIUS and self.puck.vector.x < -.7) or self.puck.speedMagnitude < 200: # A bit of aiming # self.debugString += " - Acurate shot (aimming)" vectorToGoal = self.lineToGoal.end - self.lineToGoal.start step = (self.puck.position - self.striker.position) step.scale_to_length(PUCK_RADIUS*3) angleDiff = self.getAngleDifference(vectorToGoal, step) step = step.rotate(angleDiff) stepFromStriker = (self.puck.position - self.striker.position) + step if abs(self.puck.position.y) > YLIMIT - STRIKER_RADIUS: # and self.puck.position.x > XLIMIT + STRIKER_RADIUS: self.setDesiredPosition(self.striker.position + stepFromStriker) else: self.clampDesired(self.striker.position, stepFromStriker) # Inaccurate shot else: # self.debugString = " - Inaccurate shot (aimming)" perpendicularPoint = self.puck.trajectory[0].getPerpendicularPoint(self.striker.position) self.getPredictedPuckPosition(perpendicularPoint, 0.8) if perpendicularPoint.x < self.predictedPosition.x and self.puck.vector.x < 0: step = (self.predictedPosition - self.striker.position) elif self.puck.vector.x > 0: self.getPredictedPuckPosition(self.puck.position, 0.8) step = (self.predictedPosition - self.striker.position) else: self.getPredictedPuckPosition(self.puck.position) step = (self.predictedPosition - self.striker.position) step.scale_to_length(PUCK_RADIUS*3) self.clampDesired(self.predictedPosition, step) if self.isPuckBehingStriker() or (self.badAttackingAngle(self.striker.desiredPosition) and abs(self.puck.position.y) < YLIMIT - STRIKER_RADIUS and self.puck.position.x > XLIMIT + STRIKER_RADIUS and self.puck.vector.x < -.6) or abs(self.puck.velocity.y) > self.maxSpeed*.8: if self.shouldIntercept(): self.defendTrajectory() else: self.defendGoalDefault() self.subState = WAITING self.state = DEFEND else: self.subState = WAITING self.debugLines.append(self.lineToGoal) elif case(STOP_PUCK): self.slowDownPuck() if self.striker.desiredPosition.x > self.puck.position.x: self.defendGoalDefault() self.subState = WAITING self.state = DEFEND if self.puck.speedMagnitude < 100 or self.isPuckDangerous() or (self.puck.state == ACURATE and self.puck.vector.x > 0): self.subState = WAITING self.state = ATTACK else: pass # 'Always' fucntions pos = self.getPredictedPuckPosition(self.striker.desiredPosition, 1) if self.isPuckBehingStriker(pos) and self.puck.speedMagnitude > 100 and abs(self.puck.vector.y) < .6 and self.state == DEFEND: self.defendGoalLastLine() self.subState = WAITING self.state = DEFEND
def initialCheck(self, pos): currentStepVector = pos - self.puck.position stepDistance = currentStepVector.magnitude() if self.puck.timeSinceCaptured == 0: stepSpeed = 0 else: stepSpeed = stepDistance / self.puck.timeSinceCaptured errorAngle = self.getAngleDifference(currentStepVector, self.puck.velocity) # Low angle condition if abs(errorAngle) > self.lowAngleTolerance and sign( errorAngle) == self.previousErrorSide: self.capturesWithBadLowAngle += 1 if (self.capturesWithBadLowAngle > 4): # print("Low Angle error") for i in range(4): self.puckHistory[self.firstUsefull].state = USELESS if self.firstUsefull > 1: self.firstUsefull -= 1 else: self.capturesWithBadLowAngle = 0 self.previousErrorSide = sign(errorAngle) if stepSpeed > 200 and stepDistance > 4 and abs(errorAngle): # Medium angle condition if abs(errorAngle) > self.mediumAngleTolerance and sign( errorAngle) == self.previousErrorSide: self.capturesWithBadMediumAngle += 1 if (self.capturesWithBadMediumAngle > 3): # print("Low angle condition.. 4 states -> useless") self.capturesWithBadLowAngle = 0 self.capturesWithBadMediumAngle = 0 # print("Medium Angle error") for i in range(3, len(self.puckHistory)): self.puckHistory[i].state = USELESS else: self.capturesWithBadMediumAngle = 0 # Debug # if len(self.puck.trajectory) > 0: # trajectoryLine = Line(self.puckHistory[self.firstUsefull].position, self.puck.position) # bounceLine = Line(Vector2(0, sign(pos.y) * (FIELD_HEIGHT/2 - PUCK_RADIUS)), Vector2(FIELD_WIDTH, sign(pos.y) * (FIELD_HEIGHT/2 - PUCK_RADIUS))) # self.debugLines.append(trajectoryLine) # self.debugLines.append(bounceLine) # self.debugPoints.append(self.getIntersectPoint(trajectoryLine, bounceLine)) # High angle condition if (abs(errorAngle) > self.highAngleTolerance) or ( stepSpeed > 700 and stepDistance > 25 and abs(errorAngle) > self.highAngleTolerance * .4): self.capturesWithBadLowAngle = 0 self.capturesWithBadMediumAngle = 0 # print("Angle condition: " + str(errorAngle)) if abs(pos.y) > max( 200, FIELD_HEIGHT / 2 - (stepDistance * abs(self.puck.vector.y) + PUCK_RADIUS) ) and sign(currentStepVector.x) == sign( self.puck.velocity.x ) and sign(self.puck.velocity.y) == sign( pos.y ) and self.puck.state == ACURATE: # seems like bounce from sidewalls occured trajectoryLine = Line( self.puckHistory[self.firstUsefull].position, self.puck.position) bounceLine = Line( Vector2(0, sign(pos.y) * (FIELD_HEIGHT / 2 - PUCK_RADIUS)), Vector2(FIELD_WIDTH, sign(pos.y) * (FIELD_HEIGHT / 2 - PUCK_RADIUS))) bouncePoint = trajectoryLine.getIntersectPoint(bounceLine) self.debugLines.append(trajectoryLine) self.debugLines.append(bounceLine) bouncePoint = trajectoryLine.getIntersectPoint(bounceLine) self.puck.position = bouncePoint # print(bouncePoint) for i in range(len(self.puckHistory)): self.puckHistory[i].state = USELESS
def _process(self): def case(state): return state == self.state def subCase(state): return state == self.subState if case(DEFEND): if self.isPuckBehingStriker(): self.defendGoalLastLine() elif self.canAttack(): self.subState = WAITING self.state = ATTACK elif self.shouldIntercept(): self.defendTrajectory() else: self.defendGoalDefault() elif case(ATTACK): if self.puck.velocity.x > self.maxSpeed * 0.7 or self.getPredictedPuckPosition( self.puck.position).x > STRIKER_AREA_WIDTH: self.subState = WAITING self.state = DEFEND self.getPredictedPuckPosition(self.puck.position) if subCase(WAITING): if abs( self.goalLineIntersection ) < GOAL_SPAN / 2 and self.puck.state == ACURATE or self.puck.speedMagnitude > 200: self.subState = ATTACK_SHOOT else: self.subState = ATTACK_INIT elif subCase(ATTACK_INIT): self.lineToGoal = Line(self.predictedPosition, Vector2(FIELD_WIDTH * 1, 0)) vectorFromGoal = self.lineToGoal.start - self.lineToGoal.end vectorFromGoal.scale_to_length(STRIKER_RADIUS * 4) self.setDesiredPosition(self.predictedPosition + vectorFromGoal) if self.striker.position.distance_squared_to( self.striker.desiredPosition ) < CLOSE_DISTANCE**2 or self.isPuckDangerous( ) or self.isInGoodPosition(self.lineToGoal): self.subState = ATTACK_SHOOT elif subCase(ATTACK_SHOOT): # Accurate shot if len(self.puck.trajectory ) > 0 and self.puck.trajectory[0].getPointLineDist( self.striker.position) < STRIKER_RADIUS: step = (self.puck.position - self.striker.position) step.scale_to_length(PUCK_RADIUS * 3) self.clampDesired(self.puck.position, step) # Inaccurate shot else: perpendicularPoint = self.puck.trajectory[ 0].getPerpendicularPoint(self.striker.position) self.getPredictedPuckPosition(perpendicularPoint) if perpendicularPoint.x < self.predictedPosition.x: step = (self.predictedPosition - self.striker.position) step.scale_to_length(PUCK_RADIUS * 3) self.clampDesired(self.predictedPosition, step) else: self.getPredictedPuckPosition(self.puck.position) step = (self.predictedPosition - self.striker.position) step.scale_to_length(PUCK_RADIUS * 3) self.clampDesired(self.predictedPosition, step) if self.isPuckBehingStriker() or self.badAttackingAngle( self.striker.desiredPosition): self.defendTrajectory() self.subState = WAITING self.state = DEFEND else: self.subState = WAITING else: pass # 'Always' fucntions pos = self.getPredictedPuckPosition(self.striker.desiredPosition, 1) if self.isPuckBehingStriker( pos ) and self.puck.speedMagnitude > 100 and self.state == DEFEND: self.defendGoalLastLine() self.subState = WAITING self.state = DEFEND
def __init__(self): super().__init__() self.description = "Basic game mechanics. Uses puck position prediction." self.actionState = 0 self.lineToGoal = Line()