Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pCuts/src/modules/tetris/Tetris.cc @ 9087

Last change on this file since 9087 was 9087, checked in by jo, 13 years ago

Still a long way to go. A short todo list can be found at the beginning of Tetric.cc. A first, buggy clear-row function has been implemented.

  • Property svn:eol-style set to native
File size: 13.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 *      ...
24 *   Co-authors:
25 *      Johannes Ritz
26 *
27 *BUG a) double stone model (@ brick's location the stone's model is duplicated. Why does the brick have a model attached to it.)
28 *BUG b) the brick is set the wrong way after a (brick-brick) collision, if the brick was turned
29 *BUG c) destroying the old stones causes segfault -> WeakPointer as solution ?
30 *BUG
31 *
32 *TASK a) give points for winning
33 *TASK b) write a hud (show points gained; new brick)
34 *TASK c) end the game in a nicer way
35 *TASK d) save the highscore
36 *TASK e) eye candy
37 */
38
39/**
40    @file Tetris.cc
41    @brief Implementation of the Tetris class.
42*/
43
44#include "Tetris.h"
45
46#include "core/CoreIncludes.h"
47#include "core/EventIncludes.h"
48#include "core/command/Executor.h"
49
50#include "gamestates/GSLevel.h"
51
52#include "TetrisCenterpoint.h"
53#include "TetrisStone.h"
54#include "TetrisBrick.h"
55#include "infos/PlayerInfo.h"
56
57namespace orxonox
58{
59
60    CreateUnloadableFactory(Tetris);
61
62    /**
63    @brief
64        Constructor. Registers and initializes the object.
65    */
66    Tetris::Tetris(BaseObject* creator) : Deathmatch(creator)
67    {
68        RegisterObject(Tetris);
69
70        this->activeBrick_ = NULL;
71
72        // Pre-set the timer, but don't start it yet.
73        this->starttimer_.setTimer(1.0, false, createExecutor(createFunctor(&Tetris::startBrick, this)));
74        this->starttimer_.stopTimer();
75
76        this->player_ = NULL;
77        this->endGameCriteria_ = 0.0f;
78    }
79
80    /**
81    @brief
82        Destructor. Cleans up, if initialized.
83    */
84    Tetris::~Tetris()
85    {
86        if (this->isInitialized())
87            this->cleanup();
88    }
89
90    /**
91    @brief
92        Cleans up the Gametype.
93    */
94    void Tetris::cleanup()
95    {
96        /*for(int i = 0;i < this->stones_.size(); i++) //TODO: Why isn't there any code like this
97        {                                              // compensating the 'new' statement?
98            delete this->stones_[i];
99        }//*/
100
101    }
102
103    void Tetris::tick(float dt)
104    {
105        SUPER(Tetris, tick, dt);
106
107        if((this->activeBrick_ != NULL)&&(!this->hasEnded()))
108        {
109                this->endGameCriteria_ += dt;
110            if(!this->isValidBrickPosition(this->activeBrick_, this->activeBrick_->getPosition()))
111            {
112                this->activeBrick_->setVelocity(Vector3::ZERO);
113                this->activeBrick_->releaseStones(this->center_);
114                //delete this->activeBrick_; //releasing the memory
115                this->findFullRows();
116                if(this->endGameCriteria_ < 0.1f) //end game if two bricks are created within a 0.1s interval.
117                    this->end();
118                this->createBrick();
119                this->startBrick();
120                this->endGameCriteria_ = 0.0f;
121            }
122        }
123    }
124
125    bool Tetris::isValidMove(TetrisStone* stone, const Vector3& position)
126    {
127        assert(stone);
128
129        if(position.x < this->center_->getStoneSize()/2.0)  //!< If the stone touches the left edge of the level
130            return false;
131        else if(position.x > (this->center_->getWidth()-0.5)*this->center_->getStoneSize()) //!< If the stone touches the right edge of the level
132            return false;
133
134        for(std::vector<TetrisStone*>::const_iterator it = this->stones_.begin(); it != this->stones_.end(); ++it)
135        {
136            if(stone == *it)
137                continue;
138
139            const Vector3& currentStonePosition = (*it)->getPosition(); //!< Saves the position of the currentStone
140
141            if((position.x == currentStonePosition.x) && abs(position.y-currentStonePosition.y) < this->center_->getStoneSize())
142                return false;
143        }
144
145        return true;
146    }
147
148    /**
149    @brief
150        Check for each stone in a brick if it is moved the right way.
151    */
152    bool Tetris::isValidMove(TetrisBrick* brick, const Vector3& position, bool isRotation = false)
153    {
154        assert(brick);
155
156        for (unsigned int i = 0; i < brick->getNumberOfStones(); i++ )
157        {
158            TetrisStone* stone = brick->getStone(i);
159            Vector3 stonePosition;
160            if(isRotation)
161                stonePosition = rotateVector(stone->getPosition(), brick->getRotationCount()+1);
162            else
163                stonePosition = rotateVector(stone->getPosition(), brick->getRotationCount());
164
165            if(! this->isValidMove(stone, position + stonePosition )) // wrong position??
166            {
167                return false;
168            }
169        }
170        return true;
171
172    }
173
174
175
176    bool Tetris::isValidStonePosition(TetrisStone* stone, const Vector3& position)
177    {
178        assert(stone);
179
180        // we use a reverse iterator because we have to check for collisions with the topmost stones first
181        for(std::vector<TetrisStone*>::const_reverse_iterator it = this->stones_.rbegin(); it != this->stones_.rend(); ++it)
182        {
183            if(this->activeBrick_->contains(*it))
184                continue;
185            //Vector3 currentStonePosition = rotateVector((*it)->getPosition(), this->activeBrick_->getRotationCount());
186            const Vector3& currentStonePosition = (*it)->getPosition(); //!< Saves the position of the currentStone
187            //!< Saves the position of the currentStone
188
189            if((position.x == currentStonePosition.x) && (position.y < currentStonePosition.y + this->center_->getStoneSize()))
190            {
191                this->activeBrick_->setPosition(Vector3(this->activeBrick_->getPosition().x, currentStonePosition.y+this->center_->getStoneSize(), this->activeBrick_->getPosition().z));
192                return false;
193            }// This case applies if the stones overlap partially vertically
194        }
195
196        // after we checked for collision with all stones, we also check for collision with the bottom
197        if(position.y < this->center_->getStoneSize()/2.0f) //!< If the stone has reached the bottom of the level
198        {
199                int yOffset = stone->getPosition().y;//calculate offset
200                this->activeBrick_->setPosition(Vector3(this->activeBrick_->getPosition().x, this->center_->getStoneSize()/2.0f+yOffset, this->activeBrick_->getPosition().z));
201            return false;
202        }
203
204        return true;
205    }
206
207    bool Tetris::isValidBrickPosition(TetrisBrick* brick, const Vector3& position)
208    {
209        assert(brick);
210
211        for (unsigned int i = 0; i < brick->getNumberOfStones(); i++ )
212        {
213            TetrisStone* stone = brick->getStone(i);
214            Vector3 stonePosition = rotateVector(stone->getPosition(), brick->getRotationCount());
215            if(! this->isValidStonePosition(stone, position + stonePosition) )
216                return false;
217        }
218        return true;
219    }
220
221    /**
222    @brief
223        A Vector3 is rolled 90 * degrees * amount (anticlockwise rotation)
224    */
225    Vector3 Tetris::rotateVector(Vector3 position, unsigned int amount)
226    {
227        int temp = 0;
228        for(unsigned int i = 0; i < amount; i++)
229        {
230            temp = position.x;
231            position.x = -position.y;
232            position.y = temp;
233        }
234        return position;
235    }
236
237    /**
238    @brief
239        Starts the Tetris minigame.
240    */
241    void Tetris::start()
242    {
243        if (this->center_ != NULL) // There needs to be a TetrisCenterpoint, i.e. the area the game takes place.
244        {
245            // Create the first brick.
246            this->createBrick();
247        }
248        else // If no centerpoint was specified, an error is thrown and the level is exited.
249        {
250            orxout(internal_error) << "Tetris: No Centerpoint specified." << endl;
251            GSLevel::startMainMenu();
252            return;
253        }
254
255        // Start the timer. After it has expired the stone is started.
256        this->starttimer_.startTimer();
257
258        // Set variable to temporarily force the player to spawn.
259        bool temp = this->bForceSpawn_;
260        this->bForceSpawn_ = true;
261
262        // Call start for the parent class.
263        Deathmatch::start();
264
265        // Reset the variable.
266        this->bForceSpawn_ = temp;
267    }
268
269    /**
270    @brief
271        Ends the Tetris minigame.
272    */
273    void Tetris::end()
274    {
275        this->activeBrick_->setVelocity(Vector3::ZERO);
276        this->cleanup();
277
278        // Call end for the parent class.
279        Deathmatch::end();
280    }
281
282    /**
283    @brief
284        Spawns player.
285    */
286    void Tetris::spawnPlayersIfRequested()
287    {
288        // Spawn a human player.
289        for (std::map<PlayerInfo*, Player>::iterator it = this->players_.begin(); it != this->players_.end(); ++it)
290            if (it->first->isHumanPlayer() && (it->first->isReadyToSpawn() || this->bForceSpawn_))
291                this->spawnPlayer(it->first);
292    }
293
294    /**
295    @brief
296        Spawns the input player.
297    @param player
298        The player to be spawned.
299    */
300    void Tetris::spawnPlayer(PlayerInfo* player)
301    {
302        assert(player);
303
304        if(this->player_ == NULL)
305        {
306            this->player_ = player;
307            this->players_[player].state_ = PlayerState::Alive;
308        }
309    }
310
311
312
313    void Tetris::startBrick(void)
314    {
315        if(this->player_ == NULL)
316            return;
317
318        unsigned int cameraIndex = 0;
319        if(this->activeBrick_ != NULL)
320        {
321            // Get camera settings
322            cameraIndex = this->activeBrick_->getCurrentCameraIndex();
323            this->player_->stopControl();
324        }
325
326        // Make the last brick to be created the active brick.
327        this->activeBrick_ = this->bricks_.back();
328
329        this->player_->startControl(this->activeBrick_);
330        this->activeBrick_->setVelocity(0.0f, -this->center_->getStoneSpeed(), 0.0f);
331        this->activeBrick_->setCameraPosition(cameraIndex);
332    }
333
334    void Tetris::createBrick(void)             //TODO: random rotation offset between 0 and 3 (times 90°)
335    {
336        // Create a new brick and add it to the list of bricks && to the list of stones.
337        TetrisBrick* brick = new TetrisBrick(this->center_);
338        this->bricks_.push_back(brick);
339        for (unsigned int i = 0; i < brick->getNumberOfStones(); i++)
340        {
341            this->stones_.push_back(brick->getStone(i));
342        }
343
344        // Apply the stone template to the stone.
345        brick->addTemplate(this->center_->getStoneTemplate()); // TODO: find error concerning the cameras
346
347        // Attach the brick to the Centerpoint and set the position of the brick to be at the top middle.
348        this->center_->attach(brick);
349        float xPos = (this->center_->getWidth()/2 + ((this->center_->getWidth() % 2)*2-1)/2.0f)*this->center_->getStoneSize();
350        float yPos = (this->center_->getHeight()-0.5f)*this->center_->getStoneSize();
351        brick->setPosition(xPos, yPos, 0.0f);
352        brick->setGame(this);
353    }
354
355
356    /**
357    @brief
358        Get the player.
359    @return
360        Returns a pointer to the player. If there is no player, NULL is returned.
361    */
362    PlayerInfo* Tetris::getPlayer(void) const
363    {
364        return this->player_;
365    }
366
367    /*TetrisCenterpoint* Tetris::getCenterpoint(void) const
368    {
369        return this->center_;
370    }*/
371
372    /**
373    @brief Set the TetrisCenterpoint (the playing field).
374    @param center A pointer to the TetrisCenterpoint to be set.
375    */
376    void Tetris::setCenterpoint(TetrisCenterpoint* center)
377    {
378        this->center_ = center;
379    }
380
381    /**
382    @brief Check each row if it is full. Remove all full rows. Let all stones above the deleted row sink down.
383    @brief Manage score.
384    */
385    void Tetris::findFullRows()
386    {
387        unsigned int correctPosition = 0;
388                orxout()<< "clear full rows ************ " <<endl;
389        unsigned int stonesPerRow = 0;
390        for (unsigned int row = 0; row < this->center_->getHeight(); row++)
391        {
392            stonesPerRow = 0;
393            for(std::vector<TetrisStone*>::const_reverse_iterator it = this->stones_.rbegin(); it != this->stones_.rend(); ++it)
394            {
395                correctPosition = static_cast<unsigned int>(((*it)->getPosition().y - 5)/this->center_->getStoneSize());
396                if(correctPosition == row)
397                        stonesPerRow++;
398                if(stonesPerRow == this->center_->getWidth())
399                    {orxout()<< "CANDIDATE FOUND in row " << row <<endl; clearRow(row);}
400            }
401
402        }
403    }
404
405    void Tetris::clearRow(unsigned int row)
406    {//std::vector<int>::iterator it = v.begin()
407        for(std::vector<TetrisStone*>::iterator it = this->stones_.begin(); it != this->stones_.end(); ++it)
408        {
409            if(static_cast<unsigned int>(((*it)->getPosition().y - 5)/this->center_->getStoneSize()) == row)
410                (*it)->setPosition(Vector3(-10,-10,0));
411                //{(*it)->destroy(); this->stones_.erase(it); orxout()<< "destroy row "<<endl;}//experimental
412        }
413        for(std::vector<TetrisStone*>::const_reverse_iterator it2 = this->stones_.rbegin(); it2 != this->stones_.rend(); ++it2)
414        {
415            /*if(static_cast<unsigned int>(((*it2)->getPosition().y - 5)/this->center_->getStoneSize()) > row)
416                (*it2)->setPosition((*it2)->getPosition()-Vector3(0,1,0));//*/
417        }
418
419    }
420
421
422}
Note: See TracBrowser for help on using the repository browser.