Torque 2D/GenreTutorials/PlatformerCamera
From TDN
[edit] IntroductionA camera systems features are usually specific to the game for which it is being created. For example: The camera in Super Mario Brothers is very different from the camera in Sonic the Hedgehog. Because of this, we will be designing a system in this tutorial that can do anything you might want it to. So, you can just grab the parts out of it that you want, or, implement them all right along with me and just use what you need.
|
|
[edit] ImplementationMost of the code in this tutorial is going to be created in a new file called camera.cs. So create this file now and add its exec statement to InitializeT2D.cs:
exec("./camera.cs");
While still in game.cs, add this to the setupT2DScene function between the calls to createPlayer and createLevel: createCamera(); We are going to create the camera as a script object, which is basically a class in TorqueScript. This will allow us to define methods for our camera that will make handling it simpler and cleaner. Here is the createCamera function definition that you should put in camera.cs:
function createCamera()
{
$camera = new ScriptObject()
{
class = Camera;
};
}
Pretty compact, but powerful. We are creating a new ScriptObject of class camera and saving it as $camera. The class attribute allows us to define functions like this:
function Camera::functionName(%this)
{
}
That can be called like this: $camera.functionName(); So, let’s define some of these functions:
function Camera::onAdd(%this)
{
%this.camera = new t2dSceneObject()
{
scenegraph = t2dscene;
};
%this.setTrackHeight(true);
%this.setTrackingForce(0);
%this.setFacePlayer(false);
%this.setOffset("20 -15");
%this.setTarget($player);
}
The Camera::onAdd function will be called by the engine anytime a new object of class Camera is created. In this case, it will be called right after our createCamera function. The first parameter of the function (%this) and of all functions that are methods of a ScriptObject, is a reference to the object that the function was called on. In other words, it is the same as $camera.
function Camera::setTrackHeight(%this, %trackHeight)
{
%this.trackHeight = %trackHeight;
}
function Camera::setTrackingForce(%this, %force)
{
%this.trackingForce = %force;
sceneWindow2D.mount(%this.camera, "0 0", %force, true);
}
function Camera::setFacePlayer(%this, %face)
{
%this.facePlayer = %face;
}
function Camera::setTarget(%this, %target)
{
%this.target = %target;
}
function Camera::setOffset(%this, %offset)
{
%this.xOffset = getWord(%offset, 0);
%this.yOffset = getWord(%offset, 1);
}
function Camera::setTrapObject(%this, %trap)
{
%this.trapObject = %trap;
if (%trap)
%this.target.setWorldLimit(CLAMP, %this.viewArea);
else
%this.target.setWorldLimit(OFF);
}
function Camera::setLimits(%this, %area)
{
%this.viewArea = %area;
sceneWindow2D.setViewLimitOn(%area);
}
function Camera::setAutoScroll(%this, %dir)
{
%this.autoScroll = true;
%this.scrollDirection = t2dVectorScale(%dir, 0.001);
}
function Camera::stopAutoScroll(%this, %dir)
{
%this.autoScroll = false;
}
Really all these functions do is set parameters that are used in the update camera function, with the exception of the calls to setWorldLimit and mount. The call to mount in setTrackingForce tells the scene window to follow our camera around. The setWorldLimit calls bind the target object to the area defined in Camera::setLimits. Here is a list of the functions and their purpose:
function Camera::onRemove(%this)
{
if (isObject(%this.camera))
%this.camera.delete();
}
Now we need to use all of our new parameters to actually move the camera around. In game.cs, in the updateScene function, add this after the call to updatePlayer: $camera.update(); And back in camera.cs, add this function definition:
function Camera::update(%this)
{
if (%this.autoScroll)
{
%pos = t2dVectorAdd(%this.camera.getPosition(), %this.scrollDirection);
%this.camera.setPosition(%pos);
if (%this.trapObject)
{
%area = sceneWindow2D.getcurrentCameraArea();
%x = getWord(%area, 0);
%y = getWord(%area, 1);
%width = getWord(%area, 2);
%height = getWord(%area, 3);
%this.target.setWorldLimit(CLAMP, %x SPC %y SPC (%x + %width) SPC (%y + %height));
}
}
else
{
%this.camera.setPositionX(%this.target.getPositionX() + %this.xOffset);
if (%this.trackHeight)
%this.camera.setPositionY(%this.target.getPositionY() + %this.yOffset);
if (%this.facePlayer)
{
%move = $moveRight - $moveLeft;
if ((%move * %this.xOffset) < 0)
%this.xOffset = -%this.xOffset;
}
}
}
This function will be called every frame to update the position of the camera. The first if statement determines if the camera is auto scrolling or not, as set by Camera::setAutoScroll. If it is scrolling, the position of the camera is moved by the amount that we stored in scrollDirection. The next section updates the world limits of the object that is being tracked if trapObject is true so the object can’t leave the bounds of the camera area.
$camera.setLimits(%layer.getArea()); This is telling the camera to never leave the area covered by the tile layer. Since we want the player to be confined to the same area as the camera, we can just call this in the resetPlayer function in player.cs: $camera.setTrapObject(true); Now the player will be trapped in the camera's view area. |
|
[edit] UsageAnytime during the game, you can change any of the camera’s parameters and it will update accordingly. You do this by calling $camera.functionName. So, if you wanted to set the offset of the camera, you would call $camera.setOffset("10 10"); Here are a couple of examples for when you might want to change something on the fly.
$camera.setOffset("-10 25");
or: $camera.setTrackingForce(1); |
|
[edit] ExpansionThis system should be easily expandable. Some things you might want to add: Zooming in and out, path following, or edge scrolling (like Mario 2). All you would need to do is add a method to the Camera class, and update the Camera::update function to use the new stuff.
|



