So, I'm developing simple snakegame in SFML, and I've just wanted to ask you if there is way to automate creating bodyparts and drawing them. Curently I have code that looks like this:
// defining bodyparts
sf::RectangleShape square (sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart1(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart2(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart3(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart4(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart5(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart6(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart7(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart8(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart9(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart10(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart11(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart12(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart13(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart14(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart15(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart16(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart17(sf::Vector2f(res.x/grid, res.x/grid));
sf::RectangleShape bodyPart18(sf::Vector2f(res.x/grid, res.x/grid));
//etc
//pos of bodyyparts
sf::Vector2i part1Pos(snakePos.x + grid, snakePos.y);
sf::Vector2i part2Pos(part1Pos.x + grid, part1Pos.y);
sf::Vector2i part3Pos(part2Pos.x + grid, part2Pos.y);
sf::Vector2i part4Pos(part3Pos.x + grid, part3Pos.y);
sf::Vector2i part5Pos(part4Pos.x + grid, part4Pos.y);
sf::Vector2i part6Pos(part5Pos.x + grid, part5Pos.y);
//etc
//set position of body
square.setPosition(snakePos.x, snakePos.y);
bodyPart1.setPosition(part1Pos.x, part1Pos.y);
bodyPart2.setPosition(part2Pos.x, part2Pos.y);
bodyPart3.setPosition(part3Pos.x, part3Pos.y);
bodyPart4.setPosition(part4Pos.x, part4Pos.y);
bodyPart5.setPosition(part5Pos.x, part5Pos.y);
bodyPart6.setPosition(part6Pos.x, part6Pos.y);
bodyPart7.setPosition(part1Pos.x, part1Pos.y);
bodyPart8.setPosition(part2Pos.x, part2Pos.y);
bodyPart9.setPosition(part3Pos.x, part3Pos.y);
bodyPart10.setPosition(part4Pos.x, part4Pos.y);
bodyPart11.setPosition(part5Pos.x, part5Pos.y);
bodyPart12.setPosition(part6Pos.x, part6Pos.y);
//etc
And then to draw it:
if(snakeSize >= 1)
window.draw(bodyPart1);
if(snakeSize >= 2)
window.draw(bodyPart2);
if(snakeSize >= 3)
window.draw(bodyPart3);
if(snakeSize >= 4)
window.draw(bodyPart4);
if(snakeSize >= 5)
window.draw(bodyPart5);
if(snakeSize >= 6)
window.draw(bodyPart6);
//etc
It basically works, but it doesn't look nice.
(http://s27.postimg.org/axuewb2dd/snake_1.png)
(http://s27.postimg.org/ydcc1nm4h/snake_2.png)
The thing to remember about snakes is that only the head and tail actually move. All the body parts in between stay in position.
So, an easy way to implement a snake is to use a std::deque<sf::Vector2i> to store the positions (x, y) of the snakes body parts.
If you do that, then moving the snake is as simple as removing the old tail at the end and then adding a new head at the front - something like this:
...
std::deque<sf::Vector2i> segments;
...
void Snake::move()
{
// first remove old tail
segments.pop_back();
// figure out where new head needs to go ...
sf::vector2i new_head(x, y); // x, y being where ever you want the new head to be
// then add the new head
segments.emplace_front(new_head);
}
To grow the snake by one segment you can then simply skip removing the tail when you move it. So something like:
void Snake::move()
{
if (!growing) {
// remove old tail
segments.pop_back();
}
growing = false; // don't grow again next move (unless something sets growing again before next move)
// figure out where new head needs to go ...
sf::vector2i new_head(x, y); // x, y being where ever you want the new head to be
// then add the new head
segments.emplace_front(new_head);
}
and to draw it you can then simply do something like:
...
for (auto& segment : segments) {
sf::Sprite sprite(...);
sprite.setPosition(segment.x, segment.y);
draw(sprite);
}
...
I hope that makes sense :)
The thing to remember about snakes is that only the head and tail actually move. All the body parts in between stay in position.
So, an easy way to implement a snake is to use a std::deque<sf::Vector2i> to store the positions (x, y) of the snakes body parts.
If you do that, then moving the snake is as simple as removing the old tail at the end and then adding a new head at the front - something like this:
...
std::deque<sf::Vector2i> segments;
...
void Snake::move()
{
// first remove old tail
segments.pop_back();
// figure out where new head needs to go ...
sf::vector2i new_head(x, y); // x, y being where ever you want the new head to be
// then add the new head
segments.emplace_front(new_head);
}
To grow the snake by one segment you can then simply skip removing the tail when you move it. So something like:
void Snake::move()
{
if (!growing) {
// remove old tail
segments.pop_back();
}
growing = false; // don't grow again next move (unless something sets growing again before next move)
// figure out where new head needs to go ...
sf::vector2i new_head(x, y); // x, y being where ever you want the new head to be
// then add the new head
segments.emplace_front(new_head);
}
and to draw it you can then simply do something like:
...
for (auto& segment : segments) {
sf::Sprite sprite(...);
sprite.setPosition(segment.x, segment.y);
draw(sprite);
}
...
I hope that makes sense :)
I've mase it completely different. Basically snakes tail is mase of a squares (bodyParts) that move as head of the snake moves. When head moves bodyPart1 takes position of a snakes head, then bodyPart2 takes position of the bodyPart1 and so on.
I'm happy with my whole code except that part. Whole game scales as I change resolution.