Skip to content

Commit b19225a

Browse files
Add class for picking and tracking objects
PickedMovableObject represents a node object figure that has been picked to be followed in the observation window.
1 parent 4b98d9b commit b19225a

File tree

2 files changed

+215
-0
lines changed

2 files changed

+215
-0
lines changed
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// Copyright (C) 2005 - 2023 Settlers Freaks (sf-team at siedler25.org)
2+
//
3+
// SPDX-License-Identifier: GPL-2.0-or-later
4+
5+
#include "PickedMovableObject.h"
6+
#include "desktops/dskGameInterface.h"
7+
#include "drivers/VideoDriverWrapper.h"
8+
#include "world/GameWorldBase.h"
9+
#include "world/GameWorldView.h"
10+
#include "nodeObjs/noMovable.h"
11+
#include <cmath>
12+
13+
namespace {
14+
constexpr unsigned PickRadius = 2;
15+
constexpr unsigned TrackRadius = 5;
16+
constexpr unsigned long ExpireIn = 5000;
17+
constexpr auto ExpireNever = static_cast<unsigned long>(-1);
18+
19+
// Make (ab-)use of CheckPointsInRadius() easier
20+
constexpr bool CheckPointsBreak = true;
21+
constexpr bool CheckPointsContinue = false;
22+
} // namespace
23+
24+
PickedMovableObject PickedMovableObject::Pick(const GameWorldView& gwv, MapPoint mapPt, DrawPoint drawPt, bool expire)
25+
{
26+
// DEBUG REMOVE BEFORE MERGE
27+
unsigned i = 1;
28+
29+
const auto offset = gwv.GetOffset();
30+
const auto center = gwv.GetSize() / 2.f;
31+
const auto zoomFactor = gwv.GetZoomFactor();
32+
const auto& world = gwv.GetWorld();
33+
const auto worldSize = world.GetSize() * DrawPoint(TR_W, TR_H);
34+
auto minDistance = std::numeric_limits<float>::max();
35+
36+
PickedMovableObject pmo;
37+
38+
world.CheckPointsInRadius(
39+
mapPt, PickRadius,
40+
[&](MapPoint curPt, unsigned) {
41+
if(gwv.GetViewer().GetVisibility(curPt) != Visibility::Visible)
42+
return CheckPointsContinue;
43+
44+
DrawPoint curDrawPt = world.GetNodePos(curPt);
45+
if(curDrawPt.x < offset.x)
46+
curDrawPt.x += worldSize.x;
47+
if(curDrawPt.y < offset.y)
48+
curDrawPt.y += worldSize.y;
49+
curDrawPt -= offset;
50+
for(const noBase& obj : world.GetFigures(curPt))
51+
{
52+
const auto* movable = dynamic_cast<const noMovable*>(&obj);
53+
if(!movable)
54+
continue;
55+
56+
DrawPoint objDrawPt = curDrawPt;
57+
if(movable->IsMoving())
58+
objDrawPt += movable->CalcWalkingRelative();
59+
objDrawPt = DrawPoint((objDrawPt - center) * zoomFactor + center);
60+
61+
// DEBUG REMOVE BEFORE MERGE
62+
dskGameInterface::SetDebugPoint(i++, objDrawPt, 8, 4, MakeColor(255, 255, 0, 255));
63+
64+
auto diff = Point<float>(objDrawPt - drawPt);
65+
float distance = std::sqrt(diff.x * diff.x + diff.y * diff.y);
66+
if(distance < minDistance)
67+
{
68+
pmo.id_ = movable->GetObjId();
69+
pmo.mapPt_ = curPt;
70+
pmo.drawPt_ = objDrawPt; // TODO Do we need the unwrapped point here or was this always wrong?
71+
minDistance = distance;
72+
}
73+
}
74+
75+
return CheckPointsContinue;
76+
},
77+
true);
78+
79+
if(pmo.IsValid() && expire)
80+
pmo.expiration_ = VIDEODRIVER.GetTickCount() + ExpireIn;
81+
82+
return pmo;
83+
}
84+
85+
PickedMovableObject PickedMovableObject::PickAtCursor(const GameWorldView& gwv, bool expire)
86+
{
87+
return Pick(gwv, gwv.GetSelectedPt(), DrawPoint(VIDEODRIVER.GetMousePos()), expire);
88+
}
89+
90+
PickedMovableObject PickedMovableObject::PickAtViewCenter(const GameWorldView& gwv, bool expire)
91+
{
92+
const auto centerMapPt = gwv.GetWorld().MakeMapPoint((gwv.GetFirstPt() + gwv.GetLastPt()) / 2);
93+
const auto centerDrawPt = DrawPoint(gwv.GetSize() / 2u);
94+
return Pick(gwv, centerMapPt, centerDrawPt, expire);
95+
}
96+
97+
PickedMovableObject::PickedMovableObject(PickedMovableObject&& other) noexcept
98+
{
99+
*this = std::move(other);
100+
}
101+
102+
PickedMovableObject& PickedMovableObject::operator=(PickedMovableObject&& other) noexcept
103+
{
104+
id_ = other.id_;
105+
mapPt_ = other.mapPt_;
106+
drawPt_ = other.drawPt_;
107+
expiration_ = other.expiration_;
108+
109+
// invalidate moved-from object
110+
other.Invalidate();
111+
112+
return *this;
113+
}
114+
115+
bool PickedMovableObject::IsValid() const
116+
{
117+
return id_ != 0 && VIDEODRIVER.GetTickCount() < expiration_;
118+
}
119+
120+
void PickedMovableObject::CancelExpiration()
121+
{
122+
expiration_ = ExpireNever;
123+
}
124+
125+
void PickedMovableObject::Invalidate()
126+
{
127+
id_ = 0;
128+
expiration_ = 0;
129+
}
130+
131+
bool PickedMovableObject::Track(const GameWorldView& gwv)
132+
{
133+
if(!IsValid())
134+
return false;
135+
136+
const auto& world = gwv.GetWorld();
137+
const auto success = world.CheckPointsInRadius(
138+
mapPt_, TrackRadius,
139+
[&](MapPoint curPt, unsigned) {
140+
if(gwv.GetViewer().GetVisibility(curPt) != Visibility::Visible)
141+
return CheckPointsContinue;
142+
143+
for(const noBase& obj : world.GetFigures(curPt))
144+
{
145+
if(obj.GetObjId() != id_)
146+
continue;
147+
148+
const auto& movable = dynamic_cast<const noMovable&>(obj);
149+
mapPt_ = curPt;
150+
drawPt_ = world.GetNodePos(curPt);
151+
if(movable.IsMoving())
152+
drawPt_ += movable.CalcWalkingRelative();
153+
154+
return CheckPointsBreak;
155+
}
156+
return CheckPointsContinue;
157+
},
158+
true);
159+
160+
if(!success)
161+
Invalidate();
162+
163+
return success;
164+
}
165+
166+
bool PickedMovableObject::Track(GameWorldView& gwv, bool moveTo)
167+
{
168+
const auto success = Track(gwv);
169+
if(success && moveTo)
170+
gwv.MoveTo(drawPt_ - gwv.GetSize() / 2u);
171+
return success;
172+
}

libs/s25main/PickedMovableObject.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (C) 2005 - 2023 Settlers Freaks (sf-team at siedler25.org)
2+
//
3+
// SPDX-License-Identifier: GPL-2.0-or-later
4+
5+
#pragma once
6+
7+
#include "DrawPoint.h"
8+
#include "gameTypes/MapCoordinates.h"
9+
10+
class GameWorldView;
11+
12+
class PickedMovableObject
13+
{
14+
public:
15+
static PickedMovableObject Pick(const GameWorldView& gwv, MapPoint mapPt, DrawPoint drawPt, bool expire);
16+
static PickedMovableObject PickAtCursor(const GameWorldView& gwv, bool expire);
17+
static PickedMovableObject PickAtViewCenter(const GameWorldView& gwv, bool expire);
18+
19+
PickedMovableObject() = default;
20+
21+
// disable implicit copy; may still be useful
22+
explicit PickedMovableObject(const PickedMovableObject&) = default;
23+
PickedMovableObject& operator=(const PickedMovableObject&) = default;
24+
25+
// invalidates the moved-from object
26+
PickedMovableObject(PickedMovableObject&& other) noexcept;
27+
PickedMovableObject& operator=(PickedMovableObject&& other) noexcept;
28+
29+
unsigned Id() const { return id_; }
30+
bool IsValid() const;
31+
32+
void CancelExpiration();
33+
void Invalidate();
34+
35+
bool Track(const GameWorldView& gwv);
36+
bool Track(GameWorldView& gwv, bool moveTo);
37+
38+
private:
39+
unsigned id_ = 0;
40+
MapPoint mapPt_{};
41+
DrawPoint drawPt_{};
42+
unsigned long expiration_ = static_cast<unsigned long>(-1) /* = ExpireNever */;
43+
};

0 commit comments

Comments
 (0)