Move through course, sprite and input

Signed-off-by: Daniel Henry <iamdanhenry@gmail.com>
This commit is contained in:
2025-09-05 11:00:14 -05:00
parent c545d800d2
commit b64f931010
342 changed files with 2258 additions and 33 deletions

View File

@@ -13,6 +13,15 @@ add_library(${LIGHT_YEARS_ENGINE_TARGET_NAME} STATIC
${CMAKE_CURRENT_SOURCE_DIR}/include/framework/Actor.h ${CMAKE_CURRENT_SOURCE_DIR}/include/framework/Actor.h
${CMAKE_CURRENT_SOURCE_DIR}/src/framework/Actor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/framework/Actor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/framework/Object.h
${CMAKE_CURRENT_SOURCE_DIR}/src/framework/Object.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/framework/AssetManager.h
${CMAKE_CURRENT_SOURCE_DIR}/src/framework/AssetManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/framework/MathUtility.h
${CMAKE_CURRENT_SOURCE_DIR}/src/framework/MathUtility.cpp
) )
target_include_directories(${LIGHT_YEARS_ENGINE_TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(${LIGHT_YEARS_ENGINE_TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

View File

@@ -1,20 +1,42 @@
#pragma once #pragma once
#include <SFML/Graphics.hpp>
#include "framework/Core.h"
#include "framework/Object.h"
#include "framework/AssetManager.h"
class World;
namespace ly { namespace ly {
class World;
class Actor { class Actor : public Object {
public: public:
Actor(World *owningWorld); Actor(World *owningWorld, const std::string& texturePath = "");
virtual ~Actor();
void BeginPlayInternal(); void BeginPlayInternal();
virtual void BeginPlay(); virtual void BeginPlay();
void TickInternal(float deltaTime);
virtual void Tick(float deltaTime); virtual void Tick(float deltaTime);
void SetTexture(const std::string& texturePath);
void Render(sf::RenderWindow& window);
void SetActorLocation(const sf::Vector2f &newLocation);
void SetActorRotation(const float newRotation);
void AddActorLocationOffset(const sf::Vector2f& offset);
void AddActorRotationOffset(const float offset);
sf::Vector2f GetActorLocation() const;
float GetActorRotation() const;
sf::Vector2f GetActorForwardDirection() const;
sf::Vector2f GetActorRightDirection() const;
private: private:
void CenterPivot();
World *mOwningWorld; World *mOwningWorld;
bool mHasBeganPlay; bool mHasBeganPlay;
sf::Sprite mSprite;
shared<sf::Texture> mTexture;
}; };
} // namespace ly } // namespace ly

View File

@@ -7,7 +7,7 @@ namespace ly {
class Application { class Application {
public: public:
Application(); Application(unsigned int windowWidth, unsigned int windowHeight, const std::string& title, sf::Uint32 style);
void Run(); void Run();
template <typename WorldType> template <typename WorldType>
@@ -24,6 +24,9 @@ private:
float mTargetFrameRate; float mTargetFrameRate;
sf::Clock mTickClock; sf::Clock mTickClock;
sf::Clock mCleanCycleClock;
float mCleanCycleInterval;
shared<World> currentWorld; shared<World> currentWorld;
}; };

View File

@@ -0,0 +1,22 @@
#pragma once
#include "framework/Core.h"
#include <SFML/Graphics.hpp>
namespace ly {
class AssetManager {
public:
static AssetManager& Get();
shared<sf::Texture> LoadTexture(const std::string& path);
void CleanCycle();
void SetAssetRootDirectory(const std::string& directory);
protected:
AssetManager();
private:
static unique<AssetManager> assetManager;
Dictionary<std::string, shared<sf::Texture>> mLoadedTextureMap;
std::string mRootDirectory;
};
}

View File

@@ -23,7 +23,7 @@ template<typename keyType, typename valueType, typename Pr = std::less<keyType>>
using Map = std::map<keyType, valueType, Pr>; using Map = std::map<keyType, valueType, Pr>;
template<typename keyType, typename valueType, typename Hasher = std::hash<keyType>> template<typename keyType, typename valueType, typename Hasher = std::hash<keyType>>
using Dictionary = std::map<keyType, valueType, Hasher>; using Dictionary = std::unordered_map<keyType, valueType, Hasher>;
// Logging Macro // Logging Macro
#define LOG(M, ...) printf(M "\n", ##__VA_ARGS__) #define LOG(M, ...) printf(M "\n", ##__VA_ARGS__)

View File

@@ -0,0 +1,29 @@
#pragma once
#include <SFML/Graphics.hpp>
namespace ly {
sf::Vector2f RotationToVector(float rotation);
float DegreesToRadians(float degrees);
float RadiansToDegrees(float radians);
template<typename T>
float GetVectorLength(const sf::Vector2<T>& vector) {
return std::sqrt(vector.x * vector.x + vector.y * vector.y);
}
template<typename T>
sf::Vector2<T>& ScaleVector(sf::Vector2<T>& vectorToScale, float scaleAmount) {
vectorToScale.x *= scaleAmount;
vectorToScale.y *= scaleAmount;
return vectorToScale;
}
template<typename T>
sf::Vector2<T>& Normalize(sf::Vector2<T> &vector) {
float vectorLength = GetVectorLength<T>(vector);
if (vectorLength == 0.f) return sf::Vector2<T>{};
ScaleVector(vector, 1.f/vectorLength);
return vector;
}
}

View File

@@ -0,0 +1,15 @@
#pragma once
namespace ly{
class Object {
public:
Object();
virtual ~Object();
void Destroy();
bool IsPendingDestroy() const { return mIsPendingDestroy; };
private:
bool mIsPendingDestroy;
};
}

View File

@@ -1,26 +1,25 @@
#pragma once #pragma once
#include "framework/Core.h" #include "framework/Core.h"
class Application; #include "framework/Actor.h"
class Actor;
namespace ly { namespace ly {
class World { class Application;
class World {
public: public:
World(Application *owningApp); World(Application *owningApp);
void BeginPlayInternal(); void BeginPlayInternal();
void TickInternal(float deltaTime); void TickInternal(float deltaTime);
void Render(sf::RenderWindow& window);
virtual ~World(); virtual ~World();
template <typename ActorType> template <typename ActorType>
weak<ActorType> SpawnActor() { weak<ActorType> SpawnActor();
shared<ActorType> newActor{new ActorType{this}};
mPendingActors.push_back(newActor);
return newActor;
}
private: private:
void BeginPlay(); void BeginPlay();
@@ -30,4 +29,14 @@ private:
List<shared<Actor>> mActors; List<shared<Actor>> mActors;
List<shared<Actor>> mPendingActors; List<shared<Actor>> mPendingActors;
}; };
template<typename ActorType>
weak<ActorType> World::SpawnActor()
{
shared<ActorType> newActor{ new ActorType(this)};
mPendingActors.push_back(newActor);
return newActor;
}
} // namespace ly } // namespace ly

View File

@@ -1,9 +1,16 @@
#include "framework/Actor.h" #include "framework/Actor.h"
#include "framework/Core.h" #include "framework/Core.h"
#include "framework/MathUtility.h"
namespace ly { namespace ly {
Actor::Actor(World *owningWorld) Actor::Actor(World *owningWorld, const std::string& texturePath)
: mOwningWorld{owningWorld}, mHasBeganPlay{false} {} : mOwningWorld{ owningWorld }, mHasBeganPlay{ false }, mSprite{}, mTexture{} {
SetTexture(texturePath);
}
Actor::~Actor()
{
}
void Actor::BeginPlayInternal() { void Actor::BeginPlayInternal() {
@@ -14,9 +21,76 @@ void Actor::BeginPlayInternal() {
} }
void Actor::BeginPlay() { void Actor::BeginPlay() {
LOG("Actor begin play"); }
void Actor::TickInternal(float deltaTime)
{
if (!IsPendingDestroy()) {
Tick(deltaTime);
}
} }
void Actor::Tick(float deltaTime) { void Actor::Tick(float deltaTime) {
LOG("Actor tick"); }
void Actor::SetTexture(const std::string& texturePath)
{
AssetManager& assetManager = AssetManager::Get();
mTexture = AssetManager::Get().LoadTexture(texturePath);
if (!mTexture) {
return;
}
mSprite.setTexture(*mTexture);
int textureWidth = mTexture->getSize().x;
int textureHeight = mTexture->getSize().y;
mSprite.setTextureRect(sf::IntRect(sf::Vector2i{}, sf::Vector2i{ textureWidth, textureHeight }));
CenterPivot();
}
void Actor::Render(sf::RenderWindow& window)
{
if (IsPendingDestroy()) {
return;
}
window.draw(mSprite);
}
void Actor::SetActorLocation(const sf::Vector2f& newLocation)
{
mSprite.setPosition(newLocation);
}
void Actor::SetActorRotation(const float newRotation)
{
mSprite.setRotation(newRotation);
}
void Actor::AddActorLocationOffset(const sf::Vector2f& offset)
{
sf::Vector2f location = GetActorLocation();
mSprite.setPosition(location + offset);
}
void Actor::AddActorRotationOffset(const float offset)
{
float rotation = GetActorRotation();
mSprite.setRotation(rotation + offset);
}
sf::Vector2f Actor::GetActorLocation() const
{
return mSprite.getPosition();
}
float Actor::GetActorRotation() const
{
return mSprite.getRotation();
}
sf::Vector2f Actor::GetActorForwardDirection() const
{
return RotationToVector(GetActorRotation());
}
sf::Vector2f Actor::GetActorRightDirection() const
{
return RotationToVector(GetActorRotation() + 90);
}
void Actor::CenterPivot()
{
sf::FloatRect bound = mSprite.getGlobalBounds();
mSprite.setOrigin(bound.width / 2.f, bound.height / 2.f);
} }
} // namespace ly } // namespace ly

View File

@@ -1,11 +1,13 @@
#include "framework/Application.h" #include "framework/Application.h"
#include "framework/Core.h" #include "framework/Core.h"
#include "framework/World.h" #include "framework/World.h"
#include "framework/AssetManager.h"
namespace ly { namespace ly {
Application::Application() Application::Application(unsigned int windowWidth, unsigned int windowHeight, const std::string& title, sf::Uint32 style)
: mWindow{sf::VideoMode(1440, 1024), "LightYears"}, mTargetFrameRate{60.0f}, : mWindow{sf::VideoMode(windowWidth, windowHeight), title, style}, mTargetFrameRate{60.0f},
mTickClock{}, currentWorld{nullptr} {} mTickClock{}, currentWorld{ nullptr }, mCleanCycleClock{}, mCleanCycleInterval{ 2.f } {
}
void Application::Run() { void Application::Run() {
mTickClock.restart(); mTickClock.restart();
@@ -33,6 +35,11 @@ void Application::TickInternal(float deltaTime) {
if (currentWorld) { if (currentWorld) {
currentWorld->TickInternal(deltaTime); currentWorld->TickInternal(deltaTime);
} }
if (mCleanCycleClock.getElapsedTime().asSeconds() >= mCleanCycleInterval) {
mCleanCycleClock.restart();
AssetManager::Get().CleanCycle();
}
} }
void Application::Tick(float deltaTime) {} void Application::Tick(float deltaTime) {}
@@ -46,10 +53,8 @@ void Application::RenderInternal() {
} }
void Application::Render() { void Application::Render() {
sf::RectangleShape rect{sf::Vector2f{100, 100}}; if (currentWorld) {
rect.setFillColor(sf::Color::Green); currentWorld->Render(mWindow);
rect.setOrigin(50, 50); }
rect.setPosition(mWindow.getSize().x / 2.f, mWindow.getSize().y / 2.f);
mWindow.draw(rect);
} }
} // namespace ly } // namespace ly

View File

@@ -0,0 +1,50 @@
#include "framework/AssetManager.h"
namespace ly {
unique<AssetManager> AssetManager::assetManager{ nullptr };
AssetManager& AssetManager::Get()
{
if (!assetManager) {
assetManager = std::move(unique<AssetManager>{new AssetManager});
}
return *assetManager;
}
shared<sf::Texture> AssetManager::LoadTexture(const std::string& path)
{
auto found = mLoadedTextureMap.find(path);
if (found != mLoadedTextureMap.end()) {
return found->second;
}
shared<sf::Texture> newTexture{ new sf::Texture };
if (newTexture->loadFromFile(mRootDirectory + path)) {
mLoadedTextureMap.insert({ path, newTexture });
return newTexture;
}
return shared<sf::Texture> {nullptr};
}
void AssetManager::CleanCycle()
{
for (auto iter = mLoadedTextureMap.begin(); iter != mLoadedTextureMap.end();) {
if (iter->second.unique()) {
LOG("Cleaning texture: %s", iter->first.c_str());
iter = mLoadedTextureMap.erase(iter);
}
else {
++iter;
}
}
}
void AssetManager::SetAssetRootDirectory(const std::string& directory)
{
mRootDirectory = directory;
}
AssetManager::AssetManager() : mRootDirectory{}
{
}
}

View File

@@ -0,0 +1,19 @@
#include "framework/MathUtility.h"
namespace ly {
const float PI = 3.1415926535;
sf::Vector2f RotationToVector(float rotation)
{
float radians = DegreesToRadians(rotation);
return sf::Vector2f(std::cos(radians), std::sin(radians));
}
float DegreesToRadians(float degrees)
{
return degrees * (PI / 180.f);
}
float RadiansToDegrees(float radians)
{
return radians * (180.f / PI);
}
}

View File

@@ -0,0 +1,18 @@
#include "framework/Object.h"
#include "framework/Core.h"
namespace ly {
Object::Object() : mIsPendingDestroy{ false } {
}
Object::~Object()
{
}
void Object::Destroy() {
mIsPendingDestroy = true;
}
}

View File

@@ -1,8 +1,9 @@
#include "framework/World.h" #include "framework/World.h"
#include "framework/Core.h" #include "framework/Core.h"
#include "framework/Actor.h"
namespace ly { namespace ly {
World::World(Application* owningApp) : mOwningApp{ owningApp }, mBeganPlay{ false } { World::World(Application* owningApp) : mOwningApp{ owningApp }, mBeganPlay{ false }, mActors{}, mPendingActors{} {
} }
@@ -19,18 +20,42 @@ namespace ly {
void World::TickInternal(float deltaTime) void World::TickInternal(float deltaTime)
{ {
for (shared<Actor> actor : mPendingActors) {
mActors.push_back(actor);
actor->BeginPlayInternal();
}
mPendingActors.clear();
for (auto iter = mActors.begin(); iter != mActors.end();) {
if (iter->get()->IsPendingDestroy()) {
iter = mActors.erase(iter);
}
else {
iter->get()->TickInternal(deltaTime);
++iter;
}
}
Tick(deltaTime); Tick(deltaTime);
}
void World::Render(sf::RenderWindow& window)
{
for (auto actor : mActors) {
actor->Render(window);
}
} }
void World::BeginPlay() void World::BeginPlay()
{ {
LOG("Began Play");
} }
void World::Tick(float deltaTime) void World::Tick(float deltaTime)
{ {
LOG("Ticking at frame rate: %f", 1.f / deltaTime);
} }
} }

View File

@@ -1,6 +1,12 @@
add_executable(${LIGHT_YEARS_GAME_TARGET_NAME} add_executable(${LIGHT_YEARS_GAME_TARGET_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/include/gameFramework/GameApplication.h ${CMAKE_CURRENT_SOURCE_DIR}/include/gameFramework/GameApplication.h
${CMAKE_CURRENT_SOURCE_DIR}/src/gameFramework/GameApplication.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/gameFramework/GameApplication.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/spaceship/Spaceship.h
${CMAKE_CURRENT_SOURCE_DIR}/src/spaceship/Spaceship.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/player/PlayerSpaceship.h
${CMAKE_CURRENT_SOURCE_DIR}/src/player/PlayerSpaceship.cpp
) )
target_include_directories(${LIGHT_YEARS_GAME_TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(${LIGHT_YEARS_GAME_TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
@@ -19,3 +25,19 @@ add_custom_command(
endfunction() endfunction()
CopyLibDirToTarget(${LIGHT_YEARS_ENGINE_TARGET_NAME} ${LIGHT_YEARS_GAME_TARGET_NAME}) CopyLibDirToTarget(${LIGHT_YEARS_ENGINE_TARGET_NAME} ${LIGHT_YEARS_GAME_TARGET_NAME})
set(RESOURCE_FOLDER_NAME "assets")
set(RESOURCE_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_FOLDER_NAME}")
add_custom_command(TARGET ${LIGHT_YEARS_GAME_TARGET_NAME}
POST_BUILD
COMMAND
${CMAKE_COMMAND} -E copy_directory
${RESOURCE_SRC_DIR}
$<TARGET_FILE_DIR:${LIGHT_YEARS_GAME_TARGET_NAME}>/${RESOURCE_FOLDER_NAME}
)
configure_file(
"config.h.in"
"${CMAKE_CURRENT_SOURCE_DIR}/include/config.h" ESCAPE_QUOTES
)

BIN
LightYearsGame/assets/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 784 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Some files were not shown because too many files have changed in this diff Show More