Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # include <Siv3D.hpp> // OpenSiv3D v0.3.2
- class Bullet : public Circle
- {
- private:
- Vec2 m_vel;
- bool m_is_friend;
- public:
- Bullet(Vec2 pos, Vec2 vel, bool is_friend = false)
- : Circle(pos, 5)
- , m_vel(vel)
- , m_is_friend(is_friend)
- {}
- bool isFriend() const { return m_is_friend; }
- bool isOut() const { return !intersects(Window::ClientRect().stretched(100)); }
- void update() { moveBy(m_vel); }
- void draw() const { Circle::draw(ColorF(m_is_friend ? 0.8 : 0.6)); }
- };
- class Item : public RectF
- {
- private:
- static Array<String> m_Label;
- int m_category;
- public:
- Item(Vec2 pos, int category)
- : RectF(pos, 40.0)
- , m_category(Min(category, getCategoryNum()))
- {}
- String getLabel() const { return m_Label.at(m_category); }
- static int getCategoryNum() { return m_Label.count() - 1; }
- bool isOut() const { return !RectF::intersects(Window::ClientRect().stretched(100)); }
- void update() { RectF::moveBy(Vec2::Down(100.0 * System::DeltaTime())); }
- void draw() const
- {
- rotated(Periodic::Sine0_1(3.0s) * Math::TwoPi)
- .draw(HSV(220).lerp(HSV(330), (double)m_category / getCategoryNum()))
- .drawFrame(1.0, ColorF(0.0));
- FontAsset(U"item")(m_Label.at(m_category)).drawAt(center());
- }
- };
- Array<String> Item::m_Label({ U"HP", U"S", U"R", U"W" });
- class Shooter
- {
- protected:
- double m_Max_health;
- double m_health;
- Stopwatch m_cooldown;
- public:
- Shooter(double Max_health = 100.0)
- : m_Max_health(Max_health)
- , m_health(Max_health)
- , m_cooldown(true)
- {}
- bool isDead() const { return m_health <= 0.0; }
- void damage(double amount) { m_health = Max(0.0, m_health - amount); }
- void heal(double amout) { m_health = Min(m_Max_health, m_health + amout); }
- };
- class Player : public Triangle, public Shooter
- {
- private:
- double m_speed_factor;
- double m_reload_factor;
- int m_way;
- Font m_font;
- public:
- Player(double health = 1000.0)
- : Triangle(Window::Width() / 2, Window::Height() * 4 / 5, 30.0)
- , Shooter(health)
- , m_speed_factor(1.0)
- , m_reload_factor(1.0)
- , m_way(1)
- , m_font(100)
- {}
- void addSpeed(double amount = 0.3) { m_speed_factor += amount; }
- void addReload(double amount = 0.3) { m_reload_factor += amount; }
- void addWay(int amount = 1) { m_way += amount; }
- Array<Bullet> GenerateBullets() const
- {
- Array<Bullet> generate;
- if (m_way == 1)
- {
- generate << Bullet(centroid(), Vec2::Up(5.0), true);
- return generate;
- }
- const double theta_base = 30_deg / Math::Pow((double)(m_way - 1), 0.8);
- for (int i : step(m_way))
- {
- const double theta = (i - (double)(m_way - 1) / 2) * theta_base;
- generate << Bullet(centroid(), Circular(5.0, theta), true);
- }
- return generate;
- }
- bool update()
- {
- Vec2 Key_input(KeyD.pressed() - KeyA.pressed(), KeyS.pressed() - KeyW.pressed());
- if (Key_input.length() > 1.0) Key_input.normalize();
- const double speed = (KeyShift.pressed() ? 0.5 : 1.0) * m_speed_factor * 100.0 * System::DeltaTime();
- const Vec2 pos = centroid().movedBy(Key_input * speed);
- setCentroid(pos.clamped(Window::ClientRect()));
- if (KeySpace.pressed() && m_cooldown.msF() > 200.0 / m_reload_factor)
- {
- m_cooldown.restart();
- return true;
- }
- return false;
- }
- void drawStatus(int score) const
- {
- const int baseX = Window::Width() / 6, baseY = Window::Height() / 6;
- Transformer2D t0(Mat3x2::Translate(baseX, baseY));
- m_font(U"Score {:d}"_fmt(score)).draw(0, 0, ColorF(1.0, 0.2));
- Transformer2D t1(Mat3x2::Translate(0, baseY));
- m_font(U"Speed {:.1f}"_fmt(m_speed_factor)).draw(0, 0, ColorF(1.0, 0.2));
- Transformer2D t2(Mat3x2::Translate(0, baseY));
- m_font(U"Reload {:.1f}"_fmt(m_reload_factor)).draw(0, 0, ColorF(1.0, 0.2));
- Transformer2D t3(Mat3x2::Translate(0, baseY));
- m_font(U"Way {:d}"_fmt(m_way)).draw(0, 0, ColorF(1.0, 0.2));
- Transformer2D t4(Mat3x2::Translate(0, baseY));
- const double e = Max(0.0, m_health) / m_Max_health;
- const HSV color = HSV(0, 0.2).lerp(HSV(120, 0.2), e);
- m_font(U"HP {:.1f}%"_fmt(100.0 * e)).draw(0, 0, color);
- }
- void draw() const
- {
- Triangle::draw(ColorF(0.5, 0.5, 1.0));
- }
- };
- class Enemy : public Circle, public Shooter
- {
- private:
- Vec2 m_start;
- Vec2 m_dest;
- Transition m_transition;
- public:
- Enemy(double health = 100.0)
- : Circle(20)
- , Shooter(health)
- , m_transition(3.0s)
- {
- m_dest = RandomVec2(Window::Width(), Window::Height() * 0.3);
- m_start = m_dest + Vec2(m_dest - Window::Center());
- setPos(m_start);
- }
- bool update()
- {
- m_transition.update(true);
- setPos(m_start.lerp(m_dest, m_transition.easeOut()));
- if (m_cooldown > 2.0s)
- {
- m_cooldown.restart();
- return true;
- }
- return false;
- }
- void draw() const
- {
- const double e = Max(0.0, m_health) / m_Max_health;
- Circle::draw(ColorF(1.0, 0.5, 0.5))
- .drawFrame(1.0, ColorF(0.0))
- .drawPie(-Math::Pi * e, Math::TwoPi * e, HSV(0).lerp(HSV(120), e));
- Line({ 0, 0 }, Circular(r, Math::Pi * e)).movedBy(center).draw(ColorF(0.0, EaseOutExpo(1.0 - e)));
- Line({ 0, 0 }, Circular(r, -Math::Pi * e)).movedBy(center).draw(ColorF(0.0, EaseOutExpo(1.0 - e)));
- Circle::scaled(0.7).draw(ColorF(1.0, 0.5, 0.5))
- .drawArc(-Math::Pi * e, Math::TwoPi * e, 1.0, 0.0, ColorF(0.0));
- }
- };
- void Main()
- {
- Window::Resize(800, 800);
- Player player;
- int score = 0;
- Array<Enemy> enemies(10);
- Array<Bullet> bullets;
- Array<Item> items;
- FontAsset::Register(U"item", 24);
- System::Sleep(5.0s);
- while (System::Update())
- {
- if (player.update())
- bullets.append(player.GenerateBullets());
- if (RandomBool(2.0 * System::DeltaTime()))
- enemies << Enemy();
- for (auto it = enemies.begin(); it != enemies.end();)
- {
- if (it->isDead())
- {
- score++;
- if (RandomBool()) items << Item(it->center, Random(Item::getCategoryNum()));
- it = enemies.erase(it);
- continue;
- }
- if (it->update())
- bullets << Bullet(it->center, Circular(3.0, Random(160_deg, 200_deg)));
- it++;
- }
- for (auto it = bullets.begin(); it != bullets.end();)
- {
- it->update();
- bool is_hit = false;
- if (it->isFriend())
- {
- Optional<int> enemy_index;
- enemies.each_index([&](int i, auto & e) { if (it->intersects(e)) enemy_index = i; });
- if (enemy_index)
- {
- enemies.at(enemy_index.value()).damage(Random(20.0, 60.0));
- is_hit = true;
- }
- }
- else {
- if (it->intersects(player))
- {
- player.damage(Random(8.0, 12.0));
- is_hit = true;
- }
- }
- if (it->isOut() || is_hit)
- it = bullets.erase(it);
- else
- it++;
- }
- for (auto it = items.begin(); it != items.end();)
- {
- it->update();
- if (it->intersects(player))
- {
- if (it->getLabel() == U"HP") player.heal(50.0);
- if (it->getLabel() == U"S") player.addSpeed();
- if (it->getLabel() == U"R") player.addReload();
- if (it->getLabel() == U"W") player.addWay();
- it = items.erase(it);
- }
- else if (it->isOut())
- it = items.erase(it);
- else
- it++;
- }
- player.drawStatus(score);
- bullets.each([](const auto & b) { b.draw(); });
- items.each([](const auto & i) { i.draw(); });
- enemies.each([](const auto & e) { e.draw(); });
- player.draw();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement