Skip to content

Commit

Permalink
cmp: Improve physics and character state
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Fahien committed Jan 5, 2021
1 parent 3284f19 commit f0a6b33
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 39 deletions.
4 changes: 2 additions & 2 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Copyright (c) 2019-2020 Angelo Theodorou
Copyright (c) 2020 Antonio Caggiano
Copyright © 2019-2020 Angelo Theodorou
Copyright © 2020-2021 Antonio Caggiano

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
Expand Down
2 changes: 1 addition & 1 deletion cmake/package_info.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
set(PACKAGE_NAME "ncJump")
set(PACKAGE_EXE_NAME "ncjump")
set(PACKAGE_VENDOR "Antonio Caggiano")
set(PACKAGE_COPYRIGHT "Copyright © 2020 ${PACKAGE_VENDOR}")
set(PACKAGE_COPYRIGHT "Copyright © 2020-2021 ${PACKAGE_VENDOR}")
set(PACKAGE_DESCRIPTION "A jumping project made with the nCine")
set(PACKAGE_HOMEPAGE "https://antoniocaggiano.eu")
set(PACKAGE_REVERSE_DNS "eu.antoniocaggiano.ncjump")
Expand Down
8 changes: 5 additions & 3 deletions include/component/physics.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ struct PhysicsComponent {

b2Body* body = nullptr;

DirectionFlags obstacle;

f32 air_factor = 1.0f / 16.0f;
f32 velocity_factor = 64.0f;
f32 jump_y_factor = 360.0f;
f32 velocity_factor = 32.0f;
f32 jump_y_factor = 160.0f;
f32 jump_x_factor = 3.0f;
f32 max_x_speed = 8.0f;
f32 max_x_speed = 6.0f;
};

} // namespace jmp
82 changes: 81 additions & 1 deletion include/types.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#pragma once

#include <cassert>
#include <cstdint>
#include <optional>
#include <string>

#include <ncine/Vector2.h>
#include <ncine/common_macros.h>
Expand All @@ -16,11 +18,89 @@ using f32 = float;
using Vec2i = nc::Vector2<i32>;
using Vec2u = nc::Vector2<u32>;
using Vec2f = nc::Vector2<f32>;
constexpr auto None = std::nullopt;

#define OPTION std::optional
#define NONE std::nullopt
#define UNIQUE nctl::UniquePtr
#define MK nctl::makeUnique
#define MV nctl::move

#define PATH(path) nc::fs::joinPath(nc::fs::dataPath(), path).data()

enum class DirectionFlags {
NONE = 0,
UP = 1 << 0,
DOWN = 1 << 1,
LEFT = 1 << 2,
RIGHT = 1 << 3,
};

constexpr inline DirectionFlags operator~(DirectionFlags a)
{
return (DirectionFlags) ~(i32)a;
}

constexpr inline DirectionFlags operator|(DirectionFlags a, DirectionFlags b)
{
return (DirectionFlags)((i32)a | (i32)b);
}

constexpr inline DirectionFlags operator&(DirectionFlags a, DirectionFlags b)
{
return (DirectionFlags)((i32)a & (i32)b);
}
constexpr inline DirectionFlags operator^(DirectionFlags a, DirectionFlags b)
{
return (DirectionFlags)((i32)a ^ (i32)b);
}

constexpr inline DirectionFlags& operator|=(DirectionFlags& a, DirectionFlags b)
{
return (DirectionFlags&)((i32&)a |= (i32)b);
}

constexpr inline DirectionFlags& operator&=(DirectionFlags& a, DirectionFlags b)
{
return (DirectionFlags&)((i32&)a &= (i32)b);
}

constexpr inline DirectionFlags& operator^=(DirectionFlags& a, DirectionFlags b)
{
return (DirectionFlags&)((i32&)a ^= (i32)b);
}

constexpr inline bool any(DirectionFlags a)
{
return a != DirectionFlags::NONE;
}

