Page 1 of 1

My Player Struct

Posted: Thu Apr 30, 2009 7:41 pm
by mell1ej
Hello everybody :)

For the past few hours i have been working on this Player struct, most things are working fine but i have a few problems :(

1.) I have no idea how to modify the players (fpscamera) jumpheight after loading the camera.

2.) Crouching is not working as it is supposed to be, you get stuck after you crouch or cant get up again.

Now i was wondering if somebody could explain me these two things, and ofcource general tips are welcome aswell :D

Here is my code:

Code: Select all

// The Irrlicht examples where very usefull :)
struct Player : public IAnimationEndCallBack
{
	Player();
	Player(const string<char> &pName, WorldData* nWorldData);
	ISceneNodeAnimatorCollisionResponse* camCollisionResponse(IrrlichtDevice* device, ICameraSceneNode* camera);
	void OnAnimationEnd(IAnimatedMeshSceneNode* node);
	bool Load();	
	void Update();
	void Respawn();
	void Shoot();
	void Setpos(vector3df &pos, vector3df &rotation);
	void SetWeaponAnim(char* animation);
	void SetRunSpeed(float value);
	void SetRotateSpeed(float value);
	void SetJumpHeight(float value);
	void SetJumpSpeed(float value);
	void SetFlyMode(bool value);
	void SetGravity(vector3df &value);
	void ToggleCrouch(bool value);
	void ToggleCollision(bool value);

	WorldData* worldData;

	SKeyMap keyMap[10];

	ICameraSceneNode* camera;
	IAnimatedMeshSceneNode* WeaponNode;

	string<char> playerName;

	vector3df playerPosition, playerRotation, playerTarget, playerGravityForce, playerEllipsoidRadius, playerEllipsoidTranslation, weaponPosition, weaponRotation;
	vector3df defaultPlayerPosition, defaultPlayerRotation, defaultPlayerGravityForce, defaultPlayerEllipsoidRadius, defaultPlayerEllipsoidTranslation, defaultWeaponPosition, defaultWeaponRotation;

	float playerRunSpeed, playerRotateSpeed, playerJumpSpeed, playerJumpHeight, playerHeight;
	float defaultPlayerRunSpeed, defaultPlayerRotateSpeed, defaultPlayerJumpSpeed, defaultPlayerJumpHeight, defaultPlayerHeight;

	bool verticalMovement, crouching, collision;

	ISceneNodeAnimator* anim;
	ISceneNodeAnimatorCameraFPS* animFPS;
	ISceneNodeAnimatorCollisionResponse* animColResp;
};

Player::Player(){}

Player::Player(const string<char> &pName, WorldData* nWorldData)
{
	verticalMovement = true;
	crouching = false;

	playerName = pName;
	worldData = nWorldData;

	playerGravityForce = vector3df(0, -10.0f, 0);
	playerPosition = vector3df(50, 50, -60);
	playerRotation = vector3df(-70, 30, -60);
	playerEllipsoidRadius = vector3df(30, 50, 30);
	playerEllipsoidTranslation = vector3df(0, 30, 0);
	weaponPosition = vector3df(0, 0, 0);
	weaponRotation = vector3df(-90,-90,90);
	playerRunSpeed = 0.3f;
	playerRotateSpeed = 100.0f;
	playerJumpSpeed = 3.0f;
	playerJumpHeight = 200.0f;
	playerHeight = 50.0f;

	defaultPlayerPosition = playerPosition;
	defaultPlayerRotation = playerRotation;
	defaultPlayerGravityForce = playerGravityForce;
	defaultPlayerRunSpeed = playerRunSpeed;
	defaultPlayerRotateSpeed = playerRotateSpeed;
	defaultPlayerJumpSpeed = playerJumpSpeed;
	defaultPlayerJumpHeight = playerJumpHeight;
	defaultPlayerHeight = playerHeight;
	defaultPlayerEllipsoidRadius = playerEllipsoidRadius;
	defaultPlayerEllipsoidTranslation = playerEllipsoidTranslation;
	defaultWeaponPosition = weaponPosition;
	defaultWeaponRotation = weaponRotation;
}

ISceneNodeAnimatorCollisionResponse* Player::camCollisionResponse(IrrlichtDevice* device, ICameraSceneNode* camera)
{
	for (list<ISceneNodeAnimator*>::ConstIterator it = camera->getAnimators().begin(); it != camera->getAnimators().end(); ++it)
	{
		ISceneNodeAnimatorCollisionResponse* a = (ISceneNodeAnimatorCollisionResponse*) (*it);
		if (a->getType() == ESNAT_COLLISION_RESPONSE) return a;
	}

	return 0;
}

void Player::OnAnimationEnd(IAnimatedMeshSceneNode* node)
{
	worldData->Logger->log("Player::OnAnimationEnd()");
	SetWeaponAnim(0);
}

