Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11815 was 11781, checked in by landauf, 7 years ago

eol-style native (no changes in code)

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