term2 seminar3

This commit is contained in:
nihonium 2023-03-11 14:34:12 +03:00
parent 90d07dde3f
commit 611300636a
Signed by: nihonium
GPG key ID: 0251623741027CFC
141 changed files with 330 additions and 12119 deletions

View file

@ -44,6 +44,7 @@ public:
{
mCurrentFrame = mTextureRects.size() - 1;
mTime = mCurrentFrame / mAnimationSpeed;
mHasEnded = true;
}
}
}
@ -53,6 +54,9 @@ public:
sprite.setTextureRect(mTextureRects[mCurrentFrame]);
}
bool hasEnded() {
return mHasEnded;
}
private:
std::vector<sf::IntRect> mTextureRects {};
@ -61,4 +65,5 @@ private:
float mAnimationSpeed {1};
float mTime {0};
AnimationType mType {AnimationType::OneIteration};
};
bool mHasEnded = false;
};

View file

@ -0,0 +1,12 @@
#pragma once
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
struct Block {
sf::FloatRect mBlock;
bool mIsDestructable = false;
Block(sf::FloatRect b, bool isDestructable = false) : mBlock(b), mIsDestructable{isDestructable} {};
};

View file

@ -2,16 +2,6 @@
#include <SFML/Graphics.hpp>
#include "world.hpp"
/*
Для компиляции:
g++ main.cpp player.cpp player_states.cpp -lsfml-window -lsfml-system -lsfml-graphics
Графика взята отсюда:
https://rvros.itch.io/animated-pixel-hero
*/
int main()
{
sf::ContextSettings settings;
@ -24,17 +14,19 @@ int main()
double dt = 1.0 / 60;
World world;
world.addBlock({-500, 770, 20000, 400});
world.addBlock({-400, 100, 700, 300});
world.addBlock({600, 500, 300, 120});
world.addBlock({800, 0, 400, 200});
world.addBlock({-100, -700, 400, 100});
world.addBlock({700, -700, 400, 100});
world.addBlock({1500, -700, 400, 100});
world.addBlock({1100, -300, 400, 100});
world.addBlock({1100, 400, 400, 400});
world.addBlock({1900, -100, 200, 800});
world.addBlock({3000, 500, 1000, 200});
world.addBlock(sf::FloatRect{-500, 770, 20000, 400});
/* Разрушаемый блок слева от точки спавна игрока */
world.addBlock({sf::FloatRect{-200,700, 100, 500}, true});
world.addBlock(sf::FloatRect{-400, 100, 700, 300});
world.addBlock(sf::FloatRect{600, 500, 300, 120});
world.addBlock(sf::FloatRect{800, 0, 400, 200});
world.addBlock(sf::FloatRect{-100, -700, 400, 100});
world.addBlock(sf::FloatRect{700, -700, 400, 100});
world.addBlock(sf::FloatRect{1500, -700, 400, 100});
world.addBlock(sf::FloatRect{1100, -300, 400, 100});
world.addBlock(sf::FloatRect{1100, 400, 400, 400});
world.addBlock(sf::FloatRect{1900, -100, 200, 800});
world.addBlock(sf::FloatRect{3000, 500, 1000, 200});
while (window.isOpen())
{
@ -57,6 +49,3 @@ int main()
return 0;
}

View file

@ -4,8 +4,7 @@
#include <cmath>
#include "player.hpp"
#include "player_states.hpp"
#include "block.hpp"
Player::Player(sf::Vector2f position) : mPosition{position}
{
@ -58,19 +57,18 @@ void Player::draw(sf::RenderWindow& window)
{
window.draw(mSprite);
if (false) // For debuging
{
sf::RectangleShape shape {{mCollisionRect.width, mCollisionRect.height}};
shape.setPosition(mPosition.x + mCollisionRect.left, mPosition.y + mCollisionRect.top);
shape.setFillColor(sf::Color(150, 50, 50, 50));
window.draw(shape);
#ifdef _DEBUG
sf::RectangleShape shape {{mCollisionRect.width, mCollisionRect.height}};
shape.setPosition(mPosition.x + mCollisionRect.left, mPosition.y + mCollisionRect.top);
shape.setFillColor(sf::Color(150, 50, 50, 50));
window.draw(shape);
sf::CircleShape center {6};
center.setFillColor(sf::Color::Red);
center.setOrigin(center.getRadius(), center.getRadius());
center.setPosition(mPosition);
window.draw(center);
}
sf::CircleShape center {6};
center.setFillColor(sf::Color::Red);
center.setOrigin(center.getRadius(), center.getRadius());
center.setPosition(mPosition);
window.draw(center);
#endif
}
@ -79,14 +77,14 @@ void Player::handleEvents(const sf::Event& event)
mpState->handleEvents(this, event);
}
bool Player::handleCollision(const sf::FloatRect& rect)
bool Player::handleCollision(const Block& rect)
{
sf::FloatRect playerRect = {mPosition.x + mCollisionRect.left, mPosition.y + mCollisionRect.top, mCollisionRect.width, mCollisionRect.height};
float overlapx1 = playerRect.left + playerRect.width - rect.left;
float overlapx2 = rect.left + rect.width - playerRect.left;
float overlapy1 = playerRect.top + playerRect.height - rect.top;
float overlapy2 = rect.top + rect.height - playerRect.top;
float overlapx1 = playerRect.left + playerRect.width - rect.mBlock.left;
float overlapx2 = rect.mBlock.left + rect.mBlock.width - playerRect.left;
float overlapy1 = playerRect.top + playerRect.height - rect.mBlock.top;
float overlapy2 = rect.mBlock.top + rect.mBlock.height - playerRect.top;
if (overlapx1 < 0 || overlapx2 < 0 || overlapy1 < 0 || overlapy2 < 0)
return false;
@ -102,14 +100,14 @@ bool Player::handleCollision(const sf::FloatRect& rect)
{
case 0:
mPosition.x -= overlapx1 - 1;
if (mVelocity.y > 0 && playerRect.top < rect.top + Hooked::kMaxHookOffset && playerRect.top > rect.top - Hooked::kMaxHookOffset)
if (mVelocity.y > 0 && playerRect.top < rect.mBlock.top + Hooked::kMaxHookOffset && playerRect.top > rect.mBlock.top - Hooked::kMaxHookOffset)
{
mpState->hook(this);
}
break;
case 1:
mPosition.x += overlapx2 - 1;
if (mVelocity.y > 0 && playerRect.top < rect.top + Hooked::kMaxHookOffset && playerRect.top > rect.top - Hooked::kMaxHookOffset)
if (mVelocity.y > 0 && playerRect.top < rect.mBlock.top + Hooked::kMaxHookOffset && playerRect.top > rect.mBlock.top - Hooked::kMaxHookOffset)
{
mpState->hook(this);
}
@ -132,14 +130,29 @@ bool Player::handleCollision(const sf::FloatRect& rect)
return true;
}
void Player::handleAllCollisions(const std::vector<sf::FloatRect>& blocks)
void Player::handleAllCollisions(std::vector<Block>& blocks)
{
mIsColliding = false;
for (const sf::FloatRect& block : blocks)
{
if (handleCollision(block))
bool toRemove;
auto it = blocks.begin();
/* Remove destructable blocks */
while (it != blocks.end()) {
toRemove = false;
if (handleCollision(*it)) {
if (it->mIsDestructable && mIsAttacking &&
(((it->mBlock.left < mPosition.x) && !mIsFacedRight) ||
((it->mBlock.left > mPosition.x) && mIsFacedRight)) &&
(it->mBlock.top < mPosition.y + mCollisionRect.height)
) {
toRemove = true;
}
mIsColliding = true;
}
if (toRemove) {
it = blocks.erase(it);
}
else
it++;
}
if (!mIsColliding)
@ -150,4 +163,5 @@ void Player::handleAllCollisions(const std::vector<sf::FloatRect>& blocks)
Player::~Player()
{
delete mpState;
}
}

View file

@ -3,6 +3,7 @@
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include "player_states.hpp"
#include "block.hpp"
class PlayerState;
@ -18,9 +19,9 @@ public:
void update(float dt);
void draw(sf::RenderWindow& window);
void handleEvents(const sf::Event& event);
bool handleCollision(const sf::FloatRect& rect);
void handleAllCollisions(const std::vector<sf::FloatRect>& blocks);
bool handleCollision(const Block& rect);
void handleAllCollisions(std::vector<Block>& blocks);
bool isAttacking();
~Player();
friend class PlayerState;
@ -30,6 +31,9 @@ public:
friend class Sliding;
friend class Hooked;
friend class Sitting;
friend class FirstAttack;
friend class SecondAttack;
friend class ThirdAttack;
private:
@ -45,6 +49,7 @@ private:
sf::Sprite mSprite {};
float mScaleFactor {1};
bool mIsFacedRight {true};
bool mIsAttacking {false};
void setState(PlayerState* pNewState);

View file

@ -8,9 +8,7 @@
using std::cout, std::endl;
PlayerState::PlayerState()
{
}
PlayerState::PlayerState() {}
void PlayerState::updateSprite(sf::Sprite& sprite, bool isFacedRight, float scaleFactor)
@ -95,6 +93,10 @@ void Idle::handleEvents(Player* player, const sf::Event& event)
player->mVelocity.x = player->mIsFacedRight ? -100 : 100;
player->setState(new Sitting(player));
}
else if (event.key.code == sf::Keyboard::X)
{
player->setState(new FirstAttack(player));
}
}
}
@ -166,6 +168,10 @@ void Running::handleEvents(Player* player, const sf::Event& event)
{
player->setState(new Sliding(player));
}
else if (event.key.code == sf::Keyboard::X)
{
player->setState(new FirstAttack(player));
}
}
else if (event.type == sf::Event::KeyReleased)
@ -385,18 +391,14 @@ void Hooked::hitGround(Player* player)
/* Sitting */
Sitting::Sitting(Player* player) : PlayerState()
{
// mAnimation = Animation(Animation::AnimationType::OneIteration);
mAnimation = Animation();
mAnimation.setAnimationSpeed(4);
mAnimation = Animation();
mAnimation.setAnimationSpeed(4);
mAnimation.addTextureRect({168, 340, 18, 30});
mAnimation.addTextureRect({219, 340, 18, 30});
mAnimation.addTextureRect({267, 340, 18, 30});
// player->mCollisionRect = player->mScaleFactor * sf::FloatRect(-20, -20, 20, 40);;
player->mCollisionRect = sf::FloatRect(-80, -10, 160, 80);
player->mCollisionRect = player->mScaleFactor * sf::FloatRect(-20, -5, 40, 20);;
player->mCollisionRect = player->mScaleFactor * sf::FloatRect(-10, -10, 20, 25);
cout << "Creating Sitting state" << endl;
}
@ -423,3 +425,178 @@ void Sitting::hook(Player* player) {}
void Sitting::startFalling(Player* player) {}
void Sitting::hitGround(Player* player) {}
/* FirstAttack */
FirstAttack::FirstAttack(Player* player) : PlayerState()
{
if (player->mVelocity.x > 0)
player->mVelocity.x = kSlidingVelocity;
else if (player->mVelocity.x < 0)
player->mVelocity.x = -kSlidingVelocity;
mAnimation = Animation(Animation::AnimationType::OneIteration);
mAnimation.setAnimationSpeed(6);
mAnimation.addTextureRect({56, 222, 30, 38});
mAnimation.addTextureRect({114, 222, 36, 38});
mAnimation.addTextureRect({164, 222, 28, 38});
mAnimation.addTextureRect({214, 222, 20, 38});
mAnimation.addTextureRect({264, 222, 20, 38});
player->mCollisionRect = player->mScaleFactor * sf::FloatRect(-20, -20, 36, 38);
player->mIsAttacking = true;
cout << "Creating FirstAttack state" << endl;
}
void FirstAttack::update(Player* player, float dt)
{
mAnimation.update(dt);
player->mVelocity.x *= kVelocityDecay;
if (mAnimation.hasEnded() && player->mIsColliding)
{
if (mContinue)
player->setState(new SecondAttack(player));
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
player->mIsAttacking = false;
player->setState(new Running(player));
}
else {
player->mIsAttacking = false;
player->setState(new Idle(player));
}
return;
}
}
void FirstAttack::handleEvents(Player* player, const sf::Event& event)
{
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::X)
{
mContinue = true;
}
}
}
void FirstAttack::hook(Player* player) {}
void FirstAttack::startFalling(Player* player) {}
void FirstAttack::hitGround(Player* player) {}
/* SecondAttack */
SecondAttack::SecondAttack(Player* player) : PlayerState()
{
if (player->mVelocity.x > 0)
player->mVelocity.x = kSlidingVelocity;
else if (player->mVelocity.x < 0)
player->mVelocity.x = -kSlidingVelocity;
mAnimation = Animation(Animation::AnimationType::OneIteration);
mAnimation.setAnimationSpeed(6);
mAnimation.addTextureRect({12, 265, 20, 30});
mAnimation.addTextureRect({58, 265, 40, 30});
mAnimation.addTextureRect({102, 265, 32, 30});
mAnimation.addTextureRect({152, 265, 32, 30});
player->mCollisionRect = player->mScaleFactor * sf::FloatRect(-20, -20, 36, 36);
cout << "Creating SecondAttack state" << endl;
}
void SecondAttack::update(Player* player, float dt)
{
mAnimation.update(dt);
player->mVelocity.x *= kVelocityDecay;
if (mAnimation.hasEnded() && player->mIsColliding)
{
if (mContinue)
player->setState(new ThirdAttack(player));
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
player->mIsAttacking = false;
player->setState(new Running(player));
}
else {
player->mIsAttacking = false;
player->setState(new Idle(player));
}
return;
}
}
void SecondAttack::handleEvents(Player* player, const sf::Event& event)
{
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::X)
{
mContinue = true;
}
}
}
void SecondAttack::hook(Player* player) {}
void SecondAttack::startFalling(Player* player) {}
void SecondAttack::hitGround(Player* player) {}
/* ThirdAttack */
ThirdAttack::ThirdAttack(Player* player) : PlayerState()
{
if (player->mVelocity.x > 0)
player->mVelocity.x = kSlidingVelocity;
else if (player->mVelocity.x < 0)
player->mVelocity.x = -kSlidingVelocity;
mAnimation = Animation(Animation::AnimationType::OneIteration);
mAnimation.setAnimationSpeed(6);
mAnimation.addTextureRect({152, 265, 32, 30});
mAnimation.addTextureRect({215, 265, 23, 30});
mAnimation.addTextureRect({266, 265, 22, 30});
mAnimation.addTextureRect({298, 268, 52, 30});
mAnimation.addTextureRect({1, 302, 32, 30});
mAnimation.addTextureRect({47, 302, 36, 30});
mAnimation.addTextureRect({96, 302, 38, 30});
player->mCollisionRect = player->mScaleFactor * sf::FloatRect(-20, -20, 52, 36);
cout << "Creating ThirdAttack state" << endl;
}
void ThirdAttack::update(Player* player, float dt)
{
mAnimation.update(dt);
player->mVelocity.x *= kVelocityDecay;
if (mAnimation.hasEnded() && player->mIsColliding)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
player->mIsAttacking = false;
player->setState(new Running(player));
}
else {
player->mIsAttacking = false;
player->setState(new Idle(player));
}
return;
}
}
void ThirdAttack::handleEvents(Player* player, const sf::Event& event) {}
void ThirdAttack::hook(Player* player) {}
void ThirdAttack::startFalling(Player* player) {}
void ThirdAttack::hitGround(Player* player) {}

