Colony tech update 1: Creating a game camera, part 2, the base CameraControls class
In the first part of this series on creating a game camera, we saw the Camera
object itself, and an example of it in action; albeit moving randomly. If an unpredictable viewing experience is what you're after in your game, then happily you don't need to read any further, otherwise at some point you're going to want to control it.
There are a few ways to control a camera, depending on how you go about it. The ones that I'm going to show in this series are:
- Using the keyboard
- Using the screen edges (as you hit the edge of the screen, the camera moves)
- Using the mouse to drag and fling the camera around (equivalent to dragging with your finger in a mobile game)
- Following an object
- Not really a controller per se, but screw it, I'm adding it anyway, clicking to select objects in the current camera view rect
A lot of these share common functionality, so we'll have them all extend a base CameraControls
class.
What's in it?
It's mostly to hold common properties and to define the basics, like moveSpeed
and zoomSpeed
. We define them here rather than the Camera
class, as it gives a lot more flexibility and stops unnecessary bloat (the Camera
class is fat enough).
We also define whether we should move and zoom using velocity or not. If you're setting these to true
, you may need to adjust your move and zoom speed as the effects of both are applied for a much longer time.
Also in there is whether or not we should compensate for the current zoom when moving the camera. Basically how it works is, imagine in a single frame, the camera was going to move 10
pixels. At camera zoom 1.0
(which equates to a scaleX/scaleY
of 1.0
), our layer would move 10
pixels. If our camera zoom is 0.5
, then a move of 10
would actually result in a visual move of 20
, as our layer is half the size is normally is. Setting shouldMoveCompenstateForZoom
to true
will mean that if our zoom is 0.5
, the move is scaled to 5
pixels, so visually everything works out. If those last few sentences didn't make any sense, the playing with the code should make it pretty obvious ;) Normally, you should set this to true
, as it provides a better user experience.
The code
Again, for the CameraControls
to work properly, it needs to be added to an update loop, or at least have update()
called every frame. In my Update
class (which I'll share a basic version of with the full example code at the end of the series), update()
isn't called if active
is false
.
You can also download it below.
package
{
import flash.display.Stage;
import flash.geom.Point;
/**
* A generic camera controller
* @author Damian Connolly
*/
public class CameraControls implements IUpdateObj
{
/*******************************************************************************************/
/**
* The distance between MOUSE_DOWN and MOUSE_UP, where we consider it as a click
*/
public static const CLICK_DIST:Number = 4.0;
/*******************************************************************************************/
/**
* The speed that we're moving the camera at
*/
public var moveSpeed:Number = 200.0;
/**
* The speed that we're zooming the camera at
*/
public var zoomSpeed:Number = 5.0;
/**
* Should we move the camera using velocity?
*/
public var shouldMoveWithVelocity:Boolean = false;
/**
* Should we zoom the camera using velocity?
*/
public var shouldZoomWithVelocity:Boolean = false;
/**
* Should we take zoom into account when moving? For the most part, you should leave this
* as true, as it gives a better user experience when zoomed in or out. Setting to false
* means that we move the same amount regardless of the camera zoom (and as zoom relates
* to scale, it means we'll effectively move at twice the speed when we're half the scale)
*/
public var shouldMoveCompenstateForZoom:Boolean = true;
/*******************************************************************************************/
/**
* The main stage - so we can add event listeners
*/
protected var m_stage:Stage = null;
/**
* The camera that we're controlling
*/
protected var m_camera:Camera = null;
/**
* The direction that we're going to move in
*/
protected var m_moveDir:Point = null;
/*******************************************************************************************/
private var m_active:Boolean = true; // are the controls active?
/*******************************************************************************************/
/**
* Returns true if the CameraControls are active
*/
[Inline] public final function get active():Boolean { return this.m_active; }
[Inline] public final function set active( b:Boolean ):void
{
this.m_active = b;
}
/*******************************************************************************************/
/**
* Creates a new camera controller
* @param camera The camera that we're controlling
* @param stage The main stage
*/
public function CameraControls( camera:Camera, stage:Stage )
{
this.m_camera = camera;
this.m_stage = stage;
this.m_moveDir = new Point;
}
/**
* Destroys the CameraControls and clears it for garbage collection
*/
public function destroy():void
{
// remove from the update
// NOTE: it'll need to be removed from the Update
this.m_active = false;
// clear our properties
this.m_camera = null;
this.m_stage = null;
this.m_moveDir = null;
}
/**
* Updates the CameraControls every frame while they're active
* @param dt The delta time since the last update
*/
public function update( dt:Number ):void
{
// to be overridden
}
}
}
Colony mailing list
Again, this series is part of a tech update on my current project, Colony. If you want to get updated about it, you can sign up to the mailing list below.
Comments
Submit a comment