class Enemy(): def __init__(self, enemyType, **kwargs): self.canvas = InstructionGroup() self.enemyType = enemyType self.sprite = Sprite() if self.enemyType == 'normal': self.setOffsetTheta(0) self.sprite.color.r = 0.0 self.sprite.color.g = 0.2 self.sprite.color.b = 0.5 else: self.setOffsetTheta(math.pi / 2) self.sprite.color.r = 0.5 self.sprite.color.g = 0.1 self.sprite.color.b = 0.1 self.health = 100 self.pos = (0, 0) self.velocity = [0, 0] self.updateAppearance() self.canvas.add(self.sprite.canvas) self.shouldRemove = False def setOffsetTheta(self, offsetTheta): self.offsetTheta = offsetTheta self.otcos = math.cos(self.offsetTheta) self.otsin = math.sin(self.offsetTheta) def reset(self, isRespawned): sample = random.random() theta = math.pi * 2 * sample speed = 0.1 self.isRespawned = isRespawned self.velocity = [math.cos(theta) * speed, math.sin(theta) * speed] def setWorld(self, world): self.world = world def setCenterPos(self, centerPos): self.pos = centerPos self.sprite.setCenterPos(centerPos) def decrement(self, beamState): delta = 0 if beamState == 1: self.health -= 10 if self.enemyType == 'normal': delta = 100 else: delta = -500 if self.health <= 0: self.shouldRemove = True else: self.updateAppearance() return delta def updateAppearance(self): baseSize = 30 if not self.enemyType == 'normal': baseSize = 15 factor = math.log(100 - self.health + 1) self.sprite.setSizeScalar(baseSize + factor * 10) def update(self, dt): worldVector = (self.world.direction[0] * self.world.speed, self.world.direction[1] * self.world.speed) worldOffset = (worldVector[0] * self.otcos - worldVector[1] * self.otsin, worldVector[0] * self.otsin - worldVector[1] * self.otcos) centerPos = (self.pos[0] + self.velocity[0] + worldOffset[0], self.pos[1] + self.velocity[1] + worldOffset[1]) if self.isRespawned: self.isRespawned = False if centerPos[0] < self.world.left: self.shouldRemove = True if centerPos[0] > self.world.right: self.shouldRemove = True if centerPos[1] < self.world.left: self.shouldRemove = True if centerPos[1] > self.world.right: self.shouldRemove = True self.setCenterPos(centerPos)
class Player(): def __init__(self, playerCode, **kwargs): self.canvas = InstructionGroup() self.sprite = Sprite() self.playerCode = playerCode self.frameNum = 0 self.bottomLeft = (0, 0) self.topRight = (700, 500) self.pos = (0, 0) self.direction = (0, 0) self.speed = 0 self.targetDirection = (0, 0) self.targetSpeed = 0 self.isTweeningDirection = False self.isTweeningSpeed = False self.newDirectionSince = 0 self.newSpeedSince = 0 self.directionChange = (0, 0) if playerCode == 'p2': self.sprite.color.r = 1 if playerCode == 'enemy1': self.sprite.color.b = 1 self.canvas.add(self.sprite.canvas) def reset(self): self.frameNum = 0 def setBounds(self, bottomLeft, topRight): self.bottomLeft = bottomLeft self.topRight = topRight def setCenterPos(self, centerPos): self.pos = centerPos self.sprite.setCenterPos(self.pos) def setPlayerKeyReport(self, playerKeyReport): self.playerKeyReport = playerKeyReport def update(self, dt): self.frameNum += 1 self.updateDynamics() self.updateTweening() self.updatePosition() def updateDynamics(self): dX = 0 dY = 0 scale = 1 speed = 0 if self.playerKeyReport.up: dY = 1 elif self.playerKeyReport.down: dY = -1 if self.playerKeyReport.left: dX = -1 elif self.playerKeyReport.right: dX = 1 if not dY == 0 and not dX == 0: scale = SQRT_2_DIV_2 if not dY == 0 or not dX == 0: speed = TOP_SPEED targetDirection = (dX * scale, dY * scale) wasNullDirection = (self.targetDirection[0] == 0 and self.targetDirection[1] == 0) isNullDirection = (targetDirection[0] == 0 and targetDirection[1] == 0) isNewTargetDirection = (not self.targetDirection[0] == targetDirection[0] or not self.targetDirection[1] == targetDirection[1]) if not isNullDirection and isNewTargetDirection: if wasNullDirection: self.targetDirection = targetDirection self.direction = targetDirection else: self.isTweeningDirection = True self.newDirectionSince = self.frameNum self.targetDirection = targetDirection self.calculateDirectionVector() isNewTargetSpeed = not self.targetSpeed == speed if isNewTargetSpeed: self.isTweeningSpeed = True self.newSpeedSince = self.frameNum self.targetSpeed = speed def updateTweening(self): self.updateSpeedTweening() self.accountForZeroSpeed() self.updateDirectionTweening() def updateSpeedTweening(self): if not self.isTweeningSpeed: return speedDelta = 1 speedDirection = 1 speedTweeningContinues = True if self.targetSpeed < self.speed: speedDirection = -1 nextSpeed = self.speed + speedDirection * speedDelta if speedDirection == -1 and nextSpeed < self.targetSpeed: nextSpeed = self.targetSpeed speedTweeningContinues = False elif speedDirection == 1 and nextSpeed > self.targetSpeed: nextSpeed = self.targetSpeed speedTweeningContinues = False self.speed = nextSpeed self.isTweeningSpeed = speedTweeningContinues def accountForZeroSpeed(self): if self.speed == 0: self.isTweeningDirection = False self.targetDirection = (0, 0) self.direction = (0, 0) def calculateDirectionVector(self): subdivs = 5 vector = (self.targetDirection[0] - self.direction[0], self.targetDirection[1] - self.direction[1]) vectorLength = math.sqrt(math.pow(vector[0], 2) + math.pow(vector[1], 2)) self.directionChange = (vector[0] / (vectorLength * subdivs), vector[1] / (vectorLength * subdivs)) def updateDirectionTweening(self): if not self.isTweeningDirection: return nextDirection = self.direction directionTweeningContinues = True nextDirection = (self.direction[0] + self.directionChange[0], self.direction[1] + self.directionChange[1]) remainder = (nextDirection[0] - self.targetDirection[0], nextDirection[1] - self.targetDirection[1]) targetDirectionLen = math.sqrt(math.pow(self.targetDirection[0], 2) + math.pow(self.targetDirection[1], 2)) # "unrotate" the remainder by the target direction so we # can compare distance along that line. if False: dotA = self.targetDirection[0] * remainder[0] / targetDirectionLen dotB = self.targetDirection[1] * remainder[1] / targetDirectionLen dot = dotA + dotB didOvershoot = (dot < 0) ## Check if we went out of the unit circle len = math.pow(nextDirection[0], 2) + math.pow(nextDirection[1], 2) didOvershoot = len > 1 if didOvershoot: nextDirection = self.targetDirection directionTweeningContinues = False self.direction = nextDirection self.isTweeningDirection = directionTweeningContinues def updatePosition(self): if self.speed <= 0.001: return len = math.sqrt(math.pow(self.direction[0], 2) + math.pow(self.direction[1], 2)) if len == 0: return newCoords = (self.pos[0] + self.direction[0] * self.speed / len, self.pos[1] + self.direction[1] * self.speed / len) self.setCenterPos(newCoords)