How to: Free look camera and a player mounted camera in 3D
by Russell Bishop · in Torque X 2D · 04/08/2008 (4:20 pm) · 18 replies
Note: Portions shamelessly stolen from the FPS demo, but greatly pared down and simplified to reduce clutter for newbies.
The key to all this is to create a Controller component that acts like a traffic cop for what object is currently hooked up to the player's input and what camera is generating the output. Any object that takes input and has a camera for output will implement the IControllable interface. We'll have two:
1. PlayerController - the regular component that deals with controlling our player, taking the player's input and responding to any non-physics actions. Things like switching the camera view, switching weapons, firing, etc.
2. TestCamera - a component that does a simple free-look camera, except with an input mapped to switch back to the player.
First, create and define a FreeLook test camera, both in the XML and in the code. You need to override FreeCameraComponent because your camera must implement IControllable, as well as adding buttons to the input map to switch back to the player's camera.
XML Object (replace the existing one in the starter XML).
Code in TestCamera.cs:
The key to all this is to create a Controller component that acts like a traffic cop for what object is currently hooked up to the player's input and what camera is generating the output. Any object that takes input and has a camera for output will implement the IControllable interface. We'll have two:
1. PlayerController - the regular component that deals with controlling our player, taking the player's input and responding to any non-physics actions. Things like switching the camera view, switching weapons, firing, etc.
2. TestCamera - a component that does a simple free-look camera, except with an input mapped to switch back to the player.
First, create and define a FreeLook test camera, both in the XML and in the code. You need to override FreeCameraComponent because your camera must implement IControllable, as well as adding buttons to the input map to switch back to the player's camera.
XML Object (replace the existing one in the starter XML).
<TorqueObject type="GarageGames.Torque.Core.TorqueObject" name="Camera">
<Components>
<CameraComponent type="MyGame.TestCamera" name="CameraComponent">
<FarDistance>3000</FarDistance>
<FOV>1.57</FOV>
</CameraComponent>
<SceneComponent type="GarageGames.Torque.T3D.T3DSceneComponent">
<Position>
<X>1024</X>
<Y>1024</Y>
<Z>300</Z>
</Position>
</SceneComponent>
</Components>
</TorqueObject>Code in TestCamera.cs:
/// <summary>
/// A freelook test camera
/// </summary>
public class TestCamera : FreeCameraComponent, IControllable
{
//======================================================
#region Public properties
public ControllerComponent Controller
{
get { return _controller; }
set { _controller = value; }
}
#endregion
//======================================================
#region Public methods
/// <summary>
/// Returns the input map used by the specified player.
/// </summary>
/// <param name="playerIndex">The player index of this camera.</param>
/// <returns>The input map used by this camera.</returns>
public InputMap GetInputMap(int playerIndex)
{
if (playerIndex != PlayerIndex)
return null;
return InputMap;
}
protected void ToggleControlObject(float val)
{
if (val > 0.0f)
_controller.UseBaseControlObject();
}
public void OnControlGained(int playerIndex)
{
Game.Instance.SceneView.Camera = this;
}
public void OnControlLost() { }
#endregion
//======================================================
#region Private, protected, internal methods
protected override void _SetupInputMap()
{
base._SetupInputMap();
int gamepadId = InputManager.Instance.FindDevice("gamepad" + PlayerIndex);
if (gamepadId >= 0)
{
InputMap.BindAction(gamepadId, (int)XGamePadDevice.GamePadObjects.Y, ToggleControlObject);
}
int keyboardId = InputManager.Instance.FindDevice("keyboard");
if (keyboardId >= 0)
InputMap.BindAction(keyboardId, (int)Keys.Y, ToggleControlObject);
}
#endregion
//======================================================
#region Private, protected, internal fields
ControllerComponent _controller;
#endregion
}
#2
04/08/2008 (4:20 pm)
Now the PlayerComponent, which sets up the input map. The ControlComponent will automatically handle moving around on the ground (see below).public class PlayerComponent : T3DInputComponent, IControllable
{
//======================================================
#region Public properties, operators, constants, and enums
public TestCamera FreeCamera
{
get { return _freeCamera; }
set { _freeCamera = value; }
}
#endregion
//======================================================
#region Public methods
public override void CopyTo(TorqueComponent obj)
{
base.CopyTo(obj);
//TODO: make sure to copy properties here
(obj as PlayerComponent).PlayerIndex = this.PlayerIndex;
}
#endregion
//======================================================
#region Private, protected, internal methods
protected override bool _OnRegister(TorqueObject owner)
{
if (!base._OnRegister(owner))
return false;
return true;
}
protected override void _PostRegister()
{
base._PostRegister();
_controllerComponent = Owner.Components.FindComponent<ControllerComponent>();
}
protected override void _RegisterInterfaces(TorqueObject owner)
{
base._RegisterInterfaces(owner);
// todo: register interfaces to be accessed by other components
// E.g.,
// Owner.RegisterCachedInterface("float", "interface name", this, _ourInterface);
}
protected override void _SetupInput(InputMap inputMap, int gamepad, int keyboard)
{
// move
inputMap.BindMove(gamepad, (int)XGamePadDevice.GamePadObjects.LeftThumbX, MoveMapTypes.StickAnalogHorizontal, 0);
inputMap.BindMove(gamepad, (int)XGamePadDevice.GamePadObjects.LeftThumbY, MoveMapTypes.StickAnalogVertical, 0);
// look
inputMap.BindMove(gamepad, (int)XGamePadDevice.GamePadObjects.RightThumbX, MoveMapTypes.StickAnalogHorizontal, 1);
inputMap.BindMove(gamepad, (int)XGamePadDevice.GamePadObjects.RightThumbY, MoveMapTypes.StickAnalogVertical, 1);
inputMap.BindAction(gamepad, (int)XGamePadDevice.GamePadObjects.Y, ToggleCamera);
// do keyboard
{
// wasd
inputMap.BindMove(keyboard, (int)Keys.D, MoveMapTypes.StickDigitalRight, 0);
inputMap.BindMove(keyboard, (int)Keys.A, MoveMapTypes.StickDigitalLeft, 0);
inputMap.BindMove(keyboard, (int)Keys.W, MoveMapTypes.StickDigitalUp, 0);
inputMap.BindMove(keyboard, (int)Keys.S, MoveMapTypes.StickDigitalDown, 0);
// arrows
inputMap.BindMove(keyboard, (int)Keys.Right, MoveMapTypes.StickDigitalRight, 1);
inputMap.BindMove(keyboard, (int)Keys.Left, MoveMapTypes.StickDigitalLeft, 1);
inputMap.BindMove(keyboard, (int)Keys.Up, MoveMapTypes.StickDigitalUp, 1);
inputMap.BindMove(keyboard, (int)Keys.Down, MoveMapTypes.StickDigitalDown, 1);
inputMap.BindAction(keyboard, (int)Keys.Y, ToggleCamera);
}
}
protected void ToggleCamera(float val)
{
if (val < 1.0f)
return;
_controllerComponent.SetControlObject(_freeCamera as IControllable);
}
protected override void _UpdateInput(Move move, float dt)
{
PlayerCameraComponent cam = Owner.Components.FindComponent<PlayerCameraComponent>();
if (cam != null)
{
cam.Update();
}
}
#endregion
//======================================================
#region Private, protected, internal fields
private ControllerComponent _controllerComponent;
private TestCamera _freeCamera;
#endregion
#region IControllable Members
public ControllerComponent Controller
{
get
{
return null;
}
set
{
}
}
public InputMap GetInputMap(int playerIndex)
{
return _inputMap;
}
public void OnControlGained(int playerIndex)
{
PlayerCameraComponent camera = Owner.Components.FindComponent<PlayerCameraComponent>();
camera.WorldViewIndex = FreeCamera.WorldViewIndex;
GUISceneview sceneView = Game.Instance.SceneView;
sceneView.Camera = camera;
}
public void OnControlLost()
{
}
#endregion
}
#3
Lastly, in BeginRun() we'll go ahead and kick off this game.
I think that's it.
edit: I've added this to the wiki so please feel free to go in and add more detail to the page. This is just a starting point, not a full tutorial.
04/08/2008 (4:20 pm)
Now the control/physics defined on the player in the XML. To change the physics of your player you would override the control component and states and define custom ones here in the XML that will map to those classes. Then those states can adjust things like movement speed, etc.<ControlComponent type="GarageGames.Torque.T3D.T3DGroundControlComponent">
<SceneGroupName>PlayerMesh</SceneGroupName>
<ControlStates>
<ControlState>
<Name>OnGround</Name>
<Type>GarageGames.Torque.T3D.OnGroundControlState</Type>
</ControlState>
<ControlState>
<Name>InAir</Name>
<Type>GarageGames.Torque.T3D.InAirControlState</Type>
</ControlState>
</ControlStates>
<StartState>InAir</StartState>
</ControlComponent>
<RigidComponent type="GarageGames.Torque.T3D.T3DRigidComponent">
<SceneGroupName>PlayerMesh</SceneGroupName>
<RenderCollisionBounds>false</RenderCollisionBounds>
<ResolveCollisions>true</ResolveCollisions>
<CollisionShapes>
<CollisionShape>
<Shape type="GarageGames.Torque.T3D.RigidCollision.CollisionSphereShape">
<Radius>5.0</Radius>
<Center>
<X>0.0</X>
<Y>0.0</Y>
<Z>0.0</Z>
</Center>
</Shape>
</CollisionShape>
</CollisionShapes>
<RotationScale>0.0</RotationScale>
<GravityScale>1.5</GravityScale>
<RigidManager nameRef="RigidManager" />
<RigidMaterial type="GarageGames.Torque.T3D.RigidCollision.RigidMaterial">
<Restitution>0.0</Restitution>
</RigidMaterial>
</RigidComponent>Lastly, in BeginRun() we'll go ahead and kick off this game.
private GUISceneview _sceneView;
public GUISceneview SceneView
{
get { return _sceneView; }
}
protected override void BeginRun()
{
base.BeginRun();
// load our scene objects from XML.
SceneLoader.Load(@"data\levels\levelData.txscene");
//set sceneview
_sceneView = TorqueObjectDatabase.Instance.FindObject<GUISceneview>("DefaultSceneView");
//grab our free camera, we'll fake playerindex for now
TestCamera freeCamera = TorqueObjectDatabase.Instance.FindObject<TestCamera>("CameraComponent");
freeCamera.PlayerIndex = 1;
//get player template and clone it
TorqueObject template = TorqueObjectDatabase.Instance.FindObject<TorqueObject>("PlayerTemplate");
TorqueObject player = template.CloneT();
player.Name = "Player1";
//setup components on instance before we register it
ControllerComponent controller = player.Components.FindComponent<ControllerComponent>();
PlayerComponent playerComponent = player.Components.FindComponent<PlayerComponent>();
PlayerCameraComponent playerCamera = player.Components.FindComponent<PlayerCameraComponent>();
controller.BaseControlObject = playerComponent;
controller.PlayerIndex = 1;
playerComponent.PlayerIndex = 1;
//now register
if (!TorqueObjectDatabase.Instance.Register(player))
{
System.Diagnostics.Debug.WriteLine("Failed to register!");
}
//then setup control
controller.UseBaseControlObject();
//make sure gui is prepared
GUICanvas.Instance.OnPreRender();
//assign freecam to player
playerComponent.FreeCamera = freeCamera;
//now assign camera to start off with
_sceneView.Camera = playerCamera;
}I think that's it.
edit: I've added this to the wiki so please feel free to go in and add more detail to the page. This is just a starting point, not a full tutorial.
#4
"The operation was aborted. You may not modify a resource that has been set on a device, or after it has been used within a tiling bracket."
I thought I had it fixed but apparently not. I'm not sure what the problem is.
04/08/2008 (5:59 pm)
Still occasionally getting this message:"The operation was aborted. You may not modify a resource that has been set on a device, or after it has been used within a tiling bracket."
I thought I had it fixed but apparently not. I'm not sure what the problem is.
#5
John K.
04/08/2008 (11:20 pm)
Excellent write-up, Russell! This exception is thrown by XNA, usually when a vertex buffer is being improperly recycled on a SetData() call. It could be an engine bug. Are you able to dump the stack trace in this thread next time you see it?John K.
#6
"The operation was aborted. You may not modify a resource that has been set on a device, or after it has been used within a tiling bracket."
,when trying to use the RAWTerrainData method for terrains.
Exception Details:-
System.InvalidOperationException was unhandled
Message="The operation was aborted. You may not modify a resource that has been set on a device, or after it has been used within a tiling bracket."
Source="Microsoft.Xna.Framework"
StackTrace:
at Microsoft.Xna.Framework.Helpers.GetExceptionFromResult(UInt32 result)
at Microsoft.Xna.Framework.Graphics.Texture2D.CopyData[T](Int32 level, Nullable'1 rect, T[] data, Int32 startIndex, Int32 elementCount, UInt32 options, Boolean isSetting)
at Microsoft.Xna.Framework.Graphics.Texture2D.SetData[T](Int32 level, Nullable'1 rect, T[] data, Int32 startIndex, Int32 elementCount, SetDataOptions options)
at GarageGames.Torque.Materials.ClipMap.ClipMapUniqueImageCache.DoRectUpdate(Int32 mipLevel, ClipStackEntry stackEntry, RectangleI srcRegion, RectangleI dstRegion)
at GarageGames.Torque.Materials.ClipMap.ClipMap.Recenter(Vector2 position)
at GarageGames.Torque.Materials.ClipMap.ClipMap.UpdateAnimation(Single dt)
at GarageGames.Torque.Sim.ProcessList.UpdateAnimation(Single ms)
at GarageGames.Torque.XNA.TorqueEngineComponent._UpdateSim(String eventName, Single elapsed)
at GarageGames.Torque.Core.TorqueEvent'1._Trigger(Delegate d)
at GarageGames.Torque.Core.TorqueEventManager._TriggerEvent(TorqueEventBase ev)
at GarageGames.Torque.Core.TorqueEventManager.MgrProcessEvents()
at GarageGames.Torque.Core.TorqueEventManager.ProcessEvents()
at GarageGames.Torque.XNA.TorqueEngineComponent.Update(GameTime gameTime)
at Microsoft.Xna.Framework.Game.Update(GameTime gameTime)
at Microsoft.Xna.Framework.Game.Tick()
at Microsoft.Xna.Framework.Game.HostIdle(Object sender, EventArgs e)
at Microsoft.Xna.Framework.GameHost.OnIdle()
at Microsoft.Xna.Framework.WindowsGameHost.ApplicationIdle(Object sender, EventArgs e)
at System.Windows.Forms.Application.ThreadContext.System.Windows.Forms.UnsafeNativeMethods.IMsoComponent.FDoIdle(Int32 grfidlef)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Microsoft.Xna.Framework.WindowsGameHost.Run()
at Microsoft.Xna.Framework.Game.Run()
at StarterGame.Game.Main() in C:\Program Files\GarageGames\Torque X 2.0\v2.0.0.0\Demos\FPS\Game.cs:line 67
04/09/2008 (8:06 pm)
I'm Getting the same message :-"The operation was aborted. You may not modify a resource that has been set on a device, or after it has been used within a tiling bracket."
,when trying to use the RAWTerrainData method for terrains.
Exception Details:-
System.InvalidOperationException was unhandled
Message="The operation was aborted. You may not modify a resource that has been set on a device, or after it has been used within a tiling bracket."
Source="Microsoft.Xna.Framework"
StackTrace:
at Microsoft.Xna.Framework.Helpers.GetExceptionFromResult(UInt32 result)
at Microsoft.Xna.Framework.Graphics.Texture2D.CopyData[T](Int32 level, Nullable'1 rect, T[] data, Int32 startIndex, Int32 elementCount, UInt32 options, Boolean isSetting)
at Microsoft.Xna.Framework.Graphics.Texture2D.SetData[T](Int32 level, Nullable'1 rect, T[] data, Int32 startIndex, Int32 elementCount, SetDataOptions options)
at GarageGames.Torque.Materials.ClipMap.ClipMapUniqueImageCache.DoRectUpdate(Int32 mipLevel, ClipStackEntry stackEntry, RectangleI srcRegion, RectangleI dstRegion)
at GarageGames.Torque.Materials.ClipMap.ClipMap.Recenter(Vector2 position)
at GarageGames.Torque.Materials.ClipMap.ClipMap.UpdateAnimation(Single dt)
at GarageGames.Torque.Sim.ProcessList.UpdateAnimation(Single ms)
at GarageGames.Torque.XNA.TorqueEngineComponent._UpdateSim(String eventName, Single elapsed)
at GarageGames.Torque.Core.TorqueEvent'1._Trigger(Delegate d)
at GarageGames.Torque.Core.TorqueEventManager._TriggerEvent(TorqueEventBase ev)
at GarageGames.Torque.Core.TorqueEventManager.MgrProcessEvents()
at GarageGames.Torque.Core.TorqueEventManager.ProcessEvents()
at GarageGames.Torque.XNA.TorqueEngineComponent.Update(GameTime gameTime)
at Microsoft.Xna.Framework.Game.Update(GameTime gameTime)
at Microsoft.Xna.Framework.Game.Tick()
at Microsoft.Xna.Framework.Game.HostIdle(Object sender, EventArgs e)
at Microsoft.Xna.Framework.GameHost.OnIdle()
at Microsoft.Xna.Framework.WindowsGameHost.ApplicationIdle(Object sender, EventArgs e)
at System.Windows.Forms.Application.ThreadContext.System.Windows.Forms.UnsafeNativeMethods.IMsoComponent.FDoIdle(Int32 grfidlef)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Microsoft.Xna.Framework.WindowsGameHost.Run()
at Microsoft.Xna.Framework.Game.Run()
at StarterGame.Game.Main() in C:\Program Files\GarageGames\Torque X 2.0\v2.0.0.0\Demos\FPS\Game.cs:line 67
#7
04/09/2008 (8:46 pm)
This is tres cool!
#8
Basically *.GetData() incorrectly tries to obtain a write lock when it isn't really necessary. See this thread:
http://forums.xna.com/thread/35536.aspx
One of the XNA devs, shawn, identifies the workaround, which is to null out the texture or vertice or whatever after drawing but before calling GetData().
At the point the exception is thrown in the pipeline I have no idea what index the texture was placed in, so I can't just clear it necessarily. Someone would need to dig through the code to trace it out.
edit: The stack trace is similar to the one posted IIRC; it was definitely the clip map causing it.
04/10/2008 (3:15 pm)
I've done some research on that error and it appears that it is technically a bug in XNA at this time, though I don't know if Microsoft has issued a fix yet or not.Basically *.GetData() incorrectly tries to obtain a write lock when it isn't really necessary. See this thread:
http://forums.xna.com/thread/35536.aspx
One of the XNA devs, shawn, identifies the workaround, which is to null out the texture or vertice or whatever after drawing but before calling GetData().
At the point the exception is thrown in the pipeline I have no idea what index the texture was placed in, so I can't just clear it necessarily. Someone would need to dig through the code to trace it out.
edit: The stack trace is similar to the one posted IIRC; it was definitely the clip map causing it.
#9
I was able to resolve it by updating the PlayerComponent's OnControlGained method:
camera.WorldViewIndex = FreeCamera.WorldViewIndex;
04/10/2008 (6:52 pm)
OK it looks like the ClipMap caches are the problem if there are multiple WorldViewIndexes where they haven't been setup previously. ClipMapEffect tries to call _GenerateDuplicateClipMap in the middle of a render pass, which tries to access the texture, which is (falsely) locked by XNA. I was able to resolve it by updating the PlayerComponent's OnControlGained method:
camera.WorldViewIndex = FreeCamera.WorldViewIndex;
#10
Any chance of getting your complete source code for this(especially the xml file), I'm having some problems getting it going.
Thanks
05/18/2008 (6:25 am)
Hi there,Any chance of getting your complete source code for this(especially the xml file), I'm having some problems getting it going.
Thanks
#11
I am trying to follow along with your tutorial here but I have run into a snag. I "believe" that I have entered the data/code as instructed but when I debug my code, I cannot find the TestCamera definition in the XML file. When I debug into the .FindObject<>() function, I look at the objects in the collection and I see the TorqueObject: "Camera" but this object only has a single Component and the function does not find the CameraComponent: "ComponentCamera".
Could you perhaps send me a copy of the .txscene file for this project? Is there a good resource on .txscene heirarchy/structure, because I found it a little confusing where to put what pieces exactly?
Thanks for your time!
08/06/2008 (8:21 pm)
Hello,I am trying to follow along with your tutorial here but I have run into a snag. I "believe" that I have entered the data/code as instructed but when I debug my code, I cannot find the TestCamera definition in the XML file. When I debug into the .FindObject<>() function, I look at the objects in the collection and I see the TorqueObject: "Camera" but this object only has a single Component and the function does not find the CameraComponent: "ComponentCamera".
Could you perhaps send me a copy of the .txscene file for this project? Is there a good resource on .txscene heirarchy/structure, because I found it a little confusing where to put what pieces exactly?
Thanks for your time!
#12
Below is what I used to get it (note, my testcamera is freelookcamera)
for the testCamera in the xml file, I am sure this would do it:
08/06/2008 (8:52 pm)
I actually was using this quite a bit to build my own camera toggle peice, which I got working finally. Below is what I used to get it (note, my testcamera is freelookcamera)
TorqueObject freeCamera = TorqueObjectDatabase.Instance.FindObject<TorqueObject>("FreeCamera");
FreeLookCamera freeLookCamera = freeCamera.Components.FindComponent<FreeLookCamera>();for the testCamera in the xml file, I am sure this would do it:
TorqueObject testCamera = TorqueObjectDatabase.Instance.FindObject<TorqueObject>("Camera");
TestCamera testCameraComponent = testCamera.Components.FindComponent<TestCamera>();
#13
I don't quite understand why the isn't showing up in the object's component container using the abbreviated definition above. I have this TorqueObject defined below the definition and above the tags, is this correct?
I have even checked my PlayerTemplate (cut and pasted from tutorial source) and the doesn't exist in its component container; it only has a and a . It is my understanding that all "components" are added to this container, is this correct?
08/07/2008 (5:20 am)
I tried that as well but for some reason (using the example above) the testCamera object's component container only has one component which is the T3DSceneComponent. <TorqueObject type="GarageGames.Torque.Core.TorqueObject" name="Camera">
<Components>
<CameraComponent type="MyGame.TestCamera" name="CameraComponent">
...
</CameraComponent>
<SceneComponent type="MyGame.Torque.T3D.T3DSceneComponent">
...
</SceneComponent>
</Component>
</TorqueObject>I don't quite understand why the
I have even checked my PlayerTemplate (cut and pasted from tutorial source) and the
#14
This is the xml structure I am using.
08/07/2008 (6:43 am)
Your placement is correct of the xml. My guess then, is usually when that occurs, there is an error during the instantion of the component. Check your output in the bottom panes when debugging, it will usually say what the error is (I am guessing onRegister is failing). The "MyGame.Torque.T3D.T3DSceneComponent" of your scenecomponenet seems off as well, relative to "GarageGames.Torque.T3D.T3DSceneComponent". This is the xml structure I am using.
<Objects>
<TorqueObject type="GarageGames.Torque.Core.TorqueObject" name="FreeCamera">
<IsTemplate>false</IsTemplate>
<Components>
<SceneComponent type="GarageGames.Torque.T3D.T3DSceneComponent">
<Position>
<X>1024</X>
<Y>1024</Y>
<Z>300</Z>
</Position>
</SceneComponent>
<FreeCameraComponent type="StarterGame3D.FreeLookCamera">
<FarDistance>1000</FarDistance>
<FOV>1.57</FOV>
</FreeCameraComponent>
</Components>
</TorqueObject>
<Terrain type="GarageGames.Torque.T3D.XTerrain" name="Terrain">
...
</Terrain>
<Player type="StarterGame3D.PlayerComponent" name="Player">
....
<Components>
.....
<CameraComponent type="StarterGame3D.IsometricCamera" name="CameraComponent">
<SceneGroupName>PlayerMesh</SceneGroupName>
<FarDistance>3000</FarDistance>
<FOV>1.57</FOV>
<PositionOffset>
<X>0</X>
<Y>-20</Y>
<Z>35</Z>
</PositionOffset>
<RotationOffset>
<X>-45</X>
<Y>0</Y>
<Z>0</Z>
</RotationOffset>
<RotatedPositionOffset>
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</RotatedPositionOffset>
</CameraComponent>
</Components>
</Player>
</Objects>
</TorqueSceneData>
#15
Thank you very much!
08/07/2008 (9:38 am)
Thank you for your help. I never checked the debug output during this little trial. I had the wrong namespace for my serialized objects in my XML file so it was ignoring the components as non-instantiable during the .txscene load process. I probably wouldn't have found it except for your XML post above...Thank you very much!
#16
08/07/2008 (12:29 pm)
Thats good to hear Douglas! Glad its working out, it helped me a ton more to understand how TorqueX handles cameras and how to switch back and forth. I dont use the controllable interface per se though, since in effect, all its doing is setting the PlayerManager.Instance.GetPlayer(playerIndex).ControlObject and Inputmap when you toggle.
#17
The _SetupInputMap function for my TestCamera is firing when the camera is deserialized from the txscene and has a PlayerIndex of 0. However, the _SetupInputMap for my PlayerComponent doesn't fire until after I register the player with the database.
Is the solution for this issue basically what the FPS demo does and make the TestCamera a template and instantiate it manually in code so I can reference the proper PlayerIndex?
Are Player indices referenced starting at 1 or 0?
Is there a way I can force a controller to a particular PlayerIndex so only valid players can access a controller? This doesn't seem to be an issue for the keyboard, though I'm not sure why...
08/07/2008 (6:52 pm)
I hate to ask more questions here but I'm stumped on another problem. I'm now testing the tutorial application using both the keyboard and a gamepad. I must be missing something vital here because the FPS demo application works fine but when I execute the tutorial app, my gamepadid for the PlayerComponent is different than it is in the TestCamera Component when we look it up by PlayerIndex in their respective _SetupInputMap functions.The _SetupInputMap function for my TestCamera is firing when the camera is deserialized from the txscene and has a PlayerIndex of 0. However, the _SetupInputMap for my PlayerComponent doesn't fire until after I register the player with the database.
Is the solution for this issue basically what the FPS demo does and make the TestCamera a template and instantiate it manually in code so I can reference the proper PlayerIndex?
Are Player indices referenced starting at 1 or 0?
Is there a way I can force a controller to a particular PlayerIndex so only valid players can access a controller? This doesn't seem to be an issue for the keyboard, though I'm not sure why...
#18
. I also use 0 as well. My understanding is that each Player in the PlayerManager (up to MaxPlayers), has a control object, such as a camera, or a playercomponent, an input map that has all the bindings, and a movemanager that associates it all together. All the FPS demo is doing is swapping who is at PlayerManager.GetPlayer(playerIndex).
If you look at the Controller code :
All it is doing is setting the control object and the inputmap for whatever you are moving control to, and then calling the OnControlLost() for the old control object and then calling the OnControlGained() on the new control object. You should be able to associate different gamepads with different playerindexes aka GamePad0 to playerindex of 0, and gamepad1 to playerindex of 1. Not sure if this helps, but figure I would give it a shot :)
08/07/2008 (7:34 pm)
I believe the player references are zero based, since PlayerManager.Player is just a ListIf you look at the Controller code :
public void SetControlObject(IControllable obj, InputMap input)
{
if (input == null || obj == _currentControlObject)
return;
_previousControlObject = _currentControlObject;
_previousInputMap = PlayerManager.Instance.GetPlayer(PlayerIndex).InputMap;
_currentControlObject = obj;
_currentInputMap = input;
PlayerManager.Instance.GetPlayer(PlayerIndex).ControlObject = (obj as TorqueComponent).Owner;
PlayerManager.Instance.GetPlayer(PlayerIndex).InputMap = input;
if (_previousControlObject != null)
_previousControlObject.OnControlLost();
_currentControlObject.OnControlGained(PlayerIndex);
}All it is doing is setting the control object and the inputmap for whatever you are moving control to, and then calling the OnControlLost() for the old control object and then calling the OnControlGained() on the new control object. You should be able to associate different gamepads with different playerindexes aka GamePad0 to playerindex of 0, and gamepad1 to playerindex of 1. Not sure if this helps, but figure I would give it a shot :)
Torque Owner Russell Bishop
Default Studio Name
<Player type="GarageGames.Torque.Core.TorqueObject" name="PlayerTemplate"> <IsTemplate>true</IsTemplate> <ObjectType> <object objTypeRef="Player" /> </ObjectType> <Components> <ControllerComponent type="MyGame.ControllerComponent" /> <PlayerComponent type="MyGame.PlayerComponent"> <SceneGroupName>PlayerMesh</SceneGroupName> <PlayerIndex>1</PlayerIndex> </PlayerComponent> <CameraComponent type="MyGame.PlayerCameraComponent"> <SceneGroupName>PlayerMesh</SceneGroupName> <TransformInterfaceName>cam</TransformInterfaceName> <CameraSpeed>50</CameraSpeed> <FarDistance>1000</FarDistance> <FOV>1.57</FOV> <BoundaryObjectTypes> <object objTypeRef="Terrain" /> <object objTypeRef="StaticGeometry" /> </BoundaryObjectTypes> <RigidManager nameRef="RigidManager" /> <PositionOffset> <X>0.0</X> <Y>-9.0</Y> <Z>1</Z> </PositionOffset> <RotationOffset> <X>0</X> <Y>0</Y> <Z>0</Z> </RotationOffset> </CameraComponent> </Components> </Player>NOTE: Get the IControllable interface and ControllerComponent from the FPS starter demo, I used them essentially unchanged. They're in the player folder.
PlayerCameraComponent. Notice that I am exposing an Update() method that will make the camera update its position. The FPS demo camera seems to work as a side-effect of the fact that the view angle is constantly being updated, which causes T3DCameraComponent to set the TransformDirty flag and recalculate the transform matrix.
But in my attempts I wasn't doing that since I don't have a view angle, so my camera was just stationary in the world and didn't appear to be mounted to the vehicle. I just assumed that any T3DCameraComponent derived object would automatically track its associated owner, similar to the way the control/physics automatically deals with moving, but it doesn't.
/// <summary> /// Third person camera /// </summary> public class PlayerCameraComponent : T3DCameraComponent { //====================================================== #region Public methods public override void CopyTo(TorqueComponent obj) { base.CopyTo(obj); PlayerCameraComponent obj2 = (PlayerCameraComponent)obj; } public void Update() { this.RotatedPositionOffset = RotatedPositionOffset + Vector3.Zero; } #endregion //====================================================== #region Private, protected, internal methods protected override bool _OnRegister(TorqueObject owner) { if (!base._OnRegister(owner)) return false; return true; } protected override void _UpdateTransform() { base._UpdateTransform(); } #endregion }