Does that make sense?
Yes! Thanks! Now I could make my character move from a spritesheet within the screen.
Here's my spritesheet:
(http://puu.sh/4PIzW.png)
And here's my code:
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(640, 480), "tilemap_character_test", sf::Style::Close);
enum Direction { Down, Left, Right, Up };
sf::Vector2i source(1, Down);
sf::Texture tex;
if(!tex.loadFromFile("player2.png"))
{
system("pause");
return EXIT_FAILURE;
}
sf::Sprite sprite;
sprite.setTexture(tex);
sprite.setTextureRect(sf::IntRect(32, 0, 32, 32));
const float spriteSpeedX = 250.0f;
const float spriteSpeedY = 250.0f;
sf::Clock clock;
float deltaTime = 0.f, currentTime = 0.f, previousTime = 0.f;
float frameCounter = 0, switchFrame = 75, frameSpeed = 500;
sf::Clock clock2;
while (window.isOpen())
{
currentTime = clock.getElapsedTime().asSeconds();
deltaTime = currentTime - previousTime;
previousTime = currentTime;
sf::Event event;
while (window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
window.close();
break;
case sf::Event::KeyPressed:
if(event.key.code == sf::Keyboard::Escape)
window.close();
break;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
source.y = Direction::Up;
if(sprite.getPosition().y >= 0)
sprite.move(0, - spriteSpeedY * deltaTime);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
source.y = Direction::Down;
if(sprite.getPosition().y <= 448)
sprite.move(0, spriteSpeedY * deltaTime);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
source.y = Direction::Right;
if(sprite.getPosition().x <= 608)
sprite.move(spriteSpeedX * deltaTime, 0);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
source.y = Direction::Left;
if(sprite.getPosition().x >= 0)
sprite.move(- spriteSpeedY * deltaTime, 0);
}
frameCounter += frameSpeed * clock2.restart().asSeconds();
if(frameCounter >= switchFrame)
{
frameCounter = 0;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)
|| sf::Keyboard::isKeyPressed(sf::Keyboard::Down)
|| sf::Keyboard::isKeyPressed(sf::Keyboard::Left)
|| sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
source.x++;
if(source.x * 32 >= tex.getSize().x)
source.x = 0;
}
sprite.setTextureRect(sf::IntRect(source.x * 32, source.y * 32, 32, 32));
window.clear();
window.draw(sprite);
window.display();
}
system("pause");
return EXIT_SUCCESS;
}
And here's the output:
(http://puu.sh/4PIGU.jpg)
So, now how do I load a tilemap in which this sprite can move(and test for collisions etc). I don't need exact codes but only how I should make my approach and the methods involved.
Thanks for your help! :D
Here's a map that I've created:
(http://puu.sh/4PJpL.png)
Here are the tiles:
(http://puu.sh/4PJr4.png)
And here's my code:
#include <SFML/Graphics.hpp>
const int width = 640;
const int height = 480;
const int bpp = 32;
const char* title = "tilemap[test]_1";
const int H = 10;
const int W = 50;
sf::String tileMap[H] =
{
"00000000000000000000000000000000000000000000000000",
"0 0",
"0 0",
"0 0",
"0 0",
"0 MMM 0",
"0 0",
"0 0",
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG",
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"
};
int main()
{
sf::RenderWindow window(sf::VideoMode(width, height, bpp), title, sf::Style::Close);
sf::Texture tileset;
if(!tileset.loadFromFile("tiles.png"))
{
system("pause");
return EXIT_FAILURE;
}
sf::Sprite tile;
tile.setTexture(tileset);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed
|| event.key.code == sf::Keyboard::Escape)
window.close();
}
window.clear(sf::Color(107, 140, 255));
for(int i = 0; i < H; i++)
{
for(int j = 0; j < W; j++)
{
if(tileMap[i][j] == 'G')
tile.setTextureRect(sf::IntRect(0 * 16, 0 * 16, 16, 16));
if(tileMap[i][j] == 'M')
tile.setTextureRect(sf::IntRect(1 * 16, 0 * 16, 16, 16));
if(tileMap[i][j] == '0' || tileMap[i][j] == ' ')
continue;
tile.setPosition(sf::Vector2f(j * 16, i * 16));
window.draw(tile);
}
}
window.display();
}
system("pause");
return EXIT_SUCCESS;
}
So, how do I use this tile map along with my character?
Thanks
Hi
my code is not producing the desired ouput. Here's my code:
/* Platformer try */
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
float offsetX = 0, offsetY = 0;
const int H = 17;
const int W = 150;
sf::String tileMap[H] =
{
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"0 0",
"0 0",
"0 0",
"0 0",
"0 w 0",
"0 0",
"0 0",
"0 c 0",
"0 0",
"0 0",
"0 c kckck 0",
"0G 0",
"0 d g d 0",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
};
// Classes
/* Player */
class PLAYER
{
public:
float dy, dx;
sf::FloatRect rect;
bool onGround;
sf::Sprite sprite;
float currentFrame;
PLAYER(sf::Texture &image);
void update(float time);
void Collision(int num);
~PLAYER();
};
PLAYER::PLAYER(sf::Texture &image)
{
sprite.setTexture(image);
rect = sf::FloatRect(100, 180, 16, 16);
dx = dy = 0.1;
currentFrame = 0;
}
void PLAYER::update(float time)
{
rect.left += dx * time;
Collision(0);
if(!onGround)
dy = dy + 0.0005 * time;
rect.top += dy * time;
onGround = false;
Collision(1);
currentFrame += time * 0.005;
if(currentFrame > 3)
currentFrame -= 3;
if(dx > 0)
sprite.setTextureRect(sf::IntRect(112 + 31 * int(currentFrame), 144, 16, 16));
if(dx < 0)
sprite.setTextureRect(sf::IntRect(112 + 31 * int(currentFrame) + 16, 144, -16, 16));
sprite.setPosition(rect.left - offsetX, rect.top - offsetY);
dx = 0;
}
void PLAYER::Collision(int num)
{
for(int i = rect.top / 16; i < (rect.top + rect.height) / 16; i++)
{
for(int j = rect.left / 16; j < (rect.left + rect.width) / 16; j++)
{
if(tileMap[i][j] == 'P' || tileMap[i][j] == 'k' || tileMap[i][j] == '0' || tileMap[i][j] == 'r' || tileMap[i][j] == 't')
{
if(dy > 0 && num == 1)
{
rect.top = i * 16 - rect.height;
dy = 0;
onGround = true;
}
if(dy < 0 && num == 1)
{
rect.top = i * 16 + 16;
dy = 0;
}
if(dx > 0 && num == 0)
{
rect.left = j * 16 - rect.width;
}
if(dx < 0 && num == 0)
{
rect.left = j * 16 + 16;
}
}
}
}
}
PLAYER::~PLAYER()
{
// dctor
}
class ENEMY
{
public:
float dx, dy;
sf::FloatRect rect;
sf::Sprite sprite;
float currentFrame;
bool onGround;
bool life;
void set(sf::Texture &image, int x, int y);
void update(float time);
void Collision();
~ENEMY();
};
void ENEMY::set(sf::Texture &image, int x, int y)
{
sprite.setTexture(image);
rect = sf::FloatRect(x, y, 16, 16);
dx = 0.05;
currentFrame = 0;
life = true;
}
void ENEMY::update(float time)
{
rect.left += dx * time;
Collision();
currentFrame += time * 0.005;
if(currentFrame > 2)
currentFrame -= 2;
sprite.setTextureRect(sf::IntRect(18 * int(currentFrame), 0, 16, 16));
if(!life)
sprite.setTextureRect(sf::IntRect(58, 0, 16, 16));
sprite.setPosition(rect.left - offsetX, rect.top - offsetY);
}
void ENEMY::Collision()
{
for(int i = rect.top / 16; i < (rect.top + rect.height); i++)
{
for(int j = rect.left / 16; j < (rect.left + rect.width); j++)
{
if(tileMap[i][j] == 'p' || tileMap[i][j] == '0')
{
if(dx > 0)
{
rect.left = j * 16 - rect.width;
dx *= -1;
}
else if(dx < 0)
{
rect.left = j * 16 + 16;
dx *=- 1;
}
}
}
}
}
ENEMY::~ENEMY()
{
// dctor
}
int main()
{
sf::RenderWindow window(sf::VideoMode(400, 250, 32), "Platformer_try[mario]");
sf::Texture tileSet;
tileSet.loadFromFile("Mario_tileset.png");
PLAYER Mario(tileSet);
ENEMY Mushy;
Mushy.set(tileSet, 48 * 16, 13 * 16);
sf::Sprite tiles;
tiles.setTexture(tileSet);
sf::SoundBuffer buffer;
buffer.loadFromFile("Jump.ogg");
sf::Sound sound(buffer);
sf::Music music;
music.openFromFile("Mario_Theme.ogg");
//music.play();
sf::Clock clock;
while (window.isOpen())
{
float time = clock.getElapsedTime().asMicroseconds();
clock.restart();
time = time / 500;
if(time > 20)
time = 20;
sf::Event event;
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed || event.key.code == sf::Keyboard::Escape)
window.close();
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
Mario.dx =- 0.1f;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
Mario.dx = 0.1f;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
if(Mario.onGround)
{
Mario.dy =- 0.27f;
Mario.onGround = false;
//sound.play();
}
}
Mario.update(time);
//Mushy.update(time);
if(Mario.rect.intersects(Mushy.rect))
{
if(Mushy.life)
{
if(Mario.dy > 0)
{
Mushy.dy = 0;
Mario.dy = -0.2;
Mushy.life = false;
}
else
{
Mario.sprite.setColor(sf::Color::Red);
}
}
}
if(Mario.rect.left > 200)
offsetX = Mario.rect.left - 200;
window.clear(sf::Color(107, 140, 225));
for(int i = 0; i < H; i++)
{
for(int j = 0; j < W; j++)
{
if(tileMap[i][j] == 'P')
tiles.setTextureRect(sf::IntRect(143 - 16 * 3, 112, 16, 16));
if(tileMap[i][j] == 'k')
tiles.setTextureRect(sf::IntRect(143, 112, 16, 16));
if(tileMap[i][j] == 'c')
tiles.setTextureRect(sf::IntRect(143 - 16, 112, 16, 16));
if(tileMap[i][j] == 't')
tiles.setTextureRect(sf::IntRect(0, 47, 32, 95 - 47));
if(tileMap[i][j] == 'g')
tiles.setTextureRect(sf::IntRect(0, 16 * 9 - 5, 3 * 16, 16 * 2 + 5));
if(tileMap[i][j] == 'G')
tiles.setTextureRect(sf::IntRect(145, 222, 222 - 145, 255 - 222));
if(tileMap[i][j] == 'd')
tiles.setTextureRect(sf::IntRect(0, 106, 74, 127 - 106));
if(tileMap[i][j] == 'w')
tiles.setTextureRect(sf::IntRect(99, 224, 140 - 99, 255 - 224));
if(tileMap[i][j] == 'r')
tiles.setTextureRect(sf::IntRect(143 - 32, 112, 16, 16));
if(tileMap[i][j] == '0' || tileMap[i][j] == ' ')
continue;
tiles.setPosition(sf::Vector2f(j * 16 - offsetY, i * 16 - offsetX));
window.draw(tiles);
}
}
window.draw(Mario.sprite);
//window.draw(Mushy.sprite);
window.display();
}
return 0;
}
My mario goes correctly upto some extent but then suddenly, he starts to move in the positive y-direction.
(http://puu.sh/4PXpI.png)
(http://puu.sh/4PXrp.png)
(http://puu.sh/4PXtb.png)
(http://puu.sh/4PXtQ.png)
(http://puu.sh/4PXuB.png)
(http://puu.sh/4PXvk.png)
But I can still jump and move around as if I was moving normally(I can even jump), but only the movement is actually in y-direction.
I was following code from here which I found on this forum a few days ago(this code works correctly):
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
float offsetX = 0, offsetY = 0;
const int H = 17;
const int W = 150;
sf::String TileMap[H] =
{
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"0 0",
"0 w 0",
"0 w w w 0",
"0 w kk 0",
"0 k k k k 0",
"0 c k kkk kkk w 0",
"0 r k k k 0",
"0 rr k k 0",
"0 rrr kk 0",
"0 c kckck rrrr 0",
"0 t0 rrrrr 0",
"0G 00 t0 rrrrrr G 0",
"0 d g d 00 00 rrrrrrr 0",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
};
class PLAYER
{
public:
float dx,dy;
sf::FloatRect rect;
bool onGround;
sf::Sprite sprite;
float currentFrame;
PLAYER(sf::Texture &image)
{
sprite.setTexture(image);
rect = sf::FloatRect(100, 180, 16, 16);
dx = dy = 0.1;
currentFrame = 0;
}
void update(float time)
{
rect.left += dx * time;
Collision(0);
if(!onGround)
dy = dy + 0.0005 * time;
rect.top += dy * time;
onGround = false;
Collision(1);
currentFrame += time * 0.005;
if(currentFrame > 3)
currentFrame -= 3;
if(dx > 0)
sprite.setTextureRect(sf::IntRect(112 + 31 * int(currentFrame), 144, 16, 16));
if(dx < 0)
sprite.setTextureRect(sf::IntRect(112 + 31 * int(currentFrame) + 16, 144, -16, 16));
sprite.setPosition(rect.left - offsetX, rect.top - offsetY);
dx = 0;
}
void Collision(int num)
{
for(int i = rect.top / 16; i < (rect.top + rect.height) / 16; i++)
for (int j = rect.left / 16; j < (rect.left + rect.width) / 16; j++)
{
if((TileMap[i][j] == 'P')
|| (TileMap[i][j] == 'k')
|| (TileMap[i][j] == '0')
|| (TileMap[i][j] == 'r')
|| (TileMap[i][j] == 't'))
{
if(dy > 0 && num == 1)
{
rect.top = i * 16 - rect.height;
dy = 0;
onGround = true;
}
if(dy < 0 && num == 1)
{
rect.top = i * 16 + 16;
dy = 0;
}
if(dx > 0 && num == 0)
{
rect.left = j * 16 - rect.width;
}
if(dx < 0 && num == 0)
{
rect.left = j * 16 + 16;
}
}
if(TileMap[i][j] == 'c')
{
//TileMap[i][j]=' ';
}
}
}
};
class ENEMY
{
public:
float dx,dy;
sf::FloatRect rect;
sf::Sprite sprite;
float currentFrame;
bool life;
void set(sf::Texture &image, int x, int y)
{
sprite.setTexture(image);
rect = sf::FloatRect(x, y, 16, 16);
dx = 0.05;
currentFrame = 0;
life = true;
}
void update(float time)
{
rect.left += dx * time;
Collision();
currentFrame += time * 0.005;
if(currentFrame > 2)
currentFrame -= 2;
sprite.setTextureRect(sf::IntRect(18 * int(currentFrame), 0, 16, 16));
if(!life)
sprite.setTextureRect(sf::IntRect(58, 0, 16, 16));
sprite.setPosition(rect.left - offsetX, rect.top - offsetY);
}
void Collision()
{
for (int i = rect.top / 16; i < (rect.top + rect.height) / 16; i++)
for(int j = rect.left / 16; j < (rect.left + rect.width) / 16; j++)
if((TileMap[i][j] == 'P') || (TileMap[i][j] == '0'))
{
if(dx > 0)
{
rect.left = j * 16 - rect.width;
dx *= -1;
}
else if(dx < 0)
{
rect.left = j * 16 + 16;
dx *=- 1;
}
}
}
};
int main()
{
sf::RenderWindow window(sf::VideoMode(400, 250), "Super Mario");
sf::Texture tileSet;
tileSet.loadFromFile("Mario_Tileset.png");
PLAYER Mario(tileSet);
ENEMY enemy, enemy2;
enemy.set(tileSet, 48*16, 13*16);
sf::Sprite tile(tileSet);
sf::SoundBuffer buffer;
buffer.loadFromFile("Jump.ogg");
sf::Sound sound(buffer);
sf::Music music;
music.openFromFile("Mario_Theme.ogg");
//music.play();
sf::Clock clock;
while(window.isOpen())
{
float time = clock.getElapsedTime().asMicroseconds();
clock.restart();
time = time / 500; // здесь регулируем скорость игры
if(time > 20)
time = 20;
sf::Event event;
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
window.close();
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
Mario.dx =- 0.1;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
Mario.dx = 0.1;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
if(Mario.onGround)
{
Mario.dy =- 0.27;
Mario.onGround = false;
//sound.play();
}
Mario.update(time);
enemy.update(time);
if(Mario.rect.intersects(enemy.rect))
{
if(enemy.life)
{
if(Mario.dy > 0)
{
enemy.dx = 0;
Mario.dy =- 0.2;
enemy.life = false;
}
else Mario.sprite.setColor(sf::Color::Red);
}
}
if(Mario.rect.left > 200)
offsetX = Mario.rect.left - 200; //смещение
window.clear(sf::Color(107, 140, 255));
for(int i = 0; i < H; i++)
for(int j = 0; j < W; j++)
{
if(TileMap[i][j] == 'P')
tile.setTextureRect(sf::IntRect(143 - 16 * 3, 112, 16, 16));
if(TileMap[i][j] == 'k')
tile.setTextureRect(sf::IntRect(143, 112, 16, 16));
if(TileMap[i][j] == 'c')
tile.setTextureRect(sf::IntRect(143 - 16, 112, 16, 16));
if(TileMap[i][j] == 't')
tile.setTextureRect(sf::IntRect(0, 47, 32, 95 - 47));
if(TileMap[i][j] == 'g')
tile.setTextureRect(sf::IntRect(0, 16 * 9 - 5, 3 * 16, 16 * 2 + 5));
if(TileMap[i][j] == 'G')
tile.setTextureRect(sf::IntRect(145, 222, 222 - 145, 255 - 222));
if(TileMap[i][j] == 'd')
tile.setTextureRect(sf::IntRect(0, 106, 74, 127 - 106));
if(TileMap[i][j] == 'w')
tile.setTextureRect(sf::IntRect(99, 224, 140 - 99, 255 - 224));
if(TileMap[i][j] == 'r')
tile.setTextureRect(sf::IntRect(143 - 32, 112, 16, 16));
if((TileMap[i][j] == ' ') || (TileMap[i][j] == '0'))
continue;
tile.setPosition(j * 16 - offsetX, i * 16 - offsetY);
window.draw(tile);
}
window.draw(Mario.sprite);
window.draw(enemy.sprite);
window.draw(enemy2.sprite);
window.display();
}
return 0;
}
How exactly does this collision and update functions work? And what mistakes are therein my code?
Thanks
Ok. Here's how I load my tiles:
for(int i = 0; i < H; i++)
{
for(int j = 0; j < W; j++)
{
if(tileMap[i][j] == '0')// || tileMap[i][j] == ' ')
tile_ground.setTextureRect(sf::IntRect(256, 64, 32, 32));
if(tileMap[i][j] == 'P')
tile_ground.setTextureRect(sf::IntRect(512, 0, 32, 32));
tile_ground.setPosition(j * 32, i * 32);
window.draw(tile_ground);
}
}
And here's how I do the collision checking:
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
source.y = Up;
isKeyPressed = true;
if(!heroSprite.getLocalBounds().intersects(tile_ground.getLocalBounds())) // I check if the player sprite and the obstacle intersect
heroSprite.move(0, - heroSpeed.y * deltaTime);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
source.y = Down;
isKeyPressed = true;
if(!heroSprite.getLocalBounds().intersects(tile_ground.getLocalBounds())) // I check if the player sprite and the obstacle intersect
heroSprite.move(0, heroSpeed.y * deltaTime);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
source.y = Left;
isKeyPressed = true;
if(!heroSprite.getLocalBounds().intersects(tile_ground.getLocalBounds())) // I check if the player sprite and the obstacle intersect
heroSprite.move(- heroSpeed.x * deltaTime, 0);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
source.y = Right;
isKeyPressed = true;
if(!heroSprite.getLocalBounds().intersects(tile_ground.getLocalBounds())) // I check if the player sprite and the obstacle intersect
heroSprite.move(heroSpeed.x * deltaTime, 0);
}
But my sprite is stuck in only one tile and can't move in any direction. How do I prevent this?