SFML и C++ Уроки \ Разработка игр › Форумы › SFML Graphics › игра "Space Invaders". Нужна помощь. › Ответ в теме: игра "Space Invaders". Нужна помощь.
В общем классы вынес в отдельный файл, чтоб не мешали.
Никак не могу придумать нормальные алгоритм для задержки выстрелов игрока и алгоритм для огня целей по игроку :/
Код main.cpp и Entities.h
C++
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 |
#include <SFML/Graphics.hpp> #include <iostream> #include <sstream> #include <vector> #include <list> #include "Entities.h" int main() { RenderWindow window(sf::VideoMode(480, 640), "GAME"); float CurrentFrame = 0;//хранит текущий кадр list<Entity*> entities; list<Entity*>::iterator it; //итератор для "пробегания по списку" list<Entity*>::iterator it2; //второй итератор, для реализации модели столкновений элементов списка //Player s("ship.png", 90, 0, 90, 30, 240, 600);//создаем объект p класса player,задаем "hero.png" как имя файла+расширение, далее координата Х,У, ширина, высота. Image shipImage; shipImage.loadFromFile("textures/ship.png"); Player s(shipImage, 90, 0, 90, 30, "Player", 240, 600);//объект класса игрока Image BulletImage;//изображение для пули BulletImage.loadFromFile("textures/bullet_test.png");//загрузили картинку в объект изображения Image enemyImage; enemyImage.loadFromFile("textures/enemy_test.png"); const int n = 4; const int m = 8; int i, j; for (i = 0; i < n; i++) { for (j = 0; j < m; j++) { entities.push_back(new Enemy(enemyImage, 0, 0, 30, 30, "Enemy", 15 + j * 30 + j * 15, 20 + i * 30 + i * 15)); } } float bullettimer = 0; Clock clock; while (window.isOpen()) { float time = clock.getElapsedTime().asMicroseconds(); clock.restart(); time = time / 800; //bullettimer += time; sf::Event event; while (window.pollEvent(event)) { if (event.type == Event::Closed) window.close(); // if (s.isShoot == true) { s.isShoot = false; entities.push_back(new Bullet(BulletImage, 0, 0, 10, 10, "Bullet", s.sx+s.w/2-5, s.sy, 0)); }//если выстрелили, то появляется пуля. enum передаем как int if (event.type == Event::KeyPressed) { if (event.key.code == Keyboard::Space) { entities.push_back(new Bullet(BulletImage, 0, 0, 10, 10, "Bullet", s.sx + s.w / 2 - 5, s.sy, 0)); } } } s.update(time); 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++)//проходимся по эл-там списка { for (it2 = entities.begin(); it2 != entities.end(); it2++) { if ((*it)->getRect() != (*it2)->getRect())//при этом это должны быть разные прямоугольники if (((*it)->getRect().intersects((*it2)->getRect())) && ((*it)->name == "Enemy") && ((*it2)->name == "Bullet"))//если столкнулись два объекта и они враги { (*it)->health -= 25;//меняем направление движения врага //(*it)->sprite.scale(-1, 1);//отражаем спрайт по горизонтали (*it2)->life = false; } } } for (it = entities.begin(); it != entities.end(); it++) { if (((*it)->name == "Enemy") && ((*it)->life == true)) { int a = rand() % 1000; if (a > 99 && a < 101) entities.push_back(new Bullet(BulletImage, 0, 0, 10, 10, "EnemyBullet", (*it)->sx + s.w / 2 - 5, (*it)->sy, 1)); } } window.clear(); for (it = entities.begin(); it != entities.end(); it++){ window.draw((*it)->sprite); } window.draw(s.sprite);//рисуем спрайт объекта p класса player window.display(); } return 0; } |
C++
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 |
#define ENTITIES_H #include <SFML/Graphics.hpp> #include <iostream> #include <sstream> using namespace sf;//включаем пространство имен sf, чтобы постоянно не писать sf:: using namespace std; class Entity { public: float dx, dy, x, y, sx, sy, speed, moveTimer;//добавили переменную таймер для будущих целей int w, h, health; bool life, isMove; Texture texture; Sprite sprite; String name;//враги могут быть разные, мы не будем делать другой класс для врага.всего лишь различим врагов по имени и дадим каждому свое действие в update в зависимости от имени Entity(Image &image, float X, float Y, int W, int H, String Name, float SX, float SY){ x = X; y = Y; w = W; h = H; name = Name; moveTimer = 0; sx = SX; sy = SY; speed = 0; health = 100; dx = 0; dy = 0; life = true; isMove = false; texture.loadFromImage(image); sprite.setTexture(texture); sprite.setOrigin(w / 2, h / 2); } FloatRect getRect(){ return FloatRect(sx, sy, w, h); } virtual void update(float time) = 0;//все потомки переопределяют эту ф-цию }; class Player :public Entity { public: enum { left, right, stay } state;//добавляем тип перечисления - состояние объекта int playerScore;//эта переменная может быть только у игрока bool isShoot; Player(Image &image, float X, float Y, int W, int H, String Name, float SX, float SY) :Entity(image, X, Y, W, H, Name, SX, SY){ playerScore = isShoot = 0; state = stay; if (name == "Player"){ sprite.setTextureRect(IntRect(x, y, w, h)); } } void checkCollision(float Dx)//ф ция проверки столкновений с картой { if ((dx < 0) & (sx <= 3)) { sx = 3; state = stay; } if ((dx > 0) & (sx >= 477 - 90)) { sx = 477 - 90; state = stay; } } void control(){ if (Keyboard::isKeyPressed){//если нажата клавиша if (Keyboard::isKeyPressed(Keyboard::Left)) { state = left; speed = 0.5; sprite.setTextureRect(IntRect(0, 0, 90, 30)); }//первая координата Х отрицательна =>идём влево if (Keyboard::isKeyPressed(Keyboard::Right)) { state = right; speed = 0.5; sprite.setTextureRect(IntRect(180, 0, 90, 30)); } if (Keyboard::isKeyPressed(Keyboard::Right) & Keyboard::isKeyPressed(Keyboard::Left)) { state = stay; sprite.setTextureRect(IntRect(90, 0, 90, 30)); } //первая координата Х положительна =>идём вправо if (Keyboard::isKeyPressed(Keyboard::Space)) { isShoot = true; } } else { state = stay;; } } void update(float time) //функция "оживления" объекта класса. update - обновление. принимает в себя время SFML , вследствие чего работает бесконечно, давая персонажу движение. { control();//функция управления персонажем switch (state)//реализуем поведение в зависимости от направления. (каждая цифра соответствует направлению) { case right:dx = speed; break;//состояние идти вправо case left:dx = -speed; break;//состояние идти влево // case up: break;//будет состояние поднятия наверх (например по лестнице) // case down: dx = 0; break;//будет состояние во время спуска персонажа (например по лестнице) case stay: dx = 0; sprite.setTextureRect(IntRect(x, y, w, h)); break;//и здесь тоже } if (!isMove){ state = stay; } sx += dx*time; checkCollision(dx);//обрабатываем столкновение по Х sprite.setPosition(sx + (w / 2), sy + (h / 2)); if (health <= 0){ life = false; } } }; class Enemy :public Entity{ public: enum { left, right, up, down, stay } state; float way, xmax, xmin; Enemy(Image &image, float X, float Y, int W, int H, String Name, float SX, float SY) :Entity(image, X, Y, W, H, Name, SX, SY){ state = right; way = 140; xmin = sx; xmax = sx + way; if (name == "Enemy"){ sprite.setTextureRect(IntRect(x, y, w, h)); speed = dx = 0.1;//даем скорость.этот объект всегда двигается } } void wayCheck()//ф ция проверки столкновений с картой { if ((dx < 0) & (sx <= xmin)) { state = right; sy += 10; } if ((dx > 0) & (sx >= xmax)) { state = left; sy += 10; } } void update(float time) //функция "оживления" объекта класса. update - обновление. принимает в себя время SFML , вследствие чего работает бесконечно, давая персонажу движение. { wayCheck(); switch (state)//реализуем поведение в зависимости от направления. (каждая цифра соответствует направлению) { case right:dx = speed; break;//состояние идти вправо case left:dx = -speed; break;//состояние идти влево } sx += dx*time; sprite.setPosition(sx + (w / 2), sy + (h / 2)); if (health <= 0){ life = false; } } }; class Bullet :public Entity{//класс пули public: //enum { up, down } state; int direction; Bullet(Image &image, float X, float Y, int W, int H, String Name, float SX, float SY, int dir) :Entity(image, X, Y, W, H, Name, SX, SY){//всё так же, только взяли в конце состояние игрока (int dir) //obj = lvl.GetObjects("solid");//инициализируем .получаем нужные объекты для взаимодействия пули с карто x = X; y = Y; sx = SX, sy = SY; direction = dir; //state = up; speed = 1; w = W, h = H;; life = true; //выше инициализация в конструкторе } void update(float time) { switch (direction) { case 0: dy = -speed; break;//интовое значение state = up case 1: dy = speed; break;//интовое значение state = down } //state = up; //sx += dx*time;//само движение пули по х sy += dy*time;//по у if ((sy <= 0) | (sy >= 640)) life = false; sprite.setPosition(sx + w / 2, sy + h / 2);//задается позицию пуле } }; |