Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F86340
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
141 KB
Referenced Files
None
Subscribers
None
View Options
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 ¤tUpgrade = upgrades.paths[path][0];
if (!upgradeP_P or upgradeP_P->value != ¤tUpgrade or
upgradeP_P->name != currentUpgrade.name or (!actionP->disabled and currentUpgrade.locked)) {
entity->addComponent<UpgradeP>(¤tUpgrade);
- 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
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Sep 12, 7:03 AM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
42846
Default Alt Text
(141 KB)
Attached To
Mode
R74 BloonsTD
Attached
Detach File
Event Timeline
Log In to Comment