Added custom movement code for when player is noclipping.

This commit is contained in:
2025-03-31 16:37:31 -04:00
parent d9d8f7f3a2
commit 15d816f04f
3 changed files with 181 additions and 119 deletions

View File

@@ -56,6 +56,22 @@ void CaveGame::Core::Player::Update(float elapsed) {
Vector2 dpad = jstick::GetDPadAxisNormalized();
if (noclip) {
if (InputService::IsKeyDown(Keys::A) || dpad.x <= -0.5f)
Accelerate({-500*elapsed, 0});
if (InputService::IsKeyDown(Keys::D) || dpad.x >= +0.5f)
Accelerate({500*elapsed, 0});
if (InputService::IsKeyDown(Keys::W) || dpad.y <= -0.5f)
Accelerate({0, -500*elapsed});
if (InputService::IsKeyDown(Keys::S) || dpad.y >= 0.5f)
Accelerate({0, 500*elapsed});
return;
}
if (InputService::IsKeyDown(Keys::A) || dpad.x <= -0.5f)
WalkLeft(elapsed);

View File

@@ -9,7 +9,6 @@
/// @edit 1/28/2025
/// @auth Josh O'Leary
#pragma once
#include <Core/Entity.hpp>
@@ -19,6 +18,10 @@ namespace CaveGame::Core
{
class PhysicsEntity : public Entity {
public:
constexpr static const float gravity = 9.81f;
constexpr static const float air_resistance = 2.45f;
bool freeze_in_void = true;
explicit PhysicsEntity(const Vector2& spawnPoint);
@@ -30,123 +33,25 @@ namespace CaveGame::Core
virtual void PhysicsUpdate(float elapsed);
// TODO: Mechanism for figuring out if you're already stuck inside of tiles: i.e. sand
void CollisionTest(ITileMap* map, float elapsed) override {
void CollisionTest(ITileMap* map, float elapsed) override;
coll_tests = 0;
coll_hits = 0;
void Update(float elapsed) override;
for (int x = -1; x <= bounding_box.x; x++) {
for (int y = -1; y <= bounding_box.y; y++) {
Vector2 coll_topleft = next_position - (bounding_box / 2.f);
Vector2 tileBoxPos = Vector2(Math::Floor(coll_topleft.x), Math::Floor(coll_topleft.y)) + Vector2(x,y);
TileID id = map->GetTile(tileBoxPos.x, tileBoxPos.y);
if (id == Tiles()["void"].numeric_id) {
if (freeze_in_void)
{
velocity = {0,0};
next_position = position;
return;
}
continue;
}
if (id == Tiles()["air"].numeric_id)
continue;
coll_tests++;
Vector2 entity_centroid = next_position; // + (bounding_box / 2.f);
Vector2 entity_halfbox = bounding_box / 2.f;
Vector2 tile_centroid = tileBoxPos + Vector2{0.5f, 0.5f};
Vector2 tile_halfbox = Vector2{0.5f, 0.5f};
if (Solver::AABB2Dvs(entity_centroid, entity_halfbox, tile_centroid, tile_halfbox)) {
coll_hits++;
Vector2 separation = Solver::SolveAABB(entity_centroid, entity_halfbox, tile_centroid, tile_halfbox);
Vector2 normal = Solver::GetNormalForAABB(separation, velocity);
//std::cout << std::format("Solved: Sep: {},{}, Norm: {},{}", separation.x, separation.y, normal.x, normal.y) << std::endl;
if (normal.x == 0 && normal.y == 0)
continue;
// Touched top.
if (normal.y == -1)
{
velocity.y = 0;
on_ground = true;
//std::cout << "Touched your feet" << std::endl;
}
if (normal.y == 1) {
velocity.y = -velocity.y*0.5f;
std::cout << "Touched your head" << std::endl;
}
if (normal.x == -1)
{
//std::cout << "Touched your right" << std::endl;
}
if (normal.x == 1)
{
//std::cout << "Touched your left" << std::endl;
}
// TODO: Refine condition for "step-up"s
if (normal.x != 0 && Math::Abs(velocity.x) > 10 && on_ground) {// && Math::Abs(velocity.y) < 2 ) {
//std::cout << "Step up" << std::endl;
next_position.y -= 1;
//next_position.x -= normal.x;
velocity.y -= climbing_skill;
velocity.x *= 0.75f;
}
next_position += separation;
//next_position += separation;
//return;
}
}
}
}
void Update(float elapsed) override {
if (!on_ground)
airtime += elapsed;
else
airtime = 0;
// TODO: Sophisticated mechanism to maintain locked-timestep, multiple-iteration physics steps.
PhysicsUpdate(elapsed);
}
virtual inline float Mass() { return 40;}
protected:
Vector2 velocity;
Vector2 next_position;
float mass;
int coll_tests;
int coll_hits;
Vector2 last_normal;
private:
void ApplyHorizontalFriction(float elapsed);
void ApplyGravityForce(float elapsed);
void ApplyAirResistance(float coefficient, float elapsed);
};
}

View File

@@ -15,27 +15,168 @@ namespace CaveGame::Core
velocity += vector;
}
void PhysicsEntity::ApplyHorizontalFriction(float elapsed)
{
float base_friction_coefficient = 4.f;
velocity.x *= (1 - (elapsed * base_friction_coefficient));
}
void PhysicsEntity::ApplyGravityForce(float elapsed)
{
velocity.y += (elapsed*gravity*Mass());
}
void PhysicsEntity::Update(float elapsed) {
if (!on_ground)
airtime += elapsed;
else
airtime = 0;
// TODO: Sophisticated mechanism to maintain locked-timestep, multiple-iteration physics steps.
PhysicsUpdate(elapsed);
}
void PhysicsEntity::ApplyAirResistance(float coefficient, float elapsed)
{
velocity *= (1 - (elapsed * coefficient));
}
void PhysicsEntity::PhysicsUpdate(float elapsed) {
if (noclip)
{
on_ground = true;
next_position += velocity * elapsed;
ApplyAirResistance(air_resistance*4, elapsed);
position = next_position;
return;
}
next_position += velocity * elapsed;
float air_resistance = 2.45f;
float base_friction_coefficient = 4.f;
float gravity = 9.81f;
float mass = 40.f;
if (Math::Abs(velocity.y) > 1e-2f)
if (Math::Abs(velocity.y) > 2)
on_ground = false;
// Simulate friction.
if (on_ground)
velocity.x *= (1 - (elapsed * base_friction_coefficient));
ApplyHorizontalFriction(elapsed);
// Air resistance.
velocity *= (1 - (elapsed * air_resistance));
velocity.y += (elapsed*gravity*mass);
ApplyAirResistance(air_resistance, elapsed);
ApplyGravityForce(elapsed);
position = next_position;
}
void PhysicsEntity::CollisionTest(ITileMap *map, float elapsed) {
if (noclip)
return;
coll_tests = 0;
coll_hits = 0;
for (int x = -1; x <= bounding_box.x; x++) {
for (int y = -1; y <= bounding_box.y; y++) {
Vector2 coll_topleft = next_position - (bounding_box / 2.f);
Vector2 tileBoxPos = Vector2(Math::Floor(coll_topleft.x), Math::Floor(coll_topleft.y)) + Vector2(x,y);
TileID id = map->GetTile(tileBoxPos.x, tileBoxPos.y);
if (id == Tiles()["void"].numeric_id) {
if (freeze_in_void)
{
velocity = {0,0};
next_position = position;
return;
}
continue;
}
if (id == Tiles()["air"].numeric_id)
continue;
// TODO: Profile this bit.
if (Tiles().GetByNumericID(id).solid == false)
continue;
coll_tests++;
Vector2 entity_centroid = next_position; // + (bounding_box / 2.f);
Vector2 entity_halfbox = bounding_box / 2.f;
Vector2 tile_centroid = tileBoxPos + Vector2{0.5f, 0.5f};
Vector2 tile_halfbox = Vector2{0.5f, 0.5f};
if (Solver::AABB2Dvs(entity_centroid, entity_halfbox, tile_centroid, tile_halfbox)) {
coll_hits++;
Vector2 separation = Solver::SolveAABB(entity_centroid, entity_halfbox, tile_centroid, tile_halfbox);
Vector2 normal = Solver::GetNormalForAABB(separation, velocity);
//std::cout << std::format("Solved: Sep: {},{}, Norm: {},{}", separation.x, separation.y, normal.x, normal.y) << std::endl;
if (normal.x == 0 && normal.y == 0)
continue;
// Touched top.
if (normal.y == -1)
{
velocity.y = 0;
on_ground = true;
//std::cout << "Touched your feet" << std::endl;
}
if (normal.y == 1) {
velocity.y = -velocity.y*0.5f;
std::cout << "Touched your head" << std::endl;
}
if (normal.x == -1)
{
//std::cout << "Touched your right" << std::endl;
}
if (normal.x == 1)
{
//std::cout << "Touched your left" << std::endl;
}
// TODO: Refine condition for "step-up"s
if (normal.x != 0 && Math::Abs(velocity.x) > 10 && on_ground) {// && Math::Abs(velocity.y) < 2 ) {
//std::cout << "Step up" << std::endl;
next_position.y -= 1;
//next_position.x -= normal.x;
velocity.y -= climbing_skill;
velocity.x *= 0.75f;
}
next_position += separation;
//next_position += separation;
//return;
}
}
}
}
}