added jellyfish
authorFrank DeMarco <if.self.end@gmail.com>
Thu, 3 Sep 2020 03:32:22 +0000 (23:32 -0400)
committerFrank DeMarco <if.self.end@gmail.com>
Thu, 3 Sep 2020 03:32:22 +0000 (23:32 -0400)
Makefile
Scientist.cpp
Sea.cpp
Sea.hpp
config.json
lib/sfw

index e12e28c..f4a7141 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -47,7 +47,7 @@ $(SFW_SRC_DIR)Animation.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Timer.hpp)
 $(SFW_SRC_DIR)Recorder.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Game.hpp Configuration.hpp Delegate.hpp Animation.hpp extension.hpp)
 $(SFW_SRC_DIR)Input.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Animation.hpp Configuration.hpp Delegate.hpp)
 $(SFW_SRC_DIR)Configuration.o : $(addprefix $(SFW_SRC_DIR),Node.hpp)
-$(SFW_SRC_DIR)Delegate.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Configuration.hpp)
+$(SFW_SRC_DIR)Delegate.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Game.hpp Input.hpp)
 $(SFW_SRC_DIR)Display.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Game.hpp Box.hpp Configuration.hpp Delegate.hpp)
 $(SFW_SRC_DIR)Box.o : $(addprefix $(SFW_SRC_DIR),extension.hpp Segment.hpp)
 $(SFW_SRC_DIR)Segment.o : $(addprefix $(SFW_SRC_DIR),extension.hpp Box.hpp)