View file

@ -123,3 +123,56 @@ public:
void startFalling(Player* player);
void hitGround(Player* player);
};
class FirstAttack : public PlayerState
{
public:
FirstAttack(Player* player);
void update(Player* player, float dt);
void handleEvents(Player* player, const sf::Event& event);
void hook(Player* player);
void startFalling(Player* player);
void hitGround(Player* player);
private:
float mCurrentTime;
static constexpr float kSlidingVelocity = 2000;
static constexpr float kVelocityDecay = 0.99;
bool mContinue = false;
};
class SecondAttack : public PlayerState
{
public:
SecondAttack(Player* player);
void update(Player* player, float dt);
void handleEvents(Player* player, const sf::Event& event);
void hook(Player* player);
void startFalling(Player* player);
void hitGround(Player* player);
private:
float mCurrentTime;
static constexpr float kSlidingVelocity = 2000;
static constexpr float kVelocityDecay = 0.99;
bool mContinue = false;
};
class ThirdAttack : public PlayerState
{
public:
ThirdAttack(Player* player);
void update(Player* player, float dt);
void handleEvents(Player* player, const sf::Event& event);
void hook(Player* player);
void startFalling(Player* player);
void hitGround(Player* player);
private:
float mCurrentTime;
static constexpr float kSlidingVelocity = 2000;
static constexpr float kVelocityDecay = 0.99;
};

View file

@ -6,15 +6,13 @@
#include <cmath>
#include "player.hpp"
#include "player_states.hpp"
#include "block.hpp"
class World
{
public:
void addBlock(sf::FloatRect block)
void addBlock(Block block)
{
mBlocks.push_back(block);
}
@ -53,10 +51,10 @@ public:
window.setView(mView);
for (const sf::FloatRect& b : mBlocks)
for (const Block& b : mBlocks)
{
blockShape.setPosition(b.left, b.top);
blockShape.setSize({b.width, b.height});
blockShape.setPosition(b.mBlock.left, b.mBlock.top);
blockShape.setSize({b.mBlock.width, b.mBlock.height});
window.draw(blockShape);
}
mPlayer.draw(window);
@ -70,9 +68,9 @@ public:
private:
std::vector<sf::FloatRect> mBlocks {};
std::vector<Block> mBlocks {};
Player mPlayer {{400, 400}};
float mGravity {3600};
sf::View mView {sf::FloatRect(0, 0, 1200, 900)};
};
};