Game Development Community

dev|Pro Game Development Curriculum

Basic Weapon Sway

by Bryce · 04/05/2010 (1:57 pm) · 22 comments

This resource will implement weapon sway in your project. An alternative to a motionless weapon image floating on your screen, weapon sway adds a bit more life to it. When the player turns, the weapon will move a bit in that direction, and when the player stops turning, the weapon creeps back to its original position. It adds a bit more of a natural feel if you ask me.


Issues:

1)Since the $mvPitch and $mvYaw values are updated too inconsistently to produce smooth sway, I have a function that gets these values once every 10th of a second. This most likely won't work networked.
2)Sometimes flickers. I only have this issue with Torque 3D. I'll look into it. EDIT: See comment #11 for the fix
3)Overall, this is an extremely hacky implementation of sway, just an FYI.

Implementation:

Open up T3D/player.h

In struct PlayerData: public ShapeBaseData {, under F32 minImpactSpeed;, add

// weapon sway
   F32 weaponSwayAmtX;
   F32 weaponSwayAmtZ;
   F32 weaponSwayResetX;
   F32 weaponSwayResetZ;

In class Player: public ShapeBase, under S32 mJumpDelay;, add

F32 mSwayX;
   F32 mSwayZ;
   F32 Yaw;
   F32 Pitch;

Open up T3D/player.cpp

In PlayerData::PlayerData(), under minImpactSpeed = 25.0f;, add

weaponSwayAmtX = 0.0005;
   weaponSwayAmtZ = 0.0005;
   weaponSwayResetX = 0.0005;
   weaponSwayResetZ = 0.0005;

In PlayerData::initPersistFields(), under addField("minImpactSpeed", TypeF32, Offset(minImpactSpeed, PlayerData));, add

addField("weaponSwayAmtX", TypeF32, Offset(weaponSwayAmtX, PlayerData));
	   addField("weaponSwayAmtZ", TypeF32, Offset(weaponSwayAmtZ, PlayerData));
	   addField("weaponSwayResetX", TypeF32, Offset(weaponSwayResetX, PlayerData));
	   addField("weaponSwayResetZ", TypeF32, Offset(weaponSwayResetZ, PlayerData));

Find stream->write(minImpactSpeed);, and under it, add

stream->write(weaponSwayAmtX);
   stream->write(weaponSwayAmtZ);
   stream->write(weaponSwayResetX);
   stream->write(weaponSwayResetZ);

Find stream->read(&minImpactSpeed);. Under it, add

stream->read(&weaponSwayAmtX);
   stream->read(&weaponSwayAmtZ);
   stream->read(&weaponSwayResetX);
   stream->read(&weaponSwayResetZ);

Find mReversePending = 0;, and under it, stick in

mSwayX = 0;
   mSwayZ = 0;

In Player::processTick(const Move* move), find updatePos();. Under it, add

// weapon sway
		  F32 amtX;
		  F32 amtZ;
		  F32 resetX;
		  F32 resetZ;
		  F32 limitX;
		  F32 limitZ;
		  amtX = mDataBlock->weaponSwayAmtX;
		  amtZ = mDataBlock->weaponSwayAmtZ;
		  resetX = mDataBlock->weaponSwayResetX;
		  resetZ = mDataBlock->weaponSwayResetZ;
		  limitX = 0.02 * 0.2;
		  limitZ = 0.02 * 0.2;
		  if (Yaw > 0 && Yaw != 0 && mSwayX < limitX)
			  mSwayX += amtX;
		  if (Yaw < 0 && Yaw != 0 && mSwayX > -limitX)
			  mSwayX -= amtX;
		  // Yaw sway
		  if (Yaw == 0)
		  {
			  if (mSwayX < 0)
				  mSwayX += resetX;
			  if (mSwayX > 0)
				  mSwayX -= resetX;
		  }
		  // Now do pitch sway
		  if (Pitch > 0 && Pitch != 0 && mSwayZ < limitZ)
			  mSwayZ += amtZ;
		  if (Pitch < 0 && Pitch != 0 && mSwayZ > -limitZ)
			  mSwayZ -= amtZ;
		  if (Pitch == 0)
		  {
			  if (mSwayZ < 0)
				  mSwayZ += resetZ;
			  if (mSwayZ > 0)
				  mSwayZ -= resetZ;
		  }

In Player::RenderMountedImage, under world.mul(nmat,offsetMat);, add

GameConnection* con = getControllingClient();
		  Yaw = Con::getFloatVariable("$swayYaw");
		  Pitch = Con::getFloatVariable("$swayPitch");
		  if (con->isAIControlled())
		  {
			  mSwayX = 0;
			  mSwayZ = 0;
		  }
	  	 Point3F swayDisplace;
		 swayDisplace.x = mSwayX;
                 swayDisplace.y = 0.0f;
		 swayDisplace.z = mSwayZ;

In this same block, locate world.setPosition( world.getPosition() + displace);, and change it to

world.setPosition( world.getPosition() + displace + swayDisplace);

That's it for engine changes. Compile, good luck. You should get a lot of warnings about “truncation from 'double' to 'F32'” with Visual C++. I'm not exactly sure what causes it, I don't do a lot of T3D engine coding. Anyone care to shine some light on this?

Anyway. Scripts. Open game/scripts/client/default.bind.cs, and locate
function panDown( %val )
{
   $mvPitchUpSpeed = %val ? $Pref::Input::KeyboardTurnSpeed : 0;
}

Underneath it, add
function getTurnValues()
{
	$gettingTurnValues = true;
	$swayYaw = $mvYaw;
	$swayPitch = $mvPitch;
	schedule(100,0,getTurnValues);
}

Now, find
function getMouseAdjustAmount(%val)
{	    
   // based on a default camera FOV of 90'
   return(%val * ($cameraFov / 90) * 0.01) * $pref::Input::LinkMouseSensitivity;
}

Change it to
function getMouseAdjustAmount(%val)
{
	if (!$gettingTurnValues)
	  getTurnValues();
	    
   // based on a default camera FOV of 90'
   return(%val * ($cameraFov / 90) * 0.01) * $pref::Input::LinkMouseSensitivity;
}

Now, open up art/datablocks/player.cs, go to the DefaultPlayerData datablock, and add in
// Weapon sway
   weaponSwayAmtX = 0.0012;
   weaponSwayAmtZ = 0.0012;
   weaponSwayResetX = 0.0010;
   weaponSwayResetZ = 0.0010;

Do this for your other player datablocks if you have them.

Go into your game, and give it a try! Good luck, and happy Torque'ing!
Page «Previous 1 2
#1
04/05/2010 (2:37 pm)
Good Resource Bryce !
#2
04/05/2010 (2:43 pm)
ya good resorce will bookmark it with the other ones I have saved.
#3
04/05/2010 (2:44 pm)
Thank you Bryce. Very useful!
#4
04/05/2010 (3:29 pm)
So I take it that this resource won't work on multiplayer?
#5
04/05/2010 (3:31 pm)
@Tek0: I haven't tested, but it's extremely likely that something will go wrong.
#6
04/06/2010 (2:10 am)
Thanks man, I really appreciate this!
#7
04/06/2010 (3:19 am)
Oooo ... pawned at the end. ;)

