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

📄 g_phys.pas

📁 delphi编的不错的贪吃蛇
💻 PAS
📖 第 1 页 / 共 2 页
字号:
        if (SV_TestEntityPosition(check) = nil) then
          Continue;
      end;

      if ((pusher^.movetype = MOVETYPE_PUSH) OR (check^.groundentity = pusher)) then
      begin
        // move this entity
        _pushed_p^.ent := check;
        VectorCopy(check^.s.origin, _pushed_p^.origin);
        VectorCopy(check^.s.angles, _pushed_p^.angles);
        Inc(_pushed_p);

        // try moving the contacted entity
        VectorAdd(check^.s.origin, move_, check^.s.origin);
        if (check^.client <> nil) then
        begin	// FIXME: doesn't rotate monsters?
          check^.client^.ps.pmove.delta_angles[YAW] := check^.client^.ps.pmove.delta_angles[YAW] + trunc(amove[YAW]);
        end;

        // figure movement due to the pusher's amove
        VectorSubtract(check^.s.origin, pusher^.s.origin, org);
        org2[0] := DotProduct(org, forward_);
        org2[1] := -DotProduct(org, right);
        org2[2] := DotProduct(org, up);
        VectorSubtract(org2, org, move2);
        VectorAdd(check^.s.origin, move2, check^.s.origin);

        // may have pushed them off an edge
        if (check^.groundentity <> pusher) then
          check^.groundentity := nil;

        block := SV_TestEntityPosition(check);
        if (block = nil) then
        begin	// pushed ok
          gi.linkentity(check);
          // impact?
          Continue;
        end;

        // if it is ok to leave in the old position, do it
        // this is only relevent for riding entities, not pushed
        // FIXME: this doesn't acount for rotation
        VectorSubtract(check^.s.origin, move_, check^.s.origin);
        block := SV_TestEntityPosition(check);
        if (block = nil) then
        begin
          Dec(_pushed_p);
          Continue;
        end;
      end;

      // save off the obstacle so we can call the block function
      obstacle := check;

      // move back any entities we already moved
      // go backwards, so if the same entity was pushed
      // twice, it goes back to the original position
      p := Pointer(Cardinal(_pushed_p) - 1 * SizeOf(pushed_t));
      while (Cardinal(p) >= Cardinal(@pushed)) do
      begin
          VectorCopy(p^.origin, p^.ent^.s.origin);
          VectorCopy(p^.angles, p^.ent^.s.angles);
          if (p^.ent^.client <> nil) then
          begin
            p^.ent^.client^.ps.pmove.delta_angles[YAW] := trunc(p^.deltayaw);
          end;
          gi.linkentity(p^.ent);

          p := Pointer(Cardinal(p) - 1 * SizeOf(pushed_t));
      end;
      Result := False;
      Exit;
    finally
      { All Expression Two items get evaluated at the End of any loop }
      Inc(check);
      { Inc(e)  <-- Shouldnt' be needed as should already be incremented }
    end;
  end;

//FIXME: is there a better way to handle this?
  // see if anything we moved has touched a trigger
  p := Pointer(Cardinal(_pushed_p) - 1 * SizeOf(pushed_t));
  while (Cardinal(p) >= Cardinal(@pushed)) do
  begin
      G_TouchTriggers(p^.ent);
      p := Pointer(Cardinal(p) - 1 * SizeOf(pushed_t));
  end;

  Result := True;
end;

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

Bmodel objects don't interact with each other, but
push all box objects
================
*/}
procedure SV_Physics_Pusher(ent: edict_p);
var
  move_, amove: vec3_t;
  part, mv: edict_p;
begin
  // if not a team captain, so movement will be handled elsewhere
  if (ent^.flags AND FL_TEAMSLAVE) <> 0 then
    Exit;

  // make sure all team slaves can move before commiting
  // any moves or calling any think functions
  // if the move is blocked, all moved objects will be backed out
