Sign in to follow this  
Evan Gordon

Using Views to move in sfml

Recommended Posts

Hello all.

So im still relatively new to game programming, but ive been jabbing away at sfml for a while now and ive got a basic top down Legend of Zelda style game im working on. ive got the map drawing to the screen. however im working on implementing camera movement so that the viewstate can move up down left and right. sfml has a built in view class that manages movement. but im having trouble getting it to work, the problem might be with how i structured my code for drawing to the screen, but im not sure. I've read up as much as i can on using sf::view but its really just been hard to figure out. any advice/help or links to good articles on the subject are appreciated.

 

sorry if i forget anything so just let me know if you all need any more information.

 

here is all of the relevant code (header files not included):

 

This is my globals class which'll handle most of the game logic and it contains all of the items that the game needs.

#include "globals.h"
#include <iostream>

Globals::Globals()
{
	textures[0].fileName = "overWorld.png";
	cameraPosition.x = 0;
	cameraPosition.y = 0;	
}

Globals::Globals(int mapx,int mapy, int cameraX, int cameraY)
{
	textures[0].fileName = "overWorld.png";
	gameMap.setDefaultTiles(textures[0].texture);
	cameraPosition.x = cameraX;
	cameraPosition.y = cameraY;
}

void Globals::runGame()
{
	//window and view setup
	sf::RenderWindow window(sf::VideoMode(1280, 640), "Kill It With Fire!");
	window.setFramerateLimit(60);
	window.setMouseCursorVisible(false);
	sf::View view(sf::FloatRect(0, 0, 1280, 640));
	window.setView(view);
	view.setCenter(0, 0);

	//tiles setup - map loading
	if(!textures[0].texture.loadFromFile(textures[0].fileName))
			{
			throw(42);
			}
	gameMap = Map(100, 100);
	gameMap.setDefaultTiles(textures[0].texture);
	for(int i = 0; i < 40; i++)
	{
		for(int j = 0; j < 20; j++)
		{
			if(gameMap.validTilePosition(i, j))
			{
				gameMap.setTileDefaultPosition(i, j, i*32, j*32);
			}
		}
	}

	//game loop
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
			switch(event.type)
			{
			case sf::Event::Closed:
				window.close();
				break;
			default:
				break;
			}
        }


		//check for movement keys pressed
		if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Keyboard::isKeyPressed(sf::Keyboard::W))
		{
			if(!(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Keyboard::isKeyPressed(sf::Keyboard::S)))
			{
				//move up
			}
		}
		else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Keyboard::isKeyPressed(sf::Keyboard::S))
		{
			//move down
			view.move(1.0f, 0.0f);
		}
		
		if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::A))
		{
			if(!(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Keyboard::isKeyPressed(sf::Keyboard::D)))
			{
				//move left
			}
		}
		else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Keyboard::isKeyPressed(sf::Keyboard::D))
		{
			//right
			view.move(0.0, 1.0);
		}
        window.clear();
        drawGameMap(window);
        window.display();
    }
}

void Globals::drawGameMap(sf::RenderWindow& window)
{
	//later add function for drawing map with current offset.

	//draw map third
	for(int i = 0; i < 40; i++)
	{
		for(int j = 0; j < 20; j++)
		{
			if(gameMap.validTilePosition(i, j))
			{
				window.draw(gameMap.getSprite(i, j));
			}
		}
	}
}

map.cpp

map is a 2D vector array of tile objects

#include "Map.h"
#include <string>

Map::Map()
{   
	mapLength = 50;
	mapHeight = 50;
	map.resize(50);

	for(int i = 0; i < 50; i++)
	{
		map[i].resize(50);
	}
}


//x and y are the length and width of map
Map::Map(int mapLength, int mapHeight)
{
	this->mapLength = mapLength;
	this->mapHeight = mapHeight;
	map.resize(mapLength);

	for(int i = 0; i < mapLength; i++)
	{
		map[i].resize(mapHeight);
	}


}

//this needs revisions, how and what information about a tile will this funtion know?
void Map::setTile(int mapx, int mapy, sf::Texture &texture)
{
	map[mapx][mapy] = Tile(1, false, texture);
}

//used to change the position of a tile based on the given values
void Map::setTileDefaultPosition(int x, int y, int xLocation, int yLocation)
{
	map[x][y].setSpritePosition(xLocation, yLocation);
}

void Map::setDefaultTiles(sf::Texture &texture)
{
	for(int i = 0; i < mapLength; i++)
	{
		for(int j = 0; j < mapHeight; j++)
		{
			map[i][j] = Tile(1, false, texture);
		}

	}
}

