Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/modules/asteroidmining/AsteroidMinable.cc @ 11801

Last change on this file since 11801 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
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 *      remartin
24 *   Co-authors:
25 *      ...
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#include "AsteroidMinable.h"
74
75#include <algorithm>
76
77#include "core/CoreIncludes.h"
78#include "core/GameMode.h"
79#include "core/XMLPort.h"
80#include "util/Convert.h"
81#include "util/Math.h"
82
83#include "pickup/PickupSpawner.h"
84#include "pickup/Pickup.h"
85
86#include "objects/collisionshapes/SphereCollisionShape.h"
87#include "graphics/Model.h"
88
89namespace orxonox{
90
91    RegisterClass(AsteroidMinable);
92
93    // @brief Standard constructor
94    AsteroidMinable::AsteroidMinable(Context* context) : Pawn(context){
95
96        RegisterObject(AsteroidMinable);
97
98        // Default Values:
99        this->size = 1;
100        this->dropStuff = true; 
101        this->generateSmaller = true; 
102        this->acceptsPickups_ = false; 
103
104        this->setCollisionType(WorldEntity::CollisionType::Dynamic);
105        this->enableCollisionCallback();
106
107        // Old from Pawn
108        this->registerVariables();
109
110        this->initialised = false;
111    }
112
113    AsteroidMinable::~AsteroidMinable(){
114
115    }
116
117    void AsteroidMinable::setSize(float s)
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
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{
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);
135        }
136
137        // Add Model, random one of the 6 shapes
138        Model* hull = new Model(this->getContext());
139        hull->setMeshSource("ast" + multi_cast<std::string>(1 + (int)rnd(0, 6)) + ".mesh");
140        hull->setScale(this->size);
141        this->attach(hull);
142
143        // Collision shape
144        SphereCollisionShape* cs = new SphereCollisionShape(this->getContext());
145        cs->setRadius((this->size)*2); //OFFEN: Feinabstimmung der Radien.
146        this->attachCollisionShape(cs); 
147
148        this->initialised=true; 
149    }
150
151    void AsteroidMinable::XMLPort(Element& xmlelement, XMLPort::Mode mode){
152
153        SUPER(AsteroidMinable, XMLPort, xmlelement, mode); 
154
155        XMLPortParam(AsteroidMinable, "size", setSize, getSize, xmlelement, mode);
156        XMLPortParam(AsteroidMinable, "generateSmaller", setShattering, doesShatter, xmlelement, mode);
157        XMLPortParam(AsteroidMinable, "dropStuff", setDropStuff, doesDropStuff, xmlelement, mode);
158
159    }
160
161    void AsteroidMinable::registerVariables(){
162
163        registerVariable(this->size, VariableDirection::ToClient);
164        registerVariable(this->generateSmaller, VariableDirection::ToClient);
165        registerVariable(this->dropStuff, VariableDirection::ToClient); 
166        registerVariable(this->initialised, VariableDirection::ToClient);
167
168    }
169
170    void AsteroidMinable::tick(float dt){
171
172        if(!(this->initialised)){this->putStuff();} 
173
174        if(this->health_ <=0){this->death();}
175
176    }
177
178    void AsteroidMinable::death(){ // @brief Überschreibt die Methode in Pawn
179
180        // just copied that from somewhere else.
181        this->bAlive_ = false;
182        this->destroyLater();
183        this->setDestroyWhenPlayerLeft(false);
184        // pawn -> addExplosionPart
185        // this->goWithStyle();
186
187
188        // Pickups which can be harvested. It's munition at the moment, could be changed/extended.
189        if(dropStuff){
190            PickupSpawner* thingy = new PickupSpawner(this->getContext());
191
192            std::string tname;
193            if(this->size <= 5){
194                tname = "smallmunitionpickup";
195            }else if(this->size <= 20){
196                tname = "mediummunitionpickup";
197            }else{
198                tname = "hugemunitionpickup";
199            }
200            thingy->setPickupTemplateName(tname);
201            thingy->setPosition(this->getPosition());
202            thingy->setMaxSpawnedItems(1); // Would be default anyways
203            thingy->setRespawnTime(0.2f);
204        }
205
206        // Smaller Parts = 'Children'
207        if(this->generateSmaller){this->spawnChildren();}
208
209    }
210
211// @brief If the option generateSmaller is enabled, individual fragments are added with this method.
212    void AsteroidMinable::spawnChildren(){
213
214    if (this->size <=1){return;} // Absicherung trivialer Fall
215
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
218    if(num > 10){num = 10;} // no max function in C?
219    std::vector<float> masses(num); // Masses of the asteroids
220    // orxout() << "SpawnChildren(): Passed basic stuff. num = " << num << "; massRem(total) = "<< massRem << endl;
221    massRem = massRem-num; // mass must be at least one, add later. 
222
223    // Randomnised spawning points for the new asteroids
224    std::vector<float> phi(num);
225    std::vector<float> theta(num);
226
227    // Discusting C stuff -> use that to initialise dynamic array values to 0.
228    for(int twat = 0; twat<num; ++twat)
229    {
230        masses[twat] = 0.0f;
231        phi[twat] = 0.0f;
232        theta[twat] = 0.0f;
233    }
234
235    float piG = 3.1415927410125732421875; //pi; // Math.pi ist statisch oder so.
236    float d_p = 2*piG/num;
237    float d_t = piG/num;
238    float p = d_p/2.0f;
239    float t = d_t/2.0f;
240    // float phiOffset = rnd()*2*pi; // Added everywhere to become independent of the coordinate system?
241    // float thetaOffset = rnd()*pi;
242    float rScaling; // scale radius to prevent asteroids from touching. (distance=AsteroidRadius/tan(sector/2))
243
244    if(num == 1 ){
245        rScaling = 1; // avoid tan(90). Unused.
246    }else{
247
248        rScaling = tan(t); 
249
250        int pos; // insert at random position (linear probing) in array, to get some randomness. 
251        for(int it = 0; it<num; ++it){
252
253            pos = mod((int)(rnd((float)num)),num);
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
258
259            pos = mod((int)(rnd((float)num)),num);
260            while(theta[pos] != 0.0){
261                pos = (int)mod(++pos, num);
262            }
263            theta[pos] = t + it*d_t;
264        }
265    }
266
267    //orxout() << "SpawnChildren(): Phi: "; printArrayString(phi);
268    //orxout() << "SpawnChildren(): Theta: "; printArrayString(theta);
269    //orxout() << "SpawnChildren(): Passed angle stuff. " << endl;
270
271    // Triangular, discrete probability "density" with max at the average value massRem/num. 50% chance to be below that.
272    if(massRem>0){
273        int c = (int)massRem;
274        std::vector<float> probDensity(c);
275
276        int a = (int)roundf(massRem/num);
277        int b = c-a;
278       
279        int z = 0;
280        float dProbA = 1.0f/(a*a + 3.0f*a + 2.0f); // one 'probability unit' for discrete ramp function. Gauss stuff.
281        for(z = 0; z<a; ++z){probDensity[z] = (z+1)*dProbA; } // rising part
282
283        float dProbB = 1.0f/(b*b +3.0f*b + 2.0f);
284        for(z = 0; z<b; ++z){probDensity[c-1-z] = (z+1)*dProbB;} // falling part
285   
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;
293
294        // Distributing the mass to individual asteroids
295        int result; 
296        float rVal; // between 0 and 1
297        float probSum; // summing up until rval is reached.
298        for(int trav = 0; trav<num; ++trav){
299            result = 0;
300            rVal = rnd(); 
301            probSum = probDensity[0]; 
302
303            while(rVal>probSum && result<massRem){// Not yet found && there-s smth left to distribute (Incrementing inside!)
304                if(result<(massRem-2)){probSum = probSum + probDensity[result+1];} // avoid logical/acess error
305                ++result;
306            }
307
308            masses[trav] = 1.0f + result; // Fragments have mass of at least one.
309            massRem = massRem-result;
310
311        }
312    }else{
313        for(int schnaegg = 0; schnaegg<num; ++schnaegg){masses[schnaegg] = 1;}
314    }
315
316    // orxout() << "SpawnChildren(): Masses: "; printArrayString(masses);
317    // orxout() << "SpawnChildren(): Passed mass stuff. " << endl;
318
319    // Creating the 'chlidren':
320    for(int fisch = 0; fisch<num; ++fisch){
321
322        Vector3 pos = Vector3::ZERO; // Position offset
323        if(num > 1){// not required if there-s just one child
324            float r = masses[fisch]/rScaling;
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
326        }
327       
328        AsteroidMinable* child = new AsteroidMinable(this->getContext());
329        child->setSize(masses[fisch]);
330        child->setPosition(this->getPosition() + pos);
331        child->setVelocity(this->getVelocity());
332        child->setDropStuff(this->dropStuff);
333    }
334    // orxout() << "Leaving spawnChildren() method. " << endl;
335}
336
337// @brief overloading that to prevent asteroids from taking damage from each other (domino effect etc. )
338    void AsteroidMinable::hit(Pawn* originator, const Vector3& force, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){
339
340        // orxout() << "AsteroidMining::Hit(Variante 1) Dings aufgerufen. " << endl;
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
352// @brief overloading that to prevent asteroids from taking damage from each other (domino effect etc. )
353    void AsteroidMinable::hit(Pawn* originator, btManifoldPoint& contactpoint, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){
354
355        //orxout() << "AsteroidMining::Hit(Variante 2) Dings aufgerufen. " << endl;
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    }
367}
Note: See TracBrowser for help on using the repository browser.