Skip to content

Instantly share code, notes, and snippets.

@ajweeks
Created March 16, 2016 23:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ajweeks/781eb49186e51ac71d62 to your computer and use it in GitHub Desktop.
Save ajweeks/781eb49186e51ac71d62 to your computer and use it in GitHub Desktop.
2D Matrix Magic
//-----------------------------------------------------------------
// Base code by Thomas Kole
// http://www.thomaskole.com
//-----------------------------------------------------------------
#include "IsoScene.h"
#define GAME_ENGINE (GameEngine::GetSingleton())
void IsoScene::GameStart()
{
m_BmpGroundPtr = new Bitmap(String("Bitmaps/ground.png"));
m_BmpTreePtr = new Bitmap(String("Bitmaps/palm.png"));
m_BmpTreeShadowPtr = new Bitmap(String("Bitmaps/palm_shadow.png"));
m_BmpCharacterPtr = new Bitmap(String("Bitmaps/vaas.png"));
m_BmpCharacterShadowPtr = new Bitmap(String("Bitmaps/vaas_shadow.png"));
GenerateTrees();
m_playerPos = DOUBLE2(512, 512);
}
void IsoScene::GenerateTrees()
{
m_TreeArr = std::vector<DOUBLE2>(); // Clear th vector
for (size_t i = 0; i < 40; i++)
{
DOUBLE2 pos;
do
{
pos.x = rand() % 800 + 100;
pos.y = rand() % 800 + 100;
} while (IsCloseToTree(pos));
m_TreeArr.push_back(pos);
}
}
bool IsoScene::IsCloseToTree(const DOUBLE2& posRef)
{
double closeRadius = 60;
for (size_t i = 0; i < m_TreeArr.size(); ++i)
{
if ((posRef.x > m_TreeArr[i].x - closeRadius && posRef.x < m_TreeArr[i].x + closeRadius &&
posRef.y > m_TreeArr[i].y - closeRadius && posRef.y < m_TreeArr[i].y + closeRadius) ||
(posRef.x > m_playerPos.x - closeRadius && posRef.x < m_playerPos.x + closeRadius &&
posRef.y > m_playerPos.y - closeRadius && posRef.y < m_playerPos.y + closeRadius))
{
return true;
}
}
return false;
}
void IsoScene::GameEnd()
{
delete m_BmpGroundPtr;
delete m_BmpTreePtr;
delete m_BmpTreeShadowPtr;
delete m_BmpCharacterShadowPtr;
delete m_BmpCharacterPtr;
}
bool sortTrees(DOUBLE2 i, DOUBLE2 j)
{
return (i.y < j.y);
}
void sortVector(std::vector<DOUBLE2> & inputVector)
{
// for the curious:
// we put the vector in the std::sort method.
// this method requires #include <algorithm>
// this method asks for the beginning of the vector, and the end.
// and then it ask for a method, which takes 2 of the vector's types.
// in our case DOUBLE2's.
// I called this method sortTrees, and you can find it above this method.
// all it does is return a Bool that says if the first item is smaller than the second item.
std::sort(inputVector.begin(), inputVector.end(), sortTrees);
}
void IsoScene::GameTick(double deltaTime)
{
//all the key inputs, not that exciting.
if (GAME_ENGINE->IsKeyboardKeyDown(VK_RIGHT))
m_CamAngle += deltaTime;
if (GAME_ENGINE->IsKeyboardKeyDown(VK_LEFT))
m_CamAngle -= deltaTime;
if (GAME_ENGINE->IsKeyboardKeyDown(VK_UP))
m_TopDownFactor += deltaTime;
if (GAME_ENGINE->IsKeyboardKeyDown(VK_DOWN))
m_TopDownFactor -= deltaTime;
if (m_CamAngle < 0)
m_CamAngle += M_PI * 2;
if (m_CamAngle > (M_PI * 2))
m_CamAngle -= M_PI * 2;
if (m_TopDownFactor < 0.1)
m_TopDownFactor = 0.1;
if (m_TopDownFactor > 0.8)
m_TopDownFactor = 0.8;
double walkingSpeed = 120;
if (GAME_ENGINE->IsKeyboardKeyDown(VK_SHIFT))
walkingSpeed *= 1.8;
DOUBLE2 prevPlayerPos = m_playerPos;
if (GAME_ENGINE->IsKeyboardKeyDown('W'))
{
m_playerPos.x += deltaTime * walkingSpeed * cos(m_CamAngle + M_PI / 2.0);
m_playerPos.y -= deltaTime * walkingSpeed * sin(m_CamAngle + M_PI / 2.0);
}
if (GAME_ENGINE->IsKeyboardKeyDown('S'))
{
m_playerPos.x -= deltaTime * walkingSpeed * cos(m_CamAngle + M_PI / 2.0);
m_playerPos.y += deltaTime * walkingSpeed * sin(m_CamAngle + M_PI / 2.0);
}
if (GAME_ENGINE->IsKeyboardKeyDown('D'))
{
m_playerPos.x += deltaTime * walkingSpeed * cos(m_CamAngle);
m_playerPos.y -= deltaTime * walkingSpeed * sin(m_CamAngle);
}
if (GAME_ENGINE->IsKeyboardKeyDown('A'))
{
m_playerPos.x -= deltaTime * walkingSpeed * cos(m_CamAngle);
m_playerPos.y += deltaTime * walkingSpeed * sin(m_CamAngle);
}
m_playerPos = CheckCollisions(prevPlayerPos);
if (GAME_ENGINE->IsKeyboardKeyDown('Q'))
m_SunAngle -= deltaTime * 0.5;
if (GAME_ENGINE->IsKeyboardKeyDown('E'))
m_SunAngle += deltaTime * 0.5;
if (GAME_ENGINE->IsKeyboardKeyDown('Z'))
m_SunHeight -= deltaTime * 0.5;
if (GAME_ENGINE->IsKeyboardKeyDown('C'))
m_SunHeight += deltaTime * 0.5;
if (GAME_ENGINE->IsKeyboardKeyDown('O'))
m_CameraZoom -= deltaTime * 0.5;
if (GAME_ENGINE->IsKeyboardKeyDown('P'))
m_CameraZoom += deltaTime * 0.5;
if (GAME_ENGINE->IsKeyboardKeyPressed('R'))
GenerateTrees();
}
DOUBLE2 IsoScene::CheckCollisions(DOUBLE2 prevPlayerPos)
{
double trunkRadius = 12;
DOUBLE2 result = m_playerPos;
for (size_t i = 0; i < m_TreeArr.size(); ++i)
{
bool collidesX = (m_playerPos.x > m_TreeArr[i].x - trunkRadius && m_playerPos.x < m_TreeArr[i].x + trunkRadius);
bool collidesY = (m_playerPos.y > m_TreeArr[i].y - trunkRadius && m_playerPos.y < m_TreeArr[i].y + trunkRadius);
if (collidesX && collidesY)
{
if (prevPlayerPos.x > m_TreeArr[i].x - trunkRadius && prevPlayerPos.x < m_TreeArr[i].x + trunkRadius)
{
result.y = prevPlayerPos.y;
}
else
{
result.x = prevPlayerPos.x;
}
}
}
return result;
}
void IsoScene::GamePaint()
{
// An island isn't complete without a sea!
GAME_ENGINE->DrawSolidBackground(COLOR(10, 100, 200));
// SETUP CAMERA MATRIX
MATRIX3X2 matCameraPosition = MATRIX3X2::CreateTranslationMatrix(-m_playerPos);
MATRIX3X2 matCameraPivot = MATRIX3X2::CreateTranslationMatrix(GAME_ENGINE->GetWidth()/2,
GAME_ENGINE->GetHeight()/2);
MATRIX3X2 matCameraRotate = MATRIX3X2::CreateRotationMatrix(m_CamAngle);
MATRIX3X2 matCameraScale = MATRIX3X2::CreateScalingMatrix(1, m_TopDownFactor);
MATRIX3X2 matCameraZoom = MATRIX3X2::CreateScalingMatrix(m_CameraZoom, m_CameraZoom);
MATRIX3X2 matCameraTotal = matCameraPosition * matCameraRotate * matCameraScale * matCameraZoom * matCameraPivot;
GAME_ENGINE->SetViewMatrix(matCameraTotal);
// DRAW GROUND
GAME_ENGINE->DrawBitmap(m_BmpGroundPtr);
// DRAW TREE SHADOWS
for (size_t i = 0; i < m_TreeArr.size(); ++i)
{
MATRIX3X2 matTreeShadowPivot = MATRIX3X2::CreateTranslationMatrix(DOUBLE2(-30, -100));
MATRIX3X2 matTreeShadowScale = MATRIX3X2::CreateScalingMatrix(1, m_SunHeight);
MATRIX3X2 matTreeShadowRotation = MATRIX3X2::CreateRotationMatrix(m_SunAngle);
MATRIX3X2 matTreeShadowTranslation = MATRIX3X2::CreateTranslationMatrix(m_TreeArr[i]);
GAME_ENGINE->SetViewMatrix(matTreeShadowPivot * matTreeShadowScale * matTreeShadowRotation *
matTreeShadowTranslation * matCameraTotal);
GAME_ENGINE->DrawBitmap(m_BmpTreeShadowPtr);
}
// DRAW PLAYER SHADOW
MATRIX3X2 matPlayerShadowPivot = MATRIX3X2::CreateTranslationMatrix(DOUBLE2(-15, -60));
MATRIX3X2 matPlayerShadowRotation = MATRIX3X2::CreateRotationMatrix(m_SunAngle);
MATRIX3X2 matPlayerShadowTranslation = MATRIX3X2::CreateTranslationMatrix(m_playerPos);
GAME_ENGINE->SetViewMatrix(matPlayerShadowPivot * matPlayerShadowRotation * matPlayerShadowTranslation * matCameraTotal);
GAME_ENGINE->DrawBitmap(m_BmpCharacterShadowPtr);
DOUBLE2 vecPlayerPositionTransformed;
vecPlayerPositionTransformed = matCameraTotal.TransformPoint(m_playerPos);
// DRAW BACK TREES
std::vector<DOUBLE2> transformedTreeArr;
for (size_t i = 0; i < m_TreeArr.size(); ++i)
{
DOUBLE2 vecTransformedTreePos;
vecTransformedTreePos = matCameraTotal.TransformPoint(m_TreeArr[i]);
transformedTreeArr.push_back(vecTransformedTreePos);
}
sortVector(transformedTreeArr);
double xScale = cos(m_CamAngle);
MATRIX3X2 matSideScale = MATRIX3X2::CreateScalingMatrix(xScale, 1);
int lastTreeDrawnIndex = 0;
for (size_t i = 0; i < transformedTreeArr.size(); ++i)
{
if (transformedTreeArr[i].y >= vecPlayerPositionTransformed.y)
{
lastTreeDrawnIndex = i;
break;
}
MATRIX3X2 matTreePivot = MATRIX3X2::CreateTranslationMatrix(DOUBLE2(-30, -100));
MATRIX3X2 matTreeTranslation = MATRIX3X2::CreateTranslationMatrix(transformedTreeArr[i]);
GAME_ENGINE->SetViewMatrix(matTreePivot * matCameraZoom * matSideScale * matTreeTranslation);
GAME_ENGINE->DrawBitmap(m_BmpTreePtr);
}
// DRAW PLAYER
MATRIX3X2 matPlayerPivot = MATRIX3X2::CreateTranslationMatrix(DOUBLE2(-15, -60));
MATRIX3X2 matPlayerTranslation = MATRIX3X2::CreateTranslationMatrix(vecPlayerPositionTransformed);
GAME_ENGINE->SetViewMatrix(matPlayerPivot * matCameraZoom * matSideScale * matPlayerTranslation);
GAME_ENGINE->DrawBitmap(m_BmpCharacterPtr);
// DRAW FRONT TREES
MATRIX3X2 matTreePivot = MATRIX3X2::CreateTranslationMatrix(DOUBLE2(-30, -100));
for (size_t i = lastTreeDrawnIndex; i < transformedTreeArr.size(); ++i)
{
MATRIX3X2 matTreeTranslation = MATRIX3X2::CreateTranslationMatrix(transformedTreeArr[i]);
GAME_ENGINE->SetViewMatrix(matTreePivot * matCameraZoom * matSideScale * matTreeTranslation);
GAME_ENGINE->DrawBitmap(m_BmpTreePtr);
}
DOUBLE2 xAxis = DOUBLE2(cos(m_CamAngle), sin(m_CamAngle) * m_TopDownFactor);
DOUBLE2 yAxis = DOUBLE2(0, 1);
MATRIX3X2 matTextBoxSkewing = MATRIX3X2(xAxis, yAxis);
GAME_ENGINE->SetViewMatrix(matPlayerPivot * matCameraZoom * matTextBoxSkewing * matPlayerTranslation);
GAME_ENGINE->SetColor(COLOR(0, 0, 0, 120));
GAME_ENGINE->FillRect(-145, -100, 145, -50);
GAME_ENGINE->SetColor(COLOR(240, 240, 240));
GAME_ENGINE->DrawString(String("WASD TO MOVE VAAS, ARROWS TO ROTATE CAMERA\n"
" Q E Z C TO MOVE THE SUN, O P TO ZOOM\n SHIFT TO SPRINT, R TO REGENERATE TREES"), -138, -95);
}
#pragma once
class IsoScene : public AbstractGame
{
public:
virtual void GameInitialize(GameSettings &gameSettingsRef);
virtual void GameStart();
virtual void GameEnd();
virtual void GameTick(double deltaTime);
virtual void GamePaint();
private:
/* Returns whether or not the player collided with any trees */
DOUBLE2 CheckCollisions(DOUBLE2 prevPlayerPos);
void GenerateTrees();
bool IsCloseToTree(const DOUBLE2& posRef);
DOUBLE2 m_playerPos;
double m_CamAngle, m_TopDownFactor = 0.5;
double m_SunAngle = 0;
double m_SunHeight = 1;
double m_CameraZoom = 1;
std::vector<DOUBLE2> m_TreeArr;
Bitmap * m_BmpTreePtr, * m_BmpTreeShadowPtr , *m_BmpGroundPtr, *m_BmpCharacterPtr, *m_BmpCharacterShadowPtr;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment