我目前正试图为我的可控蛇创造一个网格来移动。目前。我使用1024x768的分辨率,并希望蛇在16x16网格(64x48分辨率)之间移动
到目前为止,蛇只是以设定的速度逐个像素地移动。
我将粘贴.cpp和.hpp文件,我认为这些文件与我需要实现代码的位置相关。如果有人能提供任何可能很棒的建议/代码!
snake.cpp
#include "snake.hpp"
#include <cstdlib>
void Snake::move()
{
switch(direction_){
case Direction::North:
position_.y += 1;
break;
case Direction::East:
position_.x += 1;
break;
case Direction::South:
position_.y -= 1;
break;
case Direction::West:
position_.x -= 1;
}
if (position_.x < 0) position_.x = 63; else if (position_.x > 63) position_.x = 0;
if (position_.y < 0) position_.y = 47; else if (position_.y > 47) position_.y = 0;
}
void Snake::render(prg::Canvas& canvas) const
{
canvas.drawCircle(getPosition().x * 16, getPosition().y * 16,16,prg::Colour::WHITE);
}
void Snake::changeDirection(Direction new_direction)
{
direction_ = new_direction;
}
snake.hpp
#if !defined SNAKE_HPP
#define SNAKE_HPP
#include <prg_interactive.hpp>
enum class Direction {
North = 1, East, South, West
};
struct Position final {
int x{0}, y{0};
Position(int ix, int iy) : x{ix}, y{iy} {}
};
class Snake {
public:
virtual ~Snake() {}
virtual void move();
void render(prg::Canvas& canvas) const;
void changeDirection(Direction new_direction);
const Position& getPosition() const {return position_;}
void setPosition(const Position& position){ position_ = position;}
private:
Direction direction_ {Direction::North};
Position position_ {0,0};
};
class PlayerSnake : public Snake,
public prg::IKeyEvent {
public:
PlayerSnake();
virtual ~PlayerSnake();
bool onKey(const prg::IKeyEvent::KeyEvent& key_event) override;
};
#endif // SNAKE_HPP
play_state.cpp
#include "play_state.hpp"
#include "ai_snake.hpp"
#include "player_snake.hpp"
#include <iostream>
const size_t MaxShapes {5};
const unsigned int MaxScale {5};
bool PlayState::onCreate()
{
snakes_.push_back(new AISnake);
snakes_.back()->setPosition(Position(100,100));
snakes_.push_back(new PlayerSnake);
snakes_.back()->setPosition(Position(50,50));
double x, y;
for(unsigned shape = 0;shape < MaxShapes;shape++)
{
x = (double)(rand() % prg::application.getScreenWidth());
y = (double)(rand() % prg::application.getScreenHeight());
shapes_.push_back(Square({x, y}));
}
return true;
}
bool PlayState::onDestroy()
{
return true;
}
void PlayState::onEntry()
{
prg::application.addKeyListener(*this);
game_timer_.start();
}
void PlayState::onExit()
{
prg::application.removeKeyListener(*this);
game_timer_.stop();
}
void PlayState::onUpdate()
{
}
void PlayState::onRender(prg::Canvas& canvas)
{
const std::string text = "";
canvas.blitFast(
background_,
canvas.getWidth() / 2 - background_.getWidth() / 2,
canvas.getHeight() / 2 - background_.getHeight() / 2
);
prg::uint text_dims[2];
prg::Font::MASSIVE.computePrintDimensions(text_dims, text);
prg::Font::MASSIVE.print(
canvas,
prg::application.getScreenWidth() / 2 - text_dims[0] / 2,
prg::application.getScreenHeight() / 2 - text_dims[1] / 2,
prg::Colour::RED,
text);
for(const auto snake : snakes_) {
snake->render(canvas);
}
for(Shape shapes : shapes_) {
shapes.render(canvas);
}
}
bool PlayState::onKey(const prg::IKeyEvent::KeyEvent& key_event)
{
if(key_event.key_state == KeyEvent::KB_DOWN) {
switch(key_event.key) {
case KeyEvent::KB_ESC_KEY:
prg::application.exit();
break;
}
}
return true;
}
void PlayState::onTimer(prg::Timer& timer)
{
for(auto snake : snakes_) {
snake->move();
}
}
play_state.hpp
#if !defined PLAY_STATE_HPP
#define PLAY_STATE_HPP
#include <prg_interactive.hpp>
#include "snake.hpp"
#include "square.hpp"
#include <list>
//Example of forward declaration of Snake class
class Snake;
class PlayState final : public prg::IAppState,
public prg::IKeyEvent,
public prg::ITimerEvent {
public:
PlayState() = default;
bool onCreate() override;
bool onDestroy() override;
void onEntry() override;
void onExit() override;
void onUpdate() override;
void onRender(prg::Canvas& canvas) override;
bool onKey(const prg::IKeyEvent::KeyEvent& key_event) override;
void onTimer(prg::Timer& timer) override;
private:
//Snake* snakes_[2] {nullptr,nullptr};
std::list<Snake*> snakes_;
prg::Timer game_timer_ {0, 1000 / 30, *this};
const prg::Image background_ {prg::ImageFile("resources/images/border.bmp").load()};
std::vector<Shape> shapes_;
};
#endif // PLAY_STATE_HPP
player_snake.cpp
#include "player_snake.hpp"
//PlayerSnake Implementation
//
PlayerSnake::PlayerSnake()
{
prg::application.addKeyListener(*this);
}
PlayerSnake::~PlayerSnake()
{
prg::application.removeKeyListener(*this);
}
bool PlayerSnake::onKey(const prg::IKeyEvent::KeyEvent& key_event)
{
if(key_event.key_state == KeyEvent::KB_DOWN) {
switch(key_event.key) {
case KeyEvent::KB_LEFT_KEY:
changeDirection(Direction::West);
break;
case KeyEvent::KB_RIGHT_KEY:
changeDirection(Direction::East);
break;
case KeyEvent::KB_UP_KEY:
changeDirection(Direction::North);
break;
case KeyEvent::KB_DOWN_KEY:
changeDirection(Direction::South);
break;
}
}
return true;
}
player_snake.hpp
#if !defined PLAYER_SNAKE_HPP
#define PLAYER_SNAKE_HPP
#include "snake.hpp"
#include <prg_interactive.hpp>
#endif //PLAYER_SNAKE_HPP
答案 0 :(得分:1)
snakes_.push_back(new AISnake);
snakes_.back()->setPosition(Position(100,100));
snakes_.push_back(new PlayerSnake);
snakes_.back()->setPosition(Position(50,50));
因为在move
函数中,您将蛇限制为(64, 48)
作为最大位置。 x位置100超过限制。 y
职位已超过限额。
您可能希望根据MAXIMUM_WIDTH和MAXIMUM_HEIGHT常量在不同位置设置它们(请参阅我的评论):
Snake AISnake;
AISnake.setPosition(MAXIMUM_WIDTH / 4, MAXIMUM_HEIGHT / 4);
snakes_.push_back(AISnake);
Snake PlayerSnake;
PlayerSnake.setPosition(MAXIMUM_WIDTH * 3 / 4,
MAXIMUM_HEIGHT * 3 / 4);
snakes_.push_back(PlayerSnake);
另请注意,在上面的代码片段中,没有动态内存分配。变量(蛇)在本地定义,复制到snakes_
容器中。这意味着无需担心内存泄漏或内存管理(比如何时删除蛇占用的内存)。
有些地方,你使用边界的屏幕尺寸,其他地方,你使用硬编码值:
x = (double)(rand() % prg::application.getScreenWidth());
y = (double)(rand() % prg::application.getScreenHeight());
您需要确定游戏板是占用整个屏幕尺寸还是固定尺寸。如果您保留上述声明,则应测试位置以验证它们是否在游戏边界内。
如果这是一个GUI应用程序,您需要决定固定大小的游戏板或设置为窗口大小或扩展到整个屏幕的板。对于固定尺寸的电路板,您应该考虑“视口”设计。这意味着窗口是显示板的一小部分的视图或端口(板比窗口大)。
您应该将逻辑板和物理屏幕之间的概念分开。此概念允许您在不影响任何其他模块的情况下使电路板适应屏幕。
例如,Board
绘制到屏幕上。 Board
单元格可能具有不同的像素尺寸,具体取决于屏幕分辨率。但是,蛇的一部分将始终占据至少一个Board
细胞。所以蛇的运动不依赖于屏幕分辨率,只取决于Board
尺寸。
通过将对象Board
和Screen
放在单独的文件中,您可以更改屏幕尺寸,而无需重新编译任何蛇形或主文件。