Implemented basic physics for projectiles.
This commit is contained in:
parent
f260e9211f
commit
6677a5e8ca
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user