From c655409596961ad6fd0a6108e5c77a45b7ac593d Mon Sep 17 00:00:00 2001 From: Kuba Date: Mon, 9 Dec 2024 16:48:31 +0100 Subject: [PATCH 01/18] =?UTF-8?q?Jakie=C5=9B=20dzia=C5=82aj=C4=85ce=20g?= =?UTF-8?q?=C3=B3wno=20Ale=20nie=20strzela=20chujek?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 5 ++++- headers/Enemy.h | 25 +++++++++++++++++++++++++ headers/Plansza.h | 7 +++++++ sources/Enemy.cpp | 36 ++++++++++++++++++++++++++++++++++++ sources/Plansza.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 headers/Enemy.h create mode 100644 sources/Enemy.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6eacb45..d09862e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,10 @@ add_executable(LotoStatek main.cpp headers/Size.h headers/Position.h headers/ObjectItem.hpp - sources/ObjectItem.cpp) + sources/ObjectItem.cpp + sources/Enemy.cpp + headers/Enemy.h +) if(WIN32) set(SFML_ROOT "${CMAKE_SOURCE_DIR}/lib/SFML") diff --git a/headers/Enemy.h b/headers/Enemy.h new file mode 100644 index 0000000..c9ec2a3 --- /dev/null +++ b/headers/Enemy.h @@ -0,0 +1,25 @@ +#ifndef ENEMY_H +#define ENEMY_H + +#include "Actor.h" +#include "SFML/System/Clock.hpp" + +class Enemy : public Actor { +public: + Enemy(int x, int y, std::string path); + + void shoot() override; + void move(float deltaX, float deltaY) override; + void moveLeft() override; + void moveRight() override; + void moveUp() override; + void moveDown() override; + bool isAlive() const; + void takeDamage(); + +private: + sf::Clock shootClock; + bool alive = true; +}; + +#endif // ENEMY_H diff --git a/headers/Plansza.h b/headers/Plansza.h index 0971823..9a46da7 100644 --- a/headers/Plansza.h +++ b/headers/Plansza.h @@ -2,6 +2,7 @@ #define PLANSZA_H #include "Meteor.h" +#include "Enemy.h" #include "RandomNumberGenerator.h" #include "SFML/System/Clock.hpp" #include "SFML/Graphics/RenderWindow.hpp" @@ -18,9 +19,12 @@ public: Plansza(unsigned int windowHeight,unsigned int windowWidth, sf::RenderWindow *mainWindow); Size getSize(); std::vector &getMeteors(); + + void spawn_meteor(); void update_meteors(); void update(); + void spawn_enemy(); private: Size size; Background background; @@ -29,6 +33,9 @@ private: sf::Texture meteorTexture1; sf::Texture meteorTexture2; sf::Clock spawnClock; + sf::Clock shooterSpawnClock; + std::vector enemies; + sf::Clock enemySpawnClock; std::vector meteors; sf::RenderWindow *window; }; diff --git a/sources/Enemy.cpp b/sources/Enemy.cpp new file mode 100644 index 0000000..db69af5 --- /dev/null +++ b/sources/Enemy.cpp @@ -0,0 +1,36 @@ +#include "../headers/Enemy.h" +#include "../headers/Bullet.h" + +Enemy::Enemy(int x, int y, std::string path) : Actor(x, y, path) { + hp = 1; // Przeciwnik ma 1 punkt życia + firerate = 1000; // Strzela co 1 sekundę + moving_speed = 2.0f; // Prędkość ruchu przeciwnika +} + +void Enemy::shoot() { + if (shootClock.getElapsedTime().asMilliseconds() >= firerate) { + bullets.emplace_back(position.x, position.y + 20, bulletTextureLeft); // Strzał w dół + shootClock.restart(); + } +} + +void Enemy::move(float deltaX, float deltaY) { + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); +} + +void Enemy::moveLeft() { move(-moving_speed, 0.0f); } +void Enemy::moveRight() { move(moving_speed, 0.0f); } +void Enemy::moveUp() { move(0.0f, -moving_speed); } +void Enemy::moveDown() { move(0.0f, moving_speed); } + +bool Enemy::isAlive() const { + return alive; +} + +void Enemy::takeDamage() { + if (--hp <= 0) { + alive = false; + } +} diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 5183a91..8e62473 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -67,7 +67,7 @@ void Plansza::update() { // generowanie nowego meteoru spawn_meteor(); - + spawn_enemy(); // utrzymanie meteorów i pocisków w ruchu for (auto& meteor : getMeteors()) { @@ -157,6 +157,41 @@ void Plansza::update() { ++meteorIt; } } + // Ruch i renderowanie przeciwników + for (auto it = enemies.begin(); it != enemies.end();) { + it->moveDown(); // Przeciwnicy poruszają się w dół + it->shoot(); + + // Rysowanie przeciwników + window->draw(it->getSprite()); + + // Usunięcie martwych przeciwników + if (!it->isAlive()) { + it = enemies.erase(it); + } else { + ++it; + } + } + + // Kolizje między pociskami gracza a przeciwnikami + for (auto enemyIt = enemies.begin(); enemyIt != enemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (enemyIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + enemyIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; + } + } + if (hit && !enemyIt->isAlive()) { + enemyIt = enemies.erase(enemyIt); + } else { + ++enemyIt; + } + } } // Meteor-related niżej @@ -183,6 +218,14 @@ void Plansza::update_meteors() { } } +void Plansza::spawn_enemy() { + if (enemySpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund + int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); + enemies.emplace_back(spawnX, -50, "../assets/img/enemy/enemy.png"); + enemySpawnClock.restart(); + } +} + Size Plansza::getSize() { return size; } From 44f4556fda62ab02d66e810126701bee0ef4bfaa Mon Sep 17 00:00:00 2001 From: Kuba Date: Mon, 9 Dec 2024 16:49:18 +0100 Subject: [PATCH 02/18] =?UTF-8?q?Jakie=C5=9B=20dzia=C5=82aj=C4=85ce=20g?= =?UTF-8?q?=C3=B3wno=20Ale=20nie=20strzela=20chujek?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/img/enemy/enemy.png | Bin 0 -> 18558 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/img/enemy/enemy.png diff --git a/assets/img/enemy/enemy.png b/assets/img/enemy/enemy.png new file mode 100644 index 0000000000000000000000000000000000000000..5ae8acc314af355534ce4b686ae99bd4a0d4962c GIT binary patch literal 18558 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 Date: Mon, 9 Dec 2024 17:36:57 +0100 Subject: [PATCH 03/18] Niby strzela, ale bez kolizji --- CMakeLists.txt | 2 ++ assets/img/bullets/enemy_bullet.png | Bin 0 -> 8535 bytes headers/Bullet.h | 2 ++ headers/Enemy.h | 14 +++++++++ headers/EnemyBullet.h | 14 +++++++++ headers/Plansza.h | 1 + sources/Actor.cpp | 12 +++++-- sources/Enemy.cpp | 47 ++++++++++++++++++++++++++-- sources/EnemyBullet.cpp | 18 +++++++++++ sources/Plansza.cpp | 24 +++++++++++++- 10 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 assets/img/bullets/enemy_bullet.png create mode 100644 headers/EnemyBullet.h create mode 100644 sources/EnemyBullet.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d09862e..56d75e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ add_executable(LotoStatek main.cpp sources/ObjectItem.cpp sources/Enemy.cpp headers/Enemy.h + headers/EnemyBullet.h + sources/EnemyBullet.cpp ) if(WIN32) diff --git a/assets/img/bullets/enemy_bullet.png b/assets/img/bullets/enemy_bullet.png new file mode 100644 index 0000000000000000000000000000000000000000..5574a54bfe36131185de7dedf79f78f96647a456 GIT binary patch literal 8535 zcmeHMc{J4R+aEhaBwHnnQP##R1~Zd=mnB;&31iGKjWN^Ah>)GKM^Yl$qas<8eT%Xe zQVNkJWho)4yhAsUhIzMQUV7Y|%0O0$QY^BT3 zCe2;D9IeH|B9bwAw#qc9Z$|72d8qO-idEl;J^uMJOBMfN)}%Y4N*ofdt^*oY=^kN1 zPsT&`CC!*ggzJHz_s2ABA^kx^&)Qv_x^n{HPyM+^6t9Ih1ny~Tc_laZQPN1%$lTTh z+c#ZRa&73nSS8!BS&cqZhQx;4z4|)MjYH-Psw;yqga)k1GfN2Q4y)o zw__QWjpA<$PV7Nh!Y}{;OE^(q-^x^9|BrN-Nu-}o)HG?)+1KW5TcIdoc<3U^t-$iE zwP3qV8~C_9Il^ATT>1OX>&X2I%JHG3rly3p+hH+f#r(ygpf4;FAI5WM!3Tao70NGu z9Dg9SxS+W(%A!}-WmhHxEVz!(oq)sBP71Q!S&|~yl!cKUc=q{ zNo#Fp*7lPuTLAb>^1DdGT1$;G;=A;xj?=k)t^Q((g-~&&8BE6qinGuJeYSBcr>$ujgFE3G(ch)-w_j zmv7Mvw~rGRQh1qg?u+rhpd?2`wOV5bJOOBD5-;^lAkc>-nlJl0*M)C3;Qo9998|)K zJYD(yyyr-qP~#?_BM}mm$KMs0C z*#hk{D>{41+n=;B`I)7|>X?~&W0N$@DffeFf{#zt+UjB|AxPWaotCDhC+5p+yR$@Q zdmXnh$KWVrWvm;;6|d||rZW2u0MO9(rDAa;JOkv4cPDyjf){HVz#yWVCis}D1t&Aec{@U=Id^ih)9Xe0-FBRFo++ zcPJc_qrXKW1 zd}OMH#h>tA^j|D6`GERjsZh8w3`!49_w_eg*U&J?M7KSqinm(<$CG9NzFO z-ismgJA@nVPk*X6&2u{)Hyjl2i6=8n>C92#e;d-+)WYgdk1Yz^iDc@w7nAJ2Su%)( zzsUMqY+IV`bbb$n>Ha6~->m=0ecPC6WnqCapy0f>!ZS6{1aFOxaiidfZkX+#2sON` zsv80h!MUjrAV`#|8w3T1sY29MU^s#+jH!mZ{RU;~MQ32WaQH1KCb%+@iG#x7Rgh>^ z6a-5kxIvIe6*vToN1-8VI5Yx_Q$xdGZrI--j?jqAuEcu&9@Q3<8xx9vQdL0{+*~0r zJRA){x~gFzSQWH71ncUmf=1xfR8{b*+fZ&ej1h%K#xl!EBxBw2P^y>vwqlELjINcb zCK#a%`%7ZwiDeL&4$L_~^m3#4(En1|5y^O426l^2xVnmpx*80LgsZ~TP)OuoM)r6b zo!N_9sBoCF3Tj)kRTvC29VWHdtxjbEY|EM1VDxEtEQ3O`qfk6G!COIrwmkn-TQDb- z8<5v>jX>15?K!;7Tw!2KJjh#f?Zf_rFCExZ zZHs=+DO>!RpHDv@J&D_s2?W}n78oqp~$cg`< z8L(~$bv#}j1#v~VF`EI7#zRm9ggOLWFnq8yyskTwM$^a3frvxY478K->L(XG6)<2`HeC#^jEUbtrg>sY&D?&gAa{ugWr}Irr%E) zbLnEPgwQ{i!e4wb$Nv9({i?(N=MW&!zk~cEe*dNGU%LJg1OLeQ-|qUCu7AY9KQjKe zyZ+DU0{(TF!h11yKt9Z)(pa-nAM=>S>1t+d0NC7mXV%@i%#`p@O-|4O0A8W3iv@5! zeK%9c#W1xn?DN;ry0vuYAE>puKutDac*vev=fT2}#kvun_0h4f-@hw&b=KCV zxH`S(-7PL5=}`UP&}cb%^K(CUCWaLdz+b?Uz^0!4U}CPOQp2|#P>>Kz`cepzZ!2w_ z?d5dPE+Gtd6yb7OC^yvKh)FAn`DhnfNpW$<=38+qh~(rM-8qtu8bC9iB)xoSF|vAK zdGD9z(%uchCYHkr(PvDYkKEcjcP|he-NnYlxYf({rTJ64Ls&nssMdDK!TKWK>r)5f z_uPiOo0Bh=5SREdTgxN0SEq*`xw&&sGCaCZJ{ty#|0KdGoE;ob^GxsHXkSfnS0j%! z1WM`%I9V%sDYOqv^o5BPwL)IRm71Wb(8@R?X27Ez>{|8A|0hB5J>dC zg0fi&F|^Yry#f@JlN%tW3zzFoYjY)YXhN@Wjv=Y-C<*X&d@i)xJ0mo$uBMKv7)?%{a%?#ERhNyXB?T}sIdbVvJuvy1ep-sN+0L2af zWq^?gEJiSYuVj~>;{McTEvevfw&*@qIP7bv>YYfldk2D>?s#Xb-Z3h_7+|2VvZrY9 zo+^uAW7IhNUACMEjiu~lJ%tGFixtDKYRim5&BWQS_aG-V8+Y6z0iNI8>y$05EiW=z z)taTN5J3;UsGn{q?Gdh{?*ZxyeS9ZL);E>Aho^_I-}G>bpA-*YU9l?FlkuR}qptFn zgJf|sF0>KUlZY23L3#+124_6d6CMGRS67vK5+AmbNRoD?<~wguN4stYo>~qOYaqRy z9(9(4d|Zo+;R}t}qYV^v)&419X9>>?JFE=Jv$O zvE8rAXvu zTAYSqq8OkDbIk;~%cnGR$S`lWpfL+JQ!_?LXP=IH(@u`LUS%y@?pguo7IUJJ`P#r8 z-AP4-=asp7(P_taTRhd_zdzd5WCs)?8sxpSC~{ccOGW~zL$0>Ys|u!3<$1z|rF7c6 z{^Ah*kbZWfUd|9%tEZLt;#JdPvMJ{?o>+B0%tG$Hduj2s5EycIkSU zT45IA9tR@;u@jTVH3Ivpday+hvuip7LosJ~& zJPA+kG;i)=*e z?M`*C*K4iT9OG^7@qG6j?Y^HDF6=amnDsR4m^%^}A|iJqeCYZ{&<~aRuU9%B%(QD0 zK2Ed^`1#Ei4|bSGJuX_?WgN10=1VEWOnkI=&>c1XI;g{cbS)4V!D@T?@~iu+XES_1 zSo`^J$Y1UJys}2uIqcaG1ex@frn_3A2~GJHC)XA<70rD;2RqOauy5E+9b;o*PIe=# zXnmN_vAa5?ZhZmIiEM#luN0SWGYNsMJG39B*8gC!JikHotgX0OdcN{#*6_iW7ko2_ z{1(Hzm<`A1Ht=O3p>L1#Zo0mHct|k(^09+6hmJYxSJXUucc*83A(`s6I)t3H=3 zL91l?lo|BFT#p>(Peh{>&;^9%;I6Rqr>0zmUm?{nv}r-!@!{KvwB55L(bZ!yZ73Zj zfN@U0iwl(-$JaYQ+D+c9iw^^;6mJ$oPqo0Z)k;csly}LEtk;Lhvs-+)H1{4ttc@uG!{VT+z zcM7tPA$9RVJLdRLBL@H;D!_i>lfV_$P?KNXl3#JctYkzqV-h+j7(}qE?iX?=a=-T zEBCo<8q3c1h%iQPnlt+8HIR;hN0-KCc-lpGcY>1WX2X0t3-SDnl4ML-U{o2qkzmC1 z-I!iSzo&v6na8~Y_nC01HRXFd+fUsncLn&bEf^Zio+t^X<(_=_JXs*nmoHD4c>O-* zc^Q3fjBqpweQmdPFgIiEb4liVE772S9cTrICTeE5#=S~FkEoa8oG{FnBce>tF%}J; z=z-s!&lf1In?K?yYibK@0|$LwZ|LwzQ+=}*G#&tum3_3{hD+P|@veQ!^QKhW{r2}K z3*}6bI3KZpYs$N+^%fJjnPk@g^3r~uLseS3DQX(N#L(_tjy(ZsAjbd$mIAAm!`-I` zo7g8)ZjL@GcCRCxdf=xj=Hwg5+uTt7p)>u{bk%rz$$FykHNUUQ2(H4TZub2h!q1{$ zPGXYZ9%IhVznn@~ZW>H4p9mj9+s9?}P;LZ;Bz!pJQ#xN?F}(k=u4j2-B|queF{HQu z0shKPo{RDs36FW(rKVR;Qm`u*9?4%-`nGcHNBoh%Ih(^%i1XjIATO$yPk1%F8G|`& zROXA=@S4hARAYFjyi;75%BWe$3|cX?t06g_>8^OSJh|dgg#Lab#}0!j=pCqDULCoZ zf3sPU_Q{?qn!aLpeF%Hj;3!z>svQ?HU5qPQX9m)tW-BV(t5GTV&Y^j{IYJo7ar?FE zlPka;^jWQqgJU(*htIyEOT_Wz3uR>xv-LtUGL$2~-nKgw&DFoNITTdm|SEqjcuRHA3E)0>>zph>r9C%CpMz;_!Qc;UPG-O+!&VX0N(c_@EW49CMe5`3%2 z-WA#x28ENlr;oU zH2H+NKWuPS8HV1GL#SaicCvqsd3|bXj3-X{@W_%5fjoMKUQ|yhGnL$J0gimxJauXC z%;iJ!ZCSVOd^%J4qUL7a<_&s%ZdrZ8QxhAz&3m>deGh`0Gav#j3pWLKdz*Z{jFGOm z{;m~17~J*oYNL8_y?-bD9#1fH-^r^q^(7uBwiX|r^_Z;6bsPO0Ji1v>8Q!J>TTgjG z3>(ryKYnSs?mvDosY?6QXthvkH&;+9(l#@nv{P7uI?Dml9IDhkeJ+f2dxx zpZK<4&AISspq;XiD1(!cj5FVv9mgW*nKC8NYOTP{H5b77V6`M4u5^{LX>Hs(GSR5A z4?5KJWEth4S$%^`Z86iI%2VMG2jg}?HrND~)K--1%}myHAHDaydT~a3CWW#IdGj_0 z5_A=9D6^bHb5QU*WGDGXKNJM!1`B}8!Ysggrw7M*^am-m>1!*YS9g-_cXK$@A(#03 z3#Mlz-hWwxYBuvUe5^@dEmqmHZ(r{5gRWi6+O{N!ii*mI;rbgZB+6veNWK2SjmNa+ ztU~WXktg@Fg{RmK&wI(LzgfMI7u*3T$ZK3^;c#Sg;|LL)aktJe{d^;09C zGZ>;~DL0$Pv)ewet_rpbhElK#qZKjkm6WM>7Z%*t^hpX&oI(RS~X-Ei=}cJh4*cu?8jv>kcpUG)2;Fkz=YK1$Q%?BIIYNC!!;U(ktj^Q$C7z9ON#Y zf!%`BC@r_gV$<~$hzD8}<&Z}Ynat&p@Xy}r=Wxdn)9jX_&Rtg@Rk>w?5O5^ulDK2F zA97hrXH&uQ9~ZA5PXlv5d0A^QM^#=n2-A_dtU2NPdFgZ}b&3JL8N(*Rfw`v`9*}Y5 zx>tTg^642 z^t&XXpssh}cZyFm81j>Zx6ZuvBD^&M7pWQcKslhnIf!)7+0|V1M)MDbZD5(NZw;yY(wWp>+y162%TT*Y&o2t_N<;wQ!PrIz;dJ6VS zjXoede=jM6r&Z2x-kjp~-}V0OzPwLOR2C)RdyRrr+x6I()5HYwm_tXpYs)ll~%gqa>FD?;k7jM_xe7T}n25)!t zEdOehsUU7KVz_A|2J;u1SEu*+&|k979lNkhnCX7&UC}=Z-81(NRfcB@J1LqyyCje_tG{L!u^yNxO-%f0Tjd>I-CwZ?}Vv$4I znVAold#caiLM<;%221NkUZLLAxnLt~zVn#p&_%(A!J*|%x2HX%=R+*Au310%uz(7wFq}Z9GG1NHb7s83FxoALF8LQk5rTW?hOpw*Rp + Actor::Actor(int x, int y, std::string path) { loadTexture(path); position.x = x; @@ -29,13 +31,17 @@ std::vector &Actor::getBullets() { } void Actor::updateBullets() { - for (auto& bullet : bullets) { - if(bullet.isOutOfBounds()) { - bullets.erase(bullets.begin()); + for (auto it = bullets.begin(); it != bullets.end(); ) { + if (it->isOutOfBounds()) { + it = bullets.erase(it); // Usuwa element i zwraca iterator na następny element + } else { + ++it; // Przechodzi do następnego elementu } } + std::cout << "Liczba pociskow: " << bullets.size() << std::endl; } + void Actor::setMovingSpeed(float speed) { moving_speed = speed; } diff --git a/sources/Enemy.cpp b/sources/Enemy.cpp index db69af5..7404e50 100644 --- a/sources/Enemy.cpp +++ b/sources/Enemy.cpp @@ -3,28 +3,71 @@ Enemy::Enemy(int x, int y, std::string path) : Actor(x, y, path) { hp = 1; // Przeciwnik ma 1 punkt życia - firerate = 1000; // Strzela co 1 sekundę + firerate = 2000; // Strzela co 1 sekundę moving_speed = 2.0f; // Prędkość ruchu przeciwnika + enemyBulletTexture.loadFromFile("../assets/img/bullets/enemy_bullet.png"); } void Enemy::shoot() { if (shootClock.getElapsedTime().asMilliseconds() >= firerate) { - bullets.emplace_back(position.x, position.y + 20, bulletTextureLeft); // Strzał w dół + Bullet bullet(position.x, position.y + actorSprite.getGlobalBounds().height / 2, enemyBulletTexture); + bullet.setSpeed(10.0f); // Prędkość w dół + bullets.emplace_back(std::move(bullet)); shootClock.restart(); } } +void Enemy::updateDirection() { + // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + if (position.y <= 0) { // Górna krawędź ekranu + direction = Direction::Down; // Zmieniamy na ruch w dół + } else if (position.y >= 800) { // Dolna krawędź ekranu + direction = Direction::Up; // Zmieniamy na ruch w górę + } + + // Podobna logika dla kierunku lewo/prawo, jeśli przeciwnik będzie się poruszał w poziomie + if (position.x <= 0) { // Lewa krawędź + direction = Direction::Right; // Zmieniamy na ruch w prawo + } else if (position.x >= 1200) { // Prawa krawędź + direction = Direction::Left; // Zmieniamy na ruch w lewo + } +} + void Enemy::move(float deltaX, float deltaY) { actorSprite.move(deltaX, deltaY); position.x += static_cast(deltaX); position.y += static_cast(deltaY); } + + void Enemy::moveLeft() { move(-moving_speed, 0.0f); } void Enemy::moveRight() { move(moving_speed, 0.0f); } void Enemy::moveUp() { move(0.0f, -moving_speed); } void Enemy::moveDown() { move(0.0f, moving_speed); } +void Enemy::update() { + // Sprawdzamy, czy przeciwnik dotarł do krawędzi i zmieniamy kierunek + updateDirection(); + + // Zgodnie z kierunkiem, poruszamy przeciwnikiem + switch (direction) { + case Direction::Up: + moveUp(); + break; + case Direction::Down: + moveDown(); + break; + case Direction::Left: + moveLeft(); + break; + case Direction::Right: + moveRight(); + break; + } +} + + bool Enemy::isAlive() const { return alive; } diff --git a/sources/EnemyBullet.cpp b/sources/EnemyBullet.cpp new file mode 100644 index 0000000..67955fd --- /dev/null +++ b/sources/EnemyBullet.cpp @@ -0,0 +1,18 @@ +#include "../headers/EnemyBullet.h" + +EnemyBullet::EnemyBullet(float x, float y, sf::Texture &texture) + : Projectile(x, y, texture) { + speed = 5.0f; // Ruch w dół (dodatnia prędkość) +} + +void EnemyBullet::update() { + sprite.move(0.0f, speed); // Przesuwanie pocisku w dół + position.y += speed; + + if (position.y > 800) { + outOfBounds = true; + } +} +void EnemyBullet::setOutOfBounds(bool status) { + outOfBounds = status; +} \ No newline at end of file diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 8e62473..d9f3a7b 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -159,7 +159,7 @@ void Plansza::update() { } // Ruch i renderowanie przeciwników for (auto it = enemies.begin(); it != enemies.end();) { - it->moveDown(); // Przeciwnicy poruszają się w dół + it->update(); // Aktualizacja kierunku i ruchu przeciwnika it->shoot(); // Rysowanie przeciwników @@ -173,6 +173,28 @@ void Plansza::update() { } } + for (auto& enemy : enemies) { // Lista przeciwników w grze + enemy.shoot(); + enemy.updateBullets(); + for (auto& bullet : enemy.getBullets()) { + bullet.update(); + window->draw(bullet.getSprite()); + } + } + + // Usuwanie pocisków, które są poza ekranem + for (auto enemyIt = enemies.begin(); enemyIt != enemies.end(); ) { + for (auto bulletIt = enemyIt->getBullets().begin(); bulletIt != enemyIt->getBullets().end();) { + if (bulletIt->isOutOfBounds()) { + bulletIt = enemyIt->getBullets().erase(bulletIt); // Usuwamy pocisk, który wyszedł poza ekran + } else { + ++bulletIt; + } + } + ++enemyIt; + } + + // Kolizje między pociskami gracza a przeciwnikami for (auto enemyIt = enemies.begin(); enemyIt != enemies.end();) { bool hit = false; From a81cf284d0a9172dd891a7347fcf1bd33620dee1 Mon Sep 17 00:00:00 2001 From: Kuba Date: Mon, 9 Dec 2024 23:09:44 +0100 Subject: [PATCH 04/18] Strzela z kolizja --- CMakeLists.txt | 2 -- headers/EnemyBullet.h | 14 ----------- headers/Player.h | 3 +++ sources/Actor.cpp | 2 +- sources/Enemy.cpp | 23 ++++++++--------- sources/EnemyBullet.cpp | 18 ------------- sources/Plansza.cpp | 56 ++++++++++++++++++++++++++++++++++++++--- sources/Player.cpp | 24 ++++++++++++++++++ 8 files changed, 91 insertions(+), 51 deletions(-) delete mode 100644 headers/EnemyBullet.h delete mode 100644 sources/EnemyBullet.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 56d75e3..d09862e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,8 +30,6 @@ add_executable(LotoStatek main.cpp sources/ObjectItem.cpp sources/Enemy.cpp headers/Enemy.h - headers/EnemyBullet.h - sources/EnemyBullet.cpp ) if(WIN32) diff --git a/headers/EnemyBullet.h b/headers/EnemyBullet.h deleted file mode 100644 index ce733db..0000000 --- a/headers/EnemyBullet.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef ENEMY_BULLET_H -#define ENEMY_BULLET_H - -#include "Projectile.h" - -class EnemyBullet : public Projectile { -public: - EnemyBullet(float x, float y, sf::Texture &texture); - void update() override; - - void setOutOfBounds(bool status); -}; - -#endif // ENEMY_BULLET_H diff --git a/headers/Player.h b/headers/Player.h index e6b4c01..b4e0fd3 100644 --- a/headers/Player.h +++ b/headers/Player.h @@ -17,11 +17,14 @@ public: void moveRight() override; void moveUp() override; void moveDown() override; + void takeDamage(); + bool isAlive() const; std::vector& getRockets(); private: std::chrono::steady_clock::time_point lastShotTime = std::chrono::steady_clock::now(); std::vector rockets; sf::Texture rocketTexture; + int health = 3; // Liczba punktów życia gracza sf::Texture bulletTexture; }; diff --git a/sources/Actor.cpp b/sources/Actor.cpp index 6ee0d0b..cff3f5d 100644 --- a/sources/Actor.cpp +++ b/sources/Actor.cpp @@ -38,7 +38,7 @@ void Actor::updateBullets() { ++it; // Przechodzi do następnego elementu } } - std::cout << "Liczba pociskow: " << bullets.size() << std::endl; + //std::cout << "Liczba pociskow: " << bullets.size() << std::endl; } diff --git a/sources/Enemy.cpp b/sources/Enemy.cpp index 7404e50..0aca9ab 100644 --- a/sources/Enemy.cpp +++ b/sources/Enemy.cpp @@ -3,8 +3,8 @@ Enemy::Enemy(int x, int y, std::string path) : Actor(x, y, path) { hp = 1; // Przeciwnik ma 1 punkt życia - firerate = 2000; // Strzela co 1 sekundę - moving_speed = 2.0f; // Prędkość ruchu przeciwnika + firerate = 2000; // Strzela co 2 + moving_speed = 2.0f; // Prędkość enemyBulletTexture.loadFromFile("../assets/img/bullets/enemy_bullet.png"); } @@ -19,17 +19,17 @@ void Enemy::shoot() { void Enemy::updateDirection() { // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi - if (position.y <= 0) { // Górna krawędź ekranu - direction = Direction::Down; // Zmieniamy na ruch w dół - } else if (position.y >= 800) { // Dolna krawędź ekranu - direction = Direction::Up; // Zmieniamy na ruch w górę + if (position.y <= 0) { + direction = Direction::Down; + } else if (position.y >= 800) { + direction = Direction::Up; } - // Podobna logika dla kierunku lewo/prawo, jeśli przeciwnik będzie się poruszał w poziomie - if (position.x <= 0) { // Lewa krawędź - direction = Direction::Right; // Zmieniamy na ruch w prawo - } else if (position.x >= 1200) { // Prawa krawędź - direction = Direction::Left; // Zmieniamy na ruch w lewo + // logika dla kierunku lewo/prawo + if (position.x <= 0) { + direction = Direction::Right; + } else if (position.x >= 1200) { + direction = Direction::Left; } } @@ -50,7 +50,6 @@ void Enemy::update() { // Sprawdzamy, czy przeciwnik dotarł do krawędzi i zmieniamy kierunek updateDirection(); - // Zgodnie z kierunkiem, poruszamy przeciwnikiem switch (direction) { case Direction::Up: moveUp(); diff --git a/sources/EnemyBullet.cpp b/sources/EnemyBullet.cpp deleted file mode 100644 index 67955fd..0000000 --- a/sources/EnemyBullet.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "../headers/EnemyBullet.h" - -EnemyBullet::EnemyBullet(float x, float y, sf::Texture &texture) - : Projectile(x, y, texture) { - speed = 5.0f; // Ruch w dół (dodatnia prędkość) -} - -void EnemyBullet::update() { - sprite.move(0.0f, speed); // Przesuwanie pocisku w dół - position.y += speed; - - if (position.y > 800) { - outOfBounds = true; - } -} -void EnemyBullet::setOutOfBounds(bool status) { - outOfBounds = status; -} \ No newline at end of file diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index d9f3a7b..2a9d147 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -22,6 +22,7 @@ ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow- audioManager.loadSoundEffect("shoot_alt", "../assets/sounds/shoot_alt.ogg"); audioManager.loadSoundEffect("fail", "../assets/sounds/fail.mp3"); + meteorTexture1.loadFromFile("../assets/img/meteors/meteor-1.png"); meteorTexture2.loadFromFile("../assets/img/meteors/meteor-2.png"); spawnClock.restart(); @@ -124,6 +125,38 @@ void Plansza::update() { } } + + if (!ship.isAlive()) { + std::cout << "Game Over! Player is dead." << std::endl; + std::cout << "You lost the game!\n"; + sf::RenderWindow errorWindow(sf::VideoMode(350, 200), "The end"); + sf::Font font; + if (!font.loadFromFile("../assets/fonts/arial.ttf")) { + std::cerr << "Error loading font\n"; + exit(-500); + } + sf::Text text("Your ship is destroyed!", font, 24); + text.setFillColor(sf::Color::Red); + text.setPosition(50, 80); + + // zatrzymanie muzyki i odtworzenie dźwięku przegranej + audioManager.playSoundEffect("fail", 70.f); + audioManager.stopBackgroundMusic(); + sf::Event event{}; + while (errorWindow.isOpen()) { + while (errorWindow.pollEvent(event)) { + if (event.type == sf::Event::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) { + errorWindow.close(); + window->close(); + exit(-2); + } + } + errorWindow.clear(); + errorWindow.draw(text); + errorWindow.display(); + } + } + for (auto meteorIt = getMeteors().begin(); meteorIt != getMeteors().end(); ) { bool meteorHit = false; for (auto rocketIt = ship.getBullets().begin(); rocketIt != ship.getBullets().end(); ) { @@ -157,12 +190,11 @@ void Plansza::update() { ++meteorIt; } } - // Ruch i renderowanie przeciwników + // Ruch i render przeciwnika for (auto it = enemies.begin(); it != enemies.end();) { - it->update(); // Aktualizacja kierunku i ruchu przeciwnika + it->update(); // Aktualizacja kierunku i ruchu it->shoot(); - // Rysowanie przeciwników window->draw(it->getSprite()); // Usunięcie martwych przeciwników @@ -173,7 +205,23 @@ void Plansza::update() { } } - for (auto& enemy : enemies) { // Lista przeciwników w grze + for (auto& enemy : enemies) { + for (auto it = enemy.getBullets().begin(); it != enemy.getBullets().end();) { + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + // Kolizja wykryta + std::cout << "Player hit by enemy bullet!\n"; + + ship.takeDamage(); + + // Usuwanie pocisku + it = enemy.getBullets().erase(it); + } else { + ++it; // Brak kolizji, przechodzimy do kolejnego pocisku + } + } + } + + for (auto& enemy : enemies) { enemy.shoot(); enemy.updateBullets(); for (auto& bullet : enemy.getBullets()) { diff --git a/sources/Player.cpp b/sources/Player.cpp index 91117cf..e5315b0 100644 --- a/sources/Player.cpp +++ b/sources/Player.cpp @@ -1,4 +1,10 @@ #include "../headers/Player.h" + +#include +#include +#include +#include + #include "../headers/Bullet.h" Player::Player(int x, int y, std::string path) : Actor(x, y, path) { @@ -22,6 +28,24 @@ void Player::alternate_shoot() { } } +void Player::takeDamage() { + if (health > 0) { + health--; + std::cout << "Player hit! Remaining health: " << health << "\n"; + + + if (health <= 0) { + std::cout << "Player has been destroyed!\n"; + std::cout << "You lost the game!\n"; + + } + } +} + +bool Player::isAlive() const { + return health > 0; +} + void Player::setFirerate(unsigned int firerate) { this->firerate = firerate; } From 77eb83c2c38a88d8a4428c4aa03793a5c0f68449 Mon Sep 17 00:00:00 2001 From: Kuba Date: Mon, 9 Dec 2024 23:36:50 +0100 Subject: [PATCH 05/18] enemy kolizja rakiet --- headers/Rocket.h | 1 + sources/Plansza.cpp | 21 +++++++++++++++++++++ sources/Rocket.cpp | 3 ++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/headers/Rocket.h b/headers/Rocket.h index 37503f7..1707559 100644 --- a/headers/Rocket.h +++ b/headers/Rocket.h @@ -7,6 +7,7 @@ class Rocket : public Projectile{ public: Rocket(float x, float y, sf::Texture &texture) : Projectile(x,y, texture) {}; void update() override; + }; diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 2a9d147..18dd01b 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -262,6 +262,26 @@ void Plansza::update() { ++enemyIt; } } + //oblsuga dla rakiety + for (auto enemyIt = enemies.begin(); enemyIt != enemies.end();) { + bool hit = false; + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (enemyIt->getSprite().getGlobalBounds().intersects(rocketIt->getSprite().getGlobalBounds())) { + rocketIt = ship.getRockets().erase(rocketIt); + enemyIt->takeDamage(); + hit = true; + break; + } else { + ++rocketIt; + } + } + if (hit && !enemyIt->isAlive()) { + enemyIt = enemies.erase(enemyIt); + } else { + ++enemyIt; + } + } + } // Meteor-related niżej @@ -293,6 +313,7 @@ void Plansza::spawn_enemy() { int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); enemies.emplace_back(spawnX, -50, "../assets/img/enemy/enemy.png"); enemySpawnClock.restart(); + } } diff --git a/sources/Rocket.cpp b/sources/Rocket.cpp index a5ae223..39af7af 100644 --- a/sources/Rocket.cpp +++ b/sources/Rocket.cpp @@ -6,4 +6,5 @@ void Rocket::update() { if(position.y < -100) { outOfBounds = true; } -} \ No newline at end of file +} + From 81b04bae0f544b7777e71533630dd05a9ac1bb44 Mon Sep 17 00:00:00 2001 From: Kuba Date: Tue, 10 Dec 2024 20:20:05 +0100 Subject: [PATCH 06/18] Dziuala 3 strzlowiec --- CMakeLists.txt | 2 + headers/Actor.h | 2 +- headers/AdvancedEnemy.h | 38 +++++++++++++ headers/Enemy.h | 2 +- headers/Plansza.h | 16 +++++- headers/Player.h | 3 +- main.cpp | 11 +++- sources/Actor.cpp | 7 ++- sources/AdvancedEnemy.cpp | 89 +++++++++++++++++++++++++++++++ sources/Enemy.cpp | 3 +- sources/Plansza.cpp | 109 ++++++++++++++++++++++++++++++++++++-- sources/Player.cpp | 12 +++-- 12 files changed, 279 insertions(+), 15 deletions(-) create mode 100644 headers/AdvancedEnemy.h create mode 100644 sources/AdvancedEnemy.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d09862e..c301c75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ add_executable(LotoStatek main.cpp sources/ObjectItem.cpp sources/Enemy.cpp headers/Enemy.h + headers/AdvancedEnemy.h + sources/AdvancedEnemy.cpp ) if(WIN32) diff --git a/headers/Actor.h b/headers/Actor.h index 7fc1ec6..fe05f3a 100644 --- a/headers/Actor.h +++ b/headers/Actor.h @@ -9,7 +9,7 @@ class Actor { public: - Actor(int x, int y, std::string path); + Actor(int x, int y, const sf::Texture& texture); void loadTexture(std::string path); diff --git a/headers/AdvancedEnemy.h b/headers/AdvancedEnemy.h new file mode 100644 index 0000000..09fe88f --- /dev/null +++ b/headers/AdvancedEnemy.h @@ -0,0 +1,38 @@ +#ifndef ADVANCED_ENEMY_H +#define ADVANCED_ENEMY_H + +#include "Enemy.h" +#include + +enum class DirectionA { + Up, + Down, + Left, + Right +}; + +class AdvancedEnemy : public Actor { +public: + AdvancedEnemy(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture); + + void shoot() override; + void move(float deltaX, float deltaY) override; + void moveLeft() override; + void moveRight() override; + void moveUp() override; + void moveDown() override; + + void update(); + + bool isAlive() const; + void takeDamage(); + void updateDirection(); + +private: + sf::Clock shootClock; + sf::Texture enemyBulletTexture; + float movementSpeed = 2.0f; + bool alive = true; + DirectionA direction = DirectionA::Down; +}; +#endif // ADVANCED_ENEMY_H diff --git a/headers/Enemy.h b/headers/Enemy.h index 4af000d..bb7c81f 100644 --- a/headers/Enemy.h +++ b/headers/Enemy.h @@ -13,7 +13,7 @@ enum class Direction { class Enemy : public Actor { public: - Enemy(int x, int y, std::string path); + Enemy(int x, int y, const sf::Texture& texture) ; void shoot() override; void move(float deltaX, float deltaY) override; diff --git a/headers/Plansza.h b/headers/Plansza.h index 1fb9d2a..4173def 100644 --- a/headers/Plansza.h +++ b/headers/Plansza.h @@ -3,10 +3,12 @@ #include "Meteor.h" #include "Enemy.h" +#include "AdvancedEnemy.h" #include "RandomNumberGenerator.h" #include "SFML/System/Clock.hpp" #include "SFML/Graphics/RenderWindow.hpp" #include "Size.h" +#include #include "Player.h" #include "Background.h" @@ -16,7 +18,8 @@ class Plansza { public: - Plansza(unsigned int windowHeight,unsigned int windowWidth, sf::RenderWindow *mainWindow); + Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::RenderWindow *mainWindow, + const sf::Texture& playerTexture, const sf::Texture& playerBulletTexture, const sf::Texture& playerRocketTexture); Size getSize(); std::vector &getMeteors(); @@ -26,6 +29,9 @@ public: void update(); void spawn_enemy(); void setOutOfBounds(bool status); + + void spawn_advanced_enemy(); + private: Size size; Background background; @@ -33,10 +39,18 @@ private: AudioManager audioManager; sf::Texture meteorTexture1; sf::Texture meteorTexture2; + sf::Texture enemyBulletTexture; + sf::Texture playerTexture; + sf::Texture playerBulletTexture; + sf::Texture playerRocketTexture; + sf::Texture enemyTexture; + sf::Texture advancedEnemyTexture; sf::Clock spawnClock; sf::Clock shooterSpawnClock; std::vector enemies; + std::vector AEnemies; sf::Clock enemySpawnClock; + sf::Clock AenemySpawnClock; std::vector meteors; sf::RenderWindow *window; }; diff --git a/headers/Player.h b/headers/Player.h index b4e0fd3..721d761 100644 --- a/headers/Player.h +++ b/headers/Player.h @@ -8,7 +8,8 @@ class Player : public Actor { public: - Player(int x, int y, std::string path); + Player(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture, const sf::Texture& rocketTexture); + void setTextures(const sf::Texture& shipTexture, const sf::Texture& bulletTexture, const sf::Texture& rocketTexture); void shoot() override; void alternate_shoot(); void setFirerate(unsigned int firerate); diff --git a/main.cpp b/main.cpp index a794292..6c612bc 100644 --- a/main.cpp +++ b/main.cpp @@ -6,6 +6,13 @@ int main() { std::clog << "Game started\n"; + sf::Texture playerTexture, playerBulletTexture, playerRocketTexture; + if (!playerTexture.loadFromFile("../assets/ship/Dreadnought-Base.png") || + !playerBulletTexture.loadFromFile("../assets/img/bullets/bullet_pink.png") || + !playerRocketTexture.loadFromFile("../assets/img/rockets/Rocket_111.png")) { + std::cerr << "Failed to load player textures!" << std::endl; + return -1; + } sf::RenderWindow mainWindow(sf::VideoMode(600, 800), "LotoStatek"); mainWindow.setVerticalSyncEnabled(true); mainWindow.setFramerateLimit(60); @@ -14,7 +21,9 @@ int main() icon.loadFromFile("../assets/img/icon/ikonka.png"); mainWindow.setIcon(128, 128, icon.getPixelsPtr()); - Plansza plansza(mainWindow.getSize().y, mainWindow.getSize().x, &mainWindow); + + + Plansza plansza(mainWindow.getSize().y, mainWindow.getSize().x, &mainWindow,playerTexture, playerBulletTexture, playerRocketTexture); while (mainWindow.isOpen()) { mainWindow.clear(); diff --git a/sources/Actor.cpp b/sources/Actor.cpp index cff3f5d..5770cbd 100644 --- a/sources/Actor.cpp +++ b/sources/Actor.cpp @@ -2,8 +2,8 @@ #include -Actor::Actor(int x, int y, std::string path) { - loadTexture(path); +Actor::Actor(int x, int y, const sf::Texture& texture) { + actorSprite.setTexture(texture); position.x = x; position.y = y; actorSprite.setOrigin(actorSprite.getLocalBounds().width / 2, actorSprite.getLocalBounds().height / 2); // wycentrowanie sprite @@ -19,6 +19,9 @@ void Actor::loadTexture(std::string path) { } sf::Sprite &Actor::getSprite() { + if (!actorSprite.getTexture()) { + std::cerr << "actorSprite has no texture set!" << std::endl; + } return actorSprite; } diff --git a/sources/AdvancedEnemy.cpp b/sources/AdvancedEnemy.cpp new file mode 100644 index 0000000..44be9ee --- /dev/null +++ b/sources/AdvancedEnemy.cpp @@ -0,0 +1,89 @@ +#include "../headers/AdvancedEnemy.h" +#include "../headers/Bullet.h" + +AdvancedEnemy::AdvancedEnemy(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture) : Actor(x, y, texture) { + actorSprite.setTexture(texture); + enemyBulletTexture = bulletTexture; + hp = 2; // 2 punkty życia + firerate = 2000; // Strzela co 2 + moving_speed = 2.0f; // Prędkość + enemyBulletTexture.loadFromFile("../assets/img/bullets/enemy_bullet.png"); +} + +void AdvancedEnemy::shoot() { + if (shootClock.getElapsedTime().asMilliseconds() >= firerate) { + Bullet Cbullet(position.x, position.y + actorSprite.getGlobalBounds().height / 2, enemyBulletTexture); + Cbullet.setSpeed(10.0f); // Prędkość w dół + bullets.emplace_back(std::move(Cbullet)); + + Bullet Lbullet(position.x - 20, position.y + actorSprite.getGlobalBounds().height / 2, enemyBulletTexture); + Lbullet.setSpeed(10.0f); // Prędkość w dół + bullets.emplace_back(std::move(Lbullet)); + + Bullet Rbullet(position.x + 20, position.y + actorSprite.getGlobalBounds().height / 2, enemyBulletTexture); + Rbullet.setSpeed(10.0f); // Prędkość w dół + bullets.emplace_back(std::move(Rbullet)); + + shootClock.restart(); + } +} + +void AdvancedEnemy::updateDirection() { + // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + if (position.y <= 0) { + direction = DirectionA::Down; + } else if (position.y >= 800) { + direction = DirectionA::Up; + } + + // logika dla kierunku lewo/prawo + if (position.x <= 0) { + direction = DirectionA::Right; + } else if (position.x >= 1200) { + direction = DirectionA::Left; + } +} + +void AdvancedEnemy::move(float deltaX, float deltaY) { + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); +} + + + +void AdvancedEnemy::moveLeft() { move(-moving_speed, 0.0f); } +void AdvancedEnemy::moveRight() { move(moving_speed, 0.0f); } +void AdvancedEnemy::moveUp() { move(0.0f, -moving_speed); } +void AdvancedEnemy::moveDown() { move(0.0f, moving_speed); } + +void AdvancedEnemy::update() { + // Sprawdzamy, czy przeciwnik dotarł do krawędzi i zmieniamy kierunek + updateDirection(); + + switch (direction) { + case DirectionA::Up: + moveUp(); + break; + case DirectionA::Down: + moveDown(); + break; + case DirectionA::Left: + moveLeft(); + break; + case DirectionA::Right: + moveRight(); + break; + } +} + + +bool AdvancedEnemy::isAlive() const { + return alive; +} + +void AdvancedEnemy::takeDamage() { + if (--hp <= 0) { + alive = false; + } +} \ No newline at end of file diff --git a/sources/Enemy.cpp b/sources/Enemy.cpp index 0aca9ab..9319e39 100644 --- a/sources/Enemy.cpp +++ b/sources/Enemy.cpp @@ -1,7 +1,8 @@ #include "../headers/Enemy.h" #include "../headers/Bullet.h" -Enemy::Enemy(int x, int y, std::string path) : Actor(x, y, path) { +Enemy::Enemy(int x, int y, const sf::Texture& texture) : Actor(x, y, texture) { + actorSprite.setTexture(texture); hp = 1; // Przeciwnik ma 1 punkt życia firerate = 2000; // Strzela co 2 moving_speed = 2.0f; // Prędkość diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 18dd01b..19727cb 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -3,15 +3,20 @@ #include "../headers/Plansza.h" #include "../headers/ObjectItem.hpp" -Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::RenderWindow *mainWindow) +Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::RenderWindow *mainWindow, + const sf::Texture& playerTexture, + const sf::Texture& playerBulletTexture, + const sf::Texture& playerRocketTexture) : background("../assets/img/background/background.png", 2.0f), -ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow->getSize().y) - 100, "../assets/ship/Dreadnought-Base.png") +ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow->getSize().y) - 100, playerTexture, playerBulletTexture, playerRocketTexture) { window = mainWindow; size.height = static_cast(windowHeight); size.width = static_cast(windowWidth); + + ship.setMovingSpeed(8); ship.setFirerate(200); @@ -23,8 +28,19 @@ ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow- audioManager.loadSoundEffect("fail", "../assets/sounds/fail.mp3"); + meteorTexture1.loadFromFile("../assets/img/meteors/meteor-1.png"); meteorTexture2.loadFromFile("../assets/img/meteors/meteor-2.png"); + + // Ładowanie tekstur wrogów + if (!enemyTexture.loadFromFile("../assets/img/enemy/enemy.png")) { + std::cerr << "Failed to load enemy texture!" << std::endl; + exit(-1); + } + if (!advancedEnemyTexture.loadFromFile("../assets/img/enemy/advanced_enemy.png")) { + std::cerr << "Failed to load advanced enemy texture!" << std::endl; + exit(-1); + } spawnClock.restart(); } @@ -69,6 +85,7 @@ void Plansza::update() { // generowanie nowego meteoru spawn_meteor(); spawn_enemy(); + spawn_advanced_enemy(); // utrzymanie meteorów i pocisków w ruchu for (auto& meteor : getMeteors()) { @@ -204,6 +221,58 @@ void Plansza::update() { ++it; } } + for (auto it = AEnemies.begin(); it != AEnemies.end();) { + it->update(); // Ruch zaawansowanego przeciwnika + it->shoot(); // Strzał przeciwnika + + window->draw(it->getSprite()); // Rysowanie na ekranie + + if (!it->isAlive()) { + std::cout << "Advanced Enemy has been eliminated." << std::endl; + it = AEnemies.erase(it); // Usunięcie martwych przeciwników + } else { + ++it; + } + } + // std::cout << "Current AEnemies size: " << AEnemies.size() << std::endl; + // Obsługa pocisków zaawansowanych przeciwników + for (auto& aEnemy : AEnemies) { + for (auto it = aEnemy.getBullets().begin(); it != aEnemy.getBullets().end();) { + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + ship.takeDamage(); // Zadanie obrażeń graczowi + it = aEnemy.getBullets().erase(it); // Usuwanie pocisku po trafieniu + } else { + ++it; + } + } + } + + for (auto advancedIt = AEnemies.begin(); advancedIt != AEnemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (advancedIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + advancedIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; + } + } + if (hit && !advancedIt->isAlive()) { + advancedIt = AEnemies.erase(advancedIt); // Usunięcie przeciwnika AdvancedEnemy + } else { + ++advancedIt; + } + } + + for (auto& advancedEnemy : AEnemies) { + advancedEnemy.updateBullets(); // Obsługuje pociski zaawansowanych przeciwników + for (auto& bullet : advancedEnemy.getBullets()) { + bullet.update(); + window->draw(bullet.getSprite()); + } + } for (auto& enemy : enemies) { for (auto it = enemy.getBullets().begin(); it != enemy.getBullets().end();) { @@ -282,6 +351,26 @@ void Plansza::update() { } } + for (auto advancedIt = AEnemies.begin(); advancedIt != AEnemies.end();) { + bool hit = false; + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (advancedIt->getSprite().getGlobalBounds().intersects(rocketIt->getSprite().getGlobalBounds())) { + rocketIt = ship.getRockets().erase(rocketIt); + advancedIt->takeDamage(); + hit = true; + break; + } else { + ++rocketIt; + } + } + if (hit && !advancedIt->isAlive()) { + advancedIt = AEnemies.erase(advancedIt); + } else { + ++advancedIt; + } + } + + } // Meteor-related niżej @@ -309,14 +398,26 @@ void Plansza::update_meteors() { } void Plansza::spawn_enemy() { - if (enemySpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund + if (enemySpawnClock.getElapsedTime().asSeconds() >= 6) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); - enemies.emplace_back(spawnX, -50, "../assets/img/enemy/enemy.png"); + enemies.emplace_back(spawnX, -50, enemyTexture); + enemySpawnClock.restart(); } } +void Plansza::spawn_advanced_enemy() { + if (AenemySpawnClock.getElapsedTime().asSeconds() >= 5) { // Spawn co 10 sekund + int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); + AEnemies.emplace_back(spawnX, 50, advancedEnemyTexture, enemyBulletTexture); + std::cout << "Spawned Advanced Enemy at X: " << spawnX << std::endl; + AenemySpawnClock.restart(); + } +} + + + Size Plansza::getSize() { return size; } diff --git a/sources/Player.cpp b/sources/Player.cpp index e5315b0..f3b3810 100644 --- a/sources/Player.cpp +++ b/sources/Player.cpp @@ -7,11 +7,16 @@ #include "../headers/Bullet.h" -Player::Player(int x, int y, std::string path) : Actor(x, y, path) { - bulletTexture.loadFromFile("../assets/img/bullets/bullet_pink.png"); - rocketTexture.loadFromFile("../assets/img/rockets/Rocket_111.png"); +Player::Player(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture, const sf::Texture& rocketTexture) : Actor(x, y, texture), bulletTexture(bulletTexture), rocketTexture(rocketTexture) { + }; +void Player::setTextures(const sf::Texture& shipTexture, const sf::Texture& bulletTexture, const sf::Texture& rocketTexture) { + this->actorSprite.setTexture(shipTexture); // Poprawiona nazwa - actorSprite zamiast shipSprite + this->bulletTexture = bulletTexture; + this->rocketTexture = rocketTexture; +} + void Player::shoot() { auto now = std::chrono::steady_clock::now(); if (std::chrono::duration_cast(now - lastShotTime).count() >= firerate) { @@ -20,6 +25,7 @@ void Player::shoot() { } } + void Player::alternate_shoot() { auto now = std::chrono::steady_clock::now(); if (std::chrono::duration_cast(now - lastShotTime).count() >= firerate) { From 2234e4d973a21ba4d2f6e9d536fe03978a7e79e4 Mon Sep 17 00:00:00 2001 From: Kuba Date: Wed, 11 Dec 2024 16:33:24 +0100 Subject: [PATCH 07/18] Dodanie bombera --- CMakeLists.txt | 2 + assets/img/bullets/bomba.png | Bin 0 -> 11688 bytes assets/img/enemy/advanced_enemy.png | Bin 0 -> 11914 bytes assets/img/enemy/wiazkowiec.png | Bin 0 -> 8117 bytes headers/AdvancedEnemy.h | 1 + headers/Bomber.h | 41 +++++++ headers/Plansza.h | 8 +- sources/Bomber.cpp | 78 ++++++++++++++ sources/Plansza.cpp | 160 ++++++++++++++++++++++------ 9 files changed, 255 insertions(+), 35 deletions(-) create mode 100644 assets/img/bullets/bomba.png create mode 100644 assets/img/enemy/advanced_enemy.png create mode 100644 assets/img/enemy/wiazkowiec.png create mode 100644 headers/Bomber.h create mode 100644 sources/Bomber.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c301c75..34a32e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,8 @@ add_executable(LotoStatek main.cpp headers/Enemy.h headers/AdvancedEnemy.h sources/AdvancedEnemy.cpp + headers/Bomber.h + sources/Bomber.cpp ) if(WIN32) diff --git a/assets/img/bullets/bomba.png b/assets/img/bullets/bomba.png new file mode 100644 index 0000000000000000000000000000000000000000..6f09bde5ba7c15c065691487ee928457b00d3004 GIT binary patch literal 11688 zcmeHtcT`i`)^7+%S9&joB25CJ7b#K#geFLr8bW|bNq_*M_pTryAYDK~iU_E5kS2&o z6QxL(Do6(bX)k)tJ@?%4zA@goW4!OblZ>6c_gr)S)||gN=Nfw@i8IjGyiCqY4gdfy z!?e_I2HJsp$duCO%5{SJBRdNUiI00rNb@8JvrM8e%b?IfYlg}6lW2jK0f2A`o5Z~ zlio`w#k*MN|Ivvwl6JxImR`}tvy73p7m3ad%ofaP2O^SWAtz$-F*sdy(ptz}c-NvT zS;Xe-`!5wXZ>lzruk57~d*sfP^rA%=CMOx`Go4pDSU$Ka0g`y)ZV+YN^A2V3(6H2e z-NkGE?u{acmaW(m3mx($PiFvtAQGjfW&l%D`&UHxIC6rL6}38VvcI)8dRmxv#fRGC zodHLeh|pK_GIJt|r_YDVB6^?N4n5(5d3exUQCtZYHs!F&@%F|r5VccLJCX21nFM!2 zU!jmh~41Gzo!eT#-Rt0**~zU3Uobyf%qcCB=!5?enwN?xz&L+9vRp-_-; zbr{*}g4HyVmKQRitG{273Zh z)!<+-hI46`YsAM%ZuBUg@+2xlMKY}zAfCdHi5XHBNG>8~r?cLE6O<8TCh@m*JwZ^C zeg{5}b_=;W>9bC>txRZkr^nU>=#~FOM*hwsDXAMF(-?=|455f`=sdr*IIrgJ2z@+s z?(ANxAQj~_@XW;>y%Ch71h81UdrT}VOVq9Nuw`>+vvqUkTybP`izNP;XBEpQtyz5K z`JnI>X0E3zk3hSLz#Y)`ND-XduQ~((6qIooIKl;q1=%B=Q0|J{TTO4cK_~}BZZj!8 zh#p1_>5S6y_e2``>l-8dT@Z2(+{#Mi3OIQ@fEyAE2jSdY-M!>-irl|(4w z-zr!aMQ(FF1CScp6A6+OkraV|p*WO}IJXixNWs&=QU12N#-9-QJ4J41EEXd#D(dU& zE8;65g7$P06_b;b6NQM2ii?Bs8elI!cPtzScK71>1@Q-lI?@Z_iNat}Xm`*rOt?MT z8>`68jUNa7%Re`ap59;Z?p}YgfagOL2gitti9kf%+(iFw;f00z;6eU$=zp~EGR8Nm z=xwAI+S?O>g!&-eu{?i=a6tTJkMZ_&{T+@2LKNwWbi=E9;b#^5k0~`_dIo=4{Gz}K z<%aofg(v$zG_fehf0OkezWo~c9nRk!!JGeu`ybl>iv71TUQ16;ULB3_{^cG_U6K3O z{PGTH1j<4F_a#DH%pM{EaR5t0?Crsl4sxhW#kZGI8sIqjJHNe$RfpLBpqb_264+1g|AAu z>)*Zl1?7N;LW(Ed_?lI!b|MB@hrf2RK|xQcUbOlmkLu1MTSs z$EOqJ26sY=V%(j65BwrrUc~^W$Sp1c`M1Qt6^?bp8{m5Y`){*90gi>M!?8#_C`4RRUQAqGOw3qJS{@=HFD`Z+ zA|?;{n?BkB<>>eS(*D&xAca4Yu7&c#&+qqJ^hZw_AwB-M`{ULX^}CrspxG0c6Jk}pW2xqvv6B56E{8_O7lB52IVvxpHkc0z73T!Vci2zGV$clmC5IH$~ zJvquC5DpL|T=Ea{{zCUcJ7Rs|o=6oZJdb#;@CEvtE0DmSsS^B8Z+xARzw&^m3@j!N z{u^c7qJIV}`fJ7bSF{SE{}&$$zZL$r#Nh4zkl~ju{7NYL*HZW=UwB{tH(!6|;eT@q z5a^#t{wsd}q3a*I{woIlE9HNx>mR!QD+c~6<$tQ{{~KN8|K3a?-SJOAzWA+DFoP2f zew#&XucN6BxcK#c+)|Q?mylt!EW7{!3c6nh0U#@f880Nk!t|gdtCSQ}gbb*>(mMbE zhapT|#TfTxBiAp`+B@@N)=Am-miuTetnq17`fVR=3nCT6Z5hhDA1ZY!=*G!blGm2oM?N=q)-P=DRu0xE zQUV70k@Sl$GkPn<;VG+bOKXW9y|;sq%d zXn3b&s*sg@t2U47Q%&N{9O!wny-sr2J_9~Y)I!E!w&Rnjy`C^jv6T& z$*$)37QDRm^+n9wLJhYk*2sCIy1$^QmF7YIPbS0qD$fsPKj!Gth3{-UH%wQ5WvQ5S zkhoqbT`wtpJvMy1Vc?1z?3DQdn-zP{jdN+}>CEu`pZR02G!w@N$q_)A!?qu+l{$)c zBJ#JUZKg;x6E;dLU!2A z5AWc{k(MD&!Y!Q=&8Ne*4;b^ zXdl)%HHyDuKd^?G-yNlrXo;y%< z2xfUH=W4W91g4gvT0y}o(#3x+E<(L~Z=6Yn>{Ttv62HF9Rg30*Ai?X;e06G$gGRun z+DF2xrWWUpY=Uc`cOu#^3GzZMX=wkOa&1e_Cdchz1if5e%q=ryt&xbcSb-i+@q|Zg4t6d)ZsqI-HXD5XzCMt2M z5)KvBXlxtX$&cqHLqTaZFB!gTva`sGA+aDx!98(Pc)1w1ki6A5J}9Z=mh-t;Lv2f_ zP_)0mo17F#8XsUsx7{WM{m^_gPvOHeb}R2w31U>bo=k@HvveKK+_Llaf1XU-~@phgc&$Y3Yp>uQ}^0>`xb5P8L*~5aA->x*rb8Ed#_HL*2JVN`#R{=@4Q!h zTcBnTW5ZETBS|%?11#y`-PwO2T$!}$slaGV7Gt6c7BBEgzL^~}x(MoFfATni-os#0 zN6U~xW&du#U6K0e$k&$qXMv%~E028utMD2PwH0k=V{yweD1Jy+3WxbVNzc~x;Oeg!(1I_KJ zy@}R}`PPj)lR?;8_vO#&Bzc6VSB_>wrHNkU)aQ(d+{icClD)e0VZm?8bZCsTr!rDw z_NtHAj~tj|s#dj`8l%)JQwl@x63xeRsm>+F_j1K;23*>H324jAT zu7TTLr`hJzZ3+MzyFYLF^9*AEp(VCcDr%Bly91^Gn?Mx*oAYmH!W=Nq3Jbfl>>{j9 z3KS)xchQ^Hqly4&wVH9Y=z$tO!!a?vS{u5uB%@@lpT;V3tRt0Xc-@5{|x702*zuX8e&9uThxg#j^Q7_xKWW9`6U zU#6iXWs|+Cd_9b0Ta*(==R`?m@pC!iQ1}GVL7aT`-5ahyJB=Q;9=LFaK88KnB`$)} zmCQl|wHG5@Nn6x3E{~J&4bWl8Y4fD%Lcp09epBw)YZ z655)mDa9>s)SL|@bPl9)s8t?n^HihTWy*zd z=VosQ=%w{CYMXEp8_C(YlJ4x;Dm2etwchZvT7Fca0M-~0B);8M`5vi1TqiEJ_+4*b z5mQ6X6GDUgI-_f7GV~Q(Hr{N&H(E+-19~il6SgTCqBb*g4;jWS9u_?vJVT}h_mQ!s zc3bg4$gzZ6k1xlj%`QknC>M7~en@Ulkoy(bJ$P$vO|;+EH8tVQ!omSxnFFDNI$_Ow zg%ZiUGDYCN| zRI}a}raxe(`Lr%ml7K$-Gh2MWV7w5OW~o=lN%kEu030RcC+K-dmVMB3`05rXS2V_5@w z^)vZZRz8=6=U3SJMI3fsJr>DjG<#2! zMKH2@;;Il)m^p8J<+?!pJ>lzGg|VVrgn2Ow^5*IH-7FU=qRgdNn%Wbi68NqS?kV_e zeu;9M3@lxlb{&_Oo!?_fm}KUJjeMk^9|*`>+?zd~K1vFqv@*LAF66(q&J^Fl&tTV6 zE6HNU)2yoI4iRjoFT6H}?ZxAGElU@8%{GHEf_B5c~@3*}FfwlrZ4p?)wgS;rE1;GHtK&5ZFVg zm7?y|9A_X9S?TgD{>})~CJPH!b{|(fcb4>VL#A%Dx=`=stM#$3HNAI+MlAUPgYoOp z>0wZaN(zzt*^J_Xlh}D)(DJOm9bDqnz{?75SvH;#;i_q1$%7K<9soof_BC&-OH19Z znq_Bqzk23%*Vdl}%0HlU***;epX@B<8HOfTc+Eh*cRfJ2Sb3$vOWXloa( zP1m(_8X{&tV`OK9U!5}YY`R3z$H5By7-A3qo(%DEp;Y*~yM4>+`_WZ`>s%i{J{@LE zS3Z|Bd~|?xehGaHJf#b+9=IG|C@He}-J!qi^Q*eobd*HYkzY)1OxE@;d+t+F9{FXJ z6|T$Ytt9uY9NrkMbrT7m?sYEPG9Trfe(RO}v#iH;Myx9%7$+NrCJwIRz z?%Q^60ah3et84LARnB3I6m{`WWJ+Bd2JP0Xc6!&XxAJy(S|%d(;O1TZI?T|Fu*ieB z63!1-_Gi%Z4oJpsAUK@Y$}ov2k3fNBiVt>s;p>2i>2rnn?r05O)Uvj9fw_ZlGAL6w zMU=5@)U1D!+)sC8>V#O3oWOeJkV^4Z>#F8gH$6kj5l76e6xY_SH-UQ@0`aP5PW;n- z=}94_N`$W-TCdpKc@UT$9tmCXuxKnR)$7sL-dA$2fm_ZGBu&n&^jL2e+qZMctj^P` zD;VB1d#ikTX+t6}SY+?}P&a!PXjoY1>V+8rvKBg%sY<9s63FI^Lc1YgW*PaZWHH6b zleKz6xs|ji3&wW42X>J9Bo}aji+rH~Hz}~dE|x!U_QQ4_(X{nO7q<$dsOxgZp<-u# z{zOMh5*og=>yFjaOh;m^c`~&PO+6^*&PhOLfT^?43keyDip_g>^Ig#QAACXXeovUV z{4K?6KFIEV_SXmDoLAjqQRtqa%4}}U0Bx;JJYn!YKrN@ug>dDfp8a_OuFHbR49g|cyR5zsO zo+rJfbU~|pwy`i?8zn$aN*Z{qc{n`tMcc^8=pfK~1jb7zn`mT+YpvRPZ3QA5^X^ew zuZBu*X*osjj!ukq=I!(-07@wo++*+7P`i*lVE2%%ytZ2^`orn@NxMSdL2!zAZWKX} zqG2dPKjMWFV8&IUJX5{k1wk-@q)bn?`Or+TR;8yW*kh}ux5n!A``)=mk)k*;RyNil zsZWtBezJ)Y<-Cb?ue7`F2r$N}a~o}Mm{dITKM()m^JVf&l`9)Oe=BDjut=8l z7^M()#fmlzCvI)0*}HlCaQ)2jy%tM!MNW&5%y(|t-Pn>1Wit=ODI5=FY%sK~g4#S` zu!;SM?6Ih2P2_ShAA1j1ns$HII{U3q<8yrzlVo199uEP=gw)wcfldBW6JcGGhl0I? zd_=0>jl?*ju2-|yGF8|HckH;!4@qTLeXg~Rhf(zK@pJ35l1>3;z30^wgWr3P3vbiT zHHD71U|Hrd%zd>mzSNhruXKOR@g!?WJ&4mNI~TsIVYq{Zb;4_}+;;KZ$BifNqEuW@+z zWh#tF;wQl6Y2FO+OAm9&(g0Blkg%~fF0X_j;<_SvZRnxlVR6HyNK1MhXiWnnNZe?)c~ReC~zP45YG9+wwI zXvy9~Sv>iOQW#V-c{o93*Ud$H#Y}3@Tryr5HeTDmI&SX$f#T9(UF&H*udNBaq<6>? ze|Dc(y6(M<5qI{Iu6LZxF7z|QgqFpA4cTsO0uzrCM-rCmHM4Fq9Em=D{rYJX4ly-2 zcw4a9^Wn2~Q8XQ~3Uw?rsNIqt`t`mC?=Zi|;5*V{6fLDL`-y8$vANKO_lx=MC&@0h zA-12xch((6STgdg96IX)=FFt5Hhm}rCPYdD3kC(2`+4;2s4&_B%uiZgUmo*@CGxzW zwQHVw_JElzCP<~Zl*}S!MvL1H;Ug~4p&>z$uFy=Bjz9cqU~rvY>1&n6m>y>3{OGEH3C(ju|nKfU&kNLV4me zFViOfQp=KA;0Zi{FZFb@rR_^-B^}zetJcl4VTvGiqw})$*s$b%jI6FKJ72DTYX1tx zI>SoomPo#nEB2nQyiv=5YPFVh#sT_H$~W_RXVvYIsZSr?tum*(1u@n~e1qoEUBZo* zs-zt#X^f76~hV)K&gExy^i=Ss0%gB`niFh zOUlR;yn7#Pf77XlyY}!$E%55w7mJm8kuiGi_oEtK>dl$lv{aMS5TGwK7J_dq$d?P% z8!JPnQ+R1eiB?y?FM>0gqn4(powK^f$C{^i|1|e ziO>Z6;)~^bX*=DE%hXW>8m>B+e;RIoJ!UQQTuhFh+~X&UQ!VkeCTTveEcxKhiw7S&pz*VsaR)jB8_OGM%Zc)QE68O zoB1|(DwCu9x_p|AI@fHAh?7uKy8E<{*DJmmt*{n1V=N@K;Kc;K)8)a>u8e$asxfUj z*Lz-14Qvyq5-Dt|G?J02^62bVlMgxjd0=#fZb|-=(Rywh;!I{BX|Wg?=6*Il$Dw>O z5h?g2t7j;>RL4j)nBy+b!YI!uPnb?yeuEFYQ%B(JC&ty${>#iyX{nSY_h?fI<7n4r z8oHJabmwkwzy0=&cHt9E7{K;;H-m+ZEql0O;`^u6D+~KG3a!R0$hf48-%$uG5EUiFP zA7h^1+Bd?*CX>T2CWA!rX=^KYcHa=f+%(C3&%QEE1&-+5OH9=7^maUcZ`LZlQBYG! zcN{Od{Q2f%q@}l?T9U#(B%@_v>$o2stj4E!{AsGzZSv?tiE^iHen?ou6#@(!8*Aj- zTpCb`dCo#$c+u3Wjw;zU`2Ub&y zCVi30b+s6MGR>XHE7GukTO?#`>2vr@Qs5$w!pZlSf%CQaJx#^)rXqwHLrH=EH3OoL zX_<$2)~&Ro4b5a;etlL{zt&==_pIBLKFUa6E^6}4Pm@v35GyyL%{0oG^~|;mp;6=V z8^USY-f8+)xcMj}Q}V6_kII(K#;i5J?x(zG_?$&+-vOnKWsL!g5-X~nK0OZ2udA!u zD@Y1<;Nx`ERHQos8d!&$xIEW6r;c2l=r;d4cc9MytHa-jruG6KwRQXRZNtWIh?R|+ zi?7NKJY3(pBE#vw-5$aD(yl!m<;OBvE68$9_T8wAH%%8{(4_2<)9pRK$9MWV<4W>y zDVN!#b$Lz{Wy6rWZD@b9F(TmUOpP#Q=S{UMBnO{dVCC);W7(}N@y|8$Qm4&NrvB) zns9BSx9fzT1u&6sbA%dyd9h1=$z|)_s^5bFhqaEh0s3O3$vZZpV9Tws8+mP)+gduC zd=ZnQ3qgZo zW_K+ZC(odwa;M%jPa7P<03k%2Z0wvJwHuzw>zS9XeZw}2IBifxCbvi&+g`#ygJiO7VQ|E@(t~C~3Wsh_F3N>La=9Bv+>P zs5QeRjyEOlz2|Pvc0h4Ii!KAwA&hI%L!`3)w%&+9nzn>Cjn!Bu!F%OJg!C z^0rHDtJlMBZnI^+=w;e1CnU%X<-BS1Iiiw7;X$@gns%`0kbIoJTMvBlhg(|sG8G`? zkqc_Dowyhh9I?r8y~&K4lIYYu>SSNHoM9e=(@<@9?Kn{IKk>gFggK8;TOBeUBnqDe zY{FnEtfoG`MWw98C{s)Q0s68s+WYE>u~PndJ(cb4@n3hTG3QqAj_-OGd=}%xb?r4@ zq-vL>nF~i3mp#jhhBHg>4STT1Km7=2YEv9UV4R<+&QP?i@Azshq-on-dyV_#JzZCP zTksm5z*3>cVv}_>C-P27F-k&<6dNCxsh(YF;0wa;N1e}>;tqgRO?d&|%()AqBe<~E z{EydhIP=jDCQM`Ab`O-j-GZ& zJ>8KmNIy$bnzkPsfr$zKldJeIFVc0ZoE)C)mY-}(O|RfCA!-HcRFh#2EXK2o< zO4~>6gQbt1r4WQsLL3WS)JyoE1qUm4b1E+fdq+26FEN_`Wmxzh{hyeVMqJbtVlAvC zEB`+l|2Q!kTX%P7VNOm@Pfrd{9u6m08%}N^At6pK5GM%4{!fG5&D+u4+>71OjrM;G z$XdBsxXFLaqKq@t;d^ZqffW z{{P5CIsXgf{|Zd}|CjuG)_>IhM&>`5{x`Z-j{hL_{D&P|S{4Qz99x{CtkefDlaqY! zHY2(0H;LxF+0oV1TrmjFqM{x`SeTBayF5QGF+g9ogekVCC@wSsGYS=6zn`U~I)RG` zm8Lmk!?CPDnWaOqxz}}PSS?Y?gj(_FaRYB{T&yoKT z>T-e=(d$R*QH;-glR7$l0N_z8`cU8AT^Py>YHSb-`gA#kO z=*@rx3!25mcBL*HcI@n&$q?EerRmtP`(?0F^w;0B-S706QR^WxII&WQy4QPB+}WT8 zrQ2sa9j9Flt&%1=)YvpCdRt7=P<&iwC|6~cJ+7QpOB66dBWKI-c~y!DVu3Cx?l3B*|H_${%`R_1zLy;^m9hCxg1~9L2LS zLqT|~2!3cVC9P}+d%r7O`47x__JqvzS^zdE%Ndf&0ntlUpRMyd+Fr2$TZ{d)WSjxQW74V18IYMP81Aj*V&RjH07B6Sa7XCK`Xb>ciBuR*238J`<{kW;QZwG5_?F16&>GjS3#BETrKjRucsa zPh#`l*T05^({*}+n`$h3Uvz#$T4lcEYw)I;v}R#Bi7K*?1fd>$iRg_iP`ayox$kfA z1e%Yq`)Fu{YX!rOdTgs3AS*~(=wV9hbNL;P)ZN^3*L=n zb@Gu`3xQrT%H5?o(AL&YQ|njCgtm}UcAn`88noV#EWBUXb<$@Vof7SI7K{f~ z#W@Qn2t#mXfVhnPYW;IeO>C|)7~%m{e`IUTxN@WbPprpHlR6;m6=3$^30URncpZ`&p0c11Q^QzNPgPd4*yy6v5IHP_@-dUYpS3Lanr|~o)qggi$ zES;i6^l=#;mu6%+6;w88J2(swm|TnFzad7D{>)ViFwaOR4>VgQ!E&mg<_Y} zYiE*Rbi;wgyZu;$x`k8%!c0KBupd7E_B2CsoCn40c{gTwLk6;td)U=W&m}Nyw~59Ix{QWqlG{`%00^fuOwf*zZV|w#!_FbG0iYgWjGqyiOb^l;Wze zW%K|P0DRwX+@*Ud)M82El$P8YPBGZRC&tS^AClOZu@YMBv58V#B&6Tn-melASr%y4 zT6xsZ21ND?f1xjG?r{MaC^uy=(JL(p&^7$70jCQfQsHty^!lsD#M|Qs0`n9z$6V(8 zRX?cbjcza}UYwfpRs@=3#^Zg$EQ_0LZtWO)j2}u)raf=oJGslC8is=>46YNOaR+53 z61U%oH(WVYc&{1rvUkK+o|j&7z$Kx#%>1}l1aYnor@4zj4{zeAu^Yyy>BJS) z4+eC{p-~A)Xh+Mmw0vHoeUvFZ+E@b9Aby)-$Wbu)(cJ36eI$aY{M*Ky**NaweCDfh zOEq$O;S_pFEu7BgoaVrdoGg;5n=Exg^dZuQXTlI9Rj^A|QnV*s~Nu!&YLYNE%~$W5|Z0p{-|X%9-YJ!bN>pU4PQuW6df8ASsFgJB3L zjzTO2(r14Bnwgq&Dd>OeR|xOhIdrl9NYJ;_YILa*a8S%MOcIObN+sQ(RsT6ZbN~fG zy2L{V3^wjxy5x|YY>1_?Y|7fADnWiwwK0{mnh~sL2{Tba27E?YjDmz`{Yv2=_*`*i zUD!jFCZpi#=FJ0_^V2Z7Y#O9$VUVgqwRlJsW@sMW-aujQJzhzV`tCoP2| zDuq*Tw25Vy}-=bOq+r0 zcWC`zE%)<1DU_J;q5=8&`C;=zJSScZ7-~7Vv=Q8&j|JruDaOw?`}H{^xG$rAf>rO| z-MlL-wT2<&#LX(Jq5)>_vh}odgHnpp4?6k37J=W_Tb3U&**Y5F#_NO;cj8$GS>taU=;guM=`W1eu#Cwb0U9EM+P8th- z?O-AdG+Fg^6uT=HMgXnw8HNmJRPVs*`wf!FZ+Cm+BtUdc2+0`9%N5Q~1hv2%ws`|# z5s|~$3Y;!e(jkVho~E0wk#*3X)<_d^?wCSIM9|J;m9qaqAvk3l)1HNI;z`Ipv75Gq za5S@N^Mh~Ff>0>)g`0ALuLZ{H4@bWWlHAL-n~F)AGV|yAi|ey>iHu&6P`1);LK+ns zD?-+gXU^-}wDhHs2aP`n1de$)RYypgy4^qq*7~Rk;SUpX!}s~PxgO^YDOa_NJRori zT)(h=?bH^kMo~{wMu;7nbYi)3W`o0W3k)+spH8DG>aV^^dVD!~Wwkgck_*8BfcNgH zXba|}aZe4k$Sb3-b#c+(3C~NK6;~L9_GjJiR;MU-Bw(MuEczJPX(&;b z$GwcZc09YIB(8OlSkddD5S)#@$}%1A6U?s1C~>=#t8k#BrMnJ2>gi~}kOslb(=?Y7 z7=RcciZfChC}5I(VP~qTCD=Z7Z%?}lkdYb~gpa@s_{8`g z$?GP(=J^gQx9x2~Tk!MSi+9%vyS`5{^@OA;P+ zWgo{+!Uo1jdGydEb50foG$NQ>=Z1MBL0LT)H>_kLLj_$#Dk<3V5obS)`ALgiswP}p zO%PDClIU+0Kc~0(F=GORN_}8j{3(v=tm&Z+of&Nb z0Op#JB95(9Y3eNWq_SWSCR>j!h8Oke9YEbowI8iN%^?${7JE--jhm25smfc4FzXq{ z0`P9+G!a&&{^rIzd&KIjFRO15-jmk0k!B&wG5)@<40E_H4W_v{fg2Z;N6^tUz}gLv zWWWV7z%z!=B)5Y%aK8q%lx?M-WZ1CKDRsH+#%FQ$kji{z7fRk-@^z&D?c9q+8}zB^ z+k|IbQ!XXrAre!0NfLt7ejIH#;nyAaGbE_8>9#9Nt;wZ=%XLzWv}hH8T$D=Rs0QWj z^}JDZ9c|Lyfsxh7PoS5zCdOu2l43s6?JQ5RvbaMhEC3CsrUdN4c%=Ql%xfoxOhdQ6 zrZk_&>BypR8(&`b(^oj^lAh~C%O+q*eQLzjYHmdGkqyiI86WgpNi-XB!-j3GB>!Ns zQ6Ux@~;&)lWjP% zNh`bJStJz%ngnK6G;!97sJHT z@`3u)dhO19IB%cW8S}+5s-uX~`T)A98q8|g@u3YxVbS!_(W{GzfkxiLenGK@=5q5K z^Qm$!&*8o65Mw#RekSUA{m4qs+4@qmpz)|FucYfWO zeYW1qNx0+2NW|gC{m7G(l=#x@+zPWb5`NLIDPc zeDmrExsy*va++OQoM~K(pY)}t3rwl^1(DHIi5Z3s5~oPW!gWIzImsRl>XP%7nkfLOz?D zmdrG3D3k^g;-$ZK@jCf~t(Xj`d{`Q1W*}ehDHO2F!9ylOAt7F~kHrz>v|Y(`LJbYYsA4eDI$xC}OnLzK>!Py`Ft&TAd!~G!;+h7KV>D zsKm>WL^9)Jad&S2dCtN$jz*9$K@&bv>n?{gK&u49`QQY?4r_0f%;3_;(3ciV_i05m zJ1i7+6sgFMY;l`-Pn)%#XHkB>_~p|A*srH}+gHyHO;oCTwtLV4XI>s6#(c?aNs>j|MShlI}_` zQN;9XNQ(>TT|NkBng-hO>1>)nj?pK&egqFd`*U+eY@PnHIT057^Aul5G2gcDk#_xr zzK=HQ;r zkXENW*}gVNY|4ITMncLHQBj#xOr6abW#ap8k^xJF)H1fqvGh_EW7$!SVm9eTi$oJP zY24Lc^gT+7=~zOpwkh%Xi1&!2U;gIcboi%4QXjPY6;pk%aJF z@RW&ej=}E&046@P(d}O={+PaqR+zTq*cd;mPi@Sy|3vf1XzUh?XC&;Hye5*Mx*MRK zVu;Vg1V7?I%1m`^{OD5glEvBY?PJ93T{Pr0bwd1xGuW`4SpUsi;qlTK7}qXLCabcB zoDqMyMt_CT={04OIsHURj~CGBUXU35?K5CnumW4nWZRr*WWO^-I&@}oCksmhFvJsx zuO80%T`~0jkkE;WXw`4N#frGa<^6m*XuKY5*wvclE+OMq8G6_9UBSQ^Av*bs4Z>`D z-_ZghnRmYL)j?pKmg3+oz$0)bH+?xx2#v=4U{+vc3O*E!e4#Q?l68DfF4VJMwwWSE z##bHmW8GwclM~(hfH6XL)Y-Nw+WI7nhEe82Qdxi*!I6MLz~@6e?0e~$z@NUDjBh}9 z3BiY)qk3T_2GDUGUYa(wDo0|Upse`l#x}3QLmP&b3zL5b0m};?I2@Z}+T~xFjr?7A zp1((|LgP`1drn!QSq#ken5%bMrfT7*lUQ|-Z&z!MFUR4=>l@r0FYd|QCb43F)=l1v zo8Y!CaiB_u!$c&6zRceiSvcBSgq5A8@cAJ8;)NSJLxdBuFPL^JakKC!bhdQ9(e1xm7%fzxKPu^PgDV76G1_hHg&H-_5oaG z#iC)bG$KT*JpO{LKwiQ3g9QMO%bbO&8#Y{-+ZsJ{(fKtG(|;R7Of)b=QAfG!ITY|H>1Cf^Wc;Tj zO?qSF8&jYxaWp!O+w?nXU9aID%OdFA{VVU4XQd-Yrk76rxV24n|0wt?bbe4kVmpZkM8 zgcOi2Kwk~&BBQAf==~Pefm*lba8K~I8%K#S+M6s_E z^0#P+{w>c1uAS{AYXCKTOG;K#Ledd1P>G|&@m8}?XK}SaBl8?k$fmI<@wK3=f}eJ zEE*xmjFb0fer)o{%|p}!s;BX^$V`{t*v^n~oCs0I5?(oj(W0Zr%7h0u>}YrjZ*PQn zDxjyU-wu`wpF|9bZ`WV97_X~6zZdRLA|=iaU*@!vBZkNN*ZKfSCNTrI z2+eh&#JW$!9tEQp+Mh@`e3ZF^ddmAnQ5;1g4i0X*k>w?$R-r%f7>J%|XqLRq+%Ikf zWBMGoO%YA!W~S>yAp4*Mveir$GHK9IoH?37VJmM9uT$d2GaDnU15)}DxF*CGf$M0QJo3p#$KWq!IRsDEL>6^p^CIIpA}viEfehS zx`i*~Hk&R&?ex#-PLxd;kA7eEz^o~Z4lg!hk`(?3xyJ-WIvU2}%>m#w1-@f!B#^$s2V2^Tbu z)ra@i;%~q-H$oGb1}R9ZW770)U8*Mx52aEfB~qeIKcQxKIIfR@(>b9GfesGXJX1VP zd-g#h)UqaqN1n9VBQyj&2=%q&ovATp=n%Sp7X0K`fd$2FthiY>)`*W7ASC?Q{`^>Q z_nyJXo6;lFKUcTa)SX`WZG|f-N zn=?3q(y)_mI(@nKQYP0idK1bQC_AIZi}Z`9Mc{ZygW2ceB~>1V*d}iViTT}z=rX7} zBv_eA+pU!ZUWdNL;ZAQ(X72zENF*D-4Jn_>Z&x=uSNG!Zyr*uvxei+IeNfjG!wzia<;KN&3;h{Pgg! zBKASv$K;c@-F>7w6;PTB$3vCF@izkZ_#_v-_HfqiE85h*p;gq2S7@>bD{#<6FFzH) zF%8wd?D|rP0V@IkeG$Wcn7Uw=hL7R!+5PCDhmK!vgJyvqv&q7;%SP9GQE*`jYP#lO z^7=TTzm!7l*y-@%ri9eU4GsUzYX(CB$?I%KMU9SB1}ykR4jx7USQ@ZY!ACvC?{psN z&gUPy#?ugA(a64xkdA-tv`#ZhoXAK#bC^}`hWstCTyU5Pc#we|9462mJlMj4fe~MH zlqCUK&$^uiAXCPY5CY5a6&D5bsl!jz?zX6w6Re1MFGHIC8}_HZwb>u}Q2-;Pam$Ke zzoMNXYL1BSDvWpEfz$<>I{lB^%!zq_V(_6K8rpZ-n>LQTj1RK-%TUqWb?mF9h2-P1 z!|3RM+=e&=W;Fv0DUkSq*$Z#Z%`Zsqxh#(qUdU$=r4MtF@7;&xu_ZRHFDnaCT|x|C zJ0;{T7A#sHR_>)DO=CZ zF89JF9+9U0yh9ZBC;aKd{62Y)o}J}EnGrw$aSGQ(G1^4s{^BbPk?!l4NfU+Hy7h}^ zA1IH+>v;aIPH>;Dp%cXkTSrydFHJ`%VNyKUX8UH*!E>B`d3B;HaaEmiu~+CVfZkk( zHX)cd!f~TJW6%lw#iK0Hn5su=i@K&4oLQDhlcqUVhplBxJAxXG7g1@1!GULPEWHWW z8D8YI^|`u)HuD?tsq%$Xa7n%+>9(bk|no=lE5+1!{JjSB6@`%MAu)Wr}<9U~od zjNq_SBfV(@rRjla8QvjmAaA!1<#=p>Ld9R1msiHjk4TbVsVL{^r=t91ZLZ&xboJ3v zt-SX>1faA($MPeA@qYj2H>)Y<#=O75>FQ1OT#FiisQ!edw|mVfX5sU1iP4l!XDkq- z-#|TLCZe-w6{p3inci7|G+6+P6L+dR&MwV*TGjN@-C#V@JVf@>mgx?&9$ijMsWT?t zx?vAWnx0N|spSrmpE)5Nq;G%t`|H!^qx-0N?^aDiYFZs6MLf+YU(Oj&iEA2m{m zla(w1!G8R6-gzs0GI53 z-|n^H#=8i?liK8!`&vF7l?RP?XkJV$21F`k%YWFzK>o|AiHveP z?IVZi+MYWbiU1&~VqsCLrKhJ*M_^8~)32kQ_1dw9<=>OEa`*^eWa7ydo)uA$ajyfa zV5i3I7Dpr8357oe_w(G6w6=uNE%^q)!n6L~5EoWNY{Bq6mHLwblz*RgO<}{$xS70U za*t>BYYdZ8emz-fYw&V8T}SIT>W+#k-OP)6O zO`jd#I5%fW-O5{SiNxjp-y-=h90psme47?GBM<$v{N?Oc@&UWE=kQhRY*m}AGPjFa zUVFoyKa5b>qB_|xbLwk<#ads@Ocj4FXa0z7;od27JK*w|Ml$F6o#K6{@Eeh&V!YsV#W~-VdbdJE2zD%y(mpO>+0c~ zY)wiAof#^IBJ+MRrQ_;W?QTZPCA2upXc^NEK~W z1$Fbi(w~8Gc5ms8S6Wu4aw2qCDRxqX;*DI#A*Y=#@RXvS9JOyygs=$S2d-$_pKc1E z1X;O7u{Ln7tP(1VpDkp#+G#r$e@?d!dO;}&O_V2}WYv^T&$17fLT0~LYH--rvKLp> z)DK0k8eV{lE9a};tUmP-ch)9G>n;=wPZ(G3N$k>|V>e$2%O>~yRV?~8b5tF0!!2r_ zJkMA`r)GxR5{kk3=;%#E6Q+-VU!Wa+rkk3sV?Q77M|{g%i`GLME0CJZb*XW`*GwyP zlCrttH9~XRp*9`36yC93?Cc(hfTl=tvNk#lj9P}X$l<5c6{&r_vb;7D6=*{;BE|0oL}XN5`*Cy`<2$nMYI zC7Bb9a1BMwInAy%W#n-Kn`WpGs#U3~Wff&Wo6Z}-C>d{}a5xgrT!|8|f^K_bn`NnL z7MD9CV_Dpxy`kFzCK8?xTobR}SlYLTqYiKFIo@}7#XhhfbP+G_f~~^%?9dMDVf>rh9P-#e7ARYC?ws z+r$4-^#-o_PzEof5Xk$z8?>kk8@z@XDbkmyK=+9mJ6Q7V?>- zh20NWQ5s$Af5mIW7><{}u+z>IZ6sgY{jPRtY9>pCH+Eoeai@AE=sIt^w{k=LMCrmiPZ|+lAbFK@r?~_qjYe(1us^hx z=8OuOf@m(47)Qn(?gZ)cjM~9-xgF?tJpU%^xP252aK9nQbKME}(8^vca=5WDyu6Qr zQf8&7kZ>{_(!K!yo<($e%x;uJicY|M6>yd3<+)p6`FI)1T03~=s4#bfcxn2A)ys|G za8-zt5R4=}q=7Vb5|R#JiKJI#;?@0ekB0z7O^dAH4F+h=CC>81^y@m9-RAu;y4^11 zdMmd%%ngZHV!0)ih)X*zI-D~FPIRZU*S;bAY5M4;O{2F>6~0@fui&~wQsL4Q{Bpmv z;>G9rj5b7_-b>tHjflN7F7T?dKf`DnxG9VWQl=vKK3<&G-(HvTwkD2$vCX_-k@)#5 zAG=AQmKus01EfmrD)O4!Ui1u>lKWC>v6eL_b`=LiSQiBQ1q5t+Jl_g*+x()osTZp* z*KKkh7r-v9SNHe@VeZ|ca?Odm{Nd};qr0gQuMR_a^2>MFH`NK~4g`;pHCFC8nR}AE z?LCP{zW1RUbTB*rT`J__+7oRPhzP|6hNw$!K%DadzBo>1zpuByi61;Ie0z&i^p8_} zLXmfwNJ&c}GV#j@6t@s2%XrQZNJf*8DhbIIBNz9K54z9@vJrRKq{4wXJKxgZ}59?ZE;+MMPQL-@j~(bov$CaEIaDiLGA1;w+G_^ zQbF5-?j9c0))T_R6AQk0vo_=tJ=8CHO=_zn!*IT|nj-6D#$eyN8TWDhx!_om@OW|nfCpRR`WC{>IHvM(|lT<*Fi4oTLp%RAL{QJQu!7ztK^wKOzxewtGnsN6wd* z?fa{i_>JQHaqEE~`wA*GUr{-XoMh0Pl08B$V0>Ro-u!2+h`!ixyrp?`M3}v-gQbNd zfZX$~^H8mVswqf)gVcb>LDM3E7n6)16N=S$A4kz>=#KpS1|Nm~Kv9VNN~uM!Ju}qd^%a+NO5RF+h7-P&Zb|SJRZT2-wPWB>|h{{rg z$Wo4d%TD%ezn41abgtj`x_;NWuHW~+GjqM${oMEGe(ukGKll4S5y^GrBBt75r`#mXZr?AY$7lzbLmNB zBhAv-Kwkun{q2+1EcB^WC>k2t>v%0Kq`sEc9}xj@r1;-fJNM>{P@TP5j;RzI4;QHs z$sByy{OyHDR`kp{g>8>Q-sRZ0WsB&ONL;qeYymQs$81wPJlweHYmcxyGDzs~o>~ml z&(w)#XxR3m&Xd;I*pn=BlhnvTk1pvVIC#k$7O;g#_F%rVTq8&2S1>pjbL*nV5n=mz z2i2y{-_x_~PbIJ{M7$*%Daj184ksELPP{Y`!eRAA)FslOUxVM?vW>qSFk!! zuR?KF6SXo%g0zV4SdfCOf-DrQ6IEvdsk&ou2vcp{pAf*4n&?#u#SH<0P^nZ| zs=O@G-4Oy)QBi?FJ;a$l;SpfKec%j@NFj**sK!E&eL8j<<0w6yp^dBwA=DJtn2{8fZ;efm;x3qk5ZA7{{_Ot9S>9`%H`Kt?LlDxCH zv;r250%H`g02CGtK*__PU`2Tam@*oNb3iGm>_cJD2wkE(0R^NJPe3_hA#SdY`vZG~ zBQ%lvYNB$o(7z-|7Ze2t7yxSk?}{N($$t%*;|W+Z3Tlr}n3BA_vXZ=t0#rdBF0ZKg zmy#vcoeb3C9x4nfE3dpivX>YH5Dq{sYOhiOfPFa-4MNKui=q(S&51-8HPO9Ef%Yu_ z95x0P6b3~>X`?7u02C^xfPl#%U@&ti6d|vIfI_9AFyQ=`J`sb*dH-M9d&>u;`XlM* z@MOTh_rB=Inli(Zemwnnbiwa0CJ<K1b76v z0t$4WE0E;RRGs>}KJ_YgFAo4^V3-{E7s^B-KZAwrb&NlvRfYU7K2-M=erYj)-47Yi zx`0jy`Lh-Nfv2La@g(MB{B^SkNDm}t8Xf{ z00$&d%oP3}4f# z^_|%sgA~cP2ImZ}avlYVWE!={L0yNtkYQnG9lx|?cCaBCk*|??$%jvIGV)6%C?F-T z*VobBSqR5&F$Neu9dj&ba4K(CpI3XeQ|e=Fx)m;F%vQ`Ekz|_VZmS)?6YkjM1Qn*$fBfbGr zcqat6GZkjo|5{d{q`>0Nv0`@Q6-$qUS0nxOdc}`4S6R_DT$HWJPtp6DlpKoxB+FE? zHBQXql`DBE0_zLjxkqP6+=%fh$~hB`^j?|izE)+>VefBJj--*$emczBVQOh~sckJi z(BKqTBtn;!JHPn;B%@0^xH;E;(qTG|&uQ}m%lGIe3gNCRDzWfY_+dnLY$wvQZ}uCa z1ZF)kHvu=G%}&3?ST%G9pDJMdh}b-LK4VHmx7M1eD`zW=8jZhPb?hOrf9Lj^dh+>) z`YpvL5L8<6vHQwJnN?WG^VKZvj#E6|Y!^m8a@f}vmz(Lz8XEWBKdQccf&I^gOu57OOIhp$_U`+1>;Hl2Mfk(P~0CK3V7L- z{0#jTvB?eJdpFixYPJ@pGh~rvQh}cLdUuD_f*3SuBc6>iAAIX^TkFG3dD*Y|Q?c{; zwc|^zF>4jXfYxny)%4mP=yLI+%X%ikXM>oB+@u02s) z+Pp>jO8-)*#5->_9cL~^8`=@k2NVn)!l5&}=#o|kq2fuwBthtXZZ3WM*C9KE0Vs{K;btp{Gpqp=R`f3Hc9G`9xKnn+f>9QRN+m2^dZgivZsX0Ji<0d&Fw#m zJ%7Vc?%2E3oN9CEfK(*=a8GwYU3dD;i`BJx%{Mt1=cGLA@0PfWEyHhrySvyD zqiu*t%`IPn)+gZd+Xd`jd`(;8f3>h>mNeDO;W`k_`8>Mlib!TyXI70K@iTO^I{A3} zOpBwW#}FpZ&*_?uLDq7Psrd_TmUzBL0(8R~fu)J-*z#t33bP@P>`?E3|MjtzsBgoocmN1<5n>*#mcXbGdF4d2aeqQ@oP(3f`(bDR85`Aus7-+?kMsX+~@M z(C}sH0JrF&np(@k{F}F!jVn!vA7-6hS$It|B0t%BYZl3fM`7MOeGl;vGZT_$3?8bu z&RCdnFFxK(%~5?I;5%x(B}$YjPe0?Nh@@#IrKXzMfI+^N!V3|_cpFRoWaKuzA$DcgGbTa z78Vt@9>yWdIX;3n%8~~|Q^sj&3nW&Zy^91tvApoNJIm<_xy$Ab2)`dRf@Z(tM}5gvy-*G zudgrf(ISUaK#T3$i_x8#!KSltIYN*M+6dlVoJ4D<(pfhqeX)ZwD^PF-Bpb>9(zFUM z^PYPp3*Oy%bI)A<0cf)IQo<_Lu-2tH+7j`xicBV{>&36kQbIjAt#2oq4<${_ zcv)&+iLOdDI>{NOEgE4wup<(XArn>1M=OVmz*kOjul0Oxn+Wo;7NoZqU|-8WR3wp{0rYhTyalZY8%sms1dYKZ!HlC>uaGK*AcQp{%>rAt2p zPOg3u(T|CYoxav7(pJB*OWRCtDV!d@#)%qxbSRpCo4?z`QN6_8)%Q{=Ia(ABhwDJ? z5^U{s3-fND%l59Pi&Dn9jVxId8V+?;^ap7oM@pVfDw=0|rOg~A+&$2Ih$|;{D!=l< ziI9z~hwmkJCg)3O-+Vh$Yu&3na;?u}qEGt-H@ZH1=<#s!z}Cs~@=l@8uhMU+mc*Ry z_dFKEpQxMTyNP=m>OZx#Tl6G9ZgKVW+{B}NqBvKKL$tg>9npJEXJ>;f2&*sgZn|4w zS4Gbn`QFarLaAh!>V_dx&voXPO+1Aky_cLeiK-c~hD)n9$yOC}RaPsStOPxirJ5T% zagVbC1Y?>H2!Ja+#HM}v;V=k>1> z&+vq*W+Zczv(|_ptxcIg={Ee-*Xbtqn{gQq9Pn+@`#aL3rHUB^1<_|~g9Yxf13KfW>sa#v%U9oxLF$$= zmXU4dkz=WTB8Da=N5Gq&(Hoz~;GKnn!rloOIa2+}dF1r$Z02OW#z%hInJ2re&vG~G zIpPIk&#w)JJszaS2!_m6Zy(8ax4c(fT@Ab3;c;F2u_Ml^Cqy_P_D*Auj9eniwGSPg z9;+QKzEn86&_pr$*wXg<$ev|})x{gao!_}HI&8~>o7ACfj?BflKjpJnH+=N|~qFQT1#a_dPh}j9a z?$}FiYdcH0X0tkv%jR^d4RwqxDW_reZKUC^-qb`FjnGD< zu@MV~%zw1+@^X&vLu%Wr?V`#i;R`FUa{gT5+q-t0HjI4w+tR<-)Qa3=7*F zs6hG9Ip-xq^lXmA+?VV4{5e3=KkUtrHmTT@VNE9UnZ`y9-I3-XTe;DgFEi{M=Y>!E zp*ZDmOIAEKM@i3p#{3djYr2Z+$cV<(L#+m zFzyrPG2La{BNhT06xP_DG(6CAJz>55yP(3tjTcU*%LL1of;WqPtFpVH(fatYoF_35 zH*RjLR}{`;wD4tl;fz|LecPu}BN*^SzczAf^N$HBnaoAIHj_ax(5N2et zAWP3DUZ_!D`OSpwxLi6X|rkKiSl`p zqhHhR&ed^R8)&iVgB-T-*7Tyyk;91z-QtFmRY+ZNb-)9CA* L*DgAHCHQ{;Q&YXY literal 0 HcmV?d00001 diff --git a/headers/AdvancedEnemy.h b/headers/AdvancedEnemy.h index 09fe88f..769fa74 100644 --- a/headers/AdvancedEnemy.h +++ b/headers/AdvancedEnemy.h @@ -2,6 +2,7 @@ #define ADVANCED_ENEMY_H #include "Enemy.h" + #include enum class DirectionA { diff --git a/headers/Bomber.h b/headers/Bomber.h new file mode 100644 index 0000000..7f1a77c --- /dev/null +++ b/headers/Bomber.h @@ -0,0 +1,41 @@ +// +// Created by k on 11.12.2024. +// + +#ifndef BOMBER_H +#define BOMBER_H + +#include "Enemy.h" +#include "Actor.h" +enum class DirectionB { + Up, + Down, + Left, + Right +}; + +class Bomber : public Actor { +public: + Bomber(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture); + + void shoot() override; + void move(float deltaX, float deltaY) override; + void moveLeft() override; + void moveRight() override; + void moveUp() override; + void moveDown() override; + + void update(); + + bool isAlive() const; + void takeDamage(); + void updateDirection(); + +private: + sf::Clock shootClock; + sf::Texture BombaTexture; + float movementSpeed = 2.0f; + bool alive = true; + DirectionB direction = DirectionB::Down; +}; +#endif //BOMBER_H diff --git a/headers/Plansza.h b/headers/Plansza.h index 4173def..b29e586 100644 --- a/headers/Plansza.h +++ b/headers/Plansza.h @@ -4,6 +4,7 @@ #include "Meteor.h" #include "Enemy.h" #include "AdvancedEnemy.h" +#include "Bomber.h" #include "RandomNumberGenerator.h" #include "SFML/System/Clock.hpp" #include "SFML/Graphics/RenderWindow.hpp" @@ -29,8 +30,9 @@ public: void update(); void spawn_enemy(); void setOutOfBounds(bool status); - void spawn_advanced_enemy(); + void spawn_wiazkowiec(); + void spawn_bomber(); private: Size size; @@ -40,17 +42,21 @@ private: sf::Texture meteorTexture1; sf::Texture meteorTexture2; sf::Texture enemyBulletTexture; + sf::Texture BombaTexture; sf::Texture playerTexture; sf::Texture playerBulletTexture; sf::Texture playerRocketTexture; sf::Texture enemyTexture; sf::Texture advancedEnemyTexture; + sf::Texture BomberEnemyTexture; sf::Clock spawnClock; sf::Clock shooterSpawnClock; std::vector enemies; std::vector AEnemies; + std::vector BEnemies; sf::Clock enemySpawnClock; sf::Clock AenemySpawnClock; + sf::Clock BomberSpawnClock; std::vector meteors; sf::RenderWindow *window; }; diff --git a/sources/Bomber.cpp b/sources/Bomber.cpp new file mode 100644 index 0000000..b909971 --- /dev/null +++ b/sources/Bomber.cpp @@ -0,0 +1,78 @@ +#include "../headers/Bomber.h" +#include "../headers/Bullet.h" + +Bomber::Bomber(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture) : Actor(x, y, texture) { + actorSprite.setTexture(texture); + BombaTexture = bulletTexture; + hp = 2; // 2 punkty życia + firerate = 2000; // Strzela co 2 + moving_speed = 2.0f; // Prędkość + BombaTexture.loadFromFile("../assets/img/bullets/bomba.png"); +} + +void Bomber::shoot() { + if (shootClock.getElapsedTime().asMilliseconds() >= firerate) { + Bullet Bbullet(position.x, position.y + actorSprite.getGlobalBounds().height / 2, BombaTexture); + Bbullet.setSpeed(0.5f); // Prędkość w dół + bullets.emplace_back(std::move(Bbullet)); + shootClock.restart(); + } +} + +void Bomber::updateDirection() { + // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + if (position.y <= 0) { + direction = DirectionB::Down; + } else if (position.y >= 800) { + direction = DirectionB::Up; + } + + // logika dla kierunku lewo/prawo + if (position.x <= 0) { + direction = DirectionB::Right; + } else if (position.x >= 1200) { + direction = DirectionB::Left; + } +} + +void Bomber::move(float deltaX, float deltaY) { + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); +} + +void Bomber::moveLeft() { move(-moving_speed, 0.0f); } +void Bomber::moveRight() { move(moving_speed, 0.0f); } +void Bomber::moveUp() { move(0.0f, -moving_speed); } +void Bomber::moveDown() { move(0.0f, moving_speed); } + +void Bomber::update() { + // Sprawdzamy, czy przeciwnik dotarł do krawędzi i zmieniamy kierunek + updateDirection(); + + switch (direction) { + case DirectionB::Up: + moveUp(); + break; + case DirectionB::Down: + moveDown(); + break; + case DirectionB::Left: + moveLeft(); + break; + case DirectionB::Right: + moveRight(); + break; + } +} + + +bool Bomber::isAlive() const { + return alive; +} + +void Bomber::takeDamage() { + if (--hp <= 0) { + alive = false; + } +} \ No newline at end of file diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 19727cb..9e91303 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -7,16 +7,14 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render const sf::Texture& playerTexture, const sf::Texture& playerBulletTexture, const sf::Texture& playerRocketTexture) -: background("../assets/img/background/background.png", 2.0f), -ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow->getSize().y) - 100, playerTexture, playerBulletTexture, playerRocketTexture) -{ - + : background("../assets/img/background/background.png", 2.0f), + ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow->getSize().y) - 100, + playerTexture, playerBulletTexture, playerRocketTexture) { window = mainWindow; size.height = static_cast(windowHeight); size.width = static_cast(windowWidth); - ship.setMovingSpeed(8); ship.setFirerate(200); @@ -28,7 +26,6 @@ ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow- audioManager.loadSoundEffect("fail", "../assets/sounds/fail.mp3"); - meteorTexture1.loadFromFile("../assets/img/meteors/meteor-1.png"); meteorTexture2.loadFromFile("../assets/img/meteors/meteor-2.png"); @@ -41,6 +38,10 @@ ship(static_cast(mainWindow->getSize().x) / 2, static_cast(mainWindow- std::cerr << "Failed to load advanced enemy texture!" << std::endl; exit(-1); } + if (!BomberEnemyTexture.loadFromFile("../assets/img/enemy/wiazkowiec.png")) { + std::cerr << "Failed to load advanced enemy texture!" << std::endl; + exit(-1); + } spawnClock.restart(); } @@ -83,9 +84,11 @@ void Plansza::update() { } // generowanie nowego meteoru - spawn_meteor(); + //spawn_meteor(); spawn_enemy(); spawn_advanced_enemy(); + //spawn_wiazkowiec(); + spawn_bomber(); // utrzymanie meteorów i pocisków w ruchu for (auto& meteor : getMeteors()) { @@ -143,6 +146,7 @@ void Plansza::update() { } + if (!ship.isAlive()) { std::cout << "Game Over! Player is dead." << std::endl; std::cout << "You lost the game!\n"; @@ -216,6 +220,7 @@ void Plansza::update() { // Usunięcie martwych przeciwników if (!it->isAlive()) { + std::cout << "Basic Enemy has been eliminated." << std::endl; it = enemies.erase(it); } else { ++it; @@ -234,7 +239,21 @@ void Plansza::update() { ++it; } } - // std::cout << "Current AEnemies size: " << AEnemies.size() << std::endl; + for (auto it = BEnemies.begin(); it != BEnemies.end();) { + it->update(); // Ruch b + it->shoot(); // Strzał przeciwnika + + window->draw(it->getSprite()); // Rysowanie na ekranie + + if (!it->isAlive()) { + std::cout << "Bomber has been eliminated." << std::endl; + it = BEnemies.erase(it); // Usunięcie martwych przeciwników + } else { + ++it; + } + } + + // Obsługa pocisków zaawansowanych przeciwników for (auto& aEnemy : AEnemies) { for (auto it = aEnemy.getBullets().begin(); it != aEnemy.getBullets().end();) { @@ -247,22 +266,25 @@ void Plansza::update() { } } - for (auto advancedIt = AEnemies.begin(); advancedIt != AEnemies.end();) { - bool hit = false; - for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { - if (advancedIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { - bulletIt = ship.getBullets().erase(bulletIt); - advancedIt->takeDamage(); - hit = true; - break; + // Obsługa bomb + for (auto& aEnemy : BEnemies) { + for (auto it = aEnemy.getBullets().begin(); it != aEnemy.getBullets().end();) { + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + ship.takeDamage(); // Zadanie obrażeń graczowi + it = aEnemy.getBullets().erase(it); // Usuwanie pocisku po trafieniu } else { - ++bulletIt; + ++it; } } - if (hit && !advancedIt->isAlive()) { - advancedIt = AEnemies.erase(advancedIt); // Usunięcie przeciwnika AdvancedEnemy - } else { - ++advancedIt; + } + + + for (auto& enemy : enemies) { + enemy.shoot(); + enemy.updateBullets(); + for (auto& bullet : enemy.getBullets()) { + bullet.update(); + window->draw(bullet.getSprite()); } } @@ -274,6 +296,14 @@ void Plansza::update() { } } + for (auto& bomberEnemy : BEnemies) { + bomberEnemy.updateBullets(); // Obsługuje bomby + for (auto& bullet : bomberEnemy.getBullets()) { + bullet.update(); + window->draw(bullet.getSprite()); + } + } + for (auto& enemy : enemies) { for (auto it = enemy.getBullets().begin(); it != enemy.getBullets().end();) { if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { @@ -290,16 +320,7 @@ void Plansza::update() { } } - for (auto& enemy : enemies) { - enemy.shoot(); - enemy.updateBullets(); - for (auto& bullet : enemy.getBullets()) { - bullet.update(); - window->draw(bullet.getSprite()); - } - } - - // Usuwanie pocisków, które są poza ekranem + // Usuwanie pocisków, które są poza ekranem srednio to dziala for (auto enemyIt = enemies.begin(); enemyIt != enemies.end(); ) { for (auto bulletIt = enemyIt->getBullets().begin(); bulletIt != enemyIt->getBullets().end();) { if (bulletIt->isOutOfBounds()) { @@ -331,6 +352,47 @@ void Plansza::update() { ++enemyIt; } } + + for (auto advancedIt = AEnemies.begin(); advancedIt != AEnemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (advancedIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + advancedIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; + } + } + if (hit && !advancedIt->isAlive()) { + advancedIt = AEnemies.erase(advancedIt); // Usunięcie przeciwnika AdvancedEnemy + } else { + ++advancedIt; + } + } + + for (auto bomberIt = BEnemies.begin(); bomberIt != BEnemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (bomberIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + bomberIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; + } + } + if (hit && !bomberIt->isAlive()) { + bomberIt = BEnemies.erase(bomberIt); // Usunięcie przeciwnika AdvancedEnemy + } else { + ++bomberIt; + } + } + + + //oblsuga dla rakiety for (auto enemyIt = enemies.begin(); enemyIt != enemies.end();) { bool hit = false; @@ -370,6 +432,25 @@ void Plansza::update() { } } + for (auto bomberIt = BEnemies.begin(); bomberIt != BEnemies.end();) { + bool hit = false; + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (bomberIt->getSprite().getGlobalBounds().intersects(rocketIt->getSprite().getGlobalBounds())) { + rocketIt = ship.getRockets().erase(rocketIt); + bomberIt->takeDamage(); + hit = true; + break; + } else { + ++rocketIt; + } + } + if (hit && !bomberIt->isAlive()) { + bomberIt = BEnemies.erase(bomberIt); + } else { + ++bomberIt; + } + } + } @@ -398,7 +479,7 @@ void Plansza::update_meteors() { } void Plansza::spawn_enemy() { - if (enemySpawnClock.getElapsedTime().asSeconds() >= 6) { // Spawn co 10 sekund + if (enemySpawnClock.getElapsedTime().asSeconds() >= 110) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); enemies.emplace_back(spawnX, -50, enemyTexture); @@ -408,14 +489,25 @@ void Plansza::spawn_enemy() { } void Plansza::spawn_advanced_enemy() { - if (AenemySpawnClock.getElapsedTime().asSeconds() >= 5) { // Spawn co 10 sekund + if (AenemySpawnClock.getElapsedTime().asSeconds() >= 100) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); - AEnemies.emplace_back(spawnX, 50, advancedEnemyTexture, enemyBulletTexture); + AEnemies.emplace_back(spawnX, -50, advancedEnemyTexture, enemyBulletTexture); std::cout << "Spawned Advanced Enemy at X: " << spawnX << std::endl; AenemySpawnClock.restart(); } } +void Plansza::spawn_bomber() { + if (BomberSpawnClock.getElapsedTime().asSeconds() >= 5) { // Spawn co 10 sekund + int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); + BEnemies.emplace_back(spawnX, -50, BomberEnemyTexture, BombaTexture); + std::cout << "Spawned Bomber Enemy at X: " << spawnX << std::endl; + BomberSpawnClock.restart(); + } +} + + + Size Plansza::getSize() { From 41945b3d88696fd9e43bfcd7073a8b52cdede2f7 Mon Sep 17 00:00:00 2001 From: Kuba Date: Wed, 11 Dec 2024 16:51:56 +0100 Subject: [PATCH 08/18] Cos usprawnione i nasrane --- CMakeLists.txt | 2 ++ headers/Bomber.h | 1 + headers/Kamikadze.h | 8 ++++++++ sources/Bomber.cpp | 35 +++++++++++++++++++++++++++++++---- sources/Bullet.cpp | 6 +++++- sources/Kamikadze.cpp | 3 +++ sources/Plansza.cpp | 8 ++++++-- 7 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 headers/Kamikadze.h create mode 100644 sources/Kamikadze.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 34a32e9..8dbfe23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,8 @@ add_executable(LotoStatek main.cpp sources/AdvancedEnemy.cpp headers/Bomber.h sources/Bomber.cpp + headers/Kamikadze.h + sources/Kamikadze.cpp ) if(WIN32) diff --git a/headers/Bomber.h b/headers/Bomber.h index 7f1a77c..9de6954 100644 --- a/headers/Bomber.h +++ b/headers/Bomber.h @@ -24,6 +24,7 @@ public: void moveRight() override; void moveUp() override; void moveDown() override; + void setRandomDirection(); void update(); diff --git a/headers/Kamikadze.h b/headers/Kamikadze.h new file mode 100644 index 0000000..5fa494c --- /dev/null +++ b/headers/Kamikadze.h @@ -0,0 +1,8 @@ +// +// Created by k on 11.12.2024. +// + +#ifndef KAMIKADZE_H +#define KAMIKADZE_H + +#endif //KAMIKADZE_H diff --git a/sources/Bomber.cpp b/sources/Bomber.cpp index b909971..efb9a63 100644 --- a/sources/Bomber.cpp +++ b/sources/Bomber.cpp @@ -1,21 +1,48 @@ #include "../headers/Bomber.h" #include "../headers/Bullet.h" +#include Bomber::Bomber(int x, int y, const sf::Texture& texture, const sf::Texture& bulletTexture) : Actor(x, y, texture) { actorSprite.setTexture(texture); BombaTexture = bulletTexture; hp = 2; // 2 punkty życia - firerate = 2000; // Strzela co 2 - moving_speed = 2.0f; // Prędkość - BombaTexture.loadFromFile("../assets/img/bullets/bomba.png"); + firerate = 10000; // Strzela co 10 + moving_speed = 1.0f; // Prędkość + // BombaTexture.loadFromFile("../assets/img/bullets/bomba.png"); +} + +// Losuje losowy kierunek dla Bombera +void Bomber::setRandomDirection() { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dist(0, 3); + + int randomDirection = dist(gen); + + // Zapobieganie wyjscia poza ekran + switch (randomDirection) { + case 0: + if (position.y > 0) direction = DirectionB::Up; + break; + case 1: + if (position.y < 800) direction = DirectionB::Down; + break; + case 2: + if (position.x > 0) direction = DirectionB::Left; + break; + case 3: + if (position.x < 1200) direction = DirectionB::Right; + break; + } } void Bomber::shoot() { if (shootClock.getElapsedTime().asMilliseconds() >= firerate) { Bullet Bbullet(position.x, position.y + actorSprite.getGlobalBounds().height / 2, BombaTexture); - Bbullet.setSpeed(0.5f); // Prędkość w dół + Bbullet.setSpeed(0.1f); // Prędkość w dół bullets.emplace_back(std::move(Bbullet)); shootClock.restart(); + setRandomDirection(); } } diff --git a/sources/Bullet.cpp b/sources/Bullet.cpp index 17ff7a2..226401f 100644 --- a/sources/Bullet.cpp +++ b/sources/Bullet.cpp @@ -1,9 +1,13 @@ #include "../headers/Bullet.h" +#include +#include + void Bullet::update() { + //std::cout << "Start update: speed = " << speed << ", position.y = " << position.y << std::endl; sprite.move(0.0f, speed); position.y += int(speed); if(position.y < -100) { outOfBounds = true; } -} \ No newline at end of file +} diff --git a/sources/Kamikadze.cpp b/sources/Kamikadze.cpp new file mode 100644 index 0000000..2fcec76 --- /dev/null +++ b/sources/Kamikadze.cpp @@ -0,0 +1,3 @@ +// +// Created by k on 11.12.2024. +// diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 9e91303..15beee7 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -42,6 +42,10 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render std::cerr << "Failed to load advanced enemy texture!" << std::endl; exit(-1); } + if (!BombaTexture.loadFromFile("../assets/img/bullets/bomba.png")) { + std::cerr << "Failed to load BombaTexture!" << std::endl; + exit(-1); + } spawnClock.restart(); } @@ -489,7 +493,7 @@ void Plansza::spawn_enemy() { } void Plansza::spawn_advanced_enemy() { - if (AenemySpawnClock.getElapsedTime().asSeconds() >= 100) { // Spawn co 10 sekund + if (AenemySpawnClock.getElapsedTime().asSeconds() >= 80) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); AEnemies.emplace_back(spawnX, -50, advancedEnemyTexture, enemyBulletTexture); std::cout << "Spawned Advanced Enemy at X: " << spawnX << std::endl; @@ -498,7 +502,7 @@ void Plansza::spawn_advanced_enemy() { } void Plansza::spawn_bomber() { - if (BomberSpawnClock.getElapsedTime().asSeconds() >= 5) { // Spawn co 10 sekund + if (BomberSpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); BEnemies.emplace_back(spawnX, -50, BomberEnemyTexture, BombaTexture); std::cout << "Spawned Bomber Enemy at X: " << spawnX << std::endl; From c1a24a701b85fd35d4714f9bc905da784d261bf1 Mon Sep 17 00:00:00 2001 From: Kuba Date: Wed, 11 Dec 2024 17:43:43 +0100 Subject: [PATCH 09/18] Kamikadze sledzi gracza --- assets/img/enemy/kamikadze.png | Bin 0 -> 6266 bytes headers/Kamikadze.h | 45 +++++++++++- headers/Plansza.h | 5 ++ sources/Kamikadze.cpp | 129 ++++++++++++++++++++++++++++++++- sources/Plansza.cpp | 87 +++++++++++++++++++++- 5 files changed, 256 insertions(+), 10 deletions(-) create mode 100644 assets/img/enemy/kamikadze.png diff --git a/assets/img/enemy/kamikadze.png b/assets/img/enemy/kamikadze.png new file mode 100644 index 0000000000000000000000000000000000000000..e8fe1a6f85e0124dddb01ea6ca2712bcd9bf6864 GIT binary patch literal 6266 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 enemies; std::vector AEnemies; std::vector BEnemies; + std::vector KEnemies; sf::Clock enemySpawnClock; sf::Clock AenemySpawnClock; sf::Clock BomberSpawnClock; + sf::Clock KamikadzeSpawnClock; std::vector meteors; sf::RenderWindow *window; }; diff --git a/sources/Kamikadze.cpp b/sources/Kamikadze.cpp index 2fcec76..bd8f05c 100644 --- a/sources/Kamikadze.cpp +++ b/sources/Kamikadze.cpp @@ -1,3 +1,126 @@ -// -// Created by k on 11.12.2024. -// +#include "../headers/Kamikadze.h" +#include "../headers/Bullet.h" +#include + +Kamikadze::Kamikadze(int x, int y, const sf::Texture& texture) : Actor(x, y, texture) { + actorSprite.setTexture(texture); + hp = 3; // 3 punkty życia + moving_speed = 2.0f; // Prędkość +} + +void Kamikadze::shoot(){} + +// Losuje losowy kierunek dla Bombera +void Kamikadze::setRandomDirection() { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dist(0, 3); + + int randomDirection = dist(gen); + + // Zapobieganie wyjscia poza ekran + switch (randomDirection) { + case 0: + if (position.y > 0) direction = DirectionK::Up; + break; + case 1: + if (position.y < 800) direction = DirectionK::Down; + break; + case 2: + if (position.x > 0) direction = DirectionK::Left; + break; + case 3: + if (position.x < 1200) direction = DirectionK::Right; + break; + } +} + + +void Kamikadze::updateDirection() { + // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + if (position.y <= 0) { + direction = DirectionK::Down; + } else if (position.y >= 800) { + direction = DirectionK::Up; + } + + // logika dla kierunku lewo/prawo + if (position.x <= 0) { + direction = DirectionK::Right; + } else if (position.x >= 1200) { + direction = DirectionK::Left; + } +} + +void Kamikadze::followPlayer(const sf::Vector2f& playerPosition) { + // Oblicz różnicę w pozycjach + float diffX = playerPosition.x - position.x; + float diffY = playerPosition.y - position.y; + + // Normalizacja wektora (skrócenie kierunku do jednostkowego) + float magnitude = std::sqrt(diffX * diffX + diffY * diffY); + if (magnitude != 0) { + diffX /= magnitude; + diffY /= magnitude; + + // Aktualizacja pozycji Kamikadze w kierunku gracza z uwzględnieniem prędkości + position.x += diffX * movementSpeed; + position.y += diffY * movementSpeed; + } else { + // Jeśli Kamikadze jest dokładnie na pozycji gracza, zatrzymaj jego ruch + movementSpeed = 0.0f; + } +} + +void Kamikadze::explode(const sf::Vector2f& playerPosition, bool& playerHit) { + if (!exploding) { + // Kamikadze rozpoczyna eksplozję + exploding = true; + explosionClock.restart(); + movementSpeed = 0.0f; // Zatrzymaj ruch + + // Sprawdź, czy gracz jest w obszarze eksplozji + const float explosionRange = 50.0f; // Zakładając promień wybuchu + sf::Vector2f diff = playerPosition - sf::Vector2f(static_cast(position.x), static_cast(position.y)); + float distance = std::sqrt(diff.x * diff.x + diff.y * diff.y); + + if (distance <= explosionRange) { + playerHit = true; // Gracz został trafiony + } + } + + // Po zakończeniu eksplozji, Kamikadze umiera + if (exploding && explosionClock.getElapsedTime().asSeconds() >= 0.5f) { // 0.5 sekundy + alive = false; + } +} + +void Kamikadze::move(float deltaX, float deltaY) { + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); +} + +void Kamikadze::moveLeft() { move(-moving_speed, 0.0f); } +void Kamikadze::moveRight() { move(moving_speed, 0.0f); } +void Kamikadze::moveUp() { move(0.0f, -moving_speed); } +void Kamikadze::moveDown() { move(0.0f, moving_speed); } + +void Kamikadze::update(const sf::Vector2f& playerPosition) { + if (alive && !exploding) { + // Podążaj za graczem, dopóki Kamikadze jest żywy i nie eksploduje + followPlayer(playerPosition); + actorSprite.setPosition(position.x, position.y); // Aktualizuj sprite + } +} + + +bool Kamikadze::isAlive() const { + return alive; +} + +void Kamikadze::takeDamage() { + if (--hp <= 0) { + alive = false; + } +} \ No newline at end of file diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 15beee7..9383785 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -42,6 +42,10 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render std::cerr << "Failed to load advanced enemy texture!" << std::endl; exit(-1); } + if (!KamikadzeTexture.loadFromFile("../assets/img/enemy/kamikadze.png")) { + std::cerr << "Failed to load advanced enemy texture!" << std::endl; + exit(-1); + } if (!BombaTexture.loadFromFile("../assets/img/bullets/bomba.png")) { std::cerr << "Failed to load BombaTexture!" << std::endl; exit(-1); @@ -93,6 +97,7 @@ void Plansza::update() { spawn_advanced_enemy(); //spawn_wiazkowiec(); spawn_bomber(); + spawn_kamikadze(); // utrzymanie meteorów i pocisków w ruchu for (auto& meteor : getMeteors()) { @@ -258,6 +263,35 @@ void Plansza::update() { } + for (auto it = KEnemies.begin(); it != KEnemies.end();) { + sf::Vector2f playerPosition = ship.getSprite().getPosition(); // Pozycja gracza + bool playerHit = false; + + // Aktualizacja ruchu Kamikadze + + it->update(playerPosition); + + // Sprawdź kolizję z graczem + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + it->explode(playerPosition, playerHit); + + if (playerHit) { + ship.takeDamage(); // Gracz traci punkt życia + } + } + + // Rysuj Kamikadze na ekranie + if (it->isAlive()) { + window->draw(it->getSprite()); + ++it; + } else { + // Usuń, jeśli Kamikadze już nie żyje + std::cout << "Kamikadze has exploded!" << std::endl; + it = KEnemies.erase(it); + } + } + + // Obsługa pocisków zaawansowanych przeciwników for (auto& aEnemy : AEnemies) { for (auto it = aEnemy.getBullets().begin(); it != aEnemy.getBullets().end();) { @@ -389,12 +423,31 @@ void Plansza::update() { } } if (hit && !bomberIt->isAlive()) { - bomberIt = BEnemies.erase(bomberIt); // Usunięcie przeciwnika AdvancedEnemy + bomberIt = BEnemies.erase(bomberIt); // Usunięcie przeciwnika Bomber } else { ++bomberIt; } } + for (auto kamikadzeIt = KEnemies.begin(); kamikadzeIt != KEnemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (kamikadzeIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + kamikadzeIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; + } + } + if (hit && !kamikadzeIt->isAlive()) { + kamikadzeIt = KEnemies.erase(kamikadzeIt); // Usunięcie przeciwnika Kamikadze + } else { + ++kamikadzeIt; + } + } + //oblsuga dla rakiety @@ -455,6 +508,25 @@ void Plansza::update() { } } + for (auto kamikadzeIt = KEnemies.begin(); kamikadzeIt != KEnemies.end();) { + bool hit = false; + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (kamikadzeIt->getSprite().getGlobalBounds().intersects(rocketIt->getSprite().getGlobalBounds())) { + rocketIt = ship.getRockets().erase(rocketIt); + kamikadzeIt->takeDamage(); + hit = true; + break; + } else { + ++rocketIt; + } + } + if (hit && !kamikadzeIt->isAlive()) { + kamikadzeIt = KEnemies.erase(kamikadzeIt); + } else { + ++kamikadzeIt; + } + } + } @@ -486,7 +558,7 @@ void Plansza::spawn_enemy() { if (enemySpawnClock.getElapsedTime().asSeconds() >= 110) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); enemies.emplace_back(spawnX, -50, enemyTexture); - + std::cout << "Spawned Basic Enemy at X: " << spawnX << std::endl; enemySpawnClock.restart(); } @@ -502,7 +574,7 @@ void Plansza::spawn_advanced_enemy() { } void Plansza::spawn_bomber() { - if (BomberSpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund + if (BomberSpawnClock.getElapsedTime().asSeconds() >= 100) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); BEnemies.emplace_back(spawnX, -50, BomberEnemyTexture, BombaTexture); std::cout << "Spawned Bomber Enemy at X: " << spawnX << std::endl; @@ -510,6 +582,15 @@ void Plansza::spawn_bomber() { } } +void Plansza::spawn_kamikadze() { + if (KamikadzeSpawnClock.getElapsedTime().asSeconds() >= 5) { // Spawn co 10 sekund + int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); + KEnemies.emplace_back(spawnX, -50, KamikadzeTexture); + std::cout << "Spawned Kamikadze Enemy at X: " << spawnX << std::endl; + KamikadzeSpawnClock.restart(); + } +} + From 0c706625d25afb770c1cc6725e3bb8d72256c919 Mon Sep 17 00:00:00 2001 From: Kuba Date: Wed, 11 Dec 2024 17:49:31 +0100 Subject: [PATCH 10/18] Kamikadze wybucha nawet bez gracza --- headers/Kamikadze.h | 1 + sources/Kamikadze.cpp | 20 ++++++++++++-------- sources/Plansza.cpp | 20 +++++++++++--------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/headers/Kamikadze.h b/headers/Kamikadze.h index 1783fcd..8f33f86 100644 --- a/headers/Kamikadze.h +++ b/headers/Kamikadze.h @@ -26,6 +26,7 @@ public: void update(const sf::Vector2f& playerPosition); bool isAlive() const; + bool isExploding() const; void takeDamage(); void updateDirection(); diff --git a/sources/Kamikadze.cpp b/sources/Kamikadze.cpp index bd8f05c..79eb3ae 100644 --- a/sources/Kamikadze.cpp +++ b/sources/Kamikadze.cpp @@ -74,24 +74,25 @@ void Kamikadze::followPlayer(const sf::Vector2f& playerPosition) { void Kamikadze::explode(const sf::Vector2f& playerPosition, bool& playerHit) { if (!exploding) { - // Kamikadze rozpoczyna eksplozję + // Rozpocznij eksplozję exploding = true; explosionClock.restart(); - movementSpeed = 0.0f; // Zatrzymaj ruch + movementSpeed = 0.0f; // Zatrzymaj Kamikadze - // Sprawdź, czy gracz jest w obszarze eksplozji - const float explosionRange = 50.0f; // Zakładając promień wybuchu + // Zakres, w jakim gracz może zostać trafiony + const float explosionRange = 50.0f; sf::Vector2f diff = playerPosition - sf::Vector2f(static_cast(position.x), static_cast(position.y)); float distance = std::sqrt(diff.x * diff.x + diff.y * diff.y); + // Trafienie gracza, jeśli jest w obszarze eksplozji if (distance <= explosionRange) { - playerHit = true; // Gracz został trafiony + playerHit = true; } } - // Po zakończeniu eksplozji, Kamikadze umiera - if (exploding && explosionClock.getElapsedTime().asSeconds() >= 0.5f) { // 0.5 sekundy - alive = false; + // Sprawdzanie czasu wybuchu + if (exploding && explosionClock.getElapsedTime().asSeconds() >= 0.5f) { + alive = false; // Kamikadze ulega zniszczeniu po eksplozji } } @@ -114,6 +115,9 @@ void Kamikadze::update(const sf::Vector2f& playerPosition) { } } +bool Kamikadze::isExploding() const { + return exploding; +} bool Kamikadze::isAlive() const { return alive; diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 9383785..e02f4b8 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -264,29 +264,31 @@ void Plansza::update() { for (auto it = KEnemies.begin(); it != KEnemies.end();) { - sf::Vector2f playerPosition = ship.getSprite().getPosition(); // Pozycja gracza + sf::Vector2f playerPosition = ship.getSprite().getPosition(); // Aktualna pozycja gracza bool playerHit = false; - // Aktualizacja ruchu Kamikadze - + // Aktualizacja pozycji Kamikadze it->update(playerPosition); - // Sprawdź kolizję z graczem + // Wybuch, gdy Kamikadze dotknie gracza if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { it->explode(playerPosition, playerHit); - if (playerHit) { - ship.takeDamage(); // Gracz traci punkt życia + ship.takeDamage(); // Gracz otrzymuje obrażenia } } - // Rysuj Kamikadze na ekranie + // Kamikadze eksploduje po aktywacji niezależnie od obecności gracza + if (it->isExploding()) { + it->explode(playerPosition, playerHit); // Eksplozja trwa + } + + // Usunięcie martwego Kamikadze z listy if (it->isAlive()) { window->draw(it->getSprite()); ++it; } else { - // Usuń, jeśli Kamikadze już nie żyje - std::cout << "Kamikadze has exploded!" << std::endl; + std::cout << "Kamikadze exploded!" << std::endl; it = KEnemies.erase(it); } } From 17c372fad9af0c5f4d0851ed279f69d50cebf747 Mon Sep 17 00:00:00 2001 From: Kuba Date: Wed, 11 Dec 2024 17:58:32 +0100 Subject: [PATCH 11/18] Kamikadze poprawnie zadaje orbazenia graczowi, problemem byla za mala odleglosc --- sources/Kamikadze.cpp | 14 +++++++++++++- sources/Plansza.cpp | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/sources/Kamikadze.cpp b/sources/Kamikadze.cpp index 79eb3ae..c3aaeb0 100644 --- a/sources/Kamikadze.cpp +++ b/sources/Kamikadze.cpp @@ -1,4 +1,7 @@ #include "../headers/Kamikadze.h" + +#include + #include "../headers/Bullet.h" #include @@ -79,20 +82,29 @@ void Kamikadze::explode(const sf::Vector2f& playerPosition, bool& playerHit) { explosionClock.restart(); movementSpeed = 0.0f; // Zatrzymaj Kamikadze + std::cout << "Kamikadze exploding!" << std::endl; + std::cout << "Kamikadze position: (" << position.x << ", " << position.y << ")" << std::endl; + std::cout << "Player position: (" << playerPosition.x << ", " << playerPosition.y << ")" << std::endl; + // Zakres, w jakim gracz może zostać trafiony - const float explosionRange = 50.0f; + sf::Vector2f diff = playerPosition - sf::Vector2f(static_cast(position.x), static_cast(position.y)); float distance = std::sqrt(diff.x * diff.x + diff.y * diff.y); + std::cout << "Distance to player: " << distance << std::endl; + // Trafienie gracza, jeśli jest w obszarze eksplozji + const float explosionRange = 100.0f; if (distance <= explosionRange) { playerHit = true; + std::cout << "Player is within explosion range! Player hit!" << std::endl; } } // Sprawdzanie czasu wybuchu if (exploding && explosionClock.getElapsedTime().asSeconds() >= 0.5f) { alive = false; // Kamikadze ulega zniszczeniu po eksplozji + std::cout << "Kamikadze destroyed after explosion!" << std::endl; } } diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index e02f4b8..3cd317e 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -275,6 +275,7 @@ void Plansza::update() { it->explode(playerPosition, playerHit); if (playerHit) { ship.takeDamage(); // Gracz otrzymuje obrażenia + std::cout << "Gracz został trafiony przez eksplozję Kamikadze!" << std::endl; } } From b257837d188303dfeae5fae0a97540b23b936799 Mon Sep 17 00:00:00 2001 From: Kuba Date: Wed, 11 Dec 2024 18:06:26 +0100 Subject: [PATCH 12/18] Bomber nie chce trzymac sie granic mapy da faq --- sources/Bomber.cpp | 2 +- sources/Plansza.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sources/Bomber.cpp b/sources/Bomber.cpp index efb9a63..4114d3a 100644 --- a/sources/Bomber.cpp +++ b/sources/Bomber.cpp @@ -31,7 +31,7 @@ void Bomber::setRandomDirection() { if (position.x > 0) direction = DirectionB::Left; break; case 3: - if (position.x < 1200) direction = DirectionB::Right; + if (position.x < 600) direction = DirectionB::Right; break; } } diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 3cd317e..4c68109 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -577,7 +577,7 @@ void Plansza::spawn_advanced_enemy() { } void Plansza::spawn_bomber() { - if (BomberSpawnClock.getElapsedTime().asSeconds() >= 100) { // Spawn co 10 sekund + if (BomberSpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); BEnemies.emplace_back(spawnX, -50, BomberEnemyTexture, BombaTexture); std::cout << "Spawned Bomber Enemy at X: " << spawnX << std::endl; @@ -586,7 +586,7 @@ void Plansza::spawn_bomber() { } void Plansza::spawn_kamikadze() { - if (KamikadzeSpawnClock.getElapsedTime().asSeconds() >= 5) { // Spawn co 10 sekund + if (KamikadzeSpawnClock.getElapsedTime().asSeconds() >= 50) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); KEnemies.emplace_back(spawnX, -50, KamikadzeTexture); std::cout << "Spawned Kamikadze Enemy at X: " << spawnX << std::endl; From c898aa0d81087c48941be23beb372b2d1e2c1224 Mon Sep 17 00:00:00 2001 From: Kuba Date: Wed, 11 Dec 2024 23:00:07 +0100 Subject: [PATCH 13/18] wiazkowiec strzela, gora dol --- CMakeLists.txt | 4 ++ headers/Beam.h | 25 +++++++ headers/Plansza.h | 6 ++ headers/Wiazkowiec.h | 51 +++++++++++++ sources/Beam.cpp | 31 ++++++++ sources/Bomber.cpp | 4 +- sources/Plansza.cpp | 80 +++++++++++++++++++-- sources/Wiazkowiec.cpp | 157 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 352 insertions(+), 6 deletions(-) create mode 100644 headers/Beam.h create mode 100644 headers/Wiazkowiec.h create mode 100644 sources/Beam.cpp create mode 100644 sources/Wiazkowiec.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dbfe23..522c937 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,10 @@ add_executable(LotoStatek main.cpp sources/Bomber.cpp headers/Kamikadze.h sources/Kamikadze.cpp + headers/wiazkowiec.h + sources/Wiazkowiec.cpp + headers/Beam.h + sources/Beam.cpp ) if(WIN32) diff --git a/headers/Beam.h b/headers/Beam.h new file mode 100644 index 0000000..70bd6aa --- /dev/null +++ b/headers/Beam.h @@ -0,0 +1,25 @@ +#ifndef LOTOSTATEK_BEAM_H +#define LOTOSTATEK_BEAM_H + +#include +#include "Position.h" + +class Beam { +public: + Beam(float x, float y, float width, float height, const sf::Color& color); + + void update(); + void render(sf::RenderWindow& window); + + sf::FloatRect getBounds() const; + + bool isVisible() const; + void setVisible(bool visible); + + +private: + sf::RectangleShape beamShape; + bool visible; +}; + +#endif // LOTOSTATEK_BEAM_H \ No newline at end of file diff --git a/headers/Plansza.h b/headers/Plansza.h index 551c0d0..cfbea3f 100644 --- a/headers/Plansza.h +++ b/headers/Plansza.h @@ -6,6 +6,8 @@ #include "AdvancedEnemy.h" #include "Bomber.h" #include "Kamikadze.h" +#include "Wiazkowiec.h" +#include "Beam.h" #include "RandomNumberGenerator.h" #include "SFML/System/Clock.hpp" #include "SFML/Graphics/RenderWindow.hpp" @@ -44,6 +46,7 @@ private: sf::Texture meteorTexture1; sf::Texture meteorTexture2; sf::Texture enemyBulletTexture; + sf::Texture WiazkaTexture; sf::Texture BombaTexture; sf::Texture playerTexture; sf::Texture playerBulletTexture; @@ -52,16 +55,19 @@ private: sf::Texture advancedEnemyTexture; sf::Texture BomberEnemyTexture; sf::Texture KamikadzeTexture; + sf::Texture WiazkowiecTexture; sf::Clock spawnClock; sf::Clock shooterSpawnClock; std::vector enemies; std::vector AEnemies; std::vector BEnemies; std::vector KEnemies; + std::vector WEnemies; sf::Clock enemySpawnClock; sf::Clock AenemySpawnClock; sf::Clock BomberSpawnClock; sf::Clock KamikadzeSpawnClock; + sf::Clock WiazkowiecSpawnClock; std::vector meteors; sf::RenderWindow *window; }; diff --git a/headers/Wiazkowiec.h b/headers/Wiazkowiec.h new file mode 100644 index 0000000..8a44ae5 --- /dev/null +++ b/headers/Wiazkowiec.h @@ -0,0 +1,51 @@ +#ifndef WIAZKOWIEC_H +#define WIAZKOWIEC_H + +#include "Enemy.h" +#include "Actor.h" +#include "Beam.h" +enum class DirectionW { + Up, + Down, + Left, + Right +}; + +class Wiazkowiec : public Actor { +public: + Wiazkowiec(int x, int y, const sf::Texture& texture); + + void shoot() override; + void move(float deltaX, float deltaY) override; + void moveLeft() override; + void moveRight() override; + void moveUp() override; + void moveDown() override; + void setRandomDirection(); + + void update(); + + void render(sf::RenderWindow &window); + + bool isAlive() const; + void takeDamage(); + void updateDirection(); + bool isShooting() const; + const Beam& getBeam() const; + + +private: + sf::Clock shootClock; + sf::Texture WiazkaTexture; + float movementSpeed = 2.0f; + bool alive = true; + DirectionW direction = DirectionW::Down; + Beam beam; // Wiązka + bool shooting = false; // Czy obecnie strzela + sf::Clock shootingClock; // Zegar kontrolujący czas strzału + float beamDuration = 1.0f; // Czas trwania widoczności wiązki (w sekundach) + + void spawnBeam(); // Tworzy wiązkę +}; + +#endif //WIAZKOWIEC_H diff --git a/sources/Beam.cpp b/sources/Beam.cpp new file mode 100644 index 0000000..afd3ac4 --- /dev/null +++ b/sources/Beam.cpp @@ -0,0 +1,31 @@ +#include "../headers/Beam.h" + +Beam::Beam(float x, float y, float width, float height, const sf::Color& color) + : visible(false) { + beamShape.setPosition(x, y); + beamShape.setSize({width, height}); + beamShape.setFillColor(color); +} + +void Beam::update() { + // Wiązka może mieć logikę do czasu, jeśli potrzebne +} + +void Beam::render(sf::RenderWindow& window) { + if (visible) { + window.draw(beamShape); + } +} + +sf::FloatRect Beam::getBounds() const { + return beamShape.getGlobalBounds(); +} + +bool Beam::isVisible() const { + return visible; +} + +void Beam::setVisible(bool visible) { + this->visible = visible; +} + diff --git a/sources/Bomber.cpp b/sources/Bomber.cpp index 4114d3a..76b090c 100644 --- a/sources/Bomber.cpp +++ b/sources/Bomber.cpp @@ -25,13 +25,13 @@ void Bomber::setRandomDirection() { if (position.y > 0) direction = DirectionB::Up; break; case 1: - if (position.y < 800) direction = DirectionB::Down; + if (position.y < 600) direction = DirectionB::Down; break; case 2: if (position.x > 0) direction = DirectionB::Left; break; case 3: - if (position.x < 600) direction = DirectionB::Right; + if (position.x < 800) direction = DirectionB::Right; break; } } diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 4c68109..8b2217c 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -34,11 +34,15 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render std::cerr << "Failed to load enemy texture!" << std::endl; exit(-1); } + if (!WiazkaTexture.loadFromFile("../assets/img/bullets/wiazka.png")) { + std::cerr << "Failed to load wiazka texture!" << std::endl; + exit(-1); + } if (!advancedEnemyTexture.loadFromFile("../assets/img/enemy/advanced_enemy.png")) { std::cerr << "Failed to load advanced enemy texture!" << std::endl; exit(-1); } - if (!BomberEnemyTexture.loadFromFile("../assets/img/enemy/wiazkowiec.png")) { + if (!BomberEnemyTexture.loadFromFile("../assets/img/enemy/bomber.png")) { std::cerr << "Failed to load advanced enemy texture!" << std::endl; exit(-1); } @@ -50,6 +54,10 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render std::cerr << "Failed to load BombaTexture!" << std::endl; exit(-1); } + if (!WiazkowiecTexture.loadFromFile("../assets/img/enemy/wiazkowiec.png")) { + std::cerr << "Failed to load BombaTexture!" << std::endl; + exit(-1); + } spawnClock.restart(); } @@ -95,7 +103,7 @@ void Plansza::update() { //spawn_meteor(); spawn_enemy(); spawn_advanced_enemy(); - //spawn_wiazkowiec(); + spawn_wiazkowiec(); spawn_bomber(); spawn_kamikadze(); @@ -361,6 +369,51 @@ void Plansza::update() { } } + for (auto& bomberEnemy : BEnemies) { + for (auto it = bomberEnemy.getBullets().begin(); it != bomberEnemy.getBullets().end();) { + bool bulletDestroyed = false; + + // Kolizja pocisku gracza z pociskiem Bombera + for (auto playerBulletIt = ship.getBullets().begin(); playerBulletIt != ship.getBullets().end();) { + if (playerBulletIt->getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + // Usuń pocisk Bombera i pocisk gracza + it = bomberEnemy.getBullets().erase(it); + playerBulletIt = ship.getBullets().erase(playerBulletIt); + bulletDestroyed = true; + break; + } else { + ++playerBulletIt; + } + } + + // Kolizja rakiety gracza z pociskiem Bombera + if (!bulletDestroyed) { + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (rocketIt->getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + // Usuń pocisk Bombera i rakietę gracza + it = bomberEnemy.getBullets().erase(it); + rocketIt = ship.getRockets().erase(rocketIt); + bulletDestroyed = true; + break; + } else { + ++rocketIt; + } + } + } + + // Jeśli pocisk Bombera przetrwał dotychczasowe sprawdzenia, wykonaj inne działania + if (!bulletDestroyed) { + if (ship.getSprite().getGlobalBounds().intersects(it->getSprite().getGlobalBounds())) { + // Kolizja pocisku Bombera z graczem + ship.takeDamage(); + it = bomberEnemy.getBullets().erase(it); + } else { + ++it; + } + } + } + } + // Usuwanie pocisków, które są poza ekranem srednio to dziala for (auto enemyIt = enemies.begin(); enemyIt != enemies.end(); ) { for (auto bulletIt = enemyIt->getBullets().begin(); bulletIt != enemyIt->getBullets().end();) { @@ -451,7 +504,18 @@ void Plansza::update() { } } + for (auto& wiazkowiec : WEnemies) { + wiazkowiec.update(); + if (wiazkowiec.isShooting() && wiazkowiec.getBeam().isVisible()) { + if (ship.getSprite().getGlobalBounds().intersects(wiazkowiec.getBeam().getBounds())) { + ship.takeDamage(); // Gracz otrzymuje obrażenia + } + } + + window->draw(wiazkowiec.getSprite()); + wiazkowiec.render(*window); + } //oblsuga dla rakiety for (auto enemyIt = enemies.begin(); enemyIt != enemies.end();) { @@ -577,7 +641,7 @@ void Plansza::spawn_advanced_enemy() { } void Plansza::spawn_bomber() { - if (BomberSpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund + if (BomberSpawnClock.getElapsedTime().asSeconds() >= 120) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); BEnemies.emplace_back(spawnX, -50, BomberEnemyTexture, BombaTexture); std::cout << "Spawned Bomber Enemy at X: " << spawnX << std::endl; @@ -586,7 +650,7 @@ void Plansza::spawn_bomber() { } void Plansza::spawn_kamikadze() { - if (KamikadzeSpawnClock.getElapsedTime().asSeconds() >= 50) { // Spawn co 10 sekund + if (KamikadzeSpawnClock.getElapsedTime().asSeconds() >= 220) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); KEnemies.emplace_back(spawnX, -50, KamikadzeTexture); std::cout << "Spawned Kamikadze Enemy at X: " << spawnX << std::endl; @@ -594,6 +658,14 @@ void Plansza::spawn_kamikadze() { } } +void Plansza::spawn_wiazkowiec() { + if (WiazkowiecSpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund + int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); + WEnemies.emplace_back(spawnX, -50, WiazkowiecTexture); + std::cout << "Spawned Wiazkowiec Enemy at X: " << spawnX << std::endl; + WiazkowiecSpawnClock.restart(); + } +} diff --git a/sources/Wiazkowiec.cpp b/sources/Wiazkowiec.cpp new file mode 100644 index 0000000..a9443f9 --- /dev/null +++ b/sources/Wiazkowiec.cpp @@ -0,0 +1,157 @@ +#include "../headers/Wiazkowiec.h" + +#include + +#include "../headers/Bullet.h" +#include + +Wiazkowiec::Wiazkowiec(int x, int y, const sf::Texture& texture) : Actor(x, y, texture), beam(0, 0, 50.f, 50.f, sf::Color::Red) { + actorSprite.setTexture(texture); + hp = 2; // 2 punkty życia + firerate = 5000; // Strzela co 10 + moving_speed = 1.0f; // Prędkość + // BombaTexture.loadFromFile("../assets/img/bullets/bomba.png"); +} + +void Wiazkowiec::spawnBeam() { + float beamX = position.x; + float beamY = position.y; + float beamWidth = 50.f; + float beamHeight = 0.f; + + switch (direction) { + case DirectionW::Up: + beamHeight = position.y; + beamY -= beamHeight; + break; + case DirectionW::Down: + beamHeight = 600 - position.y; + break; + case DirectionW::Left: + beamWidth = position.x; + beamX -= beamWidth; + break; + case DirectionW::Right: + beamWidth = 800 - position.x; + break; + } + + beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); + beam.setVisible(true); + + shooting = true; + shootingClock.restart(); // Reset zegara +} + +// Strzał wiązki +void Wiazkowiec::shoot() { + if (!shooting) { + spawnBeam(); + std::cout << "Wiazkowiec shot a beam!" << std::endl; + } +} + +void Wiazkowiec::setRandomDirection() { + // Losowanie kierunku: 0 = Up, 1 = Down, 2 = Left, 3 = Right + int directionIndex = std::rand() % 4; + + switch (directionIndex) { + case 0: + direction = DirectionW::Up; + break; + case 1: + direction = DirectionW::Down; + break; + case 2: + direction = DirectionW::Left; + break; + case 3: + direction = DirectionW::Right; + break; + } +} + +void Wiazkowiec::updateDirection() { + // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + if (position.y <= 0) { + direction = DirectionW::Down; + } else if (position.y >= 800) { + direction = DirectionW::Up; + } + + // logika dla kierunku lewo/prawo + if (position.x <= 0) { + direction = DirectionW::Right; + } else if (position.x >= 1200) { + direction = DirectionW::Left; + } +} + +void Wiazkowiec::move(float deltaX, float deltaY) { + actorSprite.move(deltaX, deltaY); + position.x += static_cast(deltaX); + position.y += static_cast(deltaY); +} + +void Wiazkowiec::moveLeft() { move(-moving_speed, 0.0f); } +void Wiazkowiec::moveRight() { move(moving_speed, 0.0f); } +void Wiazkowiec::moveUp() { move(0.0f, -moving_speed); } +void Wiazkowiec::moveDown() { move(0.0f, moving_speed); } + +void Wiazkowiec::update() { + if (shooting) { + // Kontrola zakończenia strzału + if (shootingClock.getElapsedTime().asSeconds() >= beamDuration) { + beam.setVisible(false); + shooting = false; + setRandomDirection(); // Zmień kierunek po strzale + } + } else { + updateDirection(); + + switch (direction) { + case DirectionW::Up: + moveUp(); + break; + case DirectionW::Down: + moveDown(); + break; + case DirectionW::Left: + moveLeft(); + break; + case DirectionW::Right: + moveRight(); + break; + } + + if (shootClock.getElapsedTime().asSeconds() >= 3.0f) { // Co 3 sekundy + shoot(); + shootClock.restart(); + } + } +} + +// Ustawianie widoczności wiązki podczas renderowania +void Wiazkowiec::render(sf::RenderWindow& window) { + if (beam.isVisible()) { + beam.render(window); + } +} + +bool Wiazkowiec::isAlive() const { + return alive; +} + +void Wiazkowiec::takeDamage() { + if (--hp <= 0) { + alive = false; + } +} + +bool Wiazkowiec::isShooting() const { + return shooting; +} + +const Beam& Wiazkowiec::getBeam() const { + return beam; +} \ No newline at end of file From 1c0e5d0293cc92ff5a665ebf99d80feb2b2c01d1 Mon Sep 17 00:00:00 2001 From: Kuba Date: Wed, 11 Dec 2024 23:00:19 +0100 Subject: [PATCH 14/18] wiazkowiec strzela, gora dol --- assets/img/bullets/wiazka.png | Bin 0 -> 40209 bytes assets/img/enemy/bomber.png | Bin 0 -> 11038 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/img/bullets/wiazka.png create mode 100644 assets/img/enemy/bomber.png diff --git a/assets/img/bullets/wiazka.png b/assets/img/bullets/wiazka.png new file mode 100644 index 0000000000000000000000000000000000000000..a70f3f0411eb46287fa8c90bf8940b0041958258 GIT binary patch literal 40209 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 literal 0 HcmV?d00001 diff --git a/assets/img/enemy/bomber.png b/assets/img/enemy/bomber.png new file mode 100644 index 0000000000000000000000000000000000000000..836259cda63b4d8f2bf7504d964782805ab73c41 GIT binary patch literal 11038 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 Date: Wed, 11 Dec 2024 23:47:20 +0100 Subject: [PATCH 15/18] 5 przeciwnikow, jakos to dziala --- assets/img/{bullets => wiazka}/wiazka.png | Bin headers/Beam.h | 4 ++ headers/Player.h | 6 ++ headers/Wiazkowiec.h | 6 +- sources/Beam.cpp | 28 +++++++-- sources/Plansza.cpp | 70 +++++++++++++++++----- sources/Player.cpp | 43 +++++++++---- sources/Wiazkowiec.cpp | 43 +++++++++---- 8 files changed, 158 insertions(+), 42 deletions(-) rename assets/img/{bullets => wiazka}/wiazka.png (100%) diff --git a/assets/img/bullets/wiazka.png b/assets/img/wiazka/wiazka.png similarity index 100% rename from assets/img/bullets/wiazka.png rename to assets/img/wiazka/wiazka.png diff --git a/headers/Beam.h b/headers/Beam.h index 70bd6aa..704d15d 100644 --- a/headers/Beam.h +++ b/headers/Beam.h @@ -8,6 +8,8 @@ class Beam { public: Beam(float x, float y, float width, float height, const sf::Color& color); + void draw(sf::RenderWindow &window); + void update(); void render(sf::RenderWindow& window); @@ -20,6 +22,8 @@ public: private: sf::RectangleShape beamShape; bool visible; + sf::Texture beamTexture; + sf::Sprite beamSprite; }; #endif // LOTOSTATEK_BEAM_H \ No newline at end of file diff --git a/headers/Player.h b/headers/Player.h index 721d761..4793332 100644 --- a/headers/Player.h +++ b/headers/Player.h @@ -3,6 +3,8 @@ #include +#include + #include "Actor.h" #include "Rocket.h" @@ -20,6 +22,7 @@ public: void moveDown() override; void takeDamage(); bool isAlive() const; + void update(); std::vector& getRockets(); private: std::chrono::steady_clock::time_point lastShotTime = std::chrono::steady_clock::now(); @@ -27,6 +30,9 @@ private: sf::Texture rocketTexture; int health = 3; // Liczba punktów życia gracza sf::Texture bulletTexture; + bool isImmortal = false; // Czy gracz jest chwilowo nietykalny + sf::Clock immortalityClock; // Zegar kontrolujący czas nieśmiertelności + float immortalityDuration = 1.5f; // Czas trwania nieśmiertelności (w sekundach) }; diff --git a/headers/Wiazkowiec.h b/headers/Wiazkowiec.h index 8a44ae5..1c1fe64 100644 --- a/headers/Wiazkowiec.h +++ b/headers/Wiazkowiec.h @@ -32,9 +32,12 @@ public: void updateDirection(); bool isShooting() const; const Beam& getBeam() const; + void setPlanszaHeight(float height); + void setMapBounds(float width, float height); private: + float planszaHeight = 800.f; sf::Clock shootClock; sf::Texture WiazkaTexture; float movementSpeed = 2.0f; @@ -44,7 +47,8 @@ private: bool shooting = false; // Czy obecnie strzela sf::Clock shootingClock; // Zegar kontrolujący czas strzału float beamDuration = 1.0f; // Czas trwania widoczności wiązki (w sekundach) - + float mapWidth; // Szerokość mapy/planszy + float mapHeight; void spawnBeam(); // Tworzy wiązkę }; diff --git a/sources/Beam.cpp b/sources/Beam.cpp index afd3ac4..c0771a6 100644 --- a/sources/Beam.cpp +++ b/sources/Beam.cpp @@ -1,20 +1,40 @@ #include "../headers/Beam.h" +#include + Beam::Beam(float x, float y, float width, float height, const sf::Color& color) : visible(false) { beamShape.setPosition(x, y); beamShape.setSize({width, height}); beamShape.setFillColor(color); + + if (!beamTexture.loadFromFile("../assets/img/wiazka/wiazka.png")) { + std::cerr << "Błąd! Nie można załadować tekstury wiazka.png" << std::endl; + } + beamSprite.setTexture(beamTexture); + + if (beamTexture.getSize().x > 0 && beamTexture.getSize().y > 0) { + float scaleX = width / beamTexture.getSize().x; + float scaleY = height / beamTexture.getSize().y; + beamSprite.setScale(scaleX, scaleY); + beamSprite.setPosition(x, y); + } else { + std::cerr << "Błąd: Tekstura wiązki nie została poprawnie załadowana." << std::endl; + } + +} + +void Beam::draw(sf::RenderWindow& window) { + + window.draw(beamSprite); + } void Beam::update() { - // Wiązka może mieć logikę do czasu, jeśli potrzebne } void Beam::render(sf::RenderWindow& window) { - if (visible) { - window.draw(beamShape); - } + window.draw(beamSprite); } sf::FloatRect Beam::getBounds() const { diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 8b2217c..0a7f4a4 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -34,10 +34,6 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render std::cerr << "Failed to load enemy texture!" << std::endl; exit(-1); } - if (!WiazkaTexture.loadFromFile("../assets/img/bullets/wiazka.png")) { - std::cerr << "Failed to load wiazka texture!" << std::endl; - exit(-1); - } if (!advancedEnemyTexture.loadFromFile("../assets/img/enemy/advanced_enemy.png")) { std::cerr << "Failed to load advanced enemy texture!" << std::endl; exit(-1); @@ -55,7 +51,7 @@ Plansza::Plansza(unsigned int windowHeight, unsigned int windowWidth, sf::Render exit(-1); } if (!WiazkowiecTexture.loadFromFile("../assets/img/enemy/wiazkowiec.png")) { - std::cerr << "Failed to load BombaTexture!" << std::endl; + std::cerr << "Failed to load Wiazkowiec texture!" << std::endl; exit(-1); } spawnClock.restart(); @@ -101,6 +97,7 @@ void Plansza::update() { // generowanie nowego meteoru //spawn_meteor(); + ship.update(); spawn_enemy(); spawn_advanced_enemy(); spawn_wiazkowiec(); @@ -414,6 +411,19 @@ void Plansza::update() { } } + for (auto& wiazkowiec : WEnemies) { + wiazkowiec.update(); + + if (wiazkowiec.isShooting() && wiazkowiec.getBeam().isVisible()) { + if (ship.getSprite().getGlobalBounds().intersects(wiazkowiec.getBeam().getBounds())) { + ship.takeDamage(); // Gracz otrzymuje obrażenia + } + } + + window->draw(wiazkowiec.getSprite()); + wiazkowiec.render(*window); + } + // Usuwanie pocisków, które są poza ekranem srednio to dziala for (auto enemyIt = enemies.begin(); enemyIt != enemies.end(); ) { for (auto bulletIt = enemyIt->getBullets().begin(); bulletIt != enemyIt->getBullets().end();) { @@ -504,19 +514,27 @@ void Plansza::update() { } } - for (auto& wiazkowiec : WEnemies) { - wiazkowiec.update(); - - if (wiazkowiec.isShooting() && wiazkowiec.getBeam().isVisible()) { - if (ship.getSprite().getGlobalBounds().intersects(wiazkowiec.getBeam().getBounds())) { - ship.takeDamage(); // Gracz otrzymuje obrażenia + for (auto wiazkowiecIt = WEnemies.begin(); wiazkowiecIt != WEnemies.end();) { + bool hit = false; + for (auto bulletIt = ship.getBullets().begin(); bulletIt != ship.getBullets().end();) { + if (wiazkowiecIt->getSprite().getGlobalBounds().intersects(bulletIt->getSprite().getGlobalBounds())) { + bulletIt = ship.getBullets().erase(bulletIt); + wiazkowiecIt->takeDamage(); + hit = true; + break; + } else { + ++bulletIt; } } - - window->draw(wiazkowiec.getSprite()); - wiazkowiec.render(*window); + if (hit && !wiazkowiecIt->isAlive()) { + wiazkowiecIt = WEnemies.erase(wiazkowiecIt); // Usunięcie przeciwnika Wiazkowiec + } else { + ++wiazkowiecIt; + } } + + //oblsuga dla rakiety for (auto enemyIt = enemies.begin(); enemyIt != enemies.end();) { bool hit = false; @@ -594,6 +612,25 @@ void Plansza::update() { } } + for (auto wiazkowiecIt = WEnemies.begin(); wiazkowiecIt != WEnemies.end();) { + bool hit = false; + for (auto rocketIt = ship.getRockets().begin(); rocketIt != ship.getRockets().end();) { + if (wiazkowiecIt->getSprite().getGlobalBounds().intersects(rocketIt->getSprite().getGlobalBounds())) { + rocketIt = ship.getRockets().erase(rocketIt); + wiazkowiecIt->takeDamage(); + hit = true; + break; + } else { + ++rocketIt; + } + } + if (hit && !wiazkowiecIt->isAlive()) { + wiazkowiecIt = WEnemies.erase(wiazkowiecIt); + } else { + ++wiazkowiecIt; + } + } + } @@ -661,7 +698,10 @@ void Plansza::spawn_kamikadze() { void Plansza::spawn_wiazkowiec() { if (WiazkowiecSpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); - WEnemies.emplace_back(spawnX, -50, WiazkowiecTexture); + Wiazkowiec wiazkowiec(spawnX, -50, WiazkowiecTexture); + wiazkowiec.setPlanszaHeight(size.height); // Przekazanie wysokości okna + wiazkowiec.setMapBounds(size.width, size.height); + WEnemies.push_back(wiazkowiec); std::cout << "Spawned Wiazkowiec Enemy at X: " << spawnX << std::endl; WiazkowiecSpawnClock.restart(); } diff --git a/sources/Player.cpp b/sources/Player.cpp index f3b3810..5e64758 100644 --- a/sources/Player.cpp +++ b/sources/Player.cpp @@ -34,17 +34,40 @@ void Player::alternate_shoot() { } } -void Player::takeDamage() { - if (health > 0) { - health--; - std::cout << "Player hit! Remaining health: " << health << "\n"; - - - if (health <= 0) { - std::cout << "Player has been destroyed!\n"; - std::cout << "You lost the game!\n"; - +void Player::update() { + // Wyłącz nieśmiertelność po określonym czasie + if (isImmortal && immortalityClock.getElapsedTime().asSeconds() >= immortalityDuration) { + isImmortal = false; + std::cout << "Immortality ended.\n"; } + + // Efekt migania podczas nieśmiertelności + if (isImmortal) { + if (static_cast(immortalityClock.getElapsedTime().asMilliseconds() / 200) % 2 == 0) { + actorSprite.setColor(sf::Color(255, 255, 255, 128)); // Półprzezroczysty + } else { + actorSprite.setColor(sf::Color(255, 255, 255, 255)); // Normalny + } + } else { + actorSprite.setColor(sf::Color(255, 255, 255, 255)); // Normalny + } +} + +void Player::takeDamage() { + if (!isImmortal) { + if (health > 0) { + health--; + std::cout << "Player hit! Remaining health: " << health << "\n"; + isImmortal = true; // Aktywuj chwilową nieśmiertelność + immortalityClock.restart(); + + + if (health <= 0) { + std::cout << "Player has been destroyed!\n"; + std::cout << "You lost the game!\n"; + + } + } } } diff --git a/sources/Wiazkowiec.cpp b/sources/Wiazkowiec.cpp index a9443f9..954dd2b 100644 --- a/sources/Wiazkowiec.cpp +++ b/sources/Wiazkowiec.cpp @@ -13,6 +13,15 @@ Wiazkowiec::Wiazkowiec(int x, int y, const sf::Texture& texture) : Actor(x, y, t // BombaTexture.loadFromFile("../assets/img/bullets/bomba.png"); } +void Wiazkowiec::setPlanszaHeight(float height) { + planszaHeight = height; +} + +void Wiazkowiec::setMapBounds(float width, float height) { + mapWidth = width; + mapHeight = height; +} + void Wiazkowiec::spawnBeam() { float beamX = position.x; float beamY = position.y; @@ -23,16 +32,24 @@ void Wiazkowiec::spawnBeam() { case DirectionW::Up: beamHeight = position.y; beamY -= beamHeight; + beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); break; case DirectionW::Down: - beamHeight = 600 - position.y; + beamHeight = planszaHeight - position.y; // Dynamiczna wysokość okna + beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); break; case DirectionW::Left: - beamWidth = position.x; - beamX -= beamWidth; + beamHeight = 50.f; // Stała wysokość + beamWidth = position.x; + beamX -= beamWidth; // Wiązka w lewo od pozycji statku + beamY = position.y + (actorSprite.getGlobalBounds().height / 2) - 25.f; + beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); break; case DirectionW::Right: - beamWidth = 800 - position.x; + beamHeight = 50.f; // Stała wysokość + beamWidth = 800 - position.x; + beamY = position.y + (actorSprite.getGlobalBounds().height / 2) - 25.f; + beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); break; } @@ -72,17 +89,19 @@ void Wiazkowiec::setRandomDirection() { } void Wiazkowiec::updateDirection() { - // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + auto spriteBounds = actorSprite.getGlobalBounds(); + + // Kontrola dolnej i górnej krawędzi if (position.y <= 0) { direction = DirectionW::Down; - } else if (position.y >= 800) { + } else if (position.y + spriteBounds.height >= mapHeight) { direction = DirectionW::Up; } - // logika dla kierunku lewo/prawo + // Kontrola lewej i prawej krawędzi if (position.x <= 0) { direction = DirectionW::Right; - } else if (position.x >= 1200) { + } else if (position.x + spriteBounds.width >= mapWidth) { direction = DirectionW::Left; } } @@ -111,16 +130,16 @@ void Wiazkowiec::update() { switch (direction) { case DirectionW::Up: - moveUp(); + if (position.y > 0) moveUp(); break; case DirectionW::Down: - moveDown(); + if (position.y + actorSprite.getGlobalBounds().height < mapHeight) moveDown(); break; case DirectionW::Left: - moveLeft(); + if (position.x > 0) moveLeft(); break; case DirectionW::Right: - moveRight(); + if (position.x + actorSprite.getGlobalBounds().width < mapWidth) moveRight(); break; } From 168ba2e477153604b93543252269115217c53578 Mon Sep 17 00:00:00 2001 From: Kuba Date: Wed, 11 Dec 2024 23:52:06 +0100 Subject: [PATCH 16/18] 5 przeciwnikow, do poprawy lewa strona mapy przy poruszaniu i teksturki --- headers/Kamikadze.h | 2 +- headers/Player.h | 4 ++-- headers/Wiazkowiec.h | 8 +++----- sources/Plansza.cpp | 1 - sources/Wiazkowiec.cpp | 24 +++++++++--------------- 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/headers/Kamikadze.h b/headers/Kamikadze.h index 8f33f86..9445530 100644 --- a/headers/Kamikadze.h +++ b/headers/Kamikadze.h @@ -35,7 +35,7 @@ public: void explode(const sf::Vector2f &playerPosition, bool &playerHit); private: - bool exploding = false; // Czy kamikadze obecnie eksploduje + bool exploding = false; sf::Clock explosionClock; sf::Clock shootClock; float movementSpeed = 2.0f; diff --git a/headers/Player.h b/headers/Player.h index 4793332..a3a64d6 100644 --- a/headers/Player.h +++ b/headers/Player.h @@ -30,9 +30,9 @@ private: sf::Texture rocketTexture; int health = 3; // Liczba punktów życia gracza sf::Texture bulletTexture; - bool isImmortal = false; // Czy gracz jest chwilowo nietykalny + bool isImmortal = false; // flaga na immortal sf::Clock immortalityClock; // Zegar kontrolujący czas nieśmiertelności - float immortalityDuration = 1.5f; // Czas trwania nieśmiertelności (w sekundach) + float immortalityDuration = 1.5f; // Czas trwania nieśmiertelności w sec }; diff --git a/headers/Wiazkowiec.h b/headers/Wiazkowiec.h index 1c1fe64..933e86d 100644 --- a/headers/Wiazkowiec.h +++ b/headers/Wiazkowiec.h @@ -44,11 +44,9 @@ private: bool alive = true; DirectionW direction = DirectionW::Down; Beam beam; // Wiązka - bool shooting = false; // Czy obecnie strzela - sf::Clock shootingClock; // Zegar kontrolujący czas strzału - float beamDuration = 1.0f; // Czas trwania widoczności wiązki (w sekundach) - float mapWidth; // Szerokość mapy/planszy - float mapHeight; + bool shooting = false; + sf::Clock shootingClock; + float beamDuration = 1.0f; void spawnBeam(); // Tworzy wiązkę }; diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index 0a7f4a4..d16135a 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -700,7 +700,6 @@ void Plansza::spawn_wiazkowiec() { int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); Wiazkowiec wiazkowiec(spawnX, -50, WiazkowiecTexture); wiazkowiec.setPlanszaHeight(size.height); // Przekazanie wysokości okna - wiazkowiec.setMapBounds(size.width, size.height); WEnemies.push_back(wiazkowiec); std::cout << "Spawned Wiazkowiec Enemy at X: " << spawnX << std::endl; WiazkowiecSpawnClock.restart(); diff --git a/sources/Wiazkowiec.cpp b/sources/Wiazkowiec.cpp index 954dd2b..4e3d7d3 100644 --- a/sources/Wiazkowiec.cpp +++ b/sources/Wiazkowiec.cpp @@ -17,11 +17,6 @@ void Wiazkowiec::setPlanszaHeight(float height) { planszaHeight = height; } -void Wiazkowiec::setMapBounds(float width, float height) { - mapWidth = width; - mapHeight = height; -} - void Wiazkowiec::spawnBeam() { float beamX = position.x; float beamY = position.y; @@ -89,23 +84,22 @@ void Wiazkowiec::setRandomDirection() { } void Wiazkowiec::updateDirection() { - auto spriteBounds = actorSprite.getGlobalBounds(); - - // Kontrola dolnej i górnej krawędzi + // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi if (position.y <= 0) { direction = DirectionW::Down; - } else if (position.y + spriteBounds.height >= mapHeight) { + } else if (position.y >= 800) { direction = DirectionW::Up; } - // Kontrola lewej i prawej krawędzi + // logika dla kierunku lewo/prawo if (position.x <= 0) { direction = DirectionW::Right; - } else if (position.x + spriteBounds.width >= mapWidth) { + } else if (position.x >= 1200) { direction = DirectionW::Left; } } + void Wiazkowiec::move(float deltaX, float deltaY) { actorSprite.move(deltaX, deltaY); position.x += static_cast(deltaX); @@ -130,16 +124,16 @@ void Wiazkowiec::update() { switch (direction) { case DirectionW::Up: - if (position.y > 0) moveUp(); + moveUp(); break; case DirectionW::Down: - if (position.y + actorSprite.getGlobalBounds().height < mapHeight) moveDown(); + moveDown(); break; case DirectionW::Left: - if (position.x > 0) moveLeft(); + moveLeft(); break; case DirectionW::Right: - if (position.x + actorSprite.getGlobalBounds().width < mapWidth) moveRight(); + moveRight(); break; } From f1dc19e795484e3b3f880fa462c8c4373aba010b Mon Sep 17 00:00:00 2001 From: Kuba Date: Thu, 12 Dec 2024 00:11:24 +0100 Subject: [PATCH 17/18] Bomber i wiazkowiec nie wylaza poza ekran --- headers/Bomber.h | 3 +++ headers/Wiazkowiec.h | 3 ++- sources/Bomber.cpp | 34 +++++++++++++++++++++++++++------- sources/Kamikadze.cpp | 16 ++++++---------- sources/Plansza.cpp | 17 +++++++++-------- sources/Wiazkowiec.cpp | 42 ++++++++++++++++++++++++++++++------------ 6 files changed, 77 insertions(+), 38 deletions(-) diff --git a/headers/Bomber.h b/headers/Bomber.h index 9de6954..562268d 100644 --- a/headers/Bomber.h +++ b/headers/Bomber.h @@ -31,8 +31,11 @@ public: bool isAlive() const; void takeDamage(); void updateDirection(); + void setPlanszaHeight(float height, float width); private: + float planszaHeight = 800.f; + float planszaWidth = 600.f; sf::Clock shootClock; sf::Texture BombaTexture; float movementSpeed = 2.0f; diff --git a/headers/Wiazkowiec.h b/headers/Wiazkowiec.h index 933e86d..cf996ad 100644 --- a/headers/Wiazkowiec.h +++ b/headers/Wiazkowiec.h @@ -32,12 +32,13 @@ public: void updateDirection(); bool isShooting() const; const Beam& getBeam() const; - void setPlanszaHeight(float height); + void setPlanszaHeight(float height, float width); void setMapBounds(float width, float height); private: float planszaHeight = 800.f; + float planszaWidth = 600.f; sf::Clock shootClock; sf::Texture WiazkaTexture; float movementSpeed = 2.0f; diff --git a/sources/Bomber.cpp b/sources/Bomber.cpp index 76b090c..7a81cd9 100644 --- a/sources/Bomber.cpp +++ b/sources/Bomber.cpp @@ -7,11 +7,14 @@ Bomber::Bomber(int x, int y, const sf::Texture& texture, const sf::Texture& bull BombaTexture = bulletTexture; hp = 2; // 2 punkty życia firerate = 10000; // Strzela co 10 - moving_speed = 1.0f; // Prędkość - // BombaTexture.loadFromFile("../assets/img/bullets/bomba.png"); + moving_speed = 10.0f; // Prędkość +} + +void Bomber::setPlanszaHeight(float height, float width) { + planszaHeight = height; + planszaWidth = width; } -// Losuje losowy kierunek dla Bombera void Bomber::setRandomDirection() { std::random_device rd; std::mt19937 gen(rd()); @@ -47,22 +50,39 @@ void Bomber::shoot() { } void Bomber::updateDirection() { - // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + auto spriteBounds = actorSprite.getGlobalBounds(); // Pobierz rozmiar i pozycję sprite'a + + // Kontrola górnej i dolnej krawędzi (wysokości planszy) if (position.y <= 0) { direction = DirectionB::Down; - } else if (position.y >= 800) { + } else if (position.y + spriteBounds.height >= planszaHeight) { direction = DirectionB::Up; } - // logika dla kierunku lewo/prawo + // Kontrola lewej i prawej krawędzi (szerokości planszy) if (position.x <= 0) { direction = DirectionB::Right; - } else if (position.x >= 1200) { + } else if (position.x + spriteBounds.width >= planszaWidth) { direction = DirectionB::Left; } } void Bomber::move(float deltaX, float deltaY) { + auto spriteBounds = actorSprite.getGlobalBounds(); // Rozmiar i pozycja sprite'a + + // Zapobiegaj wyjściu poza poziome granice + if (position.x + deltaX < 0) { + deltaX = -position.x; + } else if (position.x + spriteBounds.width + deltaX > planszaWidth) { + deltaX = planszaWidth - (position.x + spriteBounds.width); + } + + // Zapobiegaj wyjściu poza pionowe granice + if (position.y + deltaY < 0) { + deltaY = -position.y; + } else if (position.y + spriteBounds.height + deltaY > planszaHeight) { + deltaY = planszaHeight - (position.y + spriteBounds.height); + } actorSprite.move(deltaX, deltaY); position.x += static_cast(deltaX); position.y += static_cast(deltaY); diff --git a/sources/Kamikadze.cpp b/sources/Kamikadze.cpp index c3aaeb0..e18927c 100644 --- a/sources/Kamikadze.cpp +++ b/sources/Kamikadze.cpp @@ -13,7 +13,6 @@ Kamikadze::Kamikadze(int x, int y, const sf::Texture& texture) : Actor(x, y, tex void Kamikadze::shoot(){} -// Losuje losowy kierunek dla Bombera void Kamikadze::setRandomDirection() { std::random_device rd; std::mt19937 gen(rd()); @@ -56,31 +55,28 @@ void Kamikadze::updateDirection() { } void Kamikadze::followPlayer(const sf::Vector2f& playerPosition) { - // Oblicz różnicę w pozycjach float diffX = playerPosition.x - position.x; float diffY = playerPosition.y - position.y; - // Normalizacja wektora (skrócenie kierunku do jednostkowego) float magnitude = std::sqrt(diffX * diffX + diffY * diffY); if (magnitude != 0) { diffX /= magnitude; diffY /= magnitude; - // Aktualizacja pozycji Kamikadze w kierunku gracza z uwzględnieniem prędkości + // Aktualizacja pozycji Kamikadze w kierunku gracza position.x += diffX * movementSpeed; position.y += diffY * movementSpeed; - } else { - // Jeśli Kamikadze jest dokładnie na pozycji gracza, zatrzymaj jego ruch + } else { //zatrzymanie kamikadze movementSpeed = 0.0f; } } void Kamikadze::explode(const sf::Vector2f& playerPosition, bool& playerHit) { if (!exploding) { - // Rozpocznij eksplozję + // Rozpocznij kamikadze exploding = true; explosionClock.restart(); - movementSpeed = 0.0f; // Zatrzymaj Kamikadze + movementSpeed = 0.0f; std::cout << "Kamikadze exploding!" << std::endl; std::cout << "Kamikadze position: (" << position.x << ", " << position.y << ")" << std::endl; @@ -121,9 +117,9 @@ void Kamikadze::moveDown() { move(0.0f, moving_speed); } void Kamikadze::update(const sf::Vector2f& playerPosition) { if (alive && !exploding) { - // Podążaj za graczem, dopóki Kamikadze jest żywy i nie eksploduje + // Podążanie za graczem, dopóki Kamikadze jest żywy followPlayer(playerPosition); - actorSprite.setPosition(position.x, position.y); // Aktualizuj sprite + actorSprite.setPosition(position.x, position.y); } } diff --git a/sources/Plansza.cpp b/sources/Plansza.cpp index d16135a..a7969c8 100644 --- a/sources/Plansza.cpp +++ b/sources/Plansza.cpp @@ -96,8 +96,8 @@ void Plansza::update() { } // generowanie nowego meteoru - //spawn_meteor(); ship.update(); + spawn_meteor(); spawn_enemy(); spawn_advanced_enemy(); spawn_wiazkowiec(); @@ -254,7 +254,7 @@ void Plansza::update() { } } for (auto it = BEnemies.begin(); it != BEnemies.end();) { - it->update(); // Ruch b + it->update(); // Ruch bombera it->shoot(); // Strzał przeciwnika window->draw(it->getSprite()); // Rysowanie na ekranie @@ -272,7 +272,6 @@ void Plansza::update() { sf::Vector2f playerPosition = ship.getSprite().getPosition(); // Aktualna pozycja gracza bool playerHit = false; - // Aktualizacja pozycji Kamikadze it->update(playerPosition); // Wybuch, gdy Kamikadze dotknie gracza @@ -289,7 +288,7 @@ void Plansza::update() { it->explode(playerPosition, playerHit); // Eksplozja trwa } - // Usunięcie martwego Kamikadze z listy + // Usunięcie martwego Kamikadze if (it->isAlive()) { window->draw(it->getSprite()); ++it; @@ -678,9 +677,11 @@ void Plansza::spawn_advanced_enemy() { } void Plansza::spawn_bomber() { - if (BomberSpawnClock.getElapsedTime().asSeconds() >= 120) { // Spawn co 10 sekund + if (BomberSpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); - BEnemies.emplace_back(spawnX, -50, BomberEnemyTexture, BombaTexture); + Bomber bomber(spawnX, -50, BomberEnemyTexture, BombaTexture); + bomber.setPlanszaHeight(size.height, size.width); // Przekazanie wysokości i szerokości okna + BEnemies.push_back(bomber); std::cout << "Spawned Bomber Enemy at X: " << spawnX << std::endl; BomberSpawnClock.restart(); } @@ -696,10 +697,10 @@ void Plansza::spawn_kamikadze() { } void Plansza::spawn_wiazkowiec() { - if (WiazkowiecSpawnClock.getElapsedTime().asSeconds() >= 10) { // Spawn co 10 sekund + if (WiazkowiecSpawnClock.getElapsedTime().asSeconds() >= 110) { // Spawn co 10 sekund int spawnX = RandomNumberGenerator::getRandomNumber(50, size.width - 50); Wiazkowiec wiazkowiec(spawnX, -50, WiazkowiecTexture); - wiazkowiec.setPlanszaHeight(size.height); // Przekazanie wysokości okna + wiazkowiec.setPlanszaHeight(size.height, size.width); // Przekazanie wysokości i szerokosci okna WEnemies.push_back(wiazkowiec); std::cout << "Spawned Wiazkowiec Enemy at X: " << spawnX << std::endl; WiazkowiecSpawnClock.restart(); diff --git a/sources/Wiazkowiec.cpp b/sources/Wiazkowiec.cpp index 4e3d7d3..c51371b 100644 --- a/sources/Wiazkowiec.cpp +++ b/sources/Wiazkowiec.cpp @@ -9,12 +9,12 @@ Wiazkowiec::Wiazkowiec(int x, int y, const sf::Texture& texture) : Actor(x, y, t actorSprite.setTexture(texture); hp = 2; // 2 punkty życia firerate = 5000; // Strzela co 10 - moving_speed = 1.0f; // Prędkość - // BombaTexture.loadFromFile("../assets/img/bullets/bomba.png"); + moving_speed = 5.0f; // Prędkość } -void Wiazkowiec::setPlanszaHeight(float height) { +void Wiazkowiec::setPlanszaHeight(float height, float width) { planszaHeight = height; + planszaWidth = width; } void Wiazkowiec::spawnBeam() { @@ -30,18 +30,18 @@ void Wiazkowiec::spawnBeam() { beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); break; case DirectionW::Down: - beamHeight = planszaHeight - position.y; // Dynamiczna wysokość okna + beamHeight = planszaHeight - position.y; beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); break; case DirectionW::Left: - beamHeight = 50.f; // Stała wysokość + beamHeight = 50.f; beamWidth = position.x; - beamX -= beamWidth; // Wiązka w lewo od pozycji statku + beamX -= beamWidth; beamY = position.y + (actorSprite.getGlobalBounds().height / 2) - 25.f; beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); break; case DirectionW::Right: - beamHeight = 50.f; // Stała wysokość + beamHeight = 50.f; beamWidth = 800 - position.x; beamY = position.y + (actorSprite.getGlobalBounds().height / 2) - 25.f; beam = Beam(beamX, beamY, beamWidth, beamHeight, sf::Color::Red); @@ -52,7 +52,7 @@ void Wiazkowiec::spawnBeam() { beam.setVisible(true); shooting = true; - shootingClock.restart(); // Reset zegara + shootingClock.restart(); } // Strzał wiązki @@ -84,23 +84,41 @@ void Wiazkowiec::setRandomDirection() { } void Wiazkowiec::updateDirection() { - // Zmieniamy kierunek przeciwnika, gdy dotrze do krawędzi + auto spriteBounds = actorSprite.getGlobalBounds(); // Pobierz rozmiar i pozycję sprite'a + + // Kontrola górnej i dolnej krawędzi if (position.y <= 0) { direction = DirectionW::Down; - } else if (position.y >= 800) { + } else if (position.y + spriteBounds.height >= planszaHeight) { direction = DirectionW::Up; } - // logika dla kierunku lewo/prawo + // Kontrola lewej i prawej krawędzi if (position.x <= 0) { direction = DirectionW::Right; - } else if (position.x >= 1200) { + } else if (position.x + spriteBounds.width >= planszaWidth) { direction = DirectionW::Left; } } void Wiazkowiec::move(float deltaX, float deltaY) { + auto spriteBounds = actorSprite.getGlobalBounds(); // Rozmiar i pozycja sprite'a + + // Zapobiegaj wyjściu poza poziome granice + if (position.x + deltaX < 0) { + deltaX = -position.x; + } else if (position.x + spriteBounds.width + deltaX > planszaWidth) { + deltaX = planszaWidth - (position.x + spriteBounds.width); + } + + // Zapobiegaj wyjściu poza pionowe granice + if (position.y + deltaY < 0) { + deltaY = -position.y; + } else if (position.y + spriteBounds.height + deltaY > planszaHeight) { + deltaY = planszaHeight - (position.y + spriteBounds.height); + } + actorSprite.move(deltaX, deltaY); position.x += static_cast(deltaX); position.y += static_cast(deltaY); From 87399213b307f95843a08425db4744983b258f43 Mon Sep 17 00:00:00 2001 From: Andrii Solianyk Date: Thu, 12 Dec 2024 22:22:01 +0100 Subject: [PATCH 18/18] Malutki refactor --- sources/Kamikadze.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sources/Kamikadze.cpp b/sources/Kamikadze.cpp index e18927c..5067acd 100644 --- a/sources/Kamikadze.cpp +++ b/sources/Kamikadze.cpp @@ -1,10 +1,10 @@ #include "../headers/Kamikadze.h" #include - -#include "../headers/Bullet.h" #include +#include "../headers/RandomNumberGenerator.h" + Kamikadze::Kamikadze(int x, int y, const sf::Texture& texture) : Actor(x, y, texture) { actorSprite.setTexture(texture); hp = 3; // 3 punkty życia @@ -14,11 +14,7 @@ Kamikadze::Kamikadze(int x, int y, const sf::Texture& texture) : Actor(x, y, tex void Kamikadze::shoot(){} void Kamikadze::setRandomDirection() { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution dist(0, 3); - - int randomDirection = dist(gen); + int randomDirection = RandomNumberGenerator::getRandomNumber(0,3); // Zapobieganie wyjscia poza ekran switch (randomDirection) {