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 CCharacterCamera::CameraThink() { BaseClass::CameraThink(); CCharacter* pCharacter = m_hCharacter; if (!pCharacter) return; if (GetThirdPerson()) { SetGlobalOrigin(GetThirdPersonCameraPosition()); SetGlobalAngles(VectorAngles(GetThirdPersonCameraDirection())); } else { SetGlobalOrigin(pCharacter->GetGlobalOrigin() + pCharacter->GetUpVector() * (TFloat)pCharacter->EyeHeight()); SetGlobalAngles(pCharacter->GetViewAngles()); } }
void CGame::DrawCharacters(const std::vector<CCharacter*>& apRenderList, bool bTransparent) { CRenderer* pRenderer = GetRenderer(); // Loop through all characters, render them one at a time. // Start at the back of the list so that transparent entities use the painter's algorithm. for (size_t i = apRenderList.size()-1; i < apRenderList.size(); i--) { CCharacter* pCharacter = apRenderList[i]; CRenderingContext c(pRenderer, true); c.SetBlend(BLEND_NONE); c.SetAlpha(1); // Set the color of the box to be rendered. c.SetUniform("vecColor", pCharacter->m_clrRender); if (pCharacter->m_iBillboardTexture) { c.SetBackCulling(false); c.SetUniform("bDiffuse", true); // Create a billboard by creating basis vectors. https://www.youtube.com/watch?v=puOTwCrEm7Q Vector vecForward, vecRight, vecUp; vecForward = pCharacter->GetGlobalOrigin() - pRenderer->GetCameraPosition(); vecRight = -Vector(0, 1, 0).Cross(vecForward).Normalized(); vecUp = vecForward.Cross(-vecRight).Normalized(); if (pCharacter->m_bDrawTransparent) { c.SetAlpha(0.6f); c.SetBlend(BLEND_ALPHA); } c.LoadTransform(pCharacter->GetGlobalTransform()); c.Translate(Vector(0, pCharacter->m_aabbSize.GetHeight()/2, 0)); // Move the character up so his feet don't stick in the ground. pCharacter->ShotEffect(&c); c.RenderBillboard(pCharacter->m_iBillboardTexture, pCharacter->m_aabbSize.vecMax.x, vecUp, vecRight); } else { c.SetUniform("bDiffuse", false); // The transform matrix holds all transformations for the player. Just pass it through to the renderer. // http://youtu.be/7pe1xYzFCvA c.Transform(pCharacter->GetGlobalTransform()); if (pCharacter->m_bDrawTransparent) { c.SetAlpha(0.6f); c.SetBlend(BLEND_ALPHA); } if (pCharacter->m_iTexture) { c.SetUniform("bDiffuse", true); c.BindTexture(pCharacter->m_iTexture); } // Render the player-box c.RenderBox(pCharacter->m_aabbSize.vecMin, pCharacter->m_aabbSize.vecMax); } } }
void CGame::Draw() { Vector vecForward = m_hPlayer->GetGlobalView(); Vector vecUp(0, 1, 0); // Cross-product http://www.youtube.com/watch?v=FT7MShdqK6w Vector vecRight = vecUp.Cross(vecForward).Normalized(); CRenderer* pRenderer = GetRenderer(); // Tell the renderer how to set up the camera. pRenderer->SetCameraPosition(m_hPlayer->GetGlobalOrigin() - vecForward * 6 + vecUp * 3 - vecRight * 0.5f); pRenderer->SetCameraDirection(vecForward); pRenderer->SetCameraUp(Vector(0, 1, 0)); pRenderer->SetCameraFOV(90); pRenderer->SetCameraNear(0.1f); pRenderer->SetCameraFar(1000); // This rendering context is a tool for rendering things to the screen. // All of our drawing commands are part of it. CRenderingContext r(pRenderer); // Clear the depth buffer and set a background color. r.ClearDepth(); r.ClearColor(Color(210, 230, 255)); // CRenderer::StartRendering() - This function sets up OpenGL with the // camera information that we passed it before. pRenderer->StartRendering(&r); m_oFrameFrustum = CFrustum(r.GetProjection() * r.GetView()); // First tell OpenGL what "shader" or "program" to use. r.UseProgram("model"); // Set the sunlight direction. The y component is -1 so the light is pointing down. Vector vecSunlight = Vector(1, -1, 1).Normalized(); // Uncomment this code to make the sunlight rotate: //Vector vecSunlight = Vector(cos(Game()->GetTime()), -1, sin(Game()->GetTime())).Normalized(); r.SetUniform("vecSunlight", vecSunlight); r.SetUniform("bLighted", false); r.SetUniform("bDiffuse", false); // Render the ground. r.SetUniform("vecColor", Vector4D(0.6f, 0.7f, 0.9f, 1)); r.SetUniform("vecCameraPosition", GetRenderer()->GetCameraPosition()); r.BeginRenderTriFan(); r.Normal(Vector(0, 1, 0)); r.Tangent(Vector(1, 0, 0)); r.Bitangent(Vector(0, 0, 1)); r.TexCoord(Vector2D(0, 1)); r.Vertex(Vector(-30, 0, -30)); r.TexCoord(Vector2D(0, 0)); r.Vertex(Vector(-30, 0, 30)); r.TexCoord(Vector2D(1, 0)); r.Vertex(Vector(30, 0, 30)); r.TexCoord(Vector2D(1, 1)); r.Vertex(Vector(30, 0, -30)); r.EndRender(); r.SetUniform("bLighted", true); // Prepare a list of entities to render. m_apRenderOpaqueList.clear(); m_apRenderTransparentList.clear(); for (size_t i = 0; i < MAX_CHARACTERS; i++) { CCharacter* pCharacter = GetCharacterIndex(i); if (!pCharacter) continue; // We need to scale the AABB using the character's scale values before we can use it to calculate our center/radius. AABB aabbSizeWithScaling = pCharacter->m_aabbSize * pCharacter->m_vecScaling; Vector vecCharacterCenter = pCharacter->GetGlobalOrigin() + aabbSizeWithScaling.GetCenter(); float flCharacterRadius = aabbSizeWithScaling.GetRadius(); // If the entity is outside the viewing frustum then the player can't see it - don't draw it. // http://youtu.be/4p-E_31XOPM if (!m_oFrameFrustum.SphereIntersection(vecCharacterCenter, flCharacterRadius)) continue; if (pCharacter->m_bDrawTransparent) m_apRenderTransparentList.push_back(pCharacter); else m_apRenderOpaqueList.push_back(pCharacter); } // Draw all opaque characters first. DrawCharacters(m_apRenderOpaqueList, false); for (size_t i = 0; i < MAX_CHARACTERS; i++) { CCharacter* pCharacter = GetCharacterIndex(i); if (!pCharacter) continue; if (!pCharacter->m_bEnemyAI) continue; float flRadius = 3.5f; Vector vecIndicatorOrigin = NearestPointOnSphere(m_hPlayer->GetGlobalOrigin(), flRadius, pCharacter->GetGlobalOrigin()); float flBoxSize = 0.1f; r.SetUniform("vecColor", Color(255, 0, 0, 255)); r.RenderBox(vecIndicatorOrigin - Vector(1, 1, 1)*flBoxSize, vecIndicatorOrigin + Vector(1, 1, 1)*flBoxSize); } // Sort the transparent render list so that we paint the items farther from the camera first. http://youtu.be/fEjZrwDKdi8 MergeSortTransparentRenderList(); // Now draw all transparent characters, sorted by distance from the camera. DrawCharacters(m_apRenderTransparentList, true); r.SetUniform("bDiffuse", false); // Render any bullet tracers that may have been created. float flBulletTracerTime = 0.1f; for (size_t i = 0; i < Game()->GetTracers().size(); i++) { if (Game()->GetTime() < Game()->GetTracers()[i].flTimeCreated + flBulletTracerTime) { Vector vecStart = Game()->GetTracers()[i].vecStart; Vector vecEnd = Game()->GetTracers()[i].vecEnd; r.SetUniform("vecColor", Vector4D(1, 0.9f, 0, 1)); r.BeginRenderLines(); r.Normal(Vector(0, 1, 0)); r.Vertex(vecStart); r.Vertex(vecEnd); r.EndRender(); } } // Render any puffs that may have been created. float flPuffTime = 0.3f; for (size_t i = 0; i < Game()->GetPuffs().size(); i++) { if (Game()->GetTime() < Game()->GetPuffs()[i].flTimeCreated + flPuffTime) { float flTimeCreated = Game()->GetPuffs()[i].flTimeCreated; float flTimeOver = Game()->GetPuffs()[i].flTimeCreated + flPuffTime; float flStartSize = 0.2f; float flEndSize = 2.0f; float flSize = Remap(Game()->GetTime(), flTimeCreated, flTimeOver, flStartSize, flEndSize); Vector vecOrigin = Game()->GetPuffs()[i].vecOrigin; int iOrange = (int)Remap(Game()->GetTime(), flTimeCreated, flTimeOver, 0, 255); r.SetUniform("vecColor", Color(255, iOrange, 0, 255)); r.RenderBox(vecOrigin - Vector(1, 1, 1)*flSize, vecOrigin + Vector(1, 1, 1)*flSize); } } GraphDraw(); pRenderer->FinishRendering(&r); // Call this last. Your rendered stuff won't appear on the screen until you call this. Application()->SwapBuffers(); }
// In this Update() function we need to update all of our characters. Move them around or whatever we want to do. // http://www.youtube.com/watch?v=c4b9lCfSDQM void CGame::Update(float dt) { Vector x0 = m_hPlayer->GetGlobalOrigin(); // The approach function http://www.youtube.com/watch?v=qJq7I2DLGzI m_hPlayer->m_vecMovement.x = Approach(m_hPlayer->m_vecMovementGoal.x, m_hPlayer->m_vecMovement.x, dt * 65); m_hPlayer->m_vecMovement.z = Approach(m_hPlayer->m_vecMovementGoal.z, m_hPlayer->m_vecMovement.z, dt * 65); Vector vecForward = m_hPlayer->GetGlobalView(); vecForward.y = 0; vecForward.Normalize(); Vector vecUp(0, 1, 0); // Cross product http://www.youtube.com/watch?v=FT7MShdqK6w Vector vecRight = vecUp.Cross(vecForward); float flSaveY = m_hPlayer->m_vecVelocity.y; m_hPlayer->m_vecVelocity = vecForward * m_hPlayer->m_vecMovement.x + vecRight * m_hPlayer->m_vecMovement.z; m_hPlayer->m_vecVelocity.y = flSaveY; // Update position and vecMovement. http://www.youtube.com/watch?v=c4b9lCfSDQM m_hPlayer->SetTranslation(m_hPlayer->GetGlobalOrigin() + m_hPlayer->m_vecVelocity * dt); m_hPlayer->m_vecVelocity = m_hPlayer->m_vecVelocity + m_hPlayer->m_vecGravity * dt; // Make sure the player doesn't fall through the floor. The y dimension is up/down, and the floor is at 0. Vector vecTranslation = m_hPlayer->GetGlobalOrigin(); if (vecTranslation.y < 0) m_hPlayer->SetTranslation(Vector(vecTranslation.x, 0, vecTranslation.z)); // Grab the player's translation and make a translation only matrix. http://www.youtube.com/watch?v=iCazI3nKBf0 Vector vecPosition = m_hPlayer->GetGlobalOrigin(); Matrix4x4 mPlayerTranslation; mPlayerTranslation.SetTranslation(vecPosition); // Create a set of basis vectors that do what we need. vecForward = m_hPlayer->GetGlobalView(); vecForward.y = 0; // Flatten the angles so that the box doesn't rotate up and down as the player does. vecForward.Normalize(); // Re-normalize, we need all of our basis vectors to be normal vectors (unit-length) vecUp = Vector(0, 1, 0); // The global up vector vecRight = -vecUp.Cross(vecForward).Normalized(); // Cross-product: https://www.youtube.com/watch?v=FT7MShdqK6w // Use these basis vectors to make a matrix that will transform the player-box the way we want it. // http://youtu.be/8sqv11x10lc Matrix4x4 mPlayerRotation(vecForward, vecUp, vecRight); Matrix4x4 mPlayerScaling = Matrix4x4(); // Produce a transformation matrix from our three TRS matrices. // Order matters! http://youtu.be/7pe1xYzFCvA m_hPlayer->SetGlobalTransform(mPlayerTranslation * mPlayerRotation * mPlayerScaling); Vector x1 = m_hPlayer->GetGlobalOrigin(); float flPlayerDistanceTraveled = m_hPlayer->m_flDistanceTraveled; // Add the distance traveled this frame. flPlayerDistanceTraveled += (x1 - x0).Length(); m_hPlayer->m_flDistanceTraveled = flPlayerDistanceTraveled; float flMonsterSpeed = 0.5f; for (size_t i = 0; i < MAX_CHARACTERS; i++) { CCharacter* pCharacter = GetCharacterIndex(i); if (!pCharacter) continue; if (!pCharacter->m_bEnemyAI) continue; // Update position and movement. http://www.youtube.com/watch?v=c4b9lCfSDQM pCharacter->m_vecVelocity = (m_hPlayer->GetGlobalOrigin() - pCharacter->GetGlobalOrigin()).Normalized() * flMonsterSpeed; pCharacter->SetTranslation(pCharacter->GetGlobalOrigin() + pCharacter->m_vecVelocity * dt); } if (Game()->GetTime() >= m_projectile_initial_time + 8) { m_projectile_position[0] = m_projectile_initial_position; m_projectile_velocity[0] = m_projectile_initial_velocity = Vector((float)(mtrand()%1000)/250-2, 2.5, (float)(mtrand()%1000)/250-2) * 5; m_projectile_initial_time = Game()->GetTime(); m_projectile_break_time = Game()->GetTime() + PredictProjectileMaximumHeightTime(m_projectile_initial_velocity, m_projectile_gravity); m_projectile_number = 1; } if (Game()->GetTime() >= m_projectile_break_time && m_projectile_number == 1) { for (int i = 1; i < MAX_PROJECTILES; i++) { m_projectile_position[i] = m_projectile_position[0]; m_projectile_velocity[i] = m_projectile_velocity[0] + Vector((float)(mtrand()%1000)/250-2, (float)(mtrand()%1000)/250-2, (float)(mtrand()%1000)/250-2); } m_projectile_number = MAX_PROJECTILES; } // Simulate the projectile for (int i = 0; i < m_projectile_number; i++) { m_projectile_position[i] = m_projectile_position[i] + m_projectile_velocity[i] * dt; m_projectile_velocity[i] = m_projectile_velocity[i] + m_projectile_gravity * dt; if (m_projectile_position[i].y < 0) { MakePuff(m_projectile_position[i]); m_projectile_position[i].y = 9999999; // Move it way up high and out of sight until it gets reset. Sort of a hack, no big deal. } } }