Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/AsteroidMining_HS17/src/modules/asteroidmining/AsteroidMinable.cc @ 11823

Last change on this file since 11823 was 11667, checked in by remartin, 7 years ago

Added tilting for the spicedAsteroidBelt. Finished commenting, polish up. Done.

File size: 16.8 KB
RevLine 
[11547]1
[11550]2 /*   ORXONOX - the hottest 3D action shooter ever to exist
[11547]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/*
[11550]30
[11667]31    @file
32    @author remartin
33    @brief An asteroid which can be destroyed. Some smaller asteroids are created and a pickup spawns.
[11664]34
[11667]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.
[11547]39
[11667]40OFFEN/Weiterentwicklung:
41o @TODO Add resource pickups.
42--> data_extern/images/effects: PNG's für die Pickups
[11640]43--> https://www.orxonox.net/jenkins/view/Management/job/orxonox_doxygen_trunk/javadoc/group___pickup.html
[11609]44
[11640]45o Density doesn't add up to 1...
[11667]46o Does collision damage work properly
[11640]47o Add sound effect (crunching etc. ) (No sound in space...)
[11561]48o Explosion parts
[11553]49
[11667]50ANDERORTS VERÄNDERTE SACHEN:
[11609]51Pickup-Zeug:
[11667]52o Pickup.h: createSpawner() neu public statt private
[11561]53o PickupSpawner.h: Zugriffsrechte setPickupTemplateName() und setMaxSpawnedItems()
[11667]54o PickupSpawner.h: In Tick() zwei Testbedingungen eingefügt.
[11609]55o Pawn.h: Attribut acceptsPickups_ inklusive get/set.
[11553]56
[11640]57ERLEGTE FEHLER:
[11667]58o Grössenabhängige Collision Shape -> putStuff-Methode, Werte noch nicht durchgesickert.
59o setHealth: maxHealth() des pawns setzen!
[11609]60o Asteroiden fressen Pickups: Argument in Pawn, Test darauf in Tick() von PickupSpawner.
[11615]61o i++ einfach ganz verhindern, ++i stattdessen.
[11667]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
[11586]64
[11587]65NOTIZEN:
[11667]66o SUPER
[11609]67o Warnungsverhinderung anderswo: (void)pickedUp; // To avoid compiler warning.
[11667]68o friend class Pickupable;
[11587]69
[11609]70
71
[11551]72*/
73
74
[11547]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"
[11615]86#include "network/NetworkFunction.h"
87#include "util/Math.h"
[11547]88
89#include "../pickup/PickupSpawner.h"
90#include "../pickup/Pickup.h"
[11664]91
[11547]92#include "../objects/collisionshapes/SphereCollisionShape.h"
93#include "../../orxonox/graphics/Model.h"
94
95
[11664]96namespace orxonox{
[11547]97
98    RegisterClass(AsteroidMinable);
99
[11640]100    // @brief Standard constructor
[11586]101    AsteroidMinable::AsteroidMinable(Context* context) : Pawn(context){
[11581]102
[11586]103        RegisterObject(AsteroidMinable);
[11547]104        this->context = context;
105
[11664]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
[11586]114        this->setCollisionType(WorldEntity::CollisionType::Dynamic);
[11664]115        this->enableCollisionCallback();
[11547]116
[11586]117        // Old from Pawn
118        this->registerVariables();
[11553]119
[11664]120        this->initialised = false;
[11586]121    }
[11547]122
[11640]123    // @brief Use this constructor with care. Mainly used internally, arguments are passed directly.
[11667]124    AsteroidMinable::AsteroidMinable(Context* c, float size, Vector3 position, bool dropStuff) : Pawn(c){
[11547]125
[11586]126        RegisterObject(AsteroidMinable);
[11547]127
[11640]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{
[11667]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);
[11640]136        }
137
[11587]138        this->context = c;
[11618]139        this->size = size;
140        this->health_ = 15*size; 
[11587]141        this->maxHealth_ = this->health_;
[11640]142        this->acceptsPickups_ = false; 
143        this->generateSmaller = true; 
144        this->dropStuff = dropStuff; 
[11609]145
[11587]146        this->setPosition(position);
[11664]147        //this->roll = rand()*5; //etwas Drehung. Richtige Variable?
[11547]148
[11664]149        this->setCollisionType(WorldEntity::CollisionType::Dynamic);
150        this->enableCollisionCallback();
[11547]151
[11664]152        // Add Model, random one of the 6 shapes
[11551]153        Model* hull = new Model(this->context);
154        char meshThingy[] = "";
[11664]155        sprintf(meshThingy, "ast%.0f.mesh", round(5*rnd())+1); 
[11551]156        hull->setMeshSource(meshThingy);
157        hull->setScale(this->size);
158        this->attach(hull);
[11547]159
[11551]160        // Collision shape
161        SphereCollisionShape* cs = new SphereCollisionShape(this->context);
[11664]162        cs->setRadius((this->size)*2); //OFFEN: Feinabstimmung der Radien.
[11551]163        this->attachCollisionShape(cs); 
[11547]164
[11586]165        this->registerVariables();
[11547]166
[11581]167        this->initialised=true; 
168
[11547]169    }
170
[11586]171    AsteroidMinable::~AsteroidMinable(){
172
173    }
[11664]174
[11667]175    // @brief Helper method.
[11586]176    void AsteroidMinable::putStuff(){
177
[11667]178        AsteroidMinable* reborn = new AsteroidMinable(this->context, this->size, this->getPosition(), this->dropStuff);
179        reborn->setVelocity(this->getVelocity());
180        // reborn->setAngularVelocity(this->getAngularVelocity()); // Add all other stuff, too?
[11664]181        (void)reborn; // avoid compiler warning
[11667]182
[11640]183        this->bAlive_ = false;
184        this->destroyLater();
[11586]185
186    }
187
[11664]188    void AsteroidMinable::XMLPort(Element& xmlelement, XMLPort::Mode mode){
189
190        SUPER(AsteroidMinable, XMLPort, xmlelement, mode); 
191
[11547]192        XMLPortParam(AsteroidMinable, "size", setSize, getSize, xmlelement, mode);
[11664]193        XMLPortParam(AsteroidMinable, "generateSmaller", toggleShattering, doesShatter, xmlelement, mode);
194        XMLPortParam(AsteroidMinable, "dropStuff", toggleDropStuff, doesDropStuff, xmlelement, mode); 
[11547]195
196    }
197
[11664]198    void AsteroidMinable::XMLEventPort(Element& xmlelement, XMLPort::Mode mode){
199
[11547]200        SUPER(AsteroidMinable, XMLEventPort, xmlelement, mode);
201
202    }
203
[11664]204    void AsteroidMinable::registerVariables(){
[11551]205
206        registerVariable(this->size, VariableDirection::ToClient);
207        registerVariable(this->generateSmaller, VariableDirection::ToClient);
[11664]208        registerVariable(this->dropStuff, VariableDirection::ToClient); 
[11553]209        registerVariable(this->initialised, VariableDirection::ToClient);
210
[11547]211    }
212
[11664]213    void AsteroidMinable::tick(float dt){
214
[11618]215        if(!(this->initialised)){this->putStuff();} 
[11547]216
[11551]217        if(this->health_ <=0){this->death();}
218
[11547]219    }
220
[11667]221    void AsteroidMinable::death(){ // @brief Überschreibt die Methode in Pawn
[11547]222
[11664]223        // just copied that from somewhere else.
[11581]224        this->bAlive_ = false;
225        this->destroyLater();
226        this->setDestroyWhenPlayerLeft(false);
227        // pawn -> addExplosionPart
228        // this->goWithStyle();
[11551]229
[11547]230
[11667]231        // Pickups which can be harvested. It's munition at the moment, could be changed/extended.
[11640]232        if(dropStuff){
233            PickupSpawner* thingy = new PickupSpawner(this->context);
[11667]234
[11640]235            char tname[] = ""; // can-t overwrite strings easily in C (strcat etc.)
236            if(this->size <= 5){
237                strcat(tname, "smallmunitionpickup");
238            }else if(this->size <= 20){
239                strcat(tname, "mediummunitionpickup");
240            }else{
241                strcat(tname, "hugemunitionpickup");
242            }
243            thingy->setPickupTemplateName(tname);
244            thingy->setPosition(this->getPosition());
245            thingy->setMaxSpawnedItems(1); // Would be default anyways
246            thingy->setRespawnTime(0.2f);
[11609]247        }
[11553]248
[11561]249        // Smaller Parts = 'Children'
[11618]250        if(this->generateSmaller){this->spawnChildren();}
[11553]251
[11547]252    }
253
[11667]254// @brief If the option generateSmaller is enabled, individual fragments are added with this method.
255    void AsteroidMinable::spawnChildren(){
[11547]256
[11581]257    if (this->size <=1){return;} // Absicherung trivialer Fall
258
[11547]259    int massRem = this->size-1; //some mass is lost
[11615]260    int num = round(rnd()*(massRem-1)) + 1; // random number of children, at least one
[11667]261    if(num > 10){num = 10;} // no max function in C?
262    int masses[num]; // Masses of the asteroids
[11664]263    // orxout() << "SpawnChildren(): Passed basic stuff. num = " << num << "; massRem(total) = "<< massRem << endl;
[11667]264    massRem = massRem-num; // mass must be at least one, add later. 
[11664]265
[11615]266    // Randomnised spawning points for the new asteroids
[11664]267    float phi[num]; 
268    float theta[num]; 
269
270    // Discusting C stuff -> use that to initialise dynamic array values to 0.
271    for(int twat = 0; twat<num; ++twat){masses[twat] = 0; phi[twat] = 0.0; theta[twat] = 0.0;}
272
[11640]273    float piG = 3.1415927410125732421875; //pi; // Math.pi ist statisch oder so.
[11618]274    float d_p = 2*piG/num;
275    float d_t = piG/num;
276    float p = d_p/2.0;
277    float t = d_t/2.0;
278    // float phiOffset = rnd()*2*pi; // Added everywhere to become independent of the coordinate system?
[11615]279    // float thetaOffset = rnd()*pi;
[11618]280    float rScaling; // scale radius to prevent asteroids from touching. (distance=AsteroidRadius/tan(sector/2))
[11664]281
[11618]282    if(num == 1 ){
283        rScaling = 1; // avoid tan(90). Unused.
284    }else{
[11609]285
[11618]286        rScaling = tan(t); 
[11609]287
[11618]288        int pos; // insert at random position (linear probing) in array, to get some randomness. 
289        for(int it = 0; it<num; ++it){
[11609]290
[11618]291            pos = mod((int)(rnd()*num),num); 
292            while(phi[pos] != 0.0){// find empty spot in array
293                pos = (int)mod(++pos, num);
294            }
295            phi[pos] = p + it*d_p;// set angle there
[11561]296
[11618]297            pos = mod((int)(rnd()*num),num);
298            while(theta[pos] != 0.0){
299                pos = (int)mod(++pos, num);
300            }
301            theta[pos] = t + it*d_t;
[11615]302        }
303    }
[11561]304
[11618]305    //orxout() << "SpawnChildren(): Phi: "; printArrayString(phi);
306    //orxout() << "SpawnChildren(): Theta: "; printArrayString(theta);
[11640]307    //orxout() << "SpawnChildren(): Passed angle stuff. " << endl;
[11561]308
[11667]309    // Triangular, discrete probability "density" with max at the average value massRem/num. 50% chance to be below that.
310    if(massRem>0){
[11615]311        int c = massRem;
[11641]312        float probDensity[c];
[11581]313
[11615]314        int a = round(massRem/num);
315        int b = c-a;
[11618]316       
[11615]317        int z = 0;
[11618]318        float dProbA = 1.0/(a*a + 3.0*a + 2.0); // one 'probability unit' for discrete ramp function. Gauss stuff.
319        for(z = 0; z<=a; ++z){probDensity[z] = (z+1)*dProbA; } // rising part
320
321        float dProbB = 1.0/(b*b +3.0*b + 2.0);
322        for(z = 0; z<b; ++z){probDensity[c-z] = (z+1)*dProbB;} // falling part
[11615]323   
[11640]324        // // Just for testing:
325        // float sum = 0.0;
326        // for(int globi = 0; globi<c; ++globi){
327        //     orxout() << "pDensity at [" << globi << "] is: " << probDensity[globi] << endl;
328        //     sum = sum+ probDensity[globi];
329        // }
330        // orxout() << "Sum of densities should b 1, it is: " << sum << endl;
[11581]331
[11618]332        // Distributing the mass to individual asteroids
[11667]333        int result; 
334        float rVal; // between 0 and 1
335        float probSum; // summing up until rval is reached.
[11618]336        for(int trav = 0; trav<num; ++trav){
[11667]337            result = 0;
338            rVal = rnd(); 
[11618]339            probSum = probDensity[0]; 
340
[11667]341            while(rVal>probSum && result<massRem){// Not yet found && there-s smth left to distribute (Incrementing inside!)
[11640]342                if(result<(massRem-2)){probSum = probSum + probDensity[result+1];} // avoid logical/acess error
[11615]343                ++result;
344            }
[11561]345
[11667]346            masses[trav] = 1 +result; // Fragments have mass of at least one.
[11615]347            massRem = massRem-result;
[11667]348
[11547]349        }
[11664]350    }else{
351        for(int schnaegg = 0; schnaegg<num; ++schnaegg){masses[schnaegg] = 1;}
[11615]352    }
[11551]353
[11640]354    // orxout() << "SpawnChildren(): Masses: "; printArrayString(masses);
355    // orxout() << "SpawnChildren(): Passed mass stuff. " << endl;
[11551]356
[11618]357    // Creating the 'chlidren':
358    for(int fisch = 0; fisch<num; ++fisch){
[11551]359
[11618]360        Vector3* pos = new Vector3(0,0,0); // Position offset
361        if(num > 1){// not required if there-s just one child
362            float r = masses[fisch]/rScaling;
363            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
364        }
365       
[11667]366        AsteroidMinable* child = new AsteroidMinable(this->context, masses[fisch], this->getPosition() + *pos, this->dropStuff);
367        child->setVelocity(this->getVelocity());
[11551]368
[11581]369        if(child == nullptr){
370            orxout(internal_error, context::pickups) << "Weird, can't create new AsteroidMinable." << endl;
371        }
[11553]372
[11547]373    }
[11640]374    // orxout() << "Leaving spawnChildren() method. " << endl;
[11547]375}
376
[11667]377// @brief overloading that to prevent asteroids from taking damage from each other (domino effect etc. )
[11581]378    void AsteroidMinable::hit(Pawn* originator, const Vector3& force, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){
[11547]379
[11667]380        // orxout() << "AsteroidMining::Hit(Variante 1) Dings aufgerufen. " << endl;
[11581]381        if(orxonox_cast<AsteroidMinable*>(originator) || orxonox_cast<Pickup*>(originator)){return;}
382        this->damage(damage, healthdamage, shielddamage, originator, cs);
383        this->setVelocity(this->getVelocity() + force);
384
385        // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator))// && (!this->getController() || !this->getController()->getGodMode()) )
386        // {
387        //     this->damage(damage, healthdamage, shielddamage, originator, cs);
388        //     this->setVelocity(this->getVelocity() + force);
389        // }
390    }
391
[11667]392// @brief overloading that to prevent asteroids from taking damage from each other (domino effect etc. )
[11581]393    void AsteroidMinable::hit(Pawn* originator, btManifoldPoint& contactpoint, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){
394
[11609]395        //orxout() << "AsteroidMining::Hit(Variante 2) Dings aufgerufen. " << endl;
[11581]396        if(orxonox_cast<AsteroidMinable*>(originator) || orxonox_cast<Pickup*>(originator)){return;}
397        this->damage(damage, healthdamage, shielddamage, originator, cs);
398
399        // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator))// && (!this->getController() || !this->getController()->getGodMode()) )
400        // {
401        //     this->damage(damage, healthdamage, shielddamage, originator, cs);
402
403        //     //if ( this->getController() )
404        //     //    this->getController()->hit(originator, contactpoint, damage); // changed to damage, why shielddamage?
405        // }
406    }
407
[11640]408    // @brief Just for testing. Don-t work anyways.
[11618]409    void AsteroidMinable::printArrayString(float thingy[]){ // Don-t work!
[11581]410
[11618]411        orxout() << "[" ; //<< endl; 
412        char frag[] = "";
413        int len = (int)(sizeof(thingy)/sizeof(thingy[0]));
414        for(int m = 0; m< (len-2); ++m){
415            sprintf(frag, "%.5f, ", thingy[m]);
416            orxout() << frag << endl;//std::flush;
417        }
418        sprintf(frag, "%.5f]", thingy[len-1]);
419        orxout() << frag << endl; // Just print it here! No ugly passing.
420    }
[11581]421
[11640]422    // @brief Just for testing. Don-t work anyways.
[11618]423    void AsteroidMinable::printArrayString(int thingy[]){
[11581]424
[11618]425        orxout() << "[" ; //<< endl;
426        char frag[] = "";
427        int len = (int)(sizeof(thingy)/sizeof(thingy[0]));
428        for(int m = 0; m< (len-2); ++m){
429            sprintf(frag, "%.0i, ", thingy[m]);
430            orxout() << frag << endl;//std::flush;
431            printf("TEst");
432        }
[11581]433
[11618]434        sprintf(frag, "%.0i]", thingy[len-1]); // last element
435        orxout() << frag << endl; // Just print it here! No ugly passing.
436    }
[11581]437
[11618]438    // void AsteroidMinable::printArrayString(int thingy[]){
439    //     char res[] = "[";
440    //     //strcat(res, "[");
441    //     char frag[] = "";
442
443    //     int len = (int)(sizeof(thingy)/sizeof(thingy[0]));
444    //     for(int m = 0; m< (len-1); ++m){
445    //         sprintf(frag, "%.0i, ", thingy[m]);
446    //         strcat(res, frag);
447    //     }
448    //     sprintf(frag, "%.0i]", thingy[len]);
449    //     strcat(res, frag); // last element
450
451    //     orxout() << res << endl; // Just print it here! No ugly passing.
452
453    //     // static char result[(sizeof(res)/sizeof("")] = res; // define as static, would get deleted otherwise.
454    //     // char *result = malloc(sizeof(res)/sizeof("") + 1);
455    //     // *result = res;
456    //     // return result;
457    // }
458
[11640]459}
Note: See TracBrowser for help on using the repository browser.