index b2cf375..a8b3ce9 100644 (file)
@@ -43,7 +43,8 @@ void Scientist::load()
 void Scientist::respond(SDL_Event& event)
 {
     if (&(root->get_selected_scientist()) == this && (
-            root->get_current_level()->is_active() || root->beach.is_active() || root->sail.is_active()))
+            root->get_current_level()->is_active() || root->beach.is_active() || root->sail.is_active()) &&
+        !root->get_current_level()->clownfish.at_home)
     {
         if (get_delegate().compare(event, sfw::get_keys(key_states), true))
         {
@@ -178,101 +179,104 @@ void Scientist::fall_through()
 
 void Scientist::update()
 {
-    for (const std::string& direction : {"up", "left", "right"})
+    if (!wipe_animation.is_playing())
     {
-        movement[direction] = std::clamp(movement[direction] - get_root()->weight(.417f), 0.0f, movement[direction]);
-    }
-    for (const auto& [direction, pressed] : key_states)
-    {
-        if (pressed)
+        for (const std::string& direction : {"up", "left", "right"})
         {
-            go(direction);
+            movement[direction] = std::clamp(movement[direction] - get_root()->weight(.417f), 0.0f, movement[direction]);
         }
-    }
-    if (ascending)
-    {
-        movement["up"] += get_root()->weight(2.919);
-        if (movement["up"] > max_ascension)
+        for (const auto& [direction, pressed] : key_states)
         {
-            movement["up"] = max_ascension;
-            if (!jumping)
+            if (pressed)
             {
-                ascending = false;
+                go(direction);
             }
         }
-        if (jumping)
+        if (ascending)
         {
-            max_ascension += get_root()->weight(1.3344);
-            if (max_ascension > MAX_ASCENSION_LIMIT)
+            movement["up"] += get_root()->weight(2.919);
+            if (movement["up"] > max_ascension)
             {
-                jumping = false;
-                max_ascension = MAX_ASCENSION_LIMIT;
+                movement["up"] = max_ascension;
+                if (!jumping)
+                {
+                    ascending = false;
+                }
+            }
+            if (jumping)
+            {
+                max_ascension += get_root()->weight(1.3344);
+                if (max_ascension > MAX_ASCENSION_LIMIT)
+                {
+                    jumping = false;
+                    max_ascension = MAX_ASCENSION_LIMIT;
+                }
             }
         }
-    }
-    movement["down"] = get_root<BuddiSystem>()->get_gravity();
-    dx = movement["right"] - movement["left"];
-    if (!get_root<BuddiSystem>()->select.is_active())
-    {
-        get_current_frameset().set_order_index(get_rotation_frame_index());
-    }
-    Box previous_box = get_box();
-    move_weighted({dx, movement["down"] - movement["up"]});
-    grounded = false;
-    if (!platforms.empty())
-    {
-        float landing_y;
-        bool landing_found = false;
-        glm::vec2 intersection;
-        set_motion_lines(previous_box);
-        for (const Platform* platform : platforms)
+        movement["down"] = get_root<BuddiSystem>()->get_gravity();
+        dx = movement["right"] - movement["left"];
+        if (!get_root<BuddiSystem>()->select.is_active())
+        {
+            get_current_frameset().set_order_index(get_rotation_frame_index());
+        }
+        Box previous_box = get_box();
+        move_weighted({dx, movement["down"] - movement["up"]});
+        grounded = false;
+        if (!platforms.empty())
         {
-            for (Segment& segment : motion_lines)
+            float landing_y;
+            bool landing_found = false;
+            glm::vec2 intersection;
+            set_motion_lines(previous_box);
+            for (const Platform* platform : platforms)
             {
-                if (get_configuration()["display"]["debug"])
+                for (Segment& segment : motion_lines)
                 {
-                    glm::vec2 start = segment.get_start();
-                    glm::vec2 end = segment.get_end();
-                    SDL_SetRenderTarget(get_renderer(), NULL);
-                    lineRGBA(get_renderer(), start.x, start.y, end.x, end.y, 255, 255, 0, 255);
+                    if (get_configuration()["display"]["debug"])
+                    {
+                        glm::vec2 start = segment.get_start();
+                        glm::vec2 end = segment.get_end();
+                        SDL_SetRenderTarget(get_renderer(), NULL);
+                        lineRGBA(get_renderer(), start.x, start.y, end.x, end.y, 255, 255, 0, 255);
+                    }
+                    if (segment.intersect(*platform, intersection) && (!landing_found || intersection.y < landing_y))
+                    {
+                        landing_found = true;
+                        landing_y = intersection.y;
+                        current_platform = platform;
+                        break;
+                    }
                 }
-                if (segment.intersect(*platform, intersection) && (!landing_found || intersection.y < landing_y))
+                if (get_configuration()["display"]["debug"])
                 {
-                    landing_found = true;
-                    landing_y = intersection.y;
-                    current_platform = platform;
-                    break;
+                    glm::vec2 start = platform->get_start();
+                    glm::vec2 end = platform->get_end();
+                    SDL_SetRenderTarget(get_renderer(), NULL);
+                    lineRGBA(get_renderer(), start.x, start.y, end.x, end.y, 255, 0, 0, 255);
                 }
             }
-            if (get_configuration()["display"]["debug"])
+            if (get_bottom() > previous_box.get_bottom() && landing_found)
             {
-                glm::vec2 start = platform->get_start();
-                glm::vec2 end = platform->get_end();
-                SDL_SetRenderTarget(get_renderer(), NULL);
-                lineRGBA(get_renderer(), start.x, start.y, end.x, end.y, 255, 0, 0, 255);
+                grounded = true;
+                set_bottom(landing_y - BOTTOM);
+                if (get_configuration()["display"]["debug"])
+                {
+                    SDL_SetRenderTarget(get_renderer(), NULL);
+                    filledCircleRGBA(get_renderer(), get_center_x(), landing_y, 3, 0, 255, 0, 255);
+                }
             }
         }
-        if (get_bottom() > previous_box.get_bottom() && landing_found)
+        if (!root->title.is_active())
         {
-            grounded = true;
-            set_bottom(landing_y - BOTTOM);
-            if (get_configuration()["display"]["debug"])
+            if (get_left() < 0)
             {
-                SDL_SetRenderTarget(get_renderer(), NULL);
-                filledCircleRGBA(get_renderer(), get_center_x(), landing_y, 3, 0, 255, 0, 255);
+                set_left(0);
+            }
+            if (get_right() > get_window_box().get_right() &&
+                (!root->beach.is_active() || !root->beach.walk_off_animation.is_playing()))
+            {
+                set_right(get_window_box().get_right());
             }
-        }
-    }
-    if (!root->title.is_active())
-    {
-        if (get_left() < 0)
-        {
-            set_left(0);
-        }
-        if (get_right() > get_window_box().get_right() &&
-            (!root->beach.is_active() || !root->beach.walk_off_animation.is_playing()))
-        {
-            set_right(get_window_box().get_right());
         }
     }
     Sprite::update();
diff --git a/Sea.cpp b/Sea.cpp
index 08e7d2c..fd818bd 100644 (file)
--- a/Sea.cpp
+++ b/Sea.cpp
@@ -20,6 +20,7 @@
 #include "Pixels.hpp"
 #include "Segment.hpp"
 #include "filesystem.hpp"
+#include "extension.hpp"
 #include "Sea.hpp"
 
 Sea::Sea(Node* parent) : Node(parent)
@@ -56,6 +57,10 @@ void Sea::reset()
     {
         can.reset();
     }
+    for (Jellyfish& jelly : jellyfish)
+    {
+        jelly.reset();
+    }
     anemone.reset();
     home_glow.hide();
 }
@@ -103,6 +108,10 @@ void Sea::load()
     anemone.load();
     clownfish.load();
     clownfish.set_frameset("right");
+    for (Jellyfish& jelly : jellyfish)
+    {
+        jelly.load();
+    }
     std::vector<Color> home_glow_colors = {Color(0, 255, 0), Color(64, 255, 64), Color(128, 255, 128), Color(192, 255, 192)};
     home_glow.add_frames(sfw::get_halo_frames(get_renderer(), anemone.get_w() * 2, 8, home_glow_colors));
 }
@@ -110,8 +119,13 @@ void Sea::load()
 void Sea::restart()
 {
     Scientist& scientist = get_root<BuddiSystem>()->get_selected_scientist();
-    background_offset = 169;
-    paint_background();
+    restarting = false;
+    if (!is_cleaned())
+    {
+        background_offset = 169;
+        paint_background();
+    }
+    scientist.unhide();
     scientist.clear_platforms();
     for (Coral& coral : corals)
     {
@@ -195,6 +209,10 @@ void Sea::scroll(float amount)
     {
         coral.move({amount, 0});
     }
+    for (Jellyfish& jelly : jellyfish)
+    {
+        jelly.move({amount, 0});
+    }
     for (Floor& floor : floors)
     {
         floor.move({amount, 0});
@@ -252,35 +270,38 @@ void Sea::update()
     {
         Scientist& scientist = get_root<BuddiSystem>()->get_selected_scientist();
         restore_background_animation.update();
-        if (is_cleaned() && !clownfish_hit && clownfish.engaged && !clownfish.at_home)
+        if (is_cleaned() && !clownfish_hit && !clownfish.at_home)
         {
             Segment distance = {clownfish.get_center(), scientist.get_center()};
-            if (clownfish.collide(anemone, true))
+            if (distance.start.x >= distance.end.x)
             {
-                finish_level();
+                clownfish.set_frameset("left");
             }
-            else if (distance > 50 && distance < 210)
+            else
             {
-                if (!clownfish.moving && distance > 200)
+                clownfish.set_frameset("right");
+            }
+            if (clownfish.engaged)
+            {
+                if (clownfish.collide(anemone, true))
                 {
+                    finish_level();
                 }
-                clownfish.moving = true;
-                clownfish.move(distance.get_step(1.664f));
-                if (distance.start.x >= distance.end.x)
+                else if (distance > 50 && distance < 210)
                 {
-                    clownfish.set_frameset("left");
+                    if (!clownfish.moving && distance > 200)
+                    {
+                    }
+                    clownfish.moving = true;
+                    clownfish.move_weighted(distance.get_step(1.664f));
                 }
                 else
                 {
-                    clownfish.set_frameset("right");
-                }
-            }
-            else
-            {
-                if (clownfish.moving && distance > 210)
-                {
+                    if (clownfish.moving && distance > 210)
+                    {
+                    }
+                    clownfish.moving = false;
                 }
-                clownfish.moving = false;
             }
         }
         if (!clownfish.engaged && !clownfish.at_home)
@@ -301,7 +322,7 @@ void Sea::update()
                 touching_clownfish = false;
             }
         }
-        if (!restarting)
+        if (!restarting && !clownfish.at_home)
         {
             for (Can& can : cans)
             {
@@ -330,6 +351,32 @@ void Sea::update()
                     }
                 }
             }
+            if (scientist.get_center_y() > get_window_box().get_h())
+            {
+                scientist.wipe_animation.play();
+                restarting = true;
+            }
+            else
+            {
+                for (Jellyfish& jelly : jellyfish)
+                {
+                    if (jelly.collide(scientist, true))
+                    {
+                        scientist.wipe_animation.play();
+                        restarting = true;
+                        break;
+                    }
+                }
+            }
+        }
+        for (Jellyfish& jelly : jellyfish)
+        {
+            if (clownfish.engaged && !clownfish_hit && jelly.collide(clownfish, true))
+            {
+                clownfish_hit = true;
+                clownfish.wipe_animation.play();
+                break;
+            }
         }
         if (clownfish_hit && !clownfish.wipe_animation.is_playing())
         {
@@ -337,6 +384,10 @@ void Sea::update()
             clownfish.disengage();
             clownfish_hit = false;
         }
+        if (restarting && !scientist.wipe_animation.is_playing())
+        {
+            restart();
+        }
         background.update();
         for (Sprite& school : schools)
         {
@@ -346,6 +397,13 @@ void Sea::update()
         seafloor.update();
         for (z_index = floors.size() - 1; z_index >= 0; z_index--)
         {
+            for (Jellyfish& jelly : jellyfish)
+            {
+                if (jelly.z_index == z_index)
+                {
+                    jelly.update();
+                }
+            }
             floors[z_index].update();
             if (z_index == 0)
             {
@@ -380,6 +438,13 @@ void Sea::update()
                         can.update();
                     }
                 }
+                for (Jellyfish& jelly : jellyfish)
+                {
+                    if (jelly.z_index == -1)
+                    {
+                        jelly.update();
+                    }
+                }
                 seaweed.update();
             }
         }
@@ -427,9 +492,9 @@ void Seafront::load()
 void Seafront::restart()
 {
     Scientist& scientist = get_root<BuddiSystem>()->get_selected_scientist();
-    place_cans({{410, 338}, {530, 140}, {630, 255}});
     clownfish.set_frameset("right");
     Sea::restart();
+    place_cans({{410, 338}, {530, 140}, {630, 255}});
     scientist.move({190, -220});
     scientist.update();
 }
@@ -445,6 +510,7 @@ Seafloor::Seafloor(Node* parent) : Sea(parent)
     cans.emplace_back(this);
     cans.emplace_back(this, true, true);
     cans.emplace_back(this, true);
+    jellyfish.emplace_back(this, glm::vec2(54, 64), -1);
     recycle_start = {120.0f, 20.0f};
     anemone_start = {40.0f, 120.0f};
     clownfish_start = {632.0f, 320.0f};
@@ -460,14 +526,45 @@ void Seafloor::load()
 
 void Seafloor::restart()
 {
-    place_cans({{90, 270}, {330, 360}, {540, 360}});
     clownfish.set_frameset("left");
     Sea::restart();
+    place_cans({{90, 270}, {330, 360}, {540, 360}});
+    jellyfish[0].set_center(jellyfish_start);
+    jellyfish_going_left = true;
     Scientist& scientist = root->get_selected_scientist();
     scientist.set_bottom(floors[1].get_top());
     scientist.update();
 }
 
