Game Development Community

Player speed

by Howard Dortch · in Torque Game Engine · 09/22/2004 (4:51 am) · 23 replies

In the player datablock there is a maxForwardSpeed I can change to make the player faster or slower. During a game session is there any way to change the player speed so they can run faster like pick up a powerup and change the speed they run?
All I see in the C++ code is setVelocity which wants a vector not a single speed value.
Page «Previous 1 2
#1
09/22/2004 (5:46 am)
You'll need to code in a multiplier or something that modifies the speed the code gets from the datablock in the C++ when it determines a player's velocity. You'll also need to make sure this is ghosted properly to other clients since their prediction will be horribly off otherwise, for that you'll need to make a new mask most likely. Finally you'll need to make accessor/modifier methods to get at the value from script and make an ::onCollision with your power up which changes the value and schedules a change back to the original value after the amount of time after which you want the powerup to wear off.
#2
09/22/2004 (6:36 am)
The ghosting and prediction should be part of the c++ code already. When a player is created, the engine takes the value for maxForwardSpeed and holds it as a variable in the class data per player. So when the shape is moved it calculates using it's local data for speed and sends the new information to each client. So if I could talk to the class and tell it to modify the speed value wouldn't the prediction and placement be handled?

Seems there should be an easy way to do this. A case where a player might be walking in a game or sneaking along then go into a burst run mode would be of great value.
#3
09/22/2004 (9:19 am)
MaxForwardSpeed is a datablock value. These are only sent once to the client per mission load. It is meant to be a 'static' value that does not change.

If you want a power up that effects player speed you should implement a speed 'modifier' as suggested above in the player class. You should expose any necessary get/set methods to script and make sure to send this 'modifier' value across the network via packUpdate/unpackUpdate in the player class.
#4
09/22/2004 (9:53 am)
Yeah I understand the maxForwardSpeed is a datablock item. Just figured walk would already be part of the engine or some speed modifier.
#5
10/21/2005 (12:51 pm)
This is exactly what I'm trying to do, although I'm having a few problems. This is the first code I have tried to write for Torque without following a tutorial, so please let me know if I'm horribly off. I haven't even gotten to the Networking part of the code, but here's what I have so far.

In player.h
//incSpeed adjusts the speed by the value
   //newSpeed sets the Speed to the value
   void setMaxForwardSpeed(float incSpeed, float newSpeed = 0);
   void setMaxBackwardSpeed(float incSpeed, float newSpeed = 0);
   void setMaxSideSpeed(float incSpeed, float newSpeed = 0);

In player.cc
void Player::setMaxForwardSpeed(float incSpeed, float newSpeed)
{
	if(newSpeed > 0)
	{
		mDataBlock->maxForwardSpeed = newSpeed;
	}
	else
	{
		mDataBlock->maxForwardSpeed += incSpeed;
	}

	
	if(mDataBlock->maxForwardSpeed <= 0)
		mDataBlock->maxForwardSpeed = 1;

	return;
}

void Player::setMaxBackwardSpeed(float incSpeed, float newSpeed)
{
	if(newSpeed > 0)
	{
		mDataBlock->maxBackwardSpeed = newSpeed;
	}
	else
	{
		mDataBlock->maxBackwardSpeed += incSpeed;
	}

	
	if(mDataBlock->maxBackwardSpeed <= 0)
		mDataBlock->maxBackwardSpeed = 1;

	return;
}

void Player::setMaxSideSpeed(float incSpeed, float newSpeed)
{
	if(newSpeed > 0)
	{
		mDataBlock->maxSideSpeed = newSpeed;
	}
	else
	{
		mDataBlock->maxSideSpeed += incSpeed;
	}

	
	if(mDataBlock->maxSideSpeed <= 0)
		mDataBlock->maxSideSpeed = 1;

	return;
}

ConsoleMethod(Player, setSpeed, void, 3, 4, "perameter 3 is adjusts speed by an amount, perameter 4 adjusts the speed to the new perameter")
{
	argc; argv; float incSpeed; float newSpeed;

	object->setMaxForwardSpeed(incSpeed, newSpeed);
	object->setMaxBackwardSpeed(incSpeed, newSpeed);
	object->setMaxSideSpeed(incSpeed, newSpeed);
}

in my powerup file (superbomb.cs which is just a modification of the superbomb file from the CodeSampler tutorial):
function SuperBomb::onCollision( %this, %obj, %col )
{
    echo( "SuperBomb::onCollision called ----------------------------------" );

   //Add code here to have the player react to touching the power-up!
  %col.setSpeed(5, 0);
}

I think most of my problem is with the ConsoleMethod Macro. When I place the superbombs in the scene and walk over them, I get this in the console:
Quote:
SuperBomb::onCollision called --------------------------
tutorial.base/server/superbomb.cs (0): Unknown command setSpeed
Object (1265) player Player -> ShapeBase -> GameBase -> SceneObject -> NetObject -> SimObject

Any help would be greatly appreciated.
#6
10/21/2005 (4:17 pm)
I did a little more research and I've tried a couple more things, all to no avail. First, I realized that I was not using the arguments in the ConsoleMethod correctly. So I redid the ConsoleMethod to look like this.
ConsoleMethod(Player, setSpeed, void, 3, 4, "perameter 3 is adjusts speed by an amount, perameter 4 adjusts the speed to the new perameter")
{
	float incSpeed; float newSpeed;

	incSpeed = (float)(*argv[2]);

	if(argc = 4])
		newSpeed = (float)(*argv[3]);
	else
		newSpeed = 0;

	object->setMaxForwardSpeed(incSpeed, newSpeed);
	object->setMaxBackwardSpeed(incSpeed, newSpeed);
	object->setMaxSideSpeed(incSpeed, newSpeed);
}

Still, the console said setSpeed was unknown. Up to this point I had only been building Torque Lib, so I thought maybe there was some relationship between it and Torque Demo that wasn't being updated, so I built the whole SDK. Still setSpeed was unknown. So I thought maybe I wasn't placing the ConsoleCommand in the right place (like initPersistentfields). So I tried to see what was listed in those areas.

While doing that, I found that the maxForwardSpeed, maxBackwardSpeed, and maxSideSpeed members of PlayerData were all made available to the console via AddField, and GameBase has a ConsoleMethod called getdatablock. So I started the demo, opened up the console and type:
echo(1265.getdatablock());
which echoed 62.
Then I typed;
echo(1265.getdatablock().maxforwardspeed);
which echoed 5, which is correct.
Then I typed
1265.getdatablock().maxforwardspeed = 50;
which worked.

So then I visited the player.cs file in the server folder, and added the following function:
function Player::setSpeed( %this, %incSpeed, %newSpeed = 0 )
{
	if(newSpeed > 0)
    {
		%this.getdatablock().maxforwardspeed = newSpeed;
		%this.getdatablock().maxbackwardspeed = newSpeed;
		%this.getdatablock().maxsidespeed = newSpeed;
	}
	else
	{
		%this.getdatablock().maxforwardspeed += incSpeed;
		%this.getdatablock().maxbackwardspeed += incSpeed;
		%this.getdatablock().maxsidespeed += incSpeed;
	}
}

The onCollission function of superbomb.cs still says:
function SuperBomb::onCollision( %this, %obj, %col )
{
                echo( "SuperBomb::onCollision called ----------------------------------" );

	// TO DO: Add code here to have the player react to touching the power-up!
	%col.setSpeed(5);
}

I thought that was going to do it, but the console still says setSpeed is unknown. Help please! :)
#7
10/21/2005 (4:28 pm)
Hmm... i suck at C++.. but what i did was took that console method, gutted it... and placed it in my player.cc file, recompiled. did a .dump of my player object, .setspeed() is listed amont the functions i can call.
#8
10/21/2005 (4:45 pm)
I recompiled and did a .dump and setSpeed() is not available. Where did you place the ConsoleMethod function in the player.cc file?
#9
10/21/2005 (5:08 pm)
Since you mentioned you gutted the ConsoleMethod I thought I'd try that. So I commented out the method in the post above and added this
ConsoleMethod( Player, setSpeed, void, 3, 4, "")
{
	return;
}