Awesome resource man ... will give it a bash. :)
#8
04/06/2010 (7:06 am)
Worked perfectly, except from ->

EDIT2: Edited the picture
img149.imageshack.us/img149/6977/screenshot01200001.png
So whats happening is that when i do a 360 turn, 75% of the degrees i turn the weapon disappears or moves like five meters in front of me. I think this might be related to your 2. known issue. Anyone else experienced this?

EDIT: if shooting while the weapon is far away, it will reset back players hand, and then if you turn it will mess up again.
#9
04/06/2010 (2:00 pm)
@Marcus - seeing the same thing here. Only just implemented it so I haven't looked into it yet but something's definitely acting odd!
#10
04/06/2010 (4:05 pm)
Update: if I add a console message to the last bit of engine code above:
Con::errorf("swayDisplace.x: %f, swayDisplace.z: %f.", swayDisplace.x, swayDisplace.z);
world.setPosition(world.getPosition() + displace + swayDisplace);

then it works fine. Which makes no sense!
#11
04/06/2010 (4:17 pm)
Looks like it was the undefined y value of swayDisplace causing the problem. Got it working now.

In Player::RenderMountedImage, after:

mSwayX = 0.0f;
   mSwayZ = 0.0f;
}
Point3F swayDisplace;
swayDisplace.x = mSwayX;
swayDisplace.z = mSwayZ;

Add:

swayDisplace.y = 0.0f

You may notice I've used mSwayX = 0.0f rather than just 0. I've added the f when initialising all floating point variables - that gets rid of the truncation from double to F32 warnings.
#12
04/06/2010 (4:22 pm)
Thanks Eikon. Your fix worked just fine.
#13
04/06/2010 (4:38 pm)
@Marcus: Glad to hear it.

@Bryce: Thanks for an excellent resource - the 'weapon stuck to screen' view has bugged me for years!
#14
04/11/2010 (7:04 pm)
Has anyone tried this in multiplayer?
#15
05/01/2010 (6:59 pm)
-removed-
#16
08/04/2010 (9:14 pm)
I'm going to attempt this in multiplayer as soon as I get the chance, so let me see if it works or does not.
#17
08/04/2010 (9:15 pm)
It just might. The thing I'm most worried about is if one person's sway, particularly the host's, will affect everyone else's view.
#18
08/04/2010 (9:23 pm)
Alright, I'll look for that when I test it, I'll post my results here within two hours, for some reason I'm having trouble with the TorquePowered.com website...
#19
08/04/2010 (9:37 pm)
Bryce, I'm attempting this in TGE 1.5.2, because I have not yet gotten T3D, and I've been able to follow it through up to the point where I have to find: "In Player::RenderMountedImage, under world.mul(nmat,offsetMat);, add." I do not have a world.mul (nmat, offsetMat); in the file. Where should I add it for TGE?

EDIT: It actually looks as if from that point on its no longer TGE compatible. :(
#20
08/06/2010 (6:45 pm)
I originally implemented this in TGE, and used the same function that's used to push the weapon out of walls, glTranslate(x,y,z). I don't know exactly how I did it, because I lost my original TGE code in a crash, but I think it was something along the lines of this somewhere in Player::RenderMountedImage :

F32 sX = Con::getFloatVariable("$swayYaw"); 
F32 sZ = Con::getFloatVariable("$swayPitch");
glTranslatef(sX,0,sZ);

Good luck :)
Page «Previous 1 2