commit 878039a6d5d52fefcc19421aac7771875f403886
parent 039d38da9df30a76921275780419b05e1ea18b65
Author: amrfti <andrew@kloet.net>
Date: Mon, 7 Jul 2025 12:28:38 -0400
add whale
Diffstat:
5 files changed, 159 insertions(+), 4 deletions(-)
diff --git a/src/Aquarium.cpp b/src/Aquarium.cpp
@@ -6,6 +6,7 @@
#include "Seaweed.h"
#include "Ship.h"
#include "Waterline.h"
+#include "Whale.h"
#include <algorithm>
#include <iostream>
@@ -135,20 +136,26 @@ void Aquarium::addWaterline() { addEntityImpl<Waterline>(); }
void Aquarium::addCastle() { addEntityImpl<Castle>(); }
void Aquarium::addShip() { addEntityImpl<Ship>(); }
void Aquarium::addSeaMonster() { addEntityImpl<SeaMonster>(); }
+void Aquarium::addWhale() { addEntityImpl<Whale>(); }
+
void Aquarium::ensureBigEntityExists() {
// Check if any big entities exist on screen
for (const auto &entity : entities) {
if (dynamic_cast<Ship *>(entity.get()) ||
- dynamic_cast<SeaMonster *>(entity.get())) {
+ dynamic_cast<SeaMonster *>(entity.get()) ||
+ dynamic_cast<Whale *>(entity.get())) {
return; // Big entity found, do nothing
}
}
- // No big entity found, spawn next in cycle
- if (big_entity_index % 2 == 0) {
+ // No big entity found, spawn next in cycle (Ship, SeaMonster, Whale)
+ int entity_type = big_entity_index % 3;
+ if (entity_type == 0) {
addEntityImpl<Ship>();
- } else {
+ } else if (entity_type == 1) {
addEntityImpl<SeaMonster>();
+ } else {
+ addEntityImpl<Whale>();
}
++big_entity_index;
}
diff --git a/src/Aquarium.h b/src/Aquarium.h
@@ -52,6 +52,7 @@ public:
void addCastle();
void addShip();
void addSeaMonster();
+ void addWhale();
void redraw();
void initColors();
diff --git a/src/Whale.cpp b/src/Whale.cpp
@@ -0,0 +1,60 @@
+#include "Whale.h"
+#include "Aquarium.h"
+#include "Random.h"
+#include "assets/WhaleAssets.h"
+
+Whale::Whale() : Whale(getRandomDirection()) {}
+
+Whale::Whale(int asset_index)
+ : Entity(), frames(whaleAssets[asset_index].frames),
+ mask(whaleAssets[asset_index].mask), speed(WHALE_SPEED),
+ moving_right(asset_index == 0) {
+
+ const auto &aquarium = Aquarium::getInstance();
+ y = 0;
+
+ // Use first frame for positioning calculations
+ const auto &first_frame = frames[0];
+ if (moving_right) {
+ x = -static_cast<float>(first_frame[6].length());
+ } else {
+ x = static_cast<float>(aquarium.getWidth());
+ }
+
+ current_image = first_frame;
+}
+
+int Whale::getRandomDirection() { return Random::intInRange(0, 1); }
+
+void Whale::update() noexcept {
+ x += moving_right ? speed : -speed;
+
+ ++animation_counter;
+
+ // Use longer delay for first frame (no water spout)
+ int current_delay =
+ (current_frame_index == 0) ? FIRST_FRAME_PAUSE : ANIMATION_DELAY;
+
+ if (animation_counter >= current_delay) {
+ current_frame_index = (current_frame_index + 1) % frames.size();
+ animation_counter = 0;
+ }
+}
+
+const std::vector<std::string> &Whale::getImage() const {
+ current_image = frames[current_frame_index];
+ return current_image;
+}
+
+bool Whale::shouldBeRemoved() const noexcept {
+ const auto &aquarium = Aquarium::getInstance();
+ const auto &first_frame = frames[0];
+
+ if (moving_right) {
+ return x > static_cast<float>(aquarium.getWidth());
+ } else {
+ return (x + static_cast<float>(first_frame[0].length())) < 0;
+ }
+}
+
+int Whale::getPreferredLayer() const noexcept { return 8; }
diff --git a/src/Whale.h b/src/Whale.h
@@ -0,0 +1,34 @@
+#pragma once
+#include "Entity.h"
+#include "assets/WhaleAssets.h"
+
+class Whale : public Entity {
+private:
+ static constexpr float WHALE_SPEED = 1.0f;
+
+ const std::vector<std::vector<std::string>> frames;
+ const std::vector<std::string> &mask;
+ const float speed;
+ const bool moving_right;
+
+ int current_frame_index = 0;
+ int animation_counter = 0;
+ mutable std::vector<std::string> current_image;
+
+ static constexpr int ANIMATION_DELAY = 1;
+ static constexpr int FIRST_FRAME_PAUSE = 10;
+
+ explicit Whale(int asset_index);
+ static int getRandomDirection();
+
+public:
+ Whale();
+
+ void update() noexcept override;
+ const std::vector<std::string> &getImage() const override;
+ const std::vector<std::string> &getMask() const override { return mask; }
+ char getDefaultColor() const noexcept override { return 'B'; }
+
+ bool shouldBeRemoved() const noexcept override;
+ int getPreferredLayer() const noexcept override;
+};
diff --git a/src/assets/WhaleAssets.h b/src/assets/WhaleAssets.h
@@ -0,0 +1,53 @@
+#pragma once
+#include "../Entity.h"
+#include <vector>
+
+struct WhaleAsset {
+ std::vector<std::vector<std::string>> frames;
+ std::vector<std::string> mask;
+};
+
+inline const std::vector<WhaleAsset> whaleAssets = {
+ {{{{R"()", R"()", R"()", R"( .-----.)", R"( .' `.)",
+ R"(,????/ (o) \)", R"(\`._/ ,__)"},
+ {R"()", R"()", R"( :)", R"( .-----.)",
+ R"( .' `.)", R"(,????/ (o) \)",
+ R"(\`._/ ,__)"},
+ {R"()", R"( :)", R"( :)", R"( .-----.)",
+ R"( .' `.)", R"(,????/ (o) \)",
+ R"(\`._/ ,__)"},
+ {R"( . .)", R"( -:-)", R"( :)",
+ R"( .-----.)", R"( .' `.)", R"(,????/ (o) \)",
+ R"(\`._/ ,__)"},
+ {R"( . .)", R"( .-.-.)", R"( :)",
+ R"( .-----.)", R"( .' `.)", R"(,????/ (o) \)",
+ R"(\`._/ ,__)"},
+ {R"( . .)", R"( '.-:-.')", R"( ' : ')",
+ R"( .-----.)", R"( .' `.)", R"(,????/ (o) \)",
+ R"(\`._/ ,__)"},
+ {R"()", R"( .- -.)", R"( ; : ;)", R"( .-----.)",
+ R"( .' `.)", R"(,????/ (o) \)",
+ R"(\`._/ ,__)"},
+ {R"()", R"()", R"( ; ;)", R"( .-----.)",
+ R"( .' `.)", R"(,????/ (o) \)",
+ R"(\`._/ ,__)"}},
+ {R"( C C)", R"( CCCCCCC)", R"( C C C)", R"()",
+ R"()", R"( W)", R"()"}},
+ {{{R"()", R"()", R"()", R"( .-----.)", R"( .' `.)",
+ R"( / (o) \????)", R"((__, \_.'/)"},
+ {R"()", R"()", R"( :)", R"( .-----.)", R"( .' `.)",
+ R"( / (o) \????)", R"((__, \_.'/)"},
+ {R"()", R"( :)", R"( :)", R"( .-----.)",
+ R"( .' `.)", R"( / (o) \????)", R"((__, \_.'/)"},
+ {R"( . .)", R"( -:-)", R"( :)", R"( .-----.)",
+ R"( .' `.)", R"( / (o) \????)", R"((__, \_.'/)"},
+ {R"( . .)", R"( .-.-.)", R"( :)", R"( .-----.)",
+ R"( .' `.)", R"( / (o) \????)", R"((__, \_.'/)"},
+ {R"( . .)", R"( '.-:-.')", R"( ' : ')", R"( .-----.)",
+ R"( .' `.)", R"( / (o) \????)", R"((__, \_.'/)"},
+ {R"()", R"( .- -.)", R"( ; : ;)", R"( .-----.)",
+ R"( .' `.)", R"( / (o) \????)", R"((__, \_.'/)"},
+ {R"()", R"()", R"( ; ;)", R"( .-----.)", R"( .' `.)",
+ R"( / (o) \????)", R"((__, \_.'/)"}},
+ {R"( C C)", R"( CCCCCCC)", R"( C C C)", R"()", R"()",
+ R"( W)", R"()"}}}};