Still no luck :(
#10
10/21/2005 (5:38 pm)
Having you taken a look at this resource? If it does not do exactly what you want, you could use it as a guide to add additional player attributes.

www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=8463

B--
#11
10/21/2005 (6:17 pm)
Couple of things to note:

You don't want to be changing the datablock itself in your functions, because there is one and only one instantiation of a datablock in memory, but multiple objects that may point to it. In other words, you can almost consider it "shared memory" for all objects that are using that datablock. With the technique you are using, you will be changing the max or min speed (as appropriate) for ALL objects that use this datablock, not just the one you specifically want to modify.

The second thing to keep in mind is which object you are actually using to call the .dump() upon. Try doing an %ObjectID.getClassName() and see what it outputs--should be "Player".

A couple of other minor bugs/typos:

In your second ConsoleMethod implementation, you have:

if (argc = 4 )

which should be
if (argc == 4)

Finally, and I could be wrong on this but I don't think so: you cannot initialize an inbound parameter in TorqueScript, so I'd give 2:1 odds that if you scroll up to the top of your console output and then look down at where player.cs is being loaded, you will see an error report related to this line:

function Player::setSpeed( %this, %incSpeed, %newSpeed = 0 )

If in fact that is erroring, then the TorqueScript byte code compiler refuses to compile your new code, and defaults to your old (which doesn't have your new function).

Hope this helps some!
#12
10/21/2005 (8:11 pm)
@Brandon and Steven
Those were great tips guys, and they advanced my learning a ton!

Still got a problem. I did the tutorial (including the corrections mentioned at the bottom) and deleted my other functions that were adjusting the datablock. So everything is ready to go, but I still can't get the ConsoleMethod macro to work. As I mentioned above, I can't even get an empty Macro like ConsoleMethod( Player, setSpeed, void, 3, 4, ""){ return;} to show when I do the dump(). I did the echo(1265.getclassname()); which verified that I am working on the player. And deleted the setSpeed function out of the player.cs file as it was manipulating the datablock and I didn't want it to conflict with the engine code.

So what could I be doing wrong that's stopping the ConsoleMethod from updating the script?

Thanks again for the help.
#13
10/21/2005 (8:22 pm)
There could be a number of things causing your woes.. Are you using VisualStudio? If you are, I would start by calling the added console function from an area of script where you know you have a handle to the player object; set a breakpoint in VS at the C++ console code, and see if the breakpoint gets triggered. That will at least give you an idea of where the problem is.

I've added quite a few console additions without ever having a problem, so I'll bet it is something simple you are overlooking.

B--
#14
10/21/2005 (8:52 pm)
I didn't mention this in the first response, but when you said something about "I've been compiling the ... lib", that points to the fact that you probably aren't actually recompiling your executable. The VC project can be confusing, but make sure that you are in fact recompiling the executable that is being run--in stock it should say torqueDemo.exe, or torqueDemo_DEBUG.exe. Check the date/time stamp and make sure that it corresponds to when the build finished.
#15
10/22/2005 (9:28 am)
Those last tips proved to be quite helpful. I am using Visual Studio and after my initial build 2 weeks back I had both torqueDemo and torqueDemo_Debug. I had become accustomed to running to torqueDemo. Upon checking the time stamps it turns out that only the torqueDemo_Debug had been modified by the recent changes. torqueDemo showed that it was created all the way back in January! So I ran Debug and my method is there. Hooray! So I guess my last question becomes, how do I make sure both .exe file get updated, and what settings should I change when compiling for torqueDemo and torqueDemo_Debug? Thanks again for all the help.
#16
10/22/2005 (12:36 pm)
Theres a little pulldown menu towards the top of VC, in the toolbar, near the middle. It reads 'Release', or 'Debug'. Thats what you will compile. Confused on which project you are compiling? Just highlight the name of the one you want in the leftside menu that usually lists all the projects in your solution.
#17
10/24/2005 (5:51 pm)
I had to split this up into a few posts to get it all on.

@Erik- Thanks, that works perfectly.

So after I got the tutorial code working, I thought it might be more "correct" to try implementing the code in a class that inherits from Player, but there are apparently some intricacies associated with inheriting from such a massive class (and probably inheriting in general ;p) that I'm not sure I completely understand, as evidenced by about 10 compiler errors. I tried to find some code showing objects inherited from player, but couldn't find any. A guy named Jarrod Roberson promised to do some tutorials a few years back, but I couldn't find the actual fruit of his promise. And people were telling him it would be difficult. So my first question is, in a situation like this is it better to:

1) Just make the changes directly in the class. You can always keep a backup copy to run demos and tutorials based on the stock engine, or in the worst case download it again from garagegames.

2)Create a new class that inherits from ShapeBase, copy all of the code from player.h and player.cc, and make the changes in this class. Or

3) Create a class that inherits from player and create/override the necessary functions.

Ideally, I would like to know what's best from a "propper" programming standpoint, not just what is fastest or easiest. If the answer is 1, no problem. If the answer is 2, I don't perceive any problems, but let me know if there is some hurdle I should expect. If the answer is 3, then here's what I go so far. I think my problems are with the inherited enum MaskBits- how do I properly add CharMask to this enum for the SpeedPlayer. There also appears to be a few problems in the network code (packUpdate, and unpackUpdate), and with updateMove.
#18
10/24/2005 (5:53 pm)
Anyway, in speedPlayer.h

#ifndef SPEED_PLAYER_H
#define SPEED_PLAYER_H

#include "game/player.h"

struct SpeedPlayerData: public PlayerData {
  private:
   typedef PlayerData Parent;
};

class SpeedPlayer : public Player
{
      typedef Player Parent;

protected:

      enum MaskBits {
      ActionMask   = Parent::NextFreeMask << 0,
      MoveMask     = Parent::NextFreeMask << 1,
      ImpactMask   = Parent::NextFreeMask << 2,
      NextFreeMask = Parent::NextFreeMask << 3,
      CharMask = Parent::NextFreeMask << 4
   };

	S32 speed;

	S32 maxForwardSpeed;
	S32 maxBackwardSpeed;
	S32 maxSideSpeed;

