Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: critique thread for my tetris clone (beginner, code included)  (Read 2523 times)

0 Members and 1 Guest are viewing this topic.

klefmung

  • Newbie
  • *
  • Posts: 12
    • View Profile
critique thread for my tetris clone (beginner, code included)
« on: January 20, 2018, 10:42:52 pm »
I already did this for my snake project, and received some great feedback to improve my habits, which is my primary goal right now. I've only been coding for a few months, and would like to begin making code I can show to other people and not be ashamed of myself. I guess that starts with asking people about my code, and the snake code is the only code anyone's ever seen from me. Let me know what I can do better! Screen shot attached.

Also, it's worth noting that I did my best to follow the tetris guideline

Exe with required files:
https://drive.google.com/open?id=1JP2AAomcjRNFxqLgJorH-V0_k5Xp1SsM

Source code on github:
https://github.com/letsdothis64/Tetris

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re: critique thread for my tetris clone (beginner, code included)
« Reply #1 on: January 20, 2018, 11:52:05 pm »
Great job! That's a pretty neat code for a beginner. And congrats on finishing it. :)

I recommend you to read this book, if you haven't already: https://www.packtpub.com/game-development/sfml-game-development
I think it will greatly improve your style and teach you a lot of really awesome patterns.

For now, I want to point out these things:
1) Make smaller functions. Right a lot of your game loop is in one big main function. You can separate it into three parts, at least: handleInput, update, render. I recommend you to make a "Game" class, which might make it easier to do. You can store a window, clock, pieces, etc. there

2) Give better names to some commonly used things. For example, you now have piece[0], piece[1], piece[2] everywhere. Why not do something like this? :)
auto& controlledPiece = piece[0];

3) Use enum classes instead of plain enums. Read about "enum class" to know why

4) Try to return references in your getters instead of returning by value. For example:

sf::RectangleShape Block::getRect()
{
    return rect;
}

would better be:

const sf::RectangleShape& Block::getRect() const
{
    return rect;
}

5) You don't have to call member functions with "this" pointer inside the class members. E.g.

void Block::blockRotate(sf::Vector2i piecePos)
{
    ...
    this->setLocalPos(newPos, piecePos);
}

is the same as this:

void Block::blockRotate(sf::Vector2i piecePos)
{
    ...
    setLocalPos(newPos, piecePos);
}

6) This might be a bit overkill for such a small project. But try to use less magic numbers. Define constants like border sizes, speed, colors, etc. in separate header or some txt/JSON file. This will make your code more readable, as the reader won't have to guess what one or another number means.

7) You can put more const everywhere, it'll make your code safer. Try to think about const-correctness all the time. Does the function change the argument? Make it const if not. Does the member function modify any data members? If not, make it const as well. You get the idea. :)

8 ) Use for loops instead of while loops, as they're more readable.

int loopvar=0;
while(loopvar<relativePos.size())
{
    ...
    loopvar++;
}

should really be

for (int i = 0; i < relativePos.size(); ++i)
{
    ...
}

And I want to show how I would change one small loop to show some ideas:

Before:
int loopvar=0;
while(loopvar<relativePos.size())
{
    rects.emplace_back();
    rects[loopvar].setSize(sf::Vector2f(40, 40));
    rects[loopvar].setFillColor(color);
    rects[loopvar].setOutlineThickness(-5);
    rects[loopvar].setOutlineColor(sf::Color(77, 77, 77, 255));
    rects[loopvar].setPosition(relativePos[loopvar]+bgRect.getPosition());
    loopvar++;
}

After:
Rect rect;
rect.setSize(sf::Vector2f(40, 40));
rect.setFillColor(color);
rect.setOutlineThicnkness(-5);
rect.setOutlineColor(sf::Color(77, 77, 77, 255)); // won't change for each rect in the loop

const auto& bgRectPos = bgRect.getPosition();

for (const auto& pos : relativePos)
{
    rect.setPosition(pos + bgRectPos); // only this changes
    rects.push_back(rect); // and here we copy our rect
}

That's it for now. Please, don't let the critique discourage you in any way. You're doing well, but can be doing even better, keep going! :)
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

klefmung

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: critique thread for my tetris clone (beginner, code included)
« Reply #2 on: January 21, 2018, 02:00:03 am »
Thanks for the feedback! I'm combing through my code and making changes for posterity now to practice those habits.

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re: critique thread for my tetris clone (beginner, code included)
« Reply #3 on: January 21, 2018, 09:22:31 am »
Okay! You can PM me after the changes if you want to get more feedback later. :)
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: critique thread for my tetris clone (beginner, code included)
« Reply #4 on: January 23, 2018, 09:40:06 am »
You could use hpp for the headers. It's a nitpick but I prefer it that way (and SFML does it to have C and C++ versions of itself) so each of the 4 combinations of {source, header} x {C, cpp} has its own extension and there is 0 overlap or ambiguity (and I also like to use C libraries myself, so it helps, although even C++ programmers who dislike using C directly seem to often call their headers hpp).

Your RNG is a bit strange - the function names aren't the best (like getRandom could just be randomInt, no need for that get there IMO and putting type into function name is nice if you later add randomFloat, randomUnsigned, etc. to avoid overloading shenanigans, randomSeries could be named shuffleVector or something more telling). You also include chrono in the header even though you only use it in the source.

I'll try to take a better look at all the code later.
Back to C++ gamedev with SFML in May 2023

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: critique thread for my tetris clone (beginner, code included)
« Reply #5 on: January 23, 2018, 02:10:12 pm »
Here it is (don't get discouraged, I'm only listing negative stuff, none of the positives like you using const a lot properly, etc.):

In general:
everything includes SFML/Graphics.hpp instead of what it just needs
taking const params for small/basic types
returning and using const references for small/basic types
not using class member initializers
magic constants in places
(nitpick/arguable/personal) some style stuff with spaces around operators, private vars naming, functions naming, ordering of private functions, 1 line ifs
often using lots of ifs that are exclusive so a switch would do instead

Field.h - could use a vector and indices instead of nesting vectors
main.cpp - main is over 100 lines and lots of nesting and thus hard to follow, should be in a class probably, no code in the if !font.load body, ifs instead of switches with events and keys, you could randomize shapes differently (like put them all into a vector and shuffle that instead of relying on their values, have a helper function to return a vector of all shapes and shuffle that, something like that)
Piece.cpp - for pieces could use even a static table (pretty formated) instead of all this setting by hand in each, could use rotationState = (rotationState + 1) % 4 instead of an if since thats the intent (incremeanting but modulo 4)
PieceBox.cpp - loopvar is weird name, it's usually called i, also in one function its unused (only assigned to, never read or used)
pieceRotate.h - too much includes
RNG.h - including chrono needlessly, function names are a bit meh in general
rotate.h - its an empty file and never included (?)
Shapes.h - that enum name is a bit weird, it coudl be 'shape', just like sf::Style is that, not sf::Styles,
TextBox.h - could use =default for constructor and make string const reference and font const too
Back to C++ gamedev with SFML in May 2023