1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2011
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include <movement/Boid2.h>
22 #include <movement/TargetMovementEntryBoids.h>
23 #include <common/OptionsScorched.h>
24 #include <landscapemap/LandscapeMaps.h>
25 #include <engine/ScorchedContext.h>
26 #include <engine/Simulator.h>
27 #include <target/Target.h>
28 #include <target/TargetLife.h>
29
Boid2(ScorchedContext & context,Target * target,TargetMovementEntryBoids * world)30 Boid2::Boid2(ScorchedContext &context, Target *target, TargetMovementEntryBoids *world) :
31 context_(context), target_(target), world_(world)
32 {
33 }
34
~Boid2()35 Boid2::~Boid2()
36 {
37 }
38
getPosition()39 FixedVector &Boid2::getPosition()
40 {
41 static FixedVector result;
42 if (target_) return target_->getLife().getTargetPosition();
43 return result;
44 }
45
getVelocity()46 FixedVector &Boid2::getVelocity()
47 {
48 static FixedVector result;
49 if (target_) return target_->getLife().getVelocity();
50 return result;
51 }
52
clearTarget()53 void Boid2::clearTarget()
54 {
55 target_ = 0;
56 }
57
update(fixed frameTime,std::vector<Boid2 * > & boidSet,bool complexUpdate)58 void Boid2::update(fixed frameTime, std::vector<Boid2*> &boidSet, bool complexUpdate)
59 {
60 // Limit Velocity
61 directionMag_ = getVelocity().Magnitude();
62 direction_ = getVelocity() / directionMag_;
63 if (directionMag_ > world_->getMaxVelocity())
64 {
65 getVelocity() = direction_ * world_->getMaxVelocity();
66 directionMag_ = world_->getMaxVelocity();
67 }
68
69 // Update position and rotation
70 if (target_)
71 {
72 fixed yaw = atan2x(getVelocity()[0], getVelocity()[1]);
73 fixed newRotation = -fixed(yaw) / fixed::XPI * 180;
74
75 FixedVector newPosition = getPosition() + getVelocity();
76 target_->getLife().setTargetPositionAndRotation(newPosition, newRotation);
77 }
78
79 // Calculate new velocity
80 FixedVector collisionNormal;
81 FixedVector newVelocity;
82 if (checkCollision(collisionNormal))
83 {
84 // Collision
85 newVelocity = collisionNormal / 10;
86 }
87 else
88 {
89 if (complexUpdate)
90 {
91 newVelocity = checkGrouping(boidSet);
92 }
93
94 // Wander
95 {
96 fixed cruiseDiff = world_->getCruiseVelocity() - directionMag_;
97 fixed cruiseChange = cruiseDiff / 10;
98 newVelocity += direction_ * cruiseDiff;
99 }
100
101 // Level out the flight
102 {
103 newVelocity[2] -= getVelocity()[2] / 100;
104 }
105 }
106
107 // Limit acceleration
108 fixed velocityMag = newVelocity.Magnitude();
109 if (velocityMag > world_->getMaxAcceleration())
110 {
111 newVelocity.StoreNormalize();
112 newVelocity *= world_->getMaxAcceleration();
113 }
114
115 if (target_)
116 {
117 newVelocity += getVelocity();
118 target_->getLife().setVelocity(newVelocity);
119
120 if (complexUpdate)
121 {
122 if (context_.getOptionsGame().getActionSyncCheck() &&
123 context_.getOptionsGame().getActionMovementSyncCheck())
124 {
125 context_.getSimulator().addSyncCheck(
126 S3D::formatStringBuffer("TargetMovement: %u %s %s",
127 target_->getPlayerId(),
128 target_->getLife().getTargetPosition().asQuickString(),
129 target_->getLife().getVelocity().asQuickString()));
130 }
131 }
132 }
133 }
134
checkGrouping(std::vector<Boid2 * > & boidSet)135 FixedVector Boid2::checkGrouping(std::vector<Boid2*> &boidSet)
136 {
137 FixedVector posMatch, velMatch, velDist;
138 FixedVector normalizedVelocity = direction_;
139
140 int count = 0, countDist = 0;
141 std::vector<Boid2*>::iterator itor;
142 for (itor = boidSet.begin(); itor != boidSet.end(); ++itor)
143 {
144 Boid2 *other = (Boid2 *) *itor;
145 if (!other || other == this) continue;
146
147 FixedVector direction = getPosition() - other->getPosition();
148 fixed distance = direction.Magnitude();
149 FixedVector normalizedDirection = direction / distance;
150 fixed dp = normalizedDirection.dotP(normalizedVelocity);
151 if (dp.abs() < fixed(true, 3000))
152 {
153 count++;
154
155 posMatch += other->getPosition();
156 velMatch += other->getVelocity();
157
158 if (distance < world_->getCruiseDistance())
159 {
160 velDist += direction;
161 countDist++;
162 }
163 }
164 }
165
166 if (countDist > 0)
167 {
168 velDist /= countDist;
169 velDist /= 10;
170 }
171
172 if (count > 0)
173 {
174 posMatch /= count;
175 posMatch = (posMatch - getPosition()) / 10;
176
177 velMatch /= count;
178 velMatch = (velMatch - getVelocity()) / 10;
179 }
180
181 FixedVector velocity;
182 velocity += posMatch;
183 velocity += velMatch;
184 velocity += velDist;
185 return velocity;
186 }
187
checkCollision(FixedVector & normal)188 bool Boid2::checkCollision(FixedVector &normal)
189 {
190 int collision = 0;
191 FixedVector &position = getPosition();
192 if (position[0] < world_->getMinBounds()[0])
193 {
194 collision++;
195 normal += FixedVector(1, 0, 0);
196 }
197 else if (position[0] > world_->getMaxBounds()[0])
198 {
199 collision++;
200 normal += FixedVector(-1, 0, 0);
201 }
202
203 if (position[1] < world_->getMinBounds()[1])
204 {
205 collision++;
206 normal += FixedVector(0, 1, 0);
207 }
208 else if (position[1] > world_->getMaxBounds()[1])
209 {
210 collision++;
211 normal += FixedVector(0, -1, 0);
212 }
213
214 if (position[2] < world_->getMinBounds()[2])
215 {
216 collision++;
217 normal += FixedVector(0, 0, 1);
218 }
219 else if (position[2] > world_->getMaxBounds()[2])
220 {
221 collision++;
222 normal += FixedVector(0, 0, -1);
223 }
224
225 for (int i=0; i<4; i++)
226 {
227 fixed dist = fixed(i) * 3;
228 FixedVector newPosition = position + direction_ * dist;
229
230 if (context_.getLandscapeMaps().getGroundMaps().getHeight(
231 newPosition[0].asInt(), newPosition[1].asInt()) > newPosition[2] - fixed(5))
232 {
233 collision++;
234 normal += context_.getLandscapeMaps().getGroundMaps().getNormal(
235 newPosition[0].asInt(), newPosition[1].asInt());
236 break;
237 }
238 }
239
240 if (collision > 0)
241 {
242 normal.StoreNormalize();
243 return true;
244 }
245
246 return false;
247 }
248