Добрый день. Я пишу 2D-платформы, используя sfml, крошечные XML и TiledMapEditor. Я создал персонажа, карту, столкновение и анимацию. Я пытался начать, но окно просто закрывается. Компилятор показывает 0 ошибок, я в полной растерянности, что делать. Буду очень признателен за помощь !!!:)
main. cpp file:
#include <SFML/Graphics.hpp>
#include "view.h"
#include <iostream>
#include <sstream>
#include "iostream"
#include "level.h"
#include <vector>
#include <list>
using namespace sf;
/*********************************************Р О Д И Т Е Л Ь Д Л Я Г Е Р О Я Н П С И В Р А Г О В****************************************************************************/
class Entity {
public:
std::vector<Object> obj;//вектор объектов карты
float dx, dy, x, y, speed, moveTimer;
int w, h, health;
bool life, isMove, onGround;
Texture texture;
Sprite sprite;
String name;
Entity(Image& image, String Name, float X, float Y, int W, int H) {
x = X; y = Y; w = W; h = H; name = Name; moveTimer = 0;
speed = 0; health = 100; dx = 0; dy = 0;
life = true; onGround = false; isMove = false;
texture.loadFromImage(image);
sprite.setTexture(texture);
sprite.setOrigin(w / 2, h / 2);
}
FloatRect getRect() {//ф-ция получения прямоугольника. его коорд,размеры (шир,высот).
return FloatRect(x, y, w, h);//ф-ция для проверки столкновений
}
};
/*********************************************С О З Д А Н И Е Г Л А В Н О Г О Г Е Р О Я****************************************************************************/
class Hero :public Entity
{
public:
enum { left, right, up, down, jump, stay } state;
int playerScore;
Hero(Image& image, String Name, Level& lev, float X, float Y, int W, int H) :Entity(image, Name, X, Y, W, H) {
playerScore = 0; state = stay; obj = lev.GetAllObjects();//инициализируем.получаем все объекты для взаимодействия персонажа с картой
if (name == "Player1") {
sprite.setTextureRect(IntRect(0, 0, w, h));
}
}
/******************************** У П Р А В Л Е Н И Е И А Н И М А Ц И И Г Г **********************************/
void control(float time) //управление персом
{
float currentFrame = 0;
if (Keyboard::isKeyPressed(Keyboard::Left)) {
state = left;
speed = 0.1;
currentFrame += 0.005 * time;//вывод анимации
if (currentFrame > 3)
{
currentFrame -= 3;
}
this->sprite.setTextureRect(IntRect(144 * int(currentFrame), 240, 144, 240));
}
else if (Keyboard::isKeyPressed(Keyboard::Right)) {
state = right;
speed = 0.1;
currentFrame += 0.005 * time;//вывод анимации
if (currentFrame > 3)
{
currentFrame -= 3;
}
this->sprite.setTextureRect(IntRect(144 * int(currentFrame), 480, 144, 240));
}
else if ((Keyboard::isKeyPressed(Keyboard::Up)) && (onGround)) {
state = jump; dy = -0.4; onGround = false;//то состояние равно прыжок,прыгнули и сообщили, что мы не на земле
this->sprite.setTextureRect(IntRect(144, 240, 144, 240));
}
else
{
currentFrame += 0.005 * time;//вывод анимации
if (currentFrame > 1)
{
currentFrame -= 1;
}
this->sprite.setTextureRect(IntRect(144 * int(currentFrame), 0, 144, 240));
}
}
/****************************************** С Т О Л К Н О В Е Н И Е ************************************************/
void Collision(float Dx, float Dy)
{
for (int i = 0; i < obj.size(); i++)//проходимся по объектам
{
if (getRect().intersects(obj[i].rect))//проверяем пересечение игрока с объектом
{
if (obj[i].name == "ground"|| obj[i].name == "wood"||obj[i].name == "limit")//если встретили препятствие
{
if (Dy > 0) { y = obj[i].rect.top - h; dy = 0; onGround = true; }
if (Dy < 0) { y = obj[i].rect.top + obj[i].rect.height; dy = 0; }
if (Dx > 0) { x = obj[i].rect.left - w; }
if (Dx < 0) { x = obj[i].rect.left + obj[i].rect.width; }
}
}
}
}
/*********************************** О Ж И В Л Е Н И Е П Е Р С О Н А Ж А *****************************************/
void update(float time)
{
control(time);//функция управления персонажем
switch (state)//тут делаются различные действия в зависимости от состояния
{
case right: dx = speed; break;
case left: dx = -speed; break;
case up: break;
case down: break;
case jump: break;
case stay: break;
}
x += dx * time;
Collision(dx, 0);//обрабатываем столкновение по Х
y += dy * time;
Collision(0, dy);//обрабатываем столкновение по Y
if (!isMove) speed = 0;
sprite.setPosition(x + w / 2, y + h / 2); //задаем позицию спрайта в место его центра
if (health <= 0) { life = false; }
dy = dy + 0.0015 * time;//делаем притяжение к земле
}
float getplayercoordinateX()
{
return x;
}
float getplayercoordinateY()
{
return y;
}
};
int main()
{
Clock clock;
RenderWindow window(VideoMode(1200, 720), "Look");
Image map_image;
map_image.loadFromFile("IMAGES/фон1лвл2.png");
Texture map;
map.loadFromImage(map_image);
Sprite s_map;
s_map.setTexture(map);
Image hero_image;
hero_image.loadFromFile("IMAGES/TileSetHero.png");
Level lvl;
lvl.LoadFromFile("LookMap.tmx");
Object player = lvl.GetObject("Hero");//объект игрока на нашей карте.задаем координаты игроку в начале при помощи него
Hero MainHero(hero_image, "Player1", lvl, player.rect.left, player.rect.top, 144, 240);//передаем координаты прямоугольника player из карты в координаты нашего игрока
float currentFrame = 0;
float dX = 0;
float dY = 0;
while (window.isOpen())
{
float time = clock.getElapsedTime().asMicroseconds();
clock.restart();
time = time / 800;
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::Closed)
window.close();
}
MainHero.update(time);
window.setView(view);
window.draw(s_map);
lvl.Draw(window);//рисуем новую карту
window.draw(MainHero.sprite);
window.display();
}
return 0;
}
lvl.h:
#ifndef LEVEL_H
#define LEVEL_H
#include <string>
#include <vector>
#include <map>
#include <SFML/Graphics.hpp>
#include <iostream>
#include "TinyXML/tinyxml.h"
struct Object
{
int GetPropertyInt(std::string name);//номер свойства объекта в нашем списке
float GetPropertyFloat(std::string name);//номер свойства объекта в нашем списке с точкой
std::string GetPropertyString(std::string name);//свойства
std::string name;//название
std::string type;//тип
sf::Rect<float> rect;//тип Rect с нецелыми значениями
std::map<std::string, std::string> properties;//создаём ассоциативный массив. ключ - строковый тип, значение - строковый
sf::Sprite sprite;//спрайт
};
struct Layer//слои
{
std::vector<sf::Sprite> tiles;//закидываем в вектор тайлы
};
class Level//главный класс - уровень
{
public:
bool LoadFromFile(std::string filename);//возвращает false если не получилось загрузить
Object GetObject(std::string name);
std::vector<Object> GetObjects(std::string name);//выдаем объект в наш уровень
std::vector<Object> GetAllObjects();//выдаем все объекты в наш уровень
void Draw(sf::RenderWindow& window);//рисуем в окно
sf::Vector2i GetTileSize();//получаем размер тайла
protected:
int width, height, tileWidth, tileHeight;//в tmx файле width height в начале,затем размер тайла
int firstTileID;//получаем айди первого тайла
sf::Rect<float> drawingBounds;//размер части карты которую рисуем
sf::Texture tilesetImage;//текстура карты
std::vector<Object> objects;//массив типа Объекты, который мы создали
std::vector<Layer> layers;//слои
};
///////////////////////////////////////
int Object::GetPropertyInt(std::string name)//возвращаем номер свойства в нашем списке
{
return atoi(properties[name].c_str());
}
float Object::GetPropertyFloat(std::string name)
{
return strtod(properties[name].c_str(), NULL);
}
std::string Object::GetPropertyString(std::string name)//получить имя в виде строки.вроде понятно
{
return properties[name];
}
bool Level::LoadFromFile(std::string filename)
{
TiXmlDocument levelFile(filename.c_str());//загружаем файл в TiXmlDocument
/*********************************************** З А Г Р У З К А X M L К А Р Т Ы *****************************************************/
// работаем с контейнером map
TiXmlElement* map;
map = levelFile.Child("map");
// пример карты: <map version="1.0" orientation="orthogonal"
// width="10" height="10" tilewidth="34" tileheight="34">
width = atoi(map->Attribute("width"));//извлекаем из нашей карты ее свойства
height = atoi(map->Attribute("height"));//те свойства, которые задавали при работе в
tileWidth = atoi(map->Attribute("tilewidth"));//тайлмап редакторе
tileHeight = atoi(map->Attribute("tileheight"));
// Берем описание тайлсета и идентификатор первого тайла
TiXmlElement* tilesetElement;
tilesetElement = map->Child("tileset");
firstTileID = atoi(tilesetElement->Attribute("firstgid"));
// source - путь до картинки в контейнере image
TiXmlElement* image;
image = tilesetElement->Child("image");
std::string imagepath = image->Attribute("source");
// пытаемся загрузить тайлсет
sf::Image img;
tilesetImage.loadFromImage(img);
int columns = tilesetImage.getSize().x / tileWidth;// размер тайлсета по х
int rows = tilesetImage.getSize().y / tileHeight;//по у
std::vector<sf::Rect<int>> ArrayOfRectangles;// вектор из прямоугольников изображений.Заполняем карту.
for (int y = 0; y < rows; y++)
for (int x = 0; x < columns; x++)
{
sf::Rect<int> rect;
rect.top = y * tileHeight;
rect.height = tileHeight;
rect.left = x * tileWidth;
rect.width = tileWidth;
ArrayOfRectangles.push_back(rect);
}
/*********************************************** Р А Б О Т А С О С Л О Я М И *****************************************************/
TiXmlElement* LayerEl;
LayerEl = map->Child("layer");
while (LayerEl);
{
Layer layer;
// контейнер <data>
TiXmlElement* DataOfCurrentLayer;
DataOfCurrentLayer = LayerEl->Child("data");
// контейнер <tile> - описание тайлов каждого слоя
TiXmlElement* tile;
tile = DataOfCurrentLayer->Child("tile");
int x = 0;
int y = 0;
while (tile)
{
int tileGID = atoi(tile->Attribute("gid"));
int subRectToUse = tileGID - firstTileID;
// Устанавливаем TextureRect каждого тайла
if (subRectToUse >= 0)
{
sf::Sprite sprite;
sprite.setTexture(tilesetImage);
sprite.setTextureRect(ArrayOfRectangles[subRectToUse]);
sprite.setPosition(x * tileWidth, y * tileHeight);
layer.tiles.push_back(sprite);//закидываем в слой спрайты
}
tile = tile->NextSiblingElement("tile");
x++;
if (x >= width)
{
x = 0;
y++;
if (y >= height)
y = 0;
}
}
layers.push_back(layer);//ЗАКИДЫВАЕМ В ОБЩИЙ ВЕКТОР СЛОЕВ ВСЕ СЛОИ
LayerEl = LayerEl->NextSiblingElement("layer");
}
/************************* Р А Б О Т А С О Б Ъ Е К Т А М И ***************************/
TiXmlElement* GroupOfObjects;
// если есть слои объектов
if (map->Child("objectgroup") != NULL)
{
GroupOfObjects = map->Child("objectgroup");
while (GroupOfObjects)
{
// контейнер <object>
TiXmlElement* objectElement;
objectElement = GroupOfObjects->Child("object");
while (objectElement)
{
// получаем все данные - тип, имя, позиция, и тд
std::string objectType;
if (objectElement->Attribute("type") != NULL)
{
objectType = objectElement->Attribute("type");
}
std::string objectName;
if (objectElement->Attribute("name") != NULL)
{
objectName = objectElement->Attribute("name");
}
int x = atoi(objectElement->Attribute("x"));
int y = atoi(objectElement->Attribute("y"));
int width, height;
sf::Sprite sprite;
sprite.setTexture(tilesetImage);
sprite.setTextureRect(sf::Rect<int>(0, 0, 0, 0));
sprite.setPosition(x, y);
if (objectElement->Attribute("width") != NULL)
{
width = atoi(objectElement->Attribute("width"));
height = atoi(objectElement->Attribute("height"));
}
else
{
width = ArrayOfRectangles[atoi(objectElement->Attribute("gid")) - firstTileID].width;
height = ArrayOfRectangles[atoi(objectElement->Attribute("gid")) - firstTileID].height;
sprite.setTextureRect(ArrayOfRectangles[atoi(objectElement->Attribute("gid")) - firstTileID]);
}
// экземпляр объекта
Object object;
object.name = objectName;
object.type = objectType;
object.sprite = sprite;
sf::Rect <float> objectRect;
objectRect.top = y;
objectRect.left = x;
objectRect.height = height;
objectRect.width = width;
object.rect = objectRect;
// "переменные" объекта
TiXmlElement* properties;
properties = objectElement->Child("properties");
if (properties != NULL)
{
TiXmlElement* prop;
prop = properties->Child("property");
if (prop != NULL)
{
while (prop)
{
std::string propertyName = prop->Attribute("name");
std::string propertyValue = prop->Attribute("value");
object.properties[propertyName] = propertyValue;
prop = prop->NextSiblingElement("property");
}
}
}
objects.push_back(object);
objectElement = objectElement->NextSiblingElement("object");
}
GroupOfObjects = GroupOfObjects->NextSiblingElement("objectgroup");
}
}
else{ }
return true;
}
/************************* Г Е Т Т Е Р Ы ***************************/
Object Level::GetObject(std::string name)
{
// только первый объект с заданным именем
for (int i = 0; i < objects.size(); i++)
if (objects[i].name == name)
return objects[i];
}
std::vector<Object> Level::GetObjects(std::string name)
{
// все объекты с заданным именем
std::vector<Object> vec;
for (int i = 0; i < objects.size(); i++)
if (objects[i].name == name)
vec.push_back(objects[i]);
return vec;
}
std::vector<Object> Level::GetAllObjects()
{
return objects;
};
sf::Vector2i Level::GetTileSize()
{
return sf::Vector2i(tileWidth, tileHeight);
}
/***************** О Т Р И С О В К А Т А Й Л О В *****************/
void Level::Draw(sf::RenderWindow& window)
{
// рисуем все тайлы (объекты не рисуем!)
for (int layer = 0; layer < layers.size(); layer++)
for (int tile = 0; tile < layers[layer].tiles.size(); tile++)
window.draw(layers[layer].tiles[tile]);
}
#endif
и просмотр .h:
#include <SFML/Graphics.hpp>
using namespace sf;
sf::View view;
void setPlayerCoordinateForView(float x, float y) {
float tempX = x; float tempY = y;
if (y > 5664) tempY = 5664;
view.setCenter(tempX, tempY);
}