Wednesday 15 October 2014

Game Engines Blog 2


We’ve decided to change our game idea to a competitive first person shooter. We wanted our game to have a fast paced, fun and competitive feel, and by incorporating elements like wall running can add variation to gameplay similar to Mirror's Edge. Another great aspect was the game's camera movement, it gives the player a very intense feeling when maneuvering through obstacles and looks more realistic. These are the elements I want to focus on the most while my other team member wants to focus on the shooting.

So for this week I started to implement basic movement, physics and model loading into the engine. We want swift movement along with a wall running mechanic to have fast gameplay. I started off with a basic camera class that moves in a FPS fashion by calculating the forward, right and up vectors and moving the entity along those directions.
I have also created an object class to easily create new obj entities in the scene in only 3 lines of code.

       OBJModel player;
       player.Load("Crate.obj", "crateTexture.png");
       player.Init(entityMgr, cpoolMgr, shaderPathVS, shaderPathFS);

For collision, a map class was made to extract the vertex information of a map obj file to be used with collision checking.

bool Map::Load(core_str::String model, core_str::String texture)
{
       this->Model.Load(model, texture);

       gfx_med::ObjLoader::vert_cont_type model_verts = Model.Get_Vertices();
       for (gfx_med::ObjLoader::vert_cont_type::iterator itr = model_verts.begin(), itrEnd = model_verts.end(); itr != itrEnd; ++itr)
       {
              math::types::Vector_TI<float, 3> vert = itr->GetPosition();
              mesh.push_back(math_t::Vec3f(vert[0], vert[1], vert[2]));
              //also needs verts to be transformed by the modelmatrix (NEEDS UPDATING)
       }
       return true;

}


Once that’s done I’ve implemented mesh collision between each individual triangle of the mesh and a sliding sphere.

bool camera::Collide(core_conts::Array<math_t::Vec3f> coll_verts, input_hid::keyboard_b_vptr& keyboard)
{
       bool result = false;
       int verts_size = coll_verts.size();

       if (verts_size > 0)
       {
              for (int i = 0; i < verts_size; i += 3)
              {
                     if (Collision_Tools::GetInstance()->IntersectsTriangle(this->Coll_Sphere, coll_verts[i], coll_verts[i + 1], coll_verts[i + 2]))
                     {
                           math_t::Vec3f &vertex1 = coll_verts[i];
                           math_t::Vec3f &vertex2 = coll_verts[i + 1];
                           math_t::Vec3f &vertex3 = coll_verts[i + 2];

                           math_t::Vec3f closestpt = Collision_Tools::GetInstance()->NearestPointOnTriangle(this->Coll_Sphere.center, vertex1, vertex2, vertex3);

                           math_t::Vec3f closestpt_subtr_coll_sphere = (closestpt - this->Coll_Sphere.center);
                           closestpt_subtr_coll_sphere.Normalize();
                           math_t::Vec3f PlaneNormal = closestpt_subtr_coll_sphere;


                           float penetrationdepth = abs(this->Coll_Sphere.radius - closestpt.Distance(this->Coll_Sphere.center));
                           float velocityAlongNormal = velocity.Dot(PlaneNormal);

                           float dotangle = abs(PlaneNormal.Dot(math_t::Vec3f(PlaneNormal[0], 0, PlaneNormal[2])));


                           if (dotangle < 0.6f)
                           {
                                  this->on_ground = true;
                                  PlaneNormal[0] *= 0;
                                  PlaneNormal[2] *= 0;
                           }
                           if ((dotangle > 0.8f && dotangle < 1.2f) && !on_ground)
                           {
                                  wall_normal = PlaneNormal;
                                  if (mode == 1)
                                  {
                                         previous_direction = direction;
                                         previous_direction[1] = -0.08f;
                                  }
                                  if (keyboard->IsKeyDown(input_hid::KeyboardEvent::space) || wall_run_timer > 0)
                                  {
                                  }
                                  wall_run_timer = 0.2f;
                           }

                           if (velocityAlongNormal > -penetrationdepth)
                           {
                                  this->velocity -= PlaneNormal * (penetrationdepth + velocityAlongNormal);
                                  //this->state.velocityAlongWall = glm::normalize(this->velocity);
                                  result = true;
                           }
                     }
              }
       }

       return result;
}

This algorithm calculates the velocity of the player against a wall.
For the rest of the week, I made a prototype testing out the wall running mechanic. In this example, I made a map where the player needs to wall run across to get to the other side of the building.


This is done by simply moving the player against the inverted normal of the wall and moving the player in the forward velocity along the wall.