Skip to main content
gamedev.net
🔒 Locked

Problem with tile map editor

Started by FantasyVI Dec 18, 2011 at 7:59 PM 5 replies 1.9k views
Original Post
FantasyVI
FantasyVI
Hello everyone

I have been working on a tile map editor and i have a small problem.

I have 6 buttons on my screen where you can choose what tile you want to draw. You click on the button and press on the screen to start drawing.

now the problem is when you click on grass tile and draw then click on ice tile, all the grass tiles turns into grass. what should happen is when you click on ice you draw ice and when you click on grass you draw grass not change the existing tile.

here is a video to explain my problem more.
BTW sorry i was listing to that song when i recorded and forgot to disable the sound .



Map.cpp

#include "Map.h"
#include "UI.h"

UI UI1;

Map::Map(float x, float y)
{
Delete=false;
Position = sf::Vector2f(x,y);

TileImage[0].LoadFromFile("Data/Tiles/Grass.png");
TileImage[1].LoadFromFile("Data/Tiles/Grass2.png");
TileImage[2].LoadFromFile("Data/Tiles/Dirt.png");
TileImage[3].LoadFromFile("Data/Tiles/Desert.png");
TileImage[4].LoadFromFile("Data/Tiles/Stone.png");
TileImage[5].LoadFromFile("Data/Tiles/Ice.png");
TileImage[6].LoadFromFile("Data/Tiles/Water.png");

TileSprite[0].SetImage(TileImage[0]);
TileSprite[1].SetImage(TileImage[1]);
TileSprite[2].SetImage(TileImage[2]);
TileSprite[3].SetImage(TileImage[3]);
TileSprite[4].SetImage(TileImage[4]);
TileSprite[5].SetImage(TileImage[5]);
TileSprite[6].SetImage(TileImage[6]);

TileImage[0].SetSmooth(false);
TileImage[1].SetSmooth(false);
TileImage[2].SetSmooth(false);
TileImage[3].SetSmooth(false);
TileImage[4].SetSmooth(false);
TileImage[5].SetSmooth(false);
TileImage[6].SetSmooth(false);
}

Map::~Map(void)
{
}

void Map::Init(sf::RenderWindow &Window)
{
MouseX = Window.GetInput().GetMouseX();
MouseY = Window.GetInput().GetMouseY();
}

void Map::AddTile()
{
TowerVector.push_back(new Map(MouseX, MouseY));
}

void Map::Event(sf::Event Event)
{
if(Event.Type == sf::Event::MouseButtonPressed && Event.MouseButton.Button == sf::Mouse::Left)
AddTile();

if(Event.Type == sf::Event::KeyPressed && Event.Key.Code== sf::Key:<img src='http://public.gamedev.net/public/style_emoticons/<#EMO_DIR#>/biggrin.gif' class='bbc_emoticon' alt=':D' />)
Delete=true;
}

void Map::Draw(sf::RenderWindow &Window)
{
for(int x=4; x<28; x++)
for(int y=4; y<20; y++)
map[y][x] = 0;

for(int i = 0; i <TowerVector.size(); i++)
{
int X = TowerVector->Position.x / 32;
int Y = TowerVector->Position.y / 32;

map[Y][X] = 1;

for(int x=4; x<28; x++)
{
for(int y=4; y<20; y++)
{
if(X == x && Y == y)
{
if(UI1.GetTileID() == 0)
TileSprite[0].SetPosition(X*32, Y*32);

if(UI1.GetTileID() == 1)
TileSprite[1].SetPosition(X*32, Y*32);

if(UI1.GetTileID() == 2)
TileSprite[2].SetPosition(X*32, Y*32);

if(UI1.GetTileID() == 3)
TileSprite[3].SetPosition(X*32, Y*32);

if(UI1.GetTileID() == 4)
TileSprite[4].SetPosition(X*32, Y*32);

if(UI1.GetTileID() == 5)
TileSprite[5].SetPosition(X*32, Y*32);

if(UI1.GetTileID() == 6)
TileSprite[6].SetPosition(X*32, Y*32);
}
}
}

if(Delete==true)
{
TowerVector.erase(TowerVector.end() - 1);
}
Delete=false;

for(int i=0; i<6; i++)
Window.Draw(TileSprite);
}
}




UI.CPP

int UI::GetTileID()
{
if(Tiles[0].Clicked == true)
TileID = 0;

if(Tiles[1].Clicked == true)
TileID = 1;

if(Tiles[2].Clicked == true)
TileID = 2;

if(Tiles[3].Clicked == true)
TileID = 3;

if(Tiles[4].Clicked == true)
TileID = 4;

if(Tiles[5].Clicked == true)
TileID = 5;

if(Tiles[6].Clicked == true)
TileID = 6;

return TileID;
}


Main.cpp


#include <SFML/Graphics.hpp>
#include <iostream>
#include "Map.h"
#include "UI.h"

