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)
|
/** 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.
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user