+void Seafloor::update()
+{
+    if (is_active())
+    {
+        Jellyfish& jelly = jellyfish[0];
+        float dx;
+        if (jellyfish_going_left)
+        {
+            dx = -jellyfish_speed;
+        }
+        else
+        {
+            dx = jellyfish_speed;
+        }
+        jelly.move_weighted({dx, 0});
+        if (jelly.get_left() < 0)
+        {
+            jellyfish_going_left = false;
+            jelly.move({std::abs(jelly.get_left()), 0});
+        }
+        if (jelly.get_center_x() > jellyfish_start.x)
+        {
+            jellyfish_going_left = true;
+            jelly.move({jellyfish_start.x - jelly.get_center_x(), 0});
+        }
+        Sea::update();
+    }
+}
+
 Seaside::Seaside(Node* parent) : Sea(parent)
 {
     world_box = {{0, 0}, {1025, get_window_box().get_h()}};
@@ -477,9 +574,12 @@ Seaside::Seaside(Node* parent) : Sea(parent)
     cans.emplace_back(this);
     cans.emplace_back(this, true);
     cans.emplace_back(this, true, true);
+    jellyfish.emplace_back(this, glm::vec2(54, 64), 0);
     recycle_start = {512.0f, 140.0f};
     anemone_start = {420.0f, 250.0f};
     clownfish_start = {916.0f, 311.0f};
+    hide_jellyfish_animation.set_frame_length(3000.0f);
+    jellyfish_attack_animation.set_frame_length(200.0f);
 }
 
 void Seaside::load()
