Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Tetris contais almost the same features as before introducing bricks. Two bugs are still left. And the clear row feature has to be implemented.

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