(function updateKeyControl [:FlxCamera camera :Float elapsed :Float speed :Void->Bool leftKey :Void->Bool rightKey :Void->Bool upKey :Void->Bool downKey] (let [scrollAmount (* speed elapsed) &mut :FlxVector movement (new FlxPoint)] (when (leftKey) (-= movement.x 1)) (when (rightKey) (+= movement.x 1)) (when (upKey) (-= movement.y 1)) (when (downKey) (+= movement.y 1)) (when (< 0 movement.length) (set movement (movement.normalize))) (movement.scale scrollAmount) (+= camera.scroll.x movement.x) (+= camera.scroll.y movement.y))) (var :Map borderCameras (new Map)) // Add a border sprite on top of this camera's viewport, scaling the border to frame the viewport, // and downsizing and shifting the viewport to fit within the border's opaque frame (function addBorder [:FlxCamera camera :FlxSprite border] (let [borderCamera (new FlxCamera (Std.int camera.x) (Std.int camera.y) camera.width camera.height) :BitmapData borderPixels (border.updateFramePixels) isTransparent ->c (= c FlxColor.TRANSPARENT) borderHorizontal (borderPixels.getVector (new Rectangle 0 (iHalf border.height) border.width 1)) borderVertical (borderPixels.getVector (new Rectangle (iHalf border.width) 0 1 border.height)) borderSizeLeft (borderHorizontal.findIndex isTransparent) borderSizeTop (borderVertical.findIndex isTransparent) borderSizeRight (.findIndex (borderHorizontal.reverse) isTransparent) borderSizeBottom (.findIndex (borderVertical.reverse) isTransparent)] (set border.x 0) // It will be 0,0 relative to its own camera (set border.y 0) (border.setGraphicSize camera.width camera.height) (border.updateHitbox) (FlxG.cameras.add borderCamera false) (dictSet borderCameras camera borderCamera) (set border.cameras [borderCamera]) (set borderCamera.bgColor FlxColor.TRANSPARENT) (FlxG.state.add border) (let [dx (* border.scale.x borderSizeLeft) dy (* border.scale.y borderSizeTop)] (+= camera.x dx) (+= camera.y dy) (-= camera.width dx (* border.scale.x borderSizeRight)) (-= camera.height dy (* border.scale.y borderSizeBottom))))) // GOTCHA: if you change FlxG.camera to a moving camera, you MUST provide a default camera for FlxG.mouse.getScreenPosition() (function updateMouseBorderControl [:FlxCamera camera :Float elapsed :Float speed :Float heightFraction :FlxCamera screenCamera] (let [viewport (ifLet [bc (dictGet borderCameras camera)] bc camera) left viewport.x top viewport.y right (+ viewport.x viewport.width) bottom (+ viewport.y viewport.height) // Use the same margin size for x and y, and calculate it based on height // (in a landscape view, this just makes more sense to me) margin (* viewport.height heightFraction) mPos (FlxG.mouse.getScreenPosition screenCamera)] (updateKeyControl camera elapsed speed // when the camera takes the whole screen, count the letterbox zones as margin ->(if (= left 0) (<= mPos.x (+ left margin)) (<= left mPos.x (+ left margin))) ->(if (= right FlxG.width) (<= (- right margin) mPos.x) (<= (- right margin) mPos.x right)) ->(if (= top 0) (<= mPos.y (+ top margin)) (<= top mPos.y (+ top margin))) ->(if (= bottom FlxG.height) (<= (- bottom margin) mPos.y) (<= (- bottom margin) mPos.y bottom))))) // GOTCHA: if you change FlxG.camera to a moving camera, you MUST provide a default camera for FlxG.mouse.getScreenPosition() (function updateScrollWheelZoom [:FlxCamera camera :Float elapsed :Float speed &opt :FlxCamera screenCamera] (case FlxG.mouse.wheel (0 null) (v (let [deltaZoom (* camera.zoom v elapsed speed) scrollPosition (camera.scroll.copyTo) mouseWorldPosition (FlxG.mouse.getWorldPosition camera)] (+= camera.zoom deltaZoom) (let [newMouseWorldPosition (FlxG.mouse.getWorldPosition camera) deltaMousePosition (newMouseWorldPosition.subtractPoint mouseWorldPosition)] (camera.scroll.subtractPoint deltaMousePosition)) // Undo any zooming out that expands the viewport past its bounds (when (> 0 deltaZoom) (unless (.equals (camera.getViewRect) (.intersection (getScrollBounds camera) (camera.getViewRect))) (-= camera.zoom deltaZoom) (set camera.scroll scrollPosition))))) (otherwise null))) (function getScrollBounds [:FlxCamera camera] (.fromTwoPoints (new FlxRect) (new FlxPoint camera.minScrollX camera.minScrollY) (new FlxPoint camera.maxScrollX camera.maxScrollY))) // GOTCHA: if you change FlxG.camera to a moving camera, you MUST provide a default camera for FlxG.mouse.getScreenPosition() (function calculateScrollBounds <>[:FlxSprite T] [:FlxCamera camera :FlxTypedGroup group &opt :FlxCamera screenCamera :Float margin] (let [r (GroupTools.calculateScreenBounds group screenCamera margin)] (camera.setScrollBoundsRect r.x r.y r.width r.height))) // GOTCHA: if you change FlxG.camera to a moving camera, you MUST provide a default camera for FlxG.mouse.getScreenPosition() (function extendScrollBounds [:FlxCamera camera :FlxSprite sprite &opt :FlxCamera screenCamera :Float margin] // if the given object is out of bounds, extend the bounds (let [r (sprite.getScreenBounds camera)] (setMin camera.minScrollX (- r.left margin)) (setMin camera.minScrollY (- r.top margin)) (setMax camera.maxScrollX (+ r.right margin)) (setMax camera.maxScrollY (+ r.bottom margin))))