Top Down Shooter - Move relative to player direction
by Oliver Ridgway · 03/24/2012 (12:44 am) · 11 comments
There's a couple of top down shooter resources existing already. I wanted to draw together a lot of this into one neat resource.
This will allow us to control the player from a neat orbit cam view.
Lets stop the player from looking up and down and keep them level on the horizontal plane.
Inside scripts/client/default.bind.cs comment out the following line
becomes
All works great, but moving the player around is a little disorientating, lets fix that and give it a twin stick shooter style controls.
Add the following code to the end of scripts/server/player.cs
This gives us some neat controls so left is always left regardless of which way the player is facing. Lets put them into action.
Back in scripts/client/default.bind.cs replace the moveleft, moveright, moveforward and movebackward functions with the following:
This binds the serverCmdUpdateMovement function we wrote earlier to the movement keys.
Thus far we have a fairly functional twin stick shooter style camera and controls. Whats missing at the moment is that it only supports 4 directions. I.E. pressing up and left will only move up.
If you move the mouse with a movement key still down the player will move in that direction. If this is something you don't want you can stop this by amending the "yaw" function in default.bind.cs to:
Hope this helps some people.
Step One:
Make a new project (I started with the chinatown FPS from Torque 1.2) (I created my own scripts to add all the following code, but i'm just editing existing scripts in this resource to keep is simple.)Step Two:
Create an overhead camera. Open scripts/server/gameCore.cs and inside GameCore::preparePlayer, Just after %game.loadOut(%client.player); add the following:%client.setControlObject(%client.camera); %client.setCameraObject(%client.camera); // Set a schedule so we can control the player %client.lockControlSchedule = %client.schedule(100, setControlObject, %client.player); %client.setFirstPerson(false); // This will set the orbit camera looking down at an isometic view at about 45 degrees (0.8rads) %client.camera.setOrbitObject(%client.player, "0.8 0 0.8", 3, 10, 0, false, "0 0 0", true);
This will allow us to control the player from a neat orbit cam view.
Step Three:
Lets stop the player from looking up and down and keep them level on the horizontal plane.
Inside scripts/client/default.bind.cs comment out the following line
moveMap.bind( mouse, yaxis, pitch );
becomes
//moveMap.bind( mouse, yaxis, pitch );
All works great, but moving the player around is a little disorientating, lets fix that and give it a twin stick shooter style controls.
Step Four:
Add the following code to the end of scripts/server/player.cs
function serverCmdUpdateMovement(%client) {
%euler = %client.player.getEulerRotation();
%rot = GetWord(%euler, 2);
// Messy but it works !
if($upPressed) {
if(%rot > 0) {
if(%rot < 90) {
%per = (%rot * (100/90)) / 100;
$mvForwardAction = 1 - %per;
$mvLeftAction = %per;
} else {
%rot = %rot - 90;
%per = (%rot * (100/90)) / 100;
$mvLeftAction = 1 - %per;
$mvBackwardAction = %per;
}
} else {
if(%rot > -90) {
%rot = %rot * -1;
%per = (%rot * (100/90)) / 100;
$mvForwardAction = 1 - %per;
$mvRightAction = %per;
} else {
%rot = (%rot * -1) - 90;
%per = (%rot * (100/90)) / 100;
$mvRightAction = 1 - %per;
$mvBackwardAction = %per;
}
}
} else if($downPressed) {
if(%rot > 0) {
if(%rot < 90) {
%per = (%rot * (100/90)) / 100;
$mvBackwardAction = 1 - %per;
$mvRightAction = %per;
} else {
%rot = %rot - 90;
%per = (%rot * (100/90)) / 100;
$mvRightAction = 1 - %per;
$mvForwardAction = %per;
}
} else {
if(%rot > -90) {
%rot = %rot * -1;
%per = (%rot * (100/90)) / 100;
$mvBackwardAction = 1 - %per;
$mvLeftAction = %per;
} else {
%rot = (%rot * -1) - 90;
%per = (%rot * (100/90)) / 100;
$mvLeftAction = 1 - %per;
$mvForwardAction = %per;
}
}
} else if($leftPressed) {
if(%rot > 0) {
if(%rot < 90) {
%per = (%rot * (100/90)) / 100;
$mvBackwardAction = %per;
$mvLeftAction = 1 - %per;
} else {
%rot = %rot - 90;
%per = (%rot * (100/90)) / 100;
$mvRightAction = %per;
$mvBackwardAction = 1 - %per;
}
} else {
if(%rot > -90) {
%rot = %rot * -1;
%per = (%rot * (100/90)) / 100;
$mvForwardAction = %per;
$mvLeftAction = 1 - %per;
} else {
%rot = (%rot * -1) - 90;
%per = (%rot * (100/90)) / 100;
$mvRightAction = %per;
$mvForwardAction = 1 - %per;
}
}
} else if($rightPressed) {
if(%rot > 0) {
if(%rot < 90) {
%per = (%rot * (100/90)) / 100;
$mvForwardAction = %per;
$mvRightAction = 1 - %per;
} else {
%rot = %rot - 90;
%per = (%rot * (100/90)) / 100;
$mvLeftAction = %per;
$mvForwardAction = 1 - %per;
}
} else {
if(%rot > -90) {
%rot = %rot * -1;
%per = (%rot * (100/90)) / 100;
$mvBackwardAction = %per;
$mvRightAction = 1 - %per;
} else {
%rot = (%rot * -1) - 90;
%per = (%rot * (100/90)) / 100;
$mvLeftAction = %per;
$mvBackwardAction = 1 - %per;
}
}
} else {
$mvForwardAction = 0;
$mvRightAction = 0;
$mvLeftAction = 0;
$mvBackwardAction = 0;
}
}This gives us some neat controls so left is always left regardless of which way the player is facing. Lets put them into action.
Back in scripts/client/default.bind.cs replace the moveleft, moveright, moveforward and movebackward functions with the following:
$leftPressed = 0;
$rightPressed = 0;
$upPressed = 0;
$downPressed = 0;
function moveleft(%val) {
$leftPressed = %val;
commandToServer('UpdateMovement');
}
function moveright(%val) {
$rightPressed = %val;
commandToServer('UpdateMovement');
}
function moveforward(%val) {
$upPressed = %val;
commandToServer('UpdateMovement');
}
function movebackward(%val) {
$downPressed = %val;
commandToServer('UpdateMovement');
}This binds the serverCmdUpdateMovement function we wrote earlier to the movement keys.
Thus far we have a fairly functional twin stick shooter style camera and controls. Whats missing at the moment is that it only supports 4 directions. I.E. pressing up and left will only move up.
If you move the mouse with a movement key still down the player will move in that direction. If this is something you don't want you can stop this by amending the "yaw" function in default.bind.cs to:
function yaw(%val)
{
%yawAdj = getMouseAdjustAmount(%val);
if(ServerConnection.isControlObjectRotDampedCamera())
{
// Clamp and scale
%yawAdj = mClamp(%yawAdj, -m2Pi()+0.01, m2Pi()-0.01);
%yawAdj *= 0.5;
}
$mvYaw += %yawAdj;
// sets movement relative to player direction.
commandToServer('UpdateMovement');
}Hope this helps some people.
#2
03/24/2012 (2:33 pm)
Oh goodie! This is something I've always wanted to do.
#3
03/25/2012 (2:29 am)
Nice one. Thanks for this!
#4
Nice one
03/25/2012 (5:12 am)
Talk about perfect timing!!! I was just about to start doing soemthing very similar to thisNice one
#5
03/25/2012 (2:21 pm)
Thanks Oliver great resource i had tried to follow some of the others on here but never with much luck. I wondering what area of the code i would focus on to make it so up is always going to move the player forward? Thank you
#6
The long if statement in scripts/server/player.cs what you need to take a look at.
Basically it looks at what direction the player is facing then moves them. For example, the the player is looking down and to the right at 45degree's, it sets there backward speed to 0.5 and left speed to 0.5 if you move up.
See crude drawing:

Also please take into account that its only works in 4 directions. You'll have to get your hands dirty working out the fractions for the diagonals.
I've found that this control method is fairly unintuitive for the mouse and keyboard so i'll be looking at something else in the near future.
Yep its Tuborg Yorks... :D
03/25/2012 (8:13 pm)
Hey Shane,The long if statement in scripts/server/player.cs what you need to take a look at.
Basically it looks at what direction the player is facing then moves them. For example, the the player is looking down and to the right at 45degree's, it sets there backward speed to 0.5 and left speed to 0.5 if you move up.
See crude drawing:

Also please take into account that its only works in 4 directions. You'll have to get your hands dirty working out the fractions for the diagonals.
I've found that this control method is fairly unintuitive for the mouse and keyboard so i'll be looking at something else in the near future.
Yep its Tuborg Yorks... :D
#7
I'm using a fresh Torque 3D 1.2 FPS Deathmatch Tutorial base (Chinatown as some put it). After applying the script changes I'm able to move around with the camera as the resource dictates, however after being killed and then respawning the camera looses its lock on the player and is stationary (at the default respawn point) while the player is still able to move around freely.
I'm unsure if I missed something along the way, I can upload some pics if you like.
04/15/2012 (12:17 am)
Thanks for the resource Oliver, I've been following it to a T but I've run into a possible bug that I'm not entirely sure about.I'm using a fresh Torque 3D 1.2 FPS Deathmatch Tutorial base (Chinatown as some put it). After applying the script changes I'm able to move around with the camera as the resource dictates, however after being killed and then respawning the camera looses its lock on the player and is stationary (at the default respawn point) while the player is still able to move around freely.
I'm unsure if I missed something along the way, I can upload some pics if you like.
#8
I actually stripped all of this out of my own game so it may not be 100% correct.
However if everything is working correctly before you die, I would suggest looking at step two again, specifically this line:
Seems like the game isn't reattaching the camera to your character
04/17/2012 (5:58 pm)
Hi Mack,I actually stripped all of this out of my own game so it may not be 100% correct.
However if everything is working correctly before you die, I would suggest looking at step two again, specifically this line:
%client.camera.setOrbitObject(%client.player, "0.8 0 0.8", 3, 10, 0, false, "0 0 0", true);
Seems like the game isn't reattaching the camera to your character
#9
Thanks for responding, here's the chunk of gameCore, it looks proper to me but I'm probably missing something:
Here's a screenshot of what's going on:

If you like I could upload my gameCore, it's vanilla other than the additions made with this resource.
Once we've figured out the problem then I'll post a reply on here just in case others repeat my error.
04/17/2012 (9:07 pm)
Evening Oliver,Thanks for responding, here's the chunk of gameCore, it looks proper to me but I'm probably missing something:
// Added this stage to creating a player so game types can override it easily.
// This is a good place to initiate team selection.
function GameCore::preparePlayer(%game, %client)
{
//echo (%game @&quot;c4 -&gt; &quot;@ %game.class @&quot; -&gt; GameCore::preparePlayer&quot;);
// Find a spawn point for the player
// This function currently relies on some helper functions defined in
// core/scripts/spawn.cs. For custom spawn behaviors one can either
// override the properties on the SpawnSphere's or directly override the
// functions themselves.
%playerSpawnPoint = pickPlayerSpawnPoint($Game::DefaultPlayerSpawnGroups);
// Spawn a camera for this client using the found %spawnPoint
//%client.spawnPlayer(%playerSpawnPoint);
%game.spawnPlayer(%client, %playerSpawnPoint);
// Starting equipment
%game.loadOut(%client.player);
%client.setControlObject(%client.camera);
%client.setCameraObject(%client.camera);
// Set a schedule so we can control the player
%client.lockControlSchedule = %client.schedule(100, setControlObject, %client.player);
%client.setFirstPerson(false);
// This will set the orbit camera looking down at an isometic view at about 45 degrees (0.8rads)
%client.camera.setOrbitObject(%client.player, &quot;0.8 0 0.8&quot;, 3, 10, 0, false, &quot;0 0 0&quot;, true);
}Here's a screenshot of what's going on:

If you like I could upload my gameCore, it's vanilla other than the additions made with this resource.
Once we've figured out the problem then I'll post a reply on here just in case others repeat my error.
#10
On death, gameCore.cs calls:
The most important part was its comment:
"Switch the client over to the death cam and unhook the player object"
That's the problem I was running into, upon death and subsequent respawn the camera was unhooked from the player.
So I went into scripts\server\camera.cs and under "case "Corpse":" I commented this out:
Now the player dies, has the death cam and on repsawn resumes the proper top down camera.
07/02/2012 (3:13 pm)
I've discovered the source the problem I've been having.On death, gameCore.cs calls:
%client.camera.setMode("Corpse", %client.player);The most important part was its comment:
"Switch the client over to the death cam and unhook the player object"
That's the problem I was running into, upon death and subsequent respawn the camera was unhooked from the player.
So I went into scripts\server\camera.cs and under "case "Corpse":" I commented this out:
%this.setMode(%obj,"Observer");
Now the player dies, has the death cam and on repsawn resumes the proper top down camera.
#11
09/25/2012 (5:45 am)
Nice resource, thanks a lot. 
Associate Steve Acaster
[YorkshireRifles.com]
... squints at pic ... is that Tuborg?
get some micro-brewery real ale down you!