Files
DoomRTX/neo/prey/Prey/game_barrel.cpp
T
2026-05-05 15:01:01 -07:00

182 lines
4.1 KiB
C++

#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
CLASS_DECLARATION( hhMoveable, hhBarrel )
END_CLASS
/*
================
hhBarrel::hhBarrel
================
*/
hhBarrel::hhBarrel() {
radius = 1.0f;
barrelAxis = 0;
lastOrigin.Zero();
lastAxis.Identity();
additionalRotation = 0.0f;
additionalAxis.Identity();
fl.networkSync = true;
}
/*
================
hhBarrel::Save
================
*/
void hhBarrel::Save( idSaveGame *savefile ) const {
savefile->WriteFloat( radius );
savefile->WriteInt( barrelAxis );
savefile->WriteVec3( lastOrigin );
savefile->WriteMat3( lastAxis );
savefile->WriteFloat( additionalRotation );
savefile->WriteMat3( additionalAxis );
}
/*
================
hhBarrel::Restore
================
*/
void hhBarrel::Restore( idRestoreGame *savefile ) {
savefile->ReadFloat( radius );
savefile->ReadInt( barrelAxis );
savefile->ReadVec3( lastOrigin );
savefile->ReadMat3( lastAxis );
savefile->ReadFloat( additionalRotation );
savefile->ReadMat3( additionalAxis );
}
/*
================
hhBarrel::BarrelThink
================
*/
void hhBarrel::BarrelThink( void ) {
bool wasAtRest, onGround;
float movedDistance, rotatedDistance, angle;
idVec3 curOrigin, gravityNormal, dir;
idMat3 curAxis, axis;
wasAtRest = IsAtRest();
// run physics
RunPhysics();
// only need to give the visual model an additional rotation if the physics were run
if ( !wasAtRest ) {
// current physics state
onGround = GetPhysics()->HasGroundContacts();
curOrigin = GetPhysics()->GetOrigin();
curAxis = GetPhysics()->GetAxis();
// if the barrel is on the ground
if ( onGround ) {
gravityNormal = GetPhysics()->GetGravityNormal();
dir = curOrigin - lastOrigin;
dir -= gravityNormal * dir * gravityNormal;
movedDistance = dir.LengthSqr();
// if the barrel moved and the barrel is not aligned with the gravity direction
if ( movedDistance > 0.0f && idMath::Fabs( gravityNormal * curAxis[barrelAxis] ) < 0.7f ) {
// barrel movement since last think frame orthogonal to the barrel axis
movedDistance = idMath::Sqrt( movedDistance );
dir *= 1.0f / movedDistance;
movedDistance = ( 1.0f - idMath::Fabs( dir * curAxis[barrelAxis] ) ) * movedDistance;
// get rotation about barrel axis since last think frame
angle = lastAxis[(barrelAxis+1)%3] * curAxis[(barrelAxis+1)%3];
angle = idMath::ACos( angle );
// distance along cylinder hull
rotatedDistance = angle * radius;
// if the barrel moved further than it rotated about it's axis
if ( movedDistance > rotatedDistance ) {
// additional rotation of the visual model to make it look
// like the barrel rolls instead of slides
angle = 180.0f * (movedDistance - rotatedDistance) / (radius * idMath::PI);
if ( gravityNormal.Cross( curAxis[barrelAxis] ) * dir < 0.0f ) {
additionalRotation += angle;
} else {
additionalRotation -= angle;
}
dir = vec3_origin;
dir[barrelAxis] = 1.0f;
additionalAxis = idRotation( vec3_origin, dir, additionalRotation ).ToMat3();
}
}
}
// save state for next think
lastOrigin = curOrigin;
lastAxis = curAxis;
}
Present();
}
/*
================
hhBarrel::Think
================
*/
void hhBarrel::Think( void ) {
if ( thinkFlags & TH_THINK ) {
if ( !FollowInitialSplinePath() ) {
BecomeInactive( TH_THINK );
}
}
BarrelThink();
}
/*
================
hhBarrel::GetPhysicsToVisualTransform
================
*/
bool hhBarrel::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
origin = vec3_origin;
axis = additionalAxis;
return true;
}
/*
================
hhBarrel::Spawn
================
*/
void hhBarrel::Spawn( void ) {
const idBounds &bounds = GetPhysics()->GetBounds();
// radius of the barrel cylinder
radius = ( bounds[1][0] - bounds[0][0] ) * 0.5f;
// always a vertical barrel with cylinder axis parallel to the z-axis
barrelAxis = 2;
lastOrigin = GetPhysics()->GetOrigin();
lastAxis = GetPhysics()->GetAxis();
additionalRotation = 0.0f;
additionalAxis.Identity();
}
/*
================
hhBarrel::ClientPredictionThink
================
*/
void hhBarrel::ClientPredictionThink( void ) {
Think();
}