177 lines
6.4 KiB
C++
177 lines
6.4 KiB
C++
#include "Game.hpp"
|
|
|
|
#include <numeric>
|
|
#include <SFML/System.hpp>
|
|
#include <SFML/Window/Keyboard.hpp>
|
|
#include <SFML/Window/Mouse.hpp>
|
|
|
|
#include "Engine/Misc/Logger.hpp"
|
|
#include "Engine/Utils/Perfs.hpp"
|
|
|
|
using std::make_shared;
|
|
using std::make_unique;
|
|
|
|
|
|
Game* Game::smInstance = nullptr;
|
|
|
|
|
|
/*
|
|
Game class is the conductor of every part of this "piece of scr*tch" game engine.
|
|
|
|
Only keyboard is implemented as input (but mouse alse for debug purpose).
|
|
|
|
SFX and music are planned later...
|
|
|
|
Rendering will be done with CPU intrinsics (SIMD) if available.
|
|
Both 2D and 3D rendering is mixed to display interface to the player.
|
|
The static and UI element are 2D. The world and some pieces of the UI are in 3D.
|
|
For simplicity (and somehow, style effect), the game is in wireframe like old arcade game.
|
|
> Game instance call UI Update() method for quick computation of state, but only
|
|
a call to the Draw() method will proceed to the pixels drawing.
|
|
THIS SHOULD NOT BE USED TO UPDATE THE WORLD STATE OR ANYTHING ELSE THAN UI!
|
|
|
|
World is the module responsible of the game elements states, FSM and start/end condition.
|
|
> The method Tick() is used to compute new elements states
|
|
|
|
More details to write here...
|
|
*/
|
|
Game::Game(std::shared_ptr<sf::RenderWindow> mainWnd, bool dbgFlag) : mbDbgModeEnabled(dbgFlag), mMainWindow(mainWnd) {
|
|
unsigned int wndWidth, wndHeight;
|
|
GetDefaultWindowSize(wndWidth, wndHeight);
|
|
|
|
mWorld3D = make_shared<Graphic3DRenderer>();
|
|
mCockpitUI = make_unique<CockpitUI>(wndWidth, (wndWidth * H_RATIO));
|
|
mWorldUI = make_unique<WorldUI>(wndWidth, std::floor((wndWidth * H_RATIO) * 0.45f), mWorld3D);
|
|
|
|
if (mbDbgModeEnabled) {
|
|
mDbgUI = make_unique<DebugUI>();
|
|
mPerfsTimer = make_unique<SysTimer>();
|
|
mPerfsTimer->Reset();
|
|
}
|
|
}
|
|
|
|
GAME_STATUS Game::Tick() {
|
|
static std::vector<double> msTicksMonitoring;
|
|
static double mPrevdelta = 0;
|
|
static double mLastCycleSleepDelta = 0;
|
|
static unsigned int mFrameCnt = 0;
|
|
double mDelta = mSysTimer.GetDeltaTimeUs();
|
|
|
|
// Debug performance computations
|
|
if (mDbgUI != nullptr && mPerfsTimer != nullptr) {
|
|
msTicksMonitoring.push_back(((1000000.f / TARGET_FPS) - mLastCycleSleepDelta) * TARGET_FPS / 1000000.f);
|
|
if (mPerfsTimer->GetDeltaTime() >= 1000) { // Every 1s
|
|
// This average CPU/cycle_time method can monitor when CPU is in overload state (>0%) or in underload one (<0%)
|
|
double cpuUsage = 200 * std::accumulate(msTicksMonitoring.begin(), msTicksMonitoring.end(), static_cast<double>(0)) / msTicksMonitoring.size() - 100;
|
|
|
|
mDbgUI->UpdateDebugData(cpuUsage, (((1000000.f / TARGET_FPS) - mLastCycleSleepDelta) / 1000), ((-mPrevdelta + mSysTimer.GetDeltaTimeUs()) / 1000), mFrameCnt, (PerfsGetVirtMem() / 1000), (PerfsGetPhysMem() / 1000));
|
|
|
|
mFrameCnt = 0;
|
|
msTicksMonitoring.clear();
|
|
mPerfsTimer->Reset();
|
|
}
|
|
}
|
|
|
|
// Update game stats and internal stuff
|
|
Update();
|
|
|
|
// Ugly way to wait for next frame... Maybe create a separate thread for rendering?
|
|
//while(time.GetDeltaTime() < (1000/TARGET_FPS)) {}
|
|
|
|
// Process to the final rendering if the window have the focus
|
|
if (mSysTimer.GetDeltaTime() >= (1000/TARGET_FPS) && mMainWindow->hasFocus()) {
|
|
Render();
|
|
mFrameCnt++;
|
|
mSysTimer.Reset();
|
|
mDelta = -mDelta;
|
|
}
|
|
mPrevdelta = mDelta;
|
|
|
|
// Sleep for remaining time to avoid useless CPU usage
|
|
mLastCycleSleepDelta = (1000000.f / TARGET_FPS) - (-mPrevdelta + mSysTimer.GetDeltaTimeUs());
|
|
if (mLastCycleSleepDelta > 0)
|
|
sf::sleep(sf::microseconds(mLastCycleSleepDelta));
|
|
else
|
|
mLastCycleSleepDelta = 0;
|
|
|
|
// Return the current process stat to the head process (TODO: convert to thread)
|
|
if (mMainWindow->isOpen())
|
|
return GAME_RUNNING;
|
|
else
|
|
return GAME_QUIT;
|
|
}
|
|
|
|
void Game::EventMouseMoved(int _x, int _y) {
|
|
if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
|
|
float dx = M3D_Deg2Rad(0.25f * static_cast<float>(_x - mPrevMousePos.x));
|
|
float dy = M3D_Deg2Rad(0.25f * static_cast<float>(_y - mPrevMousePos.y));
|
|
|
|
mWorld3D->UpdateCamera(CAMERA_MOVE_PITCH, dy);
|
|
mWorld3D->UpdateCamera(CAMERA_MOVE_YAW, dx);
|
|
}
|
|
|
|
mPrevMousePos.x = _x;
|
|
mPrevMousePos.y = _y;
|
|
}
|
|
|
|
void Game::EventWindowSizeChanged(unsigned int w, unsigned int h) {
|
|
mCockpitUI->SetRTSize(static_cast<float>(w), (w * H_RATIO));
|
|
mWorldUI->SetRTSize(static_cast<float>(w), std::floor((w * H_RATIO) * 0.45f), true);
|
|
mWorld3D->SetRTSize(static_cast<float>(w), std::floor((w * H_RATIO) * 0.45f));
|
|
}
|
|
|
|
void Game::Update() {
|
|
// Refresh keyboard inputs
|
|
KeyboardInputsCheck();
|
|
|
|
// Game logic calls should go here...
|
|
mWorldUI->Update();
|
|
mCockpitUI->Update();
|
|
}
|
|
|
|
void Game::KeyboardInputsCheck() {
|
|
const float deltaTimeS = mSysTimer.GetDeltaTime() / 1000;
|
|
|
|
if (mMainWindow->hasFocus()) {
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Z)) {
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::LShift))
|
|
mWorld3D->UpdateCamera(CAMERA_MOVE_WALK, 15.0f * deltaTimeS);
|
|
else
|
|
mWorld3D->UpdateCamera(CAMERA_MOVE_WALK, 10.0f * deltaTimeS);
|
|
}
|
|
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::LShift))
|
|
mWorld3D->UpdateCamera(CAMERA_MOVE_WALK, -15.0f * deltaTimeS);
|
|
else
|
|
mWorld3D->UpdateCamera(CAMERA_MOVE_WALK, -10.0f * deltaTimeS);
|
|
}
|
|
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
|
|
mWorld3D->UpdateCamera(CAMERA_MOVE_STRAFE, -10.0f * deltaTimeS);
|
|
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
|
|
mWorld3D->UpdateCamera(CAMERA_MOVE_STRAFE, 10.0f * deltaTimeS);
|
|
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
|
|
mWorld3D->UpdateCamera(CAMERA_MOVE_FLY, 5.0f * deltaTimeS);
|
|
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
|
|
mWorld3D->UpdateCamera(CAMERA_MOVE_FLY, -5.0f * deltaTimeS);
|
|
}
|
|
}
|
|
|
|
void Game::Render() {
|
|
// Clear the draw buffer
|
|
mMainWindow->clear(sf::Color::Black);
|
|
|
|
// Draw the arena view
|
|
mWorldUI->Draw(mMainWindow);
|
|
// Draw the UI above
|
|
mCockpitUI->Draw(mMainWindow);
|
|
// Draw the debug informations if enabled
|
|
if (mDbgUI != nullptr) mDbgUI->DrawDebugData(mMainWindow);
|
|
|
|
// Present the draw buffer
|
|
mMainWindow->display();
|
|
} |