Working on tileset-metadata editing.
This commit is contained in:
@@ -252,6 +252,8 @@ public:
|
||||
|
||||
void DrawLevel(const Level* level) const;
|
||||
|
||||
bool IsMouseGridCellInBounds();
|
||||
|
||||
void Draw();
|
||||
|
||||
// TODO: Closing the app nominally doesn't work on Linux.
|
||||
|
@@ -25,6 +25,7 @@ struct Tile
|
||||
std::string name;
|
||||
Quad quad;
|
||||
json::value metadata;
|
||||
bool collides;
|
||||
};
|
||||
|
||||
/// TODO: Only generate tile entry for tiles that are used in the level, or have been assigned custom metadata.
|
||||
@@ -131,4 +132,18 @@ protected:
|
||||
|
||||
/// Fill the tile-id lookup table with their respective partial-sprite bounding boxes.
|
||||
void ComputeQuads();
|
||||
|
||||
void FillTiles() {
|
||||
// Generate some tiles
|
||||
tiles.reserve(rows*cols);
|
||||
for (int i = 0 ; i < this->rows*this->cols; i++)
|
||||
{
|
||||
Tile tile;
|
||||
tile.id = i;
|
||||
tile.quad = quads[i];
|
||||
tile.name = std::format("tile_{}", i);
|
||||
tile.metadata = json::value();
|
||||
tiles.emplace(tiles.begin() + i, tile);
|
||||
}
|
||||
}
|
||||
};
|
@@ -221,8 +221,6 @@ void EditorApp::LoadLevel(const std::filesystem::path& level_meta_path)
|
||||
for (auto layer : loaded_level->layers)
|
||||
layer->Load();
|
||||
|
||||
layer_view->UpdateComponents(loaded_level);
|
||||
|
||||
data_ready = true;
|
||||
}
|
||||
|
||||
@@ -443,6 +441,11 @@ bool EditorApp::Open()
|
||||
|
||||
layer_view->UpdateComponents(loaded_level);
|
||||
|
||||
|
||||
for (auto tile : loaded_tileset->tiles) {
|
||||
std::cout << tile.id << ", " << tile.name << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -763,6 +766,18 @@ void EditorApp::DrawLevel(const Level* level) const
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorApp::IsMouseGridCellInBounds() {
|
||||
Vector2i cell = GetGridCellFromMouse();
|
||||
|
||||
if (cell.x < 0) return false;
|
||||
if (cell.y < 0) return false;
|
||||
|
||||
if (cell.x >= loaded_level->rows) return false;
|
||||
if (cell.y >= loaded_level->cols) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditorApp::Draw()
|
||||
{
|
||||
glClearColor(bg_color.RN(), bg_color.GN(), bg_color.BN(), 1);
|
||||
@@ -788,6 +803,28 @@ void EditorApp::Draw()
|
||||
|
||||
DrawCellPointerOutline();
|
||||
|
||||
Tile selected_tile = loaded_tileset->tiles[selected_quad];
|
||||
J2D::DrawString(Colors::White, std::format("Selected Tile: {}", selected_tile.name), 16, 48, 16);
|
||||
|
||||
Vector2i cell = GetGridCellFromMouse();
|
||||
|
||||
int hovered_tile_id = GetTile(cell);
|
||||
|
||||
if (hovered_tile_id > 0) {
|
||||
Tile hovered_tile = loaded_tileset->tiles[hovered_tile_id];
|
||||
J2D::DrawString(Colors::White, std::format("Hovered Tile: {}", hovered_tile.name), 16, 64, 16);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
auto maus = GetMouseCoordinates();
|
||||
@@ -799,8 +836,6 @@ void EditorApp::Draw()
|
||||
J2D::DrawPoint(Colors::White, bruhbruh, 4);
|
||||
J2D::End();
|
||||
|
||||
|
||||
|
||||
scene->Draw();
|
||||
}
|
||||
|
||||
|
@@ -6,6 +6,9 @@ Tileset::Tileset():
|
||||
tile_count(0), tiles_per_row(0)
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
|
||||
Tileset::Tileset(const std::string& name, const std::filesystem::path& texture_path, int tex_width, int tex_height, int tile_width, int tile_height,
|
||||
int tile_spacing)
|
||||
{
|
||||
@@ -29,27 +32,18 @@ Tileset::Tileset(const std::string& name, const std::filesystem::path& texture_p
|
||||
|
||||
|
||||
ComputeQuads();
|
||||
|
||||
|
||||
// Generate some tiles
|
||||
for (int i = 0 ; i < this->rows*this->cols; i++)
|
||||
{
|
||||
Tile tile;
|
||||
tile.id = i;
|
||||
tile.quad = quads[i];
|
||||
tile.name = std::format("tile_{}", i);
|
||||
tile.metadata = json::value();
|
||||
tiles.push_back(tile);
|
||||
}
|
||||
FillTiles();
|
||||
}
|
||||
|
||||
Tileset::Tileset(const json::value& json)
|
||||
{
|
||||
|
||||
Deserialize(json);
|
||||
}
|
||||
|
||||
Tileset::Tileset(const std::filesystem::path& filePath)
|
||||
{
|
||||
|
||||
auto [json, err] = json::parse(read_file_contents(filePath));
|
||||
Deserialize(json);
|
||||
}
|
||||
@@ -66,20 +60,27 @@ void Tileset::Deserialize(const json::value& json)
|
||||
this->tex_width = (int)json["texture-width"].number.value();
|
||||
this->tex_height = (int)json["texture-height"].number.value();
|
||||
|
||||
this->rows = J3ML::Math::Floor(this->tex_width / this->tile_width);
|
||||
this->cols = J3ML::Math::Floor(this->tex_height / this->tile_height);
|
||||
|
||||
ComputeQuads();
|
||||
FillTiles();
|
||||
|
||||
|
||||
if (json.as_object().contains("tiles"))
|
||||
{
|
||||
auto tilemeta = json["tiles"].as_array();
|
||||
for (json::value& v : tilemeta)
|
||||
{
|
||||
// this->tiles.push_back(v);
|
||||
int id = v["id"].number.value();
|
||||
tiles[id].name = v["name"].as_string();
|
||||
if (v.contains("collides"))
|
||||
tiles[id].collides = v["collides"].boolean.value_or(true);
|
||||
|
||||
// this->tiles.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this->rows = J3ML::Math::Floor(this->tex_width / this->tile_width);
|
||||
this->cols = J3ML::Math::Floor(this->tex_height / this->tile_height);
|
||||
ComputeQuads();
|
||||
|
||||
}
|
||||
|
||||
json::value Tileset::Serialize() const
|
||||
@@ -121,6 +122,7 @@ json::value Tileset::Serialize() const
|
||||
tile_json["name"] = tile.name;
|
||||
tile_json["id"] = (float)tile.id;
|
||||
tile_json["metadata"] = tile.metadata;
|
||||
tile_json["collides"] = json::boolean(tile.collides);
|
||||
json::array quad;
|
||||
quad.push_back((float)tile.quad.x);
|
||||
quad.push_back((float)tile.quad.y);
|
||||
|
139
testgame.cpp
139
testgame.cpp
@@ -8,6 +8,7 @@
|
||||
#include <JUI/Widgets/Window.hpp>
|
||||
#include <SimpleAABBSolver.hpp>
|
||||
|
||||
#include "App/EditorCamera.hpp"
|
||||
#include "JUI/Widgets/ListLayout.hpp"
|
||||
#include "JUI/Widgets/Slider.hpp"
|
||||
|
||||
@@ -19,6 +20,7 @@ float acceleration = 1200;
|
||||
|
||||
JGL::Texture* player_tex;
|
||||
|
||||
// Implemented in next version of JUI.
|
||||
class LabeledSlider : public JUI::Slider, public JUI::TextBase {
|
||||
public:
|
||||
LabeledSlider() : Slider(), TextBase() {
|
||||
@@ -51,81 +53,83 @@ protected:
|
||||
private:
|
||||
};
|
||||
|
||||
class GameEntity
|
||||
{
|
||||
public:
|
||||
|
||||
GameEntity(const Vector2& spawn_pos) {
|
||||
pos = spawn_pos;
|
||||
next_pos = spawn_pos;
|
||||
}
|
||||
class GameEntity
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void Update(float elapsed) = 0;
|
||||
GameEntity(const Vector2& spawn_pos) {
|
||||
pos = spawn_pos;
|
||||
next_pos = spawn_pos;
|
||||
}
|
||||
|
||||
virtual void Draw() = 0;
|
||||
virtual void Update(float elapsed) = 0;
|
||||
|
||||
Vector2 pos;
|
||||
Vector2 next_pos;
|
||||
Vector2 bbox;
|
||||
Vector2 velocity;
|
||||
bool noclip = false;
|
||||
bool on_ground = true;
|
||||
};
|
||||
virtual void Draw() = 0;
|
||||
|
||||
class Player : public GameEntity
|
||||
{
|
||||
public:
|
||||
Player(const Vector2& spawn_pos) : GameEntity(spawn_pos) {
|
||||
bbox = {16, 24};
|
||||
}
|
||||
Vector2 pos;
|
||||
Vector2 next_pos;
|
||||
Vector2 bbox;
|
||||
Vector2 velocity;
|
||||
bool noclip = false;
|
||||
bool on_ground = true;
|
||||
};
|
||||
|
||||
~Player() {
|
||||
class Player : public GameEntity
|
||||
{
|
||||
public:
|
||||
Player(const Vector2& spawn_pos) : GameEntity(spawn_pos) {
|
||||
bbox = {16, 24};
|
||||
}
|
||||
|
||||
}
|
||||
~Player() {
|
||||
|
||||
void Update(float elapsed) override {
|
||||
// Update current position to our next_position, which was computed on the last frame.
|
||||
// This means we can collision solve our next_pos in between calls to entity->Update();
|
||||
pos = next_pos;
|
||||
}
|
||||
|
||||
void Update(float elapsed) override {
|
||||
// Update current position to our next_position, which was computed on the last frame.
|
||||
// This means we can collision solve our next_pos in between calls to entity->Update();
|
||||
pos = next_pos;
|
||||
|
||||
velocity.x *= 1 - (elapsed * air_resistance);
|
||||
//velocity.y *= 1 - (elapsed * air_resistance);
|
||||
|
||||
velocity.x *= 1 - (elapsed * air_resistance);
|
||||
//velocity.y *= 1 - (elapsed * air_resistance);
|
||||
|
||||
//if (on_ground)
|
||||
//if (on_ground)
|
||||
//velocity.x *= friction;
|
||||
|
||||
velocity.y += (elapsed*gravity*mass);
|
||||
velocity.y += (elapsed*gravity*mass);
|
||||
|
||||
next_pos += velocity * elapsed;
|
||||
next_pos += velocity * elapsed;
|
||||
|
||||
if (Math::Abs(velocity.y) > 2)
|
||||
on_ground = false;
|
||||
if (Math::Abs(velocity.y) > 2)
|
||||
on_ground = false;
|
||||
|
||||
|
||||
if (InputService::IsKeyDown(Keys::A))
|
||||
velocity.x -= acceleration * elapsed;
|
||||
if (InputService::IsKeyDown(Keys::A))
|
||||
velocity.x -= acceleration * elapsed;
|
||||
|
||||
if (InputService::IsKeyDown(Keys::D))
|
||||
velocity.x += acceleration * elapsed;
|
||||
if (InputService::IsKeyDown(Keys::D))
|
||||
velocity.x += acceleration * elapsed;
|
||||
|
||||
if (InputService::IsKeyDown(Keys::W))
|
||||
velocity.y -= acceleration * elapsed;
|
||||
if (InputService::IsKeyDown(Keys::W))
|
||||
velocity.y -= acceleration * elapsed;
|
||||
|
||||
if (InputService::IsKeyDown(Keys::S))
|
||||
velocity.y += acceleration * elapsed;
|
||||
}
|
||||
|
||||
void Draw() override {
|
||||
J2D::FillRect(Colors::Blue, pos, bbox);
|
||||
J2D::DrawPartialSprite(player_tex, pos, {0,0}, bbox);
|
||||
}
|
||||
};
|
||||
|
||||
if (InputService::IsKeyDown(Keys::S))
|
||||
velocity.y += acceleration * elapsed;
|
||||
}
|
||||
|
||||
void Draw() override {
|
||||
J2D::FillRect(Colors::Blue, pos, bbox);
|
||||
J2D::DrawPartialSprite(player_tex, pos, {0,0}, bbox);
|
||||
}
|
||||
};
|
||||
|
||||
class TestGameAppWindow : public ReWindow::OpenGLWindow
|
||||
{
|
||||
public:
|
||||
EditorCamera camera;
|
||||
Level* loaded_level = nullptr;
|
||||
Tileset* loaded_tileset = nullptr;
|
||||
JGL::Texture* loaded_tilesheet = nullptr;
|
||||
@@ -133,6 +137,8 @@ public:
|
||||
JUI::Scene* scene = nullptr;
|
||||
|
||||
|
||||
Player* player = nullptr;
|
||||
|
||||
bool data_ready = false;
|
||||
|
||||
std::vector<GameEntity*> entities;
|
||||
@@ -151,8 +157,7 @@ public:
|
||||
using namespace JUI::UDimLiterals;
|
||||
scene = new JUI::Scene();
|
||||
|
||||
player_tex = new JGL::Texture("assets/player.png");
|
||||
|
||||
player_tex = new JGL::Texture("assets/player.png", FilteringMode::NEAREST);
|
||||
|
||||
//auto* fps_graph_window = new JUI::Window(scene);
|
||||
//fps_graph_window->Size({500_px, 50_px});
|
||||
@@ -220,8 +225,6 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: More sophisticated order-of-operations is required.
|
||||
// 1. Initialize elements of widgets that are independent of the level itself / the level depends on.
|
||||
// 2. Initialize the level.
|
||||
@@ -267,8 +270,10 @@ public:
|
||||
for (int i = 0; i < 100; i++) {
|
||||
auto* plr = new Player({50, 50});
|
||||
entities.emplace_back(plr);
|
||||
player = plr;
|
||||
}
|
||||
|
||||
camera.DefaultState();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -357,13 +362,31 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void CameraUpdate(float elapsed)
|
||||
{
|
||||
float move_rate = 120;
|
||||
float zoom_rate = 0.2f;
|
||||
|
||||
if (IsKeyDown(Keys::Minus))
|
||||
camera.scale.goal -= zoom_rate*elapsed;
|
||||
if (IsKeyDown(Keys::Equals))
|
||||
camera.scale.goal += zoom_rate*elapsed;
|
||||
|
||||
camera.Update(elapsed);
|
||||
|
||||
}
|
||||
|
||||
void Update(float elapsed)
|
||||
{
|
||||
CameraUpdate(elapsed);
|
||||
camera.translation.goal = player->pos;
|
||||
scene->Update(elapsed);
|
||||
|
||||
Vector2 window_dimensions(GetWidth(), GetHeight());
|
||||
|
||||
scene->SetViewportSize(window_dimensions);
|
||||
camera.screenSize = window_dimensions;
|
||||
|
||||
JGL::Update(Vector2i(GetWidth(), GetHeight()));
|
||||
|
||||
CollisionSolve(elapsed);
|
||||
@@ -419,6 +442,12 @@ public:
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
J2D::Begin();
|
||||
glPushMatrix();
|
||||
glTranslatef(GetWidth() / 2.f, GetHeight() / 2.f, 0);
|
||||
|
||||
glRotatef(camera.rotation.current, 0, 0, 1);
|
||||
glScalef(camera.scale.current, camera.scale.current, 1);
|
||||
glTranslatef(-camera.translation.current.x, -camera.translation.current.y, 0);
|
||||
|
||||
if (data_ready)
|
||||
DrawLevel(loaded_level);
|
||||
@@ -428,6 +457,7 @@ public:
|
||||
entity->Draw();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
J2D::End();
|
||||
scene->Draw();
|
||||
}
|
||||
@@ -476,6 +506,7 @@ public:
|
||||
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
ReWindow::Logger::Debug.EnableConsole(false);
|
||||
|
Reference in New Issue
Block a user