static std::string to_str(DirectionFlags a)
{
if (a == DirectionFlags::NONE) {
return "NONE";
}

std::string ret;

if (any(a & DirectionFlags::UP)) {
ret += "UP, ";
}

if (any(a & DirectionFlags::DOWN)) {
ret += "DOWN, ";
}

if (any(a & DirectionFlags::LEFT)) {
ret += "LEFT, ";
}

if (any(a & DirectionFlags::RIGHT)) {
ret += "RIGHT, ";
}

// Remove last ", "
assert(ret.length() > 2);
ret.resize(ret.length() - 2);

return ret;
}
33 changes: 29 additions & 4 deletions src/component/physics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ PhysicsComponent::PhysicsComponent(PhysicsComponent&& o)
: physics {o.physics}
, body {o.body}
, air_factor {o.air_factor}
, velocity_factor {64.0f}
, jump_y_factor {360.0f}
, jump_x_factor {3.0f}
, max_x_speed {8.0f}
, velocity_factor {o.velocity_factor}
, jump_y_factor {o.jump_y_factor}
, jump_x_factor {o.jump_x_factor}
, max_x_speed {o.max_x_speed}
{
o.body = nullptr;
}
Expand Down Expand Up @@ -66,6 +66,31 @@ void PhysicsComponent::update()
{
assert(body && "Physics component has no body");

// Update some variables
obstacle = DirectionFlags::NONE;
for (auto edge = body->GetContactList(); edge; edge = edge->next) {
auto normal = edge->contact->GetManifold()->localNormal;
if (edge->contact->GetFixtureA() == body->GetFixtureList()) {
normal = -normal;
}

if (normal.x < -0.9f) {
obstacle |= DirectionFlags::RIGHT;
}

if (normal.x > 0.9f) {
obstacle |= DirectionFlags::LEFT;
}

if (normal.y > 0.9f) {
obstacle |= DirectionFlags::DOWN;
}

if (normal.y < -0.9f) {
obstacle |= DirectionFlags::UP;
}
}

// Apply air resistance
auto vel = -body->GetLinearVelocity();
auto vel_len = vel.LengthSquared();
Expand Down
42 changes: 23 additions & 19 deletions src/component/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,7 @@ void IdleState::enter(const Input& input, Entity& entity)
void can_fall(const Input& input, Entity& entity)
{
// Can fall if there is no platform below
bool should_fall = true;

for (auto edge = entity.physics->body->GetContactList(); edge; edge = edge->next) {
auto normal = edge->contact->GetManifold()->localNormal;
if (edge->contact->GetFixtureA() == entity.physics->body->GetFixtureList()) {
normal = -normal;
}
if (normal.y > 0.5f) {
should_fall = false;
break;
}
}
bool should_fall = !any(entity.physics->obstacle & DirectionFlags::DOWN);

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

// Applying a force to move in the opposite direction of current velocity is always allowed
bool opposite_move = (input.joystick.move.x < 0 && x_velocity >= 0) ||
(input.joystick.move.x >= 0 && x_velocity < 0);

// Make sure current velocity is within limits, otherwise do not apply further force
bool within_limit =
fabs(entity.physics->body->GetLinearVelocity().x) < entity.physics->max_x_speed;

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

void JumpUpState::enter(const Input& input, Entity& entity)
{
entity.physics->body->GetFixtureList()->SetFriction(0.0f);

entity.transform.node->addChildNode(&CHAR_GFX(entity).jump_up);

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

void JumpUpState::exit(Entity& entity)
{
entity.physics->body->GetFixtureList()->SetFriction(3.0f);
entity.transform.node->removeChildNode(&CHAR_GFX(entity).jump_up);
}

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

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

void JumpDownState::handle(const Input& input, Entity& entity)
{
for (auto edge = entity.physics->body->GetContactList(); edge; edge = edge->next) {
auto& normal = edge->contact->GetManifold()->localNormal;
if (normal.y != 0.0) {
LOGI_X("Normal (%f, %f)", normal.x, normal.y);
CHAR_STT(entity).set_state(State::MOVE, input, entity);
break;
}
if (any(entity.physics->obstacle & DirectionFlags::DOWN)
) {
CHAR_STT(entity).set_state(State::MOVE, input, entity);
}
}

void JumpDownState::update(const f32, const Input& input, Entity& entity)
{
// Can move a bit
can_move_on_x(input, entity, entity.physics->jump_x_factor);

// Make sure it goes down
if (entity.physics->body->GetLinearVelocity().y > -1.0) {
entity.physics->body->ApplyForceToCenter({0.0, -100.0f}, true);
}
}

void JumpDownState::exit(Entity& entity)
{
auto fixture = entity.physics->body->GetFixtureList();
fixture->SetFriction(3.0f);

for (auto edge = entity.physics->body->GetContactList(); edge; edge = edge->next) {
edge->contact->ResetFriction();
}

entity.transform.node->removeChildNode(&CHAR_GFX(entity).jump_down);
}

Expand Down
2 changes: 2 additions & 0 deletions src/editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ void Editor::update_physics(PhysicsComponent& physics)
auto vel = physics.body->GetLinearVelocity();
ImGui::Text("vel: { x: %.2f, y: %.2f }", vel.x, vel.y);

ImGui::Text("obstacle: { %s }", to_str(physics.obstacle).c_str());

if (ImGui::TreeNode("Contacts")) {
for (auto edge = physics.body->GetContactList(); edge; edge = edge->next) {
auto normal = edge->contact->GetManifold()->localNormal;
Expand Down
7 changes: 4 additions & 3 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ Game::Game(Config& config)
void Game::update(const float dt)
{
// Update game state
physics.update(dt);

entity.update(dt, input);
editor.update();
physics.update(dt);

// @todo Move this somewhere else?
// Update entity from box
// @todo Move this somewhere else? Possibly PhysicsSystem?
// Update entity from body
auto& pos = physics.hero_body->GetPosition();
entity.transform.node->x = config.size.tile * pos.x + config.size.tile / 2.0f;
entity.transform.node->y = config.size.tile * pos.y + config.size.tile / 2.0f;
Expand Down
12 changes: 6 additions & 6 deletions src/physics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace jmp
{
Physics::Physics(f32 x, f32 y)
: gravity {0.0, -20.0f}
: gravity {0.0, -30.0f}
, world {gravity}
{
// Ground body
Expand All @@ -25,17 +25,17 @@ Physics::Physics(f32 x, f32 y)
auto hero_def = b2BodyDef();
hero_def.type = b2_dynamicBody;
hero_def.position.Set(x, y);
hero_def.fixedRotation = true;
hero_def.angularDamping = 100.0;

hero_body = world.CreateBody(&hero_def);

auto hero_box = b2PolygonShape();
hero_box.SetAsBox(0.5f, 0.5f);
auto hero_box = b2CircleShape();
hero_box.m_radius = 0.48f;

auto hero_fixture_def = b2FixtureDef();
hero_fixture_def.shape = &hero_box;
hero_fixture_def.density = 32.0f;
hero_fixture_def.friction = 3.0f;
hero_fixture_def.density = 16.0f;
hero_fixture_def.friction = 30.0f;

hero_body->CreateFixture(&hero_fixture_def);
}
Expand Down

0 comments on commit f0a6b33

Please sign in to comment.