C++ Classes and Arrays

Started by
10 comments, last by Dragonsoulj 14 years, 1 month ago
*I'm trying to find a way to do this without vectors. A bit of a learning thing.* I have this class:
class Piece
{
private:
  Block *tetromino;
  int rotation;
  Shape shape;
public:
  Piece(Shape shape);
  void translate();
  void rotate();
  bool collides();
};

and this one:
class Block
{
private:
  static sf::Image *image;
  sf::Sprite sprite;
  int x, y;
  Shape shape;

public:
  Block(Shape shape);
  void setPosition(int xCoord, int yCoord);
  void setSprite();
  friend class Piece;
};

For the Piece class, I want to allocate 4 blocks (I mean my block class) of a desired shape:
tetromino = new Block(shapeName)[4];

But you cannot do this. Is there a way to specify a constructor to use and use it? Or would I have to make the tetromino a double pointer and declare each individually?
Advertisement
Not directly. Clicky.
Heh, I guess I am left with either the vector or double pointer option. Well, thanks for that.
Now this one has me stumped.
Quote:piece.cpp: In function `void initializeShape()':
piece.cpp:20: error: `tetromino' was not declared in this scope

Is what my compiler tells me.

class Piece{private:  std::vector<Block> tetromino;  int rotation;  Shape shape;public:  Piece(Shape shape);  void translate();  void rotate();  bool collides();};

Is my header file and
Piece::Piece(Shape shape){  tetromino.push_back(Block(shape));  tetromino.push_back(Block(shape));  tetromino.push_back(Block(shape));  tetromino.push_back(Block(shape));  rotation = 0;  shape = shape;}void initializeShape(){  tetromino[0].setPosition(5, 19);  tetromino[1].setPosition(4, 19);  tetromino[2].setPosition(4, 18);  tetromino[3].setPosition(5, 18);}void Piece::translate(){}void Piece::rotate(){}bool Piece::collides(){}

is my definition file.
Quote:Is there a way to specify a constructor to use and use it?


No, but you can define and use the default constructor, and then assign over those values.

Quote:Or would I have to make the tetromino a double pointer and declare each individually?


Please wipe this idea from your head. You should never explicitly make your data structure more complicated, and manage that complexity yourself, just to satisfy the compiler. It's bad enough that you have to be so explicit about your data structure in C++.

If you really want to do "a bit of a learning thing", research how std::vector does its magic. There are a fair few subtle things in there.

Quote:piece.cpp: In function `void initializeShape()':
piece.cpp:20: error: `tetromino' was not declared in this scope


'initializeShape()' is a free function, not a member function. Therefore, there is no implicit Piece whose .tetromino to work with.

But you're going about this part all wrong, anyway. Set up that data by passing those parameters to the Block constructor, not by calling setPosition. You don't need a setPosition, anyway, if you give the Piece its own position and update that (and take the Block's position as being relative to its containing Piece).

That said, encapsulating individual Blocks is probably overkill for Tetris, and most implementations I've seen (and all the ones I've written) represent a piece with a 4x4 grid of "is there a block at this location relative to the piece location?" instead of a set of 4 "here is the relative location of a block in the piece" values. It makes the rest of the algorithmic work simpler overall. Trust me. ;)
Scratch that. I found it.
Quote:Original post by Dragonsoulj
tetromino = new Block(shapeName)[4];

tetromino = operator new(4 * sizeof Block);new(tetromino+0) Block(shapeName);new(tetromino+1) Block(shapeName);new(tetromino+2) Block(shapeName);new(tetromino+3) Block(shapeName);

Don't forget to delete[] tetromino; in the destructor. Once you figured out how this works and understand the exception-related issues, remove this ugly low-level code and just use std::vector.
If you want to do it that way. I know some about vectors:
  tetromino.push_back(Block(shape));  tetromino.push_back(Block(shape));  tetromino.push_back(Block(shape));  tetromino.push_back(Block(shape));

Is what I did.

My problem now is why when I try to delete a piece, I get an error. Is this correct (abbreviated code)?
Board Header:
private:  Piece *currentPiece;  Piece *nextPiece;

Board Declaration:
Board::Board(){  currentPiece = new Piece(O,filledSquares);  nextPiece = new Piece(O,filledSquares);}

And the deletion:
void Board::getNextPiece(){  delete currentPiece;  currentPiece = nextPiece;  delete nextPiece;  nextPiece = new Piece(O,filledSquares);}


EDIT: O is a defined shape enum and filledSquares is a boolean pointer, both of which work fine. The code I have works without the delete statements, which it should, just deleting them should work as well (memory leaks otherwise).
Quote:Original post by Dragonsoulj
void Board::getNextPiece()
{
delete currentPiece;
currentPiece = nextPiece;
delete nextPiece;
nextPiece = new Piece(O,filledSquares);
}

You are deleting two pieces but only create one new piece. That cannot be correct. Why are you handling pieces indirectly to begin with? Why can't you store the pieces by value, without pointers?
*Just a note: I'm not completely retarded. I've just been up a long time sorting out some issues in this and then caught some new ones that I just couldn't figure out.*

Missed that. 1 delete needed. I'm just generating a piece, letting the game loop through, and when the piece hits the bottom, storing it in a map and getting a new one.

I have this loop, and I wasn't sure of another way to keep a piece alive long enough for me to get use I need, then make a new one with the same name. And I probably could just make the clock and board in this loop variables. I didn't know if I was going to use them elsewhere or not.
void Interface::loop(){  float TimeElapsed = 0;  clock->Reset();  board->drawBoard(windowApp);  while(windowApp->IsOpened())  {    sf::Event Event;    while(windowApp->GetEvent(Event))    {      if((Event.Type == sf::Event::Closed) || ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape)))      {        windowApp->Close();      }      if((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Left))      {        board->currentPiece->translate(left);      }      if((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Right))      {        board->currentPiece->translate(right);      }    }    TimeElapsed = clock->GetElapsedTime();    if(0.5 <= TimeElapsed)    {      if(board->currentPiece->translate(down))      {        for(int i = 0; i < 4; i++)        {          int x = board->currentPiece->tetromino.at(i).getX();          int y = board->currentPiece->tetromino.at(i).getY();          board->filledSquares[x*20 + y] = true;          board->blocks.erase(board->blocks.begin() + x*20 + y);          board->blocks.insert(board->blocks.begin() + x*20 + y, Block(board->currentPiece->shape));          board->blocks.at(x*20 + y).setPosition(x,y);        }        board->clearLine();        board->getNextPiece();      }      clock->Reset();    }    board->drawBoard(windowApp);  }}


*EDIT*
Quote:Original post by Zahlman
That said, encapsulating individual Blocks is probably overkill for Tetris, and most implementations I've seen (and all the ones I've written) represent a piece with a 4x4 grid of "is there a block at this location relative to the piece location?" instead of a set of 4 "here is the relative location of a block in the piece" values. It makes the rest of the algorithmic work simpler overall. Trust me. ;)

I was mainly going about this because the sprite images I was loading were only filling certain squares and I was using the same image. I probably could put the piece and block classes together and attempt a 4x4 grid. Maybe doing what I did for the board, taking one array that says whether a space was filled or not and another that held the image. That was another issue. I had a space for a block in my board class, in case part of the shape was destroyed.

[Edited by - Dragonsoulj on February 20, 2010 6:24:55 AM]

This topic is closed to new replies.

Advertisement