Attached is some code which was an experiment of mine. I wanted to create the effect that the camera was separate from the player and smoothly moved to its position. I also experimented with a different type of collision system for the camera. It can clip walls but is difficult, most times you need to force it, the camera will clip if you set the speed of the player too fast. If you fall off the edge of a cliff the camera will move upwards as well as dodge the wall to get a better view of the player. I haven't tested it in every situation but it does great in turning sharp corners. This code would suit an RPG like The Lord of The Rings The Third Age. Use guard model for testing. Use WSAD keys to move the player and the mouse for moving the camera. The animations are blended and the code is the neatest I have ever done. Let me know what you think. I hope you enjoy!

----------------------------------------------------------------
string current_player_frame = " ";

DEFINE animate,skill20;
DEFINE animate2,skill21;
DEFINE move_x,skill22;
DEFINE move_y,skill23;
DEFINE move_z,skill24;
DEFINE force_x,skill25;
DEFINE force_y,skill26;
DEFINE force_z,skill27;
DEFINE velocity_x,skill28;
DEFINE velocity_y,skill29;
DEFINE velocity_z,skill30;
DEFINE pan_to,skill31;
DEFINE pan_force,skill32;
DEFINE pan_velocity,skill33;
DEFINE stand_blend,skill34;
DEFINE walk_blend,skill35;
DEFINE run_blend,skill36;
DEFINE jump_blend,skill37;
DEFINE jumping_mode,skill38;
DEFINE begin_fall,skill39;

//camera variables
var camera_force[3];
var camera_velocity[3];
var camera_move_to[3];
var camera_pan_direction = 0;
var camera_pan_to;
var camera_pan_force;
var camera_pan_velocity;
var camera_tilt_offset = 0;
var camera_tilt_to;
var camera_tilt_force;
var camera_tilt_velocity;
var camera_height = 70; //current height
var camera_height_main = 70; //set height to move to
var camera_distance = 180; //current distance camera is from player
var camera_radius = 180; //maximum distance camera will move to from player
var camera_radius_force;
var camera_radius_velocity;
var camera_radius_move_to;
var dist_traced; //similar to result, used to store trace instructions

ACTION player_action {
my.shadow = on;
my.fat = off;
my.narrow = on;
WHILE (1) {
IF (my.jumping_mode == 0) && (my.begin_fall == 0) { player_walk(); }
player_gravity();
camera_move();
move_mode = glide;
ent_move(nullvector,my.move_x);
wait(1);
}
}

FUNCTION player_walk() {
my.force_x = 0;
my.force_y = 0;
IF (key_w == 1 || key_s == 1 || key_a == 1 || key_d == 1) {
IF (key_shift == 1) {
IF (my.stand_blend == 1) { str_cpy(current_player_frame,"stand"); }
IF (my.run_blend == 1) { str_cpy(current_player_frame,"run"); }
IF (my.walk_blend == 0) {
my.stand_blend = 0;
my.run_blend = 0;
my.walk_blend = 1;
my.animate2 = my.animate;
my.animate = 0;
}
IF (my.walk_blend == 2) {
ent_cycle("walk",my.animate);
my.animate += 9 * time;
str_cpy(current_player_frame,"walk");
} ELSE {
ent_cycle(current_player_frame,my.animate2);
ent_blend("walk",0,my.animate);
my.animate += 40 * time;
IF (my.animate > 100) {
my.animate -= 100;
my.walk_blend = 2;
}
}
} ELSE {
IF (my.stand_blend == 1) { str_cpy(current_player_frame,"stand"); }
IF (my.walk_blend == 1) { str_cpy(current_player_frame,"walk"); }
IF (my.run_blend == 0) {
my.stand_blend = 0;
my.walk_blend = 0;
my.run_blend = 1;
my.animate2 = my.animate;
my.animate = 0;
}
IF (my.run_blend == 2) {
ent_cycle("run",my.animate);
my.animate += 9 * time;
str_cpy(current_player_frame,"run");
} ELSE {
ent_cycle(current_player_frame,my.animate2);
ent_blend("run",0,my.animate);
my.animate += 40 * time;
IF (my.animate > 100) {
my.animate -= 100;
my.run_blend = 2;
}
}
}
} ELSE {
IF (my.run_blend == 1) { str_cpy(current_player_frame,"run"); }
IF (my.walk_blend == 1) { str_cpy(current_player_frame,"walk"); }
IF (my.stand_blend == 0) {
my.run_blend = 0;
my.walk_blend = 0;
my.stand_blend = 1;
my.animate2 = my.animate;
my.animate = 0;
}
IF (my.stand_blend == 2) {
ent_cycle("stand",my.animate);
my.animate += 3 * time;
str_cpy(current_player_frame,"stand");
} ELSE {
ent_cycle(current_player_frame,my.animate2);
ent_blend("stand",0,my.animate);
my.animate += 40 * time;
IF (my.animate > 100) {
my.animate -= 100;
my.stand_blend = 2;
}
}
}
IF (my.animate > 100) { my.animate -= 100; }

camera_pan_to -= mouse_force.x * 6 * time;
IF (mouse_force.x < 0) { camera_pan_direction = 1; }
IF (mouse_force.x > 0) { camera_pan_direction = -1; }

IF (mouse_force.y < 0) && (camera_height_main > 70) { camera_height_main += mouse_force.y * 50 * time; camera_height = camera_height_main; }
IF (mouse_force.y > 0) && (camera_height_main < 800) { camera_height_main += mouse_force.y * 50 * time; camera_height = camera_height_main; }

IF (key_a == 1) {
my.pan_to = camera.pan + 90;
camera_pan_to += 6 * time;
camera_pan_direction = 1;
}
IF (key_d == 1) {
my.pan_to = camera.pan + 270;
camera_pan_to -= 6 * time;
camera_pan_direction = -1;
}
IF (key_w == 1) {
my.pan_to = camera.pan;
}
IF (key_s == 1) {
my.pan_to = camera.pan + 180;
}
IF (key_w == 1 && key_d == 1) {
my.pan_to = camera.pan + 315;
}
IF (key_s == 1 && key_d == 1) {
my.pan_to = camera.pan + 225;
}
IF (key_s == 1 && key_a == 1) {
my.pan_to = camera.pan + 135;
}
IF (key_w == 1 && key_a == 1) {
temp = random(2);
my.pan_to = camera.pan + 45;
}
IF ((key_d == 1 && key_a == 1) || (key_w == 1 && key_s == 1)) {
my.pan_to = my.pan;
}
IF (key_d == 1 || key_a == 1 || key_w == 1 || key_s == 1) {
my.force_x = fcos(my.pan_to,15 * time);
my.force_y = fsin(my.pan_to,15 * time);
}

IF (key_d == 1 || key_a == 1 || key_s == 1 || key_w == 1 || my.jumping_mode != 0) {
temp = ang(my.pan_to - my.pan);
IF(temp > 5) {
my.pan_force = 20;
} ELSE {
IF (temp < -5) {
my.pan_force = -20;
} ELSE {
IF (temp > -2) && (temp < 2) { my.pan_velocity = 0; }
my.pan_force = 3 * ang(my.pan_to - my.pan);
}
}

my.pan_velocity += (TIME * my.pan_force) - (min(TIME*0.7,1) * my.pan_velocity);
my.pan += my.pan_velocity * TIME;
}
IF (key_shift == 1) {
my.force_x /= 1.5;
my.force_y /= 1.5;
}
}

FUNCTION player_gravity() {
vec_set(temp,my.x);
temp.z -= 4000;
trace_mode = ignore_me+ignore_passable+use_box;
result = trace(my.x,temp);
IF (you != null) {
result = ((my.z + my.min_z) - (you.z + you.max_z)); //for precise entity collision
}

IF (result <= 5) && (my.jumping_mode == 0) {
IF (result < 1.3) && (result > -1.3) && (result > 0.5) && (result < -0.5) { my.velocity_z = 0; } //change the value 1.5 to change how high steps he can climb, make it no higher than 3
my.force_z = -1 * result;
my.jump_blend = 0;
my.begin_fall = 0;
} ELSE {
IF (result > 60) && (my.begin_fall == 0) {
my.begin_fall = 1;
}
IF (my.begin_fall == 1) {
IF (my.jump_blend == 0) {
my.animate2 = my.animate;
my.animate = 0;
my.jump_blend = 1;
}
IF (result <= 5) && (my.animate > 20) {
IF (my.jumping_mode == 2) {
my.force_x = 0;
my.force_y = 0;
IF (my.animate <= 40) { my.jumping_mode = 0; }
IF (my.animate >= 100) {
my.jumping_mode = 0;
}
}
IF (result < 1.3) && (result > -1.3) && (result > 0.5) && (result < -0.5) { my.velocity_z = 0; } //change the value 1.5 to change how high steps he can climb, make it no higher than 3
my.force_z = -1 * result;
}
IF (my.jumping_mode != 1) {
IF (result < 30) {
IF (my.animate < 80) {
ent_frame("jump",my.animate);
my.animate += 12 * time;
} ELSE {
ent_frame("jump",my.animate);
my.animate += 4 * time;
IF (my.animate > 100) { my.animate = 100; }
}
} ELSE {
IF (my.force_x != 0) { my.force_x -= 0.08 * my.force_x * time; }
IF (my.force_y != 0) { my.force_y -= 0.08 * my.force_y * time; }
IF (my.jump_blend == 1) {
ent_cycle(current_player_frame,my.animate2);
ent_blend("jump",40,my.animate);
my.animate += 30 * time;
IF (my.animate > 100) {
str_cpy(current_player_frame,"stand");
my.walk_blend = 0;
my.run_blend = 0;
my.stand_blend = 0;
my.animate = 40;
my.jump_blend = 2;
}
} ELSE {
IF (my.animate < 40) {
ent_frame("jump",my.animate);
my.animate += 5 * time;
} ELSE {
my.animate = 40;
ent_frame("jump",my.animate);
my.jumping_mode = 2;
}
}
}
}
}
IF (my.force_z > -20) { my.force_z -= 3 * time; } ELSE { my.force_z = -20; }
}

my.velocity_z = 0.5 * my.force_z + max(1-0.5*0.7,0) * my.velocity_z; // calculate vertical speed, replace 0.3 with time to convert to the old equation
my.move_z = TIME * my.velocity_z; // distance down

my.move_x = my.force_x;
my.move_y = my.force_y;
}

