📄 pmoveunit.pas
字号:
{----------------------------------------------------------------------------}
{ }
{ File(s): QCommon.h (part), PMove.c }
{ Content: Quake2\QCommon\ PLAYER MOVEMENT CODE }
{ }
{ Initial conversion by : Clootie (Alexey Barkovoy) - clootie@reactor.ru }
{ Initial conversion on : 25-Feb-2002 }
{ }
{ This File contains part of convertion of Quake2 source to ObjectPascal. }
{ More information about this project can be found at: }
{ http://www.sulaco.co.za/quake2/ }
{ }
{ Copyright (C) 1997-2001 Id Software, Inc. }
{ }
{ This program is free software; you can redistribute it and/or }
{ modify it under the terms of the GNU General Public License }
{ as published by the Free Software Foundation; either version 2 }
{ of the License, or (at your option) any later version. }
{ }
{ This program is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }
{ }
{ See the GNU General Public License for more details. }
{ }
{----------------------------------------------------------------------------}
{ * Updated: }
{ }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on: }
{ }
{----------------------------------------------------------------------------}
{ * TODO: }
{----------------------------------------------------------------------------}
unit PMoveUnit;
interface
uses
G_Local,
Q_Shared;
(*
==============================================================
PLAYER MOVEMENT CODE
Common between server and client so prediction matches
==============================================================
*)
var
pm_airaccelerate : Single = 0;
procedure Pmove(pmove: pmove_p); cdecl;
implementation
uses
Common;
const
STEPSIZE = 18;
// all of the locals will be zeroed before each
// pmove, just to make damn sure we don't have
// any differences when running on client or server
type
pml_p = ^pml_t;
pml_t = record
origin : vec3_t; // full float precision
velocity : vec3_t; // full float precision
forward, right, up : vec3_t;
frametime : Single;
groundsurface : csurface_p;
groundplane : cplane_t;
groundcontents : Integer;
previous_origin : vec3_t;
ladder : qboolean;
end;
var
pm: pmove_p;
pml: pml_t;
// movement parameters
pm_stopspeed : Single = 100;
pm_maxspeed : Single = 300;
pm_duckspeed : Single = 100;
pm_accelerate : Single = 10;
// pm_airaccelerate : Single = 0; // - in interface part
pm_wateraccelerate : Single = 10;
pm_friction : Single = 6;
pm_waterfriction : Single = 1;
pm_waterspeed : Single = 400;
(*
walking up a step should kill some velocity
*)
(*
==================
PM_ClipVelocity
Slide off of the impacting object
returns the blocked flags (1 = floor, 2 = step / wall)
==================
*)
const
STOP_EPSILON = 0.1;
procedure PM_ClipVelocity(const in_, normal: vec3_t; var out_: vec3_t; overbounce: Single);
var
backoff: Single;
change: Single;
i: Integer;
begin
backoff := DotProduct(in_, normal) * overbounce;
for i:= 0 to 2 do
begin
change := normal[i]*backoff;
out_[i] := in_[i] - change;
if (out_[i] > -STOP_EPSILON) and (out_[i] < STOP_EPSILON) then
out_[i] := 0;
end;
end;
(*
==================
PM_StepSlideMove
Each intersection will try to step over the obstruction instead of
sliding along it.
Returns a new origin, velocity, and contact entity
Does not modify any world state?
==================
*)
const
MIN_STEP_NORMAL = 0.7; // can't step up onto very steep slopes
MAX_CLIP_PLANES = 5;
procedure PM_StepSlideMove_;
var
bumpcount, numbumps: Integer;
dir: vec3_t;
d: Single;
numplanes: Integer;
planes: array [0..MAX_CLIP_PLANES-1] of vec3_t;
primal_velocity: vec3_t;
i, j: Integer;
trace: trace_t;
end_: vec3_t;
time_left: Single;
begin
numbumps := 4;
VectorCopy(pml.velocity, primal_velocity);
numplanes := 0;
time_left := pml.frametime;
for bumpcount:= 0 to numbumps - 1 do
begin
for i:= 0 to 2 do
end_[i] := pml.origin[i] + time_left * pml.velocity[i];
trace := pm.trace(pml.origin, pm.mins, pm.maxs, end_);
if (trace.allsolid) then
begin // entity is trapped in another solid
pml.velocity[2] := 0; // don't build up falling damage
Exit;
end;
if (trace.fraction > 0) then
begin // actually covered some distance
VectorCopy(trace.endpos, pml.origin);
numplanes := 0;
end;
if (trace.fraction = 1) then
Break; // moved the entire distance
// save entity for contact
if (pm.numtouch < MAXTOUCH) and (trace.ent <> nil) then
begin
pm.touchents[pm.numtouch] := trace.ent;
Inc(pm.numtouch);
end;
time_left := time_left - time_left * trace.fraction;
// slide along this plane
if (numplanes >= MAX_CLIP_PLANES) then
begin // this shouldn't really happen
VectorCopy(vec3_origin, pml.velocity);
Break;
end;
VectorCopy(trace.plane.normal, planes[numplanes]);
Inc(numplanes);
{$ifdef 0}
float rub;
//
// modify velocity so it parallels all of the clip planes
//
if (numplanes == 1)
{ // go along this plane
VectorCopy (pml.velocity, dir);
VectorNormalize (dir);
rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
// slide along the plane
PM_ClipVelocity (pml.velocity, planes[0], pml.velocity, 1.01);
// rub some extra speed off on xy axis
// not on Z, or you can scrub down walls
pml.velocity[0] *= rub;
pml.velocity[1] *= rub;
pml.velocity[2] *= rub;
}
else if (numplanes == 2)
{ // go along the crease
VectorCopy (pml.velocity, dir);
VectorNormalize (dir);
rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
// slide along the plane
CrossProduct (planes[0], planes[1], dir);
d = DotProduct (dir, pml.velocity);
VectorScale (dir, d, pml.velocity);
// rub some extra speed off
VectorScale (pml.velocity, rub, pml.velocity);
}
else
{
// Con_Printf ("clip velocity, numplanes == %d\n",numplanes);
VectorCopy (vec3_origin, pml.velocity);
break;
}
{$else}
//
// modify original_velocity so it parallels all of the clip planes
//
for i:= 0 to numplanes - 1 do
begin
PM_ClipVelocity(pml.velocity, planes[i], pml.velocity, 1.01);
for j:= 0 to numplanes - 1 do
if (j <> i) then
begin
if (DotProduct(pml.velocity, planes[j]) < 0) then Break; // not ok
end;
if (j = numplanes) then Break;
end;
if (i <> numplanes) then
begin // go along this plane
end
else
begin // go along the crease
if (numplanes <> 2) then
begin
// Con_Printf ('clip velocity, numplanes == %d'#10, [numplanes]);
VectorCopy(vec3_origin, pml.velocity);
Break;
end;
CrossProduct(planes[0], planes[1], dir);
d := DotProduct(dir, pml.velocity);
VectorScale(dir, d, pml.velocity);
end;
{$endif}
//
// if velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
if (DotProduct (pml.velocity, primal_velocity) <= 0) then
begin
VectorCopy(vec3_origin, pml.velocity);
Break;
end;
end;
if (pm.s.pm_time <> 0) then
begin
VectorCopy(primal_velocity, pml.velocity);
end;
end;
(*
==================
PM_StepSlideMove
==================
*)
procedure PM_StepSlideMove;
var
start_o, start_v: vec3_t;
down_o, down_v: vec3_t;
trace: trace_t;
down_dist, up_dist: Single;
// vec3_t delta;
up, down: vec3_t;
begin
VectorCopy(pml.origin, start_o);
VectorCopy(pml.velocity, start_v);
PM_StepSlideMove_;
VectorCopy(pml.origin, down_o);
VectorCopy(pml.velocity, down_v);
VectorCopy(start_o, up);
up[2]:= up[2] + STEPSIZE;
trace := pm.trace(up, pm.mins, pm.maxs, up);
if (trace.allsolid) then
Exit; // can't step up
// try sliding above
VectorCopy(up, pml.origin);
VectorCopy(start_v, pml.velocity);
PM_StepSlideMove_;
// push down the final amount
VectorCopy(pml.origin, down);
down[2]:= down[2] - STEPSIZE;
trace := pm.trace(pml.origin, pm.mins, pm.maxs, down);
if not trace.allsolid then
begin
VectorCopy(trace.endpos, pml.origin);
end;
{$ifdef neverever}
VectorSubtract (pml.origin, up, delta);
up_dist = DotProduct (delta, start_v);
VectorSubtract (down_o, start_o, delta);
down_dist = DotProduct (delta, start_v);
{$ELSE}
VectorCopy(pml.origin, up);
// decide which one went farther
down_dist := (down_o[0] - start_o[0])*(down_o[0] - start_o[0]) +
(down_o[1] - start_o[1])*(down_o[1] - start_o[1]);
up_dist := (up[0] - start_o[0])*(up[0] - start_o[0]) +
(up[1] - start_o[1])*(up[1] - start_o[1]);
{$ENDIF}
if (down_dist > up_dist) or (trace.plane.normal[2] < MIN_STEP_NORMAL) then
begin
VectorCopy(down_o, pml.origin);
VectorCopy(down_v, pml.velocity);
Exit;
end;
//!! Special case
// if we were walking along a plane, then we need to copy the Z over
pml.velocity[2] := down_v[2];
end;
(*
==================
PM_Friction
Handles both ground friction and water friction
==================
*)
procedure PM_Friction_func;
var
vel: vec3_p;
speed, newspeed, control: Single;
friction: Single;
drop: Single;
begin
vel := @pml.velocity;
speed := sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]);
if (speed < 1) then
begin
vel[0] := 0;
vel[1] := 0;
Exit;
end;
drop := 0;
// apply ground friction
if ((pm.groundentity <> nil) and (pml.groundsurface <> nil) and (pml.groundsurface.flags and SURF_SLICK = 0)) or
(pml.ladder) then
begin
friction := pm_friction;
// control = speed < pm_stopspeed ? pm_stopspeed : speed;
if (speed < pm_stopspeed) then
control := pm_stopspeed
else
control := speed;
drop := drop + control*friction*pml.frametime;
end;
// apply water friction
if (pm.waterlevel <> 0) and (not pml.ladder) then
drop := drop + speed*pm_waterfriction*pm.waterlevel*pml.frametime;
// scale the velocity
newspeed := speed - drop;
if (newspeed < 0) then
begin
newspeed := 0;
end;
newspeed := newspeed / speed;
vel[0] := vel[0] * newspeed;
vel[1] := vel[1] * newspeed;
vel[2] := vel[2] * newspeed;
end;
(*
==============
PM_Accelerate
Handles user intended acceleration
==============
*)
procedure PM_Accelerate_func(wishdir: vec3_t; wishspeed, accel: Single);
var
i: Integer;
addspeed, accelspeed, currentspeed: Single;
begin
currentspeed := DotProduct(pml.velocity, wishdir);
addspeed := wishspeed - currentspeed;
if (addspeed <= 0) then
Exit;
accelspeed := accel*pml.frametime*wishspeed;
if (accelspeed > addspeed) then
accelspeed := addspeed;
for i:= 0 to 2 do
pml.velocity[i]:= pml.velocity[i] + accelspeed*wishdir[i];
end;
procedure PM_AirAccelerate_func(wishdir: vec3_t; wishspeed, accel: Single);
var
i: Integer;
addspeed, accelspeed, currentspeed, wishspd: Single;
begin
wishspd := wishspeed;
if (wishspd > 30) then
wishspd := 30;
currentspeed := DotProduct(pml.velocity, wishdir);
addspeed := wishspd - currentspeed;
if (addspeed <= 0) then
Exit;
accelspeed := accel * wishspeed * pml.frametime;
if (accelspeed > addspeed) then
accelspeed := addspeed;
for i:= 0 to 2 do
pml.velocity[i]:= pml.velocity[i] + accelspeed*wishdir[i];
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -