Various Edits

This commit is contained in:
2025-04-01 18:57:01 -04:00
parent b10d1e30dc
commit f82157d240
25 changed files with 294 additions and 79 deletions

View File

@@ -20,8 +20,8 @@ set(CMAKE_CXX_STANDARD 23)
if (UNIX) if (UNIX)
# TODO: Enable ALL optimization flags for RELEASE builds. # TODO: Enable ALL optimization flags for RELEASE builds.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -floop-nest-optimize -funroll-loops") #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -floop-nest-optimize -funroll-loops")
endif() endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
@@ -39,7 +39,7 @@ CPMAddPackage(
CPMAddPackage( CPMAddPackage(
NAME jjx NAME jjx
URL https://git.redacted.cc/josh/jjx/archive/Release-1.zip URL https://git.redacted.cc/josh/jjx/archive/Release-1.1.zip
) )
CPMAddPackage( CPMAddPackage(

View File

@@ -6,7 +6,7 @@
/// @file AssetService.hpp /// @file AssetService.hpp
/// @desc Manages game asset data. /// @desc Manages game asset data.
/// @edit 1/28/2025 /// @edit 3/31/2025
/// @auth Josh O'Leary /// @auth Josh O'Leary
/// The AssetService is a class / static library that manages on-file game assets. /// The AssetService is a class / static library that manages on-file game assets.
@@ -21,9 +21,10 @@
#include <JGL/types/Texture.h> #include <JGL/types/Texture.h>
#include <JGL/types/Font.h> #include <JGL/types/Font.h>
#include <queue> #include <queue>
#include <Core/Singleton.hpp>
#include <Core/Macros.hpp>
namespace CaveGame::Client namespace CaveGame::Client {
{
using namespace JGL; using namespace JGL;
@@ -32,6 +33,7 @@ namespace CaveGame::Client
struct AssetRequest { struct AssetRequest {
std::string name;
std::filesystem::path path; std::filesystem::path path;
AssetType type; AssetType type;
}; };
@@ -62,9 +64,9 @@ namespace CaveGame::Client
//return fonts[fontName]; //return fonts[fontName];
} }
void EnqueueTexture(const std::filesystem::path &path); void EnqueueTexture(const std::string& name, const std::filesystem::path &path);
void EnqueueFont(const std::filesystem::path& path); void EnqueueFont(const std::string& name, const std::filesystem::path& path);
void EnqueueSound(const std::filesystem::path& path); void EnqueueSound(const std::string& name, const std::filesystem::path& path);
void LoadAllFromQueue(); void LoadAllFromQueue();
@@ -81,6 +83,9 @@ namespace CaveGame::Client
unsigned int TotalQueued() const { return total_queued; } unsigned int TotalQueued() const { return total_queued; }
unsigned int TotalLoaded() const { return total_loaded; } unsigned int TotalLoaded() const { return total_loaded; }
void ParseManifest();
void PreloadCertainAssets();
protected: protected:
/// @returns only the filename of the given path. /// @returns only the filename of the given path.

View File

@@ -0,0 +1,12 @@
#pragma once
#include <JUI/Widgets/Rect.hpp>
namespace CaveGame::Client
{
class PauseMenuWidget : public JUI::Rect {
};
}

View File

@@ -12,11 +12,48 @@
#pragma once #pragma once
#include <JUI/Widgets/Window.hpp> #include <JUI/Widgets/Window.hpp>
#include <JUI/Widgets/Collapsible.hpp>
#include <JUI/Widgets/ListLayout.hpp>
#include <Core/Singleton.hpp>
namespace CaveGame::Client
{ namespace CaveGame::Client {
class SettingsMenu : public JUI::Window
// TODO: Analyze behavior of singleton on an object that requires specific initialization, like this.
class SettingsMenu : public JUI::Window, public Singleton<SettingsMenu>
{ {
public:
SettingsMenu()
{
SetTitle("Settings");
auto* root_layout = new JUI::VerticalListLayout(this);
general_section = new JUI::Collapsible(root_layout);
general_section->Title("General");
auto* gen_layout = new JUI::VerticalListLayout(general_section);
sound_section = new JUI::Collapsible(root_layout);
sound_section->Title("Sound");
auto* snd_layout = new JUI::VerticalListLayout(sound_section);
graphics_section = new JUI::Collapsible(root_layout);
graphics_section->Title("Graphics");
auto* gfx_layout = new JUI::VerticalListLayout(graphics_section);
input_section = new JUI::Collapsible(root_layout);
input_section->Title("Input");
}
protected:
JUI::Collapsible* general_section;
JUI::Collapsible* sound_section;
JUI::Collapsible* graphics_section;
JUI::Collapsible* input_section;
private:
}; };
} }

View File

@@ -32,7 +32,7 @@ namespace CaveGame::Client
protected: protected:
float splash_timer = 1.5f; float splash_timer = 1.5f;
float load_percent = 0.f; float load_percent = 0.f;
JGL::Texture* splash = nullptr; std::shared_ptr<JGL::Texture> splash = nullptr;
std::array<JGL::RenderTarget*, 16> column_textures{}; std::array<JGL::RenderTarget*, 16> column_textures{};
int column_width = 0; int column_width = 0;

View File

@@ -63,8 +63,9 @@ namespace CaveGame::Client {
TextRect* tool_size_label; TextRect* tool_size_label;
TextButton* step_btn; TextButton* step_btn;
TextButton* step2_btn; TextButton* step2_btn;
TextButton* step3_btn;
bool enabled = false; bool enabled = false;
bool tile_sim_disabled; bool tile_sim_disabled = false;
private: private:
}; };
} }

