Page MenuHomePhabricator (Chris)

No OneTemporary

Size
141 KB
Referenced Files
None
Subscribers
None
diff --git a/src/Component.h b/src/Component.h
index d44c79a..a49b83d 100644
--- a/src/Component.h
+++ b/src/Component.h
@@ -1,66 +1,67 @@
//
// Created by Ido Mozes on 20/06/2019.
//
#ifndef SDL2_GAME_COMPONENT_H
#define SDL2_GAME_COMPONENT_H
#include <memory>
struct Point {
float X;
float Y;
};
class Entity;
typedef std::shared_ptr<Entity> EntityP;
enum ComponentType {
VISIBILITY,
POSITION,
VELOCITY,
SPEED,
ATTACK_SPEED,
ACCELERATION,
PATH_INDEX,
LIVES,
KIND,
SHOT_KIND,
TYPE,
RANGE,
DAMAGE,
PIERCE,
SPREAD,
SHOTS_AMOUNT,
DISTANCE,
SEQUENCE,
ACTION,
DRAGGABLE,
RANGE_SHADOW,
STRATEGY,
REGROW,
CAMO,
FORTIFIED,
GOO,
COST,
POPPED_BLOONS,
UPGRADES,
UPGRADE_P,
SEEN,
+ MOAB_CLASS_AFFECTING,
MOVE_ENTITY_EVENT,
REMOVE_ENTITY_EVENT,
DAMAGE_EVENT,
LENGTH
};
class Component {
public:
Component() = default;
virtual ~Component() = default;
};
#endif //SDL2_GAME_COMPONENT_H
diff --git a/src/Game.cpp b/src/Game.cpp
index 4a6ac9a..ce9d4e7 100644
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -1,498 +1,661 @@
//
// Created by Ido Mozes on 18/06/2019.
//
#include <array>
#include "Game.h"
using namespace boost::filesystem;
Game::Game(bool fullscreen, float mapScale) {
gameData.mapScale = mapScale;
gameData.fullscreen = fullscreen;
path p = path("../assets/Bloons");
directory_iterator it{p};
for (auto &p :it) {
gameData.assets[p.path().filename().string().substr(0, p.path().filename().string().length() - 4)] = IMG_Load(
p.path().string().c_str());
}
p = path("../assets/Sprites");
it = directory_iterator{p};
for (auto &p :it) {
gameData.assets[p.path().filename().string().substr(0, p.path().filename().string().length() - 4)] = IMG_Load(
p.path().string().c_str());
}
p = path("../assets/Icons");
it = directory_iterator{p};
for (auto &p :it) {
gameData.assets[p.path().filename().string().substr(0, p.path().filename().string().length() - 4)] = IMG_Load(
p.path().string().c_str());
}
gameData.assets["map"] = IMG_Load("../assets/map0.jpg");
gameData.assets["upgrade_bar"] = IMG_Load("../assets/upgrade_bar.png");
gameData.assets["menu"] = IMG_Load("../assets/menu.jpg");
gameData.assets["UpgradesBackground"] = IMG_Load("../assets/upgrade_bar_items.png");
renderSystem = new RenderSystem();
renderSystem->init(gameData);
loadMap();
std::initializer_list<std::tuple<int, std::string, Point, float>> sprites[]{
{{MAP, "map", {SIDEBAR_WIDTH, 0}, 1}},
{},
{},
{},
{},
{},
{},
{
{OTHER, "upgrade_bar", {0, 0}, 1},
{OTHER, "menu", {MAP_WIDTH + SIDEBAR_WIDTH, 0}, 1},
{OTHER, "Cash", {MAP_WIDTH + SIDEBAR_WIDTH + 20, 9}, 0.6},
{OTHER, "Lives", {MAP_WIDTH + SIDEBAR_WIDTH + 20, 31}, 0.6},
{UPGRADES_BACKGROUND, "UpgradesBackground", {0, 0}, 1}
},
};
for (int i = 0; i < N_LAYERS; i++) {
for (auto[kind, surfaceName, position, scale] :sprites[i]) {
auto spriteEntity = new Entity();
- SDL_Surface *surface = gameData.assets[surfaceName];
- spriteEntity->addComponent<Visibility>(gameData.renderer, surface,
+ auto[texture, surface]=gameData.getTexture(surfaceName);
+ spriteEntity->addComponent<Visibility>(texture, surface,
SDL_Rect{int(position.X), int(position.Y), int(surface->w * scale)});
if (kind != OTHER)
spriteEntity->addComponent<Kind>(kind);
layers[i].emplace_back(spriteEntity);
}
}
// Buttons
EntityP button(new Entity());
- SDL_Surface *surface = gameData.assets["Play"];
+ auto[texture, surface]=gameData.getTexture("Play");
Point position{SIDEBAR_WIDTH + MAP_WIDTH + 67, 480};
- button->addComponent<Visibility>(gameData.renderer, surface, SDL_Rect{int(position.X - surface->w / 4),
- int(position.Y - surface->h / 4),
- int(surface->w / 2)});
+ button->addComponent<Visibility>(texture, surface, SDL_Rect{int(position.X - surface->w / 4),
+ int(position.Y - surface->h / 4),
+ int(surface->w / 2)});
button->addComponent<Action>(CLICK);
button->addComponent<Kind>(PLAY_FAST_FORWARD);
layers[MENU_LAYER].emplace_back(button);
gameData.playButton = button;
auto nextStrategyButton = new Entity();
- surface = gameData.assets["RightArrow"];
+ std::tie(texture, surface) = gameData.getTexture("RightArrow");
position = {116, 21};
- nextStrategyButton->addComponent<Visibility>(gameData.renderer, surface, SDL_Rect{int(position.X - 7.5),
- int(position.Y - 7.5), 15});
+ nextStrategyButton->addComponent<Visibility>(texture, surface, SDL_Rect{int(position.X - 7.5),
+ int(position.Y - 7.5), 15});
nextStrategyButton->addComponent<Action>(CLICK);
nextStrategyButton->addComponent<Kind>(NEXT_STRATEGY);
layers[MENU_LAYER].emplace_back(nextStrategyButton);
auto previousStrategyButton = new Entity();
- surface = gameData.assets["LeftArrow"];
+ std::tie(texture, surface) = gameData.getTexture("LeftArrow");
position = {32, 21};
- previousStrategyButton->addComponent<Visibility>(gameData.renderer, surface, SDL_Rect{int(position.X - 7.5),
- int(position.Y - 7.5), 15});
+ previousStrategyButton->addComponent<Visibility>(texture, surface, SDL_Rect{int(position.X - 7.5),
+ int(position.Y - 7.5), 15});
previousStrategyButton->addComponent<Action>(CLICK);
previousStrategyButton->addComponent<Kind>(PREVIOUS_STRATEGY);
layers[MENU_LAYER].emplace_back(previousStrategyButton);
for (int j = 0; j < 3; ++j) {
auto upgradePath = new Entity();
- surface = gameData.assets["LeftArrow"];
- upgradePath->addComponent<Visibility>(gameData.renderer, surface, SDL_Rect{0, 0, 0});
+ upgradePath->addComponent<Visibility>(texture, surface, SDL_Rect{0, 0, 0});
upgradePath->addComponent<Action>(CLICK);
upgradePath->addComponent<Kind>(UPGRADE_PATH_1 + j);
layers[MENU_LAYER].emplace_back(upgradePath);
}
// Towers
auto tower = new Entity();
tower->addComponent<Kind>(SUPER_MONKEY);
tower->addComponent<ShotKind>(DART);
- surface = gameData.assets["SuperMonkey"];
+ std::tie(texture, surface) = gameData.getTexture("SuperMonkey");
position = {SIDEBAR_WIDTH + MAP_WIDTH + 65, 85};
- tower->addComponent<Visibility>(gameData.renderer, surface,
+ tower->addComponent<Visibility>(texture, surface,
SDL_Rect{int(position.X - surface->w / 3), int(position.Y - surface->h / 3),
int(surface->w / 1.5), 0});
tower->addComponent<Action>(DRAG);
tower->addComponent<Range>(150);
tower->addComponent<AttackSpeed>(17.2);
tower->addComponent<Pierce>(1);
tower->addComponent<Damage>(1);
tower->addComponent<Distance>(170);
tower->addComponent<Type>(TOWER_T);
tower->addComponent<Cost>(2975);
auto &superMonkeyUpgrades = tower->addComponent<Upgrades>();
std::string image = "SuperMonkey_LaserBlasts";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ auto[lockedTexture, lockedSurface] = gameData.getTexture(image + "Locked");
superMonkeyUpgrades.paths[0].emplace_back(
- Upgrade("Laser Blasts", 2295, image, gameData.assets[image], {{PIERCE_UPGRADE, 1},
- {SHOT_KIND_UPGRADE, LASER}}));
+ Upgrade("Laser Blasts", 2295, surface, texture, lockedTexture, {{PIERCE_UPGRADE, 1},
+ {SHOT_KIND_UPGRADE, LASER}}));
image = "SuperMonkey_PlasmaVision";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
superMonkeyUpgrades.paths[0].emplace_back(
- Upgrade("Plasma Blasts", 4250, image, gameData.assets[image], {{PIERCE_UPGRADE, 1},
- {ATTACK_SPEED_UPGRADE, 2},
- {SHOT_KIND_UPGRADE, PLASMA}}));
+ Upgrade("Plasma Blasts", 4250, surface, texture, lockedTexture, {{PIERCE_UPGRADE, 1},
+ {ATTACK_SPEED_UPGRADE, 2},
+ {SHOT_KIND_UPGRADE, PLASMA}}));
image = "SuperMonkey_SunAvatar";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
superMonkeyUpgrades.paths[0].emplace_back(
- Upgrade("Sun Avatar", 17850, image, gameData.assets[image], {{SHOTS_AMOUNT_UPGRADE, 3},
- {PIERCE_UPGRADE, 3},
- {SHOT_KIND_UPGRADE, SUN}}));
+ Upgrade("Sun Avatar", 17850, surface, texture, lockedTexture, {{SHOTS_AMOUNT_UPGRADE, 3},
+ {PIERCE_UPGRADE, 3},
+ {SHOT_KIND_UPGRADE, SUN}}));
image = "SuperMonkey_SuperRange";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
superMonkeyUpgrades.paths[1].emplace_back(
- Upgrade("Super Range", 850, image, gameData.assets[image],
+ Upgrade("Super Range", 850, surface, texture, lockedTexture,
{{RANGE_UPGRADE, 1.25},
{DISTANCE_UPGRADE, 1.25}}));
image = "SuperMonkey_EpicRange";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
superMonkeyUpgrades.paths[1].emplace_back(
- Upgrade("Epic Range", 1190, image, gameData.assets[image], {{RANGE_UPGRADE, 1.25},
- {DISTANCE_UPGRADE, 1.25},
- {PIERCE_UPGRADE, 1}}));
+ Upgrade("Epic Range", 1190, surface, texture, lockedTexture, {{RANGE_UPGRADE, 1.25},
+ {DISTANCE_UPGRADE, 1.25},
+ {PIERCE_UPGRADE, 1}}));
image = "SuperMonkey_RoboMonkey";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
superMonkeyUpgrades.paths[1].emplace_back(
- Upgrade("Robo Monkey", 7650, image, gameData.assets[image], {{SHOTS_AMOUNT_UPGRADE, 2},
- {DAMAGE_UPGRADE, 4}}));
+ Upgrade("Robo Monkey", 7650, surface, texture, lockedTexture, {{SHOTS_AMOUNT_UPGRADE, 2},
+ {DAMAGE_UPGRADE, 4}}));
image = "SuperMonkey_Ultravision";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
superMonkeyUpgrades.paths[2].emplace_back(
- Upgrade("Ultravision", 1020, image, gameData.assets[image], {{RANGE_UPGRADE, 1.1},
- {DISTANCE_UPGRADE, 1.1},
- {CAMO_UPGRADE, 0}}));
+ Upgrade("Ultravision", 1020, surface, texture, lockedTexture, {{RANGE_UPGRADE, 1.1},
+ {DISTANCE_UPGRADE, 1.1},
+ {CAMO_UPGRADE, 0}}));
superMonkeyUpgrades.selectedPathUpgrades[0] = 1;
superMonkeyUpgrades.selectedPathUpgrades[1] = 1;
superMonkeyUpgrades.selectedPathUpgrades[2] = 0;
layers[MENU_LAYER].emplace_back(tower);
tower = new Entity();
position = {SIDEBAR_WIDTH + MAP_WIDTH + 190, 85};
tower->addComponent<Kind>(SNIPER_MONKEY);
tower->addComponent<ShotKind>(BULLET);
- surface = gameData.assets["SniperMonkey"];
- tower->addComponent<Visibility>(gameData.renderer, surface,
+ std::tie(texture, surface) = gameData.getTexture("SniperMonkey");
+ tower->addComponent<Visibility>(texture, surface,
SDL_Rect{int(position.X - surface->w / 3), int(position.Y - surface->h / 3),
int(surface->w / 1.5), 0});
tower->addComponent<Action>(DRAG);
tower->addComponent<Range>(500);
tower->addComponent<AttackSpeed>(0.45);
tower->addComponent<Pierce>(1);
tower->addComponent<Damage>(1);
tower->addComponent<Distance>(500);
tower->addComponent<Cost>(300);
tower->addComponent<Type>(TOWER_T);
auto &sniperMonkeyUpgrades = tower->addComponent<Upgrades>();
image = "SniperMonkey_FullMetalJacket";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
sniperMonkeyUpgrades.paths[0].emplace_back(
- Upgrade("Full Metal Jacket", 295, image, gameData.assets[image], {{DAMAGE_UPGRADE, 3},
- {SHOT_KIND_UPGRADE, ENHANCED_BULLET}}));
+ Upgrade("Full Metal Jacket", 295, surface, texture, lockedTexture, {{DAMAGE_UPGRADE, 3},
+ {SHOT_KIND_UPGRADE, ENHANCED_BULLET}}));
image = "SniperMonkey_LargeCalibre";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
sniperMonkeyUpgrades.paths[0].emplace_back(
- Upgrade("Large Calibre", 1275, image, gameData.assets[image], {{DAMAGE_UPGRADE, 3}}));
+ Upgrade("Large Calibre", 1275, surface, texture, lockedTexture, {{DAMAGE_UPGRADE, 3}}));
image = "SniperMonkey_DeadlyPrecision";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
sniperMonkeyUpgrades.paths[0].emplace_back(
- Upgrade("Deadly Precision", 2250, image, gameData.assets[image], {{DAMAGE_UPGRADE, 11}}));
+ Upgrade("Deadly Precision", 2250, surface, texture, lockedTexture, {{DAMAGE_UPGRADE, 11}}));
image = "SniperMonkey_NightVisionGoggles";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
sniperMonkeyUpgrades.paths[1].emplace_back(
- Upgrade("Night Vision Goggles", 225, image, gameData.assets[image], {{CAMO_UPGRADE, 0}}));
+ Upgrade("Night Vision Goggles", 225, surface, texture, lockedTexture, {{CAMO_UPGRADE, 0}}));
image = "SniperMonkey_FasterFiring";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
sniperMonkeyUpgrades.paths[2].emplace_back(
- Upgrade("Faster Firing", 340, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 1.54}}));
+ Upgrade("Faster Firing", 340, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 1.54}}));
image = "SniperMonkey_EvenFasterFiring";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
sniperMonkeyUpgrades.paths[2].emplace_back(
- Upgrade("Even Faster Firing", 340, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 1.66}}));
+ Upgrade("Even Faster Firing", 340, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 1.66}}));
image = "SniperMonkey_Semi-Automatic";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
sniperMonkeyUpgrades.paths[2].emplace_back(
- Upgrade("Semi-Automatic", 2975, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 3}}));
+ Upgrade("Semi-Automatic", 2975, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 3}}));
image = "SniperMonkey_FullAutoRifle";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
sniperMonkeyUpgrades.paths[2].emplace_back(
- Upgrade("Full Auto Rifle", 4035, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 2},
- {SHOT_KIND_UPGRADE, ENHANCED_BULLET}}));
- sniperMonkeyUpgrades.selectedPathUpgrades[0] =3;
+ Upgrade("Full Auto Rifle", 4035, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 2},
+ {SHOT_KIND_UPGRADE, ENHANCED_BULLET}}));
+ sniperMonkeyUpgrades.selectedPathUpgrades[0] = 3;
sniperMonkeyUpgrades.selectedPathUpgrades[1] = 1;
sniperMonkeyUpgrades.selectedPathUpgrades[2] = 2;
layers[MENU_LAYER].emplace_back(tower);
tower = new Entity();
position = {SIDEBAR_WIDTH + MAP_WIDTH + 65, 141};
tower->addComponent<Kind>(DART_MONKEY);
tower->addComponent<ShotKind>(DART);
- surface = gameData.assets["DartMonkey"];
- tower->addComponent<Visibility>(gameData.renderer, surface,
+ std::tie(texture, surface) = gameData.getTexture("DartMonkey");
+ tower->addComponent<Visibility>(texture, surface,
SDL_Rect{int(position.X - surface->w / 3), int(position.Y - surface->h / 3),
int(surface->w / 1.5), 0});
tower->addComponent<Action>(DRAG);
tower->addComponent<Range>(100);
tower->addComponent<AttackSpeed>(0.95);
tower->addComponent<Pierce>(1);
tower->addComponent<Damage>(1);
tower->addComponent<Distance>(150);
tower->addComponent<Cost>(170);
tower->addComponent<Type>(TOWER_T);
auto &upgrades = tower->addComponent<Upgrades>();
image = "DartMonkey_SharpShots";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades.paths[0].emplace_back(
- Upgrade("Sharp Shots", 120, image, gameData.assets[image], {{PIERCE_UPGRADE, 1}}));
+ Upgrade("Sharp Shots", 120, surface, texture, lockedTexture, {{PIERCE_UPGRADE, 1}}));
image = "DartMonkey_EnhancedEyesight_RazorSharpShots";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades.paths[0].emplace_back(
- Upgrade("Razor Sharp Shots", 185, image, gameData.assets[image], {{PIERCE_UPGRADE, 2}}));
+ Upgrade("Razor Sharp Shots", 185, surface, texture, lockedTexture, {{PIERCE_UPGRADE, 2}}));
image = "DartMonkey_Spike-O-Pult";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades.paths[0].emplace_back(
- Upgrade("Spike-O-Pult", 225, image, gameData.assets[image], {{DISTANCE_UPGRADE, 6},
- {ATTACK_SPEED_UPGRADE, 0.76},
- {SHOT_KIND_UPGRADE, SPIKE},
- {PIERCE_UPGRADE, 14}}));
+ Upgrade("Spike-O-Pult", 225, surface, texture, lockedTexture, {{DISTANCE_UPGRADE, 6},
+ {ATTACK_SPEED_UPGRADE, 0.76},
+ {SHOT_KIND_UPGRADE, SPIKE},
+ {PIERCE_UPGRADE, 14}}));
image = "DartMonkey_Juggernaut";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades.paths[0].emplace_back(
- Upgrade("Juggernaut", 1530, image, gameData.assets[image],
+ Upgrade("Juggernaut", 1530, surface, texture, lockedTexture,
{{RANGE_UPGRADE, 1.25},
{ATTACK_SPEED_UPGRADE, 1.25},
{SHOT_KIND_UPGRADE, JUGGERNAUT},
{PIERCE_UPGRADE, 86}}));
image = "DartMonkey_LongRangeDarts_QuickShots";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades.paths[1].emplace_back(
- Upgrade("Quick Shots", 85, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 1.15}}));
+ Upgrade("Quick Shots", 85, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 1.15}}));
image = "DartMonkey_VeryQuickShots";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades.paths[1].emplace_back(
- Upgrade("Very Quick Shots", 160, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 1.33}}));
+ Upgrade("Very Quick Shots", 160, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 1.33}}));
image = "DartMonkey_TripleDarts";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades.paths[1].emplace_back(
- Upgrade("Triple Shot", 340, image, gameData.assets[image], {{SHOTS_AMOUNT_UPGRADE, 3}}));
+ Upgrade("Triple Shot", 340, surface, texture, lockedTexture, {{SHOTS_AMOUNT_UPGRADE, 3}}));
image = "DartMonkey_LongRangeDarts_QuickShots";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades.paths[2].emplace_back(
- Upgrade("Long Range Darts", 75, image, gameData.assets[image], {{DISTANCE_UPGRADE, 1.25},
- {RANGE_UPGRADE, 1.25}}));
+ Upgrade("Long Range Darts", 75, surface, texture, lockedTexture, {{DISTANCE_UPGRADE, 1.25},
+ {RANGE_UPGRADE, 1.25}}));
image = "DartMonkey_EnhancedEyesight_RazorSharpShots";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades.paths[2].emplace_back(
- Upgrade("Enhanced Eyesight", 170, image, gameData.assets[image], {{DISTANCE_UPGRADE, 1.2},
- {RANGE_UPGRADE, 1.2},
- {CAMO_UPGRADE, 0}}));
+ Upgrade("Enhanced Eyesight", 170, surface, texture, lockedTexture, {{DISTANCE_UPGRADE, 1.2},
+ {RANGE_UPGRADE, 1.2},
+ {CAMO_UPGRADE, 0}}));
image = "DartMonkey_Crossbow";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades.paths[2].emplace_back(
- Upgrade("Crossbow", 530, image, gameData.assets[image], {{DISTANCE_UPGRADE, 1.16},
- {RANGE_UPGRADE, 1.16},
- {PIERCE_UPGRADE, 1},
- {DAMAGE_UPGRADE, 2}}));
+ Upgrade("Crossbow", 530, surface, texture, lockedTexture, {{DISTANCE_UPGRADE, 1.16},
+ {RANGE_UPGRADE, 1.16},
+ {PIERCE_UPGRADE, 1},
+ {DAMAGE_UPGRADE, 2}}));
upgrades.selectedPathUpgrades[0] = 2;
upgrades.selectedPathUpgrades[1] = 1;
upgrades.selectedPathUpgrades[2] = 1;
layers[MENU_LAYER].emplace_back(tower);
tower = new Entity();
position = {SIDEBAR_WIDTH + MAP_WIDTH + 65, 197};
tower->addComponent<Kind>(BOMB_TOWER);
tower->addComponent<ShotKind>(BOMB);
- surface = gameData.assets["BombTower"];
- tower->addComponent<Visibility>(gameData.renderer, surface,
+ std::tie(texture, surface) = gameData.getTexture("BombTower");
+ tower->addComponent<Visibility>(texture, surface,
SDL_Rect{int(position.X - surface->w / 3), int(position.Y - surface->h / 3),
int(surface->w / 1.5), 0});
tower->addComponent<Action>(DRAG);
tower->addComponent<Range>(100);
- tower->addComponent<AttackSpeed>(2);
- tower->addComponent<Pierce>(1);
+ tower->addComponent<AttackSpeed>(0.63);
+ tower->addComponent<Pierce>(18);
tower->addComponent<Damage>(1);
tower->addComponent<Distance>(120);
tower->addComponent<Cost>(555);
- tower->addComponent<Spread>(30);
+ tower->addComponent<Spread>(20);
tower->addComponent<Type>(TOWER_T);
+ auto &bombShooterUpgrades = tower->addComponent<Upgrades>();
+ image = "BombShooter_BiggerBombs";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[0].emplace_back(
+ Upgrade("Bigger Bombs", 340, surface, texture, lockedTexture, {{PIERCE_UPGRADE, 10},
+ {SPREAD_UPGRADE, 1.25}}));
+ image = "BombShooter_HeavyBombs";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[0].emplace_back(
+ Upgrade("Heavy Bombs", 680, surface, texture, lockedTexture, {{DAMAGE_UPGRADE, 1}}));
+ image = "BombShooter_ReallyBigBombs";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[0].emplace_back(
+ Upgrade("Really Big Bombs", 1020, surface, texture, lockedTexture, {{PIERCE_UPGRADE, 20},
+ {SPREAD_UPGRADE, 1.5}}));
+ image = "BombShooter_BloonImpact";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[0].emplace_back(
+ Upgrade("Bloon Impact", 2720, surface, texture, lockedTexture, {{DAMAGE_UPGRADE, 1},
+ {SHOT_KIND_UPGRADE, ENHANCED_BOMB},
+ {ADD_GOO_UPGRADE, STUN}}));
+ image = "BombShooter_BloonCrush";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[0].emplace_back(
+ Upgrade("Bloon Crush", 46750, surface, texture, lockedTexture, {{SPREAD_UPGRADE, 1.5},
+ {MOAB_CLASS_AFFECTING_UPGRADE, 0},
+ {GOO_DURATION_UPGRADE, 120},
+ {DAMAGE_UPGRADE, 9}}));
+
+ image = "BombShooter_FasterReload";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[1].emplace_back(
+ Upgrade("Faster Reload", 210, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 1.2}}));
+ image = "BombShooter_MissileLauncher";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[1].emplace_back(
+ Upgrade("Missile Launcher", 340, surface, texture, lockedTexture, {{SHOT_KIND_UPGRADE, MISSILE},
+ {RANGE_UPGRADE, 1.15},
+ {DISTANCE_UPGRADE, 1.15}}));
+ image = "BombShooter_MOABMauler";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[1].emplace_back(
+ Upgrade("MOAB Mauler", 765, surface, texture, lockedTexture, {{SHOT_KIND_UPGRADE, MOAB_MAULER}}));
+ image = "BombShooter_MOABAssassin";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[1].emplace_back(
+ Upgrade("MOAB Assassin", 2720, surface, texture, lockedTexture, {{SHOT_KIND_UPGRADE, MOAB_ASSASSIN}}));
+ image = "BombShooter_MOABEliminator";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[1].emplace_back(
+ Upgrade("MOAB Eliminator", 21250, surface, texture, lockedTexture, {{SHOT_KIND_UPGRADE, MOAB_ELIMINATOR}}));
+
+ image = "BombShooter_ExtraRange";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
+ bombShooterUpgrades.paths[2].emplace_back(
+ Upgrade("Extra Range", 170, surface, texture, lockedTexture, {{RANGE_UPGRADE, 1.5},
+ {DISTANCE_UPGRADE, 1.5}}));
+ bombShooterUpgrades.selectedPathUpgrades[0] = 2;
+ bombShooterUpgrades.selectedPathUpgrades[1] = 4;
+ bombShooterUpgrades.selectedPathUpgrades[2] = 0;
layers[MENU_LAYER].emplace_back(tower);
tower = new Entity();
position = {SIDEBAR_WIDTH + MAP_WIDTH + 190, 197};
tower->addComponent<Kind>(GLUE_GUNNER);
tower->addComponent<ShotKind>(GOO_SHOT);
- surface = gameData.assets["GlueGunner"];
- tower->addComponent<Visibility>(gameData.renderer, surface,
+ std::tie(texture, surface) = gameData.getTexture("GlueGunner");
+ tower->addComponent<Visibility>(texture, surface,
SDL_Rect{int(position.X - surface->w / 3), int(position.Y - surface->h / 3),
int(surface->w / 1.5), 0});
tower->addComponent<Action>(DRAG);
tower->addComponent<Range>(150);
tower->addComponent<AttackSpeed>(0.97);
tower->addComponent<Pierce>(1);
tower->addComponent<Damage>(0);
tower->addComponent<Distance>(170);
tower->addComponent<Cost>(230);
tower->addComponent<Spread>(70);
tower->addComponent<Type>(TOWER_T);
tower->addComponent<Goo>(GUM, 120);
auto &upgrades2 = tower->addComponent<Upgrades>();
image = "GlueGunner_GlueSoak_BiggerGlobs";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades2.paths[0].emplace_back(
- Upgrade("Glue Soak", 170, image, gameData.assets[image], {{GOO_SOAK_UPGRADE, 0}}));
+ Upgrade("Glue Soak", 170, surface, texture, lockedTexture, {{GOO_SOAK_UPGRADE, 0}}));
image = "GlueGunner_CorrosiveGlue";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades2.paths[0].emplace_back(
- Upgrade("Corrosive Glue", 225, image, gameData.assets[image], {{GOO_KIND_UPGRADE, CORROSIVE}}));
+ Upgrade("Corrosive Glue", 225, surface, texture, lockedTexture, {{GOO_KIND_UPGRADE, CORROSIVE}}));
image = "GlueGunner_BloonDissolver";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades2.paths[0].emplace_back(
- Upgrade("Bloon Dissolver", 2805, image, gameData.assets[image], {{DAMAGE_UPGRADE, 1},
- {CORROSIVE_INTERVAL_UPGRADE, 60}}));
+ Upgrade("Bloon Dissolver", 2805, surface, texture, lockedTexture, {{DAMAGE_UPGRADE, 1},
+ {CORROSIVE_INTERVAL_UPGRADE, 60}}));
image = "GlueGunner_BloonLiquefier";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades2.paths[0].emplace_back(
- Upgrade("Bloon Liquefier", 5950, image, gameData.assets[image],
+ Upgrade("Bloon Liquefier", 5950, surface, texture, lockedTexture,
{{CORROSIVE_INTERVAL_UPGRADE, 60 / 10.0}}));
image = "GlueGunner_GlueSoak_BiggerGlobs";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades2.paths[1].emplace_back(
- Upgrade("Bigger Globs", 85, image, gameData.assets[image], {{PIERCE_UPGRADE, 1}}));
+ Upgrade("Bigger Globs", 85, surface, texture, lockedTexture, {{PIERCE_UPGRADE, 1}}));
image = "GlueGunner_GlueSplatter";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades2.paths[1].emplace_back(
- Upgrade("Glue Splatter", 1530, image, gameData.assets[image], {{PIERCE_UPGRADE, 4}}));
+ Upgrade("Glue Splatter", 1530, surface, texture, lockedTexture, {{PIERCE_UPGRADE, 4}}));
image = "GlueGunner_GlueHose";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades2.paths[1].emplace_back(
- Upgrade("Glue Hose", 2760, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 3}}));
+ Upgrade("Glue Hose", 2760, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 3}}));
image = "GlueGunner_StickierGlue";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades2.paths[2].emplace_back(
- Upgrade("Stickier Glue", 100, image, gameData.assets[image], {{GOO_DURATION_UPGRADE, 240}}));
+ Upgrade("Stickier Glue", 100, surface, texture, lockedTexture, {{GOO_DURATION_UPGRADE, 240}}));
image = "GlueGunner_StrongerGlue";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades2.paths[2].emplace_back(
- Upgrade("Stronger Glue", 340, image, gameData.assets[image], {{GOO_STICKNESS_UPGRADE, 0.3}}));
+ Upgrade("Stronger Glue", 340, surface, texture, lockedTexture, {{GOO_STICKINESS_UPGRADE, 0.3}}));
image = "GlueGunner_SuperGlue";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
upgrades2.paths[2].emplace_back(
- Upgrade("Super Glue", 2720, image, gameData.assets[image], {{GOO_KIND_UPGRADE, GLUE}}));
+ Upgrade("Super Glue", 2720, surface, texture, lockedTexture, {{GOO_KIND_UPGRADE, GLUE}}));
upgrades2.selectedPathUpgrades[0] = 3;
upgrades2.selectedPathUpgrades[1] = 2;
upgrades2.selectedPathUpgrades[2] = 1;
layers[MENU_LAYER].emplace_back(tower);
tower = new Entity();
position = {SIDEBAR_WIDTH + MAP_WIDTH + 190, 141};
tower->addComponent<Kind>(TACK_SHOOTER);
tower->addComponent<ShotKind>(TACK);
- surface = gameData.assets["TackShooter"];
- tower->addComponent<Visibility>(gameData.renderer, surface,
+ std::tie(texture, surface) = gameData.getTexture("TackShooter");
+ tower->addComponent<Visibility>(texture, surface,
SDL_Rect{int(position.X - surface->w / 3), int(position.Y - surface->h / 3),
int(surface->w / 1.5), 0});
tower->addComponent<Action>(DRAG);
tower->addComponent<Range>(90);
tower->addComponent<AttackSpeed>(0.6);
tower->addComponent<ShotsAmount>(8);
tower->addComponent<Pierce>(1);
tower->addComponent<Damage>(1);
tower->addComponent<Distance>(100);
tower->addComponent<Cost>(305);
tower->addComponent<Type>(TOWER_T);
auto &tackShooterUpgrades = tower->addComponent<Upgrades>();
image = "TackShooter_FasterShooting";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[0].emplace_back(
- Upgrade("Faster Shooting", 125, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 1.33}}));
+ Upgrade("Faster Shooting", 125, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 1.33}}));
image = "TackShooter_EvenFasterShooting";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[0].emplace_back(
- Upgrade("Even Faster Shooting", 225, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 2}}));
+ Upgrade("Even Faster Shooting", 225, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 2}}));
image = "TackShooter_HotShots";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[0].emplace_back(
- Upgrade("Hot Shots", 510, image, gameData.assets[image], {{SHOT_KIND_UPGRADE, HOT_TACK},{DAMAGE_UPGRADE, 1}}));
+ Upgrade("Hot Shots", 510, surface, texture, lockedTexture, {{SHOT_KIND_UPGRADE, HOT_TACK},
+ {DAMAGE_UPGRADE, 1}}));
image = "TackShooter_LongRangeTacks";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[1].emplace_back(
- Upgrade("Long Range Tacks", 85, image, gameData.assets[image], {{RANGE_UPGRADE, 1.15},
- {DISTANCE_UPGRADE, 1.15}}));
+ Upgrade("Long Range Tacks", 85, surface, texture, lockedTexture, {{RANGE_UPGRADE, 1.15},
+ {DISTANCE_UPGRADE, 1.15}}));
image = "TackShooter_SuperRangeTacks";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[1].emplace_back(
- Upgrade("Super Range Tacks", 190, image, gameData.assets[image], {{RANGE_UPGRADE, 1.25},
- {DISTANCE_UPGRADE, 1.25}}));
+ Upgrade("Super Range Tacks", 190, surface, texture, lockedTexture, {{RANGE_UPGRADE, 1.25},
+ {DISTANCE_UPGRADE, 1.25}}));
image = "TackShooter_BladeShooter";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[1].emplace_back(
- Upgrade("Blade Shooter", 465, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 1.18},
- {PIERCE_UPGRADE, 2},
- {DAMAGE_UPGRADE, 2},
- {SHOT_KIND_UPGRADE, BLADE}}));
+ Upgrade("Blade Shooter", 465, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 1.18},
+ {PIERCE_UPGRADE, 2},
+ {DAMAGE_UPGRADE, 2},
+ {SHOT_KIND_UPGRADE, BLADE}}));
image = "TackShooter_MoreTacks";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[2].emplace_back(
- Upgrade("More Tacks", 85, image, gameData.assets[image], {{SHOTS_AMOUNT_UPGRADE, 10}}));
+ Upgrade("More Tacks", 85, surface, texture, lockedTexture, {{SHOTS_AMOUNT_UPGRADE, 10}}));
image = "TackShooter_EvenMoreTacks";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[2].emplace_back(
- Upgrade("Even More Tacks", 85, image, gameData.assets[image], {{SHOTS_AMOUNT_UPGRADE, 12}}));
+ Upgrade("Even More Tacks", 85, surface, texture, lockedTexture, {{SHOTS_AMOUNT_UPGRADE, 12}}));
image = "TackShooter_TackSprayer";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[2].emplace_back(
- Upgrade("Tack Sprayer", 350, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 1.33},
- {SHOTS_AMOUNT_UPGRADE, 16}}));
+ Upgrade("Tack Sprayer", 350, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 1.33},
+ {SHOTS_AMOUNT_UPGRADE, 16}}));
image = "TackShooter_Overdrive";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[2].emplace_back(
- Upgrade("Overdrive", 2125, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 3}}));
+ Upgrade("Overdrive", 2125, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 3}}));
image = "TackShooter_TheTackZone";
+ std::tie(texture, surface) = gameData.getTexture(image);
+ std::tie(lockedTexture, lockedSurface) = gameData.getTexture(image + "Locked");
tackShooterUpgrades.paths[2].emplace_back(
- Upgrade("The Tack Zone", 17000, image, gameData.assets[image], {{ATTACK_SPEED_UPGRADE, 2},
- {SHOT_KIND_UPGRADE, ENHANCED_TACK},
- {RANGE_UPGRADE, 2},
- {SHOTS_AMOUNT_UPGRADE, 32},
- {DISTANCE_UPGRADE, 2},
- {PIERCE_UPGRADE, 8}}));
+ Upgrade("The Tack Zone", 17000, surface, texture, lockedTexture, {{ATTACK_SPEED_UPGRADE, 2},
+ {SHOT_KIND_UPGRADE, ENHANCED_TACK},
+ {RANGE_UPGRADE, 2},
+ {SHOTS_AMOUNT_UPGRADE, 32},
+ {DISTANCE_UPGRADE, 2},
+ {PIERCE_UPGRADE, 8}}));
tackShooterUpgrades.selectedPathUpgrades[0] = 2;
tackShooterUpgrades.selectedPathUpgrades[1] = 2;
tackShooterUpgrades.selectedPathUpgrades[2] = 2;
layers[MENU_LAYER].emplace_back(tower);
// Systems
systems.emplace_back(new LoadLevelSystem);
systems.emplace_back(new BloonsSpawnSystem);
systems.emplace_back(new ShotsSpawnSystem);
systems.emplace_back(new EventSystem);
systems.emplace_back(new DraggingSystem);
systems.emplace_back(new CollisionSystem);
systems.emplace_back(new DamageSystem);
systems.emplace_back(new PopEffectSystem);
systems.emplace_back(new MenuSystem);
systems.emplace_back(new MovementSystem);
systems.emplace_back(new RemoveEntitiesSystem);
systems.emplace_back(renderSystem);
}
Game::~Game() {
SDL_Quit();
}
void Game::update() {
for (auto &system : systems) {
system->update(layers.begin(), gameData);
}
}
void Game::loadMap() {
std::string fileName = "../assets/map" + std::to_string(gameData.map);
std::ifstream obstaclesFile(fileName + "_obstacles.data", std::ios::binary);
int x = 0, y = 0;
for (int i = 0; i < ceilf(MAP_WIDTH * MAP_HEIGHT / 8.0); ++i) {
unsigned char byte;
obstaclesFile.read((char *) &byte, 1);
for (int j = 0; j < 8; ++j) {
char bit = (byte & 2 << j) >> j;
gameData.mapData[x][y] = bit;
x++;
if (x == MAP_WIDTH) {
x = 0;
y++;
}
if (x * y >= MAP_WIDTH * MAP_HEIGHT)
goto readPathFile;
}
}
readPathFile:
gameData.path.clear();
std::ifstream pathFile(fileName + "_path.data", std::ios::binary);
unsigned int length;
TempPoint startingPoint, finishPoint;
pathFile.read((char *) &startingPoint, 4);
pathFile.read((char *) &length, 4);
gameData.path.resize(length);
pathFile.read(&gameData.path[0], length);
pathFile.read((char *) &finishPoint, 4);
gameData.startingPoint = {float(startingPoint.X), float(startingPoint.Y)};
gameData.finishPoint = {float(finishPoint.X), float(finishPoint.Y)};
}
diff --git a/src/GameData.cpp b/src/GameData.cpp
index b5d5769..73c6214 100644
--- a/src/GameData.cpp
+++ b/src/GameData.cpp
@@ -1,16 +1,28 @@
//
// Created by Ido Mozes on 07/07/2019.
//
#include "GameData.h"
GameData::~GameData() {
- for(auto & item:assets){
+ for (auto &item:assets) {
SDL_FreeSurface(item.second);
}
+ for (auto &item:assetsCache) {
+ SDL_DestroyTexture(item.second);
+ }
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
for (int i = 0; i < FONTS_LENGTH; ++i) {
FC_FreeFont(fonts[i]);
}
}
+
+std::tuple<SDL_Texture *, SDL_Surface *> GameData::getTexture(const std::string &name) {
+ SDL_Surface *surface = assets[name];
+ if (auto texture = assetsCache[name])
+ return std::make_tuple(texture, surface);
+ SDL_Texture *newTexture = SDL_CreateTextureFromSurface(renderer, surface);
+ assetsCache[name] = newTexture;
+ return std::make_tuple(newTexture, surface);
+}
diff --git a/src/GameData.h b/src/GameData.h
index 85c4659..482e88a 100644
--- a/src/GameData.h
+++ b/src/GameData.h
@@ -1,49 +1,51 @@
//
// Created by Ido Mozes on 03/07/2019.
//
#ifndef SDL_GAME_GAMEDATA_H
#define SDL_GAME_GAMEDATA_H
#include <vector>
#include <memory>
#include <unordered_map>
#include "Component.h"
#include "Entity.h"
#include "Settings.h"
#include "SDL.h"
#include "SDL_FontCache.h"
constexpr char FREE = 0;
constexpr char OBSTACLE = 1;
constexpr char TOWER = 2;
class GameData {
public:
int FPS = 60;
bool isRunning = true;
bool lost = false;
bool isDragging = false;
int cash = 100000;
bool levelRunning = false;
bool levelReady = false;
int lives = 200;
int level = 1;
int finalLevel = 2;
int map = 0;
float mapScale;
bool fullscreen;
std::vector<char> path;
char mapData[MAP_WIDTH][MAP_HEIGHT];
Point startingPoint;
Point finishPoint;
std::unordered_map<std::string, SDL_Surface *> assets;
+ std::unordered_map<std::string, SDL_Texture *> assetsCache;
SDL_Window *window = nullptr;
SDL_Renderer *renderer = nullptr;
EntityP selected;
FC_Font* fonts[FONTS_LENGTH];
EntityP playButton;
~GameData();
+ std::tuple<SDL_Texture *,SDL_Surface *> getTexture(const std::string &name);
};
#endif //SDL_GAME_GAMEDATA_H
diff --git a/src/System.cpp b/src/System.cpp
index e016537..b6e813f 100644
--- a/src/System.cpp
+++ b/src/System.cpp
@@ -1,279 +1,303 @@
//
// Created by Ido Mozes on 15/07/2019.
//
#include "System.h"
std::string getSurfaceName(EntityP &entity) {
std::string surfaceName;
int damageStateLives = getBloonProperty<SELF_LIVES>(entity) / 5;
switch (entity->getComponent<Type>()->value) {
case BLOON_T: {
auto[regrowP, camoP, fortifiedP, gooP, lives] = entity->getComponentsP<Regrow, Camo, Fortified, Goo, Lives>();
switch (entity->getComponent<Kind>()->value) {
case RED_BLOON:
surfaceName = "Red";
break;
case BLUE_BLOON:
surfaceName = "Blue";
break;
case GREEN_BLOON:
surfaceName = "Green";
break;
case YELLOW_BLOON:
surfaceName = "Yellow";
break;
case PINK_BLOON:
surfaceName = "Pink";
break;
case PURPLE_BLOON:
surfaceName = "Purple";
break;
case WHITE_BLOON:
surfaceName = "White";
break;
case BLACK_BLOON:
surfaceName = "Black";
break;
case ZEBRA_BLOON:
surfaceName = "Zebra";
break;
case LEAD_BLOON:
surfaceName = "Lead";
break;
case RAINBOW_BLOON:
surfaceName = "Rainbow";
break;
case CERAMIC_BLOON:
surfaceName = "Ceramic";
break;
case MOAB:
surfaceName = "Moab";
break;
case BFB:
surfaceName = "Bfb";
break;
case DDT:
surfaceName = "Ddt";
break;
case ZOMG:
surfaceName = "Zomg";
break;
case BAD:
surfaceName = "Bad";
break;
}
if (regrowP)
surfaceName += "Regrow";
if (camoP)
surfaceName += "Camo";
if (fortifiedP) {
surfaceName += "Fortified";
}
if (damageStateLives) {
int maxLives = getBloonProperty<TOTAL_LIVES>(entity);
if (int damageState = (maxLives - lives->value) / damageStateLives)
surfaceName += "DamageState" + std::to_string(damageState);
}
if (gooP)
switch (gooP->kind) {
case GLUE:
surfaceName += "Gum";
break;
case GUM:
surfaceName += "Glue";
break;
case CORROSIVE:
surfaceName += "Slime";
break;
}
break;
}
case TOWER_T: {
switch (entity->getComponent<Kind>()->value) {
case DART_MONKEY:
surfaceName = "DartMonkey";
break;
case TACK_SHOOTER:
surfaceName = "TackShooter";
break;
case SUPER_MONKEY:
surfaceName = "SuperMonkey";
break;
case SNIPER_MONKEY:
surfaceName = "SniperMonkey";
break;
case BOMB_TOWER:
surfaceName = "BombTower";
break;
case GLUE_GUNNER:
surfaceName = "GlueGunner";
break;
}
break;
}
case SHOT_T: {
switch (entity->getComponent<Kind>()->value) {
case SPIKE:
surfaceName = "Spike";
break;
case JUGGERNAUT:
surfaceName = "Juggernaut";
break;
case LASER:
surfaceName = "Laser";
break;
case PLASMA:
surfaceName = "Plasma";
break;
case SUN:
surfaceName = "Sun";
break;
case DART:
surfaceName = "Dart";
break;
case BOMB:
+ case ENHANCED_BOMB:
surfaceName = "Bomb";
break;
- case EXPLOSION:
+ case MISSILE:
+ surfaceName = "Missile";
+ break;
+ case MOAB_MAULER:
+ surfaceName = "MoabMauler";
+ break;
+ case MOAB_ASSASSIN:
+ surfaceName = "MoabAssassin";
+ break;
+ case MOAB_ELIMINATOR:
+ surfaceName = "MoabEliminator";
+ break;
+ case BOMB_EXPLOSION:
+ case MISSILE_EXPLOSION:
+ case ENHANCED_BOMB_EXPLOSION:
+ case MOAB_MAULER_EXPLOSION:
+ case MOAB_ASSASSIN_EXPLOSION:
+ case MOAB_ELIMINATOR_EXPLOSION:
surfaceName = "Explosion";
break;
case TACK:
case ENHANCED_TACK:
surfaceName = "Tack";
break;
case HOT_TACK:
- surfaceName="HotTack";
+ surfaceName = "HotTack";
break;
case BLADE:
- surfaceName="Blade";
+ surfaceName = "Blade";
break;
case GOO_SPLASH:
switch (entity->getComponent<Goo>()->kind) {
case GLUE:
surfaceName = "SplashGum";
break;
case GUM:
surfaceName = "SplashGlue";
break;
case CORROSIVE:
surfaceName = "SplashSlime";
break;
}
break;
case GOO_SHOT:
switch (entity->getComponent<Goo>()->kind) {
case GLUE:
surfaceName = "GumShot";
break;
case GUM:
surfaceName = "GlueShot";
break;
case CORROSIVE:
surfaceName = "SlimeShot";
break;
}
break;
}
break;
}
}
return surfaceName;
}
float getSpeed(EntityP &entity) {
float speed;
switch (entity->getComponent<Type>()->value) {
case BLOON_T: {
auto gooP = entity->getComponent<Goo>();
switch (entity->getComponent<Kind>()->value) {
case RED_BLOON:
speed = 3 * BPS;
break;
case BLUE_BLOON:
speed = 4 * BPS;
break;
case GREEN_BLOON:
speed = 5 * BPS;
break;
case YELLOW_BLOON:
speed = 10 * BPS;
break;
case PINK_BLOON:
speed = 11 * BPS;
break;
case PURPLE_BLOON:
speed = 9.5 * BPS;
break;
case WHITE_BLOON:
speed = 6 * BPS;
break;
case BLACK_BLOON:
speed = 5 * BPS;
break;
case ZEBRA_BLOON:
speed = 5 * BPS;
break;
case LEAD_BLOON:
speed = 3 * BPS;
break;
case RAINBOW_BLOON:
speed = 7 * BPS;
break;
case CERAMIC_BLOON:
speed = 8 * BPS;
break;
case MOAB:
speed = 3 * BPS;
break;
case BFB:
speed = 1 * BPS;
break;
case DDT:
speed = 9 * BPS;
break;
case ZOMG:
speed = 0.5 * BPS;
break;
case BAD:
speed = 0.2 * BPS;
break;
}
if (gooP)
switch (gooP->kind) {
case CORROSIVE:
case GUM:
speed *= gooP->stickness;
break;
case GLUE:
+ case STUN:
speed = 0;
}
break;
}
case SHOT_T: {
switch (entity->getComponent<Kind>()->value) {
case SPIKE:
case JUGGERNAUT:
speed = 12;
break;
case LASER:
case PLASMA:
case SUN:
case TACK:
case BLADE:
case ENHANCED_TACK:
case HOT_TACK:
case DART:
+ case MISSILE:
+ case MOAB_MAULER:
+ case MOAB_ASSASSIN:
+ case MOAB_ELIMINATOR:
speed = 22;
break;
case BOMB:
+ case ENHANCED_BOMB:
case GOO_SHOT:
speed = 15;
break;
}
break;
}
}
return speed;
}
diff --git a/src/components/FlagComponents.h b/src/components/FlagComponents.h
index 0f7cdd3..8f4388d 100644
--- a/src/components/FlagComponents.h
+++ b/src/components/FlagComponents.h
@@ -1,18 +1,19 @@
//
// Created by Ido Mozes on 15/07/2019.
//
#ifndef SDL_GAME_FLAGCOMPONENTS_H
#define SDL_GAME_FLAGCOMPONENTS_H
#define FLAG_COMPONENT(className, classType) class className : public FlagComponent { public: static constexpr ComponentType type = ComponentType::classType;}
#include "../Component.h"
class FlagComponent : public Component {};
FLAG_COMPONENT(RemoveEntityEvent,REMOVE_ENTITY_EVENT);
FLAG_COMPONENT(Camo,CAMO);
FLAG_COMPONENT(Fortified,FORTIFIED);
FLAG_COMPONENT(Seen,SEEN);
+FLAG_COMPONENT(MoabClassAffecting,MOAB_CLASS_AFFECTING);
#endif //SDL_GAME_FLAGCOMPONENTS_H
diff --git a/src/components/Goo.h b/src/components/Goo.h
index d330d13..7c689de 100644
--- a/src/components/Goo.h
+++ b/src/components/Goo.h
@@ -1,24 +1,24 @@
//
// Created by Ido Mozes on 18/07/2019.
//
#ifndef SDL_GAME_GOO_H
#define SDL_GAME_GOO_H
#include "../Component.h"
class Goo : public Component {
public:
int kind;
int ttl;
int interval;
int timetoRecharge;
- bool soak = false;
+ bool soak;
int damage = 1;
float stickness = 0.6;
static constexpr ComponentType type = ComponentType::GOO;
- Goo(int kind, int ttl, int interval=60) : kind(kind), ttl(ttl), timetoRecharge(interval),interval(interval) {}
+ Goo(int kind, int ttl, int interval=60, bool soak = false) : kind(kind), ttl(ttl), timetoRecharge(interval),interval(interval),soak(soak) {}
};
#endif //SDL_GAME_GOO_H
diff --git a/src/components/IntegerComponents.h b/src/components/IntegerComponents.h
index bb78167..d1bfbbc 100644
--- a/src/components/IntegerComponents.h
+++ b/src/components/IntegerComponents.h
@@ -1,92 +1,104 @@
//
// Created by Ido Mozes on 14/07/2019.
//
#ifndef SDL_GAME_INTEGERCOMPONENTS_H
#define SDL_GAME_INTEGERCOMPONENTS_H
#define INTEGER_COMPONENT(className, classType) class className : public IntegerComponent { public: static constexpr ComponentType type = ComponentType::classType; using IntegerComponent::IntegerComponent; }
#include "../Component.h"
class IntegerComponent : public Component {
public:
int value;
explicit IntegerComponent(int value) : value(value) {}
};
enum Types {
OBSTACLE_T, TOWER_T, BLOON_T, SHOT_T, SEQUENCE_T
};
enum Strategies {
FIRST, LAST, CLOSEST, STRONGEST
};
enum BloonKinds {
RED_BLOON,
BLUE_BLOON,
GREEN_BLOON,
YELLOW_BLOON,
PINK_BLOON,
PURPLE_BLOON,
WHITE_BLOON,
BLACK_BLOON,
LEAD_BLOON,
ZEBRA_BLOON,
RAINBOW_BLOON,
CERAMIC_BLOON,
MOAB,
BFB,
ZOMG,
DDT,
BAD
};
enum TowerKinds {
DART_MONKEY,
TACK_SHOOTER,
SUPER_MONKEY,
SNIPER_MONKEY,
BOMB_TOWER,
GLUE_GUNNER,
};
enum ShotKinds {
SPIKE,
JUGGERNAUT,
DART,
TACK,
ENHANCED_TACK,
HOT_TACK,
BLADE,
BULLET,
ENHANCED_BULLET,
BOMB,
- EXPLOSION,
+ BOMB_EXPLOSION,
+ MISSILE,
+ MISSILE_EXPLOSION,
+ ENHANCED_BOMB,
+ ENHANCED_BOMB_EXPLOSION,
+ MOAB_MAULER,
+ MOAB_MAULER_EXPLOSION,
+ MOAB_ASSASSIN,
+ MOAB_ASSASSIN_EXPLOSION,
+ MOAB_ELIMINATOR,
+ MOAB_ELIMINATOR_EXPLOSION,
+
GOO_SHOT,
GOO_SPLASH,
GLUE,
GUM,
+ STUN,
CORROSIVE,
LASER,
PLASMA,
SUN
};
INTEGER_COMPONENT(Lives, LIVES);
INTEGER_COMPONENT(Damage, DAMAGE);
INTEGER_COMPONENT(Pierce, PIERCE);
INTEGER_COMPONENT(Type, TYPE);
INTEGER_COMPONENT(Strategy, STRATEGY);
INTEGER_COMPONENT(Cost, COST);
INTEGER_COMPONENT(Kind, KIND);
INTEGER_COMPONENT(ShotKind, SHOT_KIND);
INTEGER_COMPONENT(ShotsAmount, SHOTS_AMOUNT);
#endif //SDL_GAME_INTEGERCOMPONENTS_H
diff --git a/src/components/Upgrades.h b/src/components/Upgrades.h
index 5fea56d..a04e751 100644
--- a/src/components/Upgrades.h
+++ b/src/components/Upgrades.h
@@ -1,66 +1,71 @@
//
// Created by Ido Mozes on 20/07/2019.
//
#ifndef SDL_GAME_UPGRADES_H
#define SDL_GAME_UPGRADES_H
#include <vector>
#include <tuple>
#include <array>
#include "../Component.h"
#include "SDL.h"
enum UpgradeTypes {
RANGE_UPGRADE,
PIERCE_UPGRADE,
DISTANCE_UPGRADE,
DAMAGE_UPGRADE,
ATTACK_SPEED_UPGRADE,
SPREAD_UPGRADE,
CAMO_UPGRADE,
+ ADD_GOO_UPGRADE,
GOO_KIND_UPGRADE,
GOO_SOAK_UPGRADE,
GOO_DURATION_UPGRADE,
- GOO_STICKNESS_UPGRADE,
+ GOO_STICKINESS_UPGRADE,
CORROSIVE_INTERVAL_UPGRADE,
CORROSIVE_DAMAGE_UPGRADE,
SHOTS_AMOUNT_UPGRADE,
- SHOT_KIND_UPGRADE
+ SHOT_KIND_UPGRADE,
+ MOAB_CLASS_AFFECTING_UPGRADE,
};
class Upgrade {
public:
std::vector<std::tuple<int, float>> improvements;
SDL_Surface *surface;
- std::string surfaceName;
+ SDL_Texture *texture;
+ SDL_Texture *lockedTexture;
std::string name;
int cost;
bool locked = false;
- Upgrade(const std::string &name, int cost, const std::string surfaceName, SDL_Surface *surface,
- std::initializer_list<std::pair<int, float>> improvements) : name(name), cost(cost),
- surfaceName(surfaceName), surface(surface) {
+ Upgrade(const std::string &name, int cost, SDL_Surface *surface, SDL_Texture *texture, SDL_Texture *lockedTexture,
+ std::initializer_list<std::pair<int, float>> improvements) : name(name), cost(cost), surface(surface),
+ texture(texture),
+ lockedTexture(lockedTexture) {
for (auto[kind, value]: improvements)
this->improvements.emplace_back(kind, value);
}
};
class UpgradeP : public Component {
public:
- Upgrade* value;
+ Upgrade *value;
static constexpr ComponentType type = ComponentType::UPGRADE_P;
std::string name;
- UpgradeP(Upgrade* value) : value(value),name(value->name) {}
+
+ UpgradeP(Upgrade *value) : value(value), name(value->name) {}
};
class Upgrades : public Component {
public:
- std::array<std::vector<Upgrade>,3> paths;
+ std::array<std::vector<Upgrade>, 3> paths;
int selectedPathUpgrades[3];
int chosenPath = -1;
static constexpr ComponentType type = ComponentType::UPGRADES;
};
#endif //SDL_GAME_UPGRADES_H
diff --git a/src/components/Visibility.cpp b/src/components/Visibility.cpp
index dac7a28..2c29a8e 100644
--- a/src/components/Visibility.cpp
+++ b/src/components/Visibility.cpp
@@ -1,40 +1,30 @@
//
// Created by Ido Mozes on 23/06/2019.
//
#include "Visibility.h"
-Visibility::Visibility(SDL_Renderer *renderer, SDL_Surface *newSurface, std::optional<SDL_Rect> dstR, float angle, bool hidden)
- : dstRect(dstR), angle(angle), hidden(hidden) {
- loadTexture(renderer, newSurface);
-}
-
-Visibility::~Visibility() {
- SDL_DestroyTexture(texture);
-}
-void Visibility::loadTexture(SDL_Renderer *renderer, SDL_Surface *newSurface) {
- surface = newSurface;
- reloadTexture(renderer);
+void Visibility::reloadTexture(SDL_Texture *newTexture, SDL_Surface *newSurface) {
+ if (newTexture) {
+ texture = newTexture;
+ surface = newSurface;
+ }
if (dstRect) {
if (dstRect->w == 0)
dstRect->w = int((float(surface->w) / surface->h) * dstRect->h);
else if (dstRect->h == 0)
dstRect->h = int((float(surface->h) / surface->w) * dstRect->w);
}
}
-void Visibility::reloadTexture(SDL_Renderer *renderer) {
- SDL_DestroyTexture(texture);
- texture = SDL_CreateTextureFromSurface(renderer, surface);
-}
void Visibility::setPosition(int x, int y) {
if (dstRect) {
dstRect->x = x;
dstRect->y = y;
}
}
diff --git a/src/components/Visibility.h b/src/components/Visibility.h
index 20cc7ab..a50dc24 100644
--- a/src/components/Visibility.h
+++ b/src/components/Visibility.h
@@ -1,47 +1,41 @@
//
// Created by Ido Mozes on 23/06/2019.
//
#ifndef SDL2_GAME_VISIBILITY_H
#define SDL2_GAME_VISIBILITY_H
#include <fstream>
#include <optional>
#include "SDL.h"
#include "SDL_image.h"
#include "../Component.h"
-SDL_Texture *loadTexture(SDL_Renderer *renderer, const char *path);
-
class Visibility : public Component {
SDL_Surface *surface = nullptr;
SDL_Texture *texture = nullptr;
std::optional<SDL_Rect> dstRect;
public:
float angle = 0;
bool hidden = false;
static constexpr ComponentType type = ComponentType::VISIBILITY;
- Visibility(SDL_Renderer *renderer, SDL_Surface *newSurface, std::optional<SDL_Rect> dstR = std::nullopt,
- float angle = 0,bool hidden = false);
-
-
- ~Visibility() override;
+ Visibility(SDL_Texture *newTexture, SDL_Surface *newSurface, std::optional<SDL_Rect> dstR = std::nullopt,
+ float angle = 0, bool hidden = false) : dstRect(dstR), angle(angle), hidden(hidden), texture(newTexture),
+ surface(newSurface) { reloadTexture(); }
SDL_Texture *getTexture() { return texture; }
SDL_Rect *getDstRect() { return dstRect ? &dstRect.value() : nullptr; }
- void setDstRect(SDL_Rect newDstRect) {dstRect.value()= newDstRect;}
+ void setDstRect(SDL_Rect newDstRect) { dstRect.value() = newDstRect; }
void setPosition(int x, int y);
- void loadTexture(SDL_Renderer *renderer, SDL_Surface *newSurface);
-
- void reloadTexture(SDL_Renderer *renderer);
+ void reloadTexture(SDL_Texture *newTexture = nullptr, SDL_Surface *newSurface = nullptr);
};
#endif //SDL2_GAME_VISIBILITY_H
diff --git a/src/systems/BloonsSpawnSystem.cpp b/src/systems/BloonsSpawnSystem.cpp
index c913125..0a5aca2 100644
--- a/src/systems/BloonsSpawnSystem.cpp
+++ b/src/systems/BloonsSpawnSystem.cpp
@@ -1,42 +1,42 @@
//
// Created by Ido Mozes on 07/07/2019.
//
#include "BloonsSpawnSystem.h"
void BloonsSpawnSystem::update(Entities *layers, GameData &gameData) {
if(!gameData.levelRunning)
return;
for (auto &entity: layers[SEQUENCES_LAYER]) {
auto[sequence, kind] = entity->getComponents<Sequence, Kind>().value();
auto [regrowP,camoP,fortifiedP] = entity->getComponentsP<Regrow,Camo,Fortified>();
int amount = sequence.getAmountReady();
if(amount == SEQUENCE_FINISHED)
{
entity->addComponent<RemoveEntityEvent>();
continue;
}
for (int j = 0; j < amount; ++j) {
EntityP bloon(new Entity());
bloon->addComponent<Type>(BLOON_T);
bloon->addComponent<Position>(gameData.startingPoint);
bloon->addComponent<PathIndex>(0);
bloon->addComponents(kind);
if (regrowP)
bloon->addComponent<Regrow>(*regrowP);
if (camoP)
bloon->addComponent<Camo>();
if (fortifiedP)
bloon->addComponent<Fortified>();
bloon->addComponent<Lives>(getBloonProperty<TOTAL_LIVES>(bloon));
- SDL_Surface *surface = gameData.assets[getSurfaceName(bloon)];
- bloon->addComponent<Visibility>(gameData.renderer, surface,
+ auto [texture,surface] = gameData.getTexture(getSurfaceName(bloon));
+ bloon->addComponent<Visibility>(texture, surface,
SDL_Rect{0, 0, int(surface->w / 3), int(surface->h / 3)});
bloon->addComponent<Range>(std::max(surface->w / 6, surface->h / 6));
layers[BLOONS_LAYER].emplace_back(bloon);
}
}
}
diff --git a/src/systems/CollisionSystem.cpp b/src/systems/CollisionSystem.cpp
index 502991a..f241875 100644
--- a/src/systems/CollisionSystem.cpp
+++ b/src/systems/CollisionSystem.cpp
@@ -1,188 +1,240 @@
//
// Created by Ido Mozes on 11/07/2019.
//
#include "CollisionSystem.h"
inline float getLeft(EntityP &entity) {
return entity->getComponent<Position>()->value.X - entity->getComponent<Range>()->value;
}
int binarySearch(Entities &layer, float left, int low, int high) {
if (high <= low)
return left > getLeft(layer[low]) ? (low + 1) : low;
int mid = (low + high) / 2;
if (left == getLeft(layer[mid]))
return mid + 1;
if (left > getLeft(layer[mid]))
return binarySearch(layer, left, mid + 1, high);
return binarySearch(layer, left, low, mid - 1);
}
int
binarySearch(std::vector<std::tuple<EntityP, EntityP, float>> collided, float distance,
int low, int high) {
if (high <= low)
return distance > std::get<2>(collided[low]) ? (low + 1) : low;
int mid = (low + high) / 2;
if (distance == std::get<2>(collided[mid]))
return mid + 1;
if (distance > std::get<2>(collided[mid]))
return binarySearch(collided, distance, mid + 1, high);
return binarySearch(collided, distance, low, mid - 1);
}
void insertionSort(Entities &layer) {
// can be optimized with binary search instead of comparison to every item
for (int i = 1, j = 0; i < layer.size(); j = i++) {
auto &entity = layer[i];
EntityP entityP(entity);
auto &previousEntity = layer[i - 1];
auto[position, range] = entity->getComponents<Position, Range>().value();
float entityLeft = position.value.X - range.value;
if (entityLeft >= getLeft(layer[j]))
continue;
int loc = binarySearch(layer, entityLeft, 0, j);
while (j >= loc) {
layer[j + 1] = layer[j];
--j;
}
if (j != i - 1) {
layer[j + 1] = entityP;
}
}
}
void CollisionSystem::update(Entities *layers, GameData &gameData) {
if (!gameData.levelRunning)
return;
Entities &bloonsLayer = layers[BLOONS_LAYER];
Entities &shotsLayer = layers[SHOTS_LAYER];
insertionSort(bloonsLayer);
insertionSort(shotsLayer);
std::vector<std::tuple<EntityP, EntityP, float>> collided;
int bloonIndex = 0;
for (auto &shot : shotsLayer) {
int collidedIndex = collided.size();
auto[shotPosition, poppedBloons] = shot->getComponents<Position, PoppedBloons>().value();
auto[shotX, shotY] = shotPosition.value;
auto shotRange = shot->getComponent<Range>()->value;
float shotLeft = shotX - shotRange;
float shotRight = shotX + shotRange;
float shotTop = shotY - shotRange;
float shotBottom = shotY + shotRange;
for (int i = bloonIndex; i < bloonsLayer.size(); ++i) {
auto &bloon = bloonsLayer[i];
auto bloonPosition = bloon->getComponent<Position>()->value;
auto[bloonX, bloonY] = bloonPosition;
auto bloonRange = bloon->getComponent<Range>()->value;
float bloonLeft = bloonX - bloonRange;
float bloonRight = bloonX + bloonRange;
float bloonTop = bloonY - bloonRange;
float bloonBottom = bloonY + bloonRange;
if (bloonRight < shotLeft) {
bloonIndex++;
continue;
}
if (shotRight < bloonLeft)
break;
if (shotBottom >= bloonTop and shotTop <= bloonBottom and !poppedBloons.value.count(bloon.get())) {
poppedBloons.value.emplace(bloon.get());
float distance = twoPointsDistance(shotPosition.value, bloonPosition);
if (collidedIndex == collided.size())
collided.emplace_back(shot, bloon, distance);
else {
int index = binarySearch(collided, distance, collidedIndex, collided.size() - 1);
if (index < collided.size())
collided.emplace(collided.begin() + index, shot, bloon, distance);
else
collided.emplace_back(shot, bloon, distance);
}
}
}
}
for (auto[shot, bloon, _] :collided) {
auto[pierce, damage, kind, position] = shot->getComponents<Pierce, Damage, Kind, Position>().value();
if (bloon->getComponent<Camo>() and !shot->getComponent<Camo>())
continue;
int bloonKind = bloon->getComponent<Kind>()->value;
- if (kind.value == EXPLOSION or pierce.value > 0) {
+ if (pierce.value > 0) {
switch (kind.value) {
case LASER:
if (bloonKind != PURPLE_BLOON and bloonKind != LEAD_BLOON)
bloon->addComponent<DamageEvent>(damage.value, shot);
break;
case PLASMA:
if (bloonKind != PURPLE_BLOON)
bloon->addComponent<DamageEvent>(damage.value, shot);
break;
case SUN:
case HOT_TACK:
case ENHANCED_TACK:
bloon->addComponent<DamageEvent>(damage.value, shot);
break;
case DART:
case TACK:
case BLADE:
case SPIKE:
if (bloonKind != LEAD_BLOON)
bloon->addComponent<DamageEvent>(damage.value, shot);
break;
case JUGGERNAUT:
bloon->addComponent<DamageEvent>(bloonKind == CERAMIC_BLOON ? 5 : damage.value, shot);
break;
- case EXPLOSION:
- if (bloonKind != BLACK_BLOON and bloonKind != ZEBRA_BLOON)
- bloon->addComponent<DamageEvent>(damage.value, shot);
+ case BOMB_EXPLOSION:
+ case MISSILE_EXPLOSION:
+ case ENHANCED_BOMB_EXPLOSION:
+ case MOAB_MAULER_EXPLOSION:
+ case MOAB_ASSASSIN_EXPLOSION:
+ case MOAB_ELIMINATOR_EXPLOSION: {
+ bool breakFlag = false;
+ shot->addComponent<RemoveEntityEvent>();
+ switch (kind.value) {
+ case BOMB_EXPLOSION:
+ case MISSILE_EXPLOSION:
+ case MOAB_MAULER_EXPLOSION:
+ if (bloonKind == BLACK_BLOON or bloonKind == ZEBRA_BLOON)
+ breakFlag = true;
+ break;
+ }
+ if (breakFlag)
+ break;
+ auto shotGooP = shot->getComponent<Goo>();
+ if (shotGooP and (bloonKind < MOAB or shot->getComponent<MoabClassAffecting>()))
+ bloon->addComponent<Goo>(*shotGooP);
+ int _damage = damage.value;
+ if (bloonKind >= MOAB)
+ switch (kind.value) {
+ case MOAB_MAULER_EXPLOSION:
+ _damage += 15;
+ break;
+ case MOAB_ASSASSIN_EXPLOSION:
+ _damage += 20;
+ break;
+ case MOAB_ELIMINATOR_EXPLOSION:
+ _damage += 80;
+ break;
+ }
+ if (bloonKind == CERAMIC_BLOON)
+ switch (kind.value) {
+ case MOAB_ASSASSIN_EXPLOSION:
+ case MOAB_ELIMINATOR_EXPLOSION:
+ _damage = 24;
+ break;
+ }
+ bloon->addComponent<DamageEvent>(_damage, shot);
break;
+ }
case GOO_SPLASH: {
bloon->addComponent<DamageEvent>(damage.value, shot);
if (bloonKind < MOAB and !bloon->getComponent<Goo>()) {
bloon->addComponent<Goo>(*shot->getComponent<Goo>());
- SDL_Surface *surface = gameData.assets[getSurfaceName(bloon)];
+ auto [texture,surface] = gameData.getTexture(getSurfaceName(bloon));
auto &visibility = *bloon->getComponent<Visibility>();
visibility.setDstRect(SDL_Rect{0, 0, surface->w / 3, 0});
- visibility.loadTexture(gameData.renderer, surface);
+ visibility.reloadTexture(texture, surface);
}
shot->addComponent<RemoveEntityEvent>();
break;
}
case BOMB:
+ case ENHANCED_BOMB:
+ case MISSILE:
+ case MOAB_MAULER:
+ case MOAB_ASSASSIN:
+ case MOAB_ELIMINATOR:
case GOO_SHOT:
if (shot->getComponent<RemoveEntityEvent>())
break;
EntityP explosion(new Entity());
explosion->addComponent<Position>(position.value.X, position.value.Y);
explosion->addComponent<Type>(SHOT_T);
switch (kind.value) {
case BOMB:
- explosion->addComponent<Kind>(EXPLOSION);
+ case ENHANCED_BOMB:
+ case MISSILE:
+ case MOAB_MAULER:
+ case MOAB_ASSASSIN:
+ case MOAB_ELIMINATOR:
+ explosion->addComponent<Kind>(kind.value + 1);
+ if (auto shotGooP = shot->getComponent<Goo>())
+ explosion->addComponent<Goo>(*shotGooP);
break;
case GOO_SHOT:
explosion->addComponent<Kind>(GOO_SPLASH);
explosion->addComponent<Goo>(*shot->getComponent<Goo>());
break;
}
explosion->addComponent<Pierce>(pierce);
explosion->addComponent<PoppedBloons>();
explosion->addComponent<Range>(shot->getComponent<Spread>()->value);
explosion->addComponents(damage);
- SDL_Surface *surface = gameData.assets[getSurfaceName(explosion)];
- explosion->addComponent<Visibility>(gameData.renderer, surface, SDL_Rect{0, 0, surface->w / 2});
+ auto [texture,surface] = gameData.getTexture(getSurfaceName(explosion));
+ explosion->addComponent<Visibility>(texture, surface, SDL_Rect{0, 0, surface->w / 2});
layers[SHOTS_LAYER].emplace_back(explosion);
shot->addComponent<RemoveEntityEvent>();
break;
}
- if (kind.value == EXPLOSION or --pierce.value == 0)
+ if (--pierce.value == 0)
shot->addComponent<RemoveEntityEvent>();
}
}
}
\ No newline at end of file
diff --git a/src/systems/DamageSystem.cpp b/src/systems/DamageSystem.cpp
index 902bb2b..b233fcd 100644
--- a/src/systems/DamageSystem.cpp
+++ b/src/systems/DamageSystem.cpp
@@ -1,220 +1,207 @@
//
// Created by Ido Mozes on 15/07/2019.
//
#include "DamageSystem.h"
bool didBloonPop(EntityP &bloon, int &lives, int &damage) {
if (bloon->getComponent<Fortified>()) {
if (damage == 1) {
lives -= damage;
if (lives % 2 == 1)
return false;
} else {
lives -= 2;
damage -= 2;
}
} else {
lives -= 1;
damage -= 1;
}
return true;
}
bool didBloonPop(EntityP &bloon, int &lives, int &damage, int minLives) {
if (lives - damage >= minLives) {
lives -= damage;
return false;
}
damage -= lives - minLives + 1;
lives = minLives - 1;
return true;
}
EntityP
spawnBloon(Entities &newBloons, GameData &gameData, int kind, EntityP &shot, int lives, float progress,
int regrow, bool camo, bool fortified, Goo *gooP) {
EntityP newBloon(new Entity());
if (shot)
shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
newBloon->addComponent<Type>(BLOON_T);
newBloon->addComponent<Kind>(kind);
newBloon->addComponent<Lives>(lives);
newBloon->addComponent<Position>(gameData.startingPoint);
newBloon->addComponent<PathIndex>(0, progress);
if (regrow)
newBloon->addComponent<Regrow>(regrow);
if (camo)
newBloon->addComponent<Camo>();
if (fortified)
newBloon->addComponent<Fortified>();
if (gooP and gooP->soak)
newBloon->addComponent<Goo>(*gooP);
- SDL_Surface *surface = gameData.assets[getSurfaceName(newBloon)];
+ auto [texture,surface] = gameData.getTexture(getSurfaceName(newBloon));
newBloon->addComponent<Range>(std::max(surface->w / 6, surface->h / 6));
- newBloon->addComponent<Visibility>(gameData.renderer, surface, SDL_Rect{0, 0, surface->w / 3, 0});
+ newBloon->addComponent<Visibility>(texture, surface, SDL_Rect{0, 0, surface->w / 3, 0});
newBloons.emplace_back(newBloon);
return newBloon;
}
void damageBloon(EntityP &bloon, EntityP &shot, int damage, GameData &gameData, Entities &newBloons) {
if (damage == 0)
return;
auto &lives = bloon->getComponent<Lives>()->value;
if (damage >= lives) {
gameData.cash += getBloonProperty<YIELD>(bloon);
bloon->addComponent<RemoveEntityEvent>();
return;
}
auto &kind = bloon->getComponent<Kind>()->value;
int shotKind = 0;
if (shot)
shotKind = shot->getComponent<Kind>()->value;
float progress = bloon->getComponent<PathIndex>()->progress;
SDL_Surface *surface;
+ SDL_Texture * texture;
auto &visibility = *bloon->getComponent<Visibility>();
if (kind > PINK_BLOON) {
if (kind >= CERAMIC_BLOON and !didBloonPop(bloon, lives, damage, getBloonProperty<MIN_LIVES>(bloon))) {
- surface = gameData.assets[getSurfaceName(bloon)];
- visibility.loadTexture(gameData.renderer, surface);
+ std::tie(texture,surface) = gameData.getTexture(getSurfaceName(bloon));
+ visibility.reloadTexture(texture, surface);
return;
}
if (kind < CERAMIC_BLOON and !didBloonPop(bloon, lives, damage))
return;
}
if (kind > PINK_BLOON) {
gameData.cash += 1;
bloon->addComponent<RemoveEntityEvent>();
}
auto[regrowP, camoP, fortifiedP, gooP] = bloon->getComponentsP<Regrow, Camo, Fortified, Goo>();
switch (kind) {
case RED_BLOON:
lives -= 1;
break;
case BLUE_BLOON:
case GREEN_BLOON:
case YELLOW_BLOON:
case PINK_BLOON: {
lives -= damage;
if (fortifiedP and damage == 1 and lives % 2 == 1)
break;
if (gooP and !gooP->soak)
bloon->removeComponent<Goo>();
gameData.cash += kind - ((fortifiedP ? lives / 2 : lives) - 1);
kind = (fortifiedP ? lives / 2 : lives) - 1;
- surface = gameData.assets[getSurfaceName(bloon)];
+ std::tie(texture,surface) = gameData.getTexture(getSurfaceName(bloon));
visibility.setDstRect(SDL_Rect{0, 0, surface->w / 3, 0});
- visibility.loadTexture(gameData.renderer, surface);
+ visibility.reloadTexture(texture, surface);
if (regrowP)
regrowP->regrowTime = 60;
bloon->getComponent<Range>()->value = std::max(surface->w / 6, surface->h / 6);
break;
}
case PURPLE_BLOON:
case WHITE_BLOON:
case BLACK_BLOON: {
for (int i = 0; i < 2; ++i) {
EntityP newBloon = spawnBloon(newBloons, gameData, PINK_BLOON, shot, lives / 2,
i == 0 ? std::fmaxf(0, progress - 10) : std::fminf(
gameData.path.size() - 1, progress + 10),
regrowP ? regrowP->kind : 0, camoP, false, gooP);
- damageBloon(newBloon, shot,
- shotKind == ENHANCED_BULLET ? damage : (i == 0 ? ceilf(damage / 2.0) : floorf(
- damage / 2.0)), gameData, newBloons);
+ damageBloon(newBloon, shot,damage, gameData, newBloons);
}
break;
}
case ZEBRA_BLOON: {
for (int i = 0; i < 2; ++i) {
EntityP newBloon = spawnBloon(newBloons, gameData, i == 0 ? BLACK_BLOON : WHITE_BLOON, shot, lives / 2,
i == 0 ? std::fmaxf(0, progress - 12) : std::fminf(
gameData.path.size() - 1, progress + 12),
regrowP ? regrowP->kind : 0, camoP, false, gooP);
- damageBloon(newBloon, shot,
- shotKind == ENHANCED_BULLET ? damage : (i == 0 ? ceilf(damage / 2.0) : floorf(
- damage / 2.0)), gameData, newBloons);
+ damageBloon(newBloon, shot,damage, gameData, newBloons);
}
break;
}
case LEAD_BLOON:
case RAINBOW_BLOON:
case CERAMIC_BLOON: {
for (int i = 0; i < 2; ++i) {
EntityP newBloon = spawnBloon(newBloons, gameData, kind - 1, shot, lives / 2,
i == 0 ? std::fmaxf(0, progress - 14) : std::fminf(
gameData.path.size() - 1, progress + 14),
regrowP ? regrowP->kind : 0, camoP, false, gooP);
- damageBloon(newBloon, shot,
- shotKind == ENHANCED_BULLET ? damage : (i == 0 ? ceilf(damage / 2.0) : floorf(
- damage / 2.0)), gameData, newBloons);
+ damageBloon(newBloon, shot, damage, gameData, newBloons);
}
break;
}
case MOAB:
case BFB:
case ZOMG:
case DDT: {
for (int i = 0; i < 4; ++i) {
EntityP newBloon = spawnBloon(newBloons, gameData, kind == DDT ? CERAMIC_BLOON : kind - 1,
shot, lives / 4,
(i < 2 ? std::fmaxf(0, progress - 20 + 10 * (i % 2)) : std::fminf(
gameData.path.size() - 1, progress + 20 - 10 * (i % 2))),
kind == DDT ? CERAMIC_BLOON : 0, kind == DDT, fortifiedP, nullptr);
- damageBloon(newBloon, shot,
- shotKind == ENHANCED_BULLET ? damage : (i == 0 ? ceilf(damage / 4.0) : damage -
- ceilf(damage / 4.0) *
- 3),
- gameData, newBloons);
+ damageBloon(newBloon, shot,damage, gameData, newBloons);
}
break;
}
case BAD: {
for (int i = 0; i < 5; ++i) {
EntityP newBloon(new Entity());
shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
newBloon->addComponent<Type>(BLOON_T);
newBloon->addComponent<Kind>(i < 2 ? ZOMG : DDT);
if (fortifiedP)
newBloon->addComponent<Fortified>();
if (i >= 2)
newBloon->addComponent<Camo>();
newBloon->addComponent<Lives>(getBloonProperty<TOTAL_LIVES>(newBloon));
newBloon->addComponent<Position>(gameData.startingPoint);
newBloon->addComponent<PathIndex>(0);
newBloon->getComponent<PathIndex>()->progress =
i < 2 ? std::fmaxf(0, progress - 20 + 10 * (i % 2)) : std::fminf(
gameData.path.size() - 1, progress + 30 - 10 * (i % 3));
- surface = gameData.assets[getSurfaceName(newBloon)];
+ std::tie(texture,surface) = gameData.getTexture(getSurfaceName(newBloon));
newBloon->addComponent<Range>(std::max(surface->w / 6, surface->h / 6));
- newBloon->addComponent<Visibility>(gameData.renderer, surface, SDL_Rect{0, 0, surface->w / 3, 0});
+ newBloon->addComponent<Visibility>(texture, surface, SDL_Rect{0, 0, surface->w / 3, 0});
newBloons.emplace_back(newBloon);
- damageBloon(newBloon, shot,
- shotKind == ENHANCED_BULLET ? damage : (i == 0 ? ceilf(damage / 5.0) : damage -
- ceilf(damage / 5.0) *
- 4), gameData,
- newBloons);
+ damageBloon(newBloon, shot,damage, gameData, newBloons);
}
break;
}
}
}
void DamageSystem::update(Entities *layers, GameData &gameData) {
if (!gameData.levelRunning)
return;
Entities newBloons;
for (auto &bloon: layers[BLOONS_LAYER]) {
if (auto damageEventP = bloon->getComponent<DamageEvent>()) {
auto &damageEvent = *damageEventP;
auto &lives = bloon->getComponent<Lives>()->value;
if (lives < damageEvent.damage) {
gameData.cash += getBloonProperty<YIELD>(bloon);
bloon->addComponent<RemoveEntityEvent>();
} else {
damageBloon(bloon, damageEvent.shot, damageEvent.damage, gameData, newBloons);
bloon->removeComponent<DamageEvent>();
}
}
}
layers[BLOONS_LAYER] += newBloons;
}
diff --git a/src/systems/EventSystem.cpp b/src/systems/EventSystem.cpp
index c0dcf58..7ddf37e 100644
--- a/src/systems/EventSystem.cpp
+++ b/src/systems/EventSystem.cpp
@@ -1,278 +1,285 @@
//
// Created by Ido Mozes on 08/07/2019.
//
#include "EventSystem.h"
void EventSystem::update(Entities *layers, GameData &gameData) {
SDL_PumpEvents();
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT: {
gameData.isRunning = false;
break;
}
case SDL_MOUSEBUTTONDOWN: {
int mouseX, mouseY, originalMouseX;
SDL_GetMouseState(&mouseX, &mouseY);
mouseX = originalMouseX = int(mouseX / gameData.mapScale);
mouseY = int(mouseY / gameData.mapScale);
bool entityClicked = false;
Entities newEntities[N_LAYERS];
for (int i = N_LAYERS - 1; i >= 0; --i) {
for (auto &entity: layers[i]) {
if (auto components = entity->getComponents<Action, Visibility>()) {
auto[action, visibility] = components.value();
int entityX, entityY, w, h;
SDL_Rect *dstRect = visibility.getDstRect();
entityX = dstRect->x;
entityY = dstRect->y;
w = dstRect->w;
h = dstRect->h;
auto buttonKindP = entity->getComponent<Kind>();
if (action.actionType == CLICK and buttonKindP->value >= UPGRADE_PATH_1 and
buttonKindP->value <= UPGRADE_PATH_3) {
entityX = 4;
entityY = 63 + 135 * (buttonKindP->value - UPGRADE_PATH_1);
w = 138;
h = 81;
}
if (auto positionP = entity->getComponent<Position>()) {
auto &position = *positionP;
entityX = int(position.value.X - w / 2.0);
entityY = int(position.value.Y - h / 2.0);
mouseX = originalMouseX - SIDEBAR_WIDTH;
} else
mouseX = originalMouseX;
if (entityX <= mouseX and mouseX <= entityX + w and entityY <= mouseY and
mouseY <= entityY + h) {
if (action.disabled or (action.actionType != DROP and gameData.isDragging)) {
entityClicked = true;
continue;
}
switch (action.actionType) {
case DRAG: {
auto[type, kind, shotKind, range, attackInterval, pierce, damage, distance, cost, upgrades] =
entity->getComponents<Type, Kind, ShotKind, Range, AttackSpeed, Pierce, Damage, Distance, Cost, Upgrades>().value();
auto draggable = new Entity();
- SDL_Surface *surface = gameData.assets[getSurfaceName(entity)];
- draggable->addComponent<Visibility>(gameData.renderer, surface, SDL_Rect{
+ auto[texture, surface] = gameData.getTexture(getSurfaceName(entity));
+ draggable->addComponent<Visibility>(texture, surface, SDL_Rect{
originalMouseX - int(surface->w / 3.0), mouseY - int(surface->h / 3.0),
int(surface->w / 1.5), int(surface->h / 1.5)});
draggable->addComponent<Draggable>();
draggable->addComponent<Action>(DROP);
draggable->addComponents(type, kind, shotKind, range, attackInterval,
pierce, damage, distance, cost, upgrades);
draggable->addComponent<Strategy>(FIRST);
if (auto spreadP = entity->getComponent<Spread>())
draggable->addComponent<Spread>(*spreadP);
if (auto gooP = entity->getComponent<Goo>())
draggable->addComponent<Goo>(*gooP);
if (entity->getComponent<Camo>())
draggable->addComponent<Camo>();
if (auto shotsAmountP = entity->getComponent<ShotsAmount>())
draggable->addComponent<ShotsAmount>(*shotsAmountP);
EntityP ptr(draggable);
gameData.selected = ptr;
auto rangeShadow = new Entity();
rangeShadow->addComponent<RangeShadow>(ptr);
newEntities[SHADOW_LAYER].emplace_back(rangeShadow);
newEntities[MENU_LAYER].emplace_back(ptr);
gameData.isDragging = true;
goto entityClicked;
}
case CLICK: {
if (entity->getComponent<Visibility>()->hidden)
break;
switch (buttonKindP->value) {
case PLAY_FAST_FORWARD: {
if (gameData.levelRunning)
gameData.FPS = 240 - gameData.FPS;
else
gameData.levelRunning = true;
- visibility.loadTexture(gameData.renderer,
- gameData.assets[std::string("FastForward") +
- (gameData.FPS == 180 ? "Enabled"
- : "")]);
+ auto[texture, surface] = gameData.getTexture(
+ std::string("FastForward") +
+ (gameData.FPS == 180 ? "Enabled" : ""));
+ visibility.reloadTexture(texture,surface);
break;
}
case NEXT_STRATEGY: {
auto &strategy = gameData.selected->getComponent<Strategy>()->value;
strategy = (strategy + 1) % 4;
break;
}
case PREVIOUS_STRATEGY: {
auto &strategy = gameData.selected->getComponent<Strategy>()->value;
strategy -= 1;
if (strategy == -1)
strategy = 3;
break;
}
case UPGRADE_PATH_1:
case UPGRADE_PATH_2:
case UPGRADE_PATH_3: {
auto &upgradeP = *entity->getComponent<UpgradeP>();
auto &upgrades = *gameData.selected->getComponent<Upgrades>();
int cost = upgradeP.value->cost;
if (cost > gameData.cash or upgradeP.value->locked)
break;
else {
gameData.cash -= cost;
gameData.selected->getComponent<Cost>()->value += cost;
}
int currentPath = buttonKindP->value - UPGRADE_PATH_1;
if (upgrades.selectedPathUpgrades[currentPath] ==
upgrades.paths[currentPath].size()) {
upgrades.chosenPath = currentPath;
for (int j = 1; j <= 2; ++j) {
int nextPathIndex = (currentPath + j) % 3;
auto &nextPath = upgrades.paths[nextPathIndex];
if (upgrades.selectedPathUpgrades[nextPathIndex])
nextPath[nextPath.size() -
upgrades.selectedPathUpgrades[nextPathIndex]].locked = true;
}
}
for (auto[kind, value]:upgradeP.value->improvements) {
switch (kind) {
case RANGE_UPGRADE:
gameData.selected->getComponent<Range>()->value *= value;
break;
case SPREAD_UPGRADE:
- gameData.selected->getComponent<Range>()->value *= value;
+ gameData.selected->getComponent<Spread>()->value *= value;
break;
case PIERCE_UPGRADE:
gameData.selected->getComponent<Pierce>()->value += value;
break;
case DAMAGE_UPGRADE:
gameData.selected->getComponent<Damage>()->value += value;
break;
case DISTANCE_UPGRADE:
gameData.selected->getComponent<Distance>()->value *= value;
break;
case ATTACK_SPEED_UPGRADE: {
auto &attackSpeed = *gameData.selected->getComponent<AttackSpeed>();
attackSpeed.interval /= value;
attackSpeed.timeToRecharge = 0;
break;
}
case CAMO_UPGRADE:
gameData.selected->addComponent<Camo>();
break;
+ case ADD_GOO_UPGRADE: {
+ gameData.selected->addComponent<Goo>(value, 60, 60, true);
+ break;
+ }
case GOO_KIND_UPGRADE: {
auto &goo = *gameData.selected->getComponent<Goo>();
goo.kind = value;
goo.ttl = goo.kind == GLUE ? 60 : 120;
break;
}
case GOO_DURATION_UPGRADE: {
auto &goo = *gameData.selected->getComponent<Goo>();
goo.ttl = value;
break;
}
case CORROSIVE_INTERVAL_UPGRADE: {
auto &goo = *gameData.selected->getComponent<Goo>();
goo.interval = value;
goo.timetoRecharge = value;
break;
}
case CORROSIVE_DAMAGE_UPGRADE: {
auto &goo = *gameData.selected->getComponent<Goo>();
goo.damage = value;
break;
}
case GOO_SOAK_UPGRADE: {
auto &goo = *gameData.selected->getComponent<Goo>();
goo.soak = true;
break;
}
- case GOO_STICKNESS_UPGRADE: {
+ case GOO_STICKINESS_UPGRADE: {
auto &goo = *gameData.selected->getComponent<Goo>();
goo.stickness = value;
break;
}
case SHOTS_AMOUNT_UPGRADE:
gameData.selected->addComponent<ShotsAmount>(value);
break;
case SHOT_KIND_UPGRADE:
gameData.selected->getComponent<ShotKind>()->value = value;
break;
+ case MOAB_CLASS_AFFECTING_UPGRADE:
+ gameData.selected->addComponent<MoabClassAffecting>();
+ break;
}
}
auto &path = gameData.selected->getComponent<Upgrades>()->paths[
buttonKindP->value - UPGRADE_PATH_1];
path.erase(path.begin());
break;
}
}
goto entityClicked;
}
case DROP: {
auto &draggable = *entity->getComponent<Draggable>();
if (draggable.isPlaceable) {
entity->removeComponent<Draggable>();
entity->getComponent<Action>()->actionType = SELECT;
gameData.isDragging = false;
if (mouseX > SIDEBAR_WIDTH + MAP_WIDTH or mouseX < SIDEBAR_WIDTH) {
entity->addComponent<RemoveEntityEvent>();
gameData.selected.reset();
} else {
for (int x = std::max(mouseX - SIDEBAR_WIDTH - 20, 0);
x < std::min(mouseX - SIDEBAR_WIDTH + 21, MAP_WIDTH); ++x) {
for (int y = std::max(mouseY - 20, 0);
y < std::min(mouseY + 21, MAP_HEIGHT); ++y) {
if (gameData.mapData[x][y] == FREE)
gameData.mapData[x][y] = TOWER;
}
}
if (i == MENU_LAYER) {
gameData.cash -= entity->getComponent<Cost>()->value;
entity->addComponent<MoveEntityEvent>(TOWERS_LAYER);
auto &visibility = *entity->getComponent<Visibility>();
SDL_Rect *dstRect = entity->getComponent<Visibility>()->getDstRect();
entity->addComponent<Position>(
dstRect->x - SIDEBAR_WIDTH + dstRect->w / 2,
dstRect->y + dstRect->h / 2);
}
}
}
goto entityClicked;
}
case SELECT: {
if (entity == gameData.selected)
goto entityClicked;
gameData.selected = entity;
auto rangeShadow = new Entity();
rangeShadow->addComponent<RangeShadow>(entity);
newEntities[SHADOW_LAYER].emplace_back(rangeShadow);
goto entityClicked;
}
}
}
}
}
}
if (!entityClicked)
gameData.selected.reset();
entityClicked:
for (int i = 0; i < N_LAYERS; ++i) {
if (!newEntities[i].empty())
layers[i] += newEntities[i];
}
break;
}
default:
break;
}
}
}
diff --git a/src/systems/MenuSystem.cpp b/src/systems/MenuSystem.cpp
index 17c44bc..80d57e1 100644
--- a/src/systems/MenuSystem.cpp
+++ b/src/systems/MenuSystem.cpp
@@ -1,65 +1,66 @@
//
// Created by Ido Mozes on 17/07/2019.
//
#include "MenuSystem.h"
void MenuSystem::update(Entities *layers, GameData &gameData) {
for (auto &entity: layers[MENU_LAYER]) {
auto[kindP, actionP] = entity->getComponentsP<Kind, Action>();
if (kindP and (!actionP or (actionP->actionType != DRAG and actionP->actionType != DROP)))
switch (kindP->value) {
case UPGRADES_BACKGROUND:
case NEXT_STRATEGY:
case PREVIOUS_STRATEGY:
case UPGRADE_PATH_1:
case UPGRADE_PATH_2:
case UPGRADE_PATH_3:
entity->getComponent<Visibility>()->hidden = bool(!gameData.selected or gameData.isDragging);
break;
}
if (kindP and actionP and actionP->actionType == CLICK and gameData.selected and !gameData.isDragging) {
switch (kindP->value) {
case UPGRADE_PATH_1:
case UPGRADE_PATH_2:
case UPGRADE_PATH_3: {
auto &upgrades = *gameData.selected->getComponent<Upgrades>();
int path = kindP->value - UPGRADE_PATH_1;
auto &visibility = *entity->getComponent<Visibility>();
auto upgradeP_P = entity->getComponent<UpgradeP>();
if (!upgrades.paths[path].empty()) {
auto &currentUpgrade = upgrades.paths[path][0];
if (!upgradeP_P or upgradeP_P->value != &currentUpgrade or
upgradeP_P->name != currentUpgrade.name or (!actionP->disabled and currentUpgrade.locked)) {
entity->addComponent<UpgradeP>(&currentUpgrade);
- if (currentUpgrade.locked)
- currentUpgrade.surface = gameData.assets[currentUpgrade.surfaceName + "Locked"];
SDL_Surface *surface = currentUpgrade.surface;
visibility.setDstRect(
{75 - surface->w / 34, 143 + 135 * path - surface->h / 17, surface->w / 17, 0});
- visibility.loadTexture(gameData.renderer, surface);
+ visibility.reloadTexture(
+ currentUpgrade.locked ? currentUpgrade.lockedTexture : currentUpgrade.texture,
+ surface);
}
actionP->disabled = currentUpgrade.locked;
visibility.hidden = false;
} else
visibility.hidden = true;
break;
}
}
}
if (auto components = entity->getComponents<Cost, Action, Visibility>()) {
auto[cost, action, visibility] = components.value();
switch (action.actionType) {
case DRAG:
bool disabled = gameData.cash < cost.value;
if (disabled != action.disabled) {
action.disabled = disabled;
- visibility.loadTexture(gameData.renderer,
- gameData.assets[getSurfaceName(entity) + (disabled ? "Disabled" : "")]);
+ auto[texture, surface] = gameData.getTexture(
+ getSurfaceName(entity) + (disabled ? "Disabled" : ""));
+ visibility.reloadTexture(texture, surface);
}
}
}
}
}
diff --git a/src/systems/MovementSystem.cpp b/src/systems/MovementSystem.cpp
index ff04c19..220be71 100644
--- a/src/systems/MovementSystem.cpp
+++ b/src/systems/MovementSystem.cpp
@@ -1,167 +1,168 @@
//
// Created by Ido Mozes on 02/07/2019.
//
#include "MovementSystem.h"
enum Directions {
RIGHT, BOTTOM_RIGHT, BOTTOM, BOTTOM_LEFT, LEFT, TOP_LEFT, TOP, TOP_RIGHT
};
std::tuple<int, int> getDelta(int direction) {
switch (direction) {
case RIGHT:
return std::make_tuple(1, 0);
case BOTTOM_RIGHT:
return std::make_tuple(1, 1);
case BOTTOM:
return std::make_tuple(0, 1);
case BOTTOM_LEFT:
return std::make_tuple(-1, 1);
case LEFT:
return std::make_tuple(-1, 0);
case TOP_LEFT:
return std::make_tuple(-1, -1);
case TOP:
return std::make_tuple(0, -1);
case TOP_RIGHT:
return std::make_tuple(1, -1);
default:
return std::make_tuple(0, 0);
}
}
void MovementSystem::update(Entities *layers, GameData &gameData) {
for (int i = 0; i < N_LAYERS; ++i) {
for (auto &entity: layers[i]) {
// Move all entities with Visibility and Position
if (auto components = entity->getComponents<Visibility, Position>()) {
auto[visibility, position]=components.value();
float deltaX = 0, deltaY = 0;
auto pathIndexP = entity->getComponent<PathIndex>();
if (auto velocityP = entity->getComponent<Velocity>()) {
auto &velocity = *velocityP;
if (auto accelerationP = entity->getComponent<Acceleration>()) {
auto &acceleration = *accelerationP;
velocity.changeVelocity(acceleration.value.X, acceleration.value.Y);
}
deltaX = velocity.value.X;
deltaY = velocity.value.Y;
if (auto distanceP = entity->getComponent<Distance>()) {
auto &distance = distanceP->value;
auto[alpha, R] = cartesianToPolar(deltaX, deltaY);
if (distance == 0) {
entity->addComponent<RemoveEntityEvent>();
} else if (distance >= R) {
distance -= R;
} else {
std::tie(deltaX, deltaY) = polarToCartesian(alpha, distance);
distance = 0;
}
}
} else if (pathIndexP) {
if (auto regrowP = entity->getComponent<Regrow>()) {
auto[lives, kind] = entity->getComponents<Lives, Kind>().value();
regrowP->regrowTime -= 1;
if (regrowP->regrowTime == 0 and kind.value < regrowP->kind) {
switch (kind.value) {
case RED_BLOON:
case BLUE_BLOON:
case GREEN_BLOON:
case YELLOW_BLOON:
kind.value += 1;
break;
case PINK_BLOON: {
switch (regrowP->kind) {
case PURPLE_BLOON:
case BLACK_BLOON:
case WHITE_BLOON:
kind.value = regrowP->kind;
break;
case LEAD_BLOON:
case ZEBRA_BLOON:
case RAINBOW_BLOON:
case CERAMIC_BLOON:
kind.value = BLACK_BLOON;
break;
}
break;
}
case BLACK_BLOON:
if (regrowP->kind == LEAD_BLOON)
kind.value = LEAD_BLOON;
else
kind.value = ZEBRA_BLOON;
break;
case WHITE_BLOON:
kind.value = ZEBRA_BLOON;
case ZEBRA_BLOON:
case RAINBOW_BLOON:
kind.value += 1;
break;
}
lives.value = getBloonProperty<TOTAL_LIVES>(entity);
- SDL_Surface *surface = gameData.assets[getSurfaceName(entity)];
+
+ auto[texture,surface] = gameData.getTexture(getSurfaceName(entity));
visibility.setDstRect(SDL_Rect{0, 0, surface->w / 3, 0});
- visibility.loadTexture(gameData.renderer, surface);
+ visibility.reloadTexture(texture, surface);
entity->getComponent<Range>()->value = std::max(surface->w / 6, surface->h / 6);
regrowP->regrowTime = 60;
}
}
auto &pathIndex = *pathIndexP;
float speed = getSpeed(entity);
if (auto gooP = entity->getComponent<Goo>()) {
if (gooP->kind == CORROSIVE and --gooP->timetoRecharge == 0){
entity->addComponent<DamageEvent>(gooP->damage, EntityP(nullptr));
gooP->timetoRecharge = gooP->interval;
}
gooP->ttl -= 1;
if (gooP->ttl == 0) {
entity->removeComponent<Goo>();
- SDL_Surface *surface = gameData.assets[getSurfaceName(entity)];
+ auto[texture,surface] = gameData.getTexture(getSurfaceName(entity));
auto &visibility = *entity->getComponent<Visibility>();
visibility.setDstRect(SDL_Rect{0, 0, surface->w / 3, 0});
- visibility.loadTexture(gameData.renderer, surface);
+ visibility.reloadTexture(texture, surface);
}
}
pathIndex.progress += speed;
float deltaIndex = pathIndex.progress - pathIndex.index;
if (entity->getComponent<Kind>()->value >= MOAB) {
float angle = 0;
Point tempPosition = position.value;
for (int j = std::max(0, pathIndex.index - 10);
j < std::min(pathIndex.index + 10, int(gameData.path.size() - 1)); ++j) {
auto[tempDeltaX, tempDeltaY] = getDelta(gameData.path[j]);
tempPosition.X += tempDeltaX;
tempPosition.Y += tempDeltaY;
}
angle = radToDeg(twoPointsAngle(position.value, tempPosition));
visibility.angle = angle;
}
while (deltaIndex >= (gameData.path[pathIndex.index] % 2 == 0 ? 1 : sqrt(2))) {
auto[tempDeltaX, tempDeltaY] = getDelta(gameData.path[pathIndex.index]);
deltaX += tempDeltaX;
deltaY += tempDeltaY;
deltaIndex -= (gameData.path[pathIndex.index] % 2 == 0 ? 1 : sqrt(2));
if (pathIndex.index < gameData.path.size() - 1)
pathIndex.index++;
}
}
position.changePosition(deltaX, deltaY);
if (position.value.X > MAP_WIDTH or position.value.X < 0 or position.value.Y > MAP_HEIGHT or
position.value.Y < 0) {
if (pathIndexP) {
gameData.lives -= entity->getComponent<Lives>()->value;
if (gameData.lives <= 0) {
gameData.lost = true;
gameData.lives = 0;
}
}
entity->addComponent<RemoveEntityEvent>();
}
}
}
}
}
diff --git a/src/systems/PopEffectSystem.cpp b/src/systems/PopEffectSystem.cpp
index 92e9cd9..35bb5dc 100644
--- a/src/systems/PopEffectSystem.cpp
+++ b/src/systems/PopEffectSystem.cpp
@@ -1,30 +1,30 @@
//
// Created by Ido Mozes on 22/07/2019.
//
#include "PopEffectSystem.h"
const int range_from = 0;
const int range_to = 360;
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<int> distr(range_from, range_to);
void PopEffectSystem::update(Entities *layers, GameData &gameData) {
layers[POP_LAYER].clear();
for (auto &bloon: layers[BLOONS_LAYER]) {
if(bloon->getComponent<RemoveEntityEvent>() and bloon->getComponent<Seen>()){
auto &position = bloon->getComponent<Position>()->value;
if(position.X <0 or position.X >= MAP_WIDTH or position.Y <0 or position.Y >= MAP_HEIGHT)
continue;
auto pop = new Entity();
pop->addComponent<Position>(position);
- SDL_Surface *surface = gameData.assets["Pop"];
- pop->addComponent<Visibility>(gameData.renderer,surface,SDL_Rect{0,0,int(surface->w/1.5)},distr(generator));
+ auto [texture,surface] = gameData.getTexture("Pop");
+ pop->addComponent<Visibility>(texture,surface,SDL_Rect{0,0,int(surface->w/1.5)},distr(generator));
layers[POP_LAYER].emplace_back(pop);
}
else
bloon->addComponent<Seen>();
}
}
diff --git a/src/systems/RemoveEntitiesSystem.cpp b/src/systems/RemoveEntitiesSystem.cpp
index 6ea5f2a..2ec251a 100644
--- a/src/systems/RemoveEntitiesSystem.cpp
+++ b/src/systems/RemoveEntitiesSystem.cpp
@@ -1,29 +1,30 @@
//
// Created by Ido Mozes on 10/07/2019.
//
#include "RemoveEntitiesSystem.h"
void RemoveEntitiesSystem::update(Entities *layers, GameData &gameData) {
for (int i = 0; i < N_LAYERS; ++i) {
layers[i].erase(
std::remove_if(layers[i].begin(), layers[i].end(), [&layers, &gameData](auto &entity) {
if (auto moveEntityEventP = entity->template getComponent<MoveEntityEvent>()) {
int newLayer = moveEntityEventP->toLayer;
entity->template removeComponent<MoveEntityEvent>();
layers[newLayer].emplace_back(std::move(entity));
}
if (entity and entity->template getComponent<RangeShadow>() and
entity->template getComponent<RangeShadow>()->entity != gameData.selected)
return true;
return !entity or entity->template getComponent<RemoveEntityEvent>();
}),
layers[i].end());
}
if (layers[SEQUENCES_LAYER].empty() and layers[BLOONS_LAYER].empty()) {
gameData.levelReady = gameData.levelRunning = false;
if (gameData.level <= gameData.finalLevel)
gameData.level += 1;
- gameData.playButton->getComponent<Visibility>()->loadTexture(gameData.renderer, gameData.assets["Play"]);
+ auto [texture,surface] = gameData.getTexture("Play");
+ gameData.playButton->getComponent<Visibility>()->reloadTexture(texture,surface);
}
}
\ No newline at end of file
diff --git a/src/systems/ShotsSpawnSystem.cpp b/src/systems/ShotsSpawnSystem.cpp
index 79d20bd..5c11cff 100644
--- a/src/systems/ShotsSpawnSystem.cpp
+++ b/src/systems/ShotsSpawnSystem.cpp
@@ -1,191 +1,201 @@
//
// Created by Ido Mozes on 11/07/2019.
//
#include "ShotsSpawnSystem.h"
void ShotsSpawnSystem::update(Entities *layers, GameData &gameData) {
if (!gameData.levelRunning)
return;
for (auto &entity: layers[TOWERS_LAYER]) {
auto[kind, shotKind, towerRange, towerPosition, strategy, attackSpeed, pierce, damage, distance, visibility] =
entity->getComponents<Kind, ShotKind, Range, Position, Strategy, AttackSpeed, Pierce, Damage, Distance, Visibility>().value();
auto camoP = entity->getComponent<Camo>();
float minDistance = MAP_HEIGHT + MAP_WIDTH;
float minProgress = gameData.path.size();
float maxProgress = -1;
float maxLives = -1;
Entity *closestBloon = nullptr, *firstBloon = nullptr, *lastBloon = nullptr, *strongestBloon = nullptr;
for (auto &gameEntity: layers[BLOONS_LAYER]) {
if (gameEntity->getComponent<Camo>() and !camoP)
continue;
float distance;
if (gameEntity->getComponent<Type>()->value == BLOON_T) {
auto[bloonRange, bloonPosition, pathIndex, lives] = gameEntity->getComponents<Range, Position, PathIndex, Lives>().value();
distance =
twoPointsDistance(bloonPosition.value, towerPosition.value) - bloonRange.value;
if (distance > towerRange.value)
continue;
if (distance < minDistance) {
minDistance = distance;
closestBloon = gameEntity.get();
}
if (pathIndex.progress < minProgress) {
minProgress = pathIndex.progress;
lastBloon = gameEntity.get();
}
if (lives.value > maxLives or (lives.value == maxLives and pathIndex.progress > maxProgress)) {
maxLives = lives.value;
strongestBloon = gameEntity.get();
}
if (pathIndex.progress > maxProgress) {
maxProgress = pathIndex.progress;
firstBloon = gameEntity.get();
}
}
}
if (closestBloon or firstBloon or lastBloon or strongestBloon) {
Entity *target;
switch (strategy.value) {
case CLOSEST:
target = closestBloon;
break;
case FIRST:
target = firstBloon;
break;
case LAST:
target = lastBloon;
break;
case STRONGEST:
target = strongestBloon;
break;
}
int amount = attackSpeed.getAmountReady();
float angle = twoPointsAngle(towerPosition.value, target->getComponent<Position>()->value);
for (int i = 0; i < amount; ++i) {
switch (shotKind.value) {
case BOMB:
+ case ENHANCED_BOMB:
+ case MISSILE:
+ case MOAB_MAULER:
+ case MOAB_ASSASSIN:
+ case MOAB_ELIMINATOR:
case GOO_SHOT:
case LASER:
case PLASMA:
case SUN:
case SPIKE:
case JUGGERNAUT:
case DART: {
int shotsAmount = 1;
auto shotsAmountP = entity->getComponent<ShotsAmount>();
float shotAngle = angle;
float deltaAngle = 10;
if (shotsAmountP) {
shotsAmount = shotsAmountP->value;
shotAngle -= degToRad((deltaAngle * (shotsAmount - 1)) / 2.0);
deltaAngle = degToRad(deltaAngle);
}
for (int j = 0; j < shotsAmount; ++j) {
EntityP shot(new Entity());
shot->addComponent<Position>(towerPosition.value.X, towerPosition.value.Y);
shot->addComponent<Type>(SHOT_T);
shot->addComponent<Kind>(shotKind.value);
auto[velocityX, velocityY] = polarToCartesian(shotAngle, getSpeed(shot));
shot->addComponent<Velocity>(velocityX, velocityY);
shot->addComponent<Range>(5);
- if (shotKind.value == BOMB or shotKind.value == GOO_SHOT) {
- shot->addComponent<Spread>(*entity->getComponent<Spread>());
+ if (auto spreadP = entity->getComponent<Spread>()) {
+ shot->addComponent<Spread>(*spreadP);
if (auto gooP = entity->getComponent<Goo>())
shot->addComponent<Goo>(*gooP);
}
shot->addComponents(pierce, damage, distance);
if (camoP)
shot->addComponent<Camo>();
shot->addComponent<PoppedBloons>();
- SDL_Surface *surface = gameData.assets[getSurfaceName(shot)];
- int scale = 1;
+ auto[texture,surface] = gameData.getTexture(getSurfaceName(shot));
+ float scale = 1;
switch (shotKind.value) {
+ case MISSILE:
+ scale = 1.5;
+ break;
case DART:
+ case MOAB_MAULER:
+ case MOAB_ASSASSIN:
+ case MOAB_ELIMINATOR:
scale = 2;
break;
case BOMB:
- scale = 4;
- break;
+ case ENHANCED_BOMB:
case SPIKE:
case JUGGERNAUT:
scale = 4;
break;
case LASER:
scale = 10;
break;
case PLASMA:
case SUN:
scale = 6;
break;
}
- shot->addComponent<Visibility>(gameData.renderer, surface,
- SDL_Rect{0, 0, surface->w / scale},
+ shot->addComponent<Visibility>(texture, surface,
+ SDL_Rect{0, 0, int(surface->w / scale)},
radToDeg(shotAngle));
layers[SHOTS_LAYER].emplace_back(shot);
shotAngle += deltaAngle;
}
break;
}
case BULLET:
case ENHANCED_BULLET: {
if (shotKind.value == BULLET and target->getComponent<Kind>()->value == LEAD_BLOON)
break;
EntityP shot(new Entity());
shot->addComponent<PoppedBloons>();
shot->addComponent<Kind>(shotKind.value);
target->addComponent<DamageEvent>(
target->getComponent<Camo>() ? damage.value * 2 : damage.value, shot);
break;
}
case TACK:
case HOT_TACK:
case BLADE:
case ENHANCED_TACK: {
int shotsAmount = entity->getComponent<ShotsAmount>()->value;
for (int j = 0; j < shotsAmount; ++j) {
EntityP shot(new Entity());
shot->addComponent<Type>(SHOT_T);
shot->addComponent<Kind>(shotKind.value);
angle = (2 * M_PI / shotsAmount) * j;
auto[velocityX, velocityY] = polarToCartesian(angle, getSpeed(shot));
shot->addComponent<Velocity>(velocityX, velocityY);
auto[deltaX, deltaY] = polarToCartesian(angle, 10);
shot->addComponent<Position>(towerPosition.value.X + deltaX,
towerPosition.value.Y + deltaY);
shot->addComponent<Range>(5);
shot->addComponents(pierce, damage, distance);
shot->addComponent<PoppedBloons>();
- SDL_Surface *surface = gameData.assets[getSurfaceName(shot)];
+ auto [texture,surface] = gameData.getTexture(getSurfaceName(shot));
int scale = 1;
switch (shotKind.value) {
case TACK:
case HOT_TACK:
case ENHANCED_TACK:
scale = 5;
break;
case BLADE:
scale = 4;
break;
}
- shot->addComponent<Visibility>(gameData.renderer, surface,
+ shot->addComponent<Visibility>(texture, surface,
SDL_Rect{0, 0, surface->w / scale},
radToDeg(angle));
layers[SHOTS_LAYER].emplace_back(shot);
}
break;
}
}
}
if (shotKind.value != TACK and shotKind.value != ENHANCED_TACK and shotKind.value != BLADE and
shotKind.value != HOT_TACK)
visibility.angle = radToDeg(angle) + 90;
} else
attackSpeed.recharge();
}
}
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Fri, Sep 12, 7:03 AM (22 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
42846
Default Alt Text
(141 KB)

Event Timeline