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) /** Called on each block encountered along the path, including the first block (path start)
When this callback returns true, the tracing is aborted. 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 /** 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. 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) /** 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. The coords specify the exact point at which the path exited the world.

View File

@ -7,6 +7,57 @@
#include "ProjectileEntity.h" #include "ProjectileEntity.h"
#include "../ClientHandle.h" #include "../ClientHandle.h"
#include "Player.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) : 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), super(etProjectile, a_X, a_Y, a_Z, a_Width, a_Height),
m_ProjectileKind(a_Kind), 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) : 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), super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height),
m_ProjectileKind(a_Kind), m_ProjectileKind(a_Kind),
m_Creator(a_Creator) m_Creator(a_Creator),
m_IsInGround(false)
{ {
SetSpeed(a_Speed); 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 AString cProjectileEntity::GetMCAClassName(void) const
{ {
switch (m_ProjectileKind) 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: // 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) void cArrowEntity::SpawnOn(cClientHandle & a_Client)
{ {
a_Client.SendSpawnObject(*this, pkArrow, 0, 0, 0); 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); 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 /// 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(double a_BlockX, double a_BlockY, double a_BlockZ, char a_BlockFace) {}; virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace);
// tolua_begin // tolua_begin
@ -72,6 +72,10 @@ protected:
/// True if the projectile has hit the ground and is stuck there /// True if the projectile has hit the ground and is stuck there
bool m_IsInGround; 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; double m_DamageCoeff;
// cEntity overrides: // cEntity overrides:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override; virtual void SpawnOn(cClientHandle & a_Client) override;
// tolua_begin // 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_DirX = (m_StartX < m_EndX) ? 1 : -1;
m_DirY = (m_StartY < m_EndY) ? 1 : -1; m_DirY = (m_StartY < m_EndY) ? 1 : -1;
m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1; m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1;
m_CurrentFace = BLOCK_FACE_NONE;
// Check the start coords, adjust into the world: // Check the start coords, adjust into the world:
if (m_StartY < 0) if (m_StartY < 0)
@ -178,9 +179,9 @@ bool cLineBlockTracer::MoveToNextBlock(void)
// Based on the wall hit, adjust the current coords // Based on the wall hit, adjust the current coords
switch (Direction) switch (Direction)
{ {
case dirX: m_CurrentX += m_DirX; 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; 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; break; case dirZ: m_CurrentZ += m_DirZ; m_CurrentFace = (m_DirZ > 0) ? BLOCK_FACE_SOUTH : BLOCK_FACE_NORTH; break;
case dirNONE: return false; case dirNONE: return false;
} }
return true; return true;
@ -211,7 +212,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk)
int RelX = m_CurrentX - a_Chunk->GetPosX() * cChunkDef::Width; int RelX = m_CurrentX - a_Chunk->GetPosX() * cChunkDef::Width;
int RelZ = m_CurrentZ - a_Chunk->GetPosZ() * cChunkDef::Width; int RelZ = m_CurrentZ - a_Chunk->GetPosZ() * cChunkDef::Width;
a_Chunk->GetBlockTypeMeta(RelX, m_CurrentY, RelZ, BlockType, BlockMeta); 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 // The callback terminated the trace
return false; return false;
@ -219,7 +220,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk)
} }
else 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 // The callback terminated the trace
return false; return false;

View File

@ -61,6 +61,9 @@ protected:
// The current block // The current block
int m_CurrentX, m_CurrentY, m_CurrentZ; 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 /// Adjusts the start point above the world to just at the world's top
void FixStartAboveWorld(void); 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")) if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock"))
{ {
@ -1661,6 +1661,7 @@ public:
m_LuaState.Push(a_BlockZ); m_LuaState.Push(a_BlockZ);
m_LuaState.Push(a_BlockType); m_LuaState.Push(a_BlockType);
m_LuaState.Push(a_BlockMeta); m_LuaState.Push(a_BlockMeta);
m_LuaState.Push(a_EntryFace);
if (!m_LuaState.CallFunction(1)) if (!m_LuaState.CallFunction(1))
{ {
return false; return false;
@ -1674,7 +1675,7 @@ public:
return res; 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")) if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData"))
{ {
@ -1684,6 +1685,7 @@ public:
m_LuaState.Push(a_BlockX); m_LuaState.Push(a_BlockX);
m_LuaState.Push(a_BlockY); m_LuaState.Push(a_BlockY);
m_LuaState.Push(a_BlockZ); m_LuaState.Push(a_BlockZ);
m_LuaState.Push(a_EntryFace);
if (!m_LuaState.CallFunction(1)) if (!m_LuaState.CallFunction(1))
{ {
return false; return false;

View File

@ -30,12 +30,13 @@ public: // tolua_export
void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; } void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; } void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; }
Vector3d operator + ( const Vector3d& v2 ) const { return Vector3d( x + v2.x, y + v2.y, z + v2.z ); } // tolua_export Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); } // tolua_export
Vector3d operator + ( const Vector3d* v2 ) const { return Vector3d( x + v2->x, y + v2->y, z + v2->z ); } // tolua_export Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); } // tolua_export
Vector3d operator - ( const Vector3d& v2 ) const { return Vector3d( x - v2.x, y - v2.y, z - v2.z ); } // tolua_export Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); } // tolua_export
Vector3d operator - ( const Vector3d* v2 ) const { return Vector3d( x - v2->x, y - v2->y, z - v2->z ); } // 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 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 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 double x, y, z; // tolua_export