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

📄 g_phys.pas

📁 delphi编的不错的贪吃蛇
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{----------------------------------------------------------------------------}
{                                                                            }
{ File(s): g_phys.c                                                          }
{ Content: physics logic                                                     }
{                                                                            }
{ Initial conversion by : MathD (matheus@tilt.net                            }
{ Initial conversion on : 05-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 on :  26-Jul-2002                                                  }
{ Updated by :  Scott Price                                                  }
{                                                                            }
{----------------------------------------------------------------------------}


unit g_phys;

interface

uses
  g_local,
  q_shared;

{pushmove objects do not obey gravity, and do not interact with each other or
trigger fields, but block normal movement and push normal objects when they move.

onground is set for toss objects when they come to a complete rest.  it is set
for steping or walking objects

doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
corpses are SOLID_NOT and MOVETYPE_TOSS
crates are SOLID_BBOX and MOVETYPE_TOSS
walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY

solid_edge items only clip against bsp models.}




function SV_TestEntityPosition(ent: edict_p): edict_p;
procedure SV_CheckVelocity (ent: edict_p);
function SV_RunThink (ent: edict_p): qboolean;
procedure SV_Impact(e1: edict_p; trace: trace_p);
function ClipVelocity(var in_, normal, out_: vec3_t; overbounce: single): integer;
function SV_FlyMove(ent: edict_p; time: single; mask: integer): integer;
procedure SV_AddGravity(ent: edict_p);
function SV_PushEntity(ent: edict_p; var push: vec3_t): trace_t;
function SV_Push(pusher: edict_p; var move_, amove: vec3_t): qboolean;
procedure SV_Physics_Pusher(ent: edict_p);
procedure SV_Physics_None(ent: edict_p);
procedure SV_Physics_Noclip(ent: edict_p);
procedure SV_Physics_Toss(ent: edict_p);
procedure SV_AddRotationalFriction(ent: edict_p);
procedure SV_Physics_Step(ent: edict_p);
procedure G_RunEntity(ent: edict_p);



implementation

uses g_main, game_add, g_utils, g_local_add, g_monster, m_move, GameUnit;


{/*
============
SV_TestEntityPosition

============
*/}
function SV_TestEntityPosition(ent: edict_p): edict_p;
var
  trace: trace_t;
  mask: integer;
begin
  if ent^.clipMask <> 0 then
    mask := ent^.clipMask
  else
    mask := MASK_SOLID;

  trace := gi.trace(@ent^.s.origin, @ent^.mins, @ent^.maxs, @ent^.s.origin, ent, mask);
  
  if (trace.startsolid) then
  begin
    Result := @g_edicts[0];
    exit;
  end;

  result := nil;
end;


{/*
================
SV_CheckVelocity
================
*/}

procedure SV_CheckVelocity (ent: edict_p);
var
  i: integer;
begin
  //
  // bound velocity
  //
  for i := 0 to 2 do
  begin
    if (ent^.velocity[i] > sv_maxvelocity^.value) then
      ent^.velocity[i] := sv_maxvelocity^.value
    else if (ent^.velocity[i] < (- sv_maxvelocity^.value)) then
      ent^.velocity[i] := -sv_maxvelocity^.value;
  end;
end;


{/*
=============
SV_RunThink

Runs thinking code for this frame if necessary
=============
*/}
function SV_RunThink (ent: edict_p): qboolean;
var
  thinktime: single;
begin
  thinktime := ent^.nextthink;
  if (thinktime <= 0) then
  begin
    Result := True;
    Exit;
  end;
  if (thinktime > level.time + 0.001) then
  begin
    Result := True;
    Exit;
  end;

  ent^.nextthink := 0;
  if (@ent^.think = nil) then
    gi.error('NIL ent^.think');
  ent^.think(ent);
  result := false;
end;


{/*
==================
SV_Impact

Two entities have touched, so run their touch functions
==================
*/}
procedure SV_Impact(e1: edict_p; trace: trace_p);
var
  e2: edict_p;
  //backplane: cplane_p;  <-- Commented out in the original
begin
  e2 := trace^.ent;

  if (@e1^.touch <> nil) and (e1^.solid <> SOLID_NOT) then
    e1^.touch(e1, e2, @trace^.plane, trace^.surface);

  if (@e2^.touch <> nil) and (e2^.solid <> SOLID_NOT) then
    e2^.touch(e2, e1, nil, nil);
end;



{/*
==================
ClipVelocity

Slide off of the impacting object
returns the blocked flags (1 = floor, 2 = step / wall)
==================
*/}
const STOP_EPSILON = 0.1;

function ClipVelocity(var in_, normal, out_: vec3_t; overbounce: single): integer;
var
  backoff, change: single;
  i, blocked: integer;
begin
  blocked := 0;
  if (normal[2] > 0) then
    blocked := blocked or 1; //floor

  if (normal[2] = 0) then
    blocked := blocked or 2; //step

  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;

  Result := blocked;
end;


{/*
============
SV_FlyMove

The basic solid body movement clip that slides along multiple planes
Returns the clipflags if the velocity was modified (hit something solid)
1 = floor
2 = wall / step
4 = dead stop
============
*/}
const MAX_CLIP_PLANES = 5;

function SV_FlyMove(ent: edict_p; time: single; mask: integer): integer;
var
  hit: edict_p;
  bumpcount, numbumps: integer;
  dir: vec3_t;
  d: single;
  numplanes: integer;
  planes: array[0..MAX_CLIP_PLANES -1] of vec3_t;
  primal_velocity, original_velocity, new_velocity: vec3_t;
  i, j: integer;
  trace: trace_t;
  end_: vec3_t;
  time_left: single;
  blocked: integer;
begin
  numbumps := 4;
  blocked := 0;
  VectorCopy(ent^.velocity, original_velocity);
  VectorCopy(ent^.velocity, primal_velocity);
  numplanes := 0;

  time_left := time;
  ent^.groundentity := nil;
  for bumpcount := 0 to (numbumps - 1) do
  begin
    for i := 0 to 2 do
      end_[i] := ent^.s.origin[i] + time_left * ent^.velocity[i];

    trace := gi.trace(@ent^.s.origin, @ent^.mins, @ent^.maxs, @end_, ent, mask);

    if (trace.allsolid) then
    begin
      //entity is trapped in another solid
      VectorCopy(vec3_origin, ent^.velocity);
      result := 3;
      Exit;
    end;

    if (trace.fraction > 0) then
    begin
      //actually covered some distance
      VectorCopy(trace.endpos, ent^.s.origin);
      VectorCopy(ent^.velocity, original_velocity);
      numplanes := 0;
    end;

    if (trace.fraction = 1) then
      Break; //moved the entire distance

    hit := trace.ent;

    if (trace.plane.normal[2] > 0.7) then
    begin
      blocked := blocked or 1; //floor;

      if (hit^.solid = SOLID_BSP) then
      begin
        ent^.groundentity := hit;
        ent^.groundentity_linkcount := hit^.linkcount;
      end;
    end;

    if trace.plane.normal[2]  = 0 then
      blocked := blocked or 2; //step

//
// run the impact function
//
    SV_Impact(ent, @trace);
    if not ent^.inuse then
      Break;

    time_left := time_left - (time_left * trace.fraction);
    //cliped to another plane
    if (numplanes >= MAX_CLIP_PLANES) then
    begin
      //this shouldn't really happen
      VectorCopy(vec3_origin, ent^.velocity);
      result := 3;
      Exit;
    end;

    VectorCopy(trace.plane.normal, planes[numplanes]);
    Inc(numplanes);

//
// modify original_velocity so it parallels all of the clip planes
//
    for i := 0 to (numplanes - 1) do
    begin
      ClipVelocity(original_velocity, planes[i], new_velocity, 1);

      for j := 0 to (numplanes - 1) do
      begin
        if (j <> i) and (VectorCompare(planes[i], planes[j]) = 0) then
        begin
          if (DotProduct(new_velocity, planes[j]) < 0) then
            Break; //not ok
        end;
      end;

      if j = numplanes then
        Break;
    end;

    if (i <> numplanes) then
      VectorCopy(new_velocity, ent^.velocity) //go along this plane
    else
    begin
      if (numplanes <> 2) then begin //go along the crease
        //gi.dprintf('clip velocity, numplanes = %i #13#10', numplanes);
        VectorCopy(vec3_origin, ent^.velocity);
        result := 7;
        Exit;
      end;

      CrossProduct(planes[0], planes[1], dir);
      d := DotProduct(dir, ent^.velocity);
      VectorScale(dir, d, ent^.velocity);
    end;

//
// if original velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
    if (DotProduct(ent^.velocity, primal_velocity) <= 0) then
    begin
      VectorCopy(vec3_origin, ent^.velocity);
      result := blocked;
      exit;
    end;
  end;

  result := blocked;
end;


{/*
============
SV_AddGravity

============
*/}
procedure SV_AddGravity(ent: edict_p);
begin
  ent^.velocity[2] := ent^.velocity[2] - (ent^.gravity * sv_gravity^.value * FRAMETIME);
end;

{/*
===============================================================================

PUSHMOVE

===============================================================================
*/`}

{/*
============
SV_PushEntity

Does not change the entities velocity at all
============
*/}
function SV_PushEntity(ent: edict_p; var push: vec3_t): trace_t;
label retry;
var
  trace: trace_t;
  start, end_: vec3_t;
  mask: integer;
begin
  VectorCopy(ent^.s.origin, start);
  VectorAdd(start, push, end_);

retry:
  if (ent^.clipmask <> 0) then
    mask := ent^.clipmask
  else
    mask := MASK_SOLID;

  trace := gi.trace(@start, @ent^.mins, @ent^.maxs, @end_, ent, mask);

  VectorCopy(trace.endpos, ent^.s.origin);
  gi.linkentity(ent);

  if (trace.fraction <> 1.0) then
  begin
    SV_Impact(ent, @trace);

    //if the pushed entity went away and the pusher is still there
    if (not edict_p(trace.ent)^.inuse) and (ent^.inuse) then
    begin
      //move the pusher back and try again
      VectorCopy(start, ent^.s.origin);
      gi.linkentity(ent);
      goto retry;
    end;
  end;

  if ent^.inuse then
    G_TouchTriggers(ent);

  result := trace;
end;

{delphi-note: converted the C pushed_p variable to _pushed_p since}
{pushed_p is the typed pointer of a record}
type
  pushed_t = packed record
    ent: edict_p;
    origin, angles: vec3_t;
    deltayaw: single;
  end;
  pushed_p = ^pushed_t;

var
  pushed: array[0..MAX_EDICTS -1] of pushed_t;
  _pushed_p: pushed_p;
  obstacle: edict_p;

{/*
============
SV_Push

Objects need to be moved back on a failed push,
otherwise riders would continue to slide.
============
*/}
function SV_Push(pusher: edict_p; var move_, amove: vec3_t): qboolean;
var
  i, e: Integer;
  check, block: edict_p;
  mins, maxs: vec3_t;
  p: pushed_p;
  org, org2, move2, forward_, right, up: vec3_t;
  temp: Single;
begin
  // clamp the move to 1/8 units, so the position will
  // be accurate for client side prediction
  for i := 0 to 2 do
  begin
    temp := move_[i] * 8.0;
    if (temp > 0.0) then
      temp := temp + 0.5
    else
      temp := temp - 0.5;

    move_[i] := 0.125 * Trunc(temp);
  end;

  // find the bounding box
  for i := 0 to 2 do
  begin
    mins[i] := pusher^.absmin[i] + move_[i];
    maxs[i] := pusher^.absmax[i] + move_[i];
  end;

// we need this for pushing things later
  VectorSubtract(vec3_origin, amove, org);
  AngleVectors(org, @forward_, @right, @up);

// save the pusher's original position
  _pushed_p^.ent := pusher;
  VectorCopy(pusher^.s.origin, _pushed_p^.origin);
  VectorCopy(pusher^.s.angles, _pushed_p^.angles);
  if (pusher^.client <> Nil) then
          _pushed_p^.deltayaw := pusher^.client^.ps.pmove.delta_angles[YAW];

  Inc(_pushed_p);

// move the pusher to it's final position
  VectorAdd(pusher^.s.origin, move_, pusher^.s.origin);
  VectorAdd(pusher^.s.angles, amove, pusher^.s.angles);
  gi.linkentity(pusher);

// see if any solid entities are inside the final position
  check :=  @g_edicts[1];
  for e := 1 to (globals.num_edicts - 1) do
  begin
    try
      if (not check^.inuse) then
        Continue;
      if (check^.movetype = MOVETYPE_PUSH)
      OR (check^.movetype = MOVETYPE_STOP)
      OR (check^.movetype = MOVETYPE_NONE)
      OR (check^.movetype = MOVETYPE_NOCLIP) then
        Continue;

      if (check^.area.prev = nil) then
        Continue;		// not linked in anywhere

  // if the entity is standing on the pusher, it will definitely be moved
      if (check^.groundentity <> pusher) then
      begin
        // see if the ent needs to be tested
        if (check^.absmin[0] >= maxs[0])
        OR (check^.absmin[1] >= maxs[1])
        OR (check^.absmin[2] >= maxs[2])
        OR (check^.absmax[0] <= mins[0])
        OR (check^.absmax[1] <= mins[1])
        OR (check^.absmax[2] <= mins[2]) then
          Continue;

        // see if the ent's bbox is inside the pusher's final position

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -