- •Содержание.
- •Введение.
- •Теоретическая часть.
- •2.1. Основные этапы развития компьютерных игр.
- •2.2. Виды компьютерных игр.
- •2.3. Выбор средств и среды для разработки.
- •Основные логические концепции приложения.
- •3.2. Интерфейс приложения.
- •3. Практическая часть.
- •3.1. Структура программы и ее реализация.
- •3.3. Руководство пользователя.
- •Заключение.
- •5. Приложения.
- •Полный код программы.
- •Дополнительные скриншоты приложения.
- •6.Список источников.
Заключение.
В ходе проделанной работы было создано простейшее игровое 2D приложение. Главная цель курсового проекта и задачи, поставленные изначально, были успешно выполнены. Проект можно назвать полноценным игровым приложением, которое имеет дальнейшие перспективы усовершенствования. Основные перспективы:
Возможность пользователя отключать звук во время игры.
Наличие нескольких уровней.
Возможность пользователя вводить свое имя перед началом игры.
Возможность пользователя сравнивать свой результат с результатами предыдущих прохождений.
Доработка графической составляющей (усовершенствование графики).
Возможность пользователя выбирать внешний вид персонажа, карту для прохождения и уровень сложности.
Добавление сюжетной канвы.
Нелинейность уровней.
Скелетная анимация.
Подключение мыши.
5. Приложения.
Полный код программы.
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <iostream>
#include <vector>
#include <list>
#include "string.h"
#include <stdio.h>
#include <sstream>//преобразование int в string
#include <string>
#include <windows.h>
#include "level.hpp"
#include "anim.hpp"
using namespace sf;
bool ingame=0,newgame=1,reit=0,esc=0,reite=0;
std::string ress,ress2,winn;
int res=0,reset,buf=100,win=100;
static inline std::string int2Str(int x)
{
std::stringstream type;
type << x;
return type.str();
}
class Entity
{
public:
float x,y,dx,dy,w,h;
AnimationManager anim;
std::vector<Object> obj;
bool life, dir;
float timer, timer_end;
String Name;
int Health;
Entity(AnimationManager &A,int X, int Y)
{
anim = A;
x = X;
y = Y;
dir = 0;
life=true;
timer=0;
timer_end=0;
dx=dy=0;
}
virtual void update(float time) = 0;
void draw(RenderWindow &window)
{
anim.draw(window,x,y+h);
}
FloatRect getRect()
{
return FloatRect(x,y,w,h);
}
void option(String NAME, float SPEED=0, int HEALTH=10, String FIRST_ANIM="")
{
Name = NAME;
if (FIRST_ANIM!="") anim.set(FIRST_ANIM);
w = anim.getW();
h = anim.getH();
dx = SPEED;
Health = HEALTH;
}
};
class Bullet:public Entity
{
public:
Bullet(AnimationManager &a, Level &lev,int x,int y,bool dir):Entity(a,x,y)
{
option("Bullet", 0.3, 10, "move");
if (dir) dx=-0.3;
obj = lev.GetObjects("solid");
}
void update(float time)
{
x+=dx*time;
for (int i=0;i<obj.size();i++)
if (getRect().intersects(obj[i].rect))
{Health=0;}
if (Health<=0) {anim.set("explode");dx=0;
if (anim.isPlaying()==false) life=false;
}
anim.tick(time);
}
};
class PLAYER: public Entity
{
public:
enum {stay,walk,duck,jump,climb,swim} STATE;
bool onLadder, shoot, hit;
std::map<std::string,bool> key;
PLAYER(AnimationManager &a, Level &lev,int x,int y):Entity(a,x,y)
{
option("Player",0,100,"stay");
STATE=stay; hit=0;
obj = lev.GetAllObjects();
}
void KeyCheck()
{
if (key["L"])
{
dir=1;
if (STATE!=duck) dx=-0.1;
if (STATE==stay) STATE=walk;
}
if (key["R"])
{
dir=0;
if (STATE!=duck) dx=0.1;
if (STATE==stay) STATE=walk;
}
if (key["Up"])
{
if (onLadder) STATE=climb;
if (STATE==stay || STATE==walk) { dy=-0.27; STATE=jump; anim.play("jump");}
if (STATE==swim || STATE==climb) dy=-0.05;
}
if (key["Down"])
{
if (STATE==stay || STATE==walk) { STATE=duck; dx=0;}
if (STATE==swim || STATE==climb) dy=0.05;
}
if (key["Space"])
{
shoot=true;
}
/////////////////////если клавиша отпущена///////////////////////////
if (!(key["R"] || key["L"]))
{
dx=0;
if (STATE==walk) STATE=stay;
}
if (!(key["Up"] || key["Down"]))
{
if (STATE==swim || STATE==climb) dy=0;
}
if (!key["Down"])
{
if (STATE==duck) { STATE=stay;}
}
if (!key["Space"])
{
shoot=false;
}
}
void update(float time)
{
KeyCheck();
if (STATE==stay) anim.set("stay");
if (STATE==walk) anim.set("walk");
if (STATE==jump) anim.set("jump");
if (STATE==duck) anim.set("duck");
if (STATE==climb) {anim.set("climb"); anim.pause(); if (dy!=0) anim.play(); if (!onLadder) STATE=stay;}
if (shoot) { anim.set("shoot");
if (STATE==walk) anim.set("shootAndWalk");}
if (hit) { timer+=time;
if (timer>1000) {hit=false; timer=0;}
anim.set("hit");}
if (dir) anim.flip();
x += dx * time;
Collision(0);
if (STATE!=climb) dy+=0.0005*time;
y += dy*time; onLadder=false;
Collision(1);
anim.tick(time);
key["R"]=key["L"]=key["Up"]=key["Down"]=key["Space"]=false;
}
void Collision(int num)
{
for (int i=0;i<obj.size();i++)
if (getRect().intersects(obj[i].rect))
{ if(obj[i].name=="do")
{
}
if(obj[i].name=="trap")
{
hit=1;
Health-=1;
}
if (obj[i].name=="solid")
{
if (dy>0 && num==1) { y = obj[i].rect.top - h; dy=0; STATE=stay;}
if (dy<0 && num==1) { y = obj[i].rect.top + obj[i].rect.height ; dy=0;}
if (dx>0 && num==0) { x = obj[i].rect.left - w; }
if (dx<0 && num==0) { x = obj[i].rect.left + obj[i].rect.width ;}
}
if (obj[i].name=="ladder") { onLadder=true; }
if (obj[i].name=="SlopeLeft")
{ FloatRect r = obj[i].rect;
int y0 = (x+w/2-r.left) * r.height/r.width+ r.top - h;
if (y>y0)
if (x+w/2>r.left)
{y = y0; dy=0; STATE=stay;}
}
if (obj[i].name=="SlopeRight")
{ FloatRect r = obj[i].rect;
int y0 = - (x+w/2-r.left) * r.height/r.width + r.top+r.height - h;
if (y > y0)
if (x+w/2<r.left+r.width)
{y = y0 ; dy=0; STATE=stay;}
}
}
}
};
class ENEMY: public Entity
{
public:
ENEMY(AnimationManager &a, Level &lev,int x,int y):Entity(a,x,y)
{
option("Enemy", 0.01, 15, "move");
}
void update(float time)
{
x += dx * time;
timer+=time;
if (timer>3200) {dx*=-1;timer=0;}
if (Health<=0) {anim.set("dead"); dx=0;
timer_end+=time;
if (timer_end>4000) life=false;
}
anim.tick(time);
}
};
class COIN: public Entity
{
public:
COIN(AnimationManager &a, Level &lev,int x,int y):Entity(a,x,y)
{
option("Coin", 0, 1, "move");
}
void update(float time)
{
x += dx * time;
timer+=time;
if (timer>3200) {dx*=-1;timer=0;}
if (Health<=0) {anim.set("dead"); dx=0;
timer_end+=time;
if (timer_end>4000) life=false;
}
anim.tick(time);
}
};
class MovingPlatform: public Entity
{
public:
MovingPlatform(AnimationManager &a, Level &lev,int x,int y):Entity(a,x,y)
{
option("MovingPlatform", 0.05, 0, "move");
}
void update(float time)
{
x += dx * time;
timer+=time;
if (timer>6000) {dx*=-1;timer=0;}
anim.tick(time);
}
};
int main()
{
Music music,jump,shoot,hit,enter,change;
jump.openFromFile("files/jump.wav");
shoot.openFromFile("files/shoot.wav");
music.openFromFile("files/main.wav");
hit.openFromFile("files/hit.wav");
enter.openFromFile("files/enter.wav");
change.openFromFile("files/change.wav");
Text text,//новая игра
text2,//результаты
text3,//выход
text4,//очки на экран
text5,//гейм овер
text6,//жизнь на экран
text7,//жизнь
text8,//about
text9,//win
text10,// /
text11,//управление
text12;//about выбрано
Font font;
font.loadFromFile("sansation.ttf");
text.setFont(font);
text.setString("New Game");
text.setCharacterSize(24);
text2.setFont(font);
text2.setString("Coin:");
text2.setCharacterSize(24);
text3.setFont(font);
text3.setString("Exit");
text3.setCharacterSize(24);
text4.setFont(font);
text4.setCharacterSize(24);
text5.setFont(font);
text5.setString("Game");
text5.setCharacterSize(24);
text6.setFont(font);
text6.setCharacterSize(24);
text7.setFont(font);
text7.setCharacterSize(24);
text7.setString("Health:");
text8.setFont(font);
text8.setCharacterSize(24);
text8.setString("About");
text9.setFont(font);
text9.setCharacterSize(24);
text10.setFont(font);
text10.setCharacterSize(24);
text10.setString("/");
text11.setFont(font);
text11.setCharacterSize(24);
text11.setString("Press [E] to select\nUse [W][A][S][D] to move\nPress [space] to shoot\nPress [Esc] to return to menu");
text12.setFont(font);
text12.setCharacterSize(24);
text12.setString("Was created by Antonova Evgenia\n Mashukow Nikolay");
///////////// инициализация ///////////////////////////
RenderWindow window(VideoMode(1280, 720), "My Game");
Style::None;
pro1:
View view( FloatRect(0, 0, 1280, 720) );
Level lvl;
lvl.LoadFromFile("level.tmx");
Texture tileSet, moveplatform, megaman, fang,coinn,menu,pict;
Sprite menuspr,pictspr;
menu.loadFromFile("files/menu.png");
menuspr.setTexture(menu);
menuspr.setTextureRect(IntRect(0,0,1280,720));
pict.loadFromFile("files/ingame.png");
pictspr.setTexture(pict);
pictspr.setTextureRect(IntRect(0,0,1280,720));
tileSet.loadFromFile("files/enemy.png");
moveplatform.loadFromFile("files/movingPlatform.png");
megaman.loadFromFile("files//megaman.png");
fang.loadFromFile("files/bullet.png");
coinn.loadFromFile("files/coin.png");
AnimationManager anim;
anim.loadFromXML("files/megaman_anim.xml",megaman);
anim.animList["jump"].loop = 0;
AnimationManager anim2;
anim2.create("move",fang,16,0,16,4,1,0);
anim2.create("explode",fang,6,0,16,16,4,0.01,29,false);
AnimationManager anim3;
anim3.create("move",tileSet,0,0,32,32,2,0.002,32);
anim3.create("dead",tileSet,64,0,32,32,2,0.0005,32);
AnimationManager anim4;
anim4.create("move",moveplatform,0,0,95,22,1,0);
AnimationManager anim5;
anim5.create("move",coinn,0,0,32,32,2,0.002,32);
anim5.create("dead",coinn,64,0,32,32,2,0.0005,32);
std::list<Entity*> entities;
std::list<Entity*>::iterator it;
std::vector<Object> e;
e= lvl.GetObjects("enemy");
for (int i=0;i < e.size();i++)
entities.push_back(new ENEMY(anim3, lvl, e[i].rect.left, e[i].rect.top) );
e = lvl.GetObjects("MovingPlatform");
for (int i=0;i < e.size();i++)
entities.push_back(new MovingPlatform(anim4, lvl, e[i].rect.left, e[i].rect.top) );
e = lvl.GetObjects("Coin");
for (int i=0;i < e.size();i++)
entities.push_back(new COIN(anim5, lvl, e[i].rect.left, e[i].rect.top) );
win=e.size();
Object pl = lvl.GetObject("player");
PLAYER player1(anim, lvl, pl.rect.left, pl.rect.top);
music.play();
Clock clock;
Clock musicc;
/////////////////// основной цикл /////////////////////
while (window.isOpen())
{
ress=int2Str(res);
winn=int2Str(win);
ress2=int2Str(player1.Health);
text4.setString(ress);
text6.setString(ress2);
text9.setString(winn);
float time = clock.getElapsedTime().asMicroseconds();
float musiccc=musicc.getElapsedTime().asSeconds();
clock.restart();
time = time/600;
if (time > 400) time = 400;
if(musiccc>=10)
{
music.play();
musicc.restart();
}
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::Closed)
window.close();
if(ingame==0)
{
if (event.type == Event::KeyPressed)
if (event.key.code==Keyboard::Escape)
window.close();
if(newgame==1)
{
if (event.type == Event::KeyPressed)
if (event.key.code==Keyboard::E)
{ enter.play();
res=0;
ingame=1;
reset=0;
text5.setCharacterSize(24);
}
}
if(esc)
{
if (event.type == Event::KeyPressed)
if (event.key.code==Keyboard::E)
{
window.close();
enter.play();
}
}
}
if (event.type == Event::KeyPressed)
if (event.key.code==Keyboard::Space)
{entities.push_back(new Bullet(anim2,lvl,player1.x+18,player1.y+18,player1.dir) ); shoot.play(); }
}
if(ingame==1)
{
if (Keyboard::isKeyPressed(Keyboard::A)) player1.key["L"]=true;
if (Keyboard::isKeyPressed(Keyboard::D)) player1.key["R"]=true;
if (Keyboard::isKeyPressed(Keyboard::W)){ player1.key["Up"]=true;if(!player1.onLadder) jump.play();}
if (Keyboard::isKeyPressed(Keyboard::S)) player1.key["Down"]=true;
if (Keyboard::isKeyPressed(Keyboard::Escape))
{ enter.play();
ingame=0;
newgame=1;
text5.setString("Game");
text5.setColor(Color::White);
reset=1;
goto pro1;
}
}
if(ingame==0)
{
if(newgame==1)
{
text.setColor(Color::Green);
text8.setColor(Color::White);
text3.setColor(Color::White);
if (Keyboard::isKeyPressed(Keyboard::D))
{ change.play();
newgame=0;
reite=0;
esc=0;
reit=1;
ingame=0;
}
if (Keyboard::isKeyPressed(Keyboard::S))
{ change.play();
reite=0;
esc=1;
reit=0;
ingame=0;
}
}
if(reit==1)
{
text.setColor(Color::White);
text8.setColor(Color::Green);
text3.setColor(Color::White);
if (Keyboard::isKeyPressed(Keyboard::S))
{change.play();
reit=0;
reite=0;
esc=1;
newgame=0;
ingame=0;
}
if (Keyboard::isKeyPressed(Keyboard::A))
{ change.play();
reit=0;
reite=0;
esc=0;
ingame=0;
newgame=1;
}
if (Keyboard::isKeyPressed(Keyboard::E))
{enter.play();
reite=1;
}
}
if(esc)
{
newgame=0;
reit=0;
text8.setColor(Color::White);
text.setColor(Color::White);
text3.setColor(Color::Green);
if (Keyboard::isKeyPressed(Keyboard::W))
{change.play();
reite=0;
reit=0;
newgame=1;
esc=0;
}
}
}
for(it=entities.begin();it!=entities.end();)
{
Entity *b = *it;
b->update(time);
if (b->life==false) { it = entities.erase(it); delete b;}
else it++;
}
player1.update(time);
if(buf!=player1.Health)
{
buf=player1.Health;
hit.play();
}
if(player1.Health<=0)
{
text5.setString("Game over");
text5.setColor(Color::Red);
text5.setCharacterSize(50);
player1.Health=10;
ingame=0;
newgame=1;
reset=1;
buf=100;
goto pro1;
}
if(newgame)
{
text.setCharacterSize(32);
text8.setCharacterSize(24);
text3.setCharacterSize(24);
}
if(reit)
{
text.setCharacterSize(24);
text8.setCharacterSize(32);
text3.setCharacterSize(24);
}
if(esc)
{
text.setCharacterSize(24);
text8.setCharacterSize(24);
text3.setCharacterSize(32);
}
if(player1.Health>0&&ingame==1)
{
text5.setString("Game");
text5.setColor(Color::Green);
}
menuspr.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2, window.getView().getCenter().y - window.getView().getSize().y/2);
pictspr.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2, window.getView().getCenter().y - window.getView().getSize().y/2);
text.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 100-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 100);
text8.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 280-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 100);
text3.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 100-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 140);
text2.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 100-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 180);
text4.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 180-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 180);
text5.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 100-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 220);
text6.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 180-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 260);
text7.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 100-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 260);
text9.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 210-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 180);
text10.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 200-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 180);
text11.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 100-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 380);
text12.setPosition( window.getView().getCenter().x - window.getView().getSize().x/2 + 280-53, window.getView().getCenter().y - window.getView().getSize().y/2 + 140);
for(it=entities.begin();it!=entities.end();it++)
{
if ((*it)->Name=="Enemy")
{
Entity *enemy = *it;
if (enemy->Health<=0) continue;
if (player1.getRect().intersects( enemy->getRect() ))
if (player1.dy>0) { enemy->dx=0; player1.dy=-0.2; enemy->Health=0;}
else if (!player1.hit) { player1.Health-=5; player1.hit=true;
if (player1.dir) player1.x+=10; else player1.x-=10;}
for (std::list<Entity*>::iterator it2=entities.begin(); it2!=entities.end(); it2++)
{
Entity *bullet = *it2;
if (bullet->Name=="Bullet")
if ( bullet->Health>0)
if (bullet->getRect().intersects( enemy->getRect() ) )
{ bullet->Health=0; enemy->Health-=5;}
}
}
if ((*it)->Name=="MovingPlatform")
{
Entity *movPlat = *it;
if (player1.getRect().intersects( movPlat->getRect() ) )
if (player1.dy>0)
if (player1.y+player1.h<movPlat->y+movPlat->h)
{player1.y=movPlat->y - player1.h + 3; player1.x+=movPlat->dx*time; player1.dy=0; player1.STATE=PLAYER::stay;}
}
if ((*it)->Name=="Coin")
{
Entity *coin = *it;
if (player1.getRect().intersects( coin->getRect() ) )
{
if(coin->Health!=0)
res++;
coin->Health=0;
if(win==res)
{
text5.setString("Victory!");
text5.setColor(Color::Blue);
text5.setCharacterSize(50);
ingame=0;
newgame=1;
esc=0;
reit=0;
goto pro1;
}
}
}
/*рисуем*/
view.setCenter( player1.x,player1.y);
window.setView(view);
window.clear(Color(107,140,255));
}
if(ingame==0)
{
window.draw(menuspr);
window.draw(text);
window.draw(text2);
window.draw(text3);
window.draw(text4);
window.draw(text5);
window.draw(text8);
window.draw(text9);
window.draw(text10);
window.draw(text11);
if(reite)
window.draw(text12);
}
if(ingame)
{
window.draw(pictspr);
lvl.Draw(window);
for(it=entities.begin();it!=entities.end();it++)
(*it)->draw(window);
player1.draw(window);
window.draw(text2);
window.draw(text4);
window.draw(text5);
window.draw(text6);
window.draw(text7);
window.draw(text9);
window.draw(text10);
}
window.display();
}
return 0;
}
#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;
std::map<std::string, std::string> properties;
sf::Sprite sprite;
};
struct Layer
{
int opacity;
std::vector<sf::Sprite> tiles;
};
class Level
{
public:
bool LoadFromFile(std::string filename);
Object GetObject(std::string name);
std::vector<Object> GetObjects(std::string name);
std::vector<Object> GetAllObjects();
void Draw(sf::RenderWindow &window);
sf::Vector2i GetTileSize();
private:
int width, height, tileWidth, tileHeight;
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());
// Загружаем XML-карту
if(!levelFile.LoadFile())
{
std::cout << "Loading level \"" << filename << "\" failed." << std::endl;
return false;
}
// Работаем с контейнером map
TiXmlElement *map;
map = levelFile.FirstChildElement("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->FirstChildElement("tileset");
firstTileID = atoi(tilesetElement->Attribute("firstgid"));
// source - путь до картинки в контейнере image
TiXmlElement *image;
image = tilesetElement->FirstChildElement("image");
std::string imagepath = image->Attribute("source");
// Пытаемся загрузить тайлсет
sf::Image img;
if(!img.loadFromFile(imagepath))
{
std::cout << "Failed to load tile sheet." << std::endl;
return false;
}
img.createMaskFromColor(sf::Color(255, 255, 255));
tilesetImage.loadFromImage(img);
tilesetImage.setSmooth(false);
// Получаем количество столбцов и строк тайлсета
int columns = tilesetImage.getSize().x / tileWidth;
int rows = tilesetImage.getSize().y / tileHeight;
// Вектор из прямоугольников изображений (TextureRect)
std::vector<sf::Rect<int>> subRects;
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;
subRects.push_back(rect);
}
// Работа со слоями
TiXmlElement *layerElement;
layerElement = map->FirstChildElement("layer");
while(layerElement)
{
Layer layer;
// Если присутствует opacity, то задаем прозрачность слоя, иначе он полностью непрозрачен
if (layerElement->Attribute("opacity") != NULL)
{
float opacity = strtod(layerElement->Attribute("opacity"), NULL);
layer.opacity = 255 * opacity;
}
else
{
layer.opacity = 255;
}
// Контейнер <data>
TiXmlElement *layerDataElement;
layerDataElement = layerElement->FirstChildElement("data");
if(layerDataElement == NULL)
{
std::cout << "Bad map. No layer information found." << std::endl;
}
// Контейнер <tile> - описание тайлов каждого слоя
TiXmlElement *tileElement;
tileElement = layerDataElement->FirstChildElement("tile");
if(tileElement == NULL)
{
std::cout << "Bad map. No tile information found." << std::endl;
return false;
}
int x = 0;
int y = 0;
while(tileElement)
{
int tileGID = atoi(tileElement->Attribute("gid"));
int subRectToUse = tileGID - firstTileID;
// Устанавливаем TextureRect каждого тайла
if (subRectToUse >= 0)
{
sf::Sprite sprite;
sprite.setTexture(tilesetImage);
sprite.setTextureRect(subRects[subRectToUse]);
sprite.setPosition(x * tileWidth, y * tileHeight);
sprite.setColor(sf::Color(255, 255, 255, layer.opacity));
layer.tiles.push_back(sprite);
}
tileElement = tileElement->NextSiblingElement("tile");
x++;
if (x >= width)
{
x = 0;
y++;
if(y >= height)
y = 0;
}
}
layers.push_back(layer);
layerElement = layerElement->NextSiblingElement("layer");
}
// Работа с объектами
TiXmlElement *objectGroupElement;
// Если есть слои объектов
if (map->FirstChildElement("objectgroup") != NULL)
{
objectGroupElement = map->FirstChildElement("objectgroup");
while (objectGroupElement)
{
// Контейнер <object>
TiXmlElement *objectElement;
objectElement = objectGroupElement->FirstChildElement("object");
while(objectElement)
{
// Получаем все данные - тип, имя, позиция, etc
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 = subRects[atoi(objectElement->Attribute("gid")) - firstTileID].width;
height = subRects[atoi(objectElement->Attribute("gid")) - firstTileID].height;
sprite.setTextureRect(subRects[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->FirstChildElement("properties");
if (properties != NULL)
{
TiXmlElement *prop;
prop = properties->FirstChildElement("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");
}
objectGroupElement = objectGroupElement->NextSiblingElement("objectgroup");
}
}
else
{
std::cout << "No object layers found..." << std::endl;
}
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
#ifndef ANIM_H
#define ANIM_H
#include "TinyXML/tinyxml.h"
#include <SFML/Graphics.hpp>
using namespace sf;
class Animation
{
public:
std::vector<IntRect> frames, frames_flip;
float currentFrame, speed;
bool loop, flip, isPlaying; // loop показвает зациклена ли анимация. Например анимация взрыва должна проиграться один раз и остановиться, loop=false
Sprite sprite;
Animation()
{
currentFrame = 0;
isPlaying=true;
flip=false;
}
void tick(float time)
{
if (!isPlaying) return;
currentFrame += speed * time;
if (currentFrame > frames.size()) { currentFrame -= frames.size();
if (!loop) {isPlaying=false; return;}
}
int i = currentFrame;
sprite.setTextureRect( frames[i] );
if (flip) sprite.setTextureRect( frames_flip[i] );
}
};
class AnimationManager
{
public:
String currentAnim;
std::map<String, Animation> animList;
AnimationManager()
{}
~AnimationManager()
{ animList.clear();
}
//создание анимаций вручную
void create(String name, Texture &texture, int x, int y, int w, int h, int count, float speed, int step=0, bool Loop=true)
{
Animation a;
a.speed = speed;
a.loop = Loop;
a.sprite.setTexture(texture);
a.sprite.setOrigin(0,h);
for (int i=0;i<count;i++)
{
a.frames.push_back( IntRect(x+i*step, y, w, h) );
a.frames_flip.push_back( IntRect(x+i*step+w, y, -w, h) );
}
animList[name] = a;
currentAnim = name;
}
//загрузка из файла XML
void loadFromXML(std::string fileName,Texture &t)
{
TiXmlDocument animFile(fileName.c_str());
animFile.LoadFile();
TiXmlElement *head;
head = animFile.FirstChildElement("sprites");
TiXmlElement *animElement;
animElement = head->FirstChildElement("animation");
while(animElement)
{
Animation anim;
currentAnim = animElement->Attribute("title");
int delay = atoi(animElement->Attribute("delay"));
anim.speed = 1.0/delay; anim.sprite.setTexture(t);
TiXmlElement *cut;
cut = animElement->FirstChildElement("cut");
while (cut)
{
int x = atoi(cut->Attribute("x"));
int y = atoi(cut->Attribute("y"));
int w = atoi(cut->Attribute("w"));
int h = atoi(cut->Attribute("h"));
anim.frames.push_back( IntRect(x,y,w,h) );
anim.frames_flip.push_back( IntRect(x+w,y,-w,h) );
cut = cut->NextSiblingElement("cut");
}
anim.sprite.setOrigin(0,anim.frames[0].height);
animList[currentAnim] = anim;
animElement = animElement->NextSiblingElement("animation");
}
}
void set(String name)
{
currentAnim = name;
animList[currentAnim].flip=0;
}
void draw(RenderWindow &window,int x=0, int y=0)
{
animList[currentAnim].sprite.setPosition(x,y);
window.draw( animList[currentAnim].sprite );
}
void flip(bool b=1) {animList[currentAnim].flip = b;}
void tick(float time) {animList[currentAnim].tick(time);}
void pause() {animList[currentAnim].isPlaying=false;}
void play() {animList[currentAnim].isPlaying=true;}
void play(String name) {animList[name].isPlaying=true;}
bool isPlaying() {return animList[currentAnim].isPlaying;}
float getH() {return animList[currentAnim].frames[0].height;}
float getW() {return animList[currentAnim].frames[0].width;}
};
#endif ANIM_H
