🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Slopey McSlopeface (part 1)

posted in The Berg for project The Berg
Published September 22, 2018
Advertisement

Hmmm, I love sausage rolls. 

Oh sorry, just having a tasty sausage roll for my lunch while thinking about the problem of... slopes.

So I have this nice terrain an' all, that I can now walk around on.  But those hills aren't exactly challenging my player character.  I breeze up those as easily as I descend a vertical drop.  Why is that?  Because I'm just making the player follow the terrain like it's on rails, that's why!  No fancy pants physics engines here guv.

I need to make the player ascend steep inclines more slowly than flat terrain and also come to a halt against any vertical, or near-vertical inclines.  I also need to make the player fall or tumble if they attempt to go down any incline too steep... but that's for another blog.

I first messed around with attempting to stop the player if they tried to walk up anything with a gradient over a certain threshold... that didn't work out too well.  Lots of jittery movement ensued.  Then I realised my approach was all wrong!  When I climb a steep hill, I don't just come to a dead stop in reality, I just move more slowly as I ascend.  So this just became a case of factoring in the terrain gradient to my player speed... simples!


// Test slope in direction of travel
let direction = new THREE.Vector3().copy( this.collisionBody.resolveMoves().normalize() );
let p1 = new THREE.Vector3().copy( this.position );
let intersection1 = _this.terrain.heightAt( p1.x, p1.z );

let p2 = new THREE.Vector3().addVectors( this.position, direction );
let intersection2 = _this.terrain.heightAt( p2.x, p2.z );

let grad = intersection2.h - intersection1.h;
_this.playerController.currentSpeed = Math.clamp( -_this.playerController.DEFAULT_SPEEDS.WALKING * grad + _this.playerController.DEFAULT_SPEEDS.WALKING, 0, 2 );

Works a treat.... except (sigh) when I'm up against a near vertical incline.  I can still climb those, just a bit more slowly (sigh).  In fact, no, this doesn't look right at all.  The graident should be so large when approaching a near vertical incline that it should reduce my speed to 0.  But for some reason I get this....

TheBerg-SlopeyMcSlopeface-01.mp4

Much head scratching ensued!

Then I realised it must be something to do with the order of processing.  The way I handle movement is through a "CollisionBody" object which is attached to the player.  I call a "move" function on the CollisionBody which basically stores it in an array until the "PhysicsManager" decides to resolve it (reminder: there is no fancy physics going on at all yet... I just decided to call it a PhysicsManager).  The thing is, my PlayerController was calling "move" before I had changed my speed to zero, so the movement vectors were already baked in (I know, I know, this is getting complicated already!) and changing the speed did nothing.  Each alternate frame I was then resetting my speed back to normal walking speed....

You know, it's only when I write all that down I see just how crazy dumb it was!  ?

So I decided on an alternative approach.  Instead of setting an absolute velocity vector when calling CollisionBody.move I now pass a direction vector and speed as a new Velocity object... however... the speed doesn't have to be a number... it can be a function!  Thereby I can delay the resolution of the velocity until absolutely necessary (i.e. when the PhysicsManager needs to apply the moves).  It may sound complicated but I quite like it.  I can then make any other adjustments to the speed (not velocity) during the frame update and it will take effect when the PhysicsManager resolves everything!

e.g.

  1. PlayerController handles movement -> player.collisionBody.move( new Velocity( direction, () => player.speed )
  2. Player object "update" tests for slopes and adjusts speed accordingly
  3. PhysicsManager "update" resolves all player.collisionBody movements, in turn resolving all Velocity values using the new updated speed rather than the speed as it was in step 1

So how does this work out now?

TheBerg-SlopeyMcSlopeface-02.mp4

Better... if you watch very closely you might notice I've added in a subtle acceleration too which gives a smoother feel to the player movement (later I'll add in head bobbing).  However, I'm still not entirely happy with it.  When you stop the player doesn't decelerate, but comes to an abrupt stop... which is fine but feels a little unnatural.  Near vertical inclines are also handled better, although I still find with the "right" movements I can still climb them so I definitely need to work on this more.

Acceleration is done by adding in a targetSpeed property on the Player, so the actual speed will accelerate towards that speed until it is reached.  It does decelerate too as the incline increases, but when you lift your key from the keyboard the direction vector is reset to {0, 0, 0} so the speed has no effect.  :(

I'll have a think a bit more about this later.  Ideas and suggestions are welcome!

 

1 likes 0 comments

Comments

Awoken

What will we do on this berg?  so many possibilities.  

September 22, 2018 07:50 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement