Upstream for PGE updates.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
olcPixelGameEngine/Videos/CarCrimeCity/Part2/cCarCrimeCity.cpp

710 lines
22 KiB

#include "cCarCrimeCity.h"
cCarCrimeCity::cCarCrimeCity()
{
sAppName = "Car Crime City";
}
cCarCrimeCity::~cCarCrimeCity()
{
}
bool cCarCrimeCity::OnUserCreate()
{
// Initialise PGEX 3D
olc::GFX3D::ConfigureDisplay();
// Load fixed system assets, i.e. those need to simply do anything
if (!LoadAssets()) return false;
// Create Default city
pCity = new cCityMap(cGameSettings::nDefaultMapWidth, cGameSettings::nDefaultMapHeight, mapAssetTextures, mapAssetMeshes, mapAssetTransform);
// If a city map file has been specified, then load it
if (!cGameSettings::sDefaultCityFile.empty())
{
if (!pCity->LoadCity(cGameSettings::sDefaultCityFile))
{
std::cout << "Failed to load '" << cGameSettings::sDefaultCityFile << "'" << std::endl;
return false;
}
}
return true;
}
bool cCarCrimeCity::LoadAssets()
{
// Game Settings should have loaded all the relevant file information
// to start loading asset information. Game assets will be stored in
// a map structure. Maps can have slightly longer access times, so each
// in game object will have facility to extract required resources once
// when it is created, meaning no map search during normal use
// System Meshes
// A simple flat unit quad
olc::GFX3D::mesh* meshQuad = new olc::GFX3D::mesh();
meshQuad->tris =
{
{ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
{ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
};
mapAssetMeshes["UnitQuad"] = meshQuad;
//// The four outer walls of a cell
olc::GFX3D::mesh* meshWallsOut = new olc::GFX3D::mesh();
meshWallsOut->tris =
{
// EAST
{ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
{ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
// WEST
{ 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
{ 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
// TOP
{ 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
{ 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
// BOTTOM
{ 1.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
{ 1.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
};
mapAssetMeshes["WallsOut"] = meshWallsOut;
// System Textures
for (auto &asset : cGameSettings::vecAssetTextures)
{
olc::Sprite *sprAsset = new olc::Sprite();
if (sprAsset->LoadFromFile(asset.sFile))
{
mapAssetTextures[asset.sName] = sprAsset;
}
else
{
std::cout << "Failed to load " << asset.sName << std::endl;
return false;
}
}
// Break up roads sprite into individual sprites. Why? Its easier to maintain
// the roads sprite as a single image, but easier to use if they are all individual.
// Breaking it up manually in the image editing software is time consuming so just
// do it here
int nRoadTexSize = 256; // In pixels in base texture
int nRoadTexOffset = 64; // There exists a 64 pixel offset from top left of source image
for (int r = 0; r < 12; r++)
{
olc::Sprite* road = new olc::Sprite(nRoadTexSize, nRoadTexSize);
SetDrawTarget(road);
DrawPartialSprite(0, 0, mapAssetTextures["AllRoads"], ((r % 3) * nRoadTexSize) + nRoadTexOffset, ((r / 3) * nRoadTexSize) + nRoadTexOffset, nRoadTexSize, nRoadTexSize);
switch (r)
{
case 0: mapAssetTextures["Road_V"] = road; break;
case 1: mapAssetTextures["Road_H"] = road; break;
case 2: mapAssetTextures["Pavement"] = road; break;
case 3: mapAssetTextures["Road_C1"] = road; break;
case 4: mapAssetTextures["Road_T1"] = road; break;
case 5: mapAssetTextures["Road_C2"] = road; break;
case 6: mapAssetTextures["Road_T2"] = road; break;
case 7: mapAssetTextures["Road_X"] = road; break;
case 8: mapAssetTextures["Road_T3"] = road; break;
case 9: mapAssetTextures["Road_C3"] = road; break;
case 10: mapAssetTextures["Road_T4"] = road; break;
case 11: mapAssetTextures["Road_C4"] = road; break;
}
}
SetDrawTarget(nullptr);
// Load Buildings
for (auto &asset : cGameSettings::vecAssetBuildings)
{
mapAssetMeshes[asset.sDescription] = new olc::GFX3D::mesh();
mapAssetMeshes[asset.sDescription]->LoadOBJFile(asset.sModelOBJ);
mapAssetTextures[asset.sDescription] = new olc::Sprite(asset.sModelPNG);
olc::GFX3D::mat4x4 matScale = olc::GFX3D::Math::Mat_MakeScale(asset.fScale[0], asset.fScale[1], asset.fScale[2]);
olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation(asset.fTranslate[0], asset.fTranslate[1], asset.fTranslate[2]);
olc::GFX3D::mat4x4 matRotateX = olc::GFX3D::Math::Mat_MakeRotationX(asset.fRotate[0]);
olc::GFX3D::mat4x4 matRotateY = olc::GFX3D::Math::Mat_MakeRotationY(asset.fRotate[1]);
olc::GFX3D::mat4x4 matRotateZ = olc::GFX3D::Math::Mat_MakeRotationZ(asset.fRotate[2]);
olc::GFX3D::mat4x4 matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTranslate, matScale);
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateX);
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateY);
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateZ);
mapAssetTransform[asset.sDescription] = matTransform;
}
// Load Vehicles
for (auto &asset : cGameSettings::vecAssetVehicles)
{
mapAssetMeshes[asset.sDescription] = new olc::GFX3D::mesh();
mapAssetMeshes[asset.sDescription]->LoadOBJFile(asset.sModelOBJ);
mapAssetTextures[asset.sDescription] = new olc::Sprite(asset.sModelPNG);
olc::GFX3D::mat4x4 matScale = olc::GFX3D::Math::Mat_MakeScale(asset.fScale[0], asset.fScale[1], asset.fScale[2]);
olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation(asset.fTranslate[0], asset.fTranslate[1], asset.fTranslate[2]);
olc::GFX3D::mat4x4 matRotateX = olc::GFX3D::Math::Mat_MakeRotationX(asset.fRotate[0]);
olc::GFX3D::mat4x4 matRotateY = olc::GFX3D::Math::Mat_MakeRotationY(asset.fRotate[1]);
olc::GFX3D::mat4x4 matRotateZ = olc::GFX3D::Math::Mat_MakeRotationZ(asset.fRotate[2]);
olc::GFX3D::mat4x4 matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTranslate, matScale);
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateX);
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateY);
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateZ);
mapAssetTransform[asset.sDescription] = matTransform;
}
return true;
}
void cCarCrimeCity::SpawnPedestrian(int x, int y)
{
cCell* cell = pCity->Cell(x, y);
cAuto_Track *t = ((cCell_Road*)cell)->pSafePedestrianTrack;
if (t == nullptr) return;
cAuto_Body *a = new cAuto_Body();
a->fAutoLength = 0.05f;
a->pCurrentTrack = t;
a->pCurrentTrack->listAutos.push_back(a);
a->pTrackOriginNode = t->node[0];
a->UpdateAuto(0.0f);
listAutomata.push_back(a);
}
void cCarCrimeCity::SpawnVehicle(int x, int y)
{
cCell* cell = pCity->Cell(x, y);
cAuto_Track *t = ((cCell_Road*)cell)->pSafeCarTrack;
if (t == nullptr) return;
cAuto_Body *a = new cAuto_Body();
a->fAutoLength = 0.2f;
a->pCurrentTrack = t;
a->pCurrentTrack->listAutos.push_back(a);
a->pTrackOriginNode = t->node[0];
a->UpdateAuto(0.0f);
listAutomata.push_back(a);
}
void cCarCrimeCity::DoEditMode(float fElapsedTime)
{
// Get cell under mouse cursor
cCell* mcell = pCity->Cell(nMouseX, nMouseY);
bool bTempCellAdded = false;
// Left click and drag adds cells
if (mcell != nullptr && GetMouse(0).bHeld)
setSelectedCells.emplace(nMouseY * pCity->GetWidth() + nMouseX);
// Right click clears selection
if (GetMouse(1).bReleased)
setSelectedCells.clear();
if (setSelectedCells.empty())
{
// If nothing can be edited validly then just exit
if (mcell == nullptr)
return;
// else set is empty, so temporarily add current cell to it
setSelectedCells.emplace(nMouseY * pCity->GetWidth() + nMouseX);
bTempCellAdded = true;
}
// If the map changes, we will need to update
// the automata, and adjacency
bool bMapChanged = false;
// Press "G" to apply grass
if (GetKey(olc::Key::G).bPressed)
{
for (auto &c : setSelectedCells)
{
int x = c % pCity->GetWidth();
int y = c / pCity->GetWidth();
cCell* cell = pCity->Replace(x, y, new cCell_Plane(pCity, x, y, PLANE_GRASS));
cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform);
}
bMapChanged = true;
}
// Press "P" to apply Pavement
if (GetKey(olc::Key::P).bPressed)
{
for (auto &c : setSelectedCells)
{
int x = c % pCity->GetWidth();
int y = c / pCity->GetWidth();
cCell* cell = pCity->Replace(x, y, new cCell_Plane(pCity, x, y, PLANE_ASPHALT));
cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform);
}
bMapChanged = true;
}
// Press "W" to apply Water
if (GetKey(olc::Key::W).bPressed)
{
for (auto &c : setSelectedCells)
{
int x = c % pCity->GetWidth();
int y = c / pCity->GetWidth();
cCell* cell = pCity->Replace(x, y, new cCell_Water(pCity, x, y));
cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform);
}
bMapChanged = true;
}
// Press "R" to apply Roads
if (GetKey(olc::Key::Q).bPressed)
{
for (auto &c : setSelectedCells)
{
int x = c % pCity->GetWidth();
int y = c / pCity->GetWidth();
cCell* cell = pCity->Replace(x, y, new cCell_Building("Apartments_1", pCity, x, y));
cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform);
}
bMapChanged = true;
}
// Press "R" to apply Roads
if (GetKey(olc::Key::R).bPressed)
{
for (auto &c : setSelectedCells)
{
int x = c % pCity->GetWidth();
int y = c / pCity->GetWidth();
cCell* cell = pCity->Replace(x, y, new cCell_Road(pCity, x, y));
cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform);
}
bMapChanged = true;
}
if (GetKey(olc::Key::C).bPressed)
{
for (auto &c : setSelectedCells)
{
int x = c % pCity->GetWidth();
int y = c / pCity->GetWidth();
SpawnVehicle(x, y);
}
}
if (GetKey(olc::Key::V).bPressed)
{
for (auto &c : setSelectedCells)
{
int x = c % pCity->GetWidth();
int y = c / pCity->GetWidth();
SpawnPedestrian(x, y);
}
}
if (bMapChanged)
{
// The navigation nodes may have tracks attached to them, so get rid of them
// all. Below we will reconstruct all tracks because city has changed
pCity->RemoveAllTracks();
for (auto &a : listAutomata) delete a;
listAutomata.clear();
for (int x = 0; x < pCity->GetWidth(); x++)
{
for (int y = 0; y < pCity->GetHeight(); y++)
{
cCell *c = pCity->Cell(x, y);
// Update adjacency information, i.e. those cells whose
// state changes based on neighbouring cells
c->CalculateAdjacency();
}
}
}
// To facilitate "edit under cursor" we added a temporary cell
// which needs to be removed now
if (bTempCellAdded)
setSelectedCells.clear();
}
olc::vf2d cCarCrimeCity::GetMouseOnGround(const olc::vf2d &vMouseScreen)
{
olc::GFX3D::vec3d vLookTarget = olc::GFX3D::Math::Vec_Add(vEye, vLookDir);
olc::GFX3D::mat4x4 matProj = olc::GFX3D::Math::Mat_MakeProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f);
olc::GFX3D::mat4x4 matView = olc::GFX3D::Math::Mat_PointAt(vEye, vLookTarget, vUp);
olc::GFX3D::vec3d vecMouseDir = {
2.0f * ((vMouseScreen.x / (float)ScreenWidth()) - 0.5f) / matProj.m[0][0],
2.0f * ((vMouseScreen.y / (float)ScreenHeight()) - 0.5f) / matProj.m[1][1],
1.0f,
0.0f };
olc::GFX3D::vec3d vecMouseOrigin = { 0.0f, 0.0f, 0.0f };
vecMouseOrigin = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseOrigin);
vecMouseDir = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseDir);
vecMouseDir = olc::GFX3D::Math::Vec_Mul(vecMouseDir, 1000.0f);
vecMouseDir = olc::GFX3D::Math::Vec_Add(vecMouseOrigin, vecMouseDir);
// Perform line/plane intersection to determine mouse position in world space
olc::GFX3D::vec3d plane_p = { 0.0f, 0.0f, 0.0f };
olc::GFX3D::vec3d plane_n = { 0.0f, 0.0f, 1.0f };
float t = 0.0f;
olc::GFX3D::vec3d mouse3d = olc::GFX3D::Math::Vec_IntersectPlane(plane_p, plane_n, vecMouseOrigin, vecMouseDir, t);
return { mouse3d.x, mouse3d.y };
}
bool cCarCrimeCity::OnUserUpdate(float fElapsedTime)
{
fGlobalTime += fElapsedTime;
if (GetKey(olc::Key::TAB).bReleased) bEditMode = !bEditMode;
if (bEditMode) // Use mouse to pan and zoom, and place objects
{
vEye = vCamera;
olc::vf2d vMouseScreen = { (float)GetMouseX(), (float)GetMouseY() };
olc::vf2d vMouseOnGroundBeforeZoom = GetMouseOnGround(vMouseScreen);
vOffset = { 0,0 };
if (IsFocused())
{
if (GetMouse(2).bPressed) { vStartPan = vMouseOnGroundBeforeZoom; }
if (GetMouse(2).bHeld) { vOffset = (vStartPan - vMouseOnGroundBeforeZoom); };
if (GetMouseWheel() > 0)
{
vCamera.z *= 0.5f;
}
if (GetMouseWheel() < 0)
{
vCamera.z *= 1.5f;
}
}
vEye = vCamera;
olc::vf2d vMouseOnGroundAfterZoom = GetMouseOnGround(vMouseScreen);
vOffset += (vMouseOnGroundBeforeZoom - vMouseOnGroundAfterZoom);
vCamera.x += vOffset.x;
vCamera.y += vOffset.y;
vEye = vCamera;
// Get Integer versions of mouse coords in world space
nMouseX = (int)vMouseOnGroundAfterZoom.x;
nMouseY = (int)vMouseOnGroundAfterZoom.y;
DoEditMode(fElapsedTime);
}
else
{
// Not in edit mode, so camera follows player
if (GetKey(olc::Key::LEFT).bHeld) fAngle += -2.5f * fElapsedTime;
if (GetKey(olc::Key::RIGHT).bHeld) fAngle += 2.5f * fElapsedTime;
if (GetKey(olc::Key::UP).bHeld)
{
carvel = { cos(fAngle), sin(fAngle) };
carpos += carvel * 2.0f * fElapsedTime;
}
vCamera.x = carpos.x;
vCamera.y = carpos.y;
vEye = vCamera;
}
/*fAngle = 0.0f;
if (GetKey(olc::Key::LEFT).bHeld) fAngle = -0.8f;
if (GetKey(olc::Key::RIGHT).bHeld) fAngle = 0.8f;*/
//car.UpdateDrive(fElapsedTime, 1.0f, GetKey(olc::Key::UP).bHeld, GetKey(olc::Key::SPACE).bHeld, GetKey(olc::Key::DOWN).bHeld, fAngle);
//if (car.bSkidding && fmod(fGlobalTime, 0.05f) < 0.01f)
//{
// listDecalSmoke.push_front({ 0.1f, {car.vPosRear.x, car.vPosRear.y, -0.03f} });
//}
//// Update Decals
//for (auto &d : listDecalSmoke)
//{
// d.fLifetime += fElapsedTime;
//}
//listDecalSmoke.remove_if([](const sSmokeDecal &d) {return d.fLifetime > 2.0f; });
//if (!bEditMode)
//{
// vCamera.x = car.GetOrigin().x;
// vCamera.y = car.GetOrigin().y;
//}
//float fTargetHeight = -1.0f;
//int nCarX = vCamera.x;
//int nCarY = vCamera.y;
std::vector<cGameObjectQuad> vecNeighbours;
//// Check surrounding cells height
//for (int x = nCarX - 1; x < nCarX + 2; x++)
// for (int y = nCarY - 1; y < nCarY + 2; y++)
// {
// if (pCity->Cell(x,y) && pCity->Cell(x, y)->bBuilding)
// {
// cGameObjectQuad ob(1.0f, 1.0f);
// ob.pos = { (float)x + 0.5f, (float)y + 0.5f, 0.0f, 1.0f };
// ob.TransformModelToWorld();
// vecNeighbours.push_back(ob);
// fTargetHeight = -2.0f;
// }
// }
//goCar->pos.x = car.GetOrigin().x;
//goCar->pos.y = car.GetOrigin().y;
//goCar->fAngle = car.GetRotation();
//goCar->TransformModelToWorld();
//for (auto &ob : vecNeighbours)
//{
// if (goCar->StaticCollisionWith(ob, true))
// {
// goCar->TransformModelToWorld();
// car.vPosRear.x += goCar->pos.x - car.GetOrigin().x;
// car.vPosRear.y += goCar->pos.y - car.GetOrigin().y;
// car.vPosFront.x += goCar->pos.x - car.GetOrigin().x;
// car.vPosFront.y += goCar->pos.y - car.GetOrigin().y;
// car.fSpeed = 0.0f;
// }
//}
//if(!bEditMode)
// vCamera.z += (fTargetHeight - vCamera.z) * 10.0f * fElapsedTime;
//car.UpdateTow(fElapsedTime, { mouse3d.x, mouse3d.y });
//for (int v = 1; v<vecTraffic.size(); v++)
//{
// //vecTraffic[v].UpdateTow(fElapsedTime * 10.0f, vecTraffic[v - 1].vPosRear);
//}
// Calculate Visible ground plane dimensions
viewWorldTopLeft = GetMouseOnGround(olc::vf2d( 0.0f, 0.0f ));
viewWorldBottomRight = GetMouseOnGround(olc::vf2d((float)ScreenWidth(), (float)ScreenHeight()));
// Calculate visible world extents
int nStartX = std::max(0, (int)viewWorldTopLeft.x - 1);
int nEndX = std::min(pCity->GetWidth(), (int)viewWorldBottomRight.x + 1);
int nStartY = std::max(0, (int)viewWorldTopLeft.y - 1);
int nEndY = std::min(pCity->GetHeight(), (int)viewWorldBottomRight.y + 1);
// Only update automata for cells near player
int nAutomStartX = std::max(0, (int)viewWorldTopLeft.x - 3);
int nAutomEndX = std::min(pCity->GetWidth(), (int)viewWorldBottomRight.x + 3);
int nAutomStartY = std::max(0, (int)viewWorldTopLeft.y - 3);
int nAutomEndY = std::min(pCity->GetHeight(), (int)viewWorldBottomRight.y + 3);
int nLocalStartX = std::max(0, (int)vCamera.x - 3);
int nLocalEndX = std::min(pCity->GetWidth(), (int)vCamera.x + 3);
int nLocalStartY = std::max(0, (int)vCamera.y - 3);
int nLocalEndY = std::min(pCity->GetHeight(), (int)vCamera.y + 3);
// Update Cells
for (int x = nStartX; x < nEndX; x++)
{
for (int y = nStartY; y < nEndY; y++)
{
pCity->Cell(x, y)->Update(fElapsedTime);
}
}
// Update Automata
for (auto &a : listAutomata)
{
a->UpdateAuto(fElapsedTime);
// If automata is too far from camera, remove it
if ((a->vAutoPos - olc::vf2d(vCamera.x, vCamera.y)).mag() > 5.0f)
{
// Despawn automata
// 1) Disconnect it from track
a->pCurrentTrack->listAutos.remove(a);
// 2) Erase it from memory
delete a; a = nullptr;
}
}
// Remove dead automata, their pointer has been set to nullptr in the list
listAutomata.remove(nullptr);
// Maintain a certain level of automata in vicinty of player
if (listAutomata.size() < 20)
{
bool bSpawnOK = false;
int nSpawnAttempt = 20;
while (!bSpawnOK && nSpawnAttempt > 0)
{
// Find random cell on edge of vicinty, which is out of view of the player
float fRandomAngle = ((float)rand() / (float)RAND_MAX) * 2.0f * 3.14159f;
int nRandomCellX = vCamera.x + cos(fRandomAngle) * 3.0f;
int nRandomCellY = vCamera.y + sin(fRandomAngle) * 3.0f;
nSpawnAttempt--;
if (pCity->Cell(nRandomCellX, nRandomCellY) && pCity->Cell(nRandomCellX, nRandomCellY)->nCellType == CELL_ROAD)
{
bSpawnOK = true;
// Add random automata
if (rand() % 100 < 50)
{
// Spawn Pedestrian
SpawnPedestrian(nRandomCellX, nRandomCellY);
}
else
{
// Spawn Vehicle
SpawnVehicle(nRandomCellX, nRandomCellY);
// TODO: Get % chance of vehicle spawn from lua script
}
}
}
}
// Render Scene
Clear(olc::BLUE);
olc::GFX3D::ClearDepth();
// Create rendering pipeline
olc::GFX3D::PipeLine pipe;
pipe.SetProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f, 0.0f, 0.0f, (float)ScreenWidth(), (float)ScreenHeight());
olc::GFX3D::vec3d vLookTarget = olc::GFX3D::Math::Vec_Add(vEye, vLookDir);
pipe.SetCamera(vEye, vLookTarget, vUp);
// Add global illumination vector (sunlight)
olc::GFX3D::vec3d lightdir = { 1.0f, 1.0f, -1.0f };
pipe.SetLightSource(0, olc::GFX3D::LIGHT_AMBIENT, olc::Pixel(100,100,100), { 0,0,0 }, lightdir);
pipe.SetLightSource(1, olc::GFX3D::LIGHT_DIRECTIONAL, olc::WHITE, { 0,0,0 }, lightdir);
// RENDER CELL CONTENTS
// Render Base Objects (those without alpha components)
for (int x = nStartX; x < nEndX; x++)
{
//omp_set_dynamic(0);
//omp_set_num_threads(4);
//#pragma omp parallel for
for (int y = nStartY; y < nEndY; y++)
{
pCity->Cell(x, y)->DrawBase(this, pipe);
}
//#pragma omp barrier
}
// Render Upper Objects (those with alpha components)
for (int x = nStartX; x < nEndX; x++)
{
for (int y = nStartY; y < nEndY; y++)
{
pCity->Cell(x, y)->DrawAlpha(this, pipe);
}
}
if (bEditMode)
{
// Render additional per cell debug information
for (int x = nStartX; x < nEndX; x++)
{
for (int y = nStartY; y < nEndY; y++)
{
pCity->Cell(x, y)->DrawDebug(this, pipe);
}
}
}
if (bEditMode)
{
// Draw Selections
for (auto &c : setSelectedCells)
{
int x = c % pCity->GetWidth();
int y = c / pCity->GetWidth();
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)x, (float)y, 0.01f);
pipe.SetTransform(matWorld);
pipe.Render(mapAssetMeshes["UnitQuad"]->tris, olc::GFX3D::RENDER_WIRE);
}
}
// RENDER AUTOMATA
std::string test[] = { "Sedan", "SUV", "TruckCab", "TruckTrailer", "UTE", "Wagon" };
int i = 0;
for (auto &a : listAutomata)
{
olc::GFX3D::vec3d v = { a->vAutoPos.x, a->vAutoPos.y, 0.0f };
/*olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(a->vAutoPos.x, a->vAutoPos.y, 0.01f);
matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(mapAssetTransform[test[i]], matWorld);
pipe.SetTransform(matWorld);
pipe.SetTexture(mapAssetTextures[test[i]]);
pipe.Render(mapAssetMeshes[test[i]]->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_LIGHTS);
i++;
i = i % 6;*/
pipe.RenderCircleXZ(v, a->fAutoLength < 0.1f ? 0.05f : 0.07f, a->fAutoLength < 0.1f ? olc::MAGENTA : olc::YELLOW);
}
// Draw Player Vehicle
{
olc::GFX3D::mat4x4 matRotateZ = olc::GFX3D::Math::Mat_MakeRotationZ(fAngle);
olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation(carpos.x, carpos.y, 0.01f);
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(mapAssetTransform["Sedan"], matRotateZ);
matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(matWorld, matTranslate);
pipe.SetTransform(matWorld);
pipe.SetTexture(mapAssetTextures["Sedan"]);
pipe.Render(mapAssetMeshes[test[i]]->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_LIGHTS);
}
DrawString(10, 10, "Automata: " + std::to_string(listAutomata.size()), olc::WHITE);
if (GetKey(olc::Key::ESCAPE).bPressed)
return false;
return true;
}
bool cCarCrimeCity::OnUserDestroy()
{
return true;
}