Implemented basic physics for projectiles.

master
madmaxoft 2013-08-27 19:57:37 +02:00
parent f260e9211f
commit 6677a5e8ca
7 changed files with 157 additions and 36 deletions

View File

@ -31,12 +31,12 @@ public:
/** Called on each block encountered along the path, including the first block (path start)
When this callback returns true, the tracing is aborted.
*/
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) = 0;
/** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded
When this callback returns true, the tracing is aborted.
*/
virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) { return false; }
virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) { return false; }
/** Called when the path goes out of world, either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height)
The coords specify the exact point at which the path exited the world.

View File

@ -7,6 +7,57 @@
#include "ProjectileEntity.h"
#include "../ClientHandle.h"
#include "Player.h"
#include "../LineBlockTracer.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProjectileTracerCallback:
class cProjectileTracerCallback :
public cBlockTracer::cCallbacks
{
public:
cProjectileTracerCallback(cProjectileEntity * a_Projectile) :
m_Projectile(a_Projectile)
{
}
protected:
cProjectileEntity * m_Projectile;
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
{
if (g_BlockIsSolid[a_BlockType])
{
// The projectile hit a solid block
m_Projectile->OnHitSolidBlock(a_BlockX, a_BlockY, a_BlockZ, a_EntryFace);
return true;
}
// Convey some special effects from special blocks:
switch (a_BlockType)
{
case E_BLOCK_LAVA:
case E_BLOCK_STATIONARY_LAVA:
{
m_Projectile->StartBurning(30);
break;
}
case E_BLOCK_WATER:
case E_BLOCK_STATIONARY_WATER:
{
m_Projectile->StopBurning();
break;
}
} // switch (a_BlockType)
// Continue tracing
return false;
}
} ;
@ -18,7 +69,8 @@
cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height) :
super(etProjectile, a_X, a_Y, a_Z, a_Width, a_Height),
m_ProjectileKind(a_Kind),
m_Creator(a_Creator)
m_Creator(a_Creator),
m_IsInGround(false)
{
}
@ -29,7 +81,8 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a
cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height) :
super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height),
m_ProjectileKind(a_Kind),
m_Creator(a_Creator)
m_Creator(a_Creator),
m_IsInGround(false)
{
SetSpeed(a_Speed);
}
@ -60,6 +113,35 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
void cProjectileEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
{
// TODO: Set proper position based on what face was hit
switch (a_BlockFace)
{
case BLOCK_FACE_TOP: SetPosition(0.5 + a_BlockX, 1.0 + a_BlockY, 0.5 + a_BlockZ); break;
case BLOCK_FACE_BOTTOM: SetPosition(0.5 + a_BlockX, a_BlockY, 0.5 + a_BlockZ); break;
case BLOCK_FACE_EAST: SetPosition( a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
case BLOCK_FACE_WEST: SetPosition(1.0 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
case BLOCK_FACE_NORTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 1.0 + a_BlockZ); break;
case BLOCK_FACE_SOUTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, a_BlockZ); break;
case BLOCK_FACE_NONE: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
}
SetSpeed(0, 0, 0);
// DEBUG:
LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, hit solid block at face %d",
m_UniqueID,
GetPosX(), GetPosY(), GetPosZ(),
a_BlockFace
);
m_IsInGround = true;
}
AString cProjectileEntity::GetMCAClassName(void) const
{
switch (m_ProjectileKind)
@ -83,6 +165,51 @@ AString cProjectileEntity::GetMCAClassName(void) const
void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
BroadcastMovementUpdate();
}
void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
if (m_IsInGround)
{
// Already-grounded projectiles don't move at all
return;
}
Vector3d PerTickSpeed = GetSpeed() / 20;
Vector3d Pos = GetPosition();
// Trace the tick's worth of movement as a line:
Vector3d NextPos = Pos + PerTickSpeed;
cProjectileTracerCallback TracerCallback(this);
if (cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
{
// Nothing in the way, update the position
SetPosition(NextPos);
}
// Add gravity effect to the vertical speed component:
SetSpeedY(GetSpeedY() + m_Gravity / 20);
// DEBUG:
LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}",
m_UniqueID,
GetPosX(), GetPosY(), GetPosZ(),
GetSpeedX(), GetSpeedY(), GetSpeedZ()
);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cArrowEntity:
@ -118,22 +245,6 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
// DEBUG:
LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}",
m_UniqueID,
GetPosX(), GetPosY(), GetPosZ(),
GetSpeedX(), GetSpeedY(), GetSpeedZ()
);
}
void cArrowEntity::SpawnOn(cClientHandle & a_Client)
{
a_Client.SendSpawnObject(*this, pkArrow, 0, 0, 0);

View File

@ -47,8 +47,8 @@ public:
static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL);
/// Called by the physics blocktracer when the entity hits a solid block, the coords and the face hit is given
virtual void OnHitSolidBlock(double a_BlockX, double a_BlockY, double a_BlockZ, char a_BlockFace) {};
/// Called by the physics blocktracer when the entity hits a solid block, the block's coords and the face hit is given
virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace);
// tolua_begin
@ -72,6 +72,10 @@ protected:
/// True if the projectile has hit the ground and is stuck there
bool m_IsInGround;
// cEntity overrides:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
} ;
@ -127,7 +131,6 @@ protected:
double m_DamageCoeff;
// cEntity overrides:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override;
// tolua_begin

View File

@ -55,6 +55,7 @@ bool cLineBlockTracer::Trace(double a_StartX, double a_StartY, double a_StartZ,
m_DirX = (m_StartX < m_EndX) ? 1 : -1;
m_DirY = (m_StartY < m_EndY) ? 1 : -1;
m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1;
m_CurrentFace = BLOCK_FACE_NONE;
// Check the start coords, adjust into the world:
if (m_StartY < 0)
@ -178,9 +179,9 @@ bool cLineBlockTracer::MoveToNextBlock(void)
// Based on the wall hit, adjust the current coords
switch (Direction)
{
case dirX: m_CurrentX += m_DirX; break;
case dirY: m_CurrentY += m_DirY; break;
case dirZ: m_CurrentZ += m_DirZ; break;
case dirX: m_CurrentX += m_DirX; m_CurrentFace = (m_DirX > 0) ? BLOCK_FACE_EAST : BLOCK_FACE_WEST; break;
case dirY: m_CurrentY += m_DirY; m_CurrentFace = (m_DirY > 0) ? BLOCK_FACE_BOTTOM : BLOCK_FACE_TOP; break;
case dirZ: m_CurrentZ += m_DirZ; m_CurrentFace = (m_DirZ > 0) ? BLOCK_FACE_SOUTH : BLOCK_FACE_NORTH; break;
case dirNONE: return false;
}
return true;
@ -211,7 +212,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk)
int RelX = m_CurrentX - a_Chunk->GetPosX() * cChunkDef::Width;
int RelZ = m_CurrentZ - a_Chunk->GetPosZ() * cChunkDef::Width;
a_Chunk->GetBlockTypeMeta(RelX, m_CurrentY, RelZ, BlockType, BlockMeta);
if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta))
if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta, m_CurrentFace))
{
// The callback terminated the trace
return false;
@ -219,7 +220,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk)
}
else
{
if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ))
if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ, m_CurrentFace))
{
// The callback terminated the trace
return false;

View File

@ -61,6 +61,9 @@ protected:
// The current block
int m_CurrentX, m_CurrentY, m_CurrentZ;
// The face through which the current block has been entered
char m_CurrentFace;
/// Adjusts the start point above the world to just at the world's top
void FixStartAboveWorld(void);

View File

@ -1649,7 +1649,7 @@ public:
{
}
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
{
if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock"))
{
@ -1661,6 +1661,7 @@ public:
m_LuaState.Push(a_BlockZ);
m_LuaState.Push(a_BlockType);
m_LuaState.Push(a_BlockMeta);
m_LuaState.Push(a_EntryFace);
if (!m_LuaState.CallFunction(1))
{
return false;
@ -1674,7 +1675,7 @@ public:
return res;
}
virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) override
virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) override
{
if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData"))
{
@ -1684,6 +1685,7 @@ public:
m_LuaState.Push(a_BlockX);
m_LuaState.Push(a_BlockY);
m_LuaState.Push(a_BlockZ);
m_LuaState.Push(a_EntryFace);
if (!m_LuaState.CallFunction(1))
{
return false;

View File

@ -36,6 +36,7 @@ public: // tolua_export
Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); } // tolua_export
Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); } // tolua_export
Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); } // tolua_export
Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); } // tolua_export
double x, y, z; // tolua_export