游戏 objects 向左和向上移动,但不要向右和向下移动
Game objects move left and up, but don't move right and down
更新
我明白了,提供部分代码并不能解决问题。有很多文件,所以我将通过 GitHub 提供所有应用程序,供任何想尝试解决此问题的人使用:
https://github.com/johnydominus/CrimsonLikeGameSMFL
提前抱歉我的英语和编程知识。我是新手。
我正在使用 C++ 和 SFML SDK 制作 2D 游戏。游戏类似于 CrimsonLand (2003):玩家应该在地图上行走并射击怪物,同时他们试图接近他。
目前玩家在走路,怪物在追他,但前提是他们的方向是左或上。如果需要的方向是正确的或向下的 - 他们不会移动。怪物只是停留并盯着玩家的方向。按下右或下按钮时播放器不会移动。
我已经实现了 2 个运动坐标系统 - 相对于地图(处理游戏事件,例如带子弹的十字路口怪物)和相对于玩家(以玩家为中心 "camera")。运动先写到地图坐标,再转换为玩家相对坐标。因此,绘图使用的是玩家相对坐标。但是,看起来问题不在于绘图。
输入有效 - 我尝试更改移动分配(仅用于检查)并设置为在按下右键时向左移动,在按下按钮时向上移动 - 它起作用了:玩家向上和向下移动按钮并通过左右按钮向左移动。
我会尝试删除所有与问题无关的字符串。但事实上,我不清楚哪里出了问题——会有很多代码。
地图、怪物和玩家 headers,以及 .cpp 文件 - 游戏的声明和定义 objects。
引擎 header 和 .cpp - 引擎的声明和定义,处理 objects 交互。
输入和更新 .cpp - 引擎方法的定义,分别处理来自键盘的输入和更新 objects 位置和状态。
player.h
class Player :
public Object
{
private:
std::vector<float> mapSize{0,0};
int speed = 1;
POINT prevPosition;
std::vector<float> relatMovement{ 0,0 };
bool leftPressed;
bool rightPressed;
bool upPressed;
bool downPressed;
public:
POINT Position;
POINT relatPosition;
void moveLeft();
void moveRight();
void moveUp();
void moveDown();
void stopLeft();
void stopRight();
void stopUp();
void stopDown();
void update(float elapsedTime);
};
player.cpp
void Player::moveLeft()
{
leftPressed = true;
}
void Player::moveRight()
{
rightPressed = true;
}
void Player::moveUp()
{
upPressed = true;
}
void Player::moveDown()
{
downPressed = true;
}
void Player::stopLeft()
{
leftPressed = false;
}
void Player::stopRight()
{
rightPressed = false;
}
void Player::stopUp()
{
upPressed = false;
}
void Player::stopDown()
{
downPressed = false;
}
void Player::update(float elapsedTime)
{
if (rightPressed)
Position.x += speed * elapsedTime;
if (leftPressed)
Position.x -= speed * elapsedTime;
if (upPressed)
Position.y -= speed * elapsedTime;
if (downPressed)
Position.y += speed * elapsedTime;
relatMovement[0] = Position.x - prevPosition.x;
relatMovement[1] = Position.y - prevPosition.y;
prevPosition = Position;
}
monster.h
class Monster :
public Object
{
private:
float pathLength;
Player* thePlayer;
Map* theMap;
POINT playerPosition;
POINT playerRelatPosition;
POINT nextStep;
std::vector<float> playerRelatMovement{0,0};
std::vector<float> direction{ 0,0 };
std::vector<float> vSpeed{ 0,0 };
public:
POINT Position;
POINT relatPosition;
POINT checkUpdate(float elapsedTime);
void update(float elapsedTime, POINT position);
};
monster.cpp
POINT Monster::checkUpdate(float elapsedTime)
{
nextStep = Position;
playerPosition = *(thePlayer->getPosition());
direction[0] = playerPosition.x - Position.x;
direction[1] = playerPosition.y - Position.y;
pathLength = sqrt(pow(direction[0], 2) + pow(direction[1], 2));
direction[0] /= pathLength;
direction[1] /= pathLength;
vSpeed[0] = ((float)direction[0] * (float)speed)/10.0;
vSpeed[1] = ((float)direction[1] * (float)speed)/10.0;
nextStep.x += vSpeed[0];
nextStep.y += vSpeed[1];
return nextStep;
}
void Monster::update(float elapsedTime, POINT aNextStep)
{
Position = aNextStep;
playerPosition = *(thePlayer->getPosition());
playerRelatPosition = *(thePlayer->getRelatPosition());
relatPosition.x = playerRelatPosition.x + (Position.x - playerPosition.x);
relatPosition.y = playerRelatPosition.y + (Position.y - playerPosition.y);
shape.left = Position.x - (size[0] / 2);
shape.right = Position.x + (size[0] / 2);
shape.top = Position.y - (size[1] / 2);
shape.bottom = Position.y + (size[1] / 2);
}
map.h
class Map:
public Object
{
private:
std::vector<float> relatMovement{0,0};
std::vector<float> size{0,0};
Player* thePlayer;
public:
POINT Position;
POINT relatPosition;
void update();
};
map.cpp
Map::Map()
{
Position.x = 0;
Position.y = 0;
}
void Map::update()
{
relatMovement = *(thePlayer->getRelatMovement());
relatPosition.x -= relatMovement[0];
relatPosition.y -= relatMovement[1];
}
Engine.h
class Engine
{
private:
Player thePlayer;
Map theMap;
Monster* allMonsters;
int mapXstart=0, mapYstart=0, ammoNumberStart=0, enemiesNumberStart=0;
void input();
void update(float timeInSeconds);
void draw();
void setWindowSize(int mapX, int mapY);
void setMapSize(float mapWidth, float mapHeight);
public:
void start();
};
Engine.cpp
Engine::Engine()
{
//setting map sprites
a = ((mapY+windowY) / theMap.mSprite.getTexture()->getSize().y) + 1;
b = ((mapX+windowX) / theMap.mSprite.getTexture()->getSize().x) + 1;
mapSprites = new sf::Sprite*[a];
for (i = 0; i < a; i++) {
mapSprites[i] = new sf::Sprite[b];
for (j = 0; j < b; j++) {
mapSprites[i][j].setTexture(*theMap.mSprite.getTexture());
}
}
//setting window
mWindow.create(sf::VideoMode(windowX, windowY), "CrimsonLikeGame", sf::Style::Default);
//setting game objects
//map
int mapRelX, mapRelY;
mapRelX = (windowX / 2) - (mapX / 2);
mapRelY = (windowY / 2) - (mapY / 2);
theMap.setRelativePosition(mapRelX, mapRelY);
theMap.setSize(mapX, mapY);
theMap.setPlayer(&thePlayer);
//player
thePlayer.setPosition(mapX/2,mapY/2);
thePlayer.setRelativePosition(windowX / 2, windowY / 2);
thePlayer.setMapSize(mapX, mapY);
//monsters
allMonsters = new Monster[enemiesNumber];
for (i = 0; i < enemiesNumber; i++) {
allMonsters[i].setPlayer(&thePlayer);
allMonsters[i].setMap(&theMap);
}
}
void Engine::start()
{
sf::Clock clock;
//game loop
while (mWindow.isOpen()) {
sf::Time dt = clock.restart();
float dtAsSeconds = dt.asSeconds();
input();
update(dtAsSeconds);
draw();
}
}
input.cpp
void Engine::input() {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) {
mWindow.close();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
thePlayer.moveLeft();
}
else {
thePlayer.stopLeft();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
thePlayer.moveRight();
}
else {
thePlayer.stopRight();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
thePlayer.moveUp();
}
else {
thePlayer.stopUp();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
thePlayer.moveDown();
}
else {
thePlayer.stopDown();
}
if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
mouseButtonPressed = true;
}
else {
mouseButtonPressed = false;
}
}
update.cpp
void Engine::update(float timeInSeconds) {
if (thePlayer.isAlive()&&enemiesAlive) {
thePlayer.update(timeInSeconds);
theMap.update();
//Writing down, where each monster is going to go by it's next step
for (i = 0; i < enemiesNumber; i++) {
if (allMonsters[i].isAlive()) {
enemiesNextSteps[i] = allMonsters[i].checkUpdate(timeInSeconds);
}
}
//cheking - does anybody is going to collide
for (i = 0; i < enemiesNumber; i++) {
if (allMonsters[i].isAlive()) {
int j;
for (j = 0; j < enemiesNumber; j++) {
if (j == i)
continue;
else {
if ((((allMonsters[i].shape.left <= allMonsters[j].shape.right) && (allMonsters[i].shape.left >= allMonsters[j].shape.left)) || ((allMonsters[i].shape.right <= allMonsters[j].shape.right) && (allMonsters[i].shape.right >= allMonsters[j].shape.left))) && (((allMonsters[i].shape.bottom >= allMonsters[j].shape.top) && (allMonsters[i].shape.bottom <= allMonsters[j].shape.bottom)) || ((allMonsters[i].shape.top >= allMonsters[j].shape.top) && (allMonsters[i].shape.top <= allMonsters[j].shape.bottom)))) {
monstersCollide[i] = true;
}
}
}
}
}
//updating each alive monster position without collisions
for (i = 0; i < enemiesNumber; i++) {
if (allMonsters[i].isAlive()/*&&!monstersCollide[i]*/) {
allMonsters[i].setPosition(enemiesNextSteps[i]);
allMonsters[i].update(timeInSeconds, enemiesNextSteps[i]);
}
}
}
else {
//if player is dead - restart the game
thePlayer.setAlive(true);
for (i = 0; i < enemiesNumber; i++) {
allMonsters[i].setAlive(true);
}
}
}
想了半天。希望你能帮我解决这个问题。
好的。我实际上已经构建了 运行 这段代码,而你的运动问题的根本原因是你的坐标使用整数,并随之而来的不对称:
if (rightPressed)
Position.x += speed * elapsedTime;
if (leftPressed)
Position.x -= speed * elapsedTime;
乍一看,这两者似乎相当,但当您考虑实际情况时,它们会略有不同。因为你的速度相对较低(1.0
),你的运行时间也相对较低(例如 ~0.016
一帧),差异最终会减少一。要了解接下来会发生什么,您需要查看类型转换。
这些语句实际上等同于:
Position.x = Position.x + (speed * elapsedTime);
因为 speed
和 elapsedTime
是浮点数,所以 Position.x
也被提升为浮点数。然后将分数加减,然后然后将结果转换回整数。
如果向左移动,数字例如100
转换为 100.0
,然后减去 0.016
,得到 99.984
。然后,整数转换删除小数部分,得到 99
的值和玩家位置的明显变化。
在向右移动的情况下,我们也这样做,但我们最终得到的值是 100.016
。这再次转换回值为 100
的整数结果。
要解决此问题,最简单的解决方案是让玩家的位置也使用浮动。然后将微小的变化适当地积累起来。您可能会观察到玩家的移动速度比您最初预期的要慢得多,因为整数钳位效应将消失;将速度设置为 60
应该会让你或多或少回到原来的位置。
更新
我明白了,提供部分代码并不能解决问题。有很多文件,所以我将通过 GitHub 提供所有应用程序,供任何想尝试解决此问题的人使用:
https://github.com/johnydominus/CrimsonLikeGameSMFL
提前抱歉我的英语和编程知识。我是新手。 我正在使用 C++ 和 SFML SDK 制作 2D 游戏。游戏类似于 CrimsonLand (2003):玩家应该在地图上行走并射击怪物,同时他们试图接近他。 目前玩家在走路,怪物在追他,但前提是他们的方向是左或上。如果需要的方向是正确的或向下的 - 他们不会移动。怪物只是停留并盯着玩家的方向。按下右或下按钮时播放器不会移动。
我已经实现了 2 个运动坐标系统 - 相对于地图(处理游戏事件,例如带子弹的十字路口怪物)和相对于玩家(以玩家为中心 "camera")。运动先写到地图坐标,再转换为玩家相对坐标。因此,绘图使用的是玩家相对坐标。但是,看起来问题不在于绘图。
输入有效 - 我尝试更改移动分配(仅用于检查)并设置为在按下右键时向左移动,在按下按钮时向上移动 - 它起作用了:玩家向上和向下移动按钮并通过左右按钮向左移动。
我会尝试删除所有与问题无关的字符串。但事实上,我不清楚哪里出了问题——会有很多代码。 地图、怪物和玩家 headers,以及 .cpp 文件 - 游戏的声明和定义 objects。 引擎 header 和 .cpp - 引擎的声明和定义,处理 objects 交互。 输入和更新 .cpp - 引擎方法的定义,分别处理来自键盘的输入和更新 objects 位置和状态。
player.h
class Player :
public Object
{
private:
std::vector<float> mapSize{0,0};
int speed = 1;
POINT prevPosition;
std::vector<float> relatMovement{ 0,0 };
bool leftPressed;
bool rightPressed;
bool upPressed;
bool downPressed;
public:
POINT Position;
POINT relatPosition;
void moveLeft();
void moveRight();
void moveUp();
void moveDown();
void stopLeft();
void stopRight();
void stopUp();
void stopDown();
void update(float elapsedTime);
};
player.cpp
void Player::moveLeft()
{
leftPressed = true;
}
void Player::moveRight()
{
rightPressed = true;
}
void Player::moveUp()
{
upPressed = true;
}
void Player::moveDown()
{
downPressed = true;
}
void Player::stopLeft()
{
leftPressed = false;
}
void Player::stopRight()
{
rightPressed = false;
}
void Player::stopUp()
{
upPressed = false;
}
void Player::stopDown()
{
downPressed = false;
}
void Player::update(float elapsedTime)
{
if (rightPressed)
Position.x += speed * elapsedTime;
if (leftPressed)
Position.x -= speed * elapsedTime;
if (upPressed)
Position.y -= speed * elapsedTime;
if (downPressed)
Position.y += speed * elapsedTime;
relatMovement[0] = Position.x - prevPosition.x;
relatMovement[1] = Position.y - prevPosition.y;
prevPosition = Position;
}
monster.h
class Monster :
public Object
{
private:
float pathLength;
Player* thePlayer;
Map* theMap;
POINT playerPosition;
POINT playerRelatPosition;
POINT nextStep;
std::vector<float> playerRelatMovement{0,0};
std::vector<float> direction{ 0,0 };
std::vector<float> vSpeed{ 0,0 };
public:
POINT Position;
POINT relatPosition;
POINT checkUpdate(float elapsedTime);
void update(float elapsedTime, POINT position);
};
monster.cpp
POINT Monster::checkUpdate(float elapsedTime)
{
nextStep = Position;
playerPosition = *(thePlayer->getPosition());
direction[0] = playerPosition.x - Position.x;
direction[1] = playerPosition.y - Position.y;
pathLength = sqrt(pow(direction[0], 2) + pow(direction[1], 2));
direction[0] /= pathLength;
direction[1] /= pathLength;
vSpeed[0] = ((float)direction[0] * (float)speed)/10.0;
vSpeed[1] = ((float)direction[1] * (float)speed)/10.0;
nextStep.x += vSpeed[0];
nextStep.y += vSpeed[1];
return nextStep;
}
void Monster::update(float elapsedTime, POINT aNextStep)
{
Position = aNextStep;
playerPosition = *(thePlayer->getPosition());
playerRelatPosition = *(thePlayer->getRelatPosition());
relatPosition.x = playerRelatPosition.x + (Position.x - playerPosition.x);
relatPosition.y = playerRelatPosition.y + (Position.y - playerPosition.y);
shape.left = Position.x - (size[0] / 2);
shape.right = Position.x + (size[0] / 2);
shape.top = Position.y - (size[1] / 2);
shape.bottom = Position.y + (size[1] / 2);
}
map.h
class Map:
public Object
{
private:
std::vector<float> relatMovement{0,0};
std::vector<float> size{0,0};
Player* thePlayer;
public:
POINT Position;
POINT relatPosition;
void update();
};
map.cpp
Map::Map()
{
Position.x = 0;
Position.y = 0;
}
void Map::update()
{
relatMovement = *(thePlayer->getRelatMovement());
relatPosition.x -= relatMovement[0];
relatPosition.y -= relatMovement[1];
}
Engine.h
class Engine
{
private:
Player thePlayer;
Map theMap;
Monster* allMonsters;
int mapXstart=0, mapYstart=0, ammoNumberStart=0, enemiesNumberStart=0;
void input();
void update(float timeInSeconds);
void draw();
void setWindowSize(int mapX, int mapY);
void setMapSize(float mapWidth, float mapHeight);
public:
void start();
};
Engine.cpp
Engine::Engine()
{
//setting map sprites
a = ((mapY+windowY) / theMap.mSprite.getTexture()->getSize().y) + 1;
b = ((mapX+windowX) / theMap.mSprite.getTexture()->getSize().x) + 1;
mapSprites = new sf::Sprite*[a];
for (i = 0; i < a; i++) {
mapSprites[i] = new sf::Sprite[b];
for (j = 0; j < b; j++) {
mapSprites[i][j].setTexture(*theMap.mSprite.getTexture());
}
}
//setting window
mWindow.create(sf::VideoMode(windowX, windowY), "CrimsonLikeGame", sf::Style::Default);
//setting game objects
//map
int mapRelX, mapRelY;
mapRelX = (windowX / 2) - (mapX / 2);
mapRelY = (windowY / 2) - (mapY / 2);
theMap.setRelativePosition(mapRelX, mapRelY);
theMap.setSize(mapX, mapY);
theMap.setPlayer(&thePlayer);
//player
thePlayer.setPosition(mapX/2,mapY/2);
thePlayer.setRelativePosition(windowX / 2, windowY / 2);
thePlayer.setMapSize(mapX, mapY);
//monsters
allMonsters = new Monster[enemiesNumber];
for (i = 0; i < enemiesNumber; i++) {
allMonsters[i].setPlayer(&thePlayer);
allMonsters[i].setMap(&theMap);
}
}
void Engine::start()
{
sf::Clock clock;
//game loop
while (mWindow.isOpen()) {
sf::Time dt = clock.restart();
float dtAsSeconds = dt.asSeconds();
input();
update(dtAsSeconds);
draw();
}
}
input.cpp
void Engine::input() {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) {
mWindow.close();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
thePlayer.moveLeft();
}
else {
thePlayer.stopLeft();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
thePlayer.moveRight();
}
else {
thePlayer.stopRight();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
thePlayer.moveUp();
}
else {
thePlayer.stopUp();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
thePlayer.moveDown();
}
else {
thePlayer.stopDown();
}
if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
mouseButtonPressed = true;
}
else {
mouseButtonPressed = false;
}
}
update.cpp
void Engine::update(float timeInSeconds) {
if (thePlayer.isAlive()&&enemiesAlive) {
thePlayer.update(timeInSeconds);
theMap.update();
//Writing down, where each monster is going to go by it's next step
for (i = 0; i < enemiesNumber; i++) {
if (allMonsters[i].isAlive()) {
enemiesNextSteps[i] = allMonsters[i].checkUpdate(timeInSeconds);
}
}
//cheking - does anybody is going to collide
for (i = 0; i < enemiesNumber; i++) {
if (allMonsters[i].isAlive()) {
int j;
for (j = 0; j < enemiesNumber; j++) {
if (j == i)
continue;
else {
if ((((allMonsters[i].shape.left <= allMonsters[j].shape.right) && (allMonsters[i].shape.left >= allMonsters[j].shape.left)) || ((allMonsters[i].shape.right <= allMonsters[j].shape.right) && (allMonsters[i].shape.right >= allMonsters[j].shape.left))) && (((allMonsters[i].shape.bottom >= allMonsters[j].shape.top) && (allMonsters[i].shape.bottom <= allMonsters[j].shape.bottom)) || ((allMonsters[i].shape.top >= allMonsters[j].shape.top) && (allMonsters[i].shape.top <= allMonsters[j].shape.bottom)))) {
monstersCollide[i] = true;
}
}
}
}
}
//updating each alive monster position without collisions
for (i = 0; i < enemiesNumber; i++) {
if (allMonsters[i].isAlive()/*&&!monstersCollide[i]*/) {
allMonsters[i].setPosition(enemiesNextSteps[i]);
allMonsters[i].update(timeInSeconds, enemiesNextSteps[i]);
}
}
}
else {
//if player is dead - restart the game
thePlayer.setAlive(true);
for (i = 0; i < enemiesNumber; i++) {
allMonsters[i].setAlive(true);
}
}
}
想了半天。希望你能帮我解决这个问题。
好的。我实际上已经构建了 运行 这段代码,而你的运动问题的根本原因是你的坐标使用整数,并随之而来的不对称:
if (rightPressed)
Position.x += speed * elapsedTime;
if (leftPressed)
Position.x -= speed * elapsedTime;
乍一看,这两者似乎相当,但当您考虑实际情况时,它们会略有不同。因为你的速度相对较低(1.0
),你的运行时间也相对较低(例如 ~0.016
一帧),差异最终会减少一。要了解接下来会发生什么,您需要查看类型转换。
这些语句实际上等同于:
Position.x = Position.x + (speed * elapsedTime);
因为 speed
和 elapsedTime
是浮点数,所以 Position.x
也被提升为浮点数。然后将分数加减,然后然后将结果转换回整数。
如果向左移动,数字例如100
转换为 100.0
,然后减去 0.016
,得到 99.984
。然后,整数转换删除小数部分,得到 99
的值和玩家位置的明显变化。
在向右移动的情况下,我们也这样做,但我们最终得到的值是 100.016
。这再次转换回值为 100
的整数结果。
要解决此问题,最简单的解决方案是让玩家的位置也使用浮动。然后将微小的变化适当地积累起来。您可能会观察到玩家的移动速度比您最初预期的要慢得多,因为整数钳位效应将消失;将速度设置为 60
应该会让你或多或少回到原来的位置。