Here is my character controller using Sparky's collision, I still have to rewrite portions of it (OK, most of it, I need to integrate PhysX into it), but you should be able to take from it what you need.
This references a few global variables not references, such as "frameSpeedMod" which I used for timer based movement.
EDIT: It appears my code is too large for a code box, oh well.
#include "DarkGDK.h"
#include "SC_Collision.h"
// Collision
int collide; // For detecting player collision with the game world
float camStartX; // For detecting camera collision with world
float camStartY; // For detecting camera collision with world
float camStartZ; // For detecting camera collision with world
float camEndX; // For detecting camera collision with world
float camEndY; // For detecting camera collision with world
float camEndZ; // For detecting camera collision with world
float deltaMousePositionX; // For detecting camera collision with world
float deltaMousePositionY; // For detecting camera collision with world
// Character control
float moveSpeed; // Total movement speed
float walkSpeed = 1.0f; // Default walk speed
float runSpeed = 2.0f; // Default run speed
float hasteSpeed = 0.0f; // Increases movement speed
float snareSpeed = 0.0f; // Decreases movement speed
int cameraScroll = -25; // How far the camera-sphere is offset from the player
float gravity = -0.0981f; // How fast you accelerate due to gravity
float slope = 0.65f; // Increasing this value means decreases how steep an incline you can traverse
int ground = 1; // Used internally to determine when the player is airborne
int jumpTimer = 0; // Default of zero
int jumpDelay = 8; // The delay between when you land and when you can jump again.
int playerHeight = 20; // How tall the player is, really just increases the height of the camera
float radius = 0.01f; // The collision radius of the default player sphere
//player movement vectors
float moveVectorX = 0; // For calculating player position
float moveVectorY = 0; // For calculating player position
float moveVectorZ = 0; // For calculating player position
float lastVectorX = 0; // For calculating player position
float lastVectorZ = 0; // For calculating player position
float playerPositionX; // For calculating player position
float playerPositionY; // For calculating player position
float playerPositionZ; // For calculating player position
float angleY; // For calculating player position
float newY; // For calculating player position
float oldX; // For calculating player position
float oldY; // For calculating player position
float oldZ; // For calculating player position
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Control the character with WASD and mouse look
void mouseWASD() {
dbHideMouse();
// Calculates move speed, press the SHIFT key to run
if (dbShiftKey() == 1 && ground == 1) { moveSpeed = (runSpeed + hasteSpeed - snareSpeed) * frameSpeedMod; } else if (ground == 1) { moveSpeed = (walkSpeed + hasteSpeed - snareSpeed) * frameSpeedMod; }
if (moveSpeed < 0) { moveSpeed = 0; }
oldX = dbObjectPositionX(20001);
oldY = dbObjectPositionY(20001);
oldZ = dbObjectPositionZ(20001);
// Applies gravity
angleY = dbObjectAngleY(20001);
moveVectorX = moveVectorZ = 0;
// Normal gravity when jumping or falling, otherwise keeps the player on the ground
if (moveVectorY == 0) { moveVectorY += 10 * gravity * frameSpeedMod * frameSpeedMod; } else { moveVectorY += gravity * frameSpeedMod * frameSpeedMod; }
// Forward, reverse, straffing movement
// W = 17, A = 30, S = 31, D = 32
if (ground == 1) {
lastVectorX = lastVectorZ = 0;
if (dbKeyState(30) == 1) { lastVectorX = moveVectorX += dbCos(angleY) * moveSpeed; lastVectorZ = moveVectorZ -= dbSin(angleY) * moveSpeed; }
if (dbKeyState(32) == 1) { lastVectorX = moveVectorX -= dbCos(angleY) * moveSpeed; lastVectorZ = moveVectorZ += dbSin(angleY) * moveSpeed; }
if (dbKeyState(17) == 1) { lastVectorX = moveVectorX -= dbSin(angleY) * moveSpeed; lastVectorZ = moveVectorZ -= dbCos(angleY) * moveSpeed; }
if (dbKeyState(31) == 1) { lastVectorX = moveVectorX += dbSin(angleY) * moveSpeed; lastVectorZ = moveVectorZ += dbCos(angleY) * moveSpeed; }
}
// Can't change movement path once airborne
if (ground == 0) { moveVectorX += lastVectorX; moveVectorZ += lastVectorZ; }
// Only jump if on the ground
if (ground == 1) { if (dbSpaceKey() == 1 && jumpTimer == 0) { moveVectorY += (3.0f * frameSpeedMod); jumpTimer = jumpDelay; } }
// Player's final position without collision
playerPositionX = oldX + moveVectorX;
playerPositionY = oldY + moveVectorY;
playerPositionZ = oldZ + moveVectorZ;
collide = SC_SphereCastGroup(1, oldX, oldY, oldZ, oldX, oldY + moveVectorY, oldZ, radius, 0);
// Start if
if (collide) {
newY = SC_GetCollisionNormalY();
if (dbAbs(newY) > slope) {
//FLAT, stick
oldY = SC_GetStaticCollisionY();
//STEEP, slide
} else {
playerPositionX -= oldX; playerPositionZ -= oldZ; oldX = SC_GetCollisionSlideX();
oldY = SC_GetCollisionSlideY(); oldZ = SC_GetCollisionSlideZ();
playerPositionX += oldX; playerPositionZ += oldZ;
}
if ( newY > slope ) {
// Only on ground if standing on flat ground
ground = 1;
moveVectorY = 0;
//if player has hit a flat ceiling then stop vy# movement
} else { ground = 0; if ( newY < -slope ) { moveVectorY = gravity; } }
//nothing below player, not on ground, add vertical speed to player
} else { oldY += moveVectorY; ground = 0; }
if (ground == 1 && jumpTimer > 0 ) { jumpTimer--; }
// Detects collision with object group 1
collide = SC_SphereSlideGroup(1, oldX, oldY, oldZ, playerPositionX, oldY, playerPositionZ, radius, 0);
// Detects collision with the ground
if (collide > 0) {
playerPositionX = SC_GetCollisionSlideX();
oldY = SC_GetCollisionSlideY();
playerPositionZ = SC_GetCollisionSlideZ();
moveVectorZ = moveVectorX = 0;
}
// Start position of camera obejct
camStartX = dbObjectPositionX(20000);
camStartY = dbObjectPositionY(20000);
camStartZ = dbObjectPositionZ(20000);
// Rotates objects
dbYRotateObject(20001, dbObjectAngleY(20001) + (deltaMousePositionX = dbMouseMoveX()));
dbXRotateObject(20000, dbObjectAngleX(20000) + (deltaMousePositionY = dbMouseMoveY() * 0.3f));
// End position of camera object
camEndX = dbObjectPositionX(20001) - dbSin(dbObjectAngleY(20001)) * cameraScroll;
camEndY = dbObjectPositionY(20001) + playerHeight - dbSin(dbObjectAngleX(20001)) * cameraScroll;
camEndZ = dbObjectPositionZ(20001) - dbCos(dbObjectAngleY(20001)) * cameraScroll;
// Limits the rotation of the camera
if (dbObjectAngleX(20000) < -10) { dbXRotateObject(20000, -10); }
if (dbObjectAngleX(20000) > 70) { dbXRotateObject(20000, 70); }
// Un-does player rotation if collision detected
if (SC_SphereCastGroup(1, camStartX, camStartY, camStartZ, camEndX, camEndY, camEndZ, 4.5, 0) > 0) {
dbYRotateObject(20001, dbObjectAngleY(20001) - deltaMousePositionX);
dbXRotateObject(20000, dbObjectAngleY(20000) - deltaMousePositionY);
}
// Resets the mouse to the center of the screen
dbPositionMouse(screenSizeX / 2, screenSizeY / 2);
// Updates the players position
dbPositionObject(20001, playerPositionX, oldY, playerPositionZ);
SC_UpdateObject(20001);
// Position the player camera sphere
dbPositionObject(20000, dbObjectPositionX(20001) - dbSin(dbObjectAngleY(20001)) * cameraScroll, (dbObjectPositionY(20001) + playerHeight) - dbSin(dbObjectAngleX(20000)) * cameraScroll, dbObjectPositionZ(20001) - dbCos(dbObjectAngleY(20001)) * cameraScroll);
// Position the camera
dbPositionCamera(dbObjectPositionX(20000), dbObjectPositionY(20000), dbObjectPositionZ(20000));
dbPointCamera(playerPositionX, oldY + playerHeight, playerPositionZ);
// Offsets the camera for an "over the shoulder" look
dbMoveCameraRight(0, 3.5f);
}
------------------------------------
Currently 1300+ lines of code into an "over-the-shoulder" action RPG with combat based on rag-doll physics.