Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

moved ParticleInterface to tools, deleted particle

by the way, the last commit also changed a lot in ParticleInterface and added a new class, ParticleSpawner.

oh, and I forgot to say:
########################################

!!! UPDATE YOUR MEDIA REPOSITORY !!!

########################################

  • 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->target_)
211            this->aimAtTarget();
212
213        if (this->bHasTargetPosition_)
214            this->moveToTargetPosition(dt);
215
216        if (this->bShooting_ && this->isCloseAtTarget(2500) && this->isLookingAtTarget(Ogre::Math::PI / 10))
217            this->doFire();
218
219        SpaceShip::tick(dt);
220    }
221
222    void SpaceShipAI::moveToTargetPosition(float dt)
223    {
224        Vector3 proj = Ogre::Plane(this->getDir(), this->getPosition()).projectVector(this->targetPosition_ - this->getPosition());
225        float angle = acos((this->getOrth().dotProduct(proj)) / (this->getOrth().length()*proj.length()));
226
227        if ((this->getDir().crossProduct(this->getOrth())).dotProduct(this->targetPosition_ - this->getPosition()) > 0)
228            this->setMoveYaw(sgn(sin(angle)));
229        else
230            this->setMoveYaw(-sgn(sin(angle)));
231        this->setMovePitch(sgn(cos(angle)));
232
233        if ((this->targetPosition_ - this->getPosition()).length() > 300)
234            this->setMoveLongitudinal(1);
235
236        if (this->isCloseAtTarget(300) && this->target_)
237        {
238            if (this->getVelocity().length() > this->target_->getVelocity().length())
239                this->setMoveLongitudinal(-1);
240        }
241    }
242
243    void SpaceShipAI::searchNewTargetPosition()
244    {
245        this->targetPosition_ = Vector3(rnd(-5000,5000), rnd(-5000,5000), rnd(-5000,5000));
246        this->bHasTargetPosition_ = true;
247    }
248
249    void SpaceShipAI::searchNewTarget()
250    {
251        this->targetPosition_ = this->getPosition();
252        this->forgetTarget();
253
254        for (Iterator<SpaceShip> it = ObjectList<SpaceShip>::begin(); it; ++it)
255        {
256            if (it->getTeamNr() != this->getTeamNr())
257            {
258                float speed = this->getVelocity().length();
259                Vector3 distanceCurrent = this->targetPosition_ - this->getPosition();
260                Vector3 distanceNew = it->getPosition() - this->getPosition();
261                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))
262                        < 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))
263                {
264                    this->target_ = (*it);
265                    this->targetPosition_ = it->getPosition();
266                }
267            }
268        }
269    }
270
271    void SpaceShipAI::forgetTarget()
272    {
273        this->target_ = 0;
274        this->bShooting_ = false;
275    }
276
277    void SpaceShipAI::aimAtTarget()
278    {
279        if (!this->target_)
280            return;
281
282        Vector3 enemymovement = this->target_->getVelocity();
283        Vector3 distance_normalised = this->target_->getPosition() - this->getPosition();
284        distance_normalised.normalise();
285
286        float scalarprod = enemymovement.dotProduct(distance_normalised);
287        float aimoffset = scalarprod*scalarprod + Projectile::getSpeed() * Projectile::getSpeed() - this->target_->getVelocity().squaredLength();
288
289        if (aimoffset < 0)
290        {
291            this->bHasTargetPosition_ = false;
292            return;
293        }
294        aimoffset = -scalarprod + sqrt(aimoffset);
295        this->targetPosition_ = this->getPosition() + enemymovement + distance_normalised * aimoffset;
296        this->bHasTargetPosition_ = true;
297    }
298
299    bool SpaceShipAI::isCloseAtTarget(float distance)
300    {
301        if (!this->target_)
302            return (this->getPosition().squaredDistance(this->targetPosition_) < distance*distance);
303        else
304            return (this->getPosition().squaredDistance(this->target_->getPosition()) < distance*distance);
305    }
306
307    bool SpaceShipAI::isLookingAtTarget(float angle)
308    {
309        Vector3 dist = this->targetPosition_ - this->getPosition();
310        return (acos((this->getDir().dotProduct(dist)) / (dist.length() * this->getDir().length())) < angle);
311    }
312
313    void SpaceShipAI::shipDied(SpaceShipAI* ship)
314    {
315        this->forgetTarget();
316        this->searchNewTargetPosition();
317    }
318}
Note: See TracBrowser for help on using the repository browser.