FUNCTION camera_move() {
my.z += 15; //temporarily changed so that camera focusus slightly above middle

vec_set(temp.x,vector(my.x - fcos(camera.pan,camera_radius),my.y - fsin(camera.pan,camera_radius),camera.z));
trace_mode = ignore_me + ignore_passable + ignore_models + ignore_maps;
result = trace (my.x,temp.x);
IF (result > 0) {
result = sqrt(((target.x - my.x)*(target.x - my.x))+((target.y - my.y)*(target.y - my.y)));
camera_pan_to += camera_pan_direction * 15 * time;
IF (my.force_z < -2) {
camera_height += 80 * time;
}
} ELSE {
IF (camera_height > camera_height_main) { camera_height -= 15 * time; } ELSE { camera_height = camera_height_main; }
result = camera_radius;
}
IF (result < camera_radius) {
camera_radius_move_to = result;
} ELSE {
camera_radius_move_to = camera_radius;
}

IF (camera_radius_move_to < 15) { camera_radius_move_to = 15; }

vec_set(temp,my.x);
vec_sub(temp,camera.x);
vec_to_angle(temp.pan,temp);
camera_tilt_to = temp.tilt + camera_tilt_offset; //this causes the camera to tilt towards the player

camera_distance = camera_radius_move_to;
my.z -= 15; //temporarily changed so that camera focusus slightly above middle

vec_set(camera_move_to.x,vector(my.x - fcos(camera.pan,camera_distance),my.y - fsin(camera.pan,camera_distance),my.z + camera_height));

camera_tilt_force = (camera.tilt - camera_tilt_to) / -3;
IF (camera_tilt_force > 0) {
camera_tilt_force = min(camera_tilt_force,3);
} ELSE {
camera_tilt_force = max(camera_tilt_force,-3);
}
camera_tilt_velocity = 0.5*camera_tilt_force + max(1-0.5*0.7,0) * camera_tilt_velocity;
camera.tilt += camera_tilt_velocity * TIME;

camera_pan_force = (camera.pan - camera_pan_to) / -3;
IF (camera_pan_force > 0) {
camera_pan_force = min(camera_pan_force,10);
} ELSE {
camera_pan_force = max(camera_pan_force,-10);
}
camera_pan_velocity = 0.5*camera_pan_force + max(1-0.5*0.7,0) * camera_pan_velocity;
camera.pan += camera_pan_velocity * TIME;

IF (abs(camera.x - camera_move_to.x) > 2) {
camera_force.x = (camera.x - camera_move_to.x) / -4;
} ELSE {
camera_force.x = 0;
camera_velocity.x = 0;
}
IF (abs(camera.y - camera_move_to.y) > 2) {
camera_force.y = (camera.y - camera_move_to.y) / -4;
} ELSE {
camera_force.y = 0;
camera_velocity.y = 0;
}
IF (abs(camera.y - camera_move_to.z) > 2) {
camera_force.z = (camera.z - camera_move_to.z) / -12;
} ELSE {
camera_force.z = 0;
camera_velocity.z = 0;
}

IF (key_w == 1 && key_d == 1) || (key_w == 1 && key_a == 1) || (key_s == 1 && key_d == 1) || (key_s == 1 && key_a == 1) {
camera_force.x /= 1.5;
camera_force.y /= 1.5;
}

camera_velocity.x = 0.5*camera_force.x + max(1-0.5*0.7,0)*camera_velocity.x;
camera_velocity.y = 0.5*camera_force.y + max(1-0.5*0.7,0)*camera_velocity.y;
camera_velocity.z = 0.5*camera_force.z + max(1-0.5*0.7,0)*camera_velocity.z;
camera.x += TIME * camera_velocity.x;
camera.y += TIME * camera_velocity.y;
camera.z += TIME * camera_velocity.z;
}