Enforce camera limits regardless of zoom level
authorWuzzy <Wuzzy2@mail.ru>
Mon, 29 Jun 2020 13:14:18 +0200
changeset 15672 85d2afe34116
parent 15671 b4ec4a8a8b09
child 15673 f75f8729cc5a
Enforce camera limits regardless of zoom level Previously, when you zoomed out, you could move the camera further out to the left, right and up.
hedgewars/uConsts.pas
hedgewars/uGearsHedgehog.pas
hedgewars/uWorld.pas
--- a/hedgewars/uConsts.pas	Mon Jun 29 00:15:37 2020 +0300
+++ b/hedgewars/uConsts.pas	Mon Jun 29 13:14:18 2020 +0200
@@ -233,6 +233,12 @@
     // do not change this value
     cDefaultZoomLevel = 2.0; // 100% zoom
 
+    // Maximum camera positions, values are "pixels outside the mainland"
+    cCamLimitX = 0; // X (left/right) camera limit, no border. Note: Influences sndFlyAway
+    cCamLimitY = 2048; // Top Y camera limit, no border
+    cCamLimitBorderX = 2048; // X (left/right) camera limit, with border
+    cCamLimitBorderY = 2048; // Top Y camera limit, with border
+
     // game flags
     gfAny                = $FFFFFFFF; // mask for all possible gameflags
     gfOneClanMode        = $00000001; // Game does not end if there's only one clan in play. For missions
--- a/hedgewars/uGearsHedgehog.pas	Mon Jun 29 00:15:37 2020 +0300
+++ b/hedgewars/uGearsHedgehog.pas	Mon Jun 29 13:14:18 2020 +0200
@@ -1281,7 +1281,7 @@
     uStats.hedgehogFlight(Gear, Gear^.FlightTime);
     Gear^.FlightTime:= 0;
     end;
-if (WorldEdge = weNone) and (not Gear^.Hedgehog^.FlownOffMap) and (not isZero(Gear^.dX)) and (not isUnderwater) and ((Gear^.State and gstHHDriven) = 0) and (hwRound(Gear^.Y) < cWaterLine-300) and ((hwRound(Gear^.X) < leftX-2048) or (hwRound(Gear^.X) > rightX+2048)) then
+if (WorldEdge = weNone) and (not hasBorder) and (not Gear^.Hedgehog^.FlownOffMap) and (not isZero(Gear^.dX)) and (not isUnderwater) and ((Gear^.State and gstHHDriven) = 0) and (hwRound(Gear^.Y) < cWaterLine-300) and ((hwRound(Gear^.X) < -cCamLimitX) or (hwRound(Gear^.X) > LAND_WIDTH+cCamLimitX)) then
     begin
     PlaySoundV(sndFlyAway, Gear^.Hedgehog^.Team^.voicepack);
     Gear^.Hedgehog^.FlownOffMap:= true;
--- a/hedgewars/uWorld.pas	Mon Jun 29 00:15:37 2020 +0300
+++ b/hedgewars/uWorld.pas	Mon Jun 29 13:14:18 2020 +0200
@@ -877,12 +877,42 @@
     end
 end;
 
-// Force the lower camera boundary to never be lower than a few pixels below the water line
-function LowerCameraBound: LongInt;
+// Force camera to stay within a certain area
+procedure CameraBounds;
+var lowBound: LongInt;
 begin
-LowerCameraBound:= trunc(cScreenHeight / cScaleFactor) + cScreenHeight div 2 - cWaterLine - (cVisibleWater + trunc(CinematicBarH / (cScaleFactor / 2.0)));
-if WorldDy < LowerCameraBound then
-    WorldDy:= LowerCameraBound;
+if (not hasBorder) then
+    begin
+    if WorldDy > (-(cScreenHeight / cScaleFactor) + cScreenHeight div 2 - TopY + cCamLimitY) then
+        WorldDy:= (-trunc(cScreenHeight / cScaleFactor) + cScreenHeight div 2 - TopY + cCamLimitY);
+    if (RightX - LeftX + cCamLimitX * 2) div 2 < cScreenWidth / cScaleFactor then
+        WorldDx:= -((LeftX + RightX) div 2)
+    else
+        begin
+        if WorldDx < -LAND_WIDTH - cCamLimitX + (cScreenWidth / cScaleFactor) then
+            WorldDx:= -LAND_WIDTH - cCamLimitX + trunc(cScreenWidth / cScaleFactor);
+        if WorldDx > cCamLimitX - (cScreenWidth / cScaleFactor) then
+            WorldDx:= cCamLimitX - trunc(cScreenWidth / cScaleFactor);
+        end;
+    end
+else
+    begin
+    if WorldDy > (-(cScreenHeight / cScaleFactor) + cScreenHeight div 2 - TopY + cCamLimitBorderY) then
+        WorldDy:= (-trunc(cScreenHeight / cScaleFactor) + cScreenHeight div 2 - TopY + cCamLimitBorderY);
+    if (RightX - LeftX + cCamLimitBorderX * 2) div 2 < cScreenWidth / cScaleFactor then
+        WorldDx:= -((LeftX + RightX) div 2)
+    else
+        begin
+        if WorldDx > -LeftX + cCamLimitBorderX - (cScreenWidth / cScaleFactor) then
+            WorldDx:= -LeftX + cCamLimitBorderX - trunc(cScreenWidth / cScaleFactor);
+        if WorldDx < -RightX - cCamLimitBorderX + (cScreenWidth / cScaleFactor) then
+            WorldDx:= -RightX - cCamLimitBorderX  + trunc(cScreenWidth / cScaleFactor);
+        end;
+    end;
+
+lowBound:= trunc(cScreenHeight / cScaleFactor) + cScreenHeight div 2 - cWaterLine - (cVisibleWater + trunc(CinematicBarH / (cScaleFactor / 2.0)));
+if WorldDy < lowBound then
+    WorldDy:= lowBound;
 end;
 
 procedure DrawWorld(Lag: LongInt);
@@ -906,7 +936,7 @@
     if (not isPaused) and (not isAFK) and (GameType <> gmtRecord) then
         MoveCamera
     else if (isPaused) then
-        LowerCameraBound;
+        CameraBounds;
 
     if cStereoMode = smNone then
         begin
@@ -1902,7 +1932,7 @@
 var PrevSentPointTime: LongWord = 0;
 
 procedure MoveCamera;
-var EdgesDist, wdy, shs,z, dstX: LongInt;
+var EdgesDist, shs,z, dstX: LongInt;
     inbtwnTrgtAttks: Boolean;
 begin
 {$IFNDEF MOBILE}
@@ -1950,10 +1980,11 @@
             WorldDx:= WorldDx + rightX - leftX;
     end;
 
-wdy:= LowerCameraBound;
-
 if ((CursorPoint.X = prevPoint.X) and (CursorPoint.Y = prevpoint.Y)) then
+    begin
+    CameraBounds;
     exit;
+    end;
 
 if (AMState = AMShowingUp) or (AMState = AMShowing) then
 begin
@@ -1966,6 +1997,7 @@
     if CursorPoint.Y < cScreenHeight - (AmmoRect.y + AmmoRect.h - AMSlotSize - 5) then//check bottom
         CursorPoint.Y:= cScreenHeight - (AmmoRect.y + AmmoRect.h - AMSlotSize - 5);
     prevPoint:= CursorPoint;
+    CameraBounds;
     exit
 end;
 
@@ -2021,14 +2053,10 @@
 
 // this moves the camera according to CursorPoint X and Y
 prevPoint:= CursorPoint;
-if WorldDy > LAND_HEIGHT + 1024 then
-    WorldDy:= LAND_HEIGHT + 1024;
-if WorldDy < wdy then
-    WorldDy:= wdy;
-if WorldDx < - LAND_WIDTH - 1024 then
-    WorldDx:= - LAND_WIDTH - 1024;
-if WorldDx > 1024 then
-    WorldDx:= 1024;
+
+// enforce camera bounds
+CameraBounds();
+
 end;
 
 procedure ShowMission(caption, subcaption, text: ansistring; icon, time : LongInt);