@@ -490,11 +590,148 @@ void Seaside::load()
 
 void Seaside::restart()
 {
-    place_cans({{64, 193}, {239, 166}, {419, 270}});
     clownfish.set_frameset("left");
+    jellyfish[0].set_nw({653, 366});
+    hide_jellyfish_animation.play();
+    jellyfish_attack_animation.reset();
+    jellyfish_hidden = true;
+    jellyfish_cooldown = false;
     Sea::restart();
+    place_cans({{64, 193}, {239, 166}, {419, 270}});
+}
+
+void Seaside::hide_jellyfish()
+{
+    if (jellyfish_hidden)
+    {
+        jellyfish[0].move({0, -16});
+    }
+    else
+    {
+        jellyfish[0].move({0, 16});
+    }
+    jellyfish_hidden = !jellyfish_hidden;
+}
+
+void Seaside::jellyfish_attack()
+{
+    if (jellyfish_emerging)
+    {
+        jellyfish[0].move_weighted({0, -16});
+        if (jellyfish[0].get_top() <= 50)
+        {
+            jellyfish_emerging = false;
+        }
+    }
+    else
+    {
+        jellyfish[0].move_weighted({0, 16});
+        if (jellyfish[0].get_top() >= 366)
+        {
+            jellyfish[0].set_top(366);
+            jellyfish_hidden = true;
+            jellyfish_attack_animation.reset();
+            hide_jellyfish_animation.play();
+            jellyfish_cooldown = true;
+            end_jellyfish_cooldown_animation.play(2000.0f, true);
+        }
+    }
+}
+
+void Seaside::end_jellyfish_cooldown()
+{
+    jellyfish_cooldown = false;
+}
+
+void Seaside::update()
+{
+    if (is_active())
+    {
+        hide_jellyfish_animation.update();
+        jellyfish_attack_animation.update();
+        end_jellyfish_cooldown_animation.update();
+        Box inflated = jellyfish[0].get_box();
+        inflated.expand({80, 100}, true);
+        if (!jellyfish_cooldown && !jellyfish_attack_animation.is_playing() &&
+            (root->get_selected_scientist().collide(inflated) || clownfish.collide(inflated)))
+        {
+            jellyfish_emerging = true;
+            jellyfish[0].set_top(350);
+            hide_jellyfish_animation.reset();
+            jellyfish_attack_animation.play();
+        }
+        Sea::update();
+    }
+}
+
+Jellyfish::Jellyfish(Sea* parent, glm::vec2 frame_size, int z_index, const Color& body_color, const Color& eye_color) :
+    Sprite(parent), frame_size(frame_size), z_index(z_index), body_color(body_color), eye_color(eye_color)
+{
+    set_frame_length(50);
 }
 
+void Jellyfish::load()
+{
+    Sprite::load();
+    SDL_Texture *not_wiggled = sfw::get_filled_texture(get_renderer(), frame_size, Color(0, 0, 0, 0)), *wiggled, *legs_texture;
+    Box box = sfw::get_texture_box(not_wiggled), head_box = Box({0, 0}, {box.get_w(), box.get_h() * 0.40625f}),
+        body_box = Box(head_box.get_sw(), {box.get_w() * 0.61f, box.get_h() * 0.3125f}),
+        eye_box = Box({0, 0}, {box.get_w() * 0.0926f, box.get_h() * 0.078125f}),
+        left_eye_box = eye_box, right_eye_box = eye_box;
+    body_box.set_center_x(box.get_center_x());
+    Box legs_box = Box(body_box.get_sw() - glm::vec2(box.get_w() * 0.025f, 1),
+                       {body_box.get_w(), box.get_h() - body_box.get_bottom()}),
+        leg_box = Box({0, 0}, {box.get_w() * 0.05556f, legs_box.get_h()});
+    float x_margin = box.get_w() * 0.0741f, y_margin = box.get_h() * 0.046875f;
+    left_eye_box.set_nw(body_box.get_nw() + glm::vec2(x_margin, y_margin));
+    right_eye_box.set_ne(body_box.get_ne() + glm::vec2(-x_margin, y_margin));
+    SDL_SetRenderTarget(get_renderer(), not_wiggled);
+    SDL_SetRenderDrawColor(get_renderer(), body_color);
+    filledTrigonColor(get_renderer(), head_box.get_left(), head_box.get_bottom(), head_box.get_center_x(),
+                      head_box.get_top(), head_box.get_right(), head_box.get_bottom(), body_color);
+    SDL_RenderFillRect(get_renderer(), body_box);
+    SDL_SetRenderDrawColor(get_renderer(), eye_color);
+    SDL_RenderFillRect(get_renderer(), left_eye_box);
+    SDL_RenderFillRect(get_renderer(), right_eye_box);
+    wiggled = sfw::duplicate_texture(get_renderer(), not_wiggled);
+    legs_texture = sfw::get_filled_texture(get_renderer(), legs_box.get_size(), Color(0, 0, 0, 0));
+    SDL_SetRenderDrawColor(get_renderer(), body_color);
+    SDL_SetRenderTarget(get_renderer(), legs_texture);
+    while (leg_box.get_left() < legs_box.get_w())
+    {
+        SDL_RenderFillRect(get_renderer(), leg_box);
+        leg_box.move({leg_box.get_w() + box.get_w() * 0.0741f, 0});
+    }
+    SDL_SetRenderTarget(get_renderer(), not_wiggled);
+    SDL_SetTextureBlendMode(legs_texture, SDL_BLENDMODE_BLEND);
+    SDL_RenderCopyF(get_renderer(), legs_texture, nullptr, &legs_box);
+    SDL_SetRenderTarget(get_renderer(), wiggled);
+    Box wiggled_legs_box = legs_box.stamp({leg_box.get_w(), 0});
+    SDL_RenderCopyF(get_renderer(), legs_texture, nullptr, &wiggled_legs_box);
+    SDL_DestroyTexture(legs_texture);
+    Color color = Color(255, 0, 0);
+    for (int hue_factor = 0; hue_factor <= 180; hue_factor += 15)
+    {
+        SDL_Texture* stinger_canvas;
+        if (hue_factor > 90)
+        {
+            stinger_canvas = sfw::duplicate_texture(get_renderer(), not_wiggled);
+        }
+        else
+        {
+            stinger_canvas = sfw::duplicate_texture(get_renderer(), wiggled);
+        }
+        color.set_hsv(hue_factor % 60);
+        SDL_SetRenderTarget(get_renderer(), stinger_canvas);
+        SDL_SetRenderDrawColor(get_renderer(), color);
+        lineColor(get_renderer(), {head_box.get_north(), head_box.get_sw()}, color, 3);
+        lineColor(get_renderer(), {head_box.get_north(), head_box.get_se()}, color, 3);
+        SDL_SetTextureBlendMode(stinger_canvas, SDL_BLENDMODE_BLEND);
+        add_frames(stinger_canvas);
+    }
+    SDL_DestroyTexture(not_wiggled);
+    SDL_DestroyTexture(wiggled);
+}
 
 Clownfish::Clownfish(Sea* parent) : Sprite(parent, "resource/clownfish")
 {
@@ -551,6 +788,10 @@ void Clownfish::update()
 {
     wipe_animation.update();
     Sprite::update();
+    if (!wipe_animation.is_playing())
+    {
+        unhide();
+    }
 }
 
 Can::Can(Sea* parent, bool horizontal, bool mirrored) :
diff --git a/Sea.hpp b/Sea.hpp
index 0c05357..2cdafbe 100644 (file)
--- a/Sea.hpp
+++ b/Sea.hpp
 #ifndef Sea_h_
 #define Sea_h_
 
+#include <vector>
+
 #include "SDL.h"
 #include "glm/vec2.hpp"
 
 #include "Sprite.hpp"
 #include "Platform.hpp"
+#include "Color.hpp"
 
 struct Sea;
 
+struct Jellyfish : Sprite
+{
+
+    glm::vec2 frame_size;
+    int z_index;
+    Color body_color, eye_color;
+
+    Jellyfish(Sea*, glm::vec2, int, const Color& = Color(255, 255, 255), const Color& = Color(255, 0, 0));
+    void load();
+
+};
+
 struct Clownfish : Sprite
 {
 
@@ -90,10 +105,7 @@ struct Coral : Sprite
 
 };
 
-#include <vector>
-
 #include "Recycle.hpp"
-#include "Color.hpp"
 #include "Animation.hpp"
 
 struct Sea : Node
@@ -117,6 +129,7 @@ struct Sea : Node
     std::vector<Coral> corals;
     std::vector<Sprite> schools;
     std::vector<Can> cans;
+    std::vector<Jellyfish> jellyfish;
     Recycle recycle = Recycle(this);
     Clownfish clownfish = Clownfish(this);
     SDL_Texture* wall_texture;
@@ -153,18 +166,32 @@ struct Seafront : Sea
 struct Seafloor : Sea
 {
 
+    glm::vec2 jellyfish_start = {450.0f, 165.0f};
+    float jellyfish_speed = 1.248f;
+    bool jellyfish_going_left = true;
+
     Seafloor(Node*);
     void load();
     void restart();
+    void update();
 
 };
 
 struct Seaside : Sea
 {
+    
+    Animation hide_jellyfish_animation = Animation(&Seaside::hide_jellyfish, this),
+        jellyfish_attack_animation = Animation(&Seaside::jellyfish_attack, this),
+        end_jellyfish_cooldown_animation = Animation(&Seaside::end_jellyfish_cooldown, this);
+    bool jellyfish_emerging = false, jellyfish_cooldown = false, jellyfish_hidden = false;
 
     Seaside(Node*);
     void load();
     void restart();
+    void hide_jellyfish();
+    void jellyfish_attack();
+    void end_jellyfish_cooldown();
+    void update();
 
 };
 
index bc027cf..697006d 100644 (file)
@@ -2,7 +2,7 @@
     "display":
     {
         "dimensions": [720, 405],
-        "framerate": 30,
+        "framerate": 60,
         "title": "B.U.D.D.I.",
         "debug": false,
         "render-test-spacing": 2,
diff --git a/lib/sfw b/lib/sfw
index 3a571ad..877d63c 160000 (submodule)
--- a/lib/sfw
+++ b/lib/sfw
@@ -1 +1 @@
-Subproject commit 3a571adaa3ffd2d511227ea236debac33ea68423
+Subproject commit 877d63cf4e9c6f7798bfbf3ee71d187430376aea