Skip to content

Commit f0a6b33

Browse files
committed
cmp: Improve physics and character state
Use a circle as a shape for the character physics body and set a high angular damping to reduce drastically its angular velocity. Also, introduce an bit flag to quickly see whether the current entity has any obstacles in the four directions up, down, left, right.
1 parent 3284f19 commit f0a6b33

9 files changed

Lines changed: 153 additions & 39 deletions

File tree

LICENSE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Copyright (c) 2019-2020 Angelo Theodorou
2-
Copyright (c) 2020 Antonio Caggiano
1+
Copyright © 2019-2020 Angelo Theodorou
2+
Copyright © 2020-2021 Antonio Caggiano
33

44
Permission is hereby granted, free of charge, to any person obtaining a
55
copy of this software and associated documentation files (the "Software"),

cmake/package_info.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
set(PACKAGE_NAME "ncJump")
22
set(PACKAGE_EXE_NAME "ncjump")
33
set(PACKAGE_VENDOR "Antonio Caggiano")
4-
set(PACKAGE_COPYRIGHT "Copyright © 2020 ${PACKAGE_VENDOR}")
4+
set(PACKAGE_COPYRIGHT "Copyright © 2020-2021 ${PACKAGE_VENDOR}")
55
set(PACKAGE_DESCRIPTION "A jumping project made with the nCine")
66
set(PACKAGE_HOMEPAGE "https://antoniocaggiano.eu")
77
set(PACKAGE_REVERSE_DNS "eu.antoniocaggiano.ncjump")

include/component/physics.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ struct PhysicsComponent {
2424

2525
b2Body* body = nullptr;
2626

27+
DirectionFlags obstacle;
28+
2729
f32 air_factor = 1.0f / 16.0f;
28-
f32 velocity_factor = 64.0f;
29-
f32 jump_y_factor = 360.0f;
30+
f32 velocity_factor = 32.0f;
31+
f32 jump_y_factor = 160.0f;
3032
f32 jump_x_factor = 3.0f;
31-
f32 max_x_speed = 8.0f;
33+
f32 max_x_speed = 6.0f;
3234
};
3335

3436
} // namespace jmp

include/types.h

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#pragma once
22

3+
#include <cassert>
34
#include <cstdint>
45
#include <optional>
6+
#include <string>
57

68
#include <ncine/Vector2.h>
79
#include <ncine/common_macros.h>
@@ -16,11 +18,89 @@ using f32 = float;
1618
using Vec2i = nc::Vector2<i32>;
1719
using Vec2u = nc::Vector2<u32>;
1820
using Vec2f = nc::Vector2<f32>;
21+
constexpr auto None = std::nullopt;
1922

2023
#define OPTION std::optional
21-
#define NONE std::nullopt
2224
#define UNIQUE nctl::UniquePtr
2325
#define MK nctl::makeUnique
2426
#define MV nctl::move
2527

2628
#define PATH(path) nc::fs::joinPath(nc::fs::dataPath(), path).data()
29+
30+
enum class DirectionFlags {
31+
NONE = 0,
32+
UP = 1 << 0,
33+
DOWN = 1 << 1,
34+
LEFT = 1 << 2,
35+
RIGHT = 1 << 3,
36+
};
37+
38+
constexpr inline DirectionFlags operator~(DirectionFlags a)
39+
{
40+
return (DirectionFlags) ~(i32)a;
41+
}
42+
43+
constexpr inline DirectionFlags operator|(DirectionFlags a, DirectionFlags b)
44+
{
45+
return (DirectionFlags)((i32)a | (i32)b);
46+
}
47+
48+
constexpr inline DirectionFlags operator&(DirectionFlags a, DirectionFlags b)
49+
{
50+
return (DirectionFlags)((i32)a & (i32)b);
51+
}
52+
constexpr inline DirectionFlags operator^(DirectionFlags a, DirectionFlags b)
53+
{
54+
return (DirectionFlags)((i32)a ^ (i32)b);
55+
}
56+
57+
constexpr inline DirectionFlags& operator|=(DirectionFlags& a, DirectionFlags b)
58+
{
59+
return (DirectionFlags&)((i32&)a |= (i32)b);
60+
}
61+
62+
constexpr inline DirectionFlags& operator&=(DirectionFlags& a, DirectionFlags b)
63+
{
64+
return (DirectionFlags&)((i32&)a &= (i32)b);
65+
}
66+
67+
constexpr inline DirectionFlags& operator^=(DirectionFlags& a, DirectionFlags b)
68+
{
69+
return (DirectionFlags&)((i32&)a ^= (i32)b);
70+
}
71+
72+
constexpr inline bool any(DirectionFlags a)
73+
{
74+
return a != DirectionFlags::NONE;
75+
}
76+
77+
static std::string to_str(DirectionFlags a)
78+
{
79+
if (a == DirectionFlags::NONE) {
80+
return "NONE";
81+
}
82+
83+
std::string ret;
84+
85+
if (any(a & DirectionFlags::UP)) {
86+
ret += "UP, ";
87+
}
88+
89+
if (any(a & DirectionFlags::DOWN)) {
90+
ret += "DOWN, ";
91+
}
92+
93+
if (any(a & DirectionFlags::LEFT)) {
94+
ret += "LEFT, ";
95+
}
96+
97+
if (any(a & DirectionFlags::RIGHT)) {
98+
ret += "RIGHT, ";
99+
}
100+
101+
// Remove last ", "
102+
assert(ret.length() > 2);
103+
ret.resize(ret.length() - 2);
104+
105+
return ret;
106+
}

