Game Development Community

Control Player while camera is in Orbit mode

by RealDecoy Inc · in Torque 3D Professional · 03/14/2010 (9:51 am) · 21 replies

Ok I am trying to do a topdown shooter. My goal is to do as much of the code in torquescript as possible. Only resorting to C++ changes if absolutely needed. (making it much more agile to port between versions of the engine).

Anyway, I can control my player great in first person camera mode, and can toggle to orbital camera mode, which I have tweaked to give a nice static angle topdown view. But when I'm in that mode I loose all control of the player.

If I toggle back, I regain control.

I'm using orbital camera centered on the controlobject, and set as locked (so that the player has no angle control of the camera itself, fixed 100% top down view).

everything works great, just can't get the topdown view working together with control of the player.

I am pretty sure I can do this with a minor C++ mod in camera.c but as I said above I want to avoid that if possible... So I ask, does anyone know a way that I can do that entirely in torquescript? Or am I stuck modding the code at this point? (I have a code license, just as I said above, trying to keep patches/mods to the engine itself to an absolute minimum).

Thanks!
Page «Previous 1 2
#1
04/20/2010 (6:41 am)
Hey sorry for the double post, but does anyone have any idea on this? It's been sitting here un-answered for over a month now.

Thanks!
#2
04/20/2010 (7:35 am)
You can have separate camera and control objects on your gameConnections. Check the setCameraObject() method on GameConnection objects. No need for source code changes.
#3
04/20/2010 (9:01 am)
the problem with that is the camera mode auto changes your control object.
#4
04/20/2010 (11:01 am)
You mean when you use the ALT+C shortcut? That's easy to deal with: modify the script function ToggleCamera() so it matches your controlObject/cameraObject configuration.
#5
04/21/2010 (9:39 am)
Interesting. I'm hoping to dig back into this problem in a day or two, so I'll take a look at your suggestions, and post back with my results.

Thanks!
#6
04/30/2010 (8:02 pm)
Ok I've given this a shot, unfortunately when I try using setControlObject to %client.player it toggles the camera to the player as well. I want to leave the camera in third person mode, and just set the control object to the player.

example:
function serverCmdEnableCustomCamera(%client)
{
   %client.camera.setOrbitObject(%client.player, mDegToRad(90) @ " 0 0", 20, 100, 80, false, "0 0 0", true);
   //For some reason the 5th parameter of setOrbitObject doesn't work (sets current distance)
   //It always defaults to max distance (4th parameter).
   //So we'll manually override by moving the camera to a position relative to the player position.
   %client.camera.position = VectorAdd(%client.player.position, "0 0 80");   
   %client.player.setVelocity("0 0 0");
   %client.setControlObject(%client.player);
   %client.setCameraObject(%client.camera);
}

In that code, when I call %client.setControlObject(%client.player), it puts the camera into first person mode automatically. I've tried with and without the setcameraobject call, no difference either way.

Any thoughts?
#7
05/01/2010 (10:24 am)
From what I can see in GameConnection::setControlObject (in gameConnection.cpp) it looks like there is some code in there to revert the camera object to the controlobject under certain conditions.

void GameConnection::setControlObject(GameBase *obj)
{
   if(mControlObject == obj)
      return;

   if(mControlObject && mControlObject != mCameraObject)
      mControlObject->setControllingClient(0);

   if(obj)
   {
      // Nothing else is permitted to control this object.
      if (GameBase* coo = obj->getControllingObject())
         coo->setControlObject(0);
      if (GameConnection *con = obj->getControllingClient())
      {
         if(this != con)
         {
            // was it controlled via camera or control
            if(con->getControlObject() == obj)
               con->setControlObject(0);
            else
               con->setCameraObject(0);
         }
      }

      // We are now the controlling client of this object.
      obj->setControllingClient(this);
   }

   // Okay, set our control object.
   mControlObject = obj;
   mControlForceMismatch = true;

   if(mCameraObject.isNull())
      setScopeObject(mControlObject);
}

In that code, it queries getControllingClient of the gameconnection object, then if that object is equal to the object specified as the parameter of setControlObject, then it resets controlobject to 0, if not, then it resets the cameraobject to 0, and lastly if the cameraobject is null, then it resets the camera to be the same as controlobject.

Since I'm setting it to %client.player (player is not the gameconnection, %client is if I understand correctly). Then it will trigger the camera object, and then reset it to the control object.

So basically that code only ever lets the camera be the same as the control, unless the control is the gameconnection object itself?

I hope I'm misunderstanding that, because it doesn't make alot of sense to me why GG would have done it that way... lol...

Anyone else have any feedback on this?

Thanks!
#8
05/06/2010 (5:20 am)
Anyone else have any thoughts on this? I'm sure I can do this without modifying source (as plenty are saying) I'm just missing something...

Thanks!
#9
05/06/2010 (5:59 am)
The orbit camera's "current distance" is broken: it's never used. I think the actual distance used is the average between minimum and maximum.

The code you see there only applies if the object suddenly becomes controlled by a different client. Make sure to call .setFirstPerson(false) in your clients and set firstPerson to false on your player datablock: if the gameConnection is using "first person" it will ignore the cameraObject and show the game through the controlObject instead.
#10
05/06/2010 (6:19 am)
Manoel, your a life saver! that's totally the piece I was missing (the setfirstperson on the datablock).

I haven't tested it yet, but that just feels right. I'll bet that was my problem.

If we get to a point where we're hiring for game dev positions I'll have to keep you in mind ;) lol (that's likely a long way off, just showing my appreciation for the several times you have solved problems for me so far)

Thanks!
#11
05/10/2010 (7:32 pm)
Ok, that worked awesome!

Just one more problem I'm encountering...

I'm hooking in GameConnection::initialControlSet. Immediately after I call Canvas.setContent(PlayGui); I then call DoPlayerSpawn(); which is my own event handler for code to run at player spawn (from the client side).

That function basically just enables the custom camera, firing off a server event. Here is the code for the relevant functions:

function DoPlayerSpawn()
{
   enableCustomCamera();
}

function enableCustomCamera()
{
   echo("Enabling Top-Down Camera...");
   commandToServer('EnableCustomCamera');   
}

function serverCmdEnableCustomCamera(%client)
{
   %client.setControlObject(%client.player);
   %client.setCameraObject(%client.camera);
   %client.setFirstPerson(false);
   %client.camera.setOrbitObject(%client.player, mDegToRad(90) @ " 0 0", 20, 100, 80, false, "0 0 0", true);
   //For some reason the 5th parameter of setOrbitObject doesn't work (sets current distance)
   //It always defaults to max distance (4th parameter).
   //So we'll manually override by moving the camera to a position relative to the player position.
   %client.camera.position = VectorAdd(%client.player.position, "0 0 80");   
}

So, I applied the fixes you reccomended, and that helps it work, BUT the problem is when I spawn in game, the camera is directly behind the player... Until I fire off the ToggleCamera function, (which I have bound to alt+c). Then it goes overhead, but still no control... Lastly when I toggle it AGAIN, then I have the correct overhead view, and I have control...

Here is the code for the togglecamera:
function toggleCamera(%val)
{
   if (%val)
      commandToServer('ToggleCamera');
}

function serverCmdToggleCamera(%client)
{
   if (%client.getControlObject() == %client.player)
   {
      %client.camera.setVelocity("0 0 0");
      %control = %client.camera;
   }
   else
   {
      %client.player.setVelocity("0 0 0");
      %control = %client.player;
   }
   %client.setControlObject(%control);
   clientCmdSyncEditorGui();
}

Now all that does is toggle the control object... Which I'm already doing in my enable custom camera function... And no matter where I move that to in the sequence it doesn't seem to matter...

I suspect something else is acting after my dospawn function runs, but I'm not sure how to hook anything that late after the spawn to reset the control object so that I can spawn with the correct camera from the start...

Any thoughts?
#12
05/13/2010 (4:56 am)
Manoel? Where are you when I need you ;) lol