int main()
{
sf::RenderWindow Window (sf::VideoMode(1024, 768, 32),"vovo");
Map Map(0,0);
UI UI;

UI.LoadFiles();
while(Window.IsOpened())
{
Window.SetFramerateLimit(60);
sf::Event Event;
Map.Init(Window);

while(Window.GetEvent(Event))
{
Map.Event(Event);
UI.Event(Event);
}

Window.Clear();
Map.Draw(Window);
Map.DrawLines(Window);
UI.Draw(Window);
Window.Display();
}
return 0;
}
FantasyVI
FantasyVI
anyone please ...
Eigen
Eigen
When drawing the map, you don't check what the tile is at each position, but use a global type for each. Hence, they are all the same. Also, you are looping the the whole map for each object. You don't need that. Just get the position of the object and draw.
FantasyVI
FantasyVI

When drawing the map, you don't check what the tile is at each position, but use a global type for each. Hence, they are all the same. Also, you are looping the the whole map for each object. You don't need that. Just get the position of the object and draw.


ok my question is how can i get each tile position ?
sorry but I'm an absolute newbie.
kauna
kauna
Hi,

A bit of non-constructive criticism : your tile drawing logic is rather strange. Your tile map structure is also rather strange.

Anyhow, to make a fix to it, I think that you'll need to change your structures:

Some pseudo-code. The code doesn't work without changes. It is just to give you idea how to store a simple tile map to your computer's memory and how to draw it simply.



class Tile
{
public:
int TileID;

Tile()
{
TileID = 0;
}
}

