Finish lecture 82: Implement the World class

Signed-off-by: Daniel Henry <iamdanhenry@gmail.com>
This commit is contained in:
2025-09-02 08:15:18 -05:00
parent 9ca8cd1e25
commit 7d2cd86fd4
15 changed files with 296 additions and 9 deletions

View File

@@ -8,6 +8,20 @@ set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFf) set(CMAKE_CXX_EXTENSIONS OFf)
include(FetchContent)
set(SFML_LIB_NAME SFML)
FetchContent_Declare(
${SFML_LIB_NAME}
GIT_REPOSITORY https://github.com/SFML/SFML.git
GIT_TAG 2.6.0
GIT_SHALLOW FALSE
)
FetchContent_MakeAvailable(${SFML_LIB_NAME})
set(LIGHT_YEARS_ENGINE_TARGET_NAME LightYearsEngine)
set(LIGHT_YEARS_GAME_TARGET_NAME LightYearsGame) set(LIGHT_YEARS_GAME_TARGET_NAME LightYearsGame)
add_subdirectory(LightYears) add_subdirectory(LightYearsEngine)
add_subdirectory(LightYearsGame)

View File

@@ -1,3 +0,0 @@
add_executable(${LIGHT_YEARS_GAME_TARGET_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
)

View File

@@ -1,5 +0,0 @@
#include <iostream>
int main() {
std::cout << "Hello, world!" << std::endl;
}

View File

@@ -0,0 +1,36 @@
add_library(${LIGHT_YEARS_ENGINE_TARGET_NAME} STATIC
${CMAKE_CURRENT_SOURCE_DIR}/include/framework/Application.h
${CMAKE_CURRENT_SOURCE_DIR}/src/framework/Application.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/EntryPoint.h
${CMAKE_CURRENT_SOURCE_DIR}/src/EntryPoint.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/framework/Core.h
${CMAKE_CURRENT_SOURCE_DIR}/src/framework/Core.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/framework/World.h
${CMAKE_CURRENT_SOURCE_DIR}/src/framework/World.cpp
)
target_include_directories(${LIGHT_YEARS_ENGINE_TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(${LIGHT_YEARS_ENGINE_TARGET_NAME} PUBLIC sfml-graphics)
target_link_libraries(${LIGHT_YEARS_ENGINE_TARGET_NAME} PUBLIC sfml-window)
target_link_libraries(${LIGHT_YEARS_ENGINE_TARGET_NAME} PUBLIC sfml-system)
target_link_libraries(${LIGHT_YEARS_ENGINE_TARGET_NAME} PUBLIC sfml-audio)
function(CopyLibToTarget LIB_NAME TARGET_NAME)
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
COMMAND
${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${LIB_NAME}>
$<TARGET_FILE_DIR:${TARGET_NAME}>
)
endfunction()
CopyLibToTarget(sfml-graphics ${LIGHT_YEARS_ENGINE_TARGET_NAME})
CopyLibToTarget(sfml-window ${LIGHT_YEARS_ENGINE_TARGET_NAME})
CopyLibToTarget(sfml-system ${LIGHT_YEARS_ENGINE_TARGET_NAME})
CopyLibToTarget(sfml-audio ${LIGHT_YEARS_ENGINE_TARGET_NAME})

View File

@@ -0,0 +1,7 @@
#pragma once
namespace ly {
class Application;
}
extern ly::Application* GetApplication();

View File

@@ -0,0 +1,34 @@
#pragma once
#include <SFML/Graphics.hpp>
#include "framework/Core.h"
namespace ly {
class World;
class Application {
public:
Application();
void Run();
template<typename WorldType>
weak<World> LoadWorld() {
shared<WorldType> newWorld{ new WorldType{this} };
currentWorld = newWorld;
currentWorld->BeginPlayInternal();
return newWorld;
}
private:
void TickInternal(float deltaTime);
void RenderInternal();
virtual void Render();
virtual void Tick(float deltaTime);
sf::RenderWindow mWindow;
float mTargetFrameRate;
sf::Clock mTickClock;
shared<World> currentWorld;
};
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include <stdio.h>
#include <memory>
#include <map>
#include <vector>
#include <unordered_map>
namespace ly {
template<typename T>
using unique = std::unique_ptr<T>;
template<typename T>
using shared = std::shared_ptr<T>;
template<typename T>
using weak = std::weak_ptr<T>;
template<typename T>
using List = std::vector<T>;
template<typename keyType, typename valueType, typename Pr = std::less<keyType>>
using Map = std::map<keyType, valueType, Pr>;
template<typename keyType, typename valueType, typename Hasher = std::hash<keyType>>
using Dictionary = std::map<keyType, valueType, Hasher>;
// Logging Macro
#define LOG(M, ...) printf(M "\n", ##__VA_ARGS__)
}

View File

@@ -0,0 +1,21 @@
#pragma once
namespace ly {
class Application;
class World {
public:
World(Application *owningApp);
void BeginPlayInternal();
void TickInternal(float deltaTime);
virtual ~World();
private:
void BeginPlay();
void Tick(float deltaTime);
Application* mOwningApp;
bool mBeganPlay;
};
}

View File

@@ -0,0 +1,8 @@
#include "EntryPoint.h"
#include "framework/Application.h"
int main() {
ly::Application* app = GetApplication();
app->Run();
delete app;
}

View File

@@ -0,0 +1,65 @@
#include "framework/Application.h"
#include "framework/Core.h"
#include "framework/World.h"
namespace ly {
Application::Application():
mWindow{sf::VideoMode(1440,1024), "LightYears"},
mTargetFrameRate{60.0f},
mTickClock{},
currentWorld{nullptr}
{
}
void Application::Run()
{
mTickClock.restart();
float accumulatedTime = 0.0f;
float targetDeltaTime = 1.f / mTargetFrameRate;
while (mWindow.isOpen()) {
sf::Event windowEvent;
while (mWindow.pollEvent(windowEvent)) {
if (windowEvent.type == sf::Event::EventType::Closed) {
mWindow.close();
}
}
float frameDeltaTime = mTickClock.restart().asSeconds();
accumulatedTime += frameDeltaTime;
while (accumulatedTime > targetDeltaTime) {
accumulatedTime -= targetDeltaTime;
TickInternal(targetDeltaTime);
RenderInternal();
}
}
}
void Application::TickInternal(float deltaTime)
{
Tick(deltaTime);
if (currentWorld) {
currentWorld->TickInternal(deltaTime);
}
}
void Application::Tick(float deltaTime)
{
}
void Application::RenderInternal()
{
mWindow.clear();
Render();
mWindow.display();
}
void Application::Render()
{
sf::RectangleShape rect{ sf::Vector2f{100,100} };
rect.setFillColor(sf::Color::Green);
rect.setOrigin(50, 50);
rect.setPosition(mWindow.getSize().x / 2, mWindow.getSize().y / 2);
mWindow.draw(rect);
}
}

View File

View File

@@ -0,0 +1,36 @@
#include "framework/World.h"
#include "framework/Core.h"
namespace ly {
World::World(Application* owningApp) : mOwningApp{ owningApp }, mBeganPlay{ false } {
}
void World::BeginPlayInternal() {
if (!mBeganPlay) {
mBeganPlay = true;
BeginPlay();
}
}
World::~World()
{
}
void World::TickInternal(float deltaTime)
{
Tick(deltaTime);
}
void World::BeginPlay()
{
LOG("Began Play");
}
void World::Tick(float deltaTime)
{
LOG("Ticking at frame rate: %f", 1.f / deltaTime);
}
}

View File

@@ -0,0 +1,21 @@
add_executable(${LIGHT_YEARS_GAME_TARGET_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/include/gameFramework/GameApplication.h
${CMAKE_CURRENT_SOURCE_DIR}/src/gameFramework/GameApplication.cpp
)
target_include_directories(${LIGHT_YEARS_GAME_TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(${LIGHT_YEARS_GAME_TARGET_NAME} PUBLIC ${LIGHT_YEARS_ENGINE_TARGET_NAME})
function(CopyLibDirToTarget LIB_NAME TARGET_NAME)
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
COMMAND
${CMAKE_COMMAND} -E copy_directory
$<TARGET_FILE_DIR:${LIB_NAME}>
$<TARGET_FILE_DIR:${TARGET_NAME}>
)
endfunction()
CopyLibDirToTarget(${LIGHT_YEARS_ENGINE_TARGET_NAME} ${LIGHT_YEARS_GAME_TARGET_NAME})

View File

@@ -0,0 +1,10 @@
#pragma once
#include <framework/Application.h>
namespace ly {
class GameApplication : public Application {
public:
GameApplication();
};
}

View File

@@ -0,0 +1,13 @@
#include "gameFramework/GameApplication.h"
#include "framework/World.h"
ly::Application* GetApplication() {
return new ly::GameApplication{};
}
namespace ly {
GameApplication::GameApplication()
{
LoadWorld<World>();
}
}