Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

[AsteroidMining_HS17] fixed a bunch of memory leaks

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