//retry:
  _pushed_p := @pushed[0];

  { ORIGINAL LINE:  for (part = ent ; part ; part=part->teamchain) }
  { NOTE(SP):  While (part <> nil) might be better - but logic similar in either case.
     - Whilst originally implemented with a repeat until and using a try..finally block
       to ensure the next pointer assignment occered, this also inadvertently moved the
       pointer forwards, even in the case of the call to Brea.  As such, changed the
       approach to use a while loop, and removed the try..finally for performance. }
  part := ent;
  while (part <> nil) do
  begin
    if (part^.velocity[0] <> 0) OR (part^.velocity[1] <> 0) OR (part^.velocity[2] <> 0) OR
    (part^.avelocity[0] <> 0) OR (part^.avelocity[1] <> 0) OR (part^.avelocity[2] <> 0) then
    begin	// object is moving
      VectorScale(part^.velocity, FRAMETIME, move_);
      VectorScale(part^.avelocity, FRAMETIME, amove);

      if (NOT SV_Push(part, move_, amove)) then
        Break;	// move was blocked
    end;
    part := part^.teamchain;
  end;

  if (Cardinal(_pushed_p) > Cardinal(@pushed[MAX_EDICTS - 1])) then //was pushed[MAX_EDICTS]
    gi.error({ERR_FATAL,} '_pushed_p > @pushed[MAX_EDICTS], memory corrupted');

  if (part <> nil) then
  begin
    // the move failed, bump all nextthink times and back out moves
    mv := ent;
    while (mv <> nil) do
    begin
      if (mv^.nextthink > 0) then
        mv^.nextthink := mv^.nextthink + FRAMETIME;
      mv := mv^.teamchain;
    end;

    // if the pusher has a "blocked" function, call it
    // otherwise, just stay in place until the obstacle is gone
    if (@part^.blocked <> nil) then
      part^.blocked(part, obstacle);
(*{$ifdef 0}
    // if the pushed entity went away and the pusher is still there
    if (NOT obstacle^.inuse) AND part^.inuse) then
      goto retry;
{$endif}*)
  end
  else
  begin
    // the move succeeded, so call all think functions
    part := ent;
    while (part <> nil) do
    begin
      SV_RunThink(part);
      part := part^.teamchain
    end;
  end;
end;

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

Non moving objects can only think
=============
*/}
procedure SV_Physics_None(ent: edict_p);
begin
  // regular thinking
  SV_RunThink(ent);
end;

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

A moving object that doesn't obey physics
=============
*/}
procedure SV_Physics_Noclip(ent: edict_p);
begin
  // regular thinking
  if not SV_RunThink(ent) then
    Exit;

  VectorMA(ent^.s.angles, FRAMETIME, ent^.avelocity, ent^.s.angles);
  VectorMA(ent^.s.origin, FRAMETIME, ent^.velocity, ent^.s.origin);

  gi.linkentity(ent);
end;

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

TOSS / BOUNCE

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

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

Toss, bounce, and fly movement.  When onground, do nothing.
=============
*/}
procedure SV_Physics_Toss(ent: edict_p);
var
  trace: trace_t;
  move_: vec3_t;
  backoff: single;
  slave: edict_p;
  wasinwater, isinwater: qboolean;
  old_origin: vec3_t;
