bool Item::CheckCollisions(vec3 positionCheck, vec3 previousPosition, vec3 *pNormal, vec3 *pMovement) { float radius = GetRadius(); vec3 movementCache = *pMovement; // World collisions bool worldCollision = false; vec3 floorPosition; if (m_pChunkManager->FindClosestFloor(positionCheck, &floorPosition) == false) { *pMovement = vec3(0.0f, 0.0f, 0.0f); return true; } else { int blockX, blockY, blockZ; vec3 blockPos; int numChecks = 1 + (int)(radius / (Chunk::BLOCK_RENDER_SIZE* 2.0f)); for (int x = -numChecks; x <= numChecks; x++) { for (int y = -numChecks; y <= numChecks; y++) { for (int z = -numChecks; z <= numChecks; z++) { *pNormal = vec3(0.0f, 0.0f, 0.0f); Chunk* pChunk = GetCachedGridChunkOrFromPosition(positionCheck + vec3((Chunk::BLOCK_RENDER_SIZE*2.0f)*x, (Chunk::BLOCK_RENDER_SIZE*2.0f)*y, (Chunk::BLOCK_RENDER_SIZE*2.0f)*z)); bool active = m_pChunkManager->GetBlockActiveFrom3DPosition(positionCheck.x + ((Chunk::BLOCK_RENDER_SIZE*2.0f)*x), positionCheck.y + ((Chunk::BLOCK_RENDER_SIZE*2.0f)*y), positionCheck.z + ((Chunk::BLOCK_RENDER_SIZE*2.0f)*z), &blockPos, &blockX, &blockY, &blockZ, &pChunk); if (active == false) { if (pChunk == NULL || pChunk->IsSetup() == false) { *pMovement = vec3(0.0f, 0.0f, 0.0f); worldCollision = false; } } else if (active == true) { Plane3D planes[6]; planes[0] = Plane3D(vec3(-1.0f, 0.0f, 0.0f), vec3(Chunk::BLOCK_RENDER_SIZE, 0.0f, 0.0f)); planes[1] = Plane3D(vec3(1.0f, 0.0f, 0.0f), vec3(-Chunk::BLOCK_RENDER_SIZE, 0.0f, 0.0f)); planes[2] = Plane3D(vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, Chunk::BLOCK_RENDER_SIZE, 0.0f)); planes[3] = Plane3D(vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, -Chunk::BLOCK_RENDER_SIZE, 0.0f)); planes[4] = Plane3D(vec3(0.0f, 0.0f, -1.0f), vec3(0.0f, 0.0f, Chunk::BLOCK_RENDER_SIZE)); planes[5] = Plane3D(vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -Chunk::BLOCK_RENDER_SIZE)); float distance; int inside = 0; bool insideCache[6]; for (int i = 0; i < 6; i++) { vec3 pointToCheck = blockPos - previousPosition; distance = planes[i].GetPointDistance(pointToCheck); if (distance < -radius) { // Outside... insideCache[i] = false; } else if (distance < radius) { // Intersecting.. insideCache[i] = true; } else { // Inside... insideCache[i] = true; } } for (int i = 0; i < 6; i++) { vec3 pointToCheck = blockPos - positionCheck; distance = planes[i].GetPointDistance(pointToCheck); if (distance < -radius) { // Outside... } else if (distance < radius) { // Intersecting.. inside++; if (insideCache[i] == false) { *pNormal += planes[i].mNormal; } } else { // Inside... inside++; if (insideCache[i] == false) { *pNormal += planes[i].mNormal; } } } if (inside == 6) { if (length(*pNormal) <= 1.0f) { if (length(*pNormal) > 0.0f) { *pNormal = normalize(*pNormal); } float dotResult = dot(*pNormal, *pMovement); *pNormal *= dotResult; *pMovement -= *pNormal; worldCollision = true; } } } } } } } if (worldCollision) return true; *pMovement = movementCache; return false; }
// Collision bool Player::CheckCollisions(vec3 positionCheck, vec3 previousPosition, vec3 *pNormal, vec3 *pMovement, bool *pStepUpBlock) { vec3 movementCache = *pMovement; // World collision bool worldCollision = false; float radius = GetRadius(); int blockX, blockY, blockZ; vec3 blockPos; int blockXAbove, blockYAbove, blockZAbove; vec3 blockPosAbove; int numChecks = 1 + (int)(radius / (Chunk::BLOCK_RENDER_SIZE* 2.0f)); bool canAllStepUp = false; bool firstStepUp = true; for (int x = -numChecks; x <= numChecks; x++) { for (int y = -numChecks; y <= numChecks; y++) { for (int z = -numChecks; z <= numChecks; z++) { bool isStepUp = false; *pNormal = vec3(0.0f, 0.0f, 0.0f); Chunk* pChunk = GetCachedGridChunkOrFromPosition(positionCheck + vec3((Chunk::BLOCK_RENDER_SIZE*2.0f)*x, (Chunk::BLOCK_RENDER_SIZE*2.0f)*y, (Chunk::BLOCK_RENDER_SIZE*2.0f)*z)); bool active = m_pChunkManager->GetBlockActiveFrom3DPosition(positionCheck.x + ((Chunk::BLOCK_RENDER_SIZE*2.0f)*x), positionCheck.y + ((Chunk::BLOCK_RENDER_SIZE*2.0f)*y), positionCheck.z + ((Chunk::BLOCK_RENDER_SIZE*2.0f)*z), &blockPos, &blockX, &blockY, &blockZ, &pChunk); bool activeAbove = false; bool activeAbove2 = false; if (active == false) { if (pChunk == NULL || pChunk->IsSetup() == false) { *pMovement = vec3(0.0f, 0.0f, 0.0f); worldCollision = true; } } else if (active == true) { Plane3D planes[6]; planes[0] = Plane3D(vec3(-1.0f, 0.0f, 0.0f), vec3(Chunk::BLOCK_RENDER_SIZE, 0.0f, 0.0f)); planes[1] = Plane3D(vec3(1.0f, 0.0f, 0.0f), vec3(-Chunk::BLOCK_RENDER_SIZE, 0.0f, 0.0f)); planes[2] = Plane3D(vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, Chunk::BLOCK_RENDER_SIZE, 0.0f)); planes[3] = Plane3D(vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, -Chunk::BLOCK_RENDER_SIZE, 0.0f)); planes[4] = Plane3D(vec3(0.0f, 0.0f, -1.0f), vec3(0.0f, 0.0f, Chunk::BLOCK_RENDER_SIZE)); planes[5] = Plane3D(vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -Chunk::BLOCK_RENDER_SIZE)); float distance; int inside = 0; bool insideCache[6]; for (int i = 0; i < 6; i++) { vec3 pointToCheck = blockPos - previousPosition; distance = planes[i].GetPointDistance(pointToCheck); if (distance < -radius) { // Outside... insideCache[i] = false; } else if (distance < radius) { // Intersecting.. insideCache[i] = true; } else { // Inside... insideCache[i] = true; } } for (int i = 0; i < 6; i++) { vec3 pointToCheck = blockPos - positionCheck; distance = planes[i].GetPointDistance(pointToCheck); if (distance < -radius) { // Outside... } else if (distance < radius) { // Intersecting.. inside++; if (insideCache[i] == false) { *pNormal += planes[i].mNormal; } } else { // Inside... inside++; if (insideCache[i] == false) { *pNormal += planes[i].mNormal; } } } if (inside == 6) { if (y == 0) // We only want to check on the same y-level as the players position. { vec3 posCheck1 = vec3(positionCheck.x + ((Chunk::BLOCK_RENDER_SIZE*2.0f)*x), positionCheck.y + (Chunk::BLOCK_RENDER_SIZE*2.0f), positionCheck.z + ((Chunk::BLOCK_RENDER_SIZE*2.0f)*z)); vec3 posCheck2 = vec3(positionCheck.x + ((Chunk::BLOCK_RENDER_SIZE*2.0f)*x), positionCheck.y + (Chunk::BLOCK_RENDER_SIZE*4.0f), positionCheck.z + ((Chunk::BLOCK_RENDER_SIZE*2.0f)*z)); Chunk* pChunkAbove = GetCachedGridChunkOrFromPosition(vec3(posCheck1.x, posCheck1.y, posCheck1.z)); activeAbove = m_pChunkManager->GetBlockActiveFrom3DPosition(posCheck1.x, posCheck1.y, posCheck1.z, &blockPosAbove, &blockXAbove, &blockYAbove, &blockZAbove, &pChunkAbove); Chunk* pChunkAbove2 = GetCachedGridChunkOrFromPosition(vec3(posCheck2.x, posCheck2.y, posCheck2.z)); activeAbove2 = m_pChunkManager->GetBlockActiveFrom3DPosition(posCheck2.x, posCheck2.y, posCheck2.z, &blockPosAbove, &blockXAbove, &blockYAbove, &blockZAbove, &pChunkAbove2); if ((activeAbove == false) && (activeAbove2 == false)) { if (firstStepUp) { canAllStepUp = true; } isStepUp = true; } else { canAllStepUp = false; } firstStepUp = false; } if (length(*pNormal) <= 1.0f) { if (length(*pNormal) > 0.0f) { *pNormal = normalize(*pNormal); } float dotResult = dot(*pNormal, *pMovement); *pNormal *= dotResult; *pMovement -= *pNormal; worldCollision = true; } } } } } } *pStepUpBlock = canAllStepUp; if (worldCollision) return true; *pMovement = movementCache; return false; }
void Item::UpdatePhysics(float dt) { vec3 acceleration = (m_gravityDirection * 9.81f) * 4.0f; // Integrate velocity m_velocity += acceleration * dt; // Integrate angular velocity and rotation vec3 angularAcceleration(0.0f, 0.0f, 0.0f); m_angularVelocity += angularAcceleration * dt; m_rotation += m_angularVelocity * dt; if (m_worldCollide) { int blockX, blockY, blockZ; vec3 blockPos; // Check collision { vec3 velocityToUse = m_velocity; vec3 velAmount = velocityToUse*dt; vec3 pNormal; int numberDivision = 1; while (length(velAmount) >= 1.0f) { numberDivision++; velAmount = velocityToUse*(dt / numberDivision); } for (int i = 0; i < numberDivision; i++) { float dtToUse = (dt / numberDivision) + ((dt / numberDivision) * i); vec3 posToCheck = GetCenter() + velocityToUse*dtToUse; bool stepUp = false; if (CheckCollisions(posToCheck, m_previousPosition, &pNormal, &velAmount)) { // Reset velocity, we don't have any bounce m_velocity = vec3(0.0f, 0.0f, 0.0f); velocityToUse = vec3(0.0f, 0.0f, 0.0f); } } // Integrate position m_position += velocityToUse * dt; } // Owning chunks if (m_pOwningChunk != NULL && m_pOwningChunk->IsSetup() && m_pOwningChunk->IsInsideChunk(m_position)) { Chunk* pChunk = GetCachedGridChunkOrFromPosition(m_position); bool active = m_pChunkManager->GetBlockActiveFrom3DPosition(m_position.x, m_position.y, m_position.z, &blockPos, &blockX, &blockY, &blockZ, &pChunk); if (active == true) { // Roll back the integration, since we will intersect the block otherwise m_position -= m_velocity * dt; m_velocity = vec3(0.0f, 0.0f, 0.0f); } } else { if (m_pOwningChunk != NULL) { m_pOwningChunk->RemoveItem(this); } m_pOwningChunk = m_pChunkManager->GetChunkFromPosition(m_position.x, m_position.y, m_position.z); if (m_pOwningChunk != NULL) { m_pOwningChunk->AddItem(this); } if (m_pOwningChunk == NULL) { m_position -= m_velocity * dt; m_velocity = vec3(0.0f, 0.0f, 0.0f); } } } else { // Integrate position m_position += m_velocity * dt; } m_previousPosition = GetCenter(); }