Anyone else?

I think when I'm done I'll have to post a resource with an end to end tutorial of all that I've figured out with everyone's help here...
#13
05/22/2010 (6:41 am)
I would definitely be interested in having a guide on how to do this for future reference, and I think a lot of others could benefit as well....I'd like to see this get solved :D
#14
05/22/2010 (7:28 am)
Your code looks fine. I tested it here on vanilla 1.1b and the same happens. The camera is being set correctly, but it ignores the rotation until it is controlled. Looking at the source for the Camera class I can see why: nearly all of the Camera::processTick() code is inside this:

if (move)
{
...
}

So if the camera has no move it does nothing, including using the orbit rotation.

So, there are two workarounds for that. For anyone who can change the source code, try adding this before that huge if() block:

if (move == NULL)
   move = &NullMove;
I haven't tested it to see what collateral effects it does, but it's worth trying.

If you don't want to (or is unable to) mess with the source, a couple schedules do the trick. Here are the modified script code (plus a working toggleCamera):

function serverCmdEnableCustomCamera(%client)
{
   %client.setControlObject(%client.camera);
   %client.setCameraObject(%client.camera);
   
   // This will allow the camera to receive inputs for 100 milliseconds
   %client.lockControlSchedule = %client.schedule(100, setControlObject, %client.player);   
   
   %client.setFirstPerson(false);
   %client.camera.setOrbitObject(%client.player, mDegToRad(90) @ " 0 0", 20, 80, 0, false, "0 0 0", true);   
}

function serverCmdToggleCamera(%client)
{
   // Prevent camera toggling while the "hack" schedule is active
   if (isEventPending(%client.lockControlSchedule))
      return;
   
   if (%client.getControlObject() == %client.player)
   {
      %client.camera.setVelocity("0 0 0");
      %client.setControlObject(%client.camera);      
      %client.camera.setFlyMode();
   }
   else
   {
      %client.player.setVelocity("0 0 0");
      
      // We need to use the schedule otherwise the camera won't orient properly
      %client.lockControlSchedule = %client.schedule(100, setControlObject, %client.player);        
      %client.camera.setOrbitObject(%client.player, mDegToRad(90) @ " 0 0", 20, 80, 0, false, "0 0 0", true);
   }   
   clientCmdSyncEditorGui();
}
#15
05/25/2010 (5:26 am)
Hey that's awesome. I tested this out and it's now working beautifully (using the schedule method)...

I just have a few bugs to tweak and a couple minor adjustments, and I should be at a spot where I can take a break and write up a resource on doing a topdown space sim with Torque3D 1.1b purely in torquescript :)

Thanks!
#16
04/04/2011 (5:30 am)
Did you ever write up a resource for this? If so, where can I find it?
#17
11/05/2012 (9:02 am)
@Manoel,

Any other ideas on your post above.
if (move == NULL)   
   move = &NullMove;
Isn't working; it doesn't seem to change anything.
#18
11/05/2012 (4:13 pm)
look at the Torque3D documentation at the RTS & Adventure Camera Modes, they will give you a good understanding of the camera system :-)
#19
11/06/2012 (9:01 am)
Yeah, I've been through them 100x over a year ago, and I'm getting framiliar with the source too. I am back...AGAIN... fighting this issue. I was using Manoel's code todo something that it wasn't meant to fix... I think, lol.

I would like to use that "tether mode", but have never been able to figure it out. And have yet to see a scripted working method of it from employee's or community members.

I see in the code that orbitMode works with newton mode on "move only", I was assuming that meant move as in the camera moves which would indicate that the camera is the controlObject, I was hoping manoel's code would alleviate that control issue so you could move the player and keep the orbit moving smoothly behind in newton mode. TETHER MODE...
#20
11/07/2012 (3:06 pm)
The RTS Prototype was updated with the T3D MIT release, might want to give it another pass.

I haven't fiddled with "tether" camera mode - I'm guessing you're looking for a camera that will sort of "drag" behind the player?
Page «Previous 1 2