diff --git a/game/sim/camera.py b/game/sim/camera.py new file mode 100644 index 0000000..764daa3 --- /dev/null +++ b/game/sim/camera.py @@ -0,0 +1,75 @@ +from .geometry import clamp + + +class Camera: + def __init__(self, viewWidth, viewHeight, worldWidth, worldHeight): + self.viewWidth = viewWidth + self.viewHeight = viewHeight + self.worldWidth = worldWidth + self.worldHeight = worldHeight + self.x = 0.0 + self.y = 0.0 + self.deadzoneWidth = viewWidth * 0.28 + self.deadzoneHeight = viewHeight * 0.32 + self.lerp = 0.18 + self.shakeFrames = 0 + self.shakeMagnitude = 0.0 + + def setBounds(self, worldWidth, worldHeight): + self.worldWidth = worldWidth + self.worldHeight = worldHeight + + def focusOn(self, targetX, targetY): + self.x = targetX - self.viewWidth * 0.5 + self.y = targetY - self.viewHeight * 0.5 + self.clampToWorld() + + def clampToWorld(self): + maxX = max(0.0, self.worldWidth - self.viewWidth) + maxY = max(0.0, self.worldHeight - self.viewHeight) + self.x = clamp(self.x, 0.0, maxX) + self.y = clamp(self.y, 0.0, maxY) + + def addShake(self, frames, magnitude): + self.shakeFrames = max(self.shakeFrames, frames) + self.shakeMagnitude = max(self.shakeMagnitude, magnitude) + + def update(self, targetX, targetY): + centerX = self.x + self.viewWidth * 0.5 + centerY = self.y + self.viewHeight * 0.5 + halfDeadX = self.deadzoneWidth * 0.5 + halfDeadY = self.deadzoneHeight * 0.5 + + desiredX = self.x + if targetX < centerX - halfDeadX: + desiredX = self.x + (targetX - (centerX - halfDeadX)) + elif targetX > centerX + halfDeadX: + desiredX = self.x + (targetX - (centerX + halfDeadX)) + + desiredY = self.y + if targetY < centerY - halfDeadY: + desiredY = self.y + (targetY - (centerY - halfDeadY)) + elif targetY > centerY + halfDeadY: + desiredY = self.y + (targetY - (centerY + halfDeadY)) + + self.x += (desiredX - self.x) * self.lerp + self.y += (desiredY - self.y) * self.lerp + self.clampToWorld() + + if self.shakeFrames > 0: + self.shakeFrames -= 1 + if self.shakeFrames == 0: + self.shakeMagnitude = 0.0 + + def offset(self): + offsetX = self.x + offsetY = self.y + if self.shakeFrames > 0: + wobble = self.shakeMagnitude * (1.0 if self.shakeFrames % 2 == 0 else -1.0) + offsetX += wobble + offsetY += wobble * 0.5 + return int(offsetX), int(offsetY) + + def worldToScreen(self, worldX, worldY): + offsetX, offsetY = self.offset() + return worldX - offsetX, worldY - offsetY diff --git a/game/sim/inputCommand.py b/game/sim/inputCommand.py new file mode 100644 index 0000000..48ace62 --- /dev/null +++ b/game/sim/inputCommand.py @@ -0,0 +1,63 @@ +class InputCommand: + __slots__ = ( + "left", + "right", + "up", + "down", + "jump", + "jumpHeld", + "dash", + "run", + "attack", + "pause", + "confirm", + ) + + def __init__( + self, + left=False, + right=False, + up=False, + down=False, + jump=False, + jumpHeld=False, + dash=False, + run=False, + attack=False, + pause=False, + confirm=False, + ): + self.left = left + self.right = right + self.up = up + self.down = down + self.jump = jump + self.jumpHeld = jumpHeld + self.dash = dash + self.run = run + self.attack = attack + self.pause = pause + self.confirm = confirm + + @property + def moveAxis(self): + return (1 if self.right else 0) - (1 if self.left else 0) + + @property + def verticalAxis(self): + return (1 if self.down else 0) - (1 if self.up else 0) + + def copy(self): + return InputCommand( + self.left, + self.right, + self.up, + self.down, + self.jump, + self.jumpHeld, + self.dash, + self.run, + self.attack, + self.pause, + self.confirm, + )