reversing my boat

Started by
9 comments, last by Zahlman 17 years, 3 months ago
Can smeone give me a hand at getting my boat to reverse :)

void CBoat::init(void)
{
	vAcceleration.x = 0.0f;
	vAcceleration.y = 0.0f;
	vAcceleration.z = 0.0f;	

	vVelocity.x = 0.0f;
	vVelocity.y = 0.0f;
	vVelocity.z = 0.0f;

	vDirection.x = 0.0f;
	vDirection.y = 0.0f;
	vDirection.z = 1.0f;
	
	vReference.x = 0.0f;
	vReference.y = 0.0f;
	vReference.z = 1.0f;
	
	ACCELERATION_RATE	=  0.5;
	BRAKING_RATE		= -4.0;
	REVERSE_RATE		= -10.0;
	FRICTION_RATE		= -1.0;
	STEERING_RATE		=  2.0;
	MAX_SPEED			=  2.4f;
}
void CBoat::updatePhysics(float dtime) 
{ 
	vVelocity += vAcceleration * dtime;	/*Update the vVelocity*/
	positionVector += vVelocity;		/*Update the positionVector*/

	speed = D3DXVec3Length(&vVelocity);		/*Get the magnitude of the Boats velocity*/

	/*Update the angle for the Boat to turn by getting the dot 
	product between the direction and a reference in radians, and then clamp it to stop floating point errors*/
	tempAngle = D3DXVec3Dot(&vDirection,&vReference);
	if (tempAngle < -1)
	{
		tempAngle = -1;
	}
	else if (tempAngle > 1)
	{
		tempAngle = 1;
	}
	angle = acos(tempAngle);
	/* check if the vDirection has a -ve X, which means it is pointing towards -ve X
	 in this case, the angle should be 360 - angle,360 in radians is 2*pi */
	if(vDirection.x < 0) 
	{
		angle = 2*D3DX_PI - angle;
	}
	//============= Update the Velocity to turn the boat to the facing heading
	vVelocity = vDirection * speed;
	update();
}

void CBoat::update()
{
	D3DXVECTOR3 vDirectionTemp;

	if (speed >= MAX_SPEED) //Cap the speed
	{
		speed = MAX_SPEED;
	}

	//============ ACCELERATE the Boat
	if (bAccelerationKeyPressed == true && bBreakingKeyPressed == false && bReverseKeyPressed == false)
	{
		vAcceleration = vDirection * ACCELERATION_RATE;
	}
	//============  DECELERATE the Boat
	if (bAccelerationKeyPressed == false && speed > 0)
	{
		vAcceleration = vDirection * FRICTION_RATE;
	}
	//============ BRAKE the Boat
	if (bBreakingKeyPressed == true)
	{		
		vAcceleration = vDirection * BRAKING_RATE;
	}
	//============ Reverse the Boat
	if (bReverseKeyPressed == true && bAccelerationKeyPressed == false && bBreakingKeyPressed == false)
	{		
		//code to reverse the boat
	}
	//============ TURN Boat LEFT
	if (bLeftKeyPressed == true)
	{
		if (speed >= 0.0f)/*only rotate if speed is above*/
		{
			vDirectionTemp.x = vDirection.x;
			vDirectionTemp.z = vDirection.z;
			//Rotate  the direction vector by an angle
			vDirection.x = vDirectionTemp.x*cos(D3DXToRadian(STEERING_RATE))
				- vDirectionTemp.z*sin(D3DXToRadian(STEERING_RATE));
			vDirection.z = vDirectionTemp.x*sin(D3DXToRadian(STEERING_RATE))
				+ vDirectionTemp.z*cos(D3DXToRadian(STEERING_RATE));
		}
	}
	//============ TURN Boat Right
	if (bRightKeyPressed == true)
	{
		if (speed >= 0.0f)/*only rotate if speed is above*/
		{
			vDirectionTemp.x = vDirection.x;
			vDirectionTemp.z = vDirection.z;
			//Rotate the direction vector by an angle
			vDirection.x = vDirectionTemp.x*cos(D3DXToRadian(- STEERING_RATE))
				- vDirectionTemp.z*sin(D3DXToRadian(- STEERING_RATE));
			vDirection.z = vDirectionTemp.x*sin(D3DXToRadian(- STEERING_RATE))
				+ vDirectionTemp.z*cos(D3DXToRadian(- STEERING_RATE));
		}
	}
}
[Edited by - Prog101 on January 17, 2007 4:22:10 PM]
Advertisement
	//============ Reverse the Boat	if (bReverseKeyPressed == true && bAccelerationKeyPressed == false && bBreakingKeyPressed == false)	{				accelerationVector = directionVector * REVERSE_ACCELERATION_RATE;	}