begin
  // regular thinking
  SV_RunThink(ent);

  // if not a team captain, so movement will be handled elsewhere
  if (ent^.flags and FL_TEAMSLAVE) <> 0 then
    Exit;

  if (ent^.velocity[2] > 0) then
    ent^.groundentity := nil;

  // check for the groundentity going away
  if (ent^.groundentity <> nil) then
    if not ent^.groundentity^.inuse then
      ent^.groundentity := nil;

  // if onground, return without moving
  if (ent^.groundentity <> nil) then
    Exit;

  VectorCopy(ent^.s.origin, old_origin);

  SV_CheckVelocity(ent);

  // add gravity
  if (ent^.movetype <> MOVETYPE_FLY) and (ent^.movetype <> MOVETYPE_FLYMISSILE) then
    SV_AddGravity(ent);

  // move angles
  VectorMA(ent^.s.angles, FRAMETIME, ent^.avelocity, ent^.s.angles);

  // move origin
  VectorScale(ent^.velocity, FRAMETIME, move_);
  trace := SV_PushEntity(ent, move_);
  if not ent^.inuse then
    Exit;

  if (trace.fraction < 1) then
  begin
    if (ent^.movetype = MOVETYPE_BOUNCE) then
      backoff := 1.5
    else
      backoff := 1;

    ClipVelocity(ent^.velocity, trace.plane.normal, ent^.velocity, backoff);

    // stop if on ground
    if (trace.plane.normal[2] > 0.7) then
    begin
      if (ent^.velocity[2] < 60) or (ent^.movetype <> MOVETYPE_BOUNCE) then
      begin
        ent^.groundentity := trace.ent;
        ent^.groundentity_linkcount := edict_p(trace.ent)^.linkcount;
        VectorCopy(vec3_origin, ent^.velocity);
        VectorCopy(vec3_origin, ent^.avelocity);
      end;
    end;

    { The following was originally commented out, but converted still :) }
    //if (ent^.touch <> nil) then
    //  ent^.touch(ent, trace.ent, @trace.plane, trace.surface);
  end;

  //check for water transition
  wasinwater := (ent^.watertype and MASK_WATER) <> 0;
  ent^.watertype := gi.pointcontents(ent^.s.origin);
  isinwater := ent^.watertype and MASK_WATER <> 0;

  if (isinwater) then
    ent^.waterlevel := 1
  else
    ent^.waterlevel := 0;

  if (not wasinwater) and isinwater then
    gi.positioned_sound(@old_origin, @g_edicts[0], CHAN_AUTO, gi.soundindex('misc/h2ohit1.wav'), 1, 1, 0)
  else if wasinwater and (not isinwater) then
    gi.positioned_sound(@ent^.s.origin, @g_edicts[0], CHAN_AUTO, gi.soundindex('misc/h2ohit1.wav'), 1, 1, 0);

  //move teamslaves
  {for (slave = ent->teamchain; slave; slave = slave->teamchain)}
  { Or replace with while (slave <> nil) do loop }
  slave := ent^.teamchain;
  while (slave <> nil) do
  begin
    VectorCopy(ent^.s.origin, slave^.s.origin);
    gi.linkentity(slave);
    slave := slave^.teamchain;
  end;
end;

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

STEPPING MOVEMENT

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

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

Monsters freefall when they don't have a ground entity, otherwise
all movement is done with discrete steps.

This is also used for objects that have become still on the ground, but
will fall if the floor is pulled out from under them.
FIXME: is this true?
=============
*/}

//FIXME: hacked in for E3 demo
const
  sv_stopspeed = 100;
  sv_friction = 6;
  sv_waterfriction = 1;

procedure SV_AddRotationalFriction(ent: edict_p);
var
  n: integer;
  adjustment: single;
begin
  VectorMA(ent^.s.angles, FRAMETIME, ent^.avelocity, ent^.s.angles);
  adjustment := FRAMETIME * sv_stopspeed * sv_friction;

  for n := 0 to 2 do
  begin
    if (ent^.avelocity[n] > 0) then
    begin
      ent^.avelocity[n] := ent^.avelocity[n] - adjustment;
      if (ent^.avelocity[n] < 0) then
        ent^.avelocity[n] := 0;
    end
    else
    begin
      ent^.avelocity[n] := ent^.avelocity[n] + adjustment;
      if (ent^.avelocity[n] > 0) then
        ent^.avelocity[n] := 0;
    end;
  end;
end;

procedure SV_Physics_Step(ent: edict_p);
var
  wasonground, hitsound: qboolean;
  vel: vec3_p;
  speed, newspeed, control, friction: Single;
  groundentity: edict_p;
  mask: Integer;
