⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pmoveunit.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
{----------------------------------------------------------------------------}
{                                                                            }
{ 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 + -