Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce GameObjects and Components. #3

Merged
merged 4 commits into from
Jul 1, 2021
Merged

Introduce GameObjects and Components. #3

merged 4 commits into from
Jul 1, 2021

Conversation

srijan-paul
Copy link
Member

A GameObject is a wrapper around a std::vector of Components, along with an onUpdate method.
Current app is a circle that slowly moves from the topleft to the bottom right of the screen.

Eventually this will become the ball in pong.

Files added:
include/wex/presets/GameObject.hpp
include/wex/presets/Component.hpp

@srijan-paul srijan-paul requested a review from karnkaul July 1, 2021 17:46
/// A component by itself has no meaning, and is useful to describe properties or attributes
/// of a `wex::GameObject`.
/// Extend this class to use custom components.
struct Component {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convention is to have such things be classes, structs don't usually have virtual semantics.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reasoning was this is more of a C-style "bag of data", rather than mutable state + mutating functions. So I went with a struct here. is that okay?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, just letting you know what to expect elsewhere

T* give(Args&&... args) {
auto compPtr = std::make_unique<T>(std::forward<Args>(args)...);
mComponents.push_back(std::move(compPtr));
return reinterpret_cast<T*>(mComponents.back().get());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static_cast pls! reinterpret will cast anything without care, we mostly restrict it to primitives only.

virtual void onUpdate([[maybe_unused]] double dt) {}

template <typename T>
T* get() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be a const member function (don't need non const overload, because pointer isn't const)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aaah, great catch!

/// TODO: optimize this O(n) lookup
for (auto const& compPtr : mComponents) {
auto comp = dynamic_cast<T*>(compPtr.get());
if (comp != nullptr) return reinterpret_cast<T*>(comp);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls no reinterpret_cast 😭
Here you can just return comp

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol, alright. Why is reinterpret_case bad?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's basically (foo)bar: there are no checks whatsoever, and unlike in C, materializing an object (or a pointer to one) that was never created before is UB in C++.

src/main.cpp Outdated
template <typename T>
struct Shape : wex::Component {
T shape;
Shape(T&& shape_) : shape(shape_) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rvalue that's not moved? sus...

void onUpdate(double) override {
sf::Vector2f const& vel = this->get<wex::CVelocity>()->vel;
auto& shape = this->get<CCircleShape>()->shape;
shape.setPosition(shape.getPosition() + vel);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing * dt for framerate independence.

src/main.cpp Outdated
}

void draw() override {
g->draw(mCircle);
g->draw(ball.get<CCircleShape>()->shape);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not delegate to ball?

@srijan-paul srijan-paul requested a review from karnkaul July 1, 2021 18:33
Copy link
Member

@karnkaul karnkaul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Small comment: while double dt is fine, it doesn't convey the units, a chrono::duration<float, R> instead will be a zero overhead unit safe wrapper.

@srijan-paul srijan-paul merged commit 24bb436 into dev Jul 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants