Merge pull request 'add whale' (#3) from abstract into master

Reviewed-on: #3
This commit is contained in:
2025-07-07 21:13:15 +03:00
5 changed files with 159 additions and 4 deletions

View File

@@ -6,6 +6,7 @@
#include "Seaweed.h" #include "Seaweed.h"
#include "Ship.h" #include "Ship.h"
#include "Waterline.h" #include "Waterline.h"
#include "Whale.h"
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
@@ -135,20 +136,26 @@ void Aquarium::addWaterline() { addEntityImpl<Waterline>(); }
void Aquarium::addCastle() { addEntityImpl<Castle>(); } void Aquarium::addCastle() { addEntityImpl<Castle>(); }
void Aquarium::addShip() { addEntityImpl<Ship>(); } void Aquarium::addShip() { addEntityImpl<Ship>(); }
void Aquarium::addSeaMonster() { addEntityImpl<SeaMonster>(); } void Aquarium::addSeaMonster() { addEntityImpl<SeaMonster>(); }
void Aquarium::addWhale() { addEntityImpl<Whale>(); }
void Aquarium::ensureBigEntityExists() { void Aquarium::ensureBigEntityExists() {
// Check if any big entities exist on screen // Check if any big entities exist on screen
for (const auto &entity : entities) { for (const auto &entity : entities) {
if (dynamic_cast<Ship *>(entity.get()) || 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 return; // Big entity found, do nothing
} }
} }
// No big entity found, spawn next in cycle // No big entity found, spawn next in cycle (Ship, SeaMonster, Whale)
if (big_entity_index % 2 == 0) { int entity_type = big_entity_index % 3;
if (entity_type == 0) {
addEntityImpl<Ship>(); addEntityImpl<Ship>();
} else { } else if (entity_type == 1) {
addEntityImpl<SeaMonster>(); addEntityImpl<SeaMonster>();
} else {
addEntityImpl<Whale>();
} }
++big_entity_index; ++big_entity_index;
} }

View File

@@ -52,6 +52,7 @@ public:
void addCastle(); void addCastle();
void addShip(); void addShip();
void addSeaMonster(); void addSeaMonster();
void addWhale();
void redraw(); void redraw();
void initColors(); void initColors();

60
src/Whale.cpp Normal file
View File

@@ -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; }

34
src/Whale.h Normal file
View File

@@ -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;
};

53
src/assets/WhaleAssets.h Normal file
View File

@@ -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"()"}}}};