-
Notifications
You must be signed in to change notification settings - Fork 0
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
add physics component #29
Conversation
…e sprite position.
DogTales/src/components/physics.cpp
Outdated
m_acceleration.y += m_gravity * dt; | ||
m_velocity = (m_velocity + (m_acceleration / m_mass) * dt) * m_friction; | ||
|
||
m_velocity.x = m_velocity.x > max_velocity.x ? max_velocity.x : m_velocity.x; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there must be a better way to constrain the velocity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor changes like stronger typing, using glm::clamp
, constructor vs no constructor, etc.
for (bave::Seconds t{}; t <= dt; t += ft) { | ||
integrate(t.count()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a subtle issue here: some residue of dt
that's less than ft
remains un-integrated on every tick
. It would be better to accumulate that in a member and add it to the next dt
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would this fix work?
for (bave::Seconds t{ m_accumulator }; t <= dt; t += ft) {
integrate(t);
if (t + ft >= dt) { m_accumulator = dt - t; }
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, something like this would be better:
void Physics::tick(bave::Seconds dt) {
// ...
for (dt += m_residue; dt > ft; dt -= ft) {
integrate(ft);
}
m_residue = dt;
}
DogTales/src/components/physics.cpp
Outdated
} | ||
} | ||
|
||
void Physics::integrate(float dt) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should use bave::Seconds
here too, it's ambiguous what unit dt
is (seconds or milliseconds etc).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
DogTales/src/components/physics.cpp
Outdated
m_velocity.x = m_velocity.x > max_velocity.x ? max_velocity.x : m_velocity.x; | ||
m_velocity.y = m_velocity.y > max_velocity.y ? max_velocity.y : m_velocity.y; | ||
m_velocity.x = m_velocity.x < -max_velocity.x ? -max_velocity.x : m_velocity.x; | ||
m_velocity.y = m_velocity.y < -max_velocity.y ? -max_velocity.y : m_velocity.y; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m_velocity.x = m_velocity.x > max_velocity.x ? max_velocity.x : m_velocity.x; | |
m_velocity.y = m_velocity.y > max_velocity.y ? max_velocity.y : m_velocity.y; | |
m_velocity.x = m_velocity.x < -max_velocity.x ? -max_velocity.x : m_velocity.x; | |
m_velocity.y = m_velocity.y < -max_velocity.y ? -max_velocity.y : m_velocity.y; | |
m_velocity = glm::clamp(m_velocity, -max_velocity, max_velocity); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
DogTales/src/components/physics.hpp
Outdated
static constexpr glm::vec2 max_velocity{1000.f, 1000.f}; | ||
static constexpr float tick_limit{0.03f}; //this should possibly go somewhere else and be globally accessible |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Globals in headers should not be static
: that will introduce new storage for the global in each translation unit (cpp file that includes the header). Just constexpr
is fine here, though if you want to be pedantic, inline constexpr
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
DogTales/src/components/physics.hpp
Outdated
static constexpr glm::vec2 max_velocity{1000.f, 1000.f}; | ||
static constexpr float tick_limit{0.03f}; //this should possibly go somewhere else and be globally accessible |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This represents time and should use chrono units (bave::Seconds
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also think 30ms is too little, 100ms is ok as the death-spiral-bail-out value.
static constexpr glm::vec2 max_velocity{1000.f, 1000.f}; | |
static constexpr float tick_limit{0.03f}; //this should possibly go somewhere else and be globally accessible | |
constexpr glm::vec2 max_velocity_v{1000.f}; | |
constexpr bave::Seconds tick_limit_v{100ms}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed!
DogTales/src/components/physics.hpp
Outdated
glm::vec2 m_position{}; | ||
glm::vec2 m_velocity{}; | ||
glm::vec2 m_acceleration{}; | ||
|
||
glm::vec2 m_friction{}; | ||
float m_gravity{}; | ||
float m_mass{}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If all this is public, a constructor isn't needed, users can just do:
auto physics = Physics{
.m_friction = /* ... */,
.m_gravity = /* ... */,
.m_mass = /* ... */,
};
As a style thing, this is one reason why I don't prefix m_
for public members.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, shouldn't gravity
be shared amongst all physics components, as opposed to being an individual member on each instance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you think friction, position, velocity etc. should be public? or should I write getters for them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree intuitively about gravity, but being able to change it might make it easier to simulate light-weightedness (for certain enemies or drops, etc).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you think friction, position, velocity etc. should be public? or should I write getters for them?
It depends on whether you want them to be "set once and then it's read-only" or "set at your discretion". The former will take the values in the constructor and provide getters (but not setters). Latter would get rid of the constructor and keep the members public.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this isn't working because it says a designator cannot be used with a non-aggregate type (even though I deleted the constructor). is my syntax wrong here?
component::Physics m_physics = {.friction{0.999f, 0.999f}, .gravity{-1000.f}, .mass{1.f}};
Is this a member variable? Try removing the =
sign.
Alternatively, try component::Physics m_physics = component::Physics{...}
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, it's a member variable of Player
. neither of those solutions worked either. here's the new physics.hpp
if the issue lies there:
namespace component {
constexpr glm::vec2 max_velocity_v{1000.f};
constexpr bave::Seconds tick_limit_v{100ms};
class Physics {
bave::Seconds m_residue{};
public:
glm::vec2 position{};
glm::vec2 velocity{};
glm::vec2 acceleration{};
glm::vec2 friction{};
float gravity{};
float mass{};
void tick(bave::Seconds const dt);
void integrate(bave::Seconds dt);
};
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok I realized it's the m_residue
being private
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so, I guess I need to define a constructor then, because m_residue
being public feels pretty wrong
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, all the fields of aggregate types must be public.
A constructor that uses default values will be best then, that way both of these would work:
auto custom = Physics{/* ... */};
auto default_ = Physics{};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also recommend removing Player::m_vel
and related logic since that's no longer used.
DogTales/src/components/physics.hpp
Outdated
constexpr glm::vec2 default_friction{0.999f}; | ||
constexpr float default_gravity{-1000.f}; | ||
constexpr float default_mass{1.f}; | ||
|
||
constexpr glm::vec2 max_velocity_v{1000.f}; | ||
constexpr bave::Seconds tick_limit_v{100ms}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd move these constants into class Physics
(as static constexpr
) since they are specific to it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
m_sprite.transform.position = m_physics.position; | ||
|
||
handle_wall_collision(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since handle_wall_collision
clamps the player sprite's position to the bottom of the screen, after that point m_physics.position
and m_sprite.transform.position
keep diverging indefinitely, effectively pinning the player to the ground no matter what (jumping from -1000 to -990 will still get clamped to -360 or whatever).
For time being I'd suggest setting m_physics.position = m_sprite.transform.position
after the clamping, to synchronize them again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed!
DogTales/src/components/physics.hpp
Outdated
glm::vec2 m_friction{}; | ||
float m_gravity{}; | ||
float m_mass{}; | ||
Physics(glm::vec2 fric = default_friction, float grav = default_gravity, float m = default_mass) : friction(fric), gravity(grav), mass(m) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use longer names, doesn't matter if the init goes into the next line.
Physics(glm::vec2 fric = default_friction, float grav = default_gravity, float m = default_mass) : friction(fric), gravity(grav), mass(m) {} | |
Physics(glm::vec2 friction = default_friction, float gravity = default_gravity, float mass = default_mass) : friction(friction), gravity(gravity), mass(mass) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, I always thought the names had to be different otherwise the compiler would get confused. good to know, and fixed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha yeah, somehow in the initializer list it can disambiguate just fine. Once you enter the constructor body you'll need explicit this->foo = foo
.
… clamping sprite position.
static constexpr glm::vec2 default_friction{0.99f}; | ||
static constexpr float default_gravity{-1000.f}; | ||
static constexpr float default_mass{1.f}; | ||
|
||
class Physics { | ||
static constexpr glm::vec2 max_velocity_v{1000.f}; | ||
static constexpr bave::Seconds tick_limit_v{100ms}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: some constants use a _v
suffix (for "value", standard library convention), some don't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it!
if (position.x < bounce_rect.top_left().x || position.x > bounce_rect.bottom_right().x) { m_physics.velocity.x *= -0.9f; } | ||
if (position.y > bounce_rect.top_left().y || position.y < bounce_rect.bottom_right().y) { m_physics.velocity.y *= -0.9f; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious: what's with the 0.9... instead of 1.0? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when it's 1.0, it bounces against the ground for a really long time. I think of the 0.9 as the object transferring 10% of its energy into the ground/wall. it's just a needless temporary cosmetic fix, since player collision will probably be completely static anyway :)
add a
component
namespace and create aPhysics
class. the player gets a physics component, and its position is updated based on the physics state.