	void updateMove(const Move *move);

public:
	DECLARE_CONOBJECT(SpeedPlayer);

	SpeedPlayer();
	~SpeedPlayer();

	U32  packUpdate  (NetConnection *conn, U32 mask, BitStream *stream);
	void unpackUpdate(NetConnection *conn,           BitStream *stream);

	//incSpeed adjusts the speed by a value
	//newSpeed resets the speed to the new value
	void setSpeed(S32 incSpeed, S32 newSpeed);
};


#endif

and in speedPlayer.cc (forgive the length updateMove is the same as in player.cc, except for the changes in the tutorial .

#include "game/speedPlayer.h"

SpeedPlayer::SpeedPlayer() : Player()
{
	maxForwardSpeed = maxBackwardSpeed = maxSideSpeed = speed = 5;
}

SpeedPlayer::~SpeedPlayer()
{
}

U32  SpeedPlayer::packUpdate  (NetConnection *con, U32 mask, BitStream *stream)
{
	U32 retMask = Parent::packUpdate(con, mask, stream);

	if (stream->writeFlag(mask & CharMask))
		stream->writeInt(speed,5);
}

void SpeedPlayer::unpackUpdate(NetConnection *con,           BitStream *stream)
{
	Parent::unpackUpdate(con,stream);

	if (stream->readFlag())
	{
		S32 speed = stream->readInt(5);
		setSpeed(0, speed);
	}
}
void SpeedPlayer::setSpeed(S32 incSpeed, S32 newSpeed)
{

if(newSpeed > 0)
	speed = newSpeed;
else
	speed += incSpeed;

if(speed < 1)
	speed = 1;


maxForwardSpeed = maxBackwardSpeed = maxSideSpeed = speed;

if(isServerObject())
	setMaskBits(CharMask);
}


ConsoleMethod( SpeedPlayer, setSpeed, void, 3, 4, "incSpeed, newSpeed")
{
	S32 incSpeed = dAtoi(argv[2]);
	S32 newSpeed = 0;

	if(argc == 4)
		S32 newSpeed = dAtoi(argv[3]);
	else
		S32 newSpeed = 0;

	object->setSpeed(incSpeed, newSpeed);
}

Well, I decided to leave out updateMove, as I mentioned its the same as the Player::updateMove(), with the changes from the tutorial applied. I get a few errors in it, but I figure if you guys can help me sort out the other stuff, I can probably get those taken care of. Hopefully anyway ;)


The compiling errors I get are:

1)error C2027: use of undefined type 'BitStream'
2)error C2027: use of undefined type 'GameConnection'
3)error C2065: 'JumpSkipContactsMax' : undeclared identifier
4)error C2065: 'sFallingThreshold' : undeclared identifier
5)error C2227: left of '->isFirstPerson' must point to class/struct/union
6)error C2227: left of '->readFlag' must point to class/struct/union
7)error C2227: left of '->readInt' must point to class/struct/union
8)error C2227: left of '->writeFlag' must point to class/struct/union
9)error C2227: left of '->writeInt' must point to class/struct/union

Sorry to be such a burden. I just figure if I learn how to do things right early on, I'll be less of a burden later down the road.
#19
10/24/2005 (7:52 pm)
Basically, you are just missing some #includes from your speedPlayer.h/cc files. You'll need to #include any .h file that declares the structures like BitStream, GameConnection, etc.

If you look at the top of the player.h and player.cc, you'll see the common techniques for including the files you need. You should be able to get away with simply copying everything in the #include areas from each file, although a more accurate inheritence set of code would only include what you need---that does however take some work.
#20
10/26/2005 (11:58 pm)
First, let me just reiterate that I love this community. It is always great to get a prompt response from other members, and its absolutely spectacular that employees seem to chime in on at least half the threads I've read. It's a rare post where someone doesn't get the help they need.

Well, I was able to figure out the include files and I got everything to build. I tried to go and edit the scripts so that the tutorial.base program would start with a SpeedPlayer instead of a Player. I get a runtime error that appears to be occuring in the inline funcion size() declared in the template class toolVector. It must be something I did in the script, because I put break points at the beginning of all my new SpeedPlayer functions, but when I debug the compiler isn't stopping at any of them before hitting size(). The error is: Unhandled exception at 0x006cc996 in torqueDemo_DEBUG.exe: 0xC0000005: Access violation reading location 0x0000000c. Anybody got any pointers (pun intended ;)

From the experience, I'm beginning to feel that for someone who is relatively new to both programming and Torque, it will be easiest to make changes and identify problems if I make changes directly to the stock engine classes. As I gain experience, and get more comfortable with both scripting and C++, I may feel more comfortable using inheritence to accomplish the changes I want to make.
Page «Previous 1 2