Just make REVERSE_ACCELERATION_RATE negative~
--Riley
i tried it that way but it does not make it go backwards it still goes forwards
REVERSE_RATE = -10.0;
//============ Reverse the Boat
if (bReverseKeyPressed == true && bAccelerationKeyPressed == false && bBreakingKeyPressed == false)
{
accelerationVector = directionVector * REVERSE_RATE;
}
	velocityVector += accelerationVector * dtime;	/*Update the velocityVector*/	positionVector += velocityVector;		/*Update the positionVector*/


So what is happening that is making the code above add positive values to position even though accelerationVector is negative? Have you traced through this part in a debugger?

I suspect that your negative velocity is becoming positive when you say:

speed = magnitude(velocity)

and then later...

velocity = speed * direction.

When you update the speed in updatePhysics, you don't consider the possibility that the boat might be going the OPPOSITE direction of the direction vector.
--Riley
Yeah it looks like
	//============= Update the Velocity to turn the boat to the facing heading	vVelocity = vDirection * speed;


is making the facing direction positive again, but how do i solve this problem?
You're making it much too complicated.

To turn, currently you apply a perpendicular adjustment to a direction vector. Then you try to make some calculations to keep a direction-magnitude representation of the speed in sync with a vector representation.

Don't do that.

Instead, have just the one representation of speed - direction-magnitude. Implement turning by - omg - changing the direction value. That is, don't use a vector for Direction, but just a radian value instead. Similarly, just use a magnitude for both speed and acceleration.

Also, several other design and/or stylistic problems of note:

- Cwhat's ca cboat, canyway? (Seriously, try and give an example of an error that this kind of naming convention would catch and the compiler wouldn't.)

- Don't use (void) for function signatures. Use (). It's more consistent (that way, a function taking n arguments has n comma-delimited items inside the parentheses, for n=0 as well), more logical (void isn't a complete type, anyway, and there's nothing of void type that you intend to pass) and not considered "an abomination" (sic) by the people who matter.

- FFS, use constructors. And learn to love the concept of initialization.

- Even if you don't get to define constructors for D3DXVECTOR3, you can at least make a helper function to set them up. (Of course, if there is a constructor for D3DXVECTOR3 that does what you want, you should *use it*. Also, be aware of initializer lists.)

- Class constants should be static. Also, you might as well wrap the degrees-to-radians conversion up in the STEERING_RATE constant, since it's never used without that conversion. That way, you provide extra documentation - right in the initialization - that the value is a degree value.

- Don't use tabs within lines to line stuff up. They will invariably break with someone else's tab stop setting. Tabs are properly used for indenting lines up to the current level of indentation, if you use them at all (this way, variations in tab stop settings become an asset rather than a liability).

- Separate physics update logic from controlling logic. Completely. update() should *only* set stuff that remembers the desired changes; *not* any implementations of those changes.

- In general, avoid redundant data. Don't make class members for things that could be locals. In the code shown, only Capitalized values are members.

- Don't compare to boolean literals. It's an extra potential failure point that doesn't add clarity. If anything, it obscures; try it out on some plain English sentences and note the effect it has.