View File

@@ -1,6 +1,8 @@
#include <Client/AssetService.hpp> #include <Client/AssetService.hpp>
#include <thread> #include <thread>
#include <JGL/types/Texture.h> #include <JGL/types/Texture.h>
#include <JJX/JSON.hpp>
using namespace std::chrono_literals; using namespace std::chrono_literals;
static CaveGame::Client::AssetService* singleton; static CaveGame::Client::AssetService* singleton;
@@ -9,18 +11,20 @@ CaveGame::Client::AssetService * CaveGame::Client::AssetService::Get() { return
CaveGame::Client::AssetService::AssetService() { CaveGame::Client::AssetService::AssetService() {
singleton = this; singleton = this;
ParseManifest();
} }
void CaveGame::Client::AssetService::TempLoadSimple() { void CaveGame::Client::AssetService::TempLoadSimple() {
player_sprite = new JGL::Texture("assets/textures/player.png", JGL::FilteringMode::NEAREST); //player_sprite = new JGL::Texture("assets/textures/player.png", JGL::FilteringMode::NEAREST);
explosion_sprite = new JGL::Texture("assets/textures/explosion.png", JGL::FilteringMode::NEAREST); //explosion_sprite = new JGL::Texture("assets/textures/explosion.png", JGL::FilteringMode::NEAREST);
title_img = new JGL::Texture("assets/textures/title_1.png"); //title_img = new JGL::Texture("assets/textures/title_1.png");
} }
void CaveGame::Client::AssetService::EnqueueDefaultAssetsFolder() { void CaveGame::Client::AssetService::EnqueueDefaultAssetsFolder() {
//EnqueueContents("assets"); //EnqueueContents("assets");
textures.emplace("player", new JGL::Texture("assets/textures/player.png")); //textures.emplace("player", new JGL::Texture("assets/textures/player.png"));
} }
@@ -35,27 +39,31 @@ std::string CaveGame::Client::AssetService::FilenameFromPathWithoutExtension(con
return base.substr(0, p); return base.substr(0, p);
} }
void CaveGame::Client::AssetService::EnqueueTexture(const std::filesystem::path &path) { void CaveGame::Client::AssetService::EnqueueTexture(const std::string& name, const std::filesystem::path &path) {
queue.push({path, AssetType::TEXTURE}); queue.push({name, path, AssetType::TEXTURE});
total_queued++; total_queued++;
} }
void CaveGame::Client::AssetService::EnqueueFont(const std::filesystem::path &path) { void CaveGame::Client::AssetService::EnqueueFont(const std::string& name, const std::filesystem::path &path) {
queue.push({path, AssetType::FONT}); queue.push({name, path, AssetType::FONT});
total_queued++; total_queued++;
} }
void CaveGame::Client::AssetService::EnqueueSound(const std::filesystem::path &path) { void CaveGame::Client::AssetService::EnqueueSound(const std::string& name, const std::filesystem::path &path) {
queue.push({path, AssetType::AUDIO}); queue.push({name, path, AssetType::AUDIO});
total_queued++; total_queued++;
} }
bool CaveGame::Client::AssetService::LoadAsset(const CaveGame::Client::AssetRequest &request) { bool CaveGame::Client::AssetService::LoadAsset(const CaveGame::Client::AssetRequest &request) {
last_asset_processed = request.path; last_asset_processed = request.path;
switch(request.type) { switch(request.type) {
case AssetType::TEXTURE: { case AssetType::TEXTURE: {
if (textures.contains(request.name)) // TODO: Note repeat request.
return true;
auto texture =std::make_shared<Texture>(request.path); auto texture =std::make_shared<Texture>(request.path);
textures[request.path] = texture; textures[request.name] = texture;
} }
default: { default: {
// TODO: We don't support this asset type yet!!! // TODO: We don't support this asset type yet!!!
@@ -109,3 +117,53 @@ void CaveGame::Client::AssetService::LoadAllFromQueue() {
} }
} }
} }
void CaveGame::Client::AssetService::ParseManifest() {
std::string contents = read_file("assets/data/manifest.json");
using namespace JJX;
auto [obj, errcode] = json::parse(contents);
json::object catalog = obj.as_object();
// TODO: in this case, calling obj.at("textures") results in a bad_alloc?
if (catalog.contains("textures")) {
json::array texlist = catalog.at("textures").as_array();
for (auto& texture_entry : texlist) {
std::string name = texture_entry[0].string.value();
std::string path = texture_entry[1].string.value();
EnqueueTexture(name, path);
}
}
if (catalog.contains("fonts")) {
for (auto &font_entry: catalog["fonts"].as_array()) {
std::string name = font_entry[0].string.value();
std::string path = font_entry[1].string.value();
EnqueueFont(name, path);
}
}
if (catalog.contains("sfx")) {
for (auto &sfx_entry: catalog["sfx"].as_array()) {
std::string name = sfx_entry[0].string.value();
std::string path = sfx_entry[1].string.value();
EnqueueSound(name, path);
}
}
if (catalog.contains("music")) {
for (auto &sfx_entry: catalog["music"].as_array()) {
std::string name = sfx_entry[0].string.value();
std::string path = sfx_entry[1].string.value();
EnqueueSound(name, path);
}
}
}
void CaveGame::Client::AssetService::PreloadCertainAssets() {
LoadAsset({"redacted", "assets/textures/redacted.png", AssetType::TEXTURE});
LoadAsset({"title", "assets/textures/title_1.png", AssetType::TEXTURE});
}

View File

@@ -116,13 +116,14 @@ namespace CaveGame::Client
Vector2 Camera2D::Position() const { return position; } Vector2 Camera2D::Position() const { return position; }
void Camera2D::MoveLeft(float rate) { void Camera2D::Move(const Vector2& dir)
position -= Vector2(move_speed * rate, 0); {
position += dir * move_speed;
last_free_move = 0;
} }
void Camera2D::Move(const Vector2& velocity) void Camera2D::MoveLeft(float rate) {
{ position -= Vector2(move_speed * rate, 0);
position += velocity * move_speed;
last_free_move = 0; last_free_move = 0;
} }

View File

@@ -133,7 +133,7 @@ void CaveGame::Client::Splash::Update(float elapsed)
void CaveGame::Client::Splash::Load() { void CaveGame::Client::Splash::Load() {
column_textures.fill(nullptr); column_textures.fill(nullptr);
splash = new JGL::Texture("assets/textures/redacted.png"); splash = AssetService::Get()->GetTexture("redacted"); //new JGL::Texture("assets/textures/redacted.png");
ComputeMatrixTextureCache(); ComputeMatrixTextureCache();
Scene::Load(); Scene::Load();
@@ -143,7 +143,8 @@ void CaveGame::Client::Splash::Load() {
void CaveGame::Client::Splash::Unload() { void CaveGame::Client::Splash::Unload() {
for (auto& r : column_textures) for (auto& r : column_textures)
delete r; delete r;
delete splash;
splash = nullptr;
column_textures.fill(nullptr); column_textures.fill(nullptr);
Scene::Unload(); Scene::Unload();

View File

@@ -44,7 +44,7 @@ CaveGame::Client::TileTool::TileTool(JUI::Widget *parent) : JUI::Window(parent)
brush_size_slider->Maximum(1.f); brush_size_slider->Maximum(1.f);
brush_size_slider->Minimum(0.01f); brush_size_slider->Minimum(0.01f);
brush_size_slider->Interval(0.001f); brush_size_slider->Interval(0.001f);
brush_size_slider->ValueChanged += [&, this] (float val) brush_size_slider->ValueChanged += [&, this] (float val) mutable
{ {
float newval = val * 50; float newval = val * 50;
tool_size_label->SetContent(std::format("Size: {}", Math::Round(newval, 1))); tool_size_label->SetContent(std::format("Size: {}", Math::Round(newval, 1)));
@@ -59,7 +59,7 @@ CaveGame::Client::TileTool::TileTool(JUI::Widget *parent) : JUI::Window(parent)
brush_percent_slider->Maximum(1.f); brush_percent_slider->Maximum(1.f);
brush_percent_slider->Minimum(0.f); brush_percent_slider->Minimum(0.f);
brush_percent_slider->Interval(0.001f); brush_percent_slider->Interval(0.001f);
brush_percent_slider->ValueChanged += [&, this, tool_percent_label] (float val) brush_percent_slider->ValueChanged += [&, this, tool_percent_label] (float val) mutable
{ {
float newval = val * 100.f; float newval = val * 100.f;
tool_percent_label->SetContent(std::format("Percent: {}%", Math::Floor(newval))); tool_percent_label->SetContent(std::format("Percent: {}%", Math::Floor(newval)));
@@ -71,11 +71,14 @@ CaveGame::Client::TileTool::TileTool(JUI::Widget *parent) : JUI::Window(parent)
auto* tile_sim_checkbox = new Checkbox(right_row_layout); auto* tile_sim_checkbox = new Checkbox(right_row_layout);
tile_sim_checkbox->Size({row_height, row_height, 0, 0}); tile_sim_checkbox->Size({row_height, row_height, 0, 0});
tile_sim_checkbox->OnReleaseEvent += [&, this] (Vector2 _, JUI::MouseButton _2, bool _3) { tile_sim_checkbox->OnClickEvent += [&, this] (Vector2 _, JUI::MouseButton _2) mutable {
tile_sim_disabled = !tile_sim_disabled; tile_sim_disabled = !tile_sim_disabled;
TileSimulationDisabledChanged.Invoke(tile_sim_disabled); TileSimulationDisabledChanged.Invoke(tile_sim_disabled);
// Set the visual state of the "step" buttonns
step_btn->SetEnabled(tile_sim_disabled); step_btn->SetEnabled(tile_sim_disabled);
step2_btn->SetEnabled(tile_sim_disabled); step2_btn->SetEnabled(tile_sim_disabled);
step3_btn->SetEnabled(tile_sim_disabled);
}; };
@@ -86,26 +89,35 @@ CaveGame::Client::TileTool::TileTool(JUI::Widget *parent) : JUI::Window(parent)
step_btn->BGColor(Colors::LightGray); step_btn->BGColor(Colors::LightGray);
step_btn->BaseBGColor(Colors::LightGray); step_btn->BaseBGColor(Colors::LightGray);
step_btn->Disable(); step_btn->Disable();
step_btn->OnClickEvent += [&, this] (auto a, auto b) { step_btn->OnClickEvent += [&, this] (auto a, auto b) mutable {
TileSimulationStep.Invoke(1); TileSimulationStep.Invoke(1);
}; };
step2_btn = new TextButton(right_row_layout); step2_btn = new TextButton(left_row_layout);
step2_btn->Size({100_percent, UDim(row_height, 0)}); step2_btn->Size({100_percent, UDim(row_height, 0)});
step2_btn->SetContent("Step 10"); step2_btn->SetContent("Step 10");
step2_btn->BGColor(Colors::LightGray); step2_btn->BGColor(Colors::LightGray);
step2_btn->BaseBGColor(Colors::LightGray); step2_btn->BaseBGColor(Colors::LightGray);
step2_btn->Disable(); step2_btn->Disable();
step2_btn->OnClickEvent += [&, this] (auto a, auto b) { step2_btn->OnClickEvent += [&, this] (auto a, auto b) mutable {
TileSimulationStep.Invoke(10); TileSimulationStep.Invoke(10);
}; };
step3_btn = new TextButton(left_row_layout);
step3_btn->Size({100_percent, UDim(row_height, 0)});
step3_btn->SetContent("Step 100");
step3_btn->BGColor(Colors::LightGray);
step3_btn->BaseBGColor(Colors::LightGray);
step3_btn->Disable();
step3_btn->OnClickEvent += [&, this] (auto a, auto b) mutable {
TileSimulationStep.Invoke(100);
};
BrushSizeChanged += [this] (float value) { BrushSizeChanged += [this] (float value) mutable {
brush_radius = value; brush_radius = value;
}; };
BrushPercentChanged += [this] (float value) { BrushPercentChanged += [this] (float value) mutable {
brush_density = value; brush_density = value;
}; };

View File

@@ -21,27 +21,33 @@
}, },
{ {
"mnemonic-id": "copper-bar", "mnemonic-id": "copper-bar",
"display-name": "Copper Bar" "display-name": "Copper Bar",
"sprite:" : "ingot"
}, },
{ {
"mnemonic-id": "iron-bar", "mnemonic-id": "iron-bar",
"display-name": "Iron Bar" "display-name": "Iron Bar",
"sprite:" : "ingot"
}, },
{ {
"mnemonic-id": "silver-bar", "mnemonic-id": "silver-bar",
"display-name": "Silver Bar" "display-name": "Silver Bar",
"sprite:" : "ingot"
}, },
{ {
"mnemonic-id": "tungsten-bar", "mnemonic-id": "tungsten-bar",
"display-name": "Tungsten Bar" "display-name": "Tungsten Bar",
"sprite:" : "ingot"
}, },
{ {
"mnemonic-id": "platinum-bar", "mnemonic-id": "platinum-bar",
"display-name": "Platinum Bar" "display-name": "Platinum Bar",
"sprite:" : "ingot.png"
}, },
{ {
"mnemonic-id": "gold-bar", "mnemonic-id": "gold-bar",
"display-name": "Gold Bar" "display-name": "Gold Bar",
"sprite:" : "ingot.png"
}, },
{ {
"mnemonic-id": "lead-bar", "mnemonic-id": "lead-bar",
@@ -84,5 +90,11 @@
"stack": 1, "stack": 1,
"tags": ["dagger", "blade", "melee", "metal", "iron", "rusty"] "tags": ["dagger", "blade", "melee", "metal", "iron", "rusty"]
},
{
"mnemonic-id": "smoke-n-dip"
},
{
"mnemonic-id": "blick-axe"
} }
] ]

View File

@@ -0,0 +1,13 @@
{
"textures": [
["ingot", "assets/textures/ingot.png"],
["player", "assets/textures/player.png"],
["bg", "assets/textures/bg.png"],
["explosion", "assets/textures/explosion.png"],
["redacted", "assets/textures/redacted.png"],
["title_1", "assets/textures/title_1.png"]
],
"music": [
]
}

View File

@@ -133,7 +133,7 @@
"forced-ticc-func": "sand-grav", "forced-ticc-func": "sand-grav",
"solid": true, "solid": true,
"color": [102, 118, 124], "color": [102, 118, 124],
"pallet": [[92, 102, 128], [89, 116, 123], [121, 95, 108]] "pallet": [[92, 102, 128], [82, 82, 82], [102, 102, 102], [132, 132, 132], [89, 116, 123], [121, 95, 108]]
}, },
{ {
"mnemonic-id" : "white-sand", "mnemonic-id" : "white-sand",

View File

@@ -65,7 +65,8 @@ namespace CaveGame::ClientApp {
/// This function performs rendering routines, once per refresh. /// This function performs rendering routines, once per refresh.
void Draw(); void Draw();
bool ReadyToClose() const { return wanna_die; } /// @return True when a flag is set that indicates the game is "preparing" to close. Certain procedures may still be taking place, such as saving and serialization.
bool ReadyToClose() const;
/// Returns the game's console GUI, which accepts commands and displays log messages. /// Returns the game's console GUI, which accepts commands and displays log messages.
Client::Console* Console(); Client::Console* Console();
@@ -85,14 +86,23 @@ namespace CaveGame::ClientApp {
public: public:
#pragma region Input Callbacks #pragma region Input Callbacks
/// Called by the window on each frame.
void OnRefresh(float elapsed) override; void OnRefresh(float elapsed) override;
/// Called by the window upon the user pressing a mouse button.
void OnMouseButtonDown(const ReWindow::MouseButtonDownEvent &ev) override; void OnMouseButtonDown(const ReWindow::MouseButtonDownEvent &ev) override;
/// Called by the window upon the user releasing a mouse button.
void OnMouseButtonUp(const ReWindow::MouseButtonUpEvent &ev) override; void OnMouseButtonUp(const ReWindow::MouseButtonUpEvent &ev) override;
/// Called by the window upon the user scrolling a mouse wheel.
void OnMouseWheel(const ReWindow::MouseWheelEvent &ev) override; void OnMouseWheel(const ReWindow::MouseWheelEvent &ev) override;
/// Called by the window upon the user releasing a keyboard key.
void OnKeyUp(const ReWindow::KeyUpEvent &ev) override; void OnKeyUp(const ReWindow::KeyUpEvent &ev) override;
/// Called by the window upon the user pressing a keyboard key.
void OnKeyDown(const ReWindow::KeyDownEvent& ev) override; void OnKeyDown(const ReWindow::KeyDownEvent& ev) override;
/// Called by the window upon the user moving their pointer device, currently just mice.
void OnMouseMove(const ReWindow::MouseMoveEvent &ev) override; void OnMouseMove(const ReWindow::MouseMoveEvent &ev) override;
/// Called by the window when it receives a request from the operating-system to resize.
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent &ev) override; bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent &ev) override;
/// Called by the window **before** it closes.
void OnClosing() override; void OnClosing() override;
#pragma endregion #pragma endregion
public: public:
@@ -107,7 +117,7 @@ namespace CaveGame::ClientApp {
/// Runs exactly one iteration of the game loop. Currently, this is one call to Update(), and then to Draw(). /// Runs exactly one iteration of the game loop. Currently, this is one call to Update(), and then to Draw().
/// @see Refresh(). /// @see Refresh().
void Step(); void Step();
/// Creates the in-game console menu.
void create_console_window(); void create_console_window();
void create_stats_window(); void create_stats_window();
void create_settings_window(); void create_settings_window();
@@ -118,9 +128,16 @@ namespace CaveGame::ClientApp {
/// Constructs the Splash screen, Main Menu screen, and In-game session. /// Constructs the Splash screen, Main Menu screen, and In-game session.
void CreateContexts(); void CreateContexts();
// TODO: Refactor this into irrelevance.
void InGameControls(float elapsed); void InGameControls(float elapsed);
void OnConsoleCommandInput(const std::string &command); void OnConsoleCommandInput(const std::string &command);
/// Toggles tile simulation if we are in-game.
bool ToggleTileSim(const CommandArgs& args);
/// Opens a singleplayer session.
/// @param info A structure containing information for joining a singleplayer world.
void OpenWorld(Client::SingleplayerSessionInfo info);
/// Logs help information to the console. Called when the user runs the 'help' command. /// Logs help information to the console. Called when the user runs the 'help' command.
bool HelpCommand(const CommandArgs& args); bool HelpCommand(const CommandArgs& args);
@@ -128,8 +145,11 @@ namespace CaveGame::ClientApp {
bool ListCommand(const CommandArgs& args); bool ListCommand(const CommandArgs& args);
bool TileListCmd(const CommandArgs& args); bool TileListCmd(const CommandArgs& args);
bool ItemListCmd(const CommandArgs& args); bool ItemListCmd(const CommandArgs& args);
/// Toggles tile simulation if we are
bool ToggleTileSim(const CommandArgs& args);
bool NoclipCmd(const CommandArgs &args);
bool FpsLimitCmd(const CommandArgs &args);
/// This table defines the supported console commands, their aliases, and the callback lambda. /// This table defines the supported console commands, their aliases, and the callback lambda.
#pragma region Commands #pragma region Commands
@@ -252,10 +272,6 @@ namespace CaveGame::ClientApp {
float our_avg = 0.f; float our_avg = 0.f;
float max_fps = 60.f; float max_fps = 60.f;
void OpenWorld(Client::SingleplayerSessionInfo info);
bool NoclipCmd(const CommandArgs &args);
bool FpsLimitCmd(const CommandArgs &args);
}; };
} }

View File

@@ -23,6 +23,8 @@ namespace CaveGame::ClientApp {
{ {
Logs::Info("Parsing Tile Data."); Logs::Info("Parsing Tile Data.");
CaveGame::Core::LoadTileMetadata(); CaveGame::Core::LoadTileMetadata();
Logs::Info("Parsing Item Data.");
CaveGame::Core::LoadItemMetadata();
Logs::Info("Creating game window."); Logs::Info("Creating game window.");
CreateContexts(); CreateContexts();
@@ -116,17 +118,21 @@ namespace CaveGame::ClientApp {
this->SetResizable(true); this->SetResizable(true);
this->SetVsyncEnabled(false); this->SetVsyncEnabled(false);
this->assets.PreloadCertainAssets();
this->assets.ParseManifest();
// TODO: Replace w/ constructor?
this->assets.TempLoadSimple(); this->assets.TempLoadSimple();
this->assets.EnqueueDefaultAssetsFolder(); this->assets.EnqueueDefaultAssetsFolder();
//for (int i = 0; i < 10; i++) //for (int i = 0; i < 10; i++)
//{ //{
assets.EnqueueTexture("assets/textures/redacted.png"); //assets.EnqueueTexture("assets/textures/redacted.png");
assets.EnqueueTexture("assets/textures/bg.png"); //assets.EnqueueTexture("assets/textures/bg.png");
assets.EnqueueTexture("assets/textures/player.png"); //assets.EnqueueTexture("assets/textures/player.png");
assets.EnqueueTexture("assets/textures/explosion.png"); //assets.EnqueueTexture("assets/textures/explosion.png");
assets.EnqueueTexture("assets/textures/title_1.png"); //assets.EnqueueTexture("assets/textures/title_1.png");
assets.EnqueueTexture("assets/textures/ash_wip_potions.png"); //assets.EnqueueTexture("assets/textures/ash_wip_potions.png");
//} //}
@@ -356,9 +362,15 @@ namespace CaveGame::ClientApp {
} }
if (ev.key == Keys::Escape) { if (ev.key == Keys::Escape) {
GameSession()->SaveAndExit(); // TODO: "Pause menu"
if (Console()->IsOpen())
Console()->SetOpen(false);
//GameSession()->SaveAndExit();
// TODO: GameContext needs mechanism to **inform** the higher-level object that we are done. // TODO: GameContext needs mechanism to **inform** the higher-level object that we are done.
ChangeScene(menu_ctx); //ChangeScene(menu_ctx);
} }
} }
@@ -626,6 +638,8 @@ namespace CaveGame::ClientApp {
return true; return true;
} }
bool CaveGameWindow::ReadyToClose() const { return wanna_die; }
} }

View File

@@ -38,6 +38,7 @@ namespace CaveGame::Core {
virtual void Draw() = 0; virtual void Draw() = 0;
virtual void Update(float elapsed) = 0; virtual void Update(float elapsed) = 0;
virtual void PhysicsUpdate(float elapsed) {}
Vector2 Position() const; Vector2 Position() const;

View File

@@ -31,7 +31,7 @@ namespace CaveGame::Core
void Accelerate(const Vector2& vector); void Accelerate(const Vector2& vector);
virtual void PhysicsUpdate(float elapsed); void PhysicsUpdate(float elapsed) override;
// TODO: Mechanism for figuring out if you're already stuck inside of tiles: i.e. sand // TODO: Mechanism for figuring out if you're already stuck inside of tiles: i.e. sand
void CollisionTest(ITileMap* map, float elapsed) override; void CollisionTest(ITileMap* map, float elapsed) override;

View File

@@ -26,16 +26,17 @@ namespace CaveGame::Core {
void Jump(float elapsed) { void Jump(float elapsed) {
// TODO: Make it so the player falls **slightly** slower // TODO: Make it so the player falls **slightly** slower
Vector2 current_velocity = this->Velocity(); Vector2 current_velocity = this->Velocity();
float horiz = 0; float horiz = 0;
if (current_velocity.x > 10.f) if (current_velocity.x > 10.f)
horiz = Math::Clamp(current_velocity.x, 10.f, 300.f); horiz = Math::Clamp(current_velocity.x, 10.f, 300.f);
if (current_velocity.x < -10.f) if (current_velocity.x < -10.f)
horiz = Math::Clamp(current_velocity.x, -300.f, 10.f); horiz = Math::Clamp(current_velocity.x, -300.f, 10.f);
if (on_ground) { if (on_ground) {
Vector2 projection = Vector2(horiz, -16000*elapsed); Vector2 projection = Vector2(horiz*elapsed, -16000*elapsed);
Accelerate(projection); Accelerate(projection);
on_ground = false; on_ground = false;

View File

@@ -28,6 +28,7 @@ namespace CaveGame::Core {
constexpr static unsigned int RandomTileTickCoefficient = 128; constexpr static unsigned int RandomTileTickCoefficient = 128;
constexpr static float PeriodicAutosaveIntervalSeconds = 30.f; constexpr static float PeriodicAutosaveIntervalSeconds = 30.f;
constexpr static float PhysicsTickrate = 100.f; // Desired physics Ticks per second.
World() = default; World() = default;
~World() = default; ~World() = default;
@@ -184,6 +185,7 @@ namespace CaveGame::Core {
ConcurrentQueue<Core::Chunk*> ServedChunks; ConcurrentQueue<Core::Chunk*> ServedChunks;
float tile_ticc_counter; float tile_ticc_counter;
float physics_ticc = 0;
// Ticcs per second. // Ticcs per second.
float tile_ticc_frequency = 24.f; float tile_ticc_frequency = 24.f;

View File

@@ -3,6 +3,7 @@
#include <filesystem> #include <filesystem>
#include <JJX/JSON.hpp> #include <JJX/JSON.hpp>
#include <Core/JsonConversions.hpp> #include <Core/JsonConversions.hpp>
#include "Core/Loggers.hpp"
namespace CaveGame::Core namespace CaveGame::Core
{ {
@@ -28,13 +29,15 @@ namespace CaveGame::Core
if (entry_obj.contains("tags")) if (entry_obj.contains("tags"))
item.tags = JsonConversions::parse_string_list(entry_obj["tags"]); item.tags = JsonConversions::parse_string_list(entry_obj["tags"]);
// TODO: Support multiple overlaid "Sprites" with assigned colors.
// TODO: Support animated sprites.
std::string sprite_name;
Items().Register(item); Items().Register(item);
} }
for (auto [name, item] : Items().GetItemMap()) {
std::cout << name << std::endl;
}
return true; return true;
} }
@@ -45,6 +48,9 @@ namespace CaveGame::Core
} }
void ItemRegistry::Register(const Item& data) { void ItemRegistry::Register(const Item& data) {
Logs::Info(std::format("\tRegister Item: id:{} display_name:{} stack:{} value:{}", data.mnemonic, data.display_name, data.max_stack, data.value));
registered_items.emplace(data.mnemonic, data); registered_items.emplace(data.mnemonic, data);
} }

View File

@@ -35,7 +35,7 @@ namespace CaveGame::Core
airtime = 0; airtime = 0;
// TODO: Sophisticated mechanism to maintain locked-timestep, multiple-iteration physics steps. // TODO: Sophisticated mechanism to maintain locked-timestep, multiple-iteration physics steps.
PhysicsUpdate(elapsed); //PhysicsUpdate(elapsed);
} }
@@ -144,7 +144,7 @@ namespace CaveGame::Core
if (normal.y == 1) { if (normal.y == 1) {
velocity.y = -velocity.y*0.5f; velocity.y = -velocity.y*0.5f;
std::cout << "Touched your head" << std::endl; //std::cout << "Touched your head" << std::endl;
} }
if (normal.x == -1) if (normal.x == -1)

View File

@@ -103,7 +103,7 @@ namespace CaveGame::Core {
void SandGravTiccFunc(const Tile &data, ITileMap *world, int x, int y) { void SandGravTiccFunc(const Tile &data, ITileMap *world, int x, int y) {
static TileID air = Tiles()["air"].numeric_id; static TileID air = Tiles()["air"].numeric_id;
static TileID water = Tiles()["water"].numeric_id; static TileID water = Tiles()["water"].numeric_id;
static TileID sand = data.numeric_id; TileID sand = data.numeric_id;
TileID below = world->GetTile(x, y + 1); TileID below = world->GetTile(x, y + 1);
if (below == air || below == water) { if (below == air || below == water) {

View File

@@ -33,7 +33,7 @@ namespace CaveGame::Core
void TileRegistry::Register(TileID ID, const Tile& data) void TileRegistry::Register(TileID ID, const Tile& data)
{ {
Logs::Info(std::format("\tid:{} mnemonic:{} display-name:{}", data.numeric_id, data.mnemonic_id, data.display_name)); Logs::Info(std::format("\tRegister Tile:: id:{} mnemonic:{} display-name:{}", data.numeric_id, data.mnemonic_id, data.display_name));
registered_tiles[ID] = data; registered_tiles[ID] = data;
@@ -91,6 +91,7 @@ namespace CaveGame::Core
bool LoadTileMetadata(const std::filesystem::path &path) { bool LoadTileMetadata(const std::filesystem::path &path) {
// TODO: Move to it's own thing.
ticc_funcs.insert({"sand-grav", SandGravTiccFunc}); ticc_funcs.insert({"sand-grav", SandGravTiccFunc});
ticc_funcs.insert({"liquid-settle", LiquidSettleTiccFunc}); ticc_funcs.insert({"liquid-settle", LiquidSettleTiccFunc});
ticc_funcs.insert({"grass-random", GrassRandomTiccFunc}); ticc_funcs.insert({"grass-random", GrassRandomTiccFunc});

View File

@@ -56,10 +56,34 @@ namespace CaveGame::Core {
if (simulate_tiles) if (simulate_tiles)
SimulateTiles(elapsed); SimulateTiles(elapsed);
physics_ticc+= elapsed;
static float PhysicsTickrateReciprocal = 1.f / PhysicsTickrate;
bool do_physics_tick_this_frame = false;
int physics_accumulator = 0;
// Fixed timestep physics within variable timestep gameloop.
while (physics_ticc > PhysicsTickrateReciprocal) {
do_physics_tick_this_frame = true;
physics_accumulator++;
physics_ticc -= PhysicsTickrateReciprocal;
}
// Max iterations per frame.
if (physics_accumulator > 10)
physics_accumulator = 10;
for (auto* entity : entities) { for (auto* entity : entities) {
entity->Update(elapsed); entity->Update(elapsed);
entity->CollisionTest(this, elapsed);
if (physics_accumulator > 0) {
for (int iters = 0; iters < physics_accumulator; iters++) {
entity->CollisionTest(this, PhysicsTickrateReciprocal);
entity->PhysicsUpdate(PhysicsTickrateReciprocal);
}
}
} }
} }

View File

@@ -6,11 +6,9 @@
#include "Sockets/UdpServer.hpp" #include "Sockets/UdpServer.hpp"
namespace CaveGame::Server namespace CaveGame::Server {
{
struct ServerInfoPacket struct ServerInfoPacket {
{
}; };