Side-Tracked

Project Stats:

Name: Side-Tracked
Project type: Student project
Production Time: 16 weeks total 8 weeks before I joined and 8 after
Date: 2018/05-2018/06
Engine/language: C++
Platforms: PC, Switch
Tools: Visual Studio, Perforce, Jira
Team members: 18 students

Project Description

For this project, my team developed a custom voxel game engine during 8 weeks before I joined the project. I mostly contributed to the gameplay programming.

My contributions

  • Engine/editor
    • Implementing a Sound manager using fmod
    • voxel raycasting to select objects in the editor
  • Gameplay
  • TODO
    • CAMERA CODE check

Camera interpolation and rotation

To implement camera interpolation I changed the way the camera moves around the train to make controlling the camera more intuitive. Instead of having a vector that controls the look at position and a vector that controls the position of the camera relative to the train. I have one vector that controls where the camera looks at(the train in most cases) and 3 floats one that controls the pitch, one that controls the yaw, and one that controls the distance from the target(train mostly). To make the camera angles dependent on the train's rotation I multiply the calculated camera offset by the train's rotation matrix.

// set horizontal angle target
void setHorizontalAngle(float newAimOffset);
// set vertical angle target
void setVerticalAngle(float newAimOffset);
// set aimoffset target
void setCameraOffset(glm::vec3 newAimOffset);
// set distance target
void setDistance(float newDistance);

By calling these functions instead of setting the value directly the camera internally interpolates to the new values. This interface makes it easy for others working on the project who are using the camera as there is no extra work required to make it interpolate.

Here is a video showing the interpolations in the main menu as well as setting the values through the editor:

Here is a video showing the interpolations in game:

Code snippets - Code I used for interpolating and rotating the camera

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// get the inverse of the targets rotation matrix
glm::mat4 targetRotMatrix = glm::inverse(m_targetObject->getTransform().getRotationMatrix());
// rotate the targets rotating matrix on the y asix by pi
targetRotMatrix *= glm::eulerAngleXYZ(0.0f,glm::pi<float>(),0.0f);

// update the cameras target
m_cameraComp->m_target = m_targetObject->getTransform().getPosition();

// interpolate camera offset
m_currentCameraOffset = glm::lerp(m_currentCameraOffset, m_cameraOffset, m_offsetInterpolationSpeed * deltaTime);

// interpolate cameras distance form the target
m_currentDistance = glm::lerp(m_currentDistance, m_distance, m_distanceInterpolationSpeed * deltaTime);

// camera offset
glm::vec4 cameraOffsetV4 = glm::vec4(m_currentCameraOffset, 1.0f) * targetRotMatrix;
glm::vec3 cameraOffset = glm::vec3(cameraOffsetV4.x, cameraOffsetV4.y, cameraOffsetV4.z);
m_cameraComp->setAimOffset(cameraOffset);

// calculate targets forward facing angle
glm::vec4 targetForward = m_targetObject->getTransform().getRotationMatrix() * glm::vec4(0,0,-1.0f,1.0f);
float targetAngle = atan2(targetForward.x, targetForward.z);

// horizontal target angle
float interpolatedHorAngle = m_horizontalAngle + targetAngle; ///////////////////////

// interpolate angles
m_currentHorizontalAngle = normalizeAngle(m_currentHorizontalAngle);
m_currentHorizontalAngle = angleLerp(m_currentHorizontalAngle, normalizeAngle(interpolatedHorAngle), m_angleInterpolationSpeed*deltaTime);
m_curretVerticleAngle = angleLerp(m_curretVerticleAngle, m_verticalAngle, m_angleInterpolationSpeed*deltaTime);

// calculate offset using interpolated angles
glm::vec3 targetOffset = glm::vec3(
cos(m_curretVerticleAngle) * sin(m_currentHorizontalAngle),
sin(m_curretVerticleAngle),
cos(m_curretVerticleAngle) * cos(m_currentHorizontalAngle)
);
targetOffset = glm::normalize(targetOffset) * m_currentDistance;
// set cameras offset
m_cameraComp->setTargetOffset(targetOffset + cameraOffset);

Muzzle flash

I added a muzzle flash to the turrets. I implemented this by using the light component and changing its intensity every time a shot is fired.

Adding the component and setting up variables:

m_lightEntity = getWorld()->addEntity<Entity>().get();
m_lightComponent = m_lightEntity->addComponent<LightComponent>().get();
m_lightComponent->setType(sb::graphics::LightType::PointLight);
m_lightComponent->getPointLight()->intensity = 0.0f;
m_lightComponent->getPointLight()->radius = 40.0f;
m_lightChangeVelocity = 0.0f;

Code in the shoot function that sets the lights color and intensity and starts the interpolation:

m_lightChangeVelocity = glm::pi<float>();
m_currentRandomIntencity = Utils::randomBetweenValue(0.0f, m_randomIntencity);
m_lightComponent->getPointLight()->color = 
    glm::vec3(1.0f, Utils::randomBetweenValue(155.0f, 255.0f)/255.0f, 100.0f / 255.0f);

Code form the update function that interpolates the lights intencity using sin and sets the position off the light on the end off the turret:

m_lightChangeVelocity -= m_lightSpeed * deltaTime;
if (m_lightChangeVelocity < 0.0f)
{
	m_lightChangeVelocity = 0.0f;
}

m_lightComponent->getPointLight()->intensity = sin(m_lightChangeVelocity) * m_lightIntencity;
glm::vec4 lightPos = 
    glm::vec4(getTransform().getPosition(), 1.0f) 
    + (glm::vec4(0.0f, 0, -5.0f, 0.0f) 
    * glm::inverse(m_onTrain->getTransform().getRotationMatrix())) 
    * glm::inverse(m_trainRef->getTransform().getRotationMatrix());
m_lightEntity->getTransform().setPosition(glm::vec3(lightPos.x, lightPos.y, lightPos.z));