Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/magento/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何让蛇咬人? 我正试着用SFML做一个C++游戏。 下面是我的代码。问题是,我不知道我怎么可能让蛇咬自己:每一个蛇块都占据最后一个蛇块的位置,形成一条完全笔直的蛇。所以这更像是一个算法问题。 感谢您的建议: 顺便说一句,由于编辑器将哈希值和最大长度和删除段_C++ - Fatal编程技术网

如何让蛇咬人? 我正试着用SFML做一个C++游戏。 下面是我的代码。问题是,我不知道我怎么可能让蛇咬自己:每一个蛇块都占据最后一个蛇块的位置,形成一条完全笔直的蛇。所以这更像是一个算法问题。 感谢您的建议: 顺便说一句,由于编辑器将哈希值和最大长度和删除段

如何让蛇咬人? 我正试着用SFML做一个C++游戏。 下面是我的代码。问题是,我不知道我怎么可能让蛇咬自己:每一个蛇块都占据最后一个蛇块的位置,形成一条完全笔直的蛇。所以这更像是一个算法问题。 感谢您的建议: 顺便说一句,由于编辑器将哈希值和最大长度和删除段,c++,C++,使用新原则的新代码: #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

使用新原则的新代码:

#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]);
}
新的代码考虑了你们所有人说的一切,但现在蛇消失了,可能是因为它回来了

#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);
}

基本原理是,你需要检测头部是否到达自身的任何一块——如果是,它自己被咬伤了

因此,当你刚刚移动了蛇,包括它的生长,如果适用的话,检查头部是否与构成蛇的任何其他块的位置相匹配

编辑:要使蛇摆动,你需要使用一个记忆头朝哪个方向移动,并且每次移动都应该将该块的方向移动到它后面的方向


换句话说,向SnakeBlock添加一个dir条目,并使用该条目移动每个块。

您的实现有很多问题。这里不是指出每一个问题,而是一个粗略的提纲。假设您的蛇是一个片段列表,具有最大长度:

在每个更新步骤上: 下一个位置=头部位置+当前方向。 在下一个位置的队列首添加段。 当队列长度大于最大长度时,请删除队列尾部的一段。 在键盘输入时,只需更改当前方向。 如果您需要更改蛇的长度,只需更改最大长度-更新步骤将调整蛇的长度。 从语义上讲,碰撞是指蛇头撞到身体的任何其他部位

要检测冲突,请在每个更新步骤上执行此操作。对照身体其余部分检查头部。如果有交叉口,就会发生碰撞

顺便说一句,如果您想在最大蛇长度减少时获得更平滑的收缩效果,例如,您可以在队列长度>最大长度和删除段<收缩率的情况下,每次更新最多删除两段

编辑:在下面回答您的评论,想知道如何根据整数或枚举改变方向,我看到您现在使用的是相同的概念;这里还有一些伪代码:

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.

这就是你将事情过度复杂化的结果

因为您使用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.
    }
};
这将模拟基于网格的经典snake

如果你想要一条更好的蛇,它能平稳地移动,并能以小角度向左旋转1度,事情会变得更复杂

简单想想。另见接吻原则

新的代码考虑到了你们所说的一切,但现在蛇消失了,可能是因为pop_回来了

替换此项:

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,并且不需要每次都选择不同的变量名,对吗

如果你对这条蛇仍然有问题,试着写一封信来代替。例如:

神秘的。 卷轴射手。
除非你想在这些游戏中添加粒子系统,否则它们应该比蛇更容易,因为在这些游戏中,一个对象只有一个精灵。

据我所知,目前你的蛇仍然是一条直线,你希望它能够像在其他游戏中一样旋转

在我的游戏中,我有两个数据结构,一个用于蛇的位置和方向,另一个用于转弯方向和位置

在游戏循环中,蛇的一部分朝着它的方向移动,但若它的位置和转弯的方向相匹配,那个么蛇的一部分就会将它的方向改变为转弯的方向,并相应地更新它的位置

当你们将它应用到蛇的尾部时,回合被移除。并添加了当你检测到按键时,捕捉到它的方向和位置就是蛇的头部位置


我的实现是,你可以看看我说的话。

每个蛇块都知道它的位置,对吗?一个简单的解决方法是,每次更新,检查每个非头部块是否与头部块重叠。请完整阅读我的帖子:蛇是完全直的,因此它不会咬自己+1为最令人惊叹的问题标题ever@pm100我对这一点的投票实际上涉及到接口,允许部队使用设计模式@user2687718在Java中攻击地面、空中或两者的能力。如果
通过人们利用他们的空闲时间来帮助你做你应该能够自己做的家庭作业。没有必要抱着这样的态度看下面对我答案的评论。不,你不明白。。。我希望蛇能有一个能咬人的动作。我这里不谈碰撞!现在,它只是一条完全笔直的蛇,不会咬自己。你明白了吗?谢谢你现在的回答,但我不明白“洗牌”这个词,你能用其他词解释这部分吗?首先,你没有看过去的评论或完全阅读我的帖子,否则你会明白这不是冲突问题。第二,当前方向是一个整数,可以等于0、1、2和3,我真的不知道如何使用它使运动看起来像它可能会咬自己,或者你需要开发更多。我上面概述的算法精确地向你展示了如何赋予蛇改变方向的能力。要基于整数值在给定方向上移动蛇,可以使用开关或if,或选择不同的方向表示。由你决定。您可能希望查看有关控制流语句的教程-虽然您的代码表明您了解如何使用if,但您的注释表明您无法了解如何基于整型常量修改方向,因此我感到困惑。这里有解决这个问题所需要的一切,因为你没有精确,所以我必须用方向整数值的条件来改变方向。我希望你将来对别人说的话要更准确,不要因为他们不理解而责备他们。但是我还是很感谢你的帮助。你真的在你的帖子里写了代码吗?该代码大量使用switch和if块。我相信我认为你知道如何使用它们是合理的。如果你从其他地方复制了这段代码,你将在这个项目中遇到很多麻烦。谢谢,现在我明白你的意思了,所以我应该制作4个向量,称为Up/Down/Left/right,并在我的setPos中使用它们@用户2687718:不,我想你只是忘了移动蛇形挡块。移除最后一个,并在每一步添加新块作为头部。如果你一直尝试只移动第一个和最后一个块,这就是你所做的,什么都不会发生。你的代码中没有一个poppop_front/pop_back,你知道的…这是因为我试图测试它是否有一条由2/3段组成的蛇,稍后我会做pop/more push_front,我也不能做你刚才在SFML中写的东西,因为,一切都在一个大的循环窗口中。isOpen,所以我真的看不出如何使用你的想法。@user2687718:我看不出问题所在,也没有任何区别。也许你应该先试试简单点的?还是改用gamemaker?或者阅读更多教程?首先学习如何处理传统的snake,它的段数不是小数,然后你就可以开始使事情复杂化了。感谢你尝试使用你的实现检查这个粘贴箱我看不出问题你需要两个队列,一个用于snake,另一个用于所有回合。在您的代码中,我只看到一个snake队列和一个全局方向,这将导致您的snake沿直线移动。当您按键时,您需要在另一个队列中存储方向和位置,在移动蛇之前,将每个蛇部分的位置与该回合的位置进行比较,并相应地更改蛇部分的方向。