На этом уроке научим персонажа стрелять. Для начала рассмотрим какой может быть стрельба. Герой может стрелять пулями (“очередями”, прерывистая стрельба) или лазером (сплошная, постоянная стрельба). Сегодня будем работать с пулями, так как они пользуются наибольшим спросом. Давайте разберемся – куда же может лететь пуля и по какой траектории?
Видеоверсия: http://youtu.be/Db04mWPtooM
Пуля мало чем отличается от платформы или врага, ну а чем? Летит себе со скоростью при появлении и исчезает/умирает при столкновении с чем-либо. Просто нужно дать ей начальную скорость и направление, и прописать, что если она столкнулась со стенкой (или врагом, но это позже), то её life = false.
Пуля может лететь сонаправлено взгляду (или движению) персонажа, то есть в ту сторону, в которую он смотрит (двигается). А может лететь и в сторону курсора (то есть прицела), а её направление может и управляться с клавиатуры , то есть если персонаж идёт вправо, он может стрельнуть влево (типа спиной вперед).
Давайте рассмотрим случай, когда выстрел происходит с помощью клавиатуры в сторону движения/взгляда персонажа. Мы будем стрелять вверх, влево, вправо. Так же сделаем пример стрельбы по диагонали – вправо вверх. Можно стрелять в место клика курсора и это тема следующего урока, но вы же знаете, что достаточно склеить знания из этого урока и урока №18 (только вместо спрайта героя из того урока будет пуля).
Есть у нас два пути. Первый – добавление переменной направления пули для героя (класса Player). Оно (направление) будет совпадать с направлением движения героя, но вы можете сделать так, чтобы не совпадало (просто надо реализовывать лишнее управление для прицеливания в другую сторону) и это будет второй путь. Мы пойдем по первому и обойдем создание переменной направления для общего развития, так скажем. Что я имел ввиду – узнаете позже, давайте сейчас создадим класс пули.
Пули (Bullets):
Создадим класс пули, он похож на класс платформы или врага, поэтому так же будет унаследован он Entity и при этом храним всё в том же списке entities.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
class Bullet :public Entity{//класс пули public: int direction;//направление пули Bullet(Image &image, String Name, Level &lvl, float X, float Y, int W, int H, int dir) :Entity(image, Name, X, Y, W, H){//всё так же, только взяли в конце состояние игрока (int dir) obj = lvl.GetObjects("solid");//инициализируем .получаем нужные объекты для взаимодействия пули с картой x = X; y = Y; direction = dir; speed = 0.8; w = h = 16; life = true; //выше инициализация в конструкторе } void update(float time) { switch (direction) { case 0: dx = -speed; dy = 0; break;//интовое значение state = left case 1: dx = speed; dy = 0; break;//интовое значение state = right case 2: dx = 0; dy = -speed; break;//интовое значение state = up case 3: dx = 0; dy = -speed; break;//интовое значение не имеющее отношения к направлению, пока просто стрельнем вверх, нам сейчас это не важно case 4: dx = 0; dy = -speed; break;//интовое значение не имеющее отношения к направлению, пока просто стрельнем вверх, нам сейчас это не важно case 5: dx = 0; dy = -speed; break;//интовое значение не имеющее отношения к направлению, пока просто стрельнем вверх, нам сейчас это не важно } x += dx*time;//само движение пули по х y += dy*time;//по у if (x <= 0) x = 1;// задержка пули в левой стене, чтобы при проседании кадров она случайно не вылетела за предел карты и не было ошибки if (y <= 0) y = 1; for (int i = 0; i < obj.size(); i++) {//проход по объектам solid if (getRect().intersects(obj[i].rect)) //если этот объект столкнулся с пулей, { life = false;// то пуля умирает } } sprite.setPosition(x+w/2, y+h/2);//задается позицию пуле } }; |
Ничего нового не произошло. Только лишь в конструкторе последним параметром мы передаём состояние персонажа state. Помните, у игрока есть состояние и оно перечисляемого типа: enum { left, right, up, down, jump, stay } state; Мы передаём это состояние в класс пули, чтобы знать в какую же сторону ей лететь при создании, принимаем это состояние типом int и таким образом сможем обращаться к индексу этого состояния. left = нулевой индекс, stay имеет индекс 5.
Строка if (x <= 0) x = 1 спасает пулю от вылета за предел карты, например когда фпс игры неожиданно просядет и игра пропустит кадр с проверкой на столкновение пули с solid объектом, но тут же пуля вернется как бы назад. Такую перестраховку сделали пока с левым и верхним краями карты, для демонстрации. В целом мы ведь не знаем размеры своей карты по ширине и высоте, пока игру до конца не допилим.
Класс пули сделали, теперь надо найти для нее картинку. Я буду использовать вот такую для теста:
маленькая пулька 16*16. Сделаю маску по черному цвету для неё, но лучше иметь прозрачную пульку – это минус одна строка кода и картинка весит меньше. Нам для урока и теста сойдёт вот эта
Загрузим для нашей пули картинку там же , где и для остальных изображений (у меня прям сразу после картинки платформы) :
1 2 3 |
Image BulletImage;//изображение для пули BulletImage.loadFromFile("images/bullet.png");//загрузили картинку в объект изображения BulletImage.createMaskFromColor(Color(0, 0, 0));//маска для пули по черному цвету |
Теперь нужно создать пулю – занести её в список. Да и всё, потому что объекты списка entities уже обновляются, рисуются и умирают. Пульки будем создавать в событиях. Когда нажимаете на клавишу выльется целая куча пуль, поэтому нужно обрабатывать в цикле событий.
Первый вариант – в функции control() класса Player описать нажатие кнопки стрельбы (создаем bool переменную isShoot и активируем её, если нажали пробел например). И потом в цикле событий впилить вот такой код:
1 2 3 4 5 6 7 8 |
Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); if (p.isShoot == true) { p.isShoot = false; entities.push_back(new Bullet(BulletImage, "Bullet", lvl, p.x, p.y, 16, 16, p.state)); }//если выстрелили, то появляется пуля. enum передаем как int } |
В цикле событий именно потому, что если вы напишите “если нажат пробел, то стрельнуть” вне цикла событий, то пули будут лететь не успеете посчитать :)) Кстати если нужно , чтобы персонаж стрелял постоянно (а такое тоже бывает) , то просто убрать условие для проверки на нажатие пробела.
Другой вариант – обработать нажатие клавиши P (пусть это будет ещё одна кнопка стрельбы) в цикле событий с помощью sfml функции:
1 2 3 4 5 6 7 |
if (event.type == sf::Event::KeyPressed) { if (event.key.code == sf::Keyboard::P) { entities.push_back(new Bullet(BulletImage, "Bullet", lvl, p.x, p.y, 16, 16, p.state)); } } |
Первый вариант лучше с точки зрения логики приложения (потому что управление у нас уже описано ранее, зачем описывать где то ещё?). Вобще в int main и main.cpp в целом получилось значительное количество нагромождений, лучше будет – если вы всё это рассортируете и уменьшите int main ().
Пример со стрельбой в 4 направления готов.
Давайте стрельнем по диагонали вправо вверх:
Пойдем по пути добавления еще одного enum state состояния right_Top, которое будет активировано , если нажаты клавиши вправо+вверх. и в control() класса игрока допишем:
1 2 3 |
if ((Keyboard::isKeyPressed(Keyboard::Right)) && (Keyboard::isKeyPressed(Keyboard::Up))) { state = right_Top; } |
Хотелось бы отметить, что нам пришлось добавить одно состояние right_top из-за текущей логики в update персонажа. Если требуется большое количество состояний как сейчас, то нужно отделить направление персонажа и его состояние, то есть просто сделать состояние “walk”, а куда он идёт уже решает другая переменная. Я не планировал, что лисёнок озвереет и будет стрелять, поэтому по привычке с enum использовал switch (частая связка , особенно в java). Вобщем допиливать еще одну переменную ради этого сейчас не будем, просто знайте. Кстати говоря, если наш герой всё таки будет стрелять вправо вверх и при этом должен стоять на месте, то это полюбому придется реализовывать, потому что сейчас он стреляет вправо вверх и при этом подпрыгивает , т.к срабатывает ещё и состояние jump. Наши прошлые состояния можно оставить в том случае, если мы будем стрелять лишь в два направления (вправо или влево), или же по клику курсора мыши. Как видите – чем толще игра , тем больше нужно вводить таких вот логических ограничений. Отступление получилось слишком большим, но я надеюсь вы поняли, что я хотел до вас донести.
Вправо вверх в платформере идти мы не можем, во всяком случае пока в нашей игре такого не предвидится , поэтому при этом состоянии мы просто будем идти вправо:
1 2 3 4 5 6 7 8 9 10 11 12 |
void update(float time) { control(); switch (state) { case right:dx = speed; break; case left:dx = -speed; break; case up: break; case down: dx = 0; break; case stay: break; case right_Top:dx = speed; break;//состояние вправо вверх, просто продолжаем идти вправо } |
Индекс этого состояния равен [6] шести , поэтому в update у пули в переключателе направлений допишем вот такую штуку:
1 |
case 6: dx = speed; dy = -speed; break;//интовое значение state = right_Top |
т.е пуля полетит вправо вверх, если нажата клавиша вправо и вверх. Аналогичным образом можно сделать и для других направлений.
Суть урока – научиться стрелять, а такие тонкости продумываете сами или спрашивайте на форуме.
На следующем уроке стрельнем в сторону клика курсора.
main.cpp урока
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
#include <SFML/Graphics.hpp> #include <SFML/Audio.hpp> #include "view.h" #include <iostream> //#include <sstream>//сейчас не нужно. раньше выводили текст ( в 13 ом уроке ) #include "mission.h" #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); } virtual void update(float time) = 0;//все потомки переопределяют эту ф-цию }; ////////////////////////////////////////////////////КЛАСС ИГРОКА//////////////////////// class Player :public Entity { public: enum { left, right, up, down, jump, stay, right_Top } state; int playerScore; bool isShoot; Player(Image &image, String Name, Level &lev, float X, float Y, int W, int H) :Entity(image, Name, X, Y, W, H ){ playerScore = isShoot = 0; state = stay; obj = lev.GetAllObjects(); if (name == "Player1"){ sprite.setTextureRect(IntRect(4, 19, w, h)); } } void control(){ if (Keyboard::isKeyPressed){ if (Keyboard::isKeyPressed(Keyboard::Left)) { state = left; speed = 0.1; } if (Keyboard::isKeyPressed(Keyboard::Right)) { state = right; speed = 0.1; } if ((Keyboard::isKeyPressed(Keyboard::Up)) && (onGround)) { state = jump; dy = -0.6; onGround = false; } if (Keyboard::isKeyPressed(Keyboard::Down)) { state = down; } if ((Keyboard::isKeyPressed(Keyboard::Right)) && (Keyboard::isKeyPressed(Keyboard::Up))) { state = right_Top; } /////выстрел if (Keyboard::isKeyPressed(Keyboard::Space)) { isShoot = true; } } } void checkCollisionWithMap(float Dx, float Dy) { for (int i = 0; i<obj.size(); i++) if (getRect().intersects(obj[i].rect)) { if (obj[i].name == "solid") { 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; } } // else { onGround = false; } } } void update(float time) { control(); switch (state) { case right:dx = speed; break; case left:dx = -speed; break; case up: break; case down: dx = 0; break; case stay: break; case right_Top:dx = speed; break;//состояние вправо вверх, просто продолжаем идти вправо } x += dx*time; checkCollisionWithMap(dx, 0); y += dy*time; checkCollisionWithMap(0, dy); sprite.setPosition(x+w/2,y+h/2); if (health <= 0){ life = false; } if (!isMove){ speed = 0; } if (life) { setPlayerCoordinateForView(x, y); } dy = dy + 0.0015*time; } }; class Enemy :public Entity{ public: Enemy(Image &image, String Name,Level &lvl, float X, float Y, int W, int H) :Entity(image, Name, X, Y, W, H){ obj = lvl.GetObjects("solid");//инициализируем.получаем нужные объекты для взаимодействия врага с картой if (name == "EasyEnemy"){ sprite.setTextureRect(IntRect(0, 0, w, h)); dx = 0.1; } } void checkCollisionWithMap(float Dx, float Dy) { for (int i = 0; i<obj.size(); i++) if (getRect().intersects(obj[i].rect)) { if (obj[i].name == "solid")//если встретили препятствие { 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; dx = -0.1; sprite.scale(-1, 1); } if (Dx<0) { x = obj[i].rect.left + obj[i].rect.width; dx = 0.1; sprite.scale(-1, 1); } } } } void update(float time) { if (name == "EasyEnemy"){ //moveTimer += time;if (moveTimer>3000){ dx *= -1; moveTimer = 0; }//меняет направление примерно каждые 3 сек(альтернативная версия смены направления) checkCollisionWithMap(dx, 0); x += dx*time; sprite.setPosition(x+w/2, y+h/2); if (health <= 0){ life = false; } } } }; class Bullet :public Entity{//класс пули public: int direction;//направление пули Bullet(Image &image, String Name, Level &lvl, float X, float Y, int W, int H, int dir) :Entity(image, Name, X, Y, W, H){//всё так же, только взяли в конце состояние игрока (int dir) obj = lvl.GetObjects("solid");//инициализируем .получаем нужные объекты для взаимодействия пули с картой x = X; y = Y; direction = dir; speed = 0.8; w = h = 16; life = true; //выше инициализация в конструкторе } void update(float time) { switch (direction) { case 0: dx = -speed; dy = 0; break;//интовое значение state = left case 1: dx = speed; dy = 0; break;//интовое значение state = right case 2: dx = 0; dy = -speed; break;//интовое значение state = up case 3: dx = 0; dy = -speed; break;//интовое значение не имеющее отношения к направлению, пока просто стрельнем вверх, нам сейчас это не важно case 4: dx = 0; dy = -speed; break;//интовое значение не имеющее отношения к направлению, пока просто стрельнем вверх, нам сейчас это не важно case 5: dx = 0; dy = -speed; break;//интовое значение не имеющее отношения к направлению, пока просто стрельнем вверх, нам сейчас это не важно case 6: dx = speed; dy = -speed; break;//интовое значение state = right_Top } x += dx*time;//само движение пули по х y += dy*time;//по у if (x <= 0) x = 1;// задержка пули в левой стене, чтобы при проседании кадров она случайно не вылетела за предел карты и не было ошибки if (y <= 0) y = 1; for (int i = 0; i < obj.size(); i++) {//проход по объектам solid if (getRect().intersects(obj[i].rect)) //если этот объект столкнулся с пулей, { life = false;// то пуля умирает } } sprite.setPosition(x+w/2, y+h/2);//задается позицию пуле } }; class MovingPlatform : public Entity{//класс движущейся платформы public: MovingPlatform(Image &image, String Name, Level &lvl, float X, float Y, int W, int H) :Entity(image, Name, X, Y, W, H){ sprite.setTextureRect(IntRect(0, 0, W, H));//прямоугольник dx = 0.08;//изначальное ускорение по Х } void update(float time)//функция обновления платформы. { x += dx * time;//реализация движения по горизонтали moveTimer += time;//наращиваем таймер if (moveTimer>2000) { dx*= -1; moveTimer = 0; }//если прошло примерно 2 сек, то меняется направление движения платформы, а таймер обнуляется sprite.setPosition(x+w/2, y+h/2);//задаем позицию спрайту } }; int main() { RenderWindow window(VideoMode(640, 480), "Lesson 28. kychka-pc.ru"); view.reset(FloatRect(0, 0, 640, 480)); Level lvl; lvl.LoadFromFile("map.tmx"); Image heroImage; heroImage.loadFromFile("images/MilesTailsPrower.gif"); Image easyEnemyImage; easyEnemyImage.loadFromFile("images/shamaich.png"); easyEnemyImage.createMaskFromColor(Color(255, 0, 0)); Image movePlatformImage; movePlatformImage.loadFromFile("images/MovingPlatform.png"); Image BulletImage;//изображение для пули BulletImage.loadFromFile("images/bullet.png");//загрузили картинку в объект изображения BulletImage.createMaskFromColor(Color(0, 0, 0));//маска для пули по черному цвету std::list<Entity*> entities; std::list<Entity*>::iterator it; std::list<Entity*>::iterator it2;//второй итератор.для взаимодействия между объектами списка std::vector<Object> e = lvl.GetObjects("EasyEnemy"); for (int i = 0; i < e.size(); i++) entities.push_back(new Enemy(easyEnemyImage, "EasyEnemy", lvl, e[i].rect.left, e[i].rect.top, 200, 97)); Object player=lvl.GetObject("player"); Player p(heroImage, "Player1", lvl, player.rect.left, player.rect.top, 40, 30); e = lvl.GetObjects("MovingPlatform");//забираем все платформы в вектор for (int i = 0; i < e.size(); i++) entities.push_back(new MovingPlatform(movePlatformImage, "MovingPlatform", lvl, e[i].rect.left, e[i].rect.top, 95, 22));//закидываем платформу в список.передаем изображение имя уровень координаты появления (взяли из tmx карты), а так же размеры Clock clock; while (window.isOpen()) { float time = clock.getElapsedTime().asMicroseconds(); clock.restart(); time = time / 800; Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); if (p.isShoot == true) { p.isShoot = false; entities.push_back(new Bullet(BulletImage, "Bullet", lvl, p.x, p.y, 16, 16, p.state)); }//если выстрелили, то появляется пуля. enum передаем как int //второй варант стрельнуть if (event.type == sf::Event::KeyPressed) { if (event.key.code == sf::Keyboard::P) { entities.push_back(new Bullet(BulletImage, "Bullet", lvl, p.x, p.y, 16, 16, p.state)); } } } for (it = entities.begin(); it != entities.end();)//говорим что проходимся от начала до конца { Entity *b = *it;//для удобства, чтобы не писать (*it)-> b->update(time);//вызываем ф-цию update для всех объектов (по сути для тех, кто жив) if (b->life == false) { it = entities.erase(it); delete b; }// если этот объект мертв, то удаляем его else it++;//и идем курсором (итератором) к след объекту. так делаем со всеми объектами списка } for (it = entities.begin(); it != entities.end(); it++)//проходимся по эл-там списка { if (((*it)->name == "MovingPlatform") && ((*it)->getRect().intersects(p.getRect())))//если игрок столкнулся с объектом списка и имя этого объекта movingplatform { Entity *movPlat = *it; if ((p.dy>0) || (p.onGround == false))//при этом игрок находится в состоянии после прыжка, т.е падает вниз if (p.y + p.h<movPlat->y + movPlat->h)//если игрок находится выше платформы, т.е это его ноги минимум (тк мы уже проверяли что он столкнулся с платформой) { p.y = movPlat->y - p.h + 3; p.x += movPlat->dx*time; p.dy = 0; p.onGround = true; // то выталкиваем игрока так, чтобы он как бы стоял на платформе } } if (((*it)->name == "EasyEnemy") && ((*it)->getRect().intersects(p.getRect()))) { ////////выталкивание врага if ((*it)->dx>0)//если враг идет вправо { std::cout << "(*it)->x" << (*it)->x << "\n";//коорд игрока std::cout << "p.x" << p.x << "\n\n";//коорд врага (*it)->x = p.x - (*it)->w; //отталкиваем его от игрока влево (впритык) (*it)->dx = 0;//останавливаем std::cout << "new (*it)->x" << (*it)->x << "\n";//новая коорд врага std::cout << "new p.x" << p.x << "\n\n";//новая коорд игрока (останется прежней) } if ((*it)->dx < 0)//если враг идет влево { (*it)->x = p.x + p.w; //аналогично - отталкиваем вправо (*it)->dx = 0;//останавливаем } ///////выталкивание игрока if (p.dx < 0) { p.x = (*it)->x + (*it)->w;}//если столкнулись с врагом и игрок идет влево то выталкиваем игрока if (p.dx > 0) { p.x = (*it)->x - p.w;}//если столкнулись с врагом и игрок идет вправо то выталкиваем игрока } for (it2 = entities.begin(); it2 != entities.end(); it2++) { if ((*it)->getRect() != (*it2)->getRect())//при этом это должны быть разные прямоугольники if (((*it)->getRect().intersects((*it2)->getRect())) && ((*it)->name == "EasyEnemy") && ((*it2)->name == "EasyEnemy"))//если столкнулись два объекта и они враги { (*it)->dx *= -1;//меняем направление движения врага (*it)->sprite.scale(-1, 1);//отражаем спрайт по горизонтали } } } p.update(time);//перенесли сюда update игрока window.setView(view); window.clear(Color(77,83,140)); lvl.Draw(window); for (it = entities.begin(); it != entities.end(); it++){ window.draw((*it)->sprite); } window.draw(p.sprite); window.display(); } return 0; } |
Спасибо, Павел! То, что надо 😉 А можно надеяться увидеть урок по созданию меню игры? А заодно по разворачиванию её на весь экран. Хотя, как мне кажется, на весь экран развернуть не тянет на отдельный урок.
Можно надеяться, такой урок планируется в будущем (только когда это будет – не знаю.. )
насчет развернуть на весь экран это как пример доп параметра рассматривалось
вот тут
https://kychka-pc.ru/sfml/urok-2-razbor-testovogo-koda-osnovnoj-princip-raboty-sfml-obyazatelnye-funkcii-sfml.html
про fullscreen пара слов поищи в уроке
Отличный сайт. Будут ли уроки о использовании SFML и Box2d вместе?
спасибо:)

будут , но тяжело говорить когда. сейчас с уроками совсем туго по времени у меня
но можно спросить на форуме и люди помогут, а может быть кто – нибудь захочет написать про это статью. я с радостью дам автора
Мне кажется, или я пропустил урок со стрельбой в клик мыши? Я просто не могу создать новую функцию, а update менять не хочется.
К сожалению потом не видел целесообразности в создании такого урока = (
Но такой код у меня где-то был, в конце недели возможно смогу выложить и найти.
На размышление
Я начал анализировать библиотеку SFML, и наткнуля вот на какую фигню:
x и y можно найти вот так
w и h можно найти вот так
и не обязательно задавать их самому, они устанавливаются автоматически после загрузки
К чему это я?
Мы создаём переменные, которые уже есть.
не
float x = sprite.setPosition().x; // возвращает положение спрайта по X
а
float x = sprite.getPosition().x; // возвращает положение спрайта по X
Верно.
Просто сейчас свой велосипед смотрел, было 20 переменных которые можно получить из image и sprite)
Всё переделываю