Creating a Torque X 3D RTS Camera
by John Kanalakis · 06/23/2009 (9:25 pm) · 6 comments
An interesting question came up about creating an RTS camera for Torque X. Instead of a simple response, I decided to write a detailed How-To posting for all those Torque X followers out there. I'm an author, I can't help it. ;)
Again, Torque X is a component-driven framework, so nearly all problems can be solved with a custom component attached to something. In this case, we'll create a new custom component, called T3DRtsCameraComponent and then attach it to a blank TorqueObject.
Defining the RTS Camera
For the sake of this post, I'm defining the RTS camera as one that does not change elevation, maintains a fixed camera angle pointing, and moves forward/backward/left/right. There are a lot of RTS games that add a lot more, like zooming, panning, etc., but this is just a quick post to get you started.Create the Custom Camera Component
To implement an RTS camera in Torque X, the best method is to create a custom 3D component. You can download the completed component from here. (remember to rename the file from .txt to .cs) To create the component from scratch, open your project in Visual Studio and then right-click your Game project within the Solution Explorer window and choose Add New Item.
Choose the T3DComponent template and then set the new component's name to T3DRtsCameraComponent.cs.
In the new class, change the inheritance to the following:
T3DRtsCameraComponent : T3DCameraComponent, ITickObjectThis will inherit the bulk of the camera rendering code from the existing 3D camera component. Now, we just add the behaviors we want. Start with a few tweakable properties, using my new favorite auto-properties.
public float CameraAngleDegrees { get; set; }
public float CameraMoveSpeed { get; set; }
public int PlayerIndex { get; set; }
public InputMap CameraInputMap { get; set; }The only bummer to auto-properties is the lack of default initialization. This can be accomodated with a class constructor.public T3DRtsCameraComponent()
{
CameraMoveSpeed = 2.5f;
CameraAngleDegrees = -45;
} The _OnRegister() method will need to request tick processing callbacks, so add a call to the AddTickCallback() method. Also, we need to setup the InputMap to respond to keyboard processing, but that can go in another method.
protected override bool _OnRegister(TorqueObject owner)
{
if (!base._OnRegister(owner))
return false;
ProcessList.Instance.AddTickCallback(owner, this);
_SetupInputMap();
return true;
} The _SetupInputMap() method specifies the key bindings to move the camera around. I'm just using the Up, Down, Left, Right keys to move the camera around. You can change the key mappings or even add a mapping to respond to the Xbox game controller.
protected virtual void _SetupInputMap()
{
if (PlayerManager.Instance.GetPlayer(PlayerIndex).ControlObject == null)
{
PlayerManager.Instance.GetPlayer(PlayerIndex).ControlObject = Owner;
CameraInputMap = PlayerManager.Instance.GetPlayer(PlayerIndex).InputMap;
}
else
{
CameraInputMap = new InputMap();
}
int keyboardId = InputManager.Instance.FindDevice("keyboard");
if (keyboardId >= 0)
{
CameraInputMap.BindMove(keyboardId, (int)Keys.Up, MoveMapTypes.StickDigitalUp, 0);
CameraInputMap.BindMove(keyboardId, (int)Keys.Down, MoveMapTypes.StickDigitalDown, 0);
CameraInputMap.BindMove(keyboardId, (int)Keys.Left, MoveMapTypes.StickDigitalLeft, 0);
CameraInputMap.BindMove(keyboardId, (int)Keys.Right, MoveMapTypes.StickDigitalRight, 0);
}
} With the input map ready, it's time for the real code. The important details happen in the _UpdateTransform() and ProcessTick() methods. Let's start with the ProcessTick() method. In addition to receiving a tick callback every couple of milliseconds, this method also receives a Move structure. When we setup the input map, we associated the arrow keys with different MoveMapTypes. As result, anytime the arrow keys are pressed, the Move structure will capture those inputs. The bottom-line is that we can check the Move structure to see which arrows have been pressed - and it also works when the Xbox game controllers are connected. In the ProcessTick() method, we simply take the amount of X and Y pressed and then multiply that value by a Speed variable. The product is all dropped into a Vector3 object that increments the X,Y,Z position of the camera.
public void ProcessTick(Move move, float elapsed)
{
if (move == null)
return;
if (move.Sticks.Count > 0)
{
Vector3 moveDirection = new Vector3((move.Sticks[0].X * CameraMoveSpeed), (move.Sticks[0].Y * CameraMoveSpeed), 0);
SceneGroup.Position += moveDirection;
}
} Next, the _UpdateTransform() is called by the scene graph when the transform of an object (such as our camera) is updated. We'll use this method to set the downward angle of the camera object. Remember that you can use the public property to easily adjust the angle of the camera.
protected override void _UpdateTransform()
{
SceneGroup.Rotation = Quaternion.CreateFromYawPitchRoll(0, MathHelper.ToRadians(CameraAngleDegrees), 0);
_transform = SceneGroup.Transform;
}Set the New Camera Component in the Level File
Now that we have a working RTS camera component, we need to change the level data file to use it. By default, each new Torque X 3D project creates a camera that uses the FreeCameraComponent. We need to change that file to use our new RTS camera. Open the levelData.txscene file and replace:<CameraComponent type="GarageGames.Torque.T3D.FreeCameraComponent" name="CameraComponent" />
with
<CameraComponent type="StarterGame3D.T3DRtsCameraComponent" name="CameraComponent" />
Referencing the component in Code
If you need to get a reference to the camera component, say to move the camera around programatically, you can use the TorqueObjectDatabase to find the RTS camera component.T3DRtsCameraComponent camera = TorqueObjectDatabase.Instance.FindObject<T3DRtsCameraComponent>("CameraComponent");
sceneView.Camera = camera;Here's how the RTS camera looks in action, combined with the water surface material I described in the last post.
Since the RTS camera is just a component, we can set the initial position and altitude in the levelData.txscene file. Just set the Position Z value that belongs to the T3DSceneComponent attached. There's a lot more that can be done with this camera to be more full-featured, such as zomming, panning around, mapping the input map to the Xbox game controller, but this is a good starting point for adding such code.
Again, you can download the component code from here.
John K.
www.envygames.com
About the author
John Kanalakis is the owner of EnvyGames, an independent game development studio in Silicon Valley that produces games and tools for Xbox 360, Windows, and the Web.
#2
06/24/2009 (12:33 am)
GREAT STUFF! Very cool of you to do this John. Thanks.
#4
John K.
www.envygames.com
06/24/2009 (12:58 am)
Thanks everyone. Good catch Tuomas, ironic that I mispell my first name as opposed to that long last name. ;)John K.
www.envygames.com
#5
Brian
06/24/2009 (4:58 pm)
I'm starting to wonder if John is a real person or if Torque X became self-aware some time between Torque X 1.0 and 2.0... Awesome stuff. Adding to community links.Brian
#6
06/25/2009 (8:48 pm)
Thanks John - your book should be in my mailbox tomorrow, can't wait to check it out so I can get fully started on my game.
Associate OmegaDog
Looking forward to your next blog!