feat: added viewport transformation
parent
e84bdf5a48
commit
6610b847b8
|
@ -31,6 +31,7 @@ void AssetDB::load(std::string asset_name) {
|
|||
void AssetDB::index_assets() {
|
||||
SDL_Log("Indexing assets");
|
||||
for(std::filesystem::directory_entry const &itr : std::filesystem::recursive_directory_iterator("resources")) {
|
||||
SDL_Log("Indexing %s", itr.path().c_str());
|
||||
if(itr.is_directory())
|
||||
continue;
|
||||
else if(!itr.path().has_extension())
|
||||
|
|
|
@ -99,6 +99,10 @@ AssetDB &CanvasEngine::get_assets() {
|
|||
return this->assets;
|
||||
}
|
||||
|
||||
CollisionWorld &CanvasEngine::get_collision_world() {
|
||||
return this->collision_world;
|
||||
}
|
||||
|
||||
InputMap &CanvasEngine::get_input_map() {
|
||||
return this->input_map;
|
||||
}
|
||||
|
@ -132,7 +136,7 @@ void CanvasEngine::process_event(SDL_Event const &evt) {
|
|||
|
||||
void CanvasEngine::tick(double delta_time) {
|
||||
this->level->propagate_tick(delta_time);
|
||||
this->physics_world.check_collisions();
|
||||
this->collision_world.check_collisions();
|
||||
}
|
||||
|
||||
void CanvasEngine::draw(SDL_Renderer *render) {
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
#ifndef CANVAS_ENGINE_HPP
|
||||
#define CANVAS_ENGINE_HPP
|
||||
|
||||
#include "assets/asset_db.hpp"
|
||||
#include "core/collision.hpp"
|
||||
#include "core/level.hpp"
|
||||
#include "node.hpp"
|
||||
#include "assets/asset_db.hpp"
|
||||
#include "input/input_map.hpp"
|
||||
#include <SDL2/SDL_stdinc.h>
|
||||
#include <ctime>
|
||||
#include <cassert>
|
||||
#include "node.hpp"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_render.h>
|
||||
#include <SDL2/SDL_stdinc.h>
|
||||
#include <cassert>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
|
||||
namespace ce {
|
||||
|
@ -22,7 +22,7 @@ private:
|
|||
SDL_Renderer *render{nullptr}; //!< primary application window's renderer
|
||||
SDL_Texture *render_target{nullptr};
|
||||
AssetDB assets{};
|
||||
CollisionWorld physics_world{};
|
||||
CollisionWorld collision_world{};
|
||||
InputMap input_map{}; //!< map of inputs to input callback objects
|
||||
std::unique_ptr<Level> level;
|
||||
Uint64 last_frame_start_time{}; //!< time at start of last frame
|
||||
|
@ -42,6 +42,7 @@ public:
|
|||
void request_close();
|
||||
void set_target_delta_time(double target);
|
||||
AssetDB &get_assets();
|
||||
CollisionWorld &get_collision_world();
|
||||
InputMap &get_input_map();
|
||||
SDL_Renderer *get_render();
|
||||
private:
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
#include "collision_shape.hpp"
|
||||
|
||||
namespace ce {
|
||||
CollidableNode::CollidableNode(std::string const &name, CollisionMask layers, CollisionMask mask)
|
||||
: ce::Node2D(name) {
|
||||
this->layers = layers;
|
||||
this->mask = mask;
|
||||
}
|
||||
|
||||
void CollidableNode::_tick(double const &delta) {
|
||||
// find nodes that were overlapping last frame but not this frame
|
||||
std::map<CollidableNode*, unsigned>::iterator iterator{this->overlapped_nodes.begin()};
|
||||
|
@ -23,4 +29,20 @@ void CollidableNode::add_overlap(CollisionShape *shape, CollisionShape *other_sh
|
|||
this->shape_overlaps.insert(other_shape);
|
||||
++this->overlapped_nodes[other_shape->get_owner()];
|
||||
}
|
||||
|
||||
void CollidableNode::set_mask(CollisionMask mask) {
|
||||
this->mask = mask;
|
||||
}
|
||||
|
||||
CollisionMask CollidableNode::get_mask() const {
|
||||
return this->mask;
|
||||
}
|
||||
|
||||
void CollidableNode::set_layers(CollisionMask layers) {
|
||||
this->layers = layers;
|
||||
}
|
||||
|
||||
CollisionMask CollidableNode::get_layers() const {
|
||||
return this->layers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,18 +7,27 @@
|
|||
#include <map>
|
||||
|
||||
namespace ce {
|
||||
typedef uint64_t CollisionMask;
|
||||
class CollisionShape;
|
||||
|
||||
class CollidableNode : public Node2D {
|
||||
std::set<CollisionShape*> shape_overlaps{};
|
||||
std::map<CollidableNode*, unsigned> overlapped_nodes{};
|
||||
CollisionMask mask{~0x0u /* all layers by default */};
|
||||
CollisionMask layers{0x1u /* only the first layer is enabled by default */};
|
||||
public:
|
||||
// collision(local_shape, other_node, other_shape)
|
||||
Signal<CollisionShape*, CollidableNode*, CollisionShape*> overlap_enter{};
|
||||
Signal<CollidableNode*> overlap_exit{};
|
||||
public:
|
||||
CollidableNode(std::string const &name, CollisionMask layers, CollisionMask mask);
|
||||
virtual void _tick(double const &delta) override;
|
||||
void add_overlap(CollisionShape *shape, CollisionShape *other);
|
||||
|
||||
void set_mask(CollisionMask mask);
|
||||
CollisionMask get_mask() const;
|
||||
void set_layers(CollisionMask layers);
|
||||
CollisionMask get_layers() const;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "collision_shape.hpp"
|
||||
#include "collidable_node.hpp"
|
||||
#include "core/canvas_engine.hpp"
|
||||
#include <SDL2/SDL_log.h>
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -24,14 +25,17 @@ Shape Shape::make_box(float h_extent, float v_extent) {
|
|||
}
|
||||
|
||||
CollisionShape::CollisionShape(std::string const &name, Node *owner, Shape shape)
|
||||
: Node2D(name) {
|
||||
: Node2D(name)
|
||||
, world{CanvasEngine::get_singleton()->get_collision_world()} {
|
||||
this->shape = shape;
|
||||
}
|
||||
|
||||
void CollisionShape::_added(Node *parent) {
|
||||
void CollisionShape::_added() {
|
||||
Node *parent{this->get_parent()};
|
||||
while(parent != nullptr) {
|
||||
if(CollidableNode *as_collidable{dynamic_cast<CollidableNode*>(parent)}) {
|
||||
this->owner = as_collidable;
|
||||
this->register_with_world();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -39,13 +43,20 @@ void CollisionShape::_added(Node *parent) {
|
|||
#ifdef DEBUG
|
||||
abort();
|
||||
#endif
|
||||
if(this->is_registered)
|
||||
this->deregister_with_world();
|
||||
}
|
||||
|
||||
void CollisionShape::_removed() {
|
||||
if(this->is_registered)
|
||||
this->deregister_with_world();
|
||||
}
|
||||
|
||||
bool CollisionShape::can_collide(CollisionShape const *lhs, CollisionShape const *rhs) {
|
||||
return lhs->owner != nullptr && rhs->owner != nullptr
|
||||
&& lhs->owner != rhs->owner
|
||||
&& ((lhs->mask & rhs->layers) != 0x0u
|
||||
|| (rhs->mask & lhs->layers) != 0x0u);
|
||||
&& ((lhs->get_mask() & rhs->get_layers()) != 0x0u
|
||||
|| (rhs->get_mask() & lhs->get_layers()) != 0x0u);
|
||||
}
|
||||
|
||||
bool CollisionShape::shapes_overlap(CollisionShape const *lhs, CollisionShape const *rhs) {
|
||||
|
@ -110,19 +121,21 @@ Shape const &CollisionShape::get_shape() const {
|
|||
return this->shape;
|
||||
}
|
||||
|
||||
void CollisionShape::set_mask(CollisionMask mask) {
|
||||
this->mask = mask;
|
||||
CollisionMask CollisionShape::get_layers() const {
|
||||
return this->owner ? this->owner->get_layers() : 0x0u;
|
||||
}
|
||||
|
||||
CollisionMask CollisionShape::get_mask() const {
|
||||
return this->mask;
|
||||
return this->owner ? this->owner->get_mask() : 0x0u;
|
||||
}
|
||||
|
||||
void CollisionShape::set_layers(CollisionMask layers) {
|
||||
this->layers = layers;
|
||||
void CollisionShape::register_with_world() {
|
||||
this->world.add_collision_shape(this);
|
||||
this->is_registered = true;
|
||||
}
|
||||
|
||||
CollisionMask CollisionShape::get_layers() const {
|
||||
return this->layers;
|
||||
void CollisionShape::deregister_with_world() {
|
||||
this->world.remove_collision_shape(this);
|
||||
this->is_registered = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
#ifndef COLLISION_SHAPE_HPP
|
||||
#define COLLISION_SHAPE_HPP
|
||||
|
||||
#include "core/math/transform.hpp"
|
||||
#include "collidable_node.hpp"
|
||||
#include "math/transform.hpp"
|
||||
#include "node2d.hpp"
|
||||
|
||||
namespace ce {
|
||||
class CollidableNode;
|
||||
class CollisionWorld;
|
||||
typedef uint64_t CollisionMask;
|
||||
|
||||
struct ShapeCircle { float radius; };
|
||||
struct ShapeAABB { float h_extent, v_extent; };
|
||||
|
@ -27,13 +26,13 @@ struct Shape {
|
|||
class CollisionShape : public Node2D {
|
||||
CollidableNode *owner{nullptr};
|
||||
Shape shape{.shape=Shape::CIRCLE, .circle={.radius=1.f}};
|
||||
CollisionWorld *world{nullptr};
|
||||
CollisionMask mask{~0x0u /* all layers by default */};
|
||||
CollisionMask layers{0x1u /* only the first layer is enabled by default */};
|
||||
CollisionWorld &world;
|
||||
bool is_registered{false};
|
||||
public:
|
||||
CollisionShape(std::string const &name, Node *owner, Shape shape);
|
||||
|
||||
virtual void _added(Node *parent) override;
|
||||
virtual void _added() override;
|
||||
virtual void _removed() override;
|
||||
|
||||
static bool can_collide(CollisionShape const *lhs, CollisionShape const *rhs);
|
||||
static bool shapes_overlap(CollisionShape const *lhs, CollisionShape const *rhs);
|
||||
|
@ -44,10 +43,11 @@ public:
|
|||
CollidableNode *get_owner() const;
|
||||
void set_shape(Shape const &shape);
|
||||
Shape const &get_shape() const;
|
||||
void set_mask(CollisionMask mask);
|
||||
CollisionMask get_mask() const;
|
||||
void set_layers(CollisionMask layers);
|
||||
CollisionMask get_layers() const;
|
||||
CollisionMask get_mask() const;
|
||||
private:
|
||||
void register_with_world();
|
||||
void deregister_with_world();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,32 @@
|
|||
#include "level.hpp"
|
||||
#include "core/math/transform.hpp"
|
||||
#include <SDL2/SDL_render.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace ce {
|
||||
void Level::deinstantiate() {
|
||||
this->root.reset();
|
||||
}
|
||||
|
||||
void Level::propagate_tick(double const &delta_time) {
|
||||
this->root->propagate_tick(delta_time);
|
||||
}
|
||||
|
||||
void Level::propagate_draw(SDL_Renderer *render) {
|
||||
this->root->propagate_draw(render);
|
||||
int w, h;
|
||||
SDL_Window *window{SDL_RenderGetWindow(render)};
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
ce::Transform const screen_transform{
|
||||
.position = ce::Vecf::ZERO,
|
||||
.rotation = 0.f,
|
||||
.scale = ce::Vecf::ONE * float(w),
|
||||
};
|
||||
float const ratio{float(h)/float(w)};
|
||||
this->root->propagate_draw(render, Transform().translated({
|
||||
0.5f / this->view_transform.scale.x,
|
||||
0.5f / this->view_transform.scale.y * ratio
|
||||
}) * this->view_transform * screen_transform);
|
||||
}
|
||||
|
||||
Node *Level::get_root() {
|
||||
|
|
|
@ -7,14 +7,22 @@ namespace ce {
|
|||
class Level {
|
||||
protected:
|
||||
Node::OwnedPtr root{nullptr};
|
||||
ce::Transform view_transform{
|
||||
.position = ce::Vecf::ZERO,
|
||||
.rotation = 0.f,
|
||||
.scale = {1.f/10.f, 1.f/10.f},
|
||||
};
|
||||
public:
|
||||
virtual ~Level() = default;
|
||||
virtual void instantiate() = 0;
|
||||
void deinstantiate();
|
||||
void propagate_tick(double const &delta_time);
|
||||
void propagate_draw(SDL_Renderer *render);
|
||||
|
||||
Node *get_root();
|
||||
bool is_instantiated() const;
|
||||
void set_view_transform(ce::Transform transform);
|
||||
ce::Transform get_view_transform() const;
|
||||
protected:
|
||||
Node::OwnedPtr &get_owned_root();
|
||||
};
|
||||
|
|
|
@ -14,6 +14,24 @@ void Transform::scale_by(Vecf const &factors) {
|
|||
this->scale.scale(factors);
|
||||
}
|
||||
|
||||
Transform Transform::translated(Vecf const &translation) const {
|
||||
Transform out{*this};
|
||||
out.translate_by(translation);
|
||||
return out;
|
||||
}
|
||||
|
||||
Transform Transform::rotated(float rotation) const {
|
||||
Transform out{*this};
|
||||
out.rotate_by(rotation);
|
||||
return out;
|
||||
}
|
||||
|
||||
Transform Transform::scaled(Vecf const &factors) const {
|
||||
Transform out{*this};
|
||||
out.scale_by(factors);
|
||||
return out;
|
||||
}
|
||||
|
||||
Vecf Transform::right() const {
|
||||
return Vecf::RIGHT.rotated(this->rotation);
|
||||
}
|
||||
|
@ -24,7 +42,7 @@ Vecf Transform::up() const {
|
|||
|
||||
Transform operator *(Transform const &lhs, Transform const &rhs) {
|
||||
Transform t{
|
||||
.position = rhs.position + lhs.position.rotated(rhs.rotation),
|
||||
.position = rhs.position + lhs.position.rotated(rhs.rotation).scaled(rhs.scale),
|
||||
.rotation = rhs.rotation + lhs.rotation,
|
||||
.scale = lhs.scale.scaled(rhs.scale)
|
||||
};
|
||||
|
@ -33,9 +51,7 @@ Transform operator *(Transform const &lhs, Transform const &rhs) {
|
|||
}
|
||||
|
||||
Transform &operator *=(Transform &lhs, Transform const &rhs) {
|
||||
lhs.position += lhs.position.rotated(rhs.rotation);
|
||||
lhs.rotation += rhs.rotation;
|
||||
lhs.scale.scale(rhs.scale);
|
||||
lhs = lhs * rhs;
|
||||
assert(lhs.scale.x != 0.f || lhs.scale.y != 0.f); // !!!
|
||||
return lhs;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,13 @@ struct Transform {
|
|||
Vecf position{0.f, 0.f};
|
||||
double rotation{0.0};
|
||||
Vecf scale{1.f, 1.f};
|
||||
|
||||
void translate_by(Vecf const &translation);
|
||||
void rotate_by(double rotation);
|
||||
void scale_by(Vecf const &factors);
|
||||
Transform translated(Vecf const &translation) const;
|
||||
Transform rotated(float rotation) const;
|
||||
Transform scaled(Vecf const &factors) const;
|
||||
|
||||
Vecf right() const;
|
||||
Vecf up() const;
|
||||
|
|
|
@ -80,9 +80,12 @@ void Vecf::scale(Vecf const &factors) {
|
|||
}
|
||||
|
||||
Vecf Vecf::scaled(Vecf const &factors) const {
|
||||
return Vecf(this->x * factors.x, this->y * factors.y);
|
||||
return Vecf{this->x * factors.x, this->y * factors.y};
|
||||
}
|
||||
|
||||
Vecf const Vecf::RIGHT{1.f, 0.f};
|
||||
Vecf const Vecf::UP{0.f, 1.f};
|
||||
Vecf const Vecf::ONE{1.f, 1.f};
|
||||
Vecf const Vecf::ZERO{0.f, 0.f};
|
||||
Vecf const Vecf::POSITIVE_INFINITY{INFINITY, INFINITY};
|
||||
}
|
||||
|
|
|
@ -45,6 +45,9 @@ struct Vecf {
|
|||
|
||||
static Vecf const RIGHT;
|
||||
static Vecf const UP;
|
||||
static Vecf const ONE;
|
||||
static Vecf const POSITIVE_INFINITY;
|
||||
static Vecf const ZERO;
|
||||
};
|
||||
|
||||
static inline
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "node.hpp"
|
||||
#include <SDL2/SDL_assert.h>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
@ -16,7 +17,7 @@ void Node::add_child(Node::OwnedPtr &child) {
|
|||
Node *added{this->children.insert({child->get_name(), std::move(child)}).first->second.get()};
|
||||
added->parent = this;
|
||||
this->child_added.invoke(added);
|
||||
added->_added(this);
|
||||
added->propagate_added();
|
||||
}
|
||||
// specialize to skip dynamic_cast
|
||||
template <> Node *Node::get_child<Node>(std::string const &name) {
|
||||
|
@ -68,6 +69,19 @@ bool Node::is_ticking() const {
|
|||
return this->tick;
|
||||
}
|
||||
|
||||
ce::Level *Node::get_level() const {
|
||||
return this->level;
|
||||
}
|
||||
|
||||
void Node::set_level(ce::Level *level) {
|
||||
// parent level needs to match
|
||||
assert(this->parent == nullptr || this->parent->get_level() == level);
|
||||
this->level = level;
|
||||
for(std::pair<std::string const, std::unique_ptr<ce::Node>> &pair : this->children) {
|
||||
pair.second->set_level(level);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Node::OwnedPtr> Node::remove_child(Node *node) {
|
||||
if(this != node->get_parent())
|
||||
return std::nullopt;
|
||||
|
@ -84,7 +98,7 @@ std::optional<Node::OwnedPtr> Node::remove_child(Node *node) {
|
|||
Node::OwnedPtr owned{std::move(child->second)};
|
||||
this->children.erase(child);
|
||||
// notify both former child and any listeners that the child has been removed
|
||||
owned->_removed();
|
||||
owned->propagate_removed();
|
||||
this->child_removed.invoke(child->second.get());
|
||||
// return optional containing owned pointer to former child
|
||||
return std::optional(std::move(owned));
|
||||
|
@ -117,18 +131,24 @@ void Node::propagate_post_tick() {
|
|||
pair.second->propagate_post_tick();
|
||||
}
|
||||
|
||||
void Node::propagate_added() {
|
||||
this->_added();
|
||||
for(std::pair<std::string const, Node::OwnedPtr> &pair : this->children)
|
||||
pair.second->propagate_added();
|
||||
}
|
||||
|
||||
void Node::propagate_removed() {
|
||||
for(std::pair<std::string const, Node::OwnedPtr> &pair : this->children)
|
||||
pair.second->propagate_removed();
|
||||
this->_removed();
|
||||
}
|
||||
|
||||
void Node::propagate_draw(SDL_Renderer *render) {
|
||||
void Node::propagate_draw(SDL_Renderer *render, ce::Transform const &view_transform) {
|
||||
this->_update_transform();
|
||||
if(this->visible) {
|
||||
this->_draw(render);
|
||||
this->_draw(render, view_transform);
|
||||
for(std::pair<std::string const, Node::OwnedPtr> &pair : this->children)
|
||||
pair.second->propagate_draw(render);
|
||||
pair.second->propagate_draw(render, view_transform);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
#ifndef CANVAS_NODE_HPP
|
||||
#define CANVAS_NODE_HPP
|
||||
|
||||
#include "core/math/transform.hpp"
|
||||
#include "core/signal.hpp"
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
struct SDL_Renderer;
|
||||
|
||||
namespace ce {
|
||||
class Level;
|
||||
|
||||
class Node {
|
||||
public:
|
||||
friend class Level;
|
||||
|
@ -22,6 +25,7 @@ private:
|
|||
ChildrenMap children{};
|
||||
bool visible{true};
|
||||
bool tick{true};
|
||||
ce::Level *level{nullptr};
|
||||
public:
|
||||
Signal<> destroyed{}; //!< Signal invoked by the destructor
|
||||
Signal<Node*> child_removed{}; //!< Signal invoked when a child is removed.
|
||||
|
@ -30,11 +34,11 @@ public:
|
|||
Node(std::string name);
|
||||
virtual ~Node();
|
||||
protected:
|
||||
virtual void _added(Node *parent [[maybe_unused]]) {} //!< called the moment after the object is added as a child to another node
|
||||
virtual void _added() {} //!< called the moment after the object is added as a child to another node
|
||||
virtual void _first_tick() {} //!< called the first frame this object is active
|
||||
virtual void _tick(double const &delta_time [[maybe_unused]]) {} //!< called every frame
|
||||
virtual void _removed() {} //!< called the moment before the object is removed as a child to another node
|
||||
virtual void _draw(SDL_Renderer *render [[maybe_unused]]) {}
|
||||
virtual void _draw(SDL_Renderer *render [[maybe_unused]], ce::Transform const &view_transform [[maybe_unused]]) {}
|
||||
virtual void _update_transform() {}
|
||||
public:
|
||||
template <class TNode> TNode *get_child(std::string const &name); //!< get a non-owning pointer to a child
|
||||
|
@ -50,18 +54,22 @@ public:
|
|||
bool is_visible() const;
|
||||
void set_tick(bool value);
|
||||
bool is_ticking() const;
|
||||
ce::Level *get_level() const;
|
||||
private:
|
||||
void set_level(ce::Level *level);
|
||||
std::optional<Node::OwnedPtr> remove_child(Node *child); //!< remove a child, the caller now owns the pointer
|
||||
void propagate_tick(double const &delta_time);
|
||||
void propagate_post_tick();
|
||||
void propagate_added();
|
||||
void propagate_removed();
|
||||
void propagate_draw(SDL_Renderer *render);
|
||||
void propagate_draw(SDL_Renderer *render, ce::Transform const &view_transform);
|
||||
bool rename_child(std::string const &old_name, std::string const &new_name);
|
||||
};
|
||||
|
||||
template <class TNode> TNode *Node::get_child(std::string const &name) {
|
||||
return children.contains(name) ? dynamic_cast<TNode*>(children.at(name).get()) : nullptr;
|
||||
}
|
||||
|
||||
template <class TNode, typename... Args> TNode *Node::create_child(Args... cargs) {
|
||||
OwnedPtr owned{std::make_unique<TNode>(cargs...)};
|
||||
TNode *referenced{dynamic_cast<TNode*>(owned.get())};
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
namespace ce {
|
||||
Node2D::Node2D(std::string name) : Node(name) {}
|
||||
|
||||
void Node2D::_added(Node *parent) {
|
||||
this->parent_node2d = dynamic_cast<Node2D*>(parent);
|
||||
void Node2D::_added() {
|
||||
this->parent_node2d = dynamic_cast<Node2D*>(this->get_parent());
|
||||
}
|
||||
|
||||
void Node2D::_update_transform() {
|
||||
|
|
|
@ -11,7 +11,7 @@ class Node2D : public Node {
|
|||
Node2D *parent_node2d{nullptr};
|
||||
public:
|
||||
Node2D(std::string name);
|
||||
virtual void _added(Node *parent) override;
|
||||
virtual void _added() override;
|
||||
Node2D *get_parent_node2d() const;
|
||||
virtual void _update_transform() override;
|
||||
void set_transform(Transform const &transform);
|
||||
|
|
|
@ -2,16 +2,18 @@
|
|||
#include "core/canvas_engine.hpp"
|
||||
#include "core/math/transform.hpp"
|
||||
#include <SDL2/SDL_render.h>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
namespace ce {
|
||||
Sprite::Sprite(std::string name, std::string texture)
|
||||
: Node2D(name) {
|
||||
std::optional<std::shared_ptr<Texture>> asset = CanvasEngine::get_singleton()->get_assets().get_asset<Texture>(texture);
|
||||
std::optional<std::shared_ptr<Texture>> asset{CanvasEngine::get_singleton()->get_assets().get_asset<Texture>(texture)};
|
||||
if(asset.has_value())
|
||||
this->texture = asset.value();
|
||||
}
|
||||
|
||||
void Sprite::_draw(SDL_Renderer *render) {
|
||||
void Sprite::_draw(SDL_Renderer *render, ce::Transform const &view_transform) {
|
||||
if(this->texture == nullptr) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "No texture assigned");
|
||||
this->set_visible(false);
|
||||
|
@ -19,9 +21,10 @@ void Sprite::_draw(SDL_Renderer *render) {
|
|||
}
|
||||
int w, h;
|
||||
SDL_QueryTexture(this->texture->get(), NULL, NULL, &w, &h);
|
||||
Transform transform{this->get_global_transform()};
|
||||
Transform transform{this->get_global_transform() * view_transform};
|
||||
assert(transform.scale.x != 0 && transform.scale.y != 0); // !!!
|
||||
float fw{w * transform.scale.x}, fh{h * transform.scale.y};
|
||||
float fw{transform.scale.x * (w > h ? float(w) / float(h) : 1.f)};
|
||||
float fh{transform.scale.y * (w < h ? float(h) / float(w) : 1.f)};
|
||||
assert(fw != 0.f && fh != 0.f);
|
||||
//float fw(w), fh(h);
|
||||
SDL_Rect src{0, 0, w, h};
|
||||
|
|
|
@ -9,7 +9,7 @@ class Sprite : public Node2D {
|
|||
std::shared_ptr<Texture> texture{nullptr};
|
||||
public:
|
||||
Sprite(std::string name, std::string texture);
|
||||
virtual void _draw(SDL_Renderer *render) override;
|
||||
virtual void _draw(SDL_Renderer *render, ce::Transform const &view_transform) override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
#include "level_1.hpp"
|
||||
#include "core/node.hpp"
|
||||
#include "test_node.hpp"
|
||||
#include "core/node2d.hpp"
|
||||
#include "core/sprite.hpp"
|
||||
#include "player.hpp"
|
||||
|
||||
void Level1::instantiate() {
|
||||
ce::Node::OwnedPtr &root_ptr{this->get_owned_root()};
|
||||
root_ptr.reset(new ce::Node("root"));
|
||||
ce::Node::OwnedPtr node{std::make_unique<TestNode>()};
|
||||
root->add_child(node);
|
||||
root.reset(new ce::Node2D("root"));
|
||||
root->create_child<ce::Sprite>("background", "background")->set_global_transform({
|
||||
.position = ce::Vecf::ZERO,
|
||||
.rotation = 0.f,
|
||||
.scale = ce::Vecf::ONE * 10.f
|
||||
});
|
||||
root->create_child<Player>();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#include "core/canvas_engine.hpp"
|
||||
#include "level_1.hpp"
|
||||
|
||||
ce::CanvasEngine engine{};
|
||||
|
||||
int main(int argc [[maybe_unused]], char* argv [[maybe_unused]][]) {
|
||||
ce::CanvasEngine engine{};
|
||||
std::unique_ptr<ce::Level> level{std::make_unique<Level1>()};
|
||||
engine.run(level);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#include "player.hpp"
|
||||
#include "core/collidable_node.hpp"
|
||||
#include "core/collision_shape.hpp"
|
||||
#include "core/math/transform.hpp"
|
||||
#include "core/sprite.hpp"
|
||||
|
||||
Player::Player()
|
||||
: ce::CollidableNode("player", 0x1u, 0x1u) {
|
||||
this->sprite = this->create_child<ce::Sprite>("bike", "bike");
|
||||
this->shape = this->create_child<ce::CollisionShape>("PlayerShape", this, ce::Shape::make_box(5.f, 10.f));
|
||||
ce::Transform trans{this->get_global_transform()};
|
||||
this->set_global_transform(trans);
|
||||
}
|
||||
|
||||
void Player::_tick(double const &delta) {
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef PLAYER_HPP
|
||||
#define PLAYER_HPP
|
||||
|
||||
#include "core/collidable_node.hpp"
|
||||
|
||||
namespace ce {
|
||||
class CollisionShape;
|
||||
class Sprite;
|
||||
};
|
||||
|
||||
class Player : public ce::CollidableNode {
|
||||
ce::CollisionShape *shape{nullptr};
|
||||
ce::Sprite *sprite{nullptr};
|
||||
public:
|
||||
Player();
|
||||
virtual void _tick(double const &delta) override;
|
||||
};
|
||||
|
||||
#endif // !PLAYER_HPP
|
|
@ -5,7 +5,7 @@
|
|||
#include <cmath>
|
||||
|
||||
TestNode::TestNode()
|
||||
: ce::Node2D("TestNode") {
|
||||
: ce::CollidableNode("TestNode", 0x1u, 0x1u) {
|
||||
this->sprite = this->create_child<ce::Sprite>("neocat", "neocat");
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,7 @@ void TestNode::_tick(double const &delta) {
|
|||
this->set_transform(trans);
|
||||
}
|
||||
|
||||
void TestNode::_draw(SDL_Renderer *render) {
|
||||
ce::Node2D::_draw(render);
|
||||
void TestNode::_draw(SDL_Renderer *render, ce::Transform const &view_transform) {
|
||||
ce::Transform trans{this->get_global_transform()};
|
||||
SDL_SetRenderDrawColor(render, 255, 255, 255, 255);
|
||||
SDL_FRect rect{trans.position.x-101.f, trans.position.y-101.f, 202.f, 202.f};
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
#ifndef TEST_NODE_HPP
|
||||
#define TEST_NODE_HPP
|
||||
|
||||
#include "core/node2d.hpp"
|
||||
#include "core/collidable_node.hpp"
|
||||
#include "core/collision_shape.hpp"
|
||||
#include "core/sprite.hpp"
|
||||
|
||||
class TestNode : public ce::Node2D {
|
||||
class TestNode : public ce::CollidableNode {
|
||||
private:
|
||||
ce::Sprite *sprite{nullptr};
|
||||
ce::CollisionShape *shape{nullptr};
|
||||
public:
|
||||
TestNode();
|
||||
virtual void _first_tick() override;
|
||||
virtual void _tick(double const &delta) override;
|
||||
virtual void _draw(SDL_Renderer *render) override;
|
||||
virtual void _draw(SDL_Renderer *render, ce::Transform const &view_transform) override;
|
||||
};
|
||||
|
||||
#endif // !TEST_NODE_HPP
|
||||
|
|
Loading…
Reference in New Issue