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_IsInGround(false) { SetSpeed(a_Speed); SetRotationFromSpeed(); SetPitchFromSpeed(); }
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_CreatorData(a_Creator->GetUniqueID(), a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "", a_Creator->GetEquippedWeapon().m_Enchantments), m_IsInGround(false) { SetSpeed(a_Speed); SetYawFromSpeed(); SetPitchFromSpeed(); }
cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), m_PickupState(psNoPickup), m_DamageCoeff(2), m_IsCritical(false) { SetSpeed(a_Speed); SetMass(0.1); SetRotationFromSpeed(); SetPitchFromSpeed(); LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}", m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), GetRotation(), GetPitch() ); }
cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), m_PickupState(psNoPickup), m_DamageCoeff(2), m_IsCritical(false), m_Timer(0), m_HitGroundTimer(0), m_bIsCollected(false), m_HitBlockPos(Vector3i(0, 0, 0)) { SetSpeed(a_Speed); SetMass(0.1); SetYawFromSpeed(); SetPitchFromSpeed(); LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}", m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), GetYaw(), GetPitch() ); }
void cProjectileEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { if (m_IsInGround) { // Already-grounded projectiles don't move at all return; } auto DtSec = std::chrono::duration_cast<std::chrono::duration<double>>(a_Dt); const Vector3d DeltaSpeed = GetSpeed() * DtSec.count(); const Vector3d Pos = GetPosition(); const Vector3d NextPos = Pos + DeltaSpeed; // Test for entity collisions: cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos); a_Chunk.ForEachEntity(EntityCollisionCallback); if (EntityCollisionCallback.HasHit()) { // An entity was hit: Vector3d HitPos = Pos + (NextPos - Pos) * EntityCollisionCallback.GetMinCoeff(); // DEBUG: LOGD("Projectile %d has hit an entity %d (%s) at {%.02f, %.02f, %.02f} (coeff %.03f)", m_UniqueID, EntityCollisionCallback.GetHitEntity()->GetUniqueID(), EntityCollisionCallback.GetHitEntity()->GetClass(), HitPos.x, HitPos.y, HitPos.z, EntityCollisionCallback.GetMinCoeff() ); OnHitEntity(*(EntityCollisionCallback.GetHitEntity()), HitPos); if (!IsTicking()) { return; // We were destroyed by an override of OnHitEntity } } // TODO: Test the entities in the neighboring chunks, too // Trace the tick's worth of movement as a line: cProjectileTracerCallback TracerCallback(this); if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos)) { // Something has been hit, abort all other processing return; } // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff // Update the position: SetPosition(NextPos); // Add slowdown and gravity effect to the speed: Vector3d NewSpeed(GetSpeed()); NewSpeed.y += m_Gravity * DtSec.count(); NewSpeed -= NewSpeed * (m_AirDrag * 20.0f) * DtSec.count(); SetSpeed(NewSpeed); SetYawFromSpeed(); SetPitchFromSpeed(); /* LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}, rot {%.02f, %.02f}", m_UniqueID, GetPosX(), GetPosY(), GetPosZ(), GetSpeedX(), GetSpeedY(), GetSpeedZ(), GetYaw(), GetPitch() ); */ }
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)) { // Something has been hit, abort all other processing return; } // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff // Test for entity collisions: cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos); a_Chunk.ForEachEntity(EntityCollisionCallback); if (EntityCollisionCallback.HasHit()) { // An entity was hit: Vector3d HitPos = Pos + (NextPos - Pos) * EntityCollisionCallback.GetMinCoeff(); // DEBUG: LOGD("Projectile %d has hit an entity %d (%s) at {%.02f, %.02f, %.02f} (coeff %.03f)", m_UniqueID, EntityCollisionCallback.GetHitEntity()->GetUniqueID(), EntityCollisionCallback.GetHitEntity()->GetClass(), HitPos.x, HitPos.y, HitPos.z, EntityCollisionCallback.GetMinCoeff() ); OnHitEntity(*(EntityCollisionCallback.GetHitEntity()), HitPos); } // TODO: Test the entities in the neighboring chunks, too // Update the position: SetPosition(NextPos); // Add slowdown and gravity effect to the speed: Vector3d NewSpeed(GetSpeed()); NewSpeed.y += m_Gravity / 20; NewSpeed *= TracerCallback.GetSlowdownCoeff(); SetSpeed(NewSpeed); SetRotationFromSpeed(); SetPitchFromSpeed(); // DEBUG: LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}, rot {%.02f, %.02f}", m_UniqueID, GetPosX(), GetPosY(), GetPosZ(), GetSpeedX(), GetSpeedY(), GetSpeedZ(), GetRotation(), GetPitch() ); }