src/component/physics.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ PhysicsComponent::PhysicsComponent(PhysicsComponent&& o)
3535
: physics {o.physics}
3636
, body {o.body}
3737
, air_factor {o.air_factor}
38-
, velocity_factor {64.0f}
39-
, jump_y_factor {360.0f}
40-
, jump_x_factor {3.0f}
41-
, max_x_speed {8.0f}
38+
, velocity_factor {o.velocity_factor}
39+
, jump_y_factor {o.jump_y_factor}
40+
, jump_x_factor {o.jump_x_factor}
41+
, max_x_speed {o.max_x_speed}
4242
{
4343
o.body = nullptr;
4444
}
@@ -66,6 +66,31 @@ void PhysicsComponent::update()
6666
{
6767
assert(body && "Physics component has no body");
6868

69+
// Update some variables
70+
obstacle = DirectionFlags::NONE;
71+
for (auto edge = body->GetContactList(); edge; edge = edge->next) {
72+
auto normal = edge->contact->GetManifold()->localNormal;
73+
if (edge->contact->GetFixtureA() == body->GetFixtureList()) {
74+
normal = -normal;
75+
}
76+
77+
if (normal.x < -0.9f) {
78+
obstacle |= DirectionFlags::RIGHT;
79+
}
80+
81+
if (normal.x > 0.9f) {
82+
obstacle |= DirectionFlags::LEFT;
83+
}
84+
85+
if (normal.y > 0.9f) {
86+
obstacle |= DirectionFlags::DOWN;
87+
}
88+
89+
if (normal.y < -0.9f) {
90+
obstacle |= DirectionFlags::UP;
91+
}
92+
}
93+
6994
// Apply air resistance
7095
auto vel = -body->GetLinearVelocity();
7196
auto vel_len = vel.LengthSquared();

src/component/state.cpp

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,7 @@ void IdleState::enter(const Input& input, Entity& entity)
7373
void can_fall(const Input& input, Entity& entity)
7474
{
7575
// Can fall if there is no platform below
76-
bool should_fall = true;
77-
78-
for (auto edge = entity.physics->body->GetContactList(); edge; edge = edge->next) {
79-
auto normal = edge->contact->GetManifold()->localNormal;
80-
if (edge->contact->GetFixtureA() == entity.physics->body->GetFixtureList()) {
81-
normal = -normal;
82-
}
83-
if (normal.y > 0.5f) {
84-
should_fall = false;
85-
break;
86-
}
87-
}
76+
bool should_fall = !any(entity.physics->obstacle & DirectionFlags::DOWN);
8877

8978
if (should_fall) {
9079
CHAR_STT(entity).set_state(State::JUMP_DOWN, input, entity);
@@ -145,8 +134,11 @@ void can_move_on_x(const Input& input, Entity& entity, f32 x_factor)
145134
{
146135
f32 x_velocity = entity.physics->body->GetLinearVelocity().x;
147136

137+
// Applying a force to move in the opposite direction of current velocity is always allowed
148138
bool opposite_move = (input.joystick.move.x < 0 && x_velocity >= 0) ||
149139
(input.joystick.move.x >= 0 && x_velocity < 0);
140+
141+
// Make sure current velocity is within limits, otherwise do not apply further force
150142
bool within_limit =
151143
fabs(entity.physics->body->GetLinearVelocity().x) < entity.physics->max_x_speed;
152144

@@ -182,6 +174,8 @@ void JumpUpState::handle(const Input& input, Entity& entity)
182174

183175
void JumpUpState::enter(const Input& input, Entity& entity)
184176
{
177+
entity.physics->body->GetFixtureList()->SetFriction(0.0f);
178+
185179
entity.transform.node->addChildNode(&CHAR_GFX(entity).jump_up);
186180

187181
auto force = b2Vec2(
@@ -197,6 +191,7 @@ void JumpUpState::update(const f32 dt, const Input& input, Entity& entity)
197191

198192
void JumpUpState::exit(Entity& entity)
199193
{
194+
entity.physics->body->GetFixtureList()->SetFriction(3.0f);
200195
entity.transform.node->removeChildNode(&CHAR_GFX(entity).jump_up);
201196
}
202197

@@ -207,29 +202,38 @@ JumpDownState::JumpDownState()
207202

208203
void JumpDownState::enter(const Input& input, Entity& entity)
209204
{
205+
entity.physics->body->GetFixtureList()->SetFriction(0.0f);
210206
entity.transform.node->addChildNode(&CHAR_GFX(entity).jump_down);
211207
}
212208

213209
void JumpDownState::handle(const Input& input, Entity& entity)
214210
{
215-
for (auto edge = entity.physics->body->GetContactList(); edge; edge = edge->next) {
216-
auto& normal = edge->contact->GetManifold()->localNormal;
217-
if (normal.y != 0.0) {
218-
LOGI_X("Normal (%f, %f)", normal.x, normal.y);
219-
CHAR_STT(entity).set_state(State::MOVE, input, entity);
220-
break;
221-
}
211+
if (any(entity.physics->obstacle & DirectionFlags::DOWN)
212+
) {
213+
CHAR_STT(entity).set_state(State::MOVE, input, entity);
222214
}
223215
}
224216

225217
void JumpDownState::update(const f32, const Input& input, Entity& entity)
226218
{
227219
// Can move a bit
228220
can_move_on_x(input, entity, entity.physics->jump_x_factor);
221+
222+
// Make sure it goes down
223+
if (entity.physics->body->GetLinearVelocity().y > -1.0) {
224+
entity.physics->body->ApplyForceToCenter({0.0, -100.0f}, true);
225+
}
229226
}
230227

231228
void JumpDownState::exit(Entity& entity)
232229
{
230+
auto fixture = entity.physics->body->GetFixtureList();
231+
fixture->SetFriction(3.0f);
232+
233+
for (auto edge = entity.physics->body->GetContactList(); edge; edge = edge->next) {
234+
edge->contact->ResetFriction();
235+
}
236+
233237
entity.transform.node->removeChildNode(&CHAR_GFX(entity).jump_down);
234238
}
235239

src/editor.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ void Editor::update_physics(PhysicsComponent& physics)
2424
auto vel = physics.body->GetLinearVelocity();
2525
ImGui::Text("vel: { x: %.2f, y: %.2f }", vel.x, vel.y);
2626

27+
ImGui::Text("obstacle: { %s }", to_str(physics.obstacle).c_str());
28+
2729
if (ImGui::TreeNode("Contacts")) {
2830
for (auto edge = physics.body->GetContactList(); edge; edge = edge->next) {
2931
auto normal = edge->contact->GetManifold()->localNormal;

src/game.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ Game::Game(Config& config)
3030
void Game::update(const float dt)
3131
{
3232
// Update game state
33+
physics.update(dt);
34+
3335
entity.update(dt, input);
3436
editor.update();
35-
physics.update(dt);
3637

37-
// @todo Move this somewhere else?
38-
// Update entity from box
38+
// @todo Move this somewhere else? Possibly PhysicsSystem?
39+
// Update entity from body
3940
auto& pos = physics.hero_body->GetPosition();
4041
entity.transform.node->x = config.size.tile * pos.x + config.size.tile / 2.0f;
4142
entity.transform.node->y = config.size.tile * pos.y + config.size.tile / 2.0f;

src/physics.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace jmp
44
{
55
Physics::Physics(f32 x, f32 y)
6-
: gravity {0.0, -20.0f}
6+
: gravity {0.0, -30.0f}
77
, world {gravity}
88
{
99
// Ground body
@@ -25,17 +25,17 @@ Physics::Physics(f32 x, f32 y)
2525
auto hero_def = b2BodyDef();
2626
hero_def.type = b2_dynamicBody;
2727
hero_def.position.Set(x, y);
28-
hero_def.fixedRotation = true;
28+
hero_def.angularDamping = 100.0;
2929

3030
hero_body = world.CreateBody(&hero_def);
3131

32-
auto hero_box = b2PolygonShape();
33-
hero_box.SetAsBox(0.5f, 0.5f);
32+
auto hero_box = b2CircleShape();
33+
hero_box.m_radius = 0.48f;
3434

3535
auto hero_fixture_def = b2FixtureDef();
3636
hero_fixture_def.shape = &hero_box;
37-
hero_fixture_def.density = 32.0f;
38-
hero_fixture_def.friction = 3.0f;
37+
hero_fixture_def.density = 16.0f;
38+
hero_fixture_def.friction = 30.0f;
3939

4040
hero_body->CreateFixture(&hero_fixture_def);
4141
}

0 commit comments

Comments
 (0)