Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/Presentation_HS17_merge/src/modules/asteroidmining/AsteroidMinable.cc @ 11732

Last change on this file since 11732 was 11732, checked in by landauf, 6 years ago

[AsteroidMining_HS17] fixed a bunch of compile- and run-time errors due to illegal usage of arrays

File size: 15.0 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 *      Simon Miescher
26 *
27 */
28
29/*
30
31    @file
32    @author remartin
33    @brief An asteroid which can be destroyed. Some smaller asteroids are created and a pickup spawns.
34
35HANDBUCH:
36o Die Collision Shape kann nur im Konstruktor hinzugefügt werden. Die XML-Argumente werden aber erst nach dem Konstruktor gesetzt.
37  Darum wird hier beim ersten Aufruf der tick()-Methode via putStuff() ein komplett neuer Asteroid generiert und der alte zerstört.
38o im Level-File includes/pickups.oxi importieren.
39
40OFFEN/Weiterentwicklung:
41o @TODO Add resource pickups.
42--> data_extern/images/effects: PNG's für die Pickups
43--> https://www.orxonox.net/jenkins/view/Management/job/orxonox_doxygen_trunk/javadoc/group___pickup.html
44
45o Density doesn't add up to 1...
46o Does collision damage work properly
47o Add sound effect (crunching etc. ) (No sound in space...)
48o Explosion parts
49
50ANDERORTS VERÄNDERTE SACHEN:
51Pickup-Zeug:
52o Pickup.h: createSpawner() neu public statt private
53o PickupSpawner.h: Zugriffsrechte setPickupTemplateName() und setMaxSpawnedItems()
54o PickupSpawner.h: In Tick() zwei Testbedingungen eingefügt.
55o Pawn.h: Attribut acceptsPickups_ inklusive get/set.
56
57ERLEGTE FEHLER:
58o Grössenabhängige Collision Shape -> putStuff-Methode, Werte noch nicht durchgesickert.
59o setHealth: maxHealth() des pawns setzen!
60o Asteroiden fressen Pickups: Argument in Pawn, Test darauf in Tick() von PickupSpawner.
61o i++ einfach ganz verhindern, ++i stattdessen.
62o Velocity didn-t get passed properly through the 2nd constructor. Used get/set instead.
63o Rand() geht bis zu riesigen Nummern! rnd() ist zwischen 0 und 1
64
65NOTIZEN:
66o SUPER
67o Warnungsverhinderung anderswo: (void)pickedUp; // To avoid compiler warning.
68o friend class Pickupable;
69
70
71
72*/
73
74
75#include "../../orxonox/worldentities/pawns/Pawn.h"
76#include "../../orxonox/worldentities/WorldEntity.h"
77
78#include "AsteroidMinable.h"
79
80#include <algorithm>
81
82#include "core/CoreIncludes.h"
83#include "core/GameMode.h"
84#include "core/XMLPort.h"
85#include "core/EventIncludes.h"
86#include "network/NetworkFunction.h"
87#include "util/Convert.h"
88#include "util/Math.h"
89
90#include "../pickup/PickupSpawner.h"
91#include "../pickup/Pickup.h"
92
93#include "../objects/collisionshapes/SphereCollisionShape.h"
94#include "../../orxonox/graphics/Model.h"
95
96
97namespace orxonox{
98
99    RegisterClass(AsteroidMinable);
100
101    // @brief Standard constructor
102    AsteroidMinable::AsteroidMinable(Context* context) : Pawn(context){
103
104        RegisterObject(AsteroidMinable);
105        this->context = context;
106
107        // Default Values:
108        this->size = 10; 
109        this->dropStuff = true; 
110        this->generateSmaller = true; 
111        this->health_ = 15*size; 
112        this->maxHealth_ = this->health_;
113        this->acceptsPickups_ = false; 
114
115        this->setCollisionType(WorldEntity::CollisionType::Dynamic);
116        this->enableCollisionCallback();
117
118        // Old from Pawn
119        this->registerVariables();
120
121        this->initialised = false;
122    }
123
124    // @brief Use this constructor with care. Mainly used internally, arguments are passed directly.
125    AsteroidMinable::AsteroidMinable(Context* c, float size, Vector3 position, bool dropStuff) : Pawn(c){
126
127        RegisterObject(AsteroidMinable);
128
129        // The radar is able to detect whether an asteroid contains resources....
130        if(dropStuff){
131            this->setRadarObjectColour(ColourValue(1.0f, 1.0f, 0.0f, 1.0f));
132            this->setRadarObjectShape(RadarViewable::Shape::Dot);
133        }else{
134            // Somehow remove from radar? (all pawns get registered automatically... )
135            this->setRadarObjectColour(ColourValue(0.663f, 0.663f, 0.663f, 1.0f));
136            this->setRadarObjectShape(RadarViewable::Shape::Dot);
137        }
138
139        this->context = c;
140        this->size = size;
141        this->health_ = 15*size; 
142        this->maxHealth_ = this->health_;
143        this->acceptsPickups_ = false; 
144        this->generateSmaller = true; 
145        this->dropStuff = dropStuff; 
146
147        this->setPosition(position);
148        //this->roll = rand()*5; //etwas Drehung. Richtige Variable?
149
150        this->setCollisionType(WorldEntity::CollisionType::Dynamic);
151        this->enableCollisionCallback();
152
153        // Add Model, random one of the 6 shapes
154        Model* hull = new Model(this->context);
155        hull->setMeshSource("ast" + multi_cast<std::string>(1 + (int)rnd(0, 6)) + ".mesh");
156        hull->setScale(this->size);
157        this->attach(hull);
158
159        // Collision shape
160        SphereCollisionShape* cs = new SphereCollisionShape(this->context);
161        cs->setRadius((this->size)*2); //OFFEN: Feinabstimmung der Radien.
162        this->attachCollisionShape(cs); 
163
164        this->registerVariables();
165
166        this->initialised=true; 
167
168    }
169
170    AsteroidMinable::~AsteroidMinable(){
171
172    }
173
174    // @brief Helper method.
175    void AsteroidMinable::putStuff(){
176
177        AsteroidMinable* reborn = new AsteroidMinable(this->context, this->size, this->getPosition(), this->dropStuff);
178        reborn->setVelocity(this->getVelocity());
179        // reborn->setAngularVelocity(this->getAngularVelocity()); // Add all other stuff, too?
180        (void)reborn; // avoid compiler warning
181
182        this->bAlive_ = false;
183        this->destroyLater();
184
185    }
186
187    void AsteroidMinable::XMLPort(Element& xmlelement, XMLPort::Mode mode){
188
189        SUPER(AsteroidMinable, XMLPort, xmlelement, mode); 
190
191        XMLPortParam(AsteroidMinable, "size", setSize, getSize, xmlelement, mode);
192        XMLPortParam(AsteroidMinable, "generateSmaller", toggleShattering, doesShatter, xmlelement, mode);
193        XMLPortParam(AsteroidMinable, "dropStuff", toggleDropStuff, doesDropStuff, xmlelement, mode); 
194
195    }
196
197    void AsteroidMinable::XMLEventPort(Element& xmlelement, XMLPort::Mode mode){
198
199        SUPER(AsteroidMinable, XMLEventPort, xmlelement, mode);
200
201    }
202
203    void AsteroidMinable::registerVariables(){
204
205        registerVariable(this->size, VariableDirection::ToClient);
206        registerVariable(this->generateSmaller, VariableDirection::ToClient);
207        registerVariable(this->dropStuff, VariableDirection::ToClient); 
208        registerVariable(this->initialised, VariableDirection::ToClient);
209
210    }
211
212    void AsteroidMinable::tick(float dt){
213
214        if(!(this->initialised)){this->putStuff();} 
215
216        if(this->health_ <=0){this->death();}
217
218    }
219
220    void AsteroidMinable::death(){ // @brief Überschreibt die Methode in Pawn
221
222        // just copied that from somewhere else.
223        this->bAlive_ = false;
224        this->destroyLater();
225        this->setDestroyWhenPlayerLeft(false);
226        // pawn -> addExplosionPart
227        // this->goWithStyle();
228
229
230        // Pickups which can be harvested. It's munition at the moment, could be changed/extended.
231        if(dropStuff){
232            PickupSpawner* thingy = new PickupSpawner(this->context);
233
234            std::string tname;
235            if(this->size <= 5){
236                tname = "smallmunitionpickup";
237            }else if(this->size <= 20){
238                tname = "mediummunitionpickup";
239            }else{
240                tname = "hugemunitionpickup";
241            }
242            thingy->setPickupTemplateName(tname);
243            thingy->setPosition(this->getPosition());
244            thingy->setMaxSpawnedItems(1); // Would be default anyways
245            thingy->setRespawnTime(0.2f);
246        }
247
248        // Smaller Parts = 'Children'
249        if(this->generateSmaller){this->spawnChildren();}
250
251    }
252
253// @brief If the option generateSmaller is enabled, individual fragments are added with this method.
254    void AsteroidMinable::spawnChildren(){
255
256    if (this->size <=1){return;} // Absicherung trivialer Fall
257
258    int massRem = this->size-1; //some mass is lost
259    int num = round(rnd()*(massRem-1)) + 1; // random number of children, at least one
260    if(num > 10){num = 10;} // no max function in C?
261    std::vector<int> masses(num); // Masses of the asteroids
262    // orxout() << "SpawnChildren(): Passed basic stuff. num = " << num << "; massRem(total) = "<< massRem << endl;
263    massRem = massRem-num; // mass must be at least one, add later. 
264
265    // Randomnised spawning points for the new asteroids
266    std::vector<float> phi(num);
267    std::vector<float> theta(num);
268
269    // Discusting C stuff -> use that to initialise dynamic array values to 0.
270    for(int twat = 0; twat<num; ++twat)
271    {
272        masses[twat] = 0;
273        phi[twat] = 0.0f;
274        theta[twat] = 0.0f;
275    }
276
277    float piG = 3.1415927410125732421875; //pi; // Math.pi ist statisch oder so.
278    float d_p = 2*piG/num;
279    float d_t = piG/num;
280    float p = d_p/2.0;
281    float t = d_t/2.0;
282    // float phiOffset = rnd()*2*pi; // Added everywhere to become independent of the coordinate system?
283    // float thetaOffset = rnd()*pi;
284    float rScaling; // scale radius to prevent asteroids from touching. (distance=AsteroidRadius/tan(sector/2))
285
286    if(num == 1 ){
287        rScaling = 1; // avoid tan(90). Unused.
288    }else{
289
290        rScaling = tan(t); 
291
292        int pos; // insert at random position (linear probing) in array, to get some randomness. 
293        for(int it = 0; it<num; ++it){
294
295            pos = mod((int)(rnd()*num),num); 
296            while(phi[pos] != 0.0){// find empty spot in array
297                pos = (int)mod(++pos, num);
298            }
299            phi[pos] = p + it*d_p;// set angle there
300
301            pos = mod((int)(rnd()*num),num);
302            while(theta[pos] != 0.0){
303                pos = (int)mod(++pos, num);
304            }
305            theta[pos] = t + it*d_t;
306        }
307    }
308
309    //orxout() << "SpawnChildren(): Phi: "; printArrayString(phi);
310    //orxout() << "SpawnChildren(): Theta: "; printArrayString(theta);
311    //orxout() << "SpawnChildren(): Passed angle stuff. " << endl;
312
313    // Triangular, discrete probability "density" with max at the average value massRem/num. 50% chance to be below that.
314    if(massRem>0){
315        int c = massRem;
316        std::vector<float> probDensity(c);
317
318        int a = round(massRem/num);
319        int b = c-a;
320       
321        int z = 0;
322        float dProbA = 1.0/(a*a + 3.0*a + 2.0); // one 'probability unit' for discrete ramp function. Gauss stuff.
323        for(z = 0; z<=a; ++z){probDensity[z] = (z+1)*dProbA; } // rising part
324
325        float dProbB = 1.0/(b*b +3.0*b + 2.0);
326        for(z = 0; z<b; ++z){probDensity[c-z] = (z+1)*dProbB;} // falling part
327   
328        // // Just for testing:
329        // float sum = 0.0;
330        // for(int globi = 0; globi<c; ++globi){
331        //     orxout() << "pDensity at [" << globi << "] is: " << probDensity[globi] << endl;
332        //     sum = sum+ probDensity[globi];
333        // }
334        // orxout() << "Sum of densities should b 1, it is: " << sum << endl;
335
336        // Distributing the mass to individual asteroids
337        int result; 
338        float rVal; // between 0 and 1
339        float probSum; // summing up until rval is reached.
340        for(int trav = 0; trav<num; ++trav){
341            result = 0;
342            rVal = rnd(); 
343            probSum = probDensity[0]; 
344
345            while(rVal>probSum && result<massRem){// Not yet found && there-s smth left to distribute (Incrementing inside!)
346                if(result<(massRem-2)){probSum = probSum + probDensity[result+1];} // avoid logical/acess error
347                ++result;
348            }
349
350            masses[trav] = 1 +result; // Fragments have mass of at least one.
351            massRem = massRem-result;
352
353        }
354    }else{
355        for(int schnaegg = 0; schnaegg<num; ++schnaegg){masses[schnaegg] = 1;}
356    }
357
358    // orxout() << "SpawnChildren(): Masses: "; printArrayString(masses);
359    // orxout() << "SpawnChildren(): Passed mass stuff. " << endl;
360
361    // Creating the 'chlidren':
362    for(int fisch = 0; fisch<num; ++fisch){
363
364        Vector3* pos = new Vector3(0,0,0); // Position offset
365        if(num > 1){// not required if there-s just one child
366            float r = masses[fisch]/rScaling;
367            pos = new Vector3(r*sin(theta[fisch])*cos(phi[fisch]), r*sin(theta[fisch])*sin(phi[fisch]), r*cos(theta[fisch])); // convert spheric coordinates to vector
368        }
369       
370        AsteroidMinable* child = new AsteroidMinable(this->context, masses[fisch], this->getPosition() + *pos, this->dropStuff);
371        child->setVelocity(this->getVelocity());
372
373        if(child == nullptr){
374            orxout(internal_error, context::pickups) << "Weird, can't create new AsteroidMinable." << endl;
375        }
376
377    }
378    // orxout() << "Leaving spawnChildren() method. " << endl;
379}
380
381// @brief overloading that to prevent asteroids from taking damage from each other (domino effect etc. )
382    void AsteroidMinable::hit(Pawn* originator, const Vector3& force, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){
383
384        // orxout() << "AsteroidMining::Hit(Variante 1) Dings aufgerufen. " << endl;
385        if(orxonox_cast<AsteroidMinable*>(originator) || orxonox_cast<Pickup*>(originator)){return;}
386        this->damage(damage, healthdamage, shielddamage, originator, cs);
387        this->setVelocity(this->getVelocity() + force);
388
389        // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator))// && (!this->getController() || !this->getController()->getGodMode()) )
390        // {
391        //     this->damage(damage, healthdamage, shielddamage, originator, cs);
392        //     this->setVelocity(this->getVelocity() + force);
393        // }
394    }
395
396// @brief overloading that to prevent asteroids from taking damage from each other (domino effect etc. )
397    void AsteroidMinable::hit(Pawn* originator, btManifoldPoint& contactpoint, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){
398
399        //orxout() << "AsteroidMining::Hit(Variante 2) Dings aufgerufen. " << endl;
400        if(orxonox_cast<AsteroidMinable*>(originator) || orxonox_cast<Pickup*>(originator)){return;}
401        this->damage(damage, healthdamage, shielddamage, originator, cs);
402
403        // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator))// && (!this->getController() || !this->getController()->getGodMode()) )
404        // {
405        //     this->damage(damage, healthdamage, shielddamage, originator, cs);
406
407        //     //if ( this->getController() )
408        //     //    this->getController()->hit(originator, contactpoint, damage); // changed to damage, why shielddamage?
409        // }
410    }
411}
Note: See TracBrowser for help on using the repository browser.