class Map
{
public:
std::vector<Tile> TileMap;

float MapOffsetX,MapOffsetY;

void InitMap()
{
TileMapSizeX =24;
TileMapSizeY=16;

TileMap.resize(TileMapSizeX * TileMapSizeY);

MapOffsetX = 4 * 32; //offset to make a gap between sides of the screen (as on your example)
MapOffsetY = 4 * 32;

//Init your textures here

//Init your sprites here
}


void DrawMap()
{
for(int i=0;i<TileMap.size();++i)
{
int PosX = i % TileMapSizeX;
int PosY = i / TileMapSizeX;

TileSprite[TileMap.TileID].SetPosition(PosX * 32 + MapOffsetX, PosY * 32 + MapOffsetY);

Window.Draw(TileSprite[TileMap);
}

void ChangeTile(int MouseX,int MouseY,int TileID)
{

MouseX -= MapOffsetX;
MouseY -= MapOffsetY;

MouseX /= 32;
MouseY /= 32;

if(MouseX>= 0 && MouseX<TileMapSizeX && MouseY>= 0 && MouseY<TileMapSizeY)
{
TileMap.TileID = TileID;
}

}
};



Best regards!
FantasyVI
FantasyVI

Hi,

A bit of non-constructive criticism : your tile drawing logic is rather strange. Your tile map structure is also rather strange.

Anyhow, to make a fix to it, I think that you'll need to change your structures:

Some pseudo-code. The code doesn't work without changes. It is just to give you idea how to store a simple tile map to your computer's memory and how to draw it simply.



class Tile
{
public:
int TileID;

Tile()
{
TileID = 0;
}
}

class Map
{
public:
std::vector<Tile> TileMap;

float MapOffsetX,MapOffsetY;

void InitMap()
{
TileMapSizeX =24;
TileMapSizeY=16;

TileMap.resize(TileMapSizeX * TileMapSizeY);

MapOffsetX = 4 * 32; //offset to make a gap between sides of the screen (as on your example)
MapOffsetY = 4 * 32;

//Init your textures here

//Init your sprites here
}


void DrawMap()
{
for(int i=0;i<TileMap.size();++i)
{
int PosX = i % TileMapSizeX;
int PosY = i / TileMapSizeX;

TileSprite[TileMap.TileID].SetPosition(PosX * 32 + MapOffsetX, PosY * 32 + MapOffsetY);

Window.Draw(TileSprite[TileMap);
}

void ChangeTile(int MouseX,int MouseY,int TileID)
{

MouseX -= MapOffsetX;
MouseY -= MapOffsetY;

MouseX /= 32;
MouseY /= 32;

if(MouseX>= 0 && MouseX<TileMapSizeX && MouseY>= 0 && MouseY<TileMapSizeY)
{
TileMap.TileID = TileID;
}

}
};



Best regards!


thank you very much now the code is working.
now I know that the code is very bad written but I just wanted the code to work then back it up and then start cleaning it and fixing it.
here is the full code if anyone is interested in making a map editor in sfml.

thank you again

Map.h

//This Code is verion 3 -- 22/12/2011.
#pragma once
#include <SFML\Graphics.hpp>
#include <SFML\Audio.hpp>
#include <iostream>
#include <string>
#include <fstream>

class Map
{
public:
Map(float x, float y);
~Map(void);
void Init(sf::RenderWindow &Window);
void Event(sf::Event Event);
void AddTile();
void WriteData();
void DrawLines(sf::RenderWindow &Window);
void Draw(sf::RenderWindow &Window);

private:
sf::Vector2f Position;
std::vector<Map*> TowerVector;
std::vector<int> TileID;

int ID;
float MouseX, MouseY;
bool Delete;
sf::Image TileImage[10];
sf::Sprite TileSprite[10];

int map[25][25];
int X, Y;

float MapSizeX, MapSizeY, MapOffsetX, MapOffsetY;
};



map.cpp

#include "Map.h"
#include "UI.h"

UI UI1; // GUI if button click do something

Map::Map(float x, float y)
{
Delete=false;
Position = sf::Vector2f(x,y);

TileImage[0].LoadFromFile("Data/Tiles/Grass.png");
TileImage[1].LoadFromFile("Data/Tiles/Grass2.png");
TileImage[2].LoadFromFile("Data/Tiles/Dirt.png");
TileImage[3].LoadFromFile("Data/Tiles/Desert.png");
TileImage[4].LoadFromFile("Data/Tiles/Stone.png");
TileImage[5].LoadFromFile("Data/Tiles/Ice.png");
TileImage[6].LoadFromFile("Data/Tiles/Water.png");

TileSprite[0].SetImage(TileImage[0]);
TileSprite[1].SetImage(TileImage[1]);
TileSprite[2].SetImage(TileImage[2]);
TileSprite[3].SetImage(TileImage[3]);
TileSprite[4].SetImage(TileImage[4]);
TileSprite[5].SetImage(TileImage[5]);
TileSprite[6].SetImage(TileImage[6]);

TileImage[0].SetSmooth(false);
TileImage[1].SetSmooth(false);
TileImage[2].SetSmooth(false);
TileImage[3].SetSmooth(false);
TileImage[4].SetSmooth(false);
TileImage[5].SetSmooth(false);
TileImage[6].SetSmooth(false);
}

Map::~Map(void)
{
}

void Map::Init(sf::RenderWindow &Window)
{
MouseX = Window.GetInput().GetMouseX();
MouseY = Window.GetInput().GetMouseY();
ID = UI1.GetTileID(); //if button click get Tile ID
}

void Map::AddTile()
{

TowerVector.push_back(new Map(MouseX, MouseY));
TileID.push_back(UI1.GetTileID());

for(int i = 0; i< TileID.size(); i++)
std::cout<<TileID;
}

void Map::Event(sf::Event Event)
{
if(Event.Type == sf::Event::MouseButtonPressed && Event.MouseButton.Button == sf::Mouse::Left)
AddTile();


if(Event.Type == sf::Event::KeyPressed && Event.Key.Code== sf::Key:<img src='http://public.gamedev.net/public/style_emoticons/<#EMO_DIR#>/biggrin.gif' class='bbc_emoticon' alt=':D' />)
Delete=true;
}

void Map::WriteData()
{
std::ofstream WriteFile("Map.Data");
if(WriteFile.is_open())
{
for(int x=4; x<28; x++)
{
for(int y=4; y<20; y++)
{
WriteFile << map[y][x] << " ";
}
WriteFile << "\n";
}
WriteFile.close();
}
else
std::cout<<"Unable to open file";
}

void Map::DrawLines(sf::RenderWindow &Window)
{
for(int X=128; X<672; X+=32)
{
sf::Shape LineX = sf::Shape::Line(128, X, 896, X, 1, sf::Color(255, 0, 0));
Window.Draw(LineX);
}

for(int Y=128; Y<928; Y+=32)
{
sf::Shape LineY = sf::Shape::Line(Y, 128, Y, 640, 1, sf::Color(255, 0, 0));
Window.Draw(LineY);
}
}

void Map::Draw(sf::RenderWindow &Window)
{
for(int x=4; x<28; x++)
for(int y=4; y<20; y++)
map[y][x] = 0;

for(int i = 0; i <TowerVector.size(); i++)
{
int X = TowerVector->Position.x / 32;
int Y = TowerVector->Position.y / 32;

map[Y][X] = 1;

for(int x=4; x<28; x++)
{
for(int y=4; y<20; y++)
{
if(X == x && Y == y)
{
TileSprite[TileID].SetPosition(X*32, Y*32);
}
}
}
for(int i=0; i<6; i++)
Window.Draw(TileSprite);
}
}
kauna
kauna
Hi,

I'm happy to hear that you have been able to advance in your project.

Anyway, I'd take another look in my code sample.

For example, your drawing code has a loop which iterates 384 * TowerVector.size() times. This gets slow in long run.
You draw also your GUI tiles 6 * TowerVector.size() times.

I suggest you to reserve a constant size vector (see the TileMap.resize() in my example). This way every tile has a known position and drawing is much simpler.

When adding a new tile you always create a new Map object, which sounds counter-intuitive. I figure that you store a position in your map structure, but I feel that it doesn't really belong there. In my example, you may also add any information to the Tile structure, which makes the system easily expandable.

Cheers!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.