Созданные ответы форума
-
АвторСообщения
-
Вопрос и правду непонятен.
C++12if (TileMap[x][y] == '-')TileMap[x][y] = '='Ты что-то подобное хотел?
Вобще, если пытаешься делать под себя обёртки для упрощения своей жизни, конструктор можно подгонять под любое количество аргументов. К примеру в своём коде я буду всегда по умолчанию использовать один и тот же шрифт который был статически где-то объявлен, соответственно в конструкторе я могу упустить передачу файла шрифта и уже сразу задавать строку и позицию, либо что-то ещё.
К примеру на C# мой класс Text который я старался сделать похожим на аналог из SFML имеет уже зарание объявленую ссылку на шрифт которая присваивается ещё до вызова конструктора(Main.Font объявлен статично)C++12345678910111213141516171819202122232425262728293031323334353637class Text : ISFDrawable{#region FieldsSpriteFont font = Main.Font;///Поскольку я знаю, что программа не запустится если XNA не обнаружит в папке Content данного шрифта,///я могу со спокойной совестью выгружать специально заранее загруженый экземпляр шрифта который я использую во всей программе не передавая///его через параметры конструктора/*...*/public Text(){}public Text(SpriteFont TextFont){font = TextFont;}public Text(string rawString){RawString = rawString;}public Text(string rawString, Vector2 position, Color color = Color.White){RawString = rawString;Position = position;Colro = color;}public Text(string rawString, Vector2 position, Color color , float fontSize = 12){RawString = rawString;Position = position;Colro = color;CharacterSize = fontSize;}}C++1234567891011121314151617181920class setText {public:Font font;setText(String sText, String sFont, int iSize,int iColor,float x, float y){font.loadFromFile("fonts/" + sFont);Text text1(sText, font, iSize);text1.setStyle(Text::Bold);switch (iColor){case 1: text1.setFillColor(Color::Red);case 2: text1.setFillColor(Color::Green);case 3: text1.setFillColor(Color::Blue);case 4: text1.setFillColor(Color::Yellow);case 5: text1.setFillColor(Color::Black);default: text1.setFillColor(Color::White);}text1.setPosition(x, y);}};Ну а собственно, как ты собрался тут обращатся к text1 если в конце конструктора класса будет автоматически вызван его деструктор так как он окажется вне поля видимости всей программы? Если ты хочешь просто использовать конструктор текста достаточно обьявить статический метод. Так же желательно Font так же обьявить статическим (Или держать его обьявление в начале int mani() дабы не терять его из поля видимости на протяжении всего жизненого цикла программы)
C++12345678910111213141516171819202122static Font publicFont//В int Mmain() просто добавляемpublicFont.loadFromFile("путь");static Text setText(String sText, int iSize,int iColor,float x, float y){Text text1(sText, publicFont, iSize);text1.setStyle(Text::Bold);switch (iColor){case 1: text1.setFillColor(Color::Red);case 2: text1.setFillColor(Color::Green);case 3: text1.setFillColor(Color::Blue);case 4: text1.setFillColor(Color::Yellow);case 5: text1.setFillColor(Color::Black);default: text1.setFillColor(Color::White);}text1.setPosition(x, y);return text1;}///Что бы получить доступ к методу в любом место просто после объявления инклудов дописываешьextern static Text setText(String sText, String sFont, int iSize,int iColor,float x, float y)А, и возможно я мог слишком неявно указать в чём проблема: Когда ты перетаскиваешь окно и игра доходит до секции отрисовки отрисовка приостанавливается до момента пока ты не отпустиш окно, и как только ты попадаешь в секцию где ты перемещаешь обьекты ты умножаешь перемещение на пройденое время ща цикл. Посколько цикл был приостановлен, но время продолжало идти перемещение обьектов оказывалось настолько большим что обьекты попросту повылетали за границы экрана.
Для избегания таких вещей делают перемещение обьектов привязанно не ко времени, а к некому игровому тику который срабатывает каждый интервал времени.
Для привязки всего к тику придётся переписывать половину кода. Для себя я набросал два класса которые отвечают за подобную механику обновления обьектов. Можешь спокойно использовать и модифицировать их как хочешь. Учти что:
1. Твой код должен содержатся в классе – наследнике от State и в int main() должна быть обьявлена конструкция:
IApp app(window);
app.run(new ИмяНовогоКлассаState(&window))
2. onHandle(sf::Event event) будет вызыватся на каждый ивент содержащийся в пуле окна
3. onUpdate(sf::Time delta) и onDraw(sf::RenderWindow window) не всегда будут вызыватся одновременно за один цикл (если отрисовка займёт слишком много времени следующее обновление будет вызвано столько раз, сколько излишнего времени заняла отрисовка и наоборот, если отрисовка проходит быстрее чем временной шаг то будет снова вызыватся отрисовка пока не пройдт времени больше чем временной шаг).
Ну, думаю и ежу понятно что код инициализации должен быть в конструкторе класса, логика в onUpdate а отрисовка в onDraw. Если нужно перехватить вводимый игроком текст или ещё что-то связаное с sf::Event – ловим в onHandle.
Узлы, добавленые в addNode(Node * node), будут иметь приоритет заданый переменной Z и всегда приоритет ниже Parent(Т.е. класса в котором он был добавлен)
Ну и собственно классы(Разбиты на хидеры и .cpp, как и положено). Кстати, если сможешь понять как можно использовать класс-узел (Node) это сильно сможет облегчить тебе жизнь в дальнейшем програмировании игры (В частности при помощи этого класса можно спокойно отрисовывать спрайты слоями, т.е. вначале то что должно быть на заднем плане, дальше на главном а после то что должно быть поверх главного плана)C++12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849//IApp.h#ifndef IAPP_H#define IAPP_H#include <vector>#include <SFML/Graphics.hpp>class State;//Forward declaration of State так как присутствует рекурсивное объявление/// \brief This class manages the different states of the game.class IApp{public:IApp(sf::RenderWindow& window);~IApp();/// \brief Runs the director with the passed state as starting statevoid run(State* state);/// \brief Replaces the current statevoid replaceState(State* state);/// \brief Push a new state on top of the stackvoid pushState(State* state);/// \brief Pop the top statevoid popState();/// \brief The timestep for the update functionvoid setTimestep(sf::Time timestep);private:void draw(sf::RenderWindow* window);void handle(const sf::Event& event);void update();void doPop();bool running;bool shouldPop;std::vector<State*> states;sf::RenderWindow& window;sf::Time accumulator;sf::Time timestep;sf::Clock frameClock;};#endif // IAPP_HC++123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140//IApp.cpp#include "IApp.h"#include "State.h"#include <iostream>//#include <tmx/Log.h>//using namespace tmx;IApp::IApp(sf::RenderWindow& window) : window(window), running(false), shouldPop(false), timestep(sf::milliseconds(20)), accumulator(sf::Time::Zero){}IApp::~IApp(){//LOG("deleting app", Logger::Type::Info);for(auto itr = states.begin(); itr != states.end(); itr++)delete (*itr);states.clear();}void IApp::run(State* state){pushState(state);running = true;sf::Event event;frameClock.restart();while(running){if(!shouldPop){//handlewhile(window.pollEvent(event)){handle(event);}//updateaccumulator += frameClock.getElapsedTime();while(accumulator >= timestep){update();accumulator -= timestep;}frameClock.restart();//drawwindow.clear();draw(&window);window.display();}else{doPop();frameClock.restart();}}}void IApp::setTimestep(sf::Time timestep){this->timestep = timestep;}void IApp::replaceState(State* state){//LOG("replacing state", Logger::Type::Info);//LOG("states: " + states.size(),Logger::Type::Info);popState();// store and init the new statestate->setDirector(this);state->setWindow(&window);states.insert(states.end() - 1, state);LOG("states: " + states.size(), Logger::Type::Info);}void IApp::pushState(State* state){//LOG("Pushing state", Logger::Type::Info);//LOG("states: " + states.size(), Logger::Type::Info);state->setDirector(this);state->setWindow(&window);// pause current stateif ( !states.empty() )states.back()->pause();// store and init the new statestates.push_back(state);//LOG("states: " + states.size(), Logger::Type::Info);}void IApp::doPop(){//LOG("Popping state", Logger::Type::Info);//LOG("states: " + states.size(), Logger::Type::Info);shouldPop = false;// cleanup the current stateif ( !states.empty() ){//LOG("deleting state", Logger::Type::Info);delete states.back();//LOG("state deleted", Logger::Type::Info);states.pop_back();}// resume previous stateif ( !states.empty() )states.back()->resume();else{running = false;window.close();}//LOG("states: " + states.size(), Logger::Type::Info);}void IApp::popState(){shouldPop = true;}void IApp::handle(const sf::Event& event){if(!states.empty())states.back()->handle(event);}void IApp::update(){if(!states.empty())states.back()->update(timestep);}void IApp::draw(sf::RenderWindow* window){if(!states.empty())states.back()->draw(window);}C++1234567891011121314151617181920212223242526272829303132//State.h#ifndef STATE_H#define STATE_H#include "IApp.h"//#include "ResourceManager.h"#include "Node.h"/// \brief The base class for states that can be added to a directorclass State : public Node{friend class IApp;public:/// \brief ConstructorState();virtual ~State(){};/// \brief Called when another state is pushed on top of the stack.virtual void pause(){};/// \brief Called when the state becomes the top of the stack.virtual void resume(){};protected:IApp* app;void setApp(IApp* app);private:};#endif // STATE_HC++123456789101112//State.cpp#include "State.h"State::State() : Node("State"){setZ(-1000);}void State::setApp(IApp* app){this->app= app;}C++123456789101112131415161718192021222324252627282930313233343536373839404142434445464748//Node.h#ifndef NODE_H#define NODE_H#include <SFML/Graphics.hpp>class Node{public:Node(const std::string& name = "Node");virtual ~Node();std::string getName();void setName(const std::string& name);void draw(sf::RenderWindow* window);void update(sf::Time delta);void handle(const sf::Event& event);void addNode(Node* node);void removeNode(Node* node);void setWindow(sf::RenderWindow* window);int getZ() const;void setZ(int z);Node* getParent();void setParent(Node* parentnode);std::vector<Node*>& getChildren();protected:virtual void onDraw(sf::RenderWindow* window){}virtual void onUpdate(sf::Time delta){}virtual void onHandle(const sf::Event& event){}virtual void onWindowSet(){}Node* parent;sf::RenderWindow* window;private:std::vector<Node*> children;std::string name;int z;};#endif // NODE_HC++123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110//Node.cpp#include "Node.h"#include <algorithm>//#include <tmx/Log.h>//using namespace tmx;bool sortByZValue(const Node* a, const Node* b){return (a->getZ() < b->getZ());}Node::Node(const std::string& name) : name(name), parent(NULL), z(0), window(NULL){//ctor}Node::~Node(){for(Node* node : children){//LOG("deleting node: " + node->getName(),Logger::Type::Info);delete node;}}std::string Node::getName(){return name;}void Node::setName(const std::string& name){this->name = name;}void Node::setZ(int z){this->z = z;}int Node::getZ() const{return z;}void Node::setWindow(sf::RenderWindow* window){this->window = window;for(Node* node : children)node->setWindow(window);onWindowSet();}void Node::draw(sf::RenderWindow* window){onDraw(window);for(Node* node : children)node->draw(window);}void Node::update(sf::Time delta){onUpdate(delta);for(Node* node : children)node->update(delta);}void Node::handle(const sf::Event& event){onHandle(event);for(Node* node : children)node->handle(event);}void Node::addNode(Node* node){node->setParent(this);node->setWindow(window);children.push_back(node);std::sort(begin(children), end(children), sortByZValue);}void Node::removeNode(Node* node){for(auto itr = children.begin(); itr != children.end(); itr++){if(node == (*itr)){children.erase(itr);return;}}}Node* Node::getParent(){return parent;}void Node::setParent(Node* parentnode){parent = parentnode;}std::vector<Node*>& Node::getChildren(){return children;}А собствено как вы его убивать собрались? Если вы хотели просто не давать камере следить за игроком то зачем тогда выстроена такая конструкция?
C++123//этим методом будем забирать координаты для камерыgetPlayerCoordinateForView(x, y);//Камера центрируется на игрокеif (life) { getPlayerCoordinateForView(x, y); }//Камера центрируется на игроке если он живПроблемы две. Первая – тот же вопрос поднимался и на оффициальном форуме но всё сошло к тому что это дело гиблое.
Вторая – на форуме практически никого нет, ну а поля для ввода и кнопочки я спокойно реализовывал и на самом SFML, так что тут я не советчик.
Если нужны оконные кнопочки и тому подобное то был уже тред на этом форуме, там человек решил свою проблему прикрутив к MVS поверх SFML QTВозможно беда с нормализацией вектора. Когда мышь находится по отношению к спрайту на расстоянии меньше одного юнита может произойти подобное из за того что мы находим скаляр для приведения длинны вектора к 1 юниту.
Попробуй заменить мой метод нормализации на этотC++1234567891011121314151617181920212223float vectorMagnitude(const sf::Vector2f& vector){return std::sqrt(vector.x * vector.x + vector.y * vector.y);}sf::Vector2f getVectorMovedOrigin(const sf::Vector2f& targetVector, const sf::Vector2f& originVector){return sf::Vector2f(targetVector - originVector);}sf::Vector2f vectorNormalize(const sf::Vector2f& vector, const sf::Vector2f origin)//1 аргумент - позицию курсора, 2 аргумент - центр спрайта{return vectorNormalize(getVectorMovedOrigin(vector, origin));}sf::Vector2f vectorNormalize(const sf::Vector2f& vector)//Если вектор уже имеет начало кординат в нужном месте{float magnitude = vectorMagnitude(vector);if (magnitude == 0.0f)return sf::Vector2f(1.0f, 0.0f);float distInv = 1.0f / magnitude;return sf::Vector2f(vector.x * distInv, vector.y * distInv);}При помощи дебага проверь попадает ли вобще код в
<div id=”crayon-591320f37a462315167078-4″ class=”crayon-line crayon-striped-line”><span class=”crayon-st”>if</span> <span class=”crayon-sy”>(</span><span class=”crayon-sy”>(</span><span class=”crayon-o”>*</span><span class=”crayon-v”>iter1</span><span class=”crayon-sy”>)</span><span class=”crayon-o”>-></span><span class=”crayon-v”>life</span> <span class=”crayon-o”>==</span> <span class=”crayon-t”>false</span><span class=”crayon-sy”>)</span></div>
<div id=”crayon-591320f37a462315167078-5″ class=”crayon-line”><span class=”crayon-sy”>{</span></div>
<div id=”crayon-591320f37a462315167078-6″ class=”crayon-line crayon-striped-line”><span class=”crayon-v”>enemyArray</span><span class=”crayon-sy”>.</span><span class=”crayon-e”>erase</span><span class=”crayon-sy”>(</span><span class=”crayon-v”>iter1</span><span class=”crayon-sy”>)</span><span class=”crayon-sy”>;//Ставь точку дебага здесь и убей противника</span></div>
<div id=”crayon-591320f37a462315167078-7″ class=”crayon-line”><span class=”crayon-e”>delete</span> <span class=”crayon-sy”>(</span><span class=”crayon-o”>*</span><span class=”crayon-v”>iter1</span><span class=”crayon-sy”>)</span><span class=”crayon-sy”>;</span></div>
<div id=”crayon-591320f37a462315167078-8″ class=”crayon-line crayon-striped-line”><span class=”crayon-v”>iter1</span><span class=”crayon-o”>++</span><span class=”crayon-sy”>;</span></div>
<div id=”crayon-591320f37a462315167078-9″ class=”crayon-line”><span class=”crayon-sy”>}</span></div>C++12345678910for (iter1 = enemyArray.begin(); iter1 != enemyArray.end();){(*iter1)->update(time);if ((*iter1)->life == false){iter1 = enemyArray.erase(iter1);delete (*iter1);}else { iter1++; }}Собственно, что вы пытались данной конструкцией донести до машины? Что бы создавался новый обьект на месте старого с полной копией его параметров?
iter1 даже после enemyArray.erase(iter1) будет сохранять ссылку на ОБЪЕКТ, при этом ссылка из листа будет удалена. Убери лишнее приведение и обьект будет успешно удалён.C++1234567891011for (iter1 = enemyArray.begin(); iter1 != enemyArray.end();){(*iter1)->update(time);if ((*iter1)->life == false){/*iter1 = */enemyArray.erase(iter1);delete (*iter1);iter1++;//Мы работаем с сылкой на обьект в листе, а не индексом в векторе}else { iter1++; }}А, и не забывай использовать где надо packet.clear();
Для начала в SFML Network уже присутствует контейнер для получаемых данных Packet. Instance of TYPE текущего масива в пакете проверяется легко
C++12345678910111213141516sf::Packet packet;std::String s;socket.recieve(packet);while (!packet.endOfPacket())if (packet >> s){//Значит пакет является строкой}//И отправлять пакет прощеstd::string s = "Hello world!";sf::Pakcet packet;packet << s;socket.send(packet);Ну и у тебя есть 2 выбора. Либо при дисконекте клиента отправлять на сервер кодовую строку, либо проверять state у sf::Socket
C++123456789//Если было socket.disconnect()if (socket.send(packet) == sf::Socket::Disconnected);if (socket.receive(packet) == sf::Socket::Disconnected);//Если подключения вовсе небылоif (socket.send(packet) == sf::Socket::NotReady);if (socket.receive(packet) == sf::Socket::NotReady);//Если при отправке/приёме данных произошла ошибкаif (socket.send(packet) == sf::Socket::Error);if (socket.receive(packet) == sf::Socket::Error);Делай проверку находится ли обьект в поле зрения и только тогда обновляй/рисуй обьект.
Человеческий фактор никогда не отменялся. Странно что IntelliSense не маячит об этом…
C++123456789101112131415161718192021222324252627sf::String TileMap[HEIGHT_MAP] = {“0000000000000000000000000000000000000000”“0 0″“0 s 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0 0″“0000000000000000000000000000000000000000”};Пробелы тоже символы, и учитываются при подсчёте длинны строки. Поскольку ты используешь константы для итерации по карте то будь добр проверять что длинна строки = этой константе:
C++123456789101112const int HEIGHT_MAP = 25;const int WIDTH_MAP = 40;for(int i = 0; i < HEIGHT_MAP; i++)for (int j = 0; j < WIDTH_MAP; j++){if (TileMap[i][j] == ‘ ‘) s_map.setTextureRect(IntRect(0, 0, 32, 32));if (TileMap[i][j] == ‘s’) s_map.setTextureRect(IntRect(32, 0, 32, 32));if ((TileMap[i][j] == ‘0’)) s_map.setTextureRect(IntRect(64, 0, 32, 32));s_map.setPosition(j * 32, i * 32);window.draw(s_map);}Поскольку c++ не поддерживает string по умолчанию сам он реализован в виде вектора char, и когда ты пытаешься сослатся на элемент которого нет в векторе – хватаешь экзепшен что ищеш обьект вне поля видимости. Выхода 2 – либо иметь строку длинной равной константе, что в данном случае самое уместное, либо считать длинну строки и использовать каждый раз её для итерации по масиву, что повлечёт свои проблемы так как это тайлсет а не строка содержащая в себе локализацию к примеру.
-
АвторСообщения