X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_phys.pas;h=81bdb78d6b095492405bb06c4afaf4d9601749d4;hb=5c816a8e702fd39c65d0928a3315d81e979f30fb;hp=a88ca21c9da246a2f61e2f76ff17160cc032681e;hpb=c7ee5fde8d382144cfd01bf9432031a827490e1b;p=d2df-sdl.git diff --git a/src/game/g_phys.pas b/src/game/g_phys.pas index a88ca21..81bdb78 100644 --- a/src/game/g_phys.pas +++ b/src/game/g_phys.pas @@ -1,9 +1,8 @@ -(* Copyright (C) DooM 2D:Forever Developers +(* Copyright (C) Doom 2D: Forever Developers * * 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 3 of the License, or - * (at your option) any later version. + * the Free Software Foundation, version 3 of the License ONLY. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -19,7 +18,7 @@ unit g_phys; interface uses - e_graphics; + r_graphics; type PObj = ^TObj; @@ -32,6 +31,9 @@ type // this is purely visual change, it won't affect anything else slopeUpLeft: Integer; // left to go slopeFramesLeft: Integer; // frames left to go + // for frame interpolation + oldX, oldY: Integer; + procedure lerp(t: Single; out fX, fY: Integer); end; const @@ -49,20 +51,24 @@ const MOVE_HITAIR = 64; MOVE_BLOCK = 128; -procedure g_Obj_Init(Obj: PObj); -function g_Obj_Move(Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean = False): Word; -function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; overload; -function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; overload; -function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; -function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; -function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; -function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; -function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; -function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; -function g_Obj_StayOnStep(Obj: PObj): Boolean; -procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); -procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); -procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); +procedure g_Obj_Init(Obj: PObj); inline; +function g_Obj_Move(Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False; asProjectile: Boolean=false): Word; +function g_Obj_Move_Projectile (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False): Word; +function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; inline; overload; +function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; inline; overload; +function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; inline; +function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; inline; +function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; inline; +function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; inline; +function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline; +function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; inline; +function g_Obj_StayOnStep(Obj: PObj): Boolean; inline; +function g_Obj_CanMoveY(Obj: PObj; YInc: Integer): Boolean; inline; +procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); inline; +procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); inline; +procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); inline; +function g_Obj_GetSpeedDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline; // `false`: zero speed +function g_Obj_GetAccelDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline; // `false`: zero speed function z_dec(a, b: Integer): Integer; inline; function z_fdec(a, b: Double): Double; inline; @@ -73,14 +79,19 @@ implementation uses g_map, g_basic, Math, g_player, g_console, SysUtils, - g_sound, g_gfx, MAPDEF, g_monsters, g_game, BinEditor, utils; + g_sound, g_gfx, MAPDEF, g_monsters, g_game, utils; const SmoothSlopeFrames = 4; +procedure TObj.lerp(t: Single; out fX, fY: Integer); +begin + fX := nlerp(oldX, X, t); + fY := nlerp(oldY, Y, t); +end; -function g_Obj_StayOnStep(Obj: PObj): Boolean; +function g_Obj_StayOnStep(Obj: PObj): Boolean; inline; begin Result := not g_Map_CollidePanel(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y+Obj^.Rect.Height-1, Obj^.Rect.Width, 1, @@ -90,14 +101,21 @@ begin PANEL_STEP, False); end; -function CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; +function g_Obj_CanMoveY(Obj: PObj; YInc: Integer): Boolean; inline; +begin + // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ + // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ + Result := not(g_Obj_CollideLevel(Obj, 0, YInc) or ((YInc > 0) and g_Obj_StayOnStep(Obj))); +end; + +function CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline; begin Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc, Obj^.Rect.Width, Obj^.Rect.Height*2 div 3, PANEL_WATER or PANEL_ACID1 or PANEL_ACID2, False); end; -function CollideLift(Obj: PObj; XInc, YInc: Integer): Integer; +function CollideLift(Obj: PObj; XInc, YInc: Integer): Integer; inline; begin if g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc, Obj^.Rect.Width, Obj^.Rect.Height, @@ -111,7 +129,7 @@ begin Result := 0; end; -function CollideHorLift(Obj: PObj; XInc, YInc: Integer): Integer; +function CollideHorLift(Obj: PObj; XInc, YInc: Integer): Integer; inline; var left, right: Boolean; begin @@ -138,7 +156,7 @@ begin for plr in gPlayers do begin if (plr = nil) then continue; - if not plr.Live then continue; + if not plr.alive then continue; with plr do begin if g_Collide(GameX+PLAYER_RECT.X, GameY+PLAYER_RECT.Y, @@ -153,42 +171,42 @@ begin end; end; -function Blocked(Obj: PObj; XInc, YInc: Integer): Boolean; +function Blocked(Obj: PObj; XInc, YInc: Integer): Boolean; inline; begin Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc, Obj^.Rect.Width, Obj^.Rect.Height, PANEL_BLOCKMON, False); end; -function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; +function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; inline; begin Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc, Obj^.Rect.Width, Obj^.Rect.Height, PANEL_WALL, False); end; -function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; +function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; inline; begin Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc, Obj^.Rect.Width, Obj^.Rect.Height, PANEL_STEP, False); end; -function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; +function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; inline; begin Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc, Obj^.Rect.Width, Obj^.Rect.Height, PANEL_WATER, False); end; -function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; +function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline; begin Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc, Obj^.Rect.Width, Obj^.Rect.Height, PANEL_WATER or PANEL_ACID1 or PANEL_ACID2, False); end; -function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; +function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; inline; begin Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc, Obj^.Rect.Width, Obj^.Rect.Height, @@ -257,7 +275,7 @@ var begin result := true; if (not g_Obj_CollideLevel(Obj, sx, -12)) and // çàáèðàåìñÿ íà 12 ïèêñåëåé âëåâî/âïðàâî - g_Obj_CollidePanel(Obj, 0, 1, PANEL_WALL or PANEL_STEP) then // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè + (sy >= 0) and (not g_Obj_CanMoveY(Obj, sy)) then // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè begin slope(-1); end @@ -299,9 +317,8 @@ var if Blocked(Obj, 0, sy) then st := st or MOVE_BLOCK; end; - // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ - // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ - if g_Obj_CollideLevel(Obj, 0, sy) or ((sy > 0) and g_Obj_StayOnStep(Obj)) then + // Åñëè øàãàòü íåëüçÿ + if not g_Obj_CanMoveY(Obj, sy) then begin if sy > 0 then st := st or MOVE_HITLAND @@ -352,19 +369,25 @@ begin end; -procedure g_Obj_Init (Obj: PObj); +procedure g_Obj_Init (Obj: PObj); inline; begin ZeroMemory(Obj, SizeOf(TObj)); end; -function g_Obj_Move (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False): Word; +function g_Obj_Move_Projectile (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False): Word; +begin + result := g_Obj_Move(Obj, Fallable, Splash, ClimbSlopes, true); +end; + +function g_Obj_Move (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False; asProjectile: Boolean=false): Word; var xv, yv, dx, dy: Integer; inwater: Boolean; c: Boolean; wtx: DWORD; slopeStep: Integer; + dirx, diry, speed: Double; label _move; begin @@ -385,7 +408,7 @@ begin } // Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû? - if (Obj^.Y > gMapInfo.Height+128) then begin result := MOVE_FALLOUT; Obj.slopeUpLeft := 0; Obj.slopeFramesLeft := 0; exit; end; + if (Obj^.Y > Integer(gMapInfo.Height)+128) then begin result := MOVE_FALLOUT; Obj.slopeUpLeft := 0; Obj.slopeFramesLeft := 0; exit; end; // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì c := (gTime mod (GAME_TICK*2) <> 0); @@ -451,17 +474,45 @@ begin inwater := CollideLiquid(Obj, 0, 0); if inwater then begin - xv := abs(Obj^.Vel.X)+1; - if (xv > 5) then Obj^.Vel.X := z_dec(Obj^.Vel.X, (xv div 2)-2); - - yv := abs(Obj^.Vel.Y)+1; - if (yv > 5) then Obj^.Vel.Y := z_dec(Obj^.Vel.Y, (yv div 2)-2); - - xv := abs(Obj^.Accel.X)+1; - if (xv > 5) then Obj^.Accel.X := z_dec(Obj^.Accel.X, (xv div 2)-2); + if asProjectile then + begin + //writeln('velocity=(', Obj^.Vel.X, ',', Obj^.Vel.Y, '); acceleration=(', Obj^.Accel.X, ',', Obj^.Accel.Y, ')'); + if (g_Obj_GetSpeedDirF(Obj, dirx, diry, speed)) then + begin + //writeln('SPEED: ', speed); + if (speed > 5) then + begin + speed := speed/1.4; + Obj^.Vel.X := round(dirx*speed); + Obj^.Vel.Y := round(diry*speed); + end; + end; - yv := abs(Obj^.Accel.Y)+1; - if (yv > 5) then Obj^.Accel.Y := z_dec(Obj^.Accel.Y, (yv div 2)-2); + // acceleration + if (g_Obj_GetAccelDirF(Obj, dirx, diry, speed)) then + begin + if (speed > 5) then + begin + speed := speed/1.4; + Obj^.Accel.X := round(dirx*speed); + Obj^.Accel.Y := round(diry*speed); + end; + end; + end + else + begin + // velocity + xv := abs(Obj^.Vel.X)+1; + if (xv > 5) then Obj^.Vel.X := z_dec(Obj^.Vel.X, (xv div 2)-2); + yv := abs(Obj^.Vel.Y)+1; + if (yv > 5) then Obj^.Vel.Y := z_dec(Obj^.Vel.Y, (yv div 2)-2); + + // acceleration + xv := abs(Obj^.Accel.X)+1; + if (xv > 5) then Obj^.Accel.X := z_dec(Obj^.Accel.X, (xv div 2)-2); + yv := abs(Obj^.Accel.Y)+1; + if (yv > 5) then Obj^.Accel.Y := z_dec(Obj^.Accel.Y, (yv div 2)-2); + end; end; // Óìåíüøàåì ïðèáàâêó ê ñêîðîñòè @@ -514,7 +565,7 @@ _move: end; -function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; +function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; inline; begin Result := g_Collide(Obj1^.X+Obj1^.Rect.X, Obj1^.Y+Obj1^.Rect.Y, Obj1^.Rect.Width, Obj1^.Rect.Height, @@ -522,7 +573,7 @@ begin Obj2^.Rect.Width, Obj2^.Rect.Height); end; -function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; +function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; inline; begin Result := g_Collide(X, Y, Width, Height, @@ -530,19 +581,19 @@ begin Obj^.Rect.Width, Obj^.Rect.Height); end; -function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; +function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; inline; begin Result := g_CollidePoint(X, Y, Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y, Obj^.Rect.Width, Obj^.Rect.Height); end; -procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); +procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); inline; begin Obj^.Vel.X := Obj^.Vel.X + VelX; Obj^.Vel.Y := Obj^.Vel.Y + VelY; end; -procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); +procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); inline; var s, c: Extended; @@ -553,7 +604,7 @@ begin Obj^.Vel.Y := Obj^.Vel.Y + Round(Vel*s); end; -procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); +procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); inline; var m, vx, vy: Integer; begin @@ -568,6 +619,52 @@ begin Obj^.Vel.Y := (vy*s) div m; end; +// `false`: zero speed +function g_Obj_GetSpeedDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline; +var + len, vx, vy: Double; +begin + if (Obj^.Vel.X = 0) and (Obj^.Vel.Y = 0) then + begin + dirx := 0; + diry := 0; + speed := 0; + result := false; + exit; + end; + + vx := Obj^.Vel.X; + vy := Obj^.Vel.Y; + len := sqrt(vx*vx+vy*vy); + dirx := vx/len; + diry := vy/len; + speed := len; + result := true; +end; + +// `false`: zero acceleratin +function g_Obj_GetAccelDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline; +var + len, vx, vy: Double; +begin + if (Obj^.Accel.X = 0) and (Obj^.Accel.Y = 0) then + begin + dirx := 0; + diry := 0; + speed := 0; + result := false; + exit; + end; + + vx := Obj^.Accel.X; + vy := Obj^.Accel.Y; + len := sqrt(vx*vx+vy*vy); + dirx := vx/len; + diry := vy/len; + speed := len; + result := true; +end; + // Ïðèáëèæàåì a ê 0 íà b åäèíèö: function z_dec (a, b: Integer): Integer; inline;