Moving a Sprite in a 2D Game
by Leo Goldseed · in Torque Developer Network · 12/28/2008 (1:22 am) · 6 replies
I am using Torque Game builder, and the script is pretty much a light version of C. Here's the deal:
I am using a behavior (Prepackaged code than can be resued as needed for any object in a game) to move an object. It works great! but there are a couple of things I don't get:
On the moveMap.bindObj( ) function, the moveup, move down, etc, etc are bound with keyboard keys. However, when I look at the actual functions that move the object (moveUp, moveDown, etc), the code passes a %val parameter that in the function body it gets assigned to %this.right, %this.left, etc.
Code:
1st Question: Where did this %val come from? What does it do???
2nd Question:
Also, on the updateMovement function, the linear velocity assignment functions pass the speed parameter like this: (%this.right - %this.left) why is that?
I know thanks to this the movement is made smooth, vs exclusively assigning the linear velocity the the object, but I don't get how they work. I would really appreciate any explanation.
I am using a behavior (Prepackaged code than can be resued as needed for any object in a game) to move an object. It works great! but there are a couple of things I don't get:
On the moveMap.bindObj( ) function, the moveup, move down, etc, etc are bound with keyboard keys. However, when I look at the actual functions that move the object (moveUp, moveDown, etc), the code passes a %val parameter that in the function body it gets assigned to %this.right, %this.left, etc.
Code:
.....
// this next field creation also effectively creates a variable with a string called upKey with a value of "Keyboard up"
%template.addBehaviorField(upKey, "Key to bind to upward movement", keybind, "keyboard up");
%template.addBehaviorField(downKey, "Key to bind to downward movement", keybind, "keyboard down");
%template.addBehaviorField(leftKey, "Key to bind to left movement", keybind, "keyboard left");
%template.addBehaviorField(rightKey, "Key to bind to right movement", keybind, "keyboard right");
%template.addBehaviorField(verticalSpeed, "Speed when moving vertically", float, 20.0);
%template.addBehaviorField(horizontalSpeed, "Speed when moving horizontally", float, 20.0);
}
function MovementBehavior::onBehaviorAdd(%this)
{
if (!isObject(moveMap))
return;
// bind our keys to the keyboard. here you obtain the value of the previously saved string, and assign a funciton to them
moveMap.bindObj(getWord(%this.upKey, 0), getWord(%this.upKey, 1), "moveUp", %this);
moveMap.bindObj(getWord(%this.downKey, 0), getWord(%this.downKey, 1), "moveDown", %this);
moveMap.bindObj(getWord(%this.leftKey, 0), getWord(%this.leftKey, 1), "moveLeft", %this);
moveMap.bindObj(getWord(%this.rightKey, 0), getWord(%this.rightKey, 1), "moveRight", %this);
// set the default values to 0
%this.up = 0;
%this.down = 0;
%this.left = 0;
%this.right = 0;
}
function MovementBehavior::onBehaviorRemove(%this)
{
if (!isObject(moveMap))
return;
%this.owner.disableUpdateCallback();
// remove the keybinds
moveMap.unbindObj(getWord(%this.upKey, 0), getWord(%this.upKey, 1), %this);
moveMap.unbindObj(getWord(%this.downKey, 0), getWord(%this.downKey, 1), %this);
moveMap.unbindObj(getWord(%this.leftKey, 0), getWord(%this.leftKey, 1), %this);
moveMap.unbindObj(getWord(%this.rightKey, 0), getWord(%this.rightKey, 1), %this);
%this.up = 0;
%this.down = 0;
%this.left = 0;
%this.right = 0;
}
function MovementBehavior::updateMovement(%this)
{
// make the player move
%this.owner.setLinearVelocityX((%this.right - %this.left) * %this.horizontalSpeed);
%this.owner.setLinearVelocityY((%this.down - %this.up) * %this.verticalSpeed);
}
function MovementBehavior::moveUp(%this, %val)
{
%this.up = %val;
%this.updateMovement();
}
function MovementBehavior::moveDown(%this, %val)
{
%this.down = %val;
%this.updateMovement();
}
function MovementBehavior::moveLeft(%this, %val)
{
%this.left = %val;
%this.updateMovement();
}
function MovementBehavior::moveRight(%this, %val)
{
%this.right = %val;
%this.updateMovement();
}1st Question: Where did this %val come from? What does it do???
2nd Question:
Also, on the updateMovement function, the linear velocity assignment functions pass the speed parameter like this: (%this.right - %this.left) why is that?
I know thanks to this the movement is made smooth, vs exclusively assigning the linear velocity the the object, but I don't get how they work. I would really appreciate any explanation.
#2
1. Is the bool parameter %val the fourth argument in the moveMap.bindObj() function?
2. If I am following this correctly, if the user presses the left key, then %val would passed as "true"and then the assignment:
%this.left = %val;
would basically set %this.left = true as well. Does this mean that since "true" is generally = 1 and "false" = 0
then:
1-0 = +1
0-1 = -1
1-1 = 0
0-0= 0
and that's how the function figures out if it shuold be left, right (positive negative)?
I think I've got it, but if you could kindly confirm if my line of thoguht is correct I would really appreciate it. THanks so much for your great help.
12/28/2008 (1:58 am)
Thanks so much! I do see things a little better now. A couple smaller doubts did arise though:1. Is the bool parameter %val the fourth argument in the moveMap.bindObj() function?
2. If I am following this correctly, if the user presses the left key, then %val would passed as "true"and then the assignment:
%this.left = %val;
would basically set %this.left = true as well. Does this mean that since "true" is generally = 1 and "false" = 0
then:
1-0 = +1
0-1 = -1
1-1 = 0
0-0= 0
and that's how the function figures out if it shuold be left, right (positive negative)?
function MovementBehavior::updateMovement(%this)
{
// make the player move
%this.owner.setLinearVelocityX((%this.right - %this.left) * %this.horizontalSpeed);
%this.owner.setLinearVelocityY((%this.down - %this.up) * %this.verticalSpeed);
}I think I've got it, but if you could kindly confirm if my line of thoguht is correct I would really appreciate it. THanks so much for your great help.
#3
The bind command and the bindObj command are identical, except the bindObj command takes a 4th parameter: the object to bind to----for use in a behavior.
add this after the bindObj lines:
echo( "1st param is the device: " @ getWord(%this.upKey, 0) );
echo( "2nd param is the action: " @ getWord(%this.upKey, 1) );
echo( "3rd param is the command to call" );
echo( "4th param is the object: " @ %this );
The called command will be passed the object (%this) and the value (%val). You are not passing in the value in script, you are receiving it from the engine in script just like you are receiving %this. How would you know it gets passed an object and a value? It is in the documentation and in the engine source code.
For reference, in the torque documentation under ActionMaps Reference there is this description:
"You can bind using this .bind() command, you must specify a device, the action to bind, then a function to be called when the event happens. The function specified must be set to receive a single value passed (ex. "function toggleU(%val)")"
To reiterate, bind and bindObj do the same thing save the 4th param (the object) of the bindObj. This allows for bind to be used in behaviors through bindObj. %this is always passed to a class function.
As far as the comments on:
%this.owner.setLinearVelocityX((%this.right - %this.left) * %this.horizontalSpeed);
You are correct. It is not making anything smoother. It is simplifying. It handles the case of what to do when the player presses left and right at the same time (possible on a keyboard). Instead of jerking around it elegantly says it will be zero.
Not to bash the example (because it is excellent and serves its purpose well) but I would like to point something out. Let's say the player speed is 10 in x and 10 in y. If the player moves diagonally this code says to move the player 10 units up and 10 units over...or about 14 units diagonally. The player should only move 10 units diagonally. Moving 14 units diagonally means the player is moving about 40% faster on the diagonals.
Hope this information helps!
Cheers,
Jim G
12/28/2008 (9:02 am)
Hi Leo,The bind command and the bindObj command are identical, except the bindObj command takes a 4th parameter: the object to bind to----for use in a behavior.
add this after the bindObj lines:
echo( "1st param is the device: " @ getWord(%this.upKey, 0) );
echo( "2nd param is the action: " @ getWord(%this.upKey, 1) );
echo( "3rd param is the command to call" );
echo( "4th param is the object: " @ %this );
The called command will be passed the object (%this) and the value (%val). You are not passing in the value in script, you are receiving it from the engine in script just like you are receiving %this. How would you know it gets passed an object and a value? It is in the documentation and in the engine source code.
For reference, in the torque documentation under ActionMaps Reference there is this description:
"You can bind using this .bind() command, you must specify a device, the action to bind, then a function to be called when the event happens. The function specified must be set to receive a single value passed (ex. "function toggleU(%val)")"
To reiterate, bind and bindObj do the same thing save the 4th param (the object) of the bindObj. This allows for bind to be used in behaviors through bindObj. %this is always passed to a class function.
As far as the comments on:
%this.owner.setLinearVelocityX((%this.right - %this.left) * %this.horizontalSpeed);
You are correct. It is not making anything smoother. It is simplifying. It handles the case of what to do when the player presses left and right at the same time (possible on a keyboard). Instead of jerking around it elegantly says it will be zero.
Not to bash the example (because it is excellent and serves its purpose well) but I would like to point something out. Let's say the player speed is 10 in x and 10 in y. If the player moves diagonally this code says to move the player 10 units up and 10 units over...or about 14 units diagonally. The player should only move 10 units diagonally. Moving 14 units diagonally means the player is moving about 40% faster on the diagonals.
Hope this information helps!
Cheers,
Jim G
#4
That's what I wasn't getting. Thanks so much! this was EXTREMELY helpful. This was giving me a headache because I did read the documentation, but it only says:
bindObj(device, action,[modifier spec, mod...], command, object)
[...]
device: Name of the device to bind the command to.
action: Name of the action to watch for.
modifier: Special modifiers (mouse only), such as dead spot, etc.
command: The function to be called on make and break.
object: The explicit object (it defaults to NULL when you call )
I guess like you said the way to know where the %val variable comes from is by checking the source code. Unfortunately I can't since I only have the binary version of TGB.
So now I know that the bindObj function passes the object (%this) and bool (&val) to the called command even though is not shown on the behavior script, but it's in the engine.
I hope TGB does not have a lot of functions like this in which more is being passed that you can see by looking at the script and the documentation, otherwise I am going to end up with similar challenges.
Thank you VERY much for taking the time to answer my post Jim. Fantastic help indeed. You made my day.
Best Wishes,
Leo.
12/28/2008 (2:18 pm)
"The called command will be passed the object (%this) and the value (%val). You are not passing in the value in script, you are receiving it from the engine in script just like you are receiving %this. " That's what I wasn't getting. Thanks so much! this was EXTREMELY helpful. This was giving me a headache because I did read the documentation, but it only says:
bindObj(device, action,[modifier spec, mod...], command, object)
[...]
device: Name of the device to bind the command to.
action: Name of the action to watch for.
modifier: Special modifiers (mouse only), such as dead spot, etc.
command: The function to be called on make and break.
object: The explicit object (it defaults to NULL when you call )
I guess like you said the way to know where the %val variable comes from is by checking the source code. Unfortunately I can't since I only have the binary version of TGB.
So now I know that the bindObj function passes the object (%this) and bool (&val) to the called command even though is not shown on the behavior script, but it's in the engine.
I hope TGB does not have a lot of functions like this in which more is being passed that you can see by looking at the script and the documentation, otherwise I am going to end up with similar challenges.
Thank you VERY much for taking the time to answer my post Jim. Fantastic help indeed. You made my day.
Best Wishes,
Leo.
#5
02/09/2009 (10:58 am)
Leo, what documentation did you find this in? I'm a new TGB user and I'm tearing my hair out trying to find it.
#6
Once you are in it, go to TGB reference and then run a search in it. You should be able to find it right there. Sometimes the search box doesn't work very well, so I just type partial words (like a prtial name of a function) until I find the reference I am looking for.
Hope it helps.
02/09/2009 (4:18 pm)
It's right on the "help" menu ot the TGB. It opens an internet explorer window: \Program Files\GarageGames\TorqueGameBuilder-1.7.4\documentation\Documentation Overview.html.Once you are in it, go to TGB reference and then run a search in it. You should be able to find it right there. Sometimes the search box doesn't work very well, so I just type partial words (like a prtial name of a function) until I find the reference I am looking for.
Hope it helps.
Torque Owner Brian Wilson
2) that allows for one call to handle the movement regardless of direction. It's a cleaner way of handling movment rather than setting the velocity with each move function. Think about what those values mean with each possilbe keypress. Since TGB is vector-based scene placement, that bit of math determines if the object should be moving + or - on each axis.