Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

[AsteroidMining_HS17] cleanup changes in common code

File size: 14.9 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        (void)reborn; // avoid compiler warning
180
181        this->bAlive_ = false;
182        this->destroyLater();
183
184    }
185
186    void AsteroidMinable::XMLPort(Element& xmlelement, XMLPort::Mode mode){
187
188        SUPER(AsteroidMinable, XMLPort, xmlelement, mode); 
189
190        XMLPortParam(AsteroidMinable, "size", setSize, getSize, xmlelement, mode);
191        XMLPortParam(AsteroidMinable, "generateSmaller", toggleShattering, doesShatter, xmlelement, mode);
192        XMLPortParam(AsteroidMinable, "dropStuff", toggleDropStuff, doesDropStuff, xmlelement, mode); 
193
194    }
195
196    void AsteroidMinable::XMLEventPort(Element& xmlelement, XMLPort::Mode mode){
197
198        SUPER(AsteroidMinable, XMLEventPort, xmlelement, mode);
199
200    }
201
202    void AsteroidMinable::registerVariables(){
203
204        registerVariable(this->size, VariableDirection::ToClient);
205        registerVariable(this->generateSmaller, VariableDirection::ToClient);
206        registerVariable(this->dropStuff, VariableDirection::ToClient); 
207        registerVariable(this->initialised, VariableDirection::ToClient);
208
209    }
210
211    void AsteroidMinable::tick(float dt){
212
213        if(!(this->initialised)){this->putStuff();} 
214
215        if(this->health_ <=0){this->death();}
216
217    }
218
219    void AsteroidMinable::death(){ // @brief Überschreibt die Methode in Pawn
220
221        // just copied that from somewhere else.
222        this->bAlive_ = false;
223        this->destroyLater();
224        this->setDestroyWhenPlayerLeft(false);
225        // pawn -> addExplosionPart
226        // this->goWithStyle();
227
228
229        // Pickups which can be harvested. It's munition at the moment, could be changed/extended.
230        if(dropStuff){
231            PickupSpawner* thingy = new PickupSpawner(this->context);
232
233            std::string tname;
234            if(this->size <= 5){
235                tname = "smallmunitionpickup";
236            }else if(this->size <= 20){
237                tname = "mediummunitionpickup";
238            }else{
239                tname = "hugemunitionpickup";
240            }
241            thingy->setPickupTemplateName(tname);
242            thingy->setPosition(this->getPosition());
243            thingy->setMaxSpawnedItems(1); // Would be default anyways
244            thingy->setRespawnTime(0.2f);
245        }
246
247        // Smaller Parts = 'Children'
248        if(this->generateSmaller){this->spawnChildren();}
249
250    }
251
252// @brief If the option generateSmaller is enabled, individual fragments are added with this method.
253    void AsteroidMinable::spawnChildren(){
254
255    if (this->size <=1){return;} // Absicherung trivialer Fall
256
257    int massRem = this->size-1; //some mass is lost
258    int num = round(rnd()*(massRem-1)) + 1; // random number of children, at least one
259    if(num > 10){num = 10;} // no max function in C?
260    std::vector<int> masses(num); // Masses of the asteroids
261    // orxout() << "SpawnChildren(): Passed basic stuff. num = " << num << "; massRem(total) = "<< massRem << endl;
262    massRem = massRem-num; // mass must be at least one, add later. 
263
264    // Randomnised spawning points for the new asteroids
265    std::vector<float> phi(num);
266    std::vector<float> theta(num);
267
268    // Discusting C stuff -> use that to initialise dynamic array values to 0.
269    for(int twat = 0; twat<num; ++twat)
270    {
271        masses[twat] = 0;
272        phi[twat] = 0.0f;
273        theta[twat] = 0.0f;
274    }
275
276    float piG = 3.1415927410125732421875; //pi; // Math.pi ist statisch oder so.
277    float d_p = 2*piG/num;
278    float d_t = piG/num;
279    float p = d_p/2.0;
280    float t = d_t/2.0;
281    // float phiOffset = rnd()*2*pi; // Added everywhere to become independent of the coordinate system?
282    // float thetaOffset = rnd()*pi;
283    float rScaling; // scale radius to prevent asteroids from touching. (distance=AsteroidRadius/tan(sector/2))
284
285    if(num == 1 ){
286        rScaling = 1; // avoid tan(90). Unused.
287    }else{
288
289        rScaling = tan(t); 
290
291        int pos; // insert at random position (linear probing) in array, to get some randomness. 
292        for(int it = 0; it<num; ++it){
293
294            pos = mod((int)(rnd()*num),num); 
295            while(phi[pos] != 0.0){// find empty spot in array
296                pos = (int)mod(++pos, num);
297            }
298            phi[pos] = p + it*d_p;// set angle there
299
300            pos = mod((int)(rnd()*num),num);
301            while(theta[pos] != 0.0){
302                pos = (int)mod(++pos, num);
303            }
304            theta[pos] = t + it*d_t;
305        }
306    }
307
308    //orxout() << "SpawnChildren(): Phi: "; printArrayString(phi);
309    //orxout() << "SpawnChildren(): Theta: "; printArrayString(theta);
310    //orxout() << "SpawnChildren(): Passed angle stuff. " << endl;
311
312    // Triangular, discrete probability "density" with max at the average value massRem/num. 50% chance to be below that.
313    if(massRem>0){
314        int c = massRem;
315        std::vector<float> probDensity(c);
316
317        int a = round(massRem/num);
318        int b = c-a;
319       
320        int z = 0;
321        float dProbA = 1.0/(a*a + 3.0*a + 2.0); // one 'probability unit' for discrete ramp function. Gauss stuff.
322        for(z = 0; z<=a; ++z){probDensity[z] = (z+1)*dProbA; } // rising part
323
324        float dProbB = 1.0/(b*b +3.0*b + 2.0);
325        for(z = 0; z<b; ++z){probDensity[c-z] = (z+1)*dProbB;} // falling part
326   
327        // // Just for testing:
328        // float sum = 0.0;
329        // for(int globi = 0; globi<c; ++globi){
330        //     orxout() << "pDensity at [" << globi << "] is: " << probDensity[globi] << endl;
331        //     sum = sum+ probDensity[globi];
332        // }
333        // orxout() << "Sum of densities should b 1, it is: " << sum << endl;
334
335        // Distributing the mass to individual asteroids
336        int result; 
337        float rVal; // between 0 and 1
338        float probSum; // summing up until rval is reached.
339        for(int trav = 0; trav<num; ++trav){
340            result = 0;
341            rVal = rnd(); 
342            probSum = probDensity[0]; 
343
344            while(rVal>probSum && result<massRem){// Not yet found && there-s smth left to distribute (Incrementing inside!)
345                if(result<(massRem-2)){probSum = probSum + probDensity[result+1];} // avoid logical/acess error
346                ++result;
347            }
348
349            masses[trav] = 1 +result; // Fragments have mass of at least one.
350            massRem = massRem-result;
351
352        }
353    }else{
354        for(int schnaegg = 0; schnaegg<num; ++schnaegg){masses[schnaegg] = 1;}
355    }
356
357    // orxout() << "SpawnChildren(): Masses: "; printArrayString(masses);
358    // orxout() << "SpawnChildren(): Passed mass stuff. " << endl;
359
360    // Creating the 'chlidren':
361    for(int fisch = 0; fisch<num; ++fisch){
362
363        Vector3* pos = new Vector3(0,0,0); // Position offset
364        if(num > 1){// not required if there-s just one child
365            float r = masses[fisch]/rScaling;
366            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
367        }
368       
369        AsteroidMinable* child = new AsteroidMinable(this->context, masses[fisch], this->getPosition() + *pos, this->dropStuff);
370        child->setVelocity(this->getVelocity());
371
372        if(child == nullptr){
373            orxout(internal_error, context::pickups) << "Weird, can't create new AsteroidMinable." << endl;
374        }
375
376    }
377    // orxout() << "Leaving spawnChildren() method. " << endl;
378}
379
380// @brief overloading that to prevent asteroids from taking damage from each other (domino effect etc. )
381    void AsteroidMinable::hit(Pawn* originator, const Vector3& force, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){
382
383        // orxout() << "AsteroidMining::Hit(Variante 1) Dings aufgerufen. " << endl;
384        if(orxonox_cast<AsteroidMinable*>(originator) || orxonox_cast<Pickup*>(originator)){return;}
385        this->damage(damage, healthdamage, shielddamage, originator, cs);
386        this->setVelocity(this->getVelocity() + force);
387
388        // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator))// && (!this->getController() || !this->getController()->getGodMode()) )
389        // {
390        //     this->damage(damage, healthdamage, shielddamage, originator, cs);
391        //     this->setVelocity(this->getVelocity() + force);
392        // }
393    }
394
395// @brief overloading that to prevent asteroids from taking damage from each other (domino effect etc. )
396    void AsteroidMinable::hit(Pawn* originator, btManifoldPoint& contactpoint, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){
397
398        //orxout() << "AsteroidMining::Hit(Variante 2) Dings aufgerufen. " << endl;
399        if(orxonox_cast<AsteroidMinable*>(originator) || orxonox_cast<Pickup*>(originator)){return;}
400        this->damage(damage, healthdamage, shielddamage, originator, cs);
401
402        // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator))// && (!this->getController() || !this->getController()->getGodMode()) )
403        // {
404        //     this->damage(damage, healthdamage, shielddamage, originator, cs);
405
406        //     //if ( this->getController() )
407        //     //    this->getController()->hit(originator, contactpoint, damage); // changed to damage, why shielddamage?
408        // }
409    }
410}
Note: See TracBrowser for help on using the repository browser.