Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9084 was 9084, checked in by jo, 12 years ago

Rotating bricks works. Next step: repairing the collision detection.

  • Property svn:eol-style set to native
File size: 11.3 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->createBrick();
102                this->startBrick();
103            }
104        }
105    }
106
107    bool Tetris::isValidMove(TetrisStone* stone, const Vector3& position)
108    {
109        assert(stone);
110
111        if(position.x < this->center_->getStoneSize()/2.0)  //!< If the stone touches the left edge of the level
112            return false;
113        else if(position.x > (this->center_->getWidth()-0.5)*this->center_->getStoneSize()) //!< If the stone touches the right edge of the level
114            return false;
115
116        for(std::vector<TetrisStone*>::const_iterator it = this->stones_.begin(); it != this->stones_.end(); ++it)
117        {
118            if(stone == *it)
119                continue;
120
121            const Vector3& currentStonePosition = (*it)->getPosition(); //!< Saves the position of the currentStone
122
123            if((position.x == currentStonePosition.x) && abs(position.y-currentStonePosition.y) < this->center_->getStoneSize())
124                return false;
125        }
126
127        return true;
128    }
129
130    /**
131    @brief
132        Check for each stone in a brick if it is moved the right way.
133    */
134    bool Tetris::isValidMove(TetrisBrick* brick, const Vector3& position, bool isRotation = false)
135    {
136        assert(brick);
137
138        for (unsigned int i = 0; i < brick->getNumberOfStones(); i++ )
139        {
140            TetrisStone* stone = brick->getStone(i);
141            Vector3 stonePosition;
142            if(isRotation)
143                stonePosition = rotateVector(stone->getPosition(), brick->getRotationCount()+1);
144            else
145                stonePosition = rotateVector(stone->getPosition(), brick->getRotationCount());
146
147            /*orxout()<< "stoneRelativePoistion: " << stonePosition << endl;
148            orxout()<< "stoneTotalPoistion   : " << position + stonePosition << endl;*/
149
150            if(! this->isValidMove(stone, position + stonePosition )) // wrong position??
151            {
152                return false;
153            }
154        }
155        return true;
156
157    }
158
159
160
161    bool Tetris::isValidStonePosition(TetrisStone* stone, const Vector3& position)
162    {
163        assert(stone);
164
165        // we use a reverse iterator because we have to check for collisions with the topmost stones first
166        for(std::vector<TetrisStone*>::const_reverse_iterator it = this->stones_.rbegin(); it != this->stones_.rend(); ++it)
167        {
168            if(this->activeBrick_->contains(*it))
169                continue;
170//TODO: is this rotation correct ??
171            Vector3 currentStonePosition = rotateVector((*it)->getPosition(), this->activeBrick_->getRotationCount());
172            //!< Saves the position of the currentStone
173
174            if((position.x == currentStonePosition.x) && (position.y < currentStonePosition.y + this->center_->getStoneSize()))
175            {//TODO: Why are such events not detected ??
176                orxout()<< "YEAY !!"<<endl;
177                this->activeBrick_->setPosition(Vector3(this->activeBrick_->getPosition().x, currentStonePosition.y+this->center_->getStoneSize(), this->activeBrick_->getPosition().z));
178                return false;
179            }// This case applies if the stones overlap partially vertically
180        }
181
182        // after we checked for collision with all stones, we also check for collision with the bottom
183        if(position.y < this->center_->getStoneSize()/2.0f) //!< If the stone has reached the bottom of the level
184        {
185                int yOffset = stone->getPosition().y;//calculate offset
186                this->activeBrick_->setPosition(Vector3(this->activeBrick_->getPosition().x, this->center_->getStoneSize()/2.0f+yOffset, this->activeBrick_->getPosition().z));
187            return false;
188        }
189
190        return true;
191    }
192
193    bool Tetris::isValidBrickPosition(TetrisBrick* brick, const Vector3& position)
194    {
195        assert(brick);
196
197        for (unsigned int i = 0; i < brick->getNumberOfStones(); i++ )
198        {
199            TetrisStone* stone = brick->getStone(i);
200            Vector3 stonePosition = rotateVector(stone->getPosition(), brick->getRotationCount());
201            if(! this->isValidStonePosition(stone, position + stonePosition) )
202                return false;
203        }
204        return true;
205    }
206
207    /**
208    @brief
209        Nasty function that allocates memory!! it rolls a vector 90° * amount
210    */
211    Vector3 Tetris::rotateVector(Vector3 position, unsigned int amount)
212    {
213
214        int temp = 0;
215        for(unsigned int i = 0; i < amount; i++)
216        {
217            temp = position.x;
218            position.x = -position.y;
219            position.y = temp;
220        }
221        return position;
222    }
223
224    /**
225    @brief
226        Starts the Tetris minigame.
227    */
228    void Tetris::start()
229    {
230        if (this->center_ != NULL) // There needs to be a TetrisCenterpoint, i.e. the area the game takes place.
231        {
232            // Create the first stone.
233            this->createBrick();
234        }
235        else // If no centerpoint was specified, an error is thrown and the level is exited.
236        {
237            orxout(internal_error) << "Tetris: No Centerpoint specified." << endl;
238            GSLevel::startMainMenu();
239            return;
240        }
241
242        // Start the timer. After it has expired the stone is started.
243        this->starttimer_.startTimer();
244
245        // Set variable to temporarily force the player to spawn.
246        bool temp = this->bForceSpawn_;
247        this->bForceSpawn_ = true;
248
249        // Call start for the parent class.
250        Deathmatch::start();
251
252        // Reset the variable.
253        this->bForceSpawn_ = temp;
254    }
255
256    /**
257    @brief
258        Ends the Tetris minigame.
259    */
260    void Tetris::end()
261    {
262        this->cleanup();
263
264        // Call end for the parent class.
265        Deathmatch::end();
266    }
267
268    /**
269    @brief
270        Spawns player.
271    */
272    void Tetris::spawnPlayersIfRequested()
273    {
274        // Spawn a human player.
275        for (std::map<PlayerInfo*, Player>::iterator it = this->players_.begin(); it != this->players_.end(); ++it)
276            if (it->first->isHumanPlayer() && (it->first->isReadyToSpawn() || this->bForceSpawn_))
277                this->spawnPlayer(it->first);
278    }
279
280    /**
281    @brief
282        Spawns the input player.
283    @param player
284        The player to be spawned.
285    */
286    void Tetris::spawnPlayer(PlayerInfo* player)
287    {
288        assert(player);
289
290        if(this->player_ == NULL)
291        {
292            this->player_ = player;
293            this->players_[player].state_ = PlayerState::Alive;
294        }
295    }
296
297
298
299    void Tetris::startBrick(void)
300    {
301        if(this->player_ == NULL)
302            return;
303
304        unsigned int cameraIndex = 0;
305        if(this->activeBrick_ != NULL)
306        {
307            // Get camera settings
308            cameraIndex = this->activeBrick_->getCurrentCameraIndex();
309            orxout() << "cameraIndex: " << this->activeBrick_->getCurrentCameraIndex() << endl;
310            this->player_->stopControl();
311        }
312
313        // Make the last brick to be created the active brick.
314        this->activeBrick_ = this->bricks_.back();
315
316        this->player_->startControl(this->activeBrick_);
317        this->activeBrick_->setVelocity(0.0f, -this->center_->getStoneSpeed(), 0.0f);
318        orxout() << "velocity: " << this->center_->getStoneSpeed() << endl;
319        this->activeBrick_->setCameraPosition(cameraIndex);
320    }
321
322    void Tetris::createBrick(void)             //TODO: random rotation offset between 0 and 3 (times 90°)
323    {
324        // Create a new brick and add it to the list of bricks && to the list of stones.
325        TetrisBrick* brick = new TetrisBrick(this->center_);
326        this->bricks_.push_back(brick);
327        for (unsigned int i = 0; i < brick->getNumberOfStones(); i++)
328        {
329            this->stones_.push_back(brick->getStone(i));
330        }
331
332        // Apply the stone template to the stone.
333        brick->addTemplate(this->center_->getStoneTemplate()); // TODO: find error concerning the cameras
334
335        // Attach the brick to the Centerpoint and set the position of the brick to be at the top middle.
336        this->center_->attach(brick);
337        float xPos = (this->center_->getWidth()/2 + ((this->center_->getWidth() % 2)*2-1)/2.0f)*this->center_->getStoneSize();
338        float yPos = (this->center_->getHeight()-0.5f)*this->center_->getStoneSize();
339        brick->setPosition(xPos, yPos, 0.0f);
340        brick->setGame(this);
341    }
342
343
344    /**
345    @brief
346        Get the player.
347    @return
348        Returns a pointer to the player. If there is no player, NULL is returned.
349    */
350    PlayerInfo* Tetris::getPlayer(void) const
351    {
352        return this->player_;
353    }
354
355    /*TetrisCenterpoint* Tetris::getCenterpoint(void) const
356    {
357        return this->center_;
358    }*/
359
360    /**
361    @brief Set the TetrisCenterpoint (the playing field).
362    @param center A pointer to the TetrisCenterpoint to be set.
363    */
364    void Tetris::setCenterpoint(TetrisCenterpoint* center)
365    {
366        this->center_ = center;
367    }
368
369}
Note: See TracBrowser for help on using the repository browser.