Files
kiss-flixel/src/kiss_flixel/CameraTools.kiss

113 lines
6.1 KiB
Plaintext

(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<FlxCamera,FlxCamera> 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<T> 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))))