void CCharacter::FindGroundEntity() { TVector vecVelocity = GetGlobalVelocity(); if (vecVelocity.Dot(GetUpVector()) > JumpStrength()/2.0f) { SetGroundEntity(NULL); SetSimulated(true); return; } TVector vecUp = GetUpVector() * m_flMaxStepSize; size_t iMaxEntities = GameServer()->GetMaxEntities(); for (size_t j = 0; j < iMaxEntities; j++) { CBaseEntity* pEntity = CBaseEntity::GetEntity(j); if (!pEntity) continue; if (pEntity->IsDeleted()) continue; if (!pEntity->ShouldCollide()) continue; if (pEntity == this) continue; TVector vecPoint, vecNormal; if (GetMoveParent() == pEntity) { TMatrix mGlobalToLocal = GetMoveParent()->GetGlobalToLocalTransform(); Vector vecUpLocal = mGlobalToLocal.TransformNoTranslate(GetUpVector()) * m_flMaxStepSize; if (pEntity->CollideLocal(GetLocalOrigin(), GetLocalOrigin() - vecUpLocal, vecPoint, vecNormal)) { SetGroundEntity(pEntity); SetSimulated(false); return; } } else { if (pEntity->Collide(GetGlobalOrigin(), GetGlobalOrigin() - vecUp, vecPoint, vecNormal)) { SetGroundEntity(pEntity); SetSimulated(false); return; } } } SetGroundEntity(NULL); SetSimulated(true); }
void CCharacter::ShowPlayerVectors() const { TMatrix m = GetGlobalTransform(); Vector vecUp = GetUpVector(); Vector vecRight = m.GetForwardVector().Cross(vecUp).Normalized(); Vector vecForward = vecUp.Cross(vecRight).Normalized(); m.SetColumn(0, vecForward); m.SetColumn(1, vecUp); m.SetColumn(2, vecRight); CCharacter* pLocalCharacter = Game()->GetLocalPlayer()->GetCharacter(); TVector vecEyeHeight = GetUpVector() * EyeHeight(); CRenderingContext c(GameServer()->GetRenderer()); c.Translate((GetGlobalOrigin() - pLocalCharacter->GetGlobalOrigin())); c.SetColor(Color(255, 255, 255)); c.BeginRenderDebugLines(); c.Vertex(Vector(0,0,0)); c.Vertex((float)EyeHeight() * vecUp); c.EndRender(); if (!GetGlobalVelocity().IsZero()) { c.BeginRenderDebugLines(); c.Vertex(vecEyeHeight); c.Vertex(vecEyeHeight + GetGlobalVelocity()); c.EndRender(); } c.SetColor(Color(255, 0, 0)); c.BeginRenderDebugLines(); c.Vertex(vecEyeHeight); c.Vertex(vecEyeHeight + vecForward); c.EndRender(); c.SetColor(Color(0, 255, 0)); c.BeginRenderDebugLines(); c.Vertex(vecEyeHeight); c.Vertex(vecEyeHeight + vecRight); c.EndRender(); c.SetColor(Color(0, 0, 255)); c.BeginRenderDebugLines(); c.Vertex(vecEyeHeight); c.Vertex(vecEyeHeight + vecUp); c.EndRender(); TVector vecPoint, vecNormal; if (Game()->TraceLine(GetGlobalOrigin(), GetGlobalOrigin() - GetUpVector()*100, vecPoint, vecNormal, NULL)) { c.Translate(vecPoint - GetGlobalOrigin()); c.Scale(0.1f, 0.1f, 0.1f); c.SetColor(Color(255, 255, 255)); c.RenderSphere(); } }
void CCharacterController::FindGround(btCollisionWorld* pCollisionWorld) { if (m_hEntity->IsFlying()) { m_hEntity->SetGroundEntity(nullptr); return; } if (GetVelocity().dot(GetUpVector()) > m_flJumpSpeed/2.0f) { m_hEntity->SetGroundEntity(nullptr); return; } bool bWalking = !m_hEntity->IsFlying() && m_hEntity->GetGroundEntity(); float flDropHeight = bWalking?m_flStepHeight:m_pConvexShape->getMargin()*2; btVector3 vecStepDrop = GetUpVector() * flDropHeight; btVector3 vecGroundPosition = m_pGhostObject->getWorldTransform().getOrigin() - vecStepDrop; CTraceResult tr; PlayerTrace(pCollisionWorld, m_pGhostObject->getWorldTransform().getOrigin(), vecGroundPosition, tr); if (tr.m_flFraction < 1) { btScalar flDot = GetUpVector().dot(ToBTVector(tr.m_vecNormal)); if (flDot < m_flMaxSlopeCosine) m_hEntity->SetGroundEntity(nullptr); else { CEntityHandle<CBaseEntity> hOther = CEntityHandle<CBaseEntity>(tr.m_iHit); if (hOther) m_hEntity->SetGroundEntity(hOther); else { m_hEntity->SetGroundEntityExtra(tr.m_iHitExtra); } } } else m_hEntity->SetGroundEntity(nullptr); if (bWalking && m_hEntity->GetGroundEntity() && tr.m_flFraction > 0.0f && tr.m_flFraction < 1.0f) { btVector3 vecNewOrigin; vecNewOrigin.setInterpolate3(m_pGhostObject->getWorldTransform().getOrigin(), vecGroundPosition, tr.m_flFraction); float flMargin = m_pConvexShape->getMargin() + 0.001f; if ((vecNewOrigin - m_pGhostObject->getWorldTransform().getOrigin()).length2() > flMargin*flMargin) { m_pGhostObject->getWorldTransform().setOrigin(vecNewOrigin); return; } } return; }
void CCharacterController::PlayerFall(btCollisionWorld* pCollisionWorld, btScalar dt) { Vector vecCurrentVelocity = m_hEntity->GetLocalVelocity(); vecCurrentVelocity += ToTVector(GetGravity()) * dt; m_hEntity->SetLocalVelocity(vecCurrentVelocity); btVector3 vecVelocity = ToBTVector(vecCurrentVelocity); if (m_vecMoveVelocity.length2()) { btVector3 vecAllowedMoveVelocity = PerpendicularComponent(m_vecMoveVelocity, GetUpVector()); if (vecAllowedMoveVelocity.dot(vecVelocity) < 0) vecVelocity = PerpendicularComponent(vecVelocity, vecAllowedMoveVelocity.normalized()); vecVelocity += vecAllowedMoveVelocity * dt; } if (vecVelocity.length2() > m_flMaxSpeed*m_flMaxSpeed) vecVelocity = vecVelocity.normalized() * m_flMaxSpeed; if (vecVelocity.length2() < 0.001f) return; btTransform mWorld; mWorld = m_pGhostObject->getWorldTransform(); btVector3 vecOriginalPosition = mWorld.getOrigin(); StepForwardAndStrafe(pCollisionWorld, vecVelocity * dt); }
EAngle Matrix4x4::GetAngles() const { #ifdef _DEBUG // If any of the below is not true then you have a matrix that has been scaled or reflected or something and it won't work to try to pull its Eulers bool b = fabs(GetForwardVector().LengthSqr() - 1) < 0.001f; if (!b) { TAssertNoMsg(b); return EAngle(0, 0, 0); } b = fabs(GetUpVector().LengthSqr() - 1) < 0.001f; if (!b) { TAssertNoMsg(b); return EAngle(0, 0, 0); } b = fabs(GetLeftVector().LengthSqr() - 1) < 0.001f; if (!b) { TAssertNoMsg(b); return EAngle(0, 0, 0); } b = GetForwardVector().Cross(GetLeftVector()).Equals(GetUpVector(), 0.001f); if (!b) { TAssertNoMsg(b); return EAngle(0, 0, 0); } #endif if (m[0][2] > 0.999999f) return EAngle(asin(Clamp(m[0][2], -1.0f, 1.0f)) * 180/M_PI, -atan2(m[1][0], m[1][1]) * 180/M_PI, 0); else if (m[0][2] < -0.999999f) return EAngle(asin(Clamp(m[0][2], -1.0f, 1.0f)) * 180/M_PI, -atan2(m[1][0], m[1][1]) * 180/M_PI, 0); // Clamp to [-1, 1] looping float flPitch = fmod(m[0][2], 2.0f); if (flPitch > 1) flPitch -= 2; else if (flPitch < -1) flPitch += 2; return EAngle(asin(flPitch) * 180/M_PI, -atan2(-m[0][1], m[0][0]) * 180/M_PI, atan2(-m[1][2], m[2][2]) * 180/M_PI); }
Vector Matrix4x4::GetScale() const { Vector vecReturn; vecReturn.x = GetForwardVector().Length(); vecReturn.y = GetUpVector().Length(); vecReturn.z = GetRightVector().Length(); return vecReturn; }
void CCharacterController::jump() { if (!canJump()) return; SetJumpSpeed((float)m_hEntity->JumpStrength()); m_hEntity->SetGlobalVelocity(ToTVector(GetUpVector()) * m_flJumpSpeed + m_hEntity->GetGlobalVelocity()); m_hEntity->SetGroundEntity(nullptr); }
// Use the information embedded in a matrix to create its inverse. // http://youtu.be/7CxKAtWqHC8 Matrix4x4 Matrix4x4::InvertedTR() const { // This method can only be used if the matrix is a translation/rotation matrix. // The below asserts will trigger if this is not the case. TAssert(fabs(GetForwardVector().LengthSqr() - 1) < 0.00001f); // Each basis vector should be length 1. TAssert(fabs(GetUpVector().LengthSqr() - 1) < 0.00001f); TAssert(fabs(GetRightVector().LengthSqr() - 1) < 0.00001f); TAssert(fabs(GetForwardVector().Dot(GetUpVector())) < 0.0001f); // All vectors should be orthogonal. TAssert(fabs(GetForwardVector().Dot(GetRightVector())) < 0.0001f); TAssert(fabs(GetRightVector().Dot(GetUpVector())) < 0.0001f); Matrix4x4 M; // Create the transposed upper 3x3 matrix for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) M.m[i][j] = m[j][i]; // The new matrix translation = -Rt M.SetTranslation(-(M*GetTranslation())); return M; }
DoubleMatrix4x4 DoubleMatrix4x4::InvertedRT() const { TAssertNoMsg(fabs(GetForwardVector().LengthSqr() - 1) < 0.00001); TAssertNoMsg(fabs(GetLeftVector().LengthSqr() - 1) < 0.00001); TAssertNoMsg(fabs(GetUpVector().LengthSqr() - 1) < 0.00001); DoubleMatrix4x4 r; for (int h = 0; h < 3; h++) for (int v = 0; v < 3; v++) r.m[h][v] = m[v][h]; r.SetTranslation(r*(-GetTranslation())); return r; }
void CCharacter::Jump() { if (!GetGroundEntity()) return; SetGroundEntity(NULL); Vector vecLocalUp = GetUpVector(); if (HasMoveParent()) { TMatrix mGlobalToLocal = GetMoveParent()->GetGlobalToLocalTransform(); vecLocalUp = mGlobalToLocal.TransformNoTranslate(vecLocalUp); } SetLocalVelocity(GetLocalVelocity() + vecLocalUp * JumpStrength()); }
void CSPCharacter::LockViewToPlanet() { // Now lock the roll value to the planet. CPlanet* pNearestPlanet = GetNearestPlanet(); if (!pNearestPlanet) return; Matrix4x4 mGlobalRotation = GetGlobalTransform(); mGlobalRotation.SetTranslation(CScalableVector()); // Construct a "local space" for the planet Vector vecPlanetUp = GetUpVector(); Vector vecPlanetForward = mGlobalRotation.GetForwardVector(); Vector vecPlanetRight = vecPlanetForward.Cross(vecPlanetUp).Normalized(); vecPlanetForward = vecPlanetUp.Cross(vecPlanetRight).Normalized(); Matrix4x4 mPlanet(vecPlanetForward, vecPlanetUp, vecPlanetRight); Matrix4x4 mPlanetInverse = mPlanet; mPlanetInverse.InvertTR(); // Bring our current view angles into that local space Matrix4x4 mLocalRotation = mPlanetInverse * mGlobalRotation; EAngle angLocalRotation = mLocalRotation.GetAngles(); // Lock them so that the roll is 0 // I'm sure there's a way to do this without converting to euler but at this point I don't care. angLocalRotation.r = 0; Matrix4x4 mLockedLocalRotation; mLockedLocalRotation.SetAngles(angLocalRotation); // Bring it back out to global space Matrix4x4 mLockedRotation = mPlanet * mLockedLocalRotation; // Only use the changed r value to avoid floating point crap EAngle angNewLockedRotation = GetGlobalAngles(); EAngle angOverloadRotation = mLockedRotation.GetAngles(); // Lerp our way there float flTimeToLocked = 1; if (GameServer()->GetGameTime() - m_flLastEnteredAtmosphere > flTimeToLocked) angNewLockedRotation.r = angOverloadRotation.r; else angNewLockedRotation.r = RemapValClamped(SLerp(GameServer()->GetGameTime() - m_flLastEnteredAtmosphere, 0.3f), 0, flTimeToLocked, m_flRollFromSpace, angOverloadRotation.r); SetGlobalAngles(angNewLockedRotation); }
// Not a true inversion, only works if the matrix is a translation/rotation matrix. void Matrix4x4::InvertRT() { TAssertNoMsg(fabs(GetForwardVector().LengthSqr() - 1) < 0.00001f); TAssertNoMsg(fabs(GetLeftVector().LengthSqr() - 1) < 0.00001f); TAssertNoMsg(fabs(GetUpVector().LengthSqr() - 1) < 0.00001f); Matrix4x4 t; for (int h = 0; h < 3; h++) for (int v = 0; v < 3; v++) t.m[h][v] = m[v][h]; Vector vecTranslation = GetTranslation(); Init(t); SetTranslation(t*(-vecTranslation)); }
void JXMesaCamera::PrepareTransforms() { // texture transform glMatrixMode(GL_TEXTURE); glLoadIdentity(); // projection transform glMatrixMode(GL_PROJECTION); glLoadIdentity(); const JFloat aspectRatio = itsGLViewport.width / (JFloat) itsGLViewport.height; if (itsPerspectiveFlag) { gluPerspective(itsFOVAngle, aspectRatio, itsNearZ, itsFarZ); } else { glOrtho(-1.0,+1.0, -1.0/aspectRatio,+1.0/aspectRatio, -1.0,+1.0); } // viewing transform -- must be last so objects can change it glMatrixMode(GL_MODELVIEW); glLoadIdentity(); const JVector& p = GetPosition(); const JVector& a = GetAttentionPt(); const JVector& u = GetUpVector(); gluLookAt(p.GetElement(1), p.GetElement(2), p.GetElement(3), a.GetElement(1), a.GetElement(2), a.GetElement(3), u.GetElement(1), u.GetElement(2), u.GetElement(3)); }
void Camera::RotateV(double angle) { Rotate(GetEyePoint(), GetUpVector(), angle); }
void CCharacterController::StepForwardAndStrafe(btCollisionWorld* pCollisionWorld, const btVector3& vecWalkMove) { //printf("m_vecNormalizedDirection=%f,%f,%f\n", m_vecNormalizedDirection[0],m_vecNormalizedDirection[1],m_vecNormalizedDirection[2]); // phase 2: forward and strafe btVector3 vecStartPosition = m_pGhostObject->getWorldTransform().getOrigin(); btVector3 vecTargetPosition = vecStartPosition + vecWalkMove; btScalar flFraction = 1.0; btScalar flDistance2 = (vecStartPosition-vecTargetPosition).length2(); int iMaxIter = 4; while (flFraction > btScalar(0.01) && iMaxIter-- > 0) { CTraceResult tr; PlayerTrace(pCollisionWorld, vecStartPosition, vecTargetPosition, tr); flFraction -= tr.m_flFraction; if (tr.m_flFraction < 1) { Vector vecVelocity = m_hEntity->GetLocalVelocity(); Vector vecNewVelocity = ToTVector(PerpendicularComponent(ToBTVector(vecVelocity), ToBTVector(tr.m_vecNormal))); m_hEntity->SetLocalVelocity(vecNewVelocity); vecStartPosition.setInterpolate3 (vecStartPosition, vecTargetPosition, tr.m_flFraction); btVector3 vecNormal = ToBTVector(tr.m_vecNormal); btVector3 vecMovement = vecTargetPosition-vecStartPosition; // Run along the wall we hit. btVector3 vecParallelDir = ParallelComponent(vecMovement, vecNormal); btVector3 vecPerpendicularDir = vecMovement - vecParallelDir; // If the vector is horizontal then we'll bring it back up to its original scale // so that we're sliding along a wall. If it's vertical though, we'll leave it at // the short scale so that we climb ramps slower. float flRescaleAmount = RemapVal(std::fabs(vecParallelDir.normalized().dot(GetUpVector())), 0, 1, vecMovement.length()/vecPerpendicularDir.length(), 1); vecTargetPosition = vecStartPosition + vecPerpendicularDir * flRescaleAmount; vecStartPosition += vecNormal * m_pConvexShape->getMargin(); vecTargetPosition += vecNormal * m_pConvexShape->getMargin(); btVector3 currentDir = vecTargetPosition - vecStartPosition; flDistance2 = currentDir.length2(); if (flDistance2 > SIMD_EPSILON) { currentDir.normalize(); /* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */ if (currentDir.dot(GetVelocity().normalized()) <= btScalar(0.0)) break; } else { //printf("currentDir: don't normalize a zero vector\n"); break; } } else { // we moved whole way vecStartPosition = vecTargetPosition; } } m_pGhostObject->getWorldTransform().setOrigin(vecStartPosition); }
bool CCharacterController::RecoverFromPenetration(btCollisionWorld* pCollisionWorld) { if (!IsColliding()) return false; bool bPenetration = false; pCollisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_pGhostObject->getOverlappingPairCache(), pCollisionWorld->getDispatchInfo(), pCollisionWorld->getDispatcher()); btVector3 vecCurrentPosition = m_pGhostObject->getWorldTransform().getOrigin(); btVector3 vecOriginalPosition = vecCurrentPosition; btScalar maxPen = btScalar(0.0); for (int i = 0; i < m_pGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) { m_aManifolds.resize(0); btBroadphasePair* pCollisionPair = &m_pGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; btCollisionObject* pObject0 = static_cast<btCollisionObject*>(pCollisionPair->m_pProxy0->m_clientObject); btCollisionObject* pObject1 = static_cast<btCollisionObject*>(pCollisionPair->m_pProxy1->m_clientObject); if (!pObject0->hasContactResponse() || !pObject1->hasContactResponse()) continue; if (pObject0->getBroadphaseHandle()->m_collisionFilterGroup == CG_TRIGGER || pObject1->getBroadphaseHandle()->m_collisionFilterGroup == CG_TRIGGER) continue; if (pCollisionPair->m_algorithm) pCollisionPair->m_algorithm->getAllContactManifolds(m_aManifolds); for (int j = 0; j < m_aManifolds.size(); j++) { btPersistentManifold* pManifold = m_aManifolds[j]; const btCollisionObject* obA = static_cast<const btCollisionObject*>(pManifold->getBody0()); const btCollisionObject* obB = static_cast<const btCollisionObject*>(pManifold->getBody1()); btScalar directionSign; CEntityHandle<CBaseEntity> hOther; size_t iExtra; if (obA == m_pGhostObject) { if (obB->getBroadphaseHandle()->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger) continue; directionSign = btScalar(-1.0); hOther = CEntityHandle<CBaseEntity>((size_t)obB->getUserPointer()); iExtra = (size_t)obB->getUserPointer()-GameServer()->GetMaxEntities(); if (obB->getCollisionFlags()&btCollisionObject::CF_CHARACTER_OBJECT) { // If I'm heavier than he, don't let him push me around if (hOther->GetMass() < m_hEntity->GetMass()) continue; } } else { if (obA->getBroadphaseHandle()->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger) continue; directionSign = btScalar(1.0); hOther = CEntityHandle<CBaseEntity>((size_t)obA->getUserPointer()); iExtra = (size_t)obB->getUserPointer()-GameServer()->GetMaxEntities(); if (obA->getCollisionFlags()&btCollisionObject::CF_CHARACTER_OBJECT) { // If I'm heavier than he, don't let him push me around if (hOther->GetMass() < m_hEntity->GetMass()) continue; } } for (int p = 0; p < pManifold->getNumContacts(); p++) { const btManifoldPoint& pt = pManifold->getContactPoint(p); if (obA == m_pGhostObject) { if (hOther) { if (!m_hEntity->ShouldCollideWith(hOther, Vector(pt.getPositionWorldOnB()))) continue; } else { if (!m_hEntity->ShouldCollideWithExtra(iExtra, Vector(pt.getPositionWorldOnB()))) continue; } } else { if (hOther) { if (!m_hEntity->ShouldCollideWith(hOther, Vector(pt.getPositionWorldOnA()))) continue; } else { if (!m_hEntity->ShouldCollideWithExtra(iExtra, Vector(pt.getPositionWorldOnA()))) continue; } } btScalar flDistance = pt.getDistance(); btScalar flMargin = std::max(obA->getCollisionShape()->getMargin(), obB->getCollisionShape()->getMargin()); if (flDistance < -flMargin) { flDistance += flMargin; if (flDistance < maxPen) maxPen = flDistance; btScalar flDot = pt.m_normalWorldOnB.dot(GetUpVector()); btVector3 vecAdjustment; if (flDot > 0.707f) vecAdjustment = GetUpVector() * (directionSign * flDistance * 1.001f); else vecAdjustment = pt.m_normalWorldOnB * (directionSign * flDistance * 1.001f); if (vecAdjustment.length2() < 0.001*0.001) continue; vecCurrentPosition += vecAdjustment; bPenetration = true; } else { //printf("touching %f\n", dist); } } //pManifold->clearManifold(); } } btTransform mNew = m_pGhostObject->getWorldTransform(); mNew.setOrigin(mNew.getOrigin() + (vecCurrentPosition - vecOriginalPosition) * m_vecLinearFactor); m_pGhostObject->setWorldTransform(mNew); return bPenetration; }
bool CCharacterController::onGround() const { return GetVelocity().dot(GetUpVector()) > 0; }
void CCharacterController::PlayerWalk(btCollisionWorld* pCollisionWorld, btScalar dt) { Vector vecCurrentVelocity = m_hEntity->GetLocalVelocity(); vecCurrentVelocity.z = 0; // Calculate friction first, so that the player's movement commands can overwhelm it. if (vecCurrentVelocity.Length2DSqr() > 0.00001f) { if (m_hEntity->GetGroundEntity()) { float flSpeed2D = vecCurrentVelocity.Length2D(); float flFriction = sv_friction.GetFloat() * flSpeed2D * dt; float flNewSpeed = flSpeed2D - flFriction; if (flNewSpeed < 0) flNewSpeed = 0; float flScale = flNewSpeed / flSpeed2D; vecCurrentVelocity *= flScale; m_hEntity->SetLocalVelocity(vecCurrentVelocity); } } // Calculate a new velocity using the player's desired direction of travel. btVector3 vecWishDirection = m_vecMoveVelocity; vecWishDirection.setZ(0); float flWishVelocity = m_vecMoveVelocity.length(); if (flWishVelocity) vecWishDirection = vecWishDirection / flWishVelocity; else vecWishDirection = btVector3(0, 0, 0); if (flWishVelocity > m_hEntity->CharacterSpeed()) flWishVelocity = m_hEntity->CharacterSpeed(); float flVelocityInWishDirection = GetVelocity().dot(vecWishDirection); float flDirectionChange = flWishVelocity - flVelocityInWishDirection; if (flDirectionChange > 0) { float flAccelerationAmount = flWishVelocity * m_hEntity->CharacterAcceleration() * dt; if (flAccelerationAmount > flDirectionChange) flAccelerationAmount = flDirectionChange; vecCurrentVelocity = vecCurrentVelocity + ToTVector(vecWishDirection) * flAccelerationAmount; TAssert(vecCurrentVelocity.z == 0); } float flCurrentVelocity = vecCurrentVelocity.Length(); if (flCurrentVelocity > m_hEntity->CharacterSpeed()) vecCurrentVelocity *= m_hEntity->CharacterSpeed()/flCurrentVelocity; if (vecCurrentVelocity.LengthSqr() < 0.001f) { m_hEntity->SetLocalVelocity(Vector()); return; } btTransform mWorld = m_pGhostObject->getWorldTransform(); // Try moving the player directly, if it's possible. { btVector3 vecTargetPosition = mWorld.getOrigin() + ToBTVector(vecCurrentVelocity) * dt; CTraceResult tr; PlayerTrace(pCollisionWorld, mWorld.getOrigin(), vecTargetPosition, tr); if (tr.m_flFraction == 1) { mWorld.setOrigin(vecTargetPosition); m_pGhostObject->setWorldTransform(mWorld); m_hEntity->SetLocalVelocity(vecCurrentVelocity); return; } } // There was something blocking the way. Try walking up a step or along walls. btVector3 vecSavedStepUp(0, 0, 0); { // Move up a bit to try to clear a step. btVector3 vecStartPosition = m_pGhostObject->getWorldTransform().getOrigin(); btVector3 vecTargetPosition = m_pGhostObject->getWorldTransform().getOrigin() + GetUpVector() * m_flStepHeight; CTraceResult tr; PlayerTrace(pCollisionWorld, vecStartPosition, vecTargetPosition, tr); if (tr.m_flFraction < 1) { // we moved up only a fraction of the step height btVector3 vecInterpolated; vecInterpolated.setInterpolate3(m_pGhostObject->getWorldTransform().getOrigin(), vecTargetPosition, tr.m_flFraction); m_pGhostObject->getWorldTransform().setOrigin(vecInterpolated); vecSavedStepUp = vecInterpolated - vecStartPosition; } else { vecSavedStepUp = vecTargetPosition - vecStartPosition; m_pGhostObject->getWorldTransform().setOrigin(vecTargetPosition); } } StepForwardAndStrafe(pCollisionWorld, ToBTVector(vecCurrentVelocity) * dt); if (vecSavedStepUp.length2() > 0) { // Move back down as much as we moved up. btVector3 vecStartPosition = m_pGhostObject->getWorldTransform().getOrigin(); btVector3 vecTargetPosition = m_pGhostObject->getWorldTransform().getOrigin() - vecSavedStepUp; CTraceResult tr; PlayerTrace(pCollisionWorld, vecStartPosition, vecTargetPosition, tr); if (tr.m_flFraction < 1) { btVector3 vecInterpolated; vecInterpolated.setInterpolate3(m_pGhostObject->getWorldTransform().getOrigin(), vecTargetPosition, tr.m_flFraction); m_pGhostObject->getWorldTransform().setOrigin(vecInterpolated); } else m_pGhostObject->getWorldTransform().setOrigin(vecTargetPosition); } }
void Player::AttackAnimationTimerFinished() { if (IsBow()) { } else if (IsBoomerang()) { vec3 boomerangSpawnPosition = GetCenter() + (m_forward*0.75f) + (GetRightVector()*-0.4f) + (GetUpVector()*0.5f); float cameraModification = (m_cameraForward.y*17.5f); if (m_cameraForward.y < 0.0f) { cameraModification = (m_cameraForward.y*5.0f); } vec3 boomerangTarget = boomerangSpawnPosition + m_forward*15.0f + (vec3(0.0f, 1.0f, 0.0f) * cameraModification); if (m_pTargetEnemy != NULL) { boomerangTarget = m_pTargetEnemy->GetProjectileHitboxCenter(); if (m_pTargetEnemy->IsMoving()) { boomerangTarget += m_pTargetEnemy->GetForwardVector() * (m_pTargetEnemy->GetMovementSpeed() / 3.0f); } } float curveTime = length(boomerangTarget - boomerangSpawnPosition) / 15.0f; if (curveTime <= 0.4f) curveTime = 0.4f; Projectile* pProjectile = m_pProjectileManager->CreateProjectile(boomerangSpawnPosition, vec3(0.0f, 0.0f, 0.0f), 0.0f, "media/gamedata/weapons/Boomerang/BoomerangThrown.weapon", 0.05f); pProjectile->SetProjectileType(true, false, false); pProjectile->SetOwner(this, NULL, NULL); pProjectile->SetGravityMultiplier(0.0f); pProjectile->SetReturnToPlayer(true); pProjectile->SetProjectileCurveParams(m_forward, boomerangTarget, curveTime); pProjectile->SetWorldCollisionEnabled(true); m_pVoxelCharacter->SetRenderRightWeapon(false); } else if (IsStaff()) { float powerAmount = 25.0f; float cameraMultiplier = 25.0f; vec3 spellSpawnPosition = GetCenter() + (m_forward*1.25f) + (GetUpVector()*0.25f); if (VoxGame::GetInstance()->GetCameraMode() == CameraMode_FirstPerson) { cameraMultiplier = 30.0f; spellSpawnPosition.y += 0.75f; } vec3 spellSpawnVelocity = m_forward * powerAmount + vec3(0.0f, 1.0f, 0.0f) * (m_cameraForward.y*cameraMultiplier); if (m_pTargetEnemy != NULL) { vec3 toTarget = m_pTargetEnemy->GetProjectileHitboxCenter() - GetCenter(); spellSpawnVelocity = (normalize(toTarget) * powerAmount); } Projectile* pProjectile = m_pProjectileManager->CreateProjectile(spellSpawnPosition, spellSpawnVelocity, 0.0f, "media/gamedata/items/Fireball/Fireball.item", 0.05f); pProjectile->SetProjectileType(true, false, false); pProjectile->SetOwner(this, NULL, NULL); pProjectile->SetGravityMultiplier(0.0f); } else if (IsWand()) { } else if (IsBomb()) { vec3 bombSpawnPosition = GetCenter() + (m_forward*0.75f) + (GetUpVector()*0.5f); float liftAmount = 8.0f; float powerAmount = 30.0f; float cameraMultiplier = 25.0f; if (VoxGame::GetInstance()->GetCameraMode() == CameraMode_FirstPerson) { cameraMultiplier = 30.0f; } vec3 bombSpawnVelocity; if (m_pTargetEnemy) { // Enemy target vec3 toTarget = m_pTargetEnemy->GetCenter() - GetCenter(); float toTargetDistance = length(toTarget); liftAmount += toTargetDistance * 0.04f; bombSpawnVelocity = (normalize(toTarget) * powerAmount) + vec3(0.0f, liftAmount, 0.0f); } else { bombSpawnVelocity = (m_forward * powerAmount) + (GetUpVector() * liftAmount) + vec3(0.0f, 1.0f, 0.0f) * (m_cameraForward.y*cameraMultiplier); } Projectile* pProjectile = m_pProjectileManager->CreateProjectile(bombSpawnPosition, bombSpawnVelocity, 0.0f, "media/gamedata/items/Bomb/BombThrown.item", 0.05f); pProjectile->SetProjectileType(true, false, false); pProjectile->SetOwner(this, NULL, NULL); pProjectile->SetGravityMultiplier(3.5f); float explodeRadius = 3.5f - (GetRandomNumber(-150, 0, 2) * 0.01f); pProjectile->SetExplodingProjectile(true, explodeRadius); //m_pVoxelCharacter->SetRenderRightWeapon(false); InventoryItem* pItem = m_pInventoryManager->GetInventoryItemForEquipSlot(EquipSlot_RightHand); if (pItem != NULL) { if (pItem->m_quantity != -1) { pItem->m_quantity -= 1; } if (pItem->m_quantity == 0) { // Remove this item from the manager, and remove it from the inventory and GUI UnequipItem(EquipSlot_RightHand, false, false); m_pInventoryManager->RemoveInventoryItem(EquipSlot_RightHand); m_pActionBar->RemoveInventoryItemFromActionBar(pItem->m_title); } } } else if (IsConsumable()) { } else if (IsDagger()) { } else if (IsHammer()) { } else if (IsMace()) { } else if (IsSickle()) { } else if (IsPickaxe()) { Item* pInteractItem = VoxGame::GetInstance()->GetInteractItem(); if (pInteractItem != NULL) { pInteractItem->Interact(); } else { DestroyBlock(); } } else if (IsAxe()) { } else if (Is2HandedSword()) { } else if (IsSword()) { } else if (IsBlockPlacing()) { } else if (IsItemPlacing()) { } else if (IsSceneryPlacing()) { } else if (IsSpellHands()) { float powerAmount = 25.0f; float cameraMultiplier = 25.0f; vec3 spellSpawnPosition = GetCenter() + (m_forward*0.5f) + (GetUpVector()*0.0f); // For right hand spellSpawnPosition += -(GetRightVector()*0.4f); if (VoxGame::GetInstance()->GetCameraMode() == CameraMode_FirstPerson) { cameraMultiplier = 30.0f; spellSpawnPosition.y += 0.75f; } vec3 spellSpawnVelocity = m_forward * powerAmount + vec3(0.0f, 1.0f, 0.0f) * (m_cameraForward.y*cameraMultiplier); if (m_pTargetEnemy != NULL) { vec3 toTarget = m_pTargetEnemy->GetProjectileHitboxCenter() - GetCenter(); spellSpawnVelocity = (normalize(toTarget) * powerAmount); } Projectile* pProjectile = m_pProjectileManager->CreateProjectile(spellSpawnPosition, spellSpawnVelocity, 0.0f, "media/gamedata/items/Fireball/FireballBlue.item", 0.05f); pProjectile->SetProjectileType(true, false, false); pProjectile->SetOwner(this, NULL, NULL); pProjectile->SetGravityMultiplier(0.0f); } else if (IsShield()) { } else if (IsTorch()) { } }
void Player::AttackAnimationTimerFinished_Alternative() { if (IsBow()) { } else if (IsBoomerang()) { } else if (IsStaff()) { } else if (IsWand()) { } else if (IsBomb()) { } else if (IsConsumable()) { } else if (IsDagger()) { } else if (IsHammer()) { } else if (IsMace()) { } else if (IsSickle()) { } else if (IsPickaxe()) { } else if (IsAxe()) { } else if (Is2HandedSword()) { } else if (IsSword()) { } else if (IsBlockPlacing()) { } else if (IsItemPlacing()) { } else if (IsSceneryPlacing()) { } else if (IsSpellHands()) { float powerAmount = 25.0f; float cameraMultiplier = 25.0f; vec3 spellSpawnPosition = GetCenter() + (m_forward*0.5f) + (GetUpVector()*0.0f); // For left hand spellSpawnPosition += (GetRightVector()*0.4f); if (VoxGame::GetInstance()->GetCameraMode() == CameraMode_FirstPerson) { cameraMultiplier = 30.0f; spellSpawnPosition.y += 0.75f; } vec3 spellSpawnVelocity = m_forward * powerAmount + vec3(0.0f, 1.0f, 0.0f) * (m_cameraForward.y*cameraMultiplier); if (m_pTargetEnemy != NULL) { vec3 toTarget = m_pTargetEnemy->GetProjectileHitboxCenter() - GetCenter(); spellSpawnVelocity = (normalize(toTarget) * powerAmount); } Projectile* pProjectile = m_pProjectileManager->CreateProjectile(spellSpawnPosition, spellSpawnVelocity, 0.0f, "media/gamedata/items/Fireball/FireballBlue.item", 0.05f); pProjectile->SetProjectileType(true, false, false); pProjectile->SetOwner(this, NULL, NULL); pProjectile->SetGravityMultiplier(0.0f); } else if (IsShield()) { } else if (IsTorch()) { } }
void Camera::RotateU(double angle) { Rotate(GetEyePoint(), cross(GetLookVector(), GetUpVector()), angle); }
void CCharacter::MoveThink() { if (!GetGroundEntity()) return; if (m_vecGoalVelocity.LengthSqr()) m_vecGoalVelocity.Normalize(); m_vecMoveVelocity.x = Approach(m_vecGoalVelocity.x, m_vecMoveVelocity.x, GameServer()->GetFrameTime()*4); m_vecMoveVelocity.y = 0; m_vecMoveVelocity.z = Approach(m_vecGoalVelocity.z, m_vecMoveVelocity.z, GameServer()->GetFrameTime()*4); if (m_vecMoveVelocity.LengthSqr() > 0) { TMatrix m = GetLocalTransform(); Vector vecUp = GetUpVector(); if (HasMoveParent()) { TMatrix mGlobalToLocal = GetMoveParent()->GetGlobalToLocalTransform(); vecUp = mGlobalToLocal.TransformNoTranslate(vecUp); } Vector vecRight = m.GetForwardVector().Cross(vecUp).Normalized(); Vector vecForward = vecUp.Cross(vecRight).Normalized(); m.SetColumn(0, vecForward); m.SetColumn(1, vecUp); m.SetColumn(2, vecRight); TVector vecMove = m_vecMoveVelocity * CharacterSpeed(); TVector vecLocalVelocity = m.TransformNoTranslate(vecMove); SetLocalVelocity(vecLocalVelocity); } else SetLocalVelocity(TVector()); eastl::vector<CEntityHandle<CBaseEntity> > apCollisionList; size_t iMaxEntities = GameServer()->GetMaxEntities(); for (size_t j = 0; j < iMaxEntities; j++) { CBaseEntity* pEntity2 = CBaseEntity::GetEntity(j); if (!pEntity2) continue; if (pEntity2->IsDeleted()) continue; if (pEntity2 == this) continue; if (!pEntity2->ShouldCollide()) continue; apCollisionList.push_back(pEntity2); } TMatrix mGlobalToLocalRotation; if (HasMoveParent()) { mGlobalToLocalRotation = GetMoveParent()->GetGlobalToLocalTransform(); mGlobalToLocalRotation.SetTranslation(TVector()); } float flSimulationFrameTime = 0.01f; // Break simulations up into consistent small steps to preserve accuracy. for (; m_flMoveSimulationTime < GameServer()->GetGameTime(); m_flMoveSimulationTime += flSimulationFrameTime) { TVector vecVelocity = GetLocalVelocity(); TVector vecLocalOrigin = GetLocalOrigin(); TVector vecGlobalOrigin = GetGlobalOrigin(); vecVelocity = vecVelocity * flSimulationFrameTime; TVector vecLocalDestination = vecLocalOrigin + vecVelocity; TVector vecGlobalDestination = vecLocalDestination; if (GetMoveParent()) vecGlobalDestination = GetMoveParent()->GetGlobalTransform() * vecLocalDestination; TVector vecNewLocalOrigin = vecLocalDestination; size_t iTries = 0; while (true) { iTries++; TVector vecPoint, vecNormal; TVector vecLocalCollisionPoint, vecGlobalCollisionPoint; bool bContact = false; for (size_t i = 0; i < apCollisionList.size(); i++) { CBaseEntity* pEntity2 = apCollisionList[i]; if (GetMoveParent() == pEntity2) { if (pEntity2->CollideLocal(vecLocalOrigin, vecLocalDestination, vecPoint, vecNormal)) { bContact = true; Touching(pEntity2); vecLocalCollisionPoint = vecPoint; vecGlobalCollisionPoint = GetMoveParent()->GetGlobalTransform() * vecPoint; } } else { if (pEntity2->Collide(vecGlobalOrigin, vecGlobalDestination, vecPoint, vecNormal)) { bContact = true; Touching(pEntity2); vecGlobalCollisionPoint = vecPoint; if (GetMoveParent()) { vecLocalCollisionPoint = GetMoveParent()->GetGlobalToLocalTransform() * vecPoint; vecNormal = GetMoveParent()->GetGlobalToLocalTransform().TransformNoTranslate(vecNormal); } else vecLocalCollisionPoint = vecGlobalCollisionPoint; } } } if (bContact) { vecNewLocalOrigin = vecLocalCollisionPoint; vecVelocity -= vecLocalCollisionPoint - vecLocalOrigin; } if (!bContact) break; if (iTries > 4) break; vecLocalOrigin = vecLocalCollisionPoint; vecGlobalOrigin = vecGlobalCollisionPoint; // Clip the velocity to the surface normal of whatever we hit. TFloat flDistance = vecVelocity.Dot(vecNormal); vecVelocity = vecVelocity - vecNormal * flDistance; // Do it one more time just to make sure we're not headed towards the plane. TFloat flAdjust = vecVelocity.Dot(vecNormal); if (flAdjust < 0.0f) vecVelocity -= (vecNormal * flAdjust); vecLocalDestination = vecLocalOrigin + vecVelocity; if (GetMoveParent()) vecGlobalDestination = GetMoveParent()->GetGlobalTransform() * vecLocalDestination; else vecGlobalDestination = vecLocalDestination; SetLocalVelocity(vecVelocity.Normalized() * GetLocalVelocity().Length()); } SetLocalOrigin(vecNewLocalOrigin); // Try to keep the player on the ground. // Untested. /*TVector vecStart = GetGlobalOrigin() + GetGlobalTransform().GetUpVector()*m_flMaxStepSize; TVector vecEnd = GetGlobalOrigin() - GetGlobalTransform().GetUpVector()*m_flMaxStepSize; // First go up a bit TVector vecHit, vecNormal; Game()->TraceLine(GetGlobalOrigin(), vecStart, vecHit, vecNormal, NULL); vecStart = vecHit; // Now see if there's ground underneath us. bool bHit = Game()->TraceLine(vecStart, vecEnd, vecHit, vecNormal, NULL); if (bHit && vecNormal.y >= TFloat(0.7f)) SetGlobalOrigin(vecHit);*/ m_flMoveSimulationTime += flSimulationFrameTime; } }