SFML и C++ Уроки \ Разработка игр › Форумы › SFML Graphics › не могу убить игрока
В этой теме 8 ответов, 3 участника, последнее обновление Serob 5 года/лет, 9 мес. назад.
-
АвторСообщения
-
Добрый день!
Спасибо Павлу за супер уроки, все очень понятно и доходчиво.
в общем вопрос не могу убить героя никак. герой может убить врагов прыжком а его никак. как быть помогите.
C++123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357#include <SFML/Graphics.hpp>#include <iostream>#include <sstream>#include <vector>#include <list>#include "level.h"#include "View.h"#include "tinyxml\tinyxml.h"using namespace :: std;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, int N){x = X; y = Y; w = W; h = H; name = Name;dx = 0; dy = 0; speed = 0; moveTimer = 0; health = N; // переменная N разное колличество жизней у монстров и игроковisMove = false; onGround = false;texture.loadFromImage(image);sprite.setTexture(texture);sprite.setOrigin(w / 2, h / 2);if (health <= 0) { life = false; }else {life = true;}}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 } state;//добавляем тип перечисления - состояние объектаint playerScore;//эта переменная может быть только у игрокаPlayer(Image &image, String Name, Level &lev, float X, float Y, int W, int H, int N) :Entity(image, Name, X, Y, W, H, N){playerScore = 0; state = stay; obj = lev.GetAllObjects();if (name == "Player"){sprite.setTextureRect(IntRect(32, 0, 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;}}}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; }}}}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;//и здесь тоже}x += dx*time;checkCollisionWithMap(dx, 0);//обрабатываем столкновение по Хy += dy*time;checkCollisionWithMap(0, dy);//обрабатываем столкновение по Ysprite.setPosition(x + w / 2, y + h / 2); //задаем позицию спрайта в место его центраif (health <= 0) { life = false; }if (!isMove){speed = 0;}//этим методом будем забирать координаты для камерыgetPlayerCoordinateForView(x, y);if (life) { getPlayerCoordinateForView(x, y); }/////заставляем прыгатьdy = dy + 0.0015*time;}};//////////////////////////// монстр ///////////////////////////////////class Monstr :public Entity{public:Monstr(Image &image, String Name, Level &lvl, float X, float Y, int W, int H, int N) :Entity(image, Name, X, Y, W, H, N){obj = lvl.GetObjects("solid"); //инициализируем.получаем нужные объекты для взаимодействия врага с картойif (name == "Monstr"){sprite.setTextureRect(IntRect(360, 22, 20, 20)); // координаты в спрайте монстра и его размерdx = 0.08;//даем скорость.этот объект всегда двигается}}void checkCollisionWithMapMonstr(float Dx, float Dy)//ф ция проверки столкновений с картой{for (int i = 0; i < obj.size(); i++) //проходимся по объектамif (getRect().intersects(obj[i].rect)) //проверяем пересечение игрока с объектом{if (obj[i].name == "solid") //если встретили препятствие (объект с именем 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); }}else { onGround = false; }}}void update(float time){if (name == "Monstr") {//для персонажа с таким именем логика будет такой//moveTimer += time; if (moveTimer>3000){ dx *= -1; moveTimer = 0; }//меняет направление примерно каждые 3 секx += dx*time;checkCollisionWithMapMonstr(dx, 0);//обрабатываем столкновение по Хy += dy*time;checkCollisionWithMapMonstr(0, dy);//обрабатываем столкновение по Yif (!isMove) speed = 0;sprite.setPosition(x + w / 2, y + h / 2); //задаем позицию спрайта в место его центраif (health <= 0) {life = false; }dy = dy + 0.0015*time;//делаем притяжение к земле}}};////////////////////////////////class hiMonstr :public Entity{public:hiMonstr(Image &image, String Name, Level &lvl, float X, float Y, int W, int H, int N) : Entity (image, Name, X, Y, W, H, N){obj = lvl.GetObjects("solid"); //инициализируем.получаем нужные объекты для взаимодействия врага с картойif (name == "hiMonstr"){sprite.setTextureRect(IntRect(77, 14, 59, 36)); // координаты в спрайте монстра и его размерdx = 0.02;//даем скорость.этот объект всегда двигается}}void checkCollisionWithMapMonstr(float Dx, float Dy)//ф ция проверки столкновений с картой{for (int i = 0; i < obj.size(); i++) //проходимся по объектамif (getRect().intersects(obj[i].rect)) //проверяем пересечение игрока с объектом{if (obj[i].name == "solid") //если встретили препятствие (объект с именем 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); }}else { onGround = false; }}}void update(float time){if (name == "hiMonstr") {//для персонажа с таким именем логика будет такой//moveTimer += time; if (moveTimer>3000){ dx *= -1; moveTimer = 0; }//меняет направление примерно каждые 3 секx += dx*time;checkCollisionWithMapMonstr(dx, 0);//обрабатываем столкновение по Хy += dy*time;checkCollisionWithMapMonstr(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;//делаем притяжение к земле}}};int main(){RenderWindow window(VideoMode(800, 600), "HER BAM");view.reset(sf::FloatRect(0, 0, 800, 600)); //размер "вида" камеры при создании объекта вида камеры. (потом можем менять как хотим) Что то типа инициализации.Level lvl;lvl.LoadFromFile("images/map.tmx");std::list <Entity*> entilist;std::list <Entity*>::iterator it;std::list <Entity*>::iterator it2; //второй итератор.для взаимодействия между объектами спискаstd::vector <Object> e = lvl.GetObjects("Monstr");std::vector <Object> c = lvl.GetObjects("hiMonstr");Image heroImage;heroImage.loadFromFile("images/sonic2.png");Image MonstrImage;MonstrImage.loadFromFile("images/02810.png");Image hiMonstrImage;hiMonstrImage.loadFromFile("images/02810.png");//easyMonstrImage.createMaskFromColor(Color(255, 0, 0));//сделали маску по цвету.но лучше изначально иметь прозрачную картинкуfor (int i = 0; i < e.size(); i++)//проходимся по элементам этого вектора(а именно по врагам)entilist.push_back(new Monstr(MonstrImage, "Monstr", lvl, e[i].rect.left, e[i].rect.top, 20, 20, 1));//и закидываем в список всех наших врагов с картыfor (int i = 0; i < c.size(); i++)entilist.push_back(new hiMonstr(hiMonstrImage, "hiMonstr", lvl, c[i].rect.left, c[i].rect.top, 57, 36, 100));//и закидываем в список всех наших врагов с картыObject player = lvl.GetObject("Player");//объект игрока на нашей карте.задаем координаты игроку в начале при помощи негоPlayer p(heroImage, "Player", lvl, player.rect.left, player.rect.top, 32, 32, 100);//передаем координаты прямоугольника player из карты в координаты нашего игрокаClock clock; // функция времениwhile (window.isOpen()){float time = clock.getElapsedTime().asMicroseconds();clock.restart();time = time / 500;// обязательная фигня для создания окна часть 1Event event;while (window.pollEvent(event)){if (event.type == Event::Closed)window.close();}for (it = entilist.begin(); it != entilist.end();)//говорим что проходимся от начала до конца{Entity *b = *it;//для удобства, чтобы не писать (*it)->b->update(time);//вызываем ф-цию update для всех объектов (по сути для тех, кто жив)if (b->life == false) { it = entilist.erase(it); delete b; }// если этот объект мертв, то удаляем его//if (p.life = false) { p.speed = 0.1; }else it++;//и идем курсором (итератором) к след объекту. так делаем со всеми объектами списка}for (it = entilist.begin(); it != entilist.end(); it++)//проходимся по эл-там списка{if ((*it)->getRect().intersects(p.getRect()))//если прямоугольник спрайта объекта пересекается с игроком{if ((*it)->name == "Monstr"){//и при этом имя объекта EasyEnemy,то..if ((p.dy > 0) && (p.onGround == false)) { (*it)->dx = 0; p.dy = -0.2; (*it)->health = 0; }//если прыгнули на врага,то даем врагу скорость 0,отпрыгиваем от него чуть вверх,даем ему здоровье 0//// тут игрок должен получить урон но нифигаelse p.health -= 10; //иначе враг подошел к нам сбоку и нанес урон{}}if ((*it)->name == "hiMonstr"){if ((p.dy > 0) && (p.onGround == false)) { (*it)->dx += 0.01*time; p.dy = -0.6; (*it)->health -= 25; } //если прыгнули на врага,то даем врагу скорость 0,отпрыгиваем от него чуть вверх,даем ему здоровье 0//// тут игрок должен получить урон но нифига //// тут игрок должен получить урон но нифигаelse p.health -= 50; //иначе враг подошел к нам сбоку и нанес урон{}}}}p.update(time);// обновляем камеруwindow.setView(view);// обязательная фигня для создания окна часть 2//window.clear(Color(77, 83, 140));//рисуем новую картуlvl.Draw(window);for (it = entilist.begin(); it != entilist.end(); it++){window.draw((*it)->sprite); //рисуем entities объекты (сейчас это только враги)}// обязательная фигня для создания окна часть 3window.draw(p.sprite); // переменная обновления Playerwindow.display();}return 0;}А собствено как вы его убивать собрались? Если вы хотели просто не давать камере следить за игроком то зачем тогда выстроена такая конструкция?
C++123//этим методом будем забирать координаты для камерыgetPlayerCoordinateForView(x, y);//Камера центрируется на игрокеif (life) { getPlayerCoordinateForView(x, y); }//Камера центрируется на игроке если он живчуть выше есть такое
C++1if (health <=0) {life = false;}этого не достаточно? с монстрами срабатывает!
игрок ходит мимо монстров и никак с ними не взаимодействует, может только “убить” прыгнув сверху.
Моожно посмотреть на значения переменных в момент пересечения. Должно стать ясно, почему код не заходит в ветку бокового столкновения с монстром. Например, так:
C++123456789101112if((*it) -> name == "Monstr"){std::cout << "intersection with Monstr, p.dy: " << p.dy <<", p.onGround: " << p.onGround << ", p.health: " << p.health << std::endl;if((p.dy > 0) && !p.onGround){(*it) -> dx = 0;p.dy = -0.2;(*it) -> health = 0;}else{p.health -= 10;}}пробовал отслеживать как сказали, терминал показывает примерно следующее
intersection with Monstr, p.dy: 0.049113, p.onGround: 1, p.health: -3400
intersection with Monstr, p.dy: 0.04953, p.onGround: 1, p.health: -3450
intersection with Monstr, p.dy: 0.069093, p.onGround: 1, p.health: -3500
intersection with Monstr, p.dy: 0.067749, p.onGround: 1, p.health: -3550изначально в первой строке терминала p.health всегда отрицательное и больше 3000 (эта цифра произвольная в диапазоне от минус 3000 до минус 9000).
Serob, теперь видно, что игрок получает урон от монстров. Если хотите, чтобы он исчезал с экрана, то нужно его добавить в список entities. Только сперва нужно подкорректировать переменную p.health. Вы говорите, что она может принимать значения от -3000 до -9000. В конструкторе класса entity есть строка if (health <= 0) { life = false; }. В функции update из класса Player у вас есть условие if (health <= 0) { life = false; }. Получается, что у игрока life всегда равна false. Лучше p.health задать равной положительному значению (например, 100), тогда после нескольких столкновений с монстром p.health станет отрицательной и p.life станет равна false. Когда вы пройдёте по списку entities, все у кого life == false, будут из него удалены и перестанут отображаться на экране.
в class Entity я объявил health=N. переменная “N” определяется в “int main” при создании игрока и монстра. у монстров “N=1″, а у игрока “N=100″
C++1234567891011121314151617class EntityEntity(Image &image, String Name, float X, float Y, int W, int H, int N)health = N; // переменная N разное колличество жизней у монстров и игроковclass Player :public EntityPlayer(Image &image, String Name, Level &lev, float X, float Y, int W, int H, int N) :Entity(image, Name, X, Y, W, H, N)class Monstr :public EntityMonstr(Image &image, String Name, Level &lvl, float X, float Y, int W, int H, int N) : Entity (image, Name, X, Y, W, H, N)int main()for (int t = 0; t < c.size(); t++)//проходимся по элементам этого вектора(а именно по врагам)entilist.push_back(new Monstr(MonstrImage, "Monstr", lvl, c[t].rect.left, c[t].rect.top, 20, 20, 1));Object player = lvl.GetObject("Player");//объект игрока на нашей карте.задаем координаты игроку в начале при помощи негоPlayer p(heroImage, "Player", lvl, player.rect.left, player.rect.top, 32, 32, 100);при изменении переменной N у монстра, жизнь монстра меняется, а вот жизнь игрока никак не работает.
сейчас писал это и до меня дошло Player у меня не в закидывается entilist он отдельно от него, но как тогда взаимодействует с монстрами? и почему p.health начинается с отрицательного числа?
Игрок взаимодействует с монстрами благодаря условию
C++1if((*it)->getRect().intersects(p.getRect()))в котором проверяется пересечение его прямоугольника с объектами списка entlist, то есть монстрами.
C++123456789101112131415161718class Entity{public:int health;//здесь идут все остальные параметрыEntity(int N, остальные параметры){health = N;//остальные параметры}};class Player: public Entity{public:Player(int N, остальные параметры): Entity(N, остальные параметры){//остальные параметры}};Player p(123, остальные параметры);std::cout << "p.health: " << p.health << std::endl;Если в классах так задавать здоровье, думаю всё должно быть нормально. Надо вывести в консоль здоровье сразу после создания игрока и потом смотреть, где оно может измениться (я так понял, оно меняется только при боковом столкновении с монстром).
cпасибо за помощь! разобрался у меня игрок умирал, только в классе управления игроком забыл дописать if (life) { тут код управления игроком} поэтому я мог игроком управлять.
в общем метод кота работает
еще раз большое спасибо за помощь!
-
АвторСообщения
Для ответа в этой теме необходимо авторизоваться.