I have attached the code for my "Character Controller" which rely's on functions from Sparky's Collisions and a few functions and variables defined elsewhere in my code, such as "frameSpeedMod" which is used for my implementation of timer based movement. Also attached is my game in its current state so that you can see how my code actually works.
** Global.h is a file included by every source code file in my project, it includes references to a few header files needed by all my source files as well as some variable and function definitions.
EDT: Just thought I should clarify in case anyone does download my game. You need to hit the "New Game" and than "Start Game" buttons. You use the WASD keys and the mouse to navigate, press the shift key to run and space to jump. Most of the items you see on the menu's don't actually do anything. All my models in the game world are place-holders.
CharacterControl.h
#pragma once
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Character control
extern float moveSpeed; // Initiated the variable
extern float walkSpeed; // Default walk speed
extern float runSpeed; // Default run speed
extern float hasteSpeed; // Increases movement speed
extern float snareSpeed; // Decreases movement speed
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void mouseWASD(void);
CharacterControl.cpp
#include "Global.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 = 2.0f; // Default walk speed
float runSpeed = 5.5f; // Default run speed
float hasteSpeed = 0.0f; // Increases movement speed
float snareSpeed = 0.0f; // Decreases movement speed
int cameraScroll = -40; // How far the camera-sphere is offset from the player
float gravity = -0.13f; // 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 = 10.0f; // 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; } else { moveVectorY += gravity * 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.8f * 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;
}
// Rotates objects
dbYRotateObject(20001, dbObjectAngleY(20001) + dbMouseMoveX());
dbXRotateObject(20000, dbObjectAngleX(20000) + dbMouseMoveY() * 0.3f);
// Limits the rotation of the camera
if (dbObjectAngleX(20000) < -90) { dbXRotateObject(20000, -90); }
if (dbObjectAngleX(20000) > 90) { dbXRotateObject(20000, 90); }
// 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);
dbPositionObject(20002, playerPositionX, oldY - radius, playerPositionZ);
dbSetObjectToObjectOrientation(20002, 20001);
SC_UpdateObject(20002);
if (SC_MultipleRayCastGroup(1, dbObjectPositionX(20001), dbObjectPositionY(20001), dbObjectPositionZ(20001), camEndX = dbObjectPositionX(20001) - dbSin(dbObjectAngleY(20001)) * cameraScroll, camEndY = (dbObjectPositionY(20001) + playerHeight) - dbSin(dbObjectAngleX(20000)) * cameraScroll, camEndZ = dbObjectPositionZ(20001) - dbCos(dbObjectAngleY(20001)) * cameraScroll, 0) > 0) {
camEndX = SC_GetStaticCollisionX();
camEndY = SC_GetStaticCollisionY();
camEndZ = SC_GetStaticCollisionZ();
}
// Position the player camera sphere
dbPositionObject(20000, camEndX, camEndY, camEndZ);
// 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, 4.5f);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
------------------------------------
Currently 1500+ lines of code into an "over-the-shoulder" action RPG with combat based on rag-doll physics.