Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/objects/SpaceShipAI.cc @ 1558

Last change on this file since 1558 was 1558, checked in by landauf, 16 years ago

added support for isVisible() and isActive() to all objects.
those functions are provided by BaseObject, combined with virtual functions changedVisibility and changedActivity respectively.
use them, to make orxonox scriptable, say: to change the state of objects with 2 simple functions instead of changing all meshes and emitters and billboards of an object. don't forget to pass calls to changedVisibility and changedActivity to the parent class.

additionally there is a new function, isInitialized(), provided by BaseObject too. this returns true if the constructor of BaseObject passed the object registration. this allows you, to check whether an object was properly initialized or if the constructor returned (as this is the case while creating the class hierarchy). use isInitialized() in your destructor before deleting something.

  • Property svn:eol-style set to native
File size: 10.6 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "OrxonoxStableHeaders.h"
30#include "SpaceShipAI.h"
31
32#include <OgreMath.h>
33#include "Projectile.h"
34#include "ParticleSpawner.h"
35#include "core/CoreIncludes.h"
36#include "core/Iterator.h"
37#include "core/Executor.h"
38#include "core/ConsoleCommand.h"
39#include "core/XMLPort.h"
40#include "tools/ParticleInterface.h"
41
42#define ACTION_INTERVAL 1.0f
43
44namespace orxonox
45{
46    SetConsoleCommand(SpaceShipAI, createEnemy, true).setDefaultValue(0, 1);
47    SetConsoleCommand(SpaceShipAI, killEnemies, true).setDefaultValue(0, 0);
48
49    CreateFactory(SpaceShipAI);
50
51    SpaceShipAI::SpaceShipAI()
52    {
53        RegisterObject(SpaceShipAI);
54
55        this->target_ = 0;
56        this->bShooting_ = 0;
57        this->bHasTargetPosition_ = false;
58
59        this->setTeamNr((int)rnd(NUM_AI_TEAMS) % NUM_AI_TEAMS + 1);
60
61        if (NUM_AI_TEAMS > 0)
62            this->teamColours_[1] = ColourValue(1, 0, 0, 1);
63        if (NUM_AI_TEAMS > 1)
64            this->teamColours_[2] = ColourValue(0, 1, 0, 1);
65        if (NUM_AI_TEAMS > 2)
66            this->teamColours_[3] = ColourValue(0, 0, 1, 1);
67
68        for (int i = 4; i <= NUM_AI_TEAMS; ++i)
69            this->teamColours_[i] = ColourValue(rnd(), rnd(), rnd(), 1);
70    }
71
72    SpaceShipAI::~SpaceShipAI()
73    {
74        for (Iterator<SpaceShipAI> it = ObjectList<SpaceShipAI>::begin(); it; ++it)
75            it->shipDied(this);
76    }
77
78    void SpaceShipAI::XMLPort(Element& xmlelement, XMLPort::Mode mode)
79    {
80        SpaceShip::XMLPort(xmlelement, mode);
81
82        this->myShip_=true;
83        this->actionTimer_.setTimer(ACTION_INTERVAL, true, this, createExecutor(createFunctor(&SpaceShipAI::action)));
84    }
85
86    void SpaceShipAI::createEnemy(int num)
87    {
88        for (int i = 0; i < num; ++i)
89        {
90            SpaceShipAI* newenemy = new SpaceShipAI();
91            newenemy->setMesh("assff.mesh");
92//            newenemy->setPosition(0, 0, 0);
93            newenemy->setPosition(Vector3(rnd(-3000, 3000), rnd(-3000, 3000), rnd(-3000, 3000)));
94            newenemy->setScale(10);
95            newenemy->setMaxSpeed(500);
96            newenemy->setMaxSideAndBackSpeed(50);
97            newenemy->setMaxRotation(1.0);
98            newenemy->setTransAcc(200);
99            newenemy->setRotAcc(3.0);
100            newenemy->setTransDamp(75);
101            newenemy->setRotDamp(1.0);
102            Element xmlelement;
103            newenemy->XMLPort(xmlelement, XMLPort::LoadObject);
104
105            ParticleSpawner* spawneffect = new ParticleSpawner("Orxonox/fairytwirl", 2.0, 0.0, newenemy->getOrth());
106            spawneffect->setPosition(newenemy->getPosition() - newenemy->getOrth() * 50);
107            spawneffect->create();
108        }
109    }
110
111    void SpaceShipAI::killEnemies(int num)
112    {
113        int i = 0;
114        for (Iterator<SpaceShipAI> it = ObjectList<SpaceShipAI>::begin(); it; )
115        {
116            (it++)->kill();
117            if (num && i >= num)
118                break;
119        }
120    }
121
122    ColourValue SpaceShipAI::getProjectileColour() const
123    {
124        return this->teamColours_[this->getTeamNr()];
125    }
126
127    void SpaceShipAI::action()
128    {
129        float random;
130        float maxrand = 100.0f / ACTION_INTERVAL;
131
132        // search enemy
133        random = rnd(maxrand);
134        if (random < 20 && (!this->target_))
135            this->searchNewTarget();
136
137        // forget enemy
138        random = rnd(maxrand);
139        if (random < 5 && (this->target_))
140            this->forgetTarget();
141
142        // next enemy
143        random = rnd(maxrand);
144        if (random < 10 && (this->target_))
145            this->searchNewTarget();
146
147        // fly somewhere
148        random = rnd(maxrand);
149        if (random < 40 && (!this->bHasTargetPosition_ && !this->target_))
150            this->searchNewTargetPosition();
151
152        // stop flying
153        random = rnd(maxrand);
154        if (random < 10 && (this->bHasTargetPosition_ && !this->target_))
155            this->bHasTargetPosition_ = false;
156
157        // fly somewhere else
158        random = rnd(maxrand);
159        if (random < 30 && (this->bHasTargetPosition_ && !this->target_))
160            this->searchNewTargetPosition();
161
162        // shoot
163        random = rnd(maxrand);
164        if (random < 75 && (this->target_ && !this->bShooting_))
165            this->bShooting_ = true;
166
167        // stop shooting
168        random = rnd(maxrand);
169        if (random < 25 && (this->bShooting_))
170            this->bShooting_ = false;
171    }
172
173    void SpaceShipAI::damage(float damage)
174    {
175        this->health_ -= damage;
176        if (this->health_ <= 0)
177        {
178            this->kill();
179            SpaceShipAI::createEnemy(1);
180        }
181    }
182
183    void SpaceShipAI::kill()
184    {
185        ParticleSpawner* explosion = new ParticleSpawner("Orxonox/BigExplosion1part1", 3.0);
186        explosion->setPosition(this->getPosition());
187        explosion->getParticleInterface()->setKeepParticlesInLocalSpace(true);
188        explosion->setScale(4);
189        explosion->create();
190
191        explosion = new ParticleSpawner("Orxonox/BigExplosion1part2", 3.0);
192        explosion->setPosition(this->getPosition());
193        explosion->getParticleInterface()->setKeepParticlesInLocalSpace(true);
194        explosion->setScale(4);
195        explosion->create();
196
197        Vector3 ringdirection = Vector3(rnd(), rnd(), rnd());
198        ringdirection.normalise();
199        explosion = new ParticleSpawner("Orxonox/BigExplosion1part3", 3.0, 0.5, ringdirection);
200        explosion->setPosition(this->getPosition());
201        explosion->getParticleInterface()->setKeepParticlesInLocalSpace(true);
202        explosion->setScale(4);
203        explosion->create();
204
205        delete this;
206    }
207
208    void SpaceShipAI::tick(float dt)
209    {
210        if (!this->isActive())
211            return;
212
213        if (this->target_)
214            this->aimAtTarget();
215
216        if (this->bHasTargetPosition_)
217            this->moveToTargetPosition(dt);
218
219        if (this->bShooting_ && this->isCloseAtTarget(2500) && this->isLookingAtTarget(Ogre::Math::PI / 10))
220            this->doFire();
221
222        SpaceShip::tick(dt);
223    }
224
225    void SpaceShipAI::moveToTargetPosition(float dt)
226    {
227        Vector3 proj = Ogre::Plane(this->getDir(), this->getPosition()).projectVector(this->targetPosition_ - this->getPosition());
228        float angle = acos((this->getOrth().dotProduct(proj)) / (this->getOrth().length()*proj.length()));
229
230        if ((this->getDir().crossProduct(this->getOrth())).dotProduct(this->targetPosition_ - this->getPosition()) > 0)
231            this->setMoveYaw(sgn(sin(angle)));
232        else
233            this->setMoveYaw(-sgn(sin(angle)));
234        this->setMovePitch(sgn(cos(angle)));
235
236        if ((this->targetPosition_ - this->getPosition()).length() > 300)
237            this->setMoveLongitudinal(1);
238
239        if (this->isCloseAtTarget(300) && this->target_)
240        {
241            if (this->getVelocity().length() > this->target_->getVelocity().length())
242                this->setMoveLongitudinal(-1);
243        }
244    }
245
246    void SpaceShipAI::searchNewTargetPosition()
247    {
248        this->targetPosition_ = Vector3(rnd(-5000,5000), rnd(-5000,5000), rnd(-5000,5000));
249        this->bHasTargetPosition_ = true;
250    }
251
252    void SpaceShipAI::searchNewTarget()
253    {
254        this->targetPosition_ = this->getPosition();
255        this->forgetTarget();
256
257        for (Iterator<SpaceShip> it = ObjectList<SpaceShip>::begin(); it; ++it)
258        {
259            if (it->getTeamNr() != this->getTeamNr())
260            {
261                float speed = this->getVelocity().length();
262                Vector3 distanceCurrent = this->targetPosition_ - this->getPosition();
263                Vector3 distanceNew = it->getPosition() - this->getPosition();
264                if (!this->target_ || it->getPosition().squaredDistance(this->getPosition()) * (1.5f + acos((this->getOrientation() * Ogre::Vector3::UNIT_X).dotProduct(distanceNew) / speed / distanceNew.length()) / (2 * Ogre::Math::PI))
265                        < this->targetPosition_.squaredDistance(this->getPosition()) * (1.5f + acos((this->getOrientation() * Ogre::Vector3::UNIT_X).dotProduct(distanceCurrent) / speed / distanceCurrent.length()) / (2 * Ogre::Math::PI)) + rnd(-250, 250))
266                {
267                    this->target_ = (*it);
268                    this->targetPosition_ = it->getPosition();
269                }
270            }
271        }
272    }
273
274    void SpaceShipAI::forgetTarget()
275    {
276        this->target_ = 0;
277        this->bShooting_ = false;
278    }
279
280    void SpaceShipAI::aimAtTarget()
281    {
282        if (!this->target_)
283            return;
284
285        Vector3 enemymovement = this->target_->getVelocity();
286        Vector3 distance_normalised = this->target_->getPosition() - this->getPosition();
287        distance_normalised.normalise();
288
289        float scalarprod = enemymovement.dotProduct(distance_normalised);
290        float aimoffset = scalarprod*scalarprod + Projectile::getSpeed() * Projectile::getSpeed() - this->target_->getVelocity().squaredLength();
291
292        if (aimoffset < 0)
293        {
294            this->bHasTargetPosition_ = false;
295            return;
296        }
297        aimoffset = -scalarprod + sqrt(aimoffset);
298        this->targetPosition_ = this->getPosition() + enemymovement + distance_normalised * aimoffset;
299        this->bHasTargetPosition_ = true;
300    }
301
302    bool SpaceShipAI::isCloseAtTarget(float distance)
303    {
304        if (!this->target_)
305            return (this->getPosition().squaredDistance(this->targetPosition_) < distance*distance);
306        else
307            return (this->getPosition().squaredDistance(this->target_->getPosition()) < distance*distance);
308    }
309
310    bool SpaceShipAI::isLookingAtTarget(float angle)
311    {
312        Vector3 dist = this->targetPosition_ - this->getPosition();
313        return (acos((this->getDir().dotProduct(dist)) / (dist.length() * this->getDir().length())) < angle);
314    }
315
316    void SpaceShipAI::shipDied(SpaceShipAI* ship)
317    {
318        this->forgetTarget();
319        this->searchNewTargetPosition();
320    }
321}
Note: See TracBrowser for help on using the repository browser.