bool Player::Load()
{
	worldData->Logger->log("Player::Load()");

	keyMap[0].Action = EKA_MOVE_FORWARD;
	keyMap[0].KeyCode = KEY_UP;
	keyMap[1].Action = EKA_MOVE_FORWARD;
	keyMap[1].KeyCode = KEY_KEY_W;

	keyMap[2].Action = EKA_MOVE_BACKWARD;
	keyMap[2].KeyCode = KEY_DOWN;
	keyMap[3].Action = EKA_MOVE_BACKWARD;
	keyMap[3].KeyCode = KEY_KEY_S;

	keyMap[4].Action = EKA_STRAFE_LEFT;
	keyMap[4].KeyCode = KEY_LEFT;
	keyMap[5].Action = EKA_STRAFE_LEFT;
	keyMap[5].KeyCode = KEY_KEY_A;

	keyMap[6].Action = EKA_STRAFE_RIGHT;
	keyMap[6].KeyCode = KEY_RIGHT;
	keyMap[7].Action = EKA_STRAFE_RIGHT;
	keyMap[7].KeyCode = KEY_KEY_D;

	keyMap[8].Action = EKA_JUMP_UP;
	keyMap[8].KeyCode = KEY_SPACE; 

	keyMap[9].Action = EKA_CROUCH;
	keyMap[9].KeyCode = KEY_LSHIFT; 

	camera = worldData->smgr->addCameraSceneNodeFPS(0, playerRotateSpeed, playerRunSpeed, -1, keyMap, sizeof(keyMap), verticalMovement, playerJumpSpeed);
	camera->setName("First Person Camera");
	camera->setFarValue(10000.0f);

	IAnimatedMeshMD2* weaponMesh = (IAnimatedMeshMD2*)worldData->smgr->getMesh("gun.md2");
	if (weaponMesh == 0)
	{
		worldData->Logger->log("Failed to Load: Gun.md2");
		MessageBox(0, "Failed to Load: Gun.md2", "Load Error!", 0);
		return false;
	}

	if (weaponMesh->getMeshType() == EAMT_MD2)
	{
		char buf[64];
		for (s32 i = 0; i != weaponMesh->getAnimationCount(); i++)
		{
			sprintf_s(buf, sizeof(buf), "Animations for Gun.md2: %s", weaponMesh->getAnimationName(i));
			worldData->Logger->log(buf);
		}
	}

	ITexture* gunTexture = worldData->videoDriver->getTexture("gun.jpg");
	if (gunTexture == 0)
	{
		worldData->Logger->log("Failed to Load: Gun.jpg");
		MessageBox(0, "Failed to Load: Gun.jpg", "Load Error!", 0);
		return false;
	}

	WeaponNode = worldData->smgr->addAnimatedMeshSceneNode(weaponMesh, camera, -1, weaponPosition, weaponRotation); 
	WeaponNode->setMaterialTexture(0, gunTexture);
	WeaponNode->setLoopMode(false);
	WeaponNode->setMaterialFlag(EMF_LIGHTING, false);
	WeaponNode->setName("Weapon");

	//create a collision auto response animator
	anim = worldData->smgr->createCollisionResponseAnimator(worldData->triangleSelector, camera, playerEllipsoidRadius, playerGravityForce, playerEllipsoidTranslation);
	camera->addAnimator(anim);
	//anim->drop();

	list<ISceneNodeAnimator*>::ConstIterator animsFPSList = camera->getAnimators().begin(); 
	animFPS = (ISceneNodeAnimatorCameraFPS*)*animsFPSList;

	animColResp = camCollisionResponse(worldData->device, camera);

	Respawn();

	return true;
}

void Player::Update()
{
	playerPosition = camera->getPosition();
	playerRotation = camera->getRotation();
	playerTarget = camera->getTarget();

	if(playerPosition.Y < -10000.0f) Respawn();
}

void Player::Respawn()
{
	worldData->Logger->log("Player::Respawn()");

	Setpos(defaultPlayerPosition, defaultPlayerRotation);
	SetWeaponAnim("idle");
}

void Player::Setpos(vector3df &pos, vector3df &rotation)
{
	worldData->Logger->log("Player::SetPos()");

	camera->setPosition(pos);
	camera->setRotation(rotation);
	camera->OnAnimate(0);
}

void Player::SetWeaponAnim(char* name)
{
	worldData->Logger->log("Player::SetAnim()"); 

	char animation[64];

	if (name)
	{
		strcpy(animation, name);
		if (WeaponNode)
		{
			WeaponNode->setAnimationEndCallback(this);
			WeaponNode->setMD2Animation(animation);
		}
	}
	else
	{
		animation[0] = 0;
		if (WeaponNode) WeaponNode->setAnimationEndCallback(0);
	}
}

void Player::Shoot()
{
	//worldData->Logger->log("Player::Shoot()");

	vector3df start = camera->getPosition();
	vector3df end = (camera->getTarget() - start).normalize();

	start += end * 8.0f;
	end = start + (end * camera->getFarValue());

	SParticleImpact imp;
	imp.when = 0;

	triangle3df triangle;
	line3d<float> line(start, end);

	// get intersection point with map
	const ISceneNode* hitNode;
	if (worldData->collMan->getCollisionPoint(line, worldData->triangleSelector, end, triangle, hitNode))
	{
		// collides with wall
		vector3df out = triangle.getNormal();
		out.setLength(0.03f);

		imp.when = 1;
		imp.outVector = out;
		imp.pos = end;
	}
	else // doesnt collide with wall
	{
		start = camera->getPosition();
		end = (camera->getTarget() - start).normalize();

		end = start + (end * camera->getFarValue());
	}

	// create fire ball
	ISceneNode* node = worldData->smgr->addBillboardSceneNode(0, dimension2d<float>(25,25), start);

	node->setMaterialFlag(EMF_LIGHTING, false);
	node->setMaterialTexture(0, worldData->bulletTexture);
	node->setMaterialType(EMT_TRANSPARENT_ADD_COLOR);

	float length = (end - start).getLength();
	float time = length / 2.0f;

	ISceneNodeAnimator* anim = worldData->smgr->createFlyStraightAnimator(start, end, time);
	node->addAnimator(anim);
	anim->drop();

	anim = worldData->smgr->createDeleteAnimator(time);
	node->addAnimator(anim);
	anim->drop();

	if (imp.when) // create impact note
	{
		imp.when = worldData->device->getTimer()->getTime() + time - 100;
		worldData->Impacts.push_back(imp);
	}

	worldData->irrKlang->play2D(worldData->ballSound);
}

void Player::SetRunSpeed(float value)
{
	worldData->Logger->log("Player::SetRunSpeed()");
	playerRunSpeed = value;

	animFPS->setMoveSpeed(playerRunSpeed);
}

void Player::SetRotateSpeed(float value)
{
	worldData->Logger->log("Player::SetRotateSpeed()");
	playerRotateSpeed = value;

	animFPS->setRotateSpeed(playerRotateSpeed);
}
void Player::SetJumpHeight(float value) // Not Working At All!
{
	worldData->Logger->log("Player::SetJumpHeight()");
	playerJumpHeight = value;

	//
}
void Player::SetJumpSpeed(float value)
{
	worldData->Logger->log("Player::SetJumpSpeed()");
	playerJumpSpeed = value;

	animColResp->jump(playerJumpSpeed);
}

void Player::SetFlyMode(bool value)
{
	worldData->Logger->log("Player::SetFlyMode()");

	verticalMovement = value;

	if(verticalMovement) SetGravity(vector3df(0, 0, 0));
	else SetGravity(defaultPlayerGravityForce);

	animFPS->setVerticalMovement(verticalMovement);
}

void Player::SetGravity(vector3df &value)
{	
	worldData->Logger->log("Player::SetGravity()");
	playerGravityForce = value;
	animColResp->setGravity(playerGravityForce);
}

void Player::ToggleCrouch(bool value) // Not Working Correctly!
{
	worldData->Logger->log("Player::ToggleCrouch()");
	crouching = value;

	if(crouching)
	{
		animColResp->setEllipsoidRadius(vector3df(30, 20, 30));
		animColResp->setEllipsoidTranslation(vector3df(0, 20, 0));

		SetRunSpeed(defaultPlayerRunSpeed / 4);
		SetJumpHeight(defaultPlayerJumpHeight / 3);
	}
	else
	{
		animColResp->setEllipsoidRadius(defaultPlayerEllipsoidRadius);
		animColResp->setEllipsoidTranslation(defaultPlayerEllipsoidTranslation);

		SetRunSpeed(defaultPlayerRunSpeed);
		SetJumpHeight(defaultPlayerJumpHeight);
	}
}

void Player::ToggleCollision(bool value)
{
	worldData->Logger->log("Player::ToggleCollision()");
	collision = value;

	if(collision) camera->addAnimator(anim);
	else camera->removeAnimator(anim);
}
Thank you :)

PS. You are free to use this in your own project if you want, even though it would be nice is you mention me somewhere :P

Re: My Player Struct

Posted: Sun Dec 21, 2014 2:16 am
by Asimov
Hi mell,

I would be interested to know why you opted for a struct rather than a class?

Re: My Player Struct

Posted: Wed Dec 24, 2014 3:00 pm
by sudi
Asimov wrote:Hi mell,

I would be interested to know why you opted for a struct rather than a class?
Probably because they work the same and he wanted all functions and variables to be public.

Re: My Player Struct

Posted: Wed Dec 24, 2014 5:18 pm
by Asimov
Hi Sudi,

You can have public variables and functions in a class also.