//check if given tile position is valid
//used for current drawing function
bool Map::validTilePosition(int x, int y)
{
	if(x >= 0 && y >= 0)
	{
		if(x <= mapLength && y <= mapHeight)
		{
			return true;
		}
	}
	return false;
}

//add image to all tiles function
bool Map::loadMap(sf::Texture &texture)
{
	for(int i = 0; i < mapHeight; i++)
	{
		for(int j = 0; j < mapLength; j++)
		{
			setTile(i, j, texture);
		}
	}
	return true;
}

Tile& Map::getTile(int &x, int &y)
{
	return map[x][y];//maybe the problem is here
}

sf::Sprite& Map::getSprite(int &x, int &y)
{
	return map[x][y].getSprite();//problem more than likely here
}

tile.cpp

#include "Tile.h"

#include <iostream>
#include <SFML/Graphics.hpp>

using namespace std;

    Tile::Tile()
	{
		ID = 1;
		solid = false;
		width = 32;
		height = 32;
	}
	
	Tile::Tile(int ID, bool solid, sf::Texture &texture)
	{
		this->ID = ID;
		this->solid = solid;
		try
		{			
			sprite = sf::Sprite(texture);
			sprite.setTextureRect(sf::IntRect(0, 0, 32, 32));
		}
		catch(int e)
		{
         cout<<"Error "<<e<<": "<<"Sprite ID "<<ID<<" does not exist in Tile.\n";
		}
	}

	Tile::Tile(int ID, bool solid, int width, int height, sf::Texture &texture)
	{
		this->ID = ID;
		this->solid = solid;
		this->width = width;
		this->height = height;
		try
		{
			sprite = sf::Sprite(texture);
			sprite.setTextureRect(sf::IntRect(0, 0, 32, 32));
		}
		catch(int e)
		{
         cout<<"Error "<<e<<": "<<"Sprite ID "<<ID<<" does not exist in Tile.\n";
		}

	}

	void Tile::setID(int ID)
	{
		this->ID = ID;
	}

	void Tile::setSolid(bool solid)
	{
		this->solid = solid;
	}

	void Tile::setWidth(int width)
	{
		this->width = width;
	}

	void Tile::setHeight(int height)
	{
		this->height = height;
	}

	void Tile::setSpritePosition(int x, int y)
	{
		sprite.setPosition(x, y); 
	}

	int Tile::getID()
	{
		return ID;
	}

	bool Tile::getSolid()
	{
		return solid;
	}

	int Tile::getWidth()
	{
		return width;
	}

	int Tile::getHeight()
	{
		return height;
	}

	sf::Sprite& Tile::getSprite()
	{
		return sprite;
	}
Edited by madgod_zhar

Share this post


Link to post
Share on other sites

A cursory glance looks ok to me (other than you only define how to move right and down). Could you clarify what specific problem you're having with getting it to work? I.e. is it rendering nothing at all, is the view not moving when keys are pressed, etc.

 

Edit*

From the wiki:

"When you call setView, the render-target makes a copy of the view, and doesn't store a pointer to the one that is passed. This means that whenever you update your view, you need to call setView again to apply the modifications.

Don't be afraid to copy views or create them on the fly, they aren't expensive objects (they just hold a few floats)."
 
I didn't think that was necessary when using the view.move() function, but I could be wrong. It'd be the first thing I'd check if I were running into issues of the view not moving. Unfortunately, I just reinstalled my OS and don't have sfml set up at the moment to test for you.
Edited by Misantes

Share this post


Link to post
Share on other sites
sf::View view(sf::FloatRect(0, 0, 1280, 640));
window.setView(view);
view.setCenter(0, 0);

This (and further code that just touches the local view and never calls window.setView again) is wrong.

Views worked liked that (by reference) in 1.6, but in 2.x they are copied, so if you want to change what is shown, you must get it (getView), change what you want in your local copy and then set it again.

So with this code you have now, you need to add window.setView(view); line just before drawing your map.

As for links, this is very long tutorial that was written by someone who later entered SFML team: https://github.com/LaurentGomila/SFML/wiki/Tutorial:-Using-View

Edited by FRex

Share this post


Link to post
Share on other sites

What you are also doing wrong is another common newbie mistake with SFML: you only check the event for if its a close event, then ignore all other events, then use other calls to get the current keyboard state.

You should check for key events instead, to avoid:

- your program having the move speed dependent on frame rate

- checking different keys on slightly different times and

- reacting to key presses when the window of your program is not the active one.

Edited by wintertime

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this