const double Boat::ACCELERATION_RATE =  0.5;const double Boat::BRAKING_RATE      = -4.0;const double Boat::REVERSE_RATE      = -10.0;const double Boat::FRICTION_RATE     = -1.0;const double Boat::STEERING_RATE     =  D3DXToRadian(2.0);const float  Boat::MAX_SPEED         =  2.4f;void initVectorXZ(D3DXVECTOR3& v, float x, float z) {	v.x = x; v.y = 0.0f; v.z = z;}Boat::Boat(float x, float z) : Acceleration(0.0), Steering(0.0), Heading(0.0), Speed(0.0) {	initVectorXZ(Position, x, z);	// It seems there used to be a member 'angle' which is now Heading.}void CBoat::updatePhysics(float dtime) {	// Apply Acceleration and Steering	Speed += Acceleration * dtime;	// Speed should be capped here. Note that you should cap it in the	// negative direction too since you allow for reversing :)	Speed = std::max(std::min(Speed, MAX_SPEED), -MAX_SPEED);	Heading += Steering * dtime;	// Disassemble Speed into x/z components and update our position.	float distance = Speed * dtime;	D3DXVECTOR3 displacement;	initVectorXZ(displacement, 	             distance * cos(Heading), distance * sin(Heading));	Position += displacement;	// Don't call update() from within here! Like I said, separate stuff.	// Call them both from a main loop. You want to be able to set your	// physics update rate, input polling rate and graphics render rate	// all independantly of each other. Trust me, you WILL have huge	// headaches otherwise sooner or later. I am telling you this out of	// real-world professional experience.}// The Boat shouldn't store information about the key presses directly; that// would make the Steering and Acceleration information redundant.// Instead, we pass that information in parameters.void CBoat::update(bool accelerate, bool brake, bool reverse, bool left, bool right) {	D3DXVECTOR3 vDirectionTemp;	// Friction should apply while the boat is in reverse, too.	Acceleration = 0;	if (accelerate && !brake && !reverse) {		Acceleration = ACCELERATION_RATE;	}	if (!accelerate) {		Acceleration = FRICTION_RATE * ((speed > 0) ? 1 : -1);	}	if (brake) {				Acceleration = BRAKING_RATE;	}	if (reverse && !accelerate && !brake) {				//code to reverse the boat	}	Steering = 0;	// I might have the signs wrong for steering values. That will be easy	// to test and fix, however. :P	if (left && speed >= 0.0f) {		// You might want to reconsider the speed restriction later :)		Steering = STEERING_RATE;	}	if (right && speed >= 0.0f) {		Steering = -STEERING_RATE;	}}


There, that wasn't so hard, was it? :}
I have done what you have suggested and the boat will not move anywhere, and when i press left or right it just flickers a bit right and left

Here is the code
boat.h
#pragma once#include "../GameObject/GameObject.h"#include "../BoundingBox/boundingvolumes.h"#include "../Model/Model.h"#include "../constants/Constants.h"class CModel;class CD3DTimer;class Boat : CGameObject{public:	Boat();	virtual ~Boat();	CBoundingVolumes	*pBoundingBox;	float	Health;	float	Heading;	float	Speed;	float	Acceleration;	float	Steering;	D3DXVECTOR3 vDisplacement;	bool	create(LPDIRECT3DDEVICE9 device);	void	render(LPDIRECT3DDEVICE9 device);	void	setPosition(D3DXVECTOR3 newPosition);		void	setSize(float Size);	void	getPosition(D3DXVECTOR3 &Position);        void	update(bool accelerate, bool brake, bool reverse, bool left, bool right) ;						void	updatePhysics(float dtime);	void    get_BoundingBox(sBoundingBox* BBox);	void    initVectorXZ(D3DXVECTOR3& v, float x, float z);private:	CModel *Model;			//Pointer to Model Class	float	size;			// The size of the Boat	D3DXMATRIX transMatrix;		// the translation matrix	D3DXMATRIX rotMatrix;		// the rotation matrix	D3DXMATRIX scaleMatrix;		// the scale matrix	//*******************************************************************	// Private Const's	//*******************************************************************	static const float ACCELERATION_RATE;	static const float BRAKING_RATE;	static const float REVERSE_RATE;	static const float FRICTION_RATE;	static const float STEERING_RATE;	static const float  MAX_SPEED;};


boat.cpp
#define NOMINMAX#include "Boat.h"#include "../Header/Header.h"//**************** globals/* Init the one and only ProjectManager */	static dxManager& dxMgr = dxManager::getInstance();const float Boat::ACCELERATION_RATE =  0.5;const float Boat::BRAKING_RATE      = -4.0;const float Boat::REVERSE_RATE      = -10.0;const float Boat::FRICTION_RATE     = -1.0;const float Boat::STEERING_RATE     =  D3DXToRadian(2.0f);const float  Boat::MAX_SPEED         =  2.4f;Boat::Boat(){	vDisplacement.x = 0.0f;	vDisplacement.y = 0.0f;	vDisplacement.z = 0.0f;	Speed = 0.0f;}Boat::~Boat(){	pBoundingBox = NULL;}bool Boat::create(LPDIRECT3DDEVICE9 device){	//Setup the Boats physics 1st	Model = new CModel();	Model->loadModel(device, "./models/BOAT4.X");	pBoundingBox = new CBoundingVolumes();	pBoundingBox->BoundingVolumes_CreateBox(device,Model->mesh,size);	return true;}void	Boat::get_BoundingBox(sBoundingBox* BBox){	*BBox = pBoundingBox->s_BoundingBox;}void Boat::setPosition(D3DXVECTOR3 newPosition){	positionVector = newPosition;}void Boat::getPosition(D3DXVECTOR3 &Position) {	Position = positionVector;} void Boat::initVectorXZ(D3DXVECTOR3& v, float x, float z) {	v.x = x; 	v.y = 0.0f; 	v.z = z;}void Boat::updatePhysics(float dtime) {	// Apply Acceleration and Steering	Speed += Acceleration * dtime;	// Speed should be capped here. Note that you should cap it in the	// negative direction too since you allow for reversing :)	Speed = std::max(std::min(Speed, MAX_SPEED), -MAX_SPEED);	Heading += Steering * dtime;	// Disassemble Speed into x/z components and update our position.	float distance = Speed * dtime;		initVectorXZ(vDisplacement,distance * cos(Heading), distance * sin(Heading));	positionVector += vDisplacement;}void Boat::update(bool accelerate, bool brake, bool reverse, bool left, bool right) {	D3DXVECTOR3 vDirectionTemp;	// Friction should apply while the boat is in reverse, too.	Acceleration = 0;	if (accelerate && !brake && !reverse) 	{		Acceleration = ACCELERATION_RATE;	}	if (!accelerate) 	{		Acceleration = FRICTION_RATE * Speed;	}	if (brake) 	{				Acceleration = BRAKING_RATE;	}	if (reverse && !accelerate && !brake) 	{				Acceleration = REVERSE_RATE;	}	Steering = 0;	if (left) 	{		Steering = -STEERING_RATE;	}	if (right) 	{		Steering = STEERING_RATE;	}}void Boat::render(LPDIRECT3DDEVICE9 device){	D3DXMatrixTranslation(&transMatrix, positionVector.x, positionVector.y, positionVector.z);	D3DXMatrixRotationY(&rotMatrix,Steering);	D3DXMatrixScaling(&scaleMatrix, size, size, size);	D3DXMatrixMultiply(&transMatrix, &rotMatrix, &transMatrix);	D3DXMatrixMultiply(&transMatrix, &scaleMatrix, &transMatrix);	device->SetTransform(D3DTS_WORLD, &transMatrix);	Model->render(device);}void Boat::setSize(float Size){	size = Size;}
The problem is that you have redundant data - you store a "speed" and also a "velocity," and they get a little out of synch. When you try to synch them you get errors (effectively absolute-valueing your speed). You also have a direction vector and an acceleration vector, but it seems like they must always be in the same direction.

As Zahlman suggests, you can fix this by getting rid of those redundant variables.

If you don't want to change how you calculate direction, etc, I think you could get away with taking out the line that says "vVelocity = vDirection * speed". If you take that out, you'll notice that the boat will start to coast sideways when you turn, but you should also be able to reverse. This would also break your braking code because vDirection will no longer be in the same direction as vVelocity (note that in real life, the direction a boat is facing and the direction of its velocity are often different).

Edit: I made this post before reading your most recent post. I was referring to the original post.
--Riley
I say go for tabs. People can always convert back and forth automatically to use the setting they wish.
Quote:Original post by Prog101
I have done what you have suggested and the boat will not move anywhere, and when i press left or right it just flickers a bit right and left


Did you see this part?

Quote:
// Don't call update() from within here! Like I said, separate stuff.
// Call them both from a main loop. You want to be able to set your
// physics update rate, input polling rate and graphics render rate
// all independantly of each other. Trust me, you WILL have huge
// headaches otherwise sooner or later. I am telling you this out of
// real-world professional experience.


(Also, the displacement was very deliberately made into a local, and initVectorXZ a global function and NOT a member function. You might want to think about why.)

Failing that, have you tried debugging? Are the functions called when expected? Does 'Speed' get a sane value? How about 'distance' and the 'vDisplacement'?

This topic is closed to new replies.

Advertisement