我正在尝试使用SFML在C ++中进行蛇形游戏。 这是我的代码如下。问题是我不知道怎么可能让蛇咬自己:每个蛇块占据最后一个蛇的位置,产生一条完美的直蛇。所以这更像是一个算法问题。 谢谢你的建议:) 顺便说一句没有把hashtages和<在include中因为编辑器将它们带走:/ BTW2:寻找类似的回答,但没有一个是我的方法或使用另一种语言。 你走了:
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Audio.hpp>
#include <deque>
void selfIncrement();
sf::Event event;
sf::Clock clockSnake;
sf::Time elapse;
enum Direction { Up, Down, Left, Right};
int dir = Up;
int n = 1;
class SnakeBlock
{
public:
SnakeBlock * next;
sf::Texture texture;
sf::Sprite snakeblock;
int lastX, lastY;
};
std::deque<SnakeBlock> Snake;
int main()
{
elapse = clockSnake.getElapsedTime();
sf::Music epicMusic;
epicMusic.openFromFile("epicmusic.wav");
epicMusic.play();
SnakeBlock snakeHead;
snakeHead.texture.loadFromFile("spritesheetsnake.png", sf::IntRect(0,0,20,22));
snakeHead.snakeblock.setTexture(snakeHead.texture);
SnakeBlock snakeBody1;
snakeBody1.snakeblock.setTexture(*(snakeHead.snakeblock.getTexture()));
SnakeBlock snakeBody2;
snakeBody2.snakeblock.setTexture(*(snakeHead.snakeblock.getTexture()));
Snake.push_front(snakeHead);
Snake.push_front(snakeBody1);
Snake.push_front(snakeBody2);
Snake[2].snakeblock.setPosition(500,350);
Snake[1].snakeblock.setPosition(475, 338);
Snake[0].snakeblock.setPosition(450, 316);
sf::RenderWindow window(sf::VideoMode(1028,768), "SFML Snake");
window.setFramerateLimit(60);
while(window.isOpen())
{
while(window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
epicMusic.stop();
window.close();
break;
default:
break;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
dir = Left;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
dir = Right;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
dir = Down;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
dir = Up;
}
if(dir == Up)
{
Snake[0].snakeblock.move(0,-2);
Snake[n].snakeblock.setPosition(Snake[n-1].snakeblock.getPosition().x, Snake[n-1].snakeblock.getPosition().y+20);
}
if(dir == Down)
{
Snake[0].snakeblock.move(0,2);
Snake[n].snakeblock.setPosition(Snake[n-1].snakeblock.getPosition().x, Snake[n-1].snakeblock.getPosition().y-20);
}
if(dir == Left)
{
Snake[0].snakeblock.move(-2,0);
Snake[n].snakeblock.setPosition(Snake[n-1].snakeblock.getPosition().x+20, Snake[n-1].snakeblock.getPosition().y);
}
if(dir == Right)
{
Snake[0].snakeblock.move(2,0);
Snake[n].snakeblock.setPosition(Snake[n-1].snakeblock.getPosition().x-20, Snake[n-1].snakeblock.getPosition().y);
}
window.clear(sf::Color::Red);
n++;
if( n > 2)
{
n = 1;
}
//selfIncrement();
for(unsigned int m = 0; m < Snake.size(); m++)
{
window.draw(Snake[m].snakeblock);
}
window.display();
}
return 0;
}
/*void selfIncrement()
{
elapse = clockSnake.getElapsedTime();
if(elapse.asSeconds() > 0.10)
{
n++;
clockSnake.restart();
}
if(n > Snake.size())
{
n = 1;
}
}
*/
新代码使用新原则::
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Audio.hpp>
#include <deque>
void advanceStep();
sf::Event event;
sf::Clock clockSnake;
sf::Time elapse;
enum Direction { Up, Down, Left, Right};
sf::Vector2i direction;
int dir = Up;
int n = 1;
class SnakeBlock
{
public:
sf::Texture texture;
sf::Sprite snakeblock;
int dir = 0;
int lastX, lastY;
};
SnakeBlock element;
std::deque<SnakeBlock> Snake;
int main()
{
elapse = clockSnake.getElapsedTime();
sf::Music epicMusic;
epicMusic.openFromFile("epicmusic.wav");
epicMusic.play();
SnakeBlock snakeHead;
snakeHead.texture.loadFromFile("spritesheetsnake.png", sf::IntRect(0,0,20,22));
snakeHead.snakeblock.setTexture(snakeHead.texture);
SnakeBlock snakeBody1;
snakeBody1.snakeblock.setTexture(*(snakeHead.snakeblock.getTexture()));
SnakeBlock snakeBody2;
snakeBody2.snakeblock.setTexture(*(snakeHead.snakeblock.getTexture()));
Snake.push_front(snakeHead);
Snake.push_front(snakeBody1);
Snake.push_front(snakeBody2);
Snake[2].snakeblock.setPosition(500,350);
Snake[1].snakeblock.setPosition(475, 338);
Snake[0].snakeblock.setPosition(450, 316);
sf::RenderWindow window(sf::VideoMode(1028,768), "SFML Snake");
window.setFramerateLimit(10);
while(window.isOpen())
{
while(window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
epicMusic.stop();
window.close();
break;
default:
break;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
dir = Left;
direction.x = -1;
direction.y = 0;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
dir = Right;
direction.x = 1;
direction.y = 0;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
dir = Down;
direction.x = 0;
direction.y = -1;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
dir = Up;
direction.x = 0;
direction.y = 1;
}
if(dir == Up)
{
Snake[0].snakeblock.move(0,-2);
Snake[1].snakeblock.setPosition(Snake[0].snakeblock.getPosition().x, Snake[0].snakeblock.getPosition().y+20);
Snake[2].snakeblock.setPosition(Snake[1].snakeblock.getPosition().x, Snake[1].snakeblock.getPosition().y+20);
}
if(dir == Down)
{
Snake[0].snakeblock.move(0,2);
Snake[1].snakeblock.setPosition(Snake[0].snakeblock.getPosition().x, Snake[0].snakeblock.getPosition().y-20);
Snake[2].snakeblock.setPosition(Snake[1].snakeblock.getPosition().x, Snake[1].snakeblock.getPosition().y-20);
}
if(dir == Left)
{
Snake[0].snakeblock.move(-2,0);
Snake[1].snakeblock.setPosition(Snake[0].snakeblock.getPosition().x+20, Snake[0].snakeblock.getPosition().y);
Snake[2].snakeblock.setPosition(Snake[1].snakeblock.getPosition().x+20, Snake[1].snakeblock.getPosition().y);
}
if(dir == Right)
{
Snake[0].snakeblock.move(2,0);
Snake[1].snakeblock.setPosition(Snake[0].snakeblock.getPosition().x-20, Snake[0].snakeblock.getPosition().y);
Snake[2].snakeblock.setPosition(Snake[1].snakeblock.getPosition().x-20, Snake[1].snakeblock.getPosition().y);
}
window.clear(sf::Color::Red);
advanceStep();
for(unsigned int m = 0; m < Snake.size(); m++)
{
window.draw(Snake[m].snakeblock);
}
window.display();
}
return 0;
}
void advanceStep()
{
sf::Vector2f headpos(Snake[0].snakeblock.getPosition());
headpos.x += 22 * direction.x;
headpos.y += 22 * direction.y;
Snake[0].snakeblock.setPosition(headpos);
Snake.pop_back();
Snake.push_front(Snake[0]);
}
新代码记录在你所有人都知道的帐户中,但现在蛇消失了,可能是因为pop_back ..
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Audio.hpp>
#include <deque>
void advanceStep();
sf::Event event;
sf::Clock clockSnake;
sf::Time elapse;
enum Direction { Up, Down, Left, Right};
sf::Vector2i direction(0, 0);
int dir = Up;
class SnakeBlock
{
public:
sf::Texture texture;
sf::Sprite snakeblock;
int dir;
};
std::deque<SnakeBlock> Snake;
int main()
{
elapse = clockSnake.getElapsedTime();
sf::Music epicMusic;
epicMusic.openFromFile("epicmusic.wav");
epicMusic.play();
SnakeBlock snakeHead;
snakeHead.texture.loadFromFile("spritesheetsnake.png", sf::IntRect(0,0,20,22));
snakeHead.snakeblock.setTexture(snakeHead.texture);
SnakeBlock snakeBody1;
snakeBody1.snakeblock.setTexture(*(snakeHead.snakeblock.getTexture()));
SnakeBlock snakeBody2;
snakeBody2.snakeblock.setTexture(*(snakeHead.snakeblock.getTexture()));
Snake.push_back(snakeHead);
Snake.push_back(snakeBody1);
Snake.push_back(snakeBody2);
Snake[2].snakeblock.setPosition(500,350);
Snake[1].snakeblock.setPosition(475, 338);
Snake[0].snakeblock.setPosition(450, 316);
sf::RenderWindow window(sf::VideoMode(1028,768), "SFML Snake");
window.setFramerateLimit(1);
while(window.isOpen())
{
while(window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
epicMusic.stop();
window.close();
break;
default:
break;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
direction.x = -1;
for(int i = 1; i < Snake.size(); i++)
{
Snake[i].snakeblock.setPosition(Snake[i+1].snakeblock.getPosition().x-20, Snake[i+1].snakeblock.getPosition().y);
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
direction.x = 1;
for(int j = 1; j < Snake.size(); j++)
{
Snake[j].snakeblock.setPosition(Snake[j+1].snakeblock.getPosition().x+20, Snake[j+1].snakeblock.getPosition().y);
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
direction.y = -1;
for(int l = 1; l < Snake.size(); l++)
{
Snake[l].snakeblock.setPosition(Snake[l+1].snakeblock.getPosition().x, Snake[l+1].snakeblock.getPosition().y-22);
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
direction.y = 1;
for(int o = 1; o < Snake.size(); o++)
{
Snake[o].snakeblock.setPosition(Snake[o+1].snakeblock.getPosition().x, Snake[o+1].snakeblock.getPosition().y+22);
}
}
window.clear(sf::Color::Red);
advanceStep();
for(unsigned int m = 1; m < Snake.size(); m++)
{
window.draw(Snake[m].snakeblock);
}
window.display();
}
return 0;
}
void advanceStep()
{
sf::Vector2f headpos;
headpos.x = Snake[0].snakeblock.getPosition().x;
headpos.y = Snake[0].snakeblock.getPosition().y;
headpos.x += 22 * direction.x;
headpos.y += 22 * direction.y;
SnakeBlock element;
element.snakeblock.setPosition(headpos);
Snake.pop_back();
Snake.push_front(element);
}
答案 0 :(得分:3)
您的实施存在很多问题。这是一个粗略的轮廓,而不是指出每个问题。假设你的蛇是一个段的列表,最大长度:
在语义上,碰撞是当蛇头进入其身体的任何其他部分时。
要检测冲突,请在每个更新步骤中执行此操作。检查头部与身体其他部分的距离。如果有交叉点,则发生碰撞。
顺便说一句,如果你想在最大蛇长度减小时获得更平滑的“收缩”效果,你可以例如每次更新最多删除两个段(队列长度&gt;最大长度和删除的段数&lt;缩减率)。
编辑:在下面发表你的评论想知道如何根据整数(或枚举,我看到你现在使用的 - 同样的概念)改变方向;这里有一些伪代码:
Vec2 direction(0, 0);
if (currentDirection == Up)
direction.y = -1;
else if (currentDirection == Down)
direction.y = 1;
else if (currentDirection == Left)
direction.x = -1;
else if (currentDirection == Right)
direction.x = 1;
// direction is now a vector containing an x and y offset, which you can
// apply to the current position of the snake head to find the next
// position.
答案 1 :(得分:2)
基本原则是你需要检测头部是否到达自身的任何一个块 - 如果是这样,它就会被“咬住”。
所以,当你刚刚移动蛇(包括“生长”它,如果适用的话)时,检查头部是否与组成蛇的任何其他“块”的位置匹配。
编辑:为了使蛇“摆动”,你需要使用“记住”头部移动的方向,并且每次移动应该将该块的方向“洗牌”到其后面的方向。
换句话说,向dir
添加SnakeBlock
条目,并使用它来移动每个区块。
答案 2 :(得分:2)
这就是过度复杂化的结果。
因为您使用std::deque
,所以您不需要“下一个”字段。或“移动”方法。块也不需要单独的纹理(这意味着所有纹理都是唯一的,这是不正确的)。
完整游戏的粗略轮廓(省略构造函数):
struct Vector2{
int x, y;
};
typedef std::deque<Vector2> Vec2Deque;
struct Snake{
Vec2 direction; //(+-1, +-1)
int blockSize;
Vec2Deque blocks;//for blocks you only need their coordinates.
void render(){
for(size_T i = 0; i < blocks.size(); i++)
renderSpriteAt(blocks[i]);
}
void advanceStep(){
Vector2 headPos = blocks[0];//take current head pos
headPos.x += blockSize * direction.x; //calculate next position based on direction
headPos.y += blockSize * direction.y; //and block size. Direction is 2component vector.
blocks.pop_back();//remove last element
blocks.push_front(headPos);//insert new element with new position as a head.
//That'll automatically create illusion of movement.
}
};
这将模拟经典的基于网格的蛇。
如果你想要更好的蛇(它可以顺利移动,并且能够以小角度转动(比如左边1度),事情会变得更复杂。
想想简单。另见KISS原则。
新代码记录在你所有人都知道的帐户中,但现在蛇消失了,可能是因为pop_back
替换它:
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
direction.x = -1;
for(int i = 1; i < Snake.size(); i++)
{
Snake[i].snakeblock.setPosition(Snake[i+1].snakeblock.getPosition().x-20, Snake[i+1].snakeblock.getPosition().y);
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
direction.x = 1;
for(int j = 1; j < Snake.size(); j++)
{
Snake[j].snakeblock.setPosition(Snake[j+1].snakeblock.getPosition().x+20, Snake[j+1].snakeblock.getPosition().y);
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
direction.y = -1;
for(int l = 1; l < Snake.size(); l++)
{
Snake[l].snakeblock.setPosition(Snake[l+1].snakeblock.getPosition().x, Snake[l+1].snakeblock.getPosition().y-22);
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
direction.y = 1;
for(int o = 1; o < Snake.size(); o++)
{
Snake[o].snakeblock.setPosition(Snake[o+1].snakeblock.getPosition().x, Snake[o+1].snakeblock.getPosition().y+22);
}
}
用这个:
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
direction.x = -1;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
direction.x = 1;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
direction.y = -1;
for(int l = 1; l < Snake.size(); l++)
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
direction.y = 1;
}
你不应该在advanceStep之外的任何地方更新snake。 你应该使用push / pop或那个移动元素的循环,而不是两个。 你不知道,你可以在你的所有循环中使用“i”,而不是每次都选择不同的变量名,对吗?
如果您仍然遇到蛇的问题,请尝试编写scroll shooter。例如:
除非你想为这些游戏添加粒子系统,否则它们应该比蛇更容易,因为在那些游戏中,一个对象只有一个精灵。
答案 3 :(得分:1)
据我所知,目前你的蛇仍然是一条直线,你希望它能像其他游戏一样转动。
我在游戏中做了什么,我有两个数据结构,一个用于蛇形部分(位置和方向),另一个用于转弯(方向和位置)。
在游戏循环中,Snake部分正朝着它的方向移动,但如果它的位置与转弯方向相匹配,则蛇形部分会改变方向以转向方向并相应地更新其位置。
当你将它应用于蛇的尾部时,转动被移除。并在检测到按键时添加,捕捉其方向和位置是蛇的头部位置。
我的实施是here,您可以查看我说的内容。