예제 #1
0
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;
	}
}