begin
  hitsound := False;

  // airborn monsters should always check for ground
  if (ent^.groundentity = nil) then
    M_CheckGround(ent);

  groundentity := ent^.groundentity;

  SV_CheckVelocity(ent);

  if (groundentity <> nil) then
    wasonground := True
  else
    wasonground := False;

  if (ent^.avelocity[0] <> 0) OR (ent^.avelocity[1] <> 0) OR (ent^.avelocity[2] <> 0) then
    SV_AddRotationalFriction(ent);

  // add gravity except:
  //   flying monsters
  //   swimming monsters who are in the water
  if (NOT wasonground) then
    if ((ent^.flags AND FL_FLY) = 0) then
      if NOT (((ent^.flags AND FL_SWIM) <> 0) AND (ent^.waterlevel > 2)) then
      begin
        if (ent^.velocity[2] < (sv_gravity^.value * -0.1)) then
          hitsound := True;
        if (ent^.waterlevel = 0) then
          SV_AddGravity(ent);
      end;

  // friction for flying monsters that have been given vertical velocity
  if ((ent^.flags AND FL_FLY) <> 0) AND (ent^.velocity[2] <> 0) then
  begin
    speed := fabs(ent^.velocity[2]);
    if (speed < sv_stopspeed) then
      control := sv_stopspeed
    else
      control := speed;

    friction := (sv_friction / 3);
    newspeed := speed - (FRAMETIME * control * friction);
    if (newspeed < 0) then
      newspeed := 0;
    newspeed := newspeed / speed;
    ent^.velocity[2] := ent^.velocity[2] * newspeed;
  end;

  // friction for flying monsters that have been given vertical velocity
  if ((ent^.flags AND FL_SWIM) <> 0) AND (ent^.velocity[2] <> 0) then
  begin
    speed := fabs(ent^.velocity[2]);
    if (speed < sv_stopspeed) then
      control := sv_stopspeed
    else
      control := speed;
    newspeed := speed - (FRAMETIME * control * sv_waterfriction * ent^.waterlevel);
    if (newspeed < 0) then
      newspeed := 0;
    newspeed := newspeed / speed;
    ent^.velocity[2] := ent^.velocity[2] * newspeed;
  end;

  if (ent^.velocity[2] <> 0) OR (ent^.velocity[1] <> 0) OR (ent^.velocity[0] <> 0) then
  begin
    // apply friction
    // let dead monsters who aren't completely onground slide
    if (wasonground) OR ((ent^.flags AND (FL_SWIM OR FL_FLY)) <> 0) then
      if NOT ((ent^.health <= 0.0) AND (NOT M_CheckBottom(ent))) then
      begin
        vel := @ent^.velocity;
        speed := sqrt(vel[0] * vel[0] + vel[1] * vel[1]);
        if (speed <> 0) then
        begin
          friction := sv_friction;

          if (speed < sv_stopspeed) then
            control := sv_stopspeed
          else
            control := speed;
          newspeed := speed - FRAMETIME * control * friction;

          if (newspeed < 0) then
            newspeed := 0;
          newspeed := newspeed / speed;

          vel[0] := vel[0] * newspeed;
          vel[1] := vel[1] * newspeed;
        end;
      end;

    if (ent^.svflags AND SVF_MONSTER) <> 0 then
      mask := MASK_MONSTERSOLID
    else
      mask := MASK_SOLID;
    SV_FlyMove(ent, FRAMETIME, mask);

    gi.linkentity(ent);
    G_TouchTriggers(ent);
    if (NOT ent^.inuse) then
      Exit;

    if (ent^.groundentity <> nil) then
      if (NOT wasonground) then
        if (hitsound) then
          gi.sound(ent, 0, gi.soundindex('world/land.wav'), 1, 1, 0);
  end;

// regular thinking
  SV_RunThink(ent);
end;

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

================
*/}
procedure G_RunEntity(ent: edict_p);
begin
  if (@ent^.prethink <> nil) then
    ent^.prethink(ent);

  case Integer(ent^.movetype) of
    Ord(MOVETYPE_PUSH),
    Ord(MOVETYPE_STOP):
    begin
      SV_Physics_Pusher(ent);
      //break;
    end;
    Ord(MOVETYPE_NONE):
    begin
      SV_Physics_None(ent);
      //break;
    end;
    Ord(MOVETYPE_NOCLIP):
    begin
      SV_Physics_Noclip(ent);
      //break;
    end;
    Ord(MOVETYPE_STEP):
    begin
      SV_Physics_Step(ent);
      //break;
    end;
    Ord(MOVETYPE_TOSS),
    Ord(MOVETYPE_BOUNCE),
    Ord(MOVETYPE_FLY),
    Ord(MOVETYPE_FLYMISSILE):
    begin
      SV_Physics_Toss(ent);
      //break;
    end;
  else
    gi.error('SV_Physics: bad movetype %i', Integer(ent^.movetype));
  end;
end;

end.

⌨️ 快捷键说明

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