Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
99 KB
Referenced Files
None
Subscribers
None
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d1baa6c..67f04dc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.14)
project(SDL_Game)
set(CMAKE_CXX_STANDARD 17)
include_directories(include)
find_package(Boost REQUIRED COMPONENTS filesystem)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(lib)
link_libraries(mingw32 SDL2main SDL2 SDL2_image SDL2_gfx)
-add_executable(SDL_Game src/main.cpp src/Game.cpp src/Game.h src/Entity.h src/Component.h src/System.h src/systems/RenderSystem.cpp src/systems/RenderSystem.h src/components/Visibility.cpp src/components/Visibility.h src/components/Velocity.cpp src/components/Velocity.h src/systems/MovementSystem.cpp src/systems/MovementSystem.h src/components/Position.h src/components/PathIndex.h src/GameData.h src/components/Speed.h src/components/Sequence.cpp src/components/Sequence.h src/components/Kind.h src/systems/BloonsSpawnSystem.cpp src/systems/BloonsSpawnSystem.h src/GameData.cpp src/components/Action.h src/systems/EventSystem.cpp src/systems/EventSystem.h src/components/Draggable.h src/systems/DraggingSystem.cpp src/systems/DraggingSystem.h src/Settings.h src/components/Type.h src/systems/RemoveEntitiesSystem.cpp src/systems/RemoveEntitiesSystem.h src/eventComponents/RemoveEntityEvent.h src/eventComponents/MoveEntityEvent.h src/components/Range.h src/components/RangeShadow.h src/Physics.cpp src/Physics.h src/components/Strategy.h src/systems/CollisionSystem.cpp src/systems/CollisionSystem.h src/systems/ShotsSpawnSystem.cpp src/systems/ShotsSpawnSystem.h)
+add_executable(SDL_Game src/main.cpp src/Game.cpp src/Game.h src/Entity.h src/Component.h src/System.h src/systems/RenderSystem.cpp src/systems/RenderSystem.h src/components/Visibility.cpp src/components/Visibility.h src/components/Velocity.cpp src/components/Velocity.h src/systems/MovementSystem.cpp src/systems/MovementSystem.h src/components/Position.h src/components/PathIndex.h src/GameData.h src/components/Sequence.cpp src/components/Sequence.h src/systems/BloonsSpawnSystem.cpp src/systems/BloonsSpawnSystem.h src/GameData.cpp src/components/Action.h src/systems/EventSystem.cpp src/systems/EventSystem.h src/components/Draggable.h src/systems/DraggingSystem.cpp src/systems/DraggingSystem.h src/Settings.h src/systems/RemoveEntitiesSystem.cpp src/systems/RemoveEntitiesSystem.h src/components/MoveEntityEvent.h src/components/RangeShadow.h src/Physics.cpp src/Physics.h src/systems/CollisionSystem.cpp src/systems/CollisionSystem.h src/systems/ShotsSpawnSystem.cpp src/systems/ShotsSpawnSystem.h src/components/IntegerComponents.h src/components/FloatComponents.h src/components/AttackSpeed.h src/components/AttackSpeed.cpp src/components/PoppedBloons.h src/systems/DamageSystem.cpp src/systems/DamageSystem.h src/components/FlagComponents.h src/System.cpp src/Entity.cpp src/components/DamageEvent.h)
target_link_libraries(SDL_Game ${Boost_LIBRARIES})
\ No newline at end of file
diff --git a/scripts/convert_maps.py b/scripts/convert_maps.py
index 4ddd8c7..6594370 100644
--- a/scripts/convert_maps.py
+++ b/scripts/convert_maps.py
@@ -1,83 +1,80 @@
from PIL import Image
from sys import argv
from struct import pack
-arrows = ['→', '↘', '↓', '↙', '←', '↖', '↑', '↗']
# obstacles
image = Image.open(argv[1] + "_obstacles.bmp")
width, height = image.size
obstacles = b''
byte = 0
i = 0
for y in range(height):
for x in range(width):
pixel = image.getpixel((x, y))
byte |= (2 ** (i % 8)) * (pixel == (0, 0, 0))
- print(i,pixel,byte)
- _=input()
if i % 8 == 7:
obstacles += bytes([byte])
byte = 0
i += 1
if i % 8 != 7:
obstacles += bytes([byte])
with open(argv[1] + "_obstacles.data", 'wb') as file:
file.write(obstacles)
# path
image = Image.open(argv[1] + "_path.bmp")
width, height = image.size
instructions = b''
i = 0
for i, pixel in enumerate(image.getdata()):
if pixel == (255, 0, 0):
break
start_loc_x = x = i % width
start_loc_y = y = i // width
prev_x = prev_y = next_x = next_y = 0
pixels = image.load()
pixel = pixels[x, y]
length = 0
prev_locations = [(x, y)]
directions = ((1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1))
while pixel != (255, 255, 0):
length += 1
possible_locations = [(pixels[x + delta_x, y + delta_y], x + delta_x, y + delta_y, mask) for
mask, (delta_x, delta_y) in
enumerate(directions) if (0 <= x + delta_x < width) and (0 <= y + delta_y < height) and not (
x + delta_x == prev_x and y + delta_y == prev_y) and pixels[x + delta_x, y + delta_y] != (
255, 255, 255)]
if len(possible_locations) == 1:
pixel, next_x, next_y, mask = possible_locations[0]
else:
special_locations = sorted([loc for loc in possible_locations if loc[0][2] == 255])
if len(special_locations) > 0:
pixel, next_x, next_y, mask = special_locations[0]
ttl = pixel[1] - 1
pixels[next_x, next_y] = (pixel[0] if ttl else 0, ttl, 255 if ttl else 0)
else:
new_locations = [loc for loc in possible_locations if (loc[1], loc[2]) not in prev_locations]
if len(new_locations) > 0:
pixel, next_x, next_y, mask = new_locations[0]
else:
old_locations = sorted((prev_locations.index((loc[1], loc[2])), loc) for loc in possible_locations if
(loc[1], loc[2]) in prev_locations)[::-1]
pixel, next_x, next_y, mask = old_locations[0][1]
if (next_x, next_y) in prev_locations:
prev_locations.remove((next_x, next_y))
prev_locations.append((next_x, next_y))
instructions += bytes([mask])
prev_x = x
prev_y = y
x = next_x
y = next_y
with open(argv[1] + "_path.data", 'wb') as file:
file.write(pack('<H', start_loc_x))
file.write(pack('<H', start_loc_y))
file.write(pack('<I', length))
file.write(instructions)
file.write(pack('<H', x))
file.write(pack('<H', y))
diff --git a/src/Component.h b/src/Component.h
index 3b58b8d..d41bb4d 100644
--- a/src/Component.h
+++ b/src/Component.h
@@ -1,29 +1,65 @@
//
// 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, ACCELERATION, PATH_INDEX, HEALTH, KIND, TYPE,RANGE, DAMAGE, PIERCE, SPREAD, SEQUENCE, ACTION, DRAGGABLE,RANGE_SHADOW,STRATEGY,
- MOVE_ENTITY_EVENT, REMOVE_ENTITY_EVENT,
- LENGTH
+ VISIBILITY,
+ POSITION,
+ VELOCITY,
+ SPEED,
+ ATTACK_SPEED,
+ ACCELERATION,
+ PATH_INDEX,
+ LIVES,
+ KIND,
+ SHOT_KIND,
+ TYPE,
+ RANGE,
+ DAMAGE,
+ PIERCE,
+ SPREAD,
+ DISTANCE,
+ SEQUENCE,
+ ACTION,
+ DRAGGABLE,
+ RANGE_SHADOW,
+ STRATEGY,
+ REGROW,
+ CAMO,
+ FORTIFIED,
+ GLUE,
+ GUM,
+ CORROSIVE,
+ COST,
+ VALUE,
+ POPPED_BLOONS,
+ MOVE_ENTITY_EVENT,
+ REMOVE_ENTITY_EVENT,
+ DAMAGE_EVENT,
+
+ LENGTH
};
class Component {
public:
- Component() = default;
+ Component() = default;
virtual ~Component() = default;
};
#endif //SDL2_GAME_COMPONENT_H
diff --git a/src/Entity.cpp b/src/Entity.cpp
new file mode 100644
index 0000000..ae5b11c
--- /dev/null
+++ b/src/Entity.cpp
@@ -0,0 +1,5 @@
+//
+// Created by Ido Mozes on 16/07/2019.
+//
+#include "Entity.h"
+
diff --git a/src/Entity.h b/src/Entity.h
index 15a04ac..b8102f1 100644
--- a/src/Entity.h
+++ b/src/Entity.h
@@ -1,60 +1,75 @@
//
// Created by Ido Mozes on 20/06/2019.
//
#ifndef SDL2_GAME_ENTITY_H
#define SDL2_GAME_ENTITY_H
#include <bitset>
#include <vector>
#include <cmath>
#include <memory>
#include <optional>
#include "Component.h"
constexpr uint64_t createMask(std::initializer_list<int> types) noexcept {
uint64_t mask = 0;
for (int bit : types) {
mask |= (uint64_t) pow(2, bit);
}
return mask;
}
class Entity {
std::bitset<ComponentType::LENGTH> componentsMask;
std::unique_ptr<Component> components[ComponentType::LENGTH];
public:
template<class ... T>
std::optional<std::tuple<T &...>> getComponents() {
constexpr uint64_t mask = createMask({T::type...});
if ((componentsMask.to_ullong() & mask) == mask) {
return std::tuple<T &...>((*(T *) components[T::type].get())...);
}
return std::nullopt;
}
+ template<class ... T>
+ std::tuple<T *...> getComponentsP() {
+ return std::tuple<T *...>(((T *) components[T::type].get())...);
+ }
+
template<class T>
T *getComponent() {
if (auto &c = components[T::type])
return (T *) c.get();
return nullptr;
}
+ template<typename ... Targs>
+ void addComponents(Targs &... args) {
+ std::initializer_list<std::tuple<ComponentType, Component *>> newComponents{
+ std::make_tuple(Targs::type, new Targs(args))...};
+ for (auto[t, p] :newComponents) {
+ componentsMask[t] = true;
+ components[t] = std::move(std::unique_ptr<Component>(p));
+ }
+ }
+
template<typename T, typename ... Targs>
Component &addComponent(Targs &&... args) {
T *c = new T(std::forward<Targs>(args)...);
components[T::type] = std::move(std::unique_ptr<Component>(c));
componentsMask[T::type] = true;
return *c;
}
template<typename T>
void removeComponent() {
components[T::type].reset(nullptr);
componentsMask[T::type] = false;
}
};
#endif //SDL2_GAME_ENTITY_H
diff --git a/src/Game.cpp b/src/Game.cpp
index 23c2f12..254a428 100644
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -1,144 +1,160 @@
//
// 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());
}
gameData.assets["map"] = IMG_Load("../assets/map0.jpg");
gameData.assets["upgrade_bar"] = IMG_Load("../assets/upgrade_bar.jpg");
gameData.assets["upgrade_bar2"] = IMG_Load("../assets/upgrade_bar2.jpg");
gameData.assets["menu"] = IMG_Load("../assets/menu.jpg");
renderSystem = new RenderSystem();
renderSystem->init(gameData);
loadMap();
std::initializer_list<std::pair<std::string, Point>> sprites[]{
{{"map", {SIDEBAR_WIDTH, 0}}},
{},
{},
{},
{},
{},
{{"upgrade_bar", {0, 0}}, {"menu", {MAP_WIDTH + SIDEBAR_WIDTH, 0}}},
};
for (int i = 0; i < N_LAYERS; i++) {
for (auto &sprite :sprites[i]) {
auto spriteEntity = new Entity();
spriteEntity->addComponent<Visibility>(gameData.renderer, gameData.assets[sprite.first],
SDL_Rect{int(sprite.second.X), int(sprite.second.Y),
gameData.assets[sprite.first]->w,
gameData.assets[sprite.first]->h});
layers[i].emplace_back(spriteEntity);
}
}
+
+
+ // Towers
auto tower = new Entity();
- tower->addComponent<Kind>("Super_Monkey");
- tower->addComponent<Visibility>(gameData.renderer, gameData.assets["Super_Monkey"],
- SDL_Rect{SIDEBAR_WIDTH + MAP_WIDTH + 10, 10,
- int(gameData.assets["Super_Monkey"]->w / 1.5), 0});
+ tower->addComponent<Kind>(SUPER_MONKEY);
+ tower->addComponent<ShotKind>(DART);
+ SDL_Surface *surface = gameData.assets["SuperMonkey"];
+ tower->addComponent<Visibility>(gameData.renderer, surface,
+ SDL_Rect{SIDEBAR_WIDTH + MAP_WIDTH + 10, 10, int(surface->w / 1.5), 0});
tower->addComponent<Action>(DRAG);
tower->addComponent<Range>(100);
+ tower->addComponent<AttackSpeed>(30);
+ tower->addComponent<Pierce>(4);
+ tower->addComponent<Damage>(21);
+ tower->addComponent<Distance>(150);
+ tower->addComponent<Type>(TOWER_T);
layers[MENU_LAYER].emplace_back(tower);
+
tower = new Entity();
- tower->addComponent<Kind>("Sniper_Monkey");
- tower->addComponent<Visibility>(gameData.renderer, gameData.assets["Sniper_Monkey"],
- SDL_Rect{SIDEBAR_WIDTH + MAP_WIDTH + 100, 10,
- int(gameData.assets["Sniper_Monkey"]->w / 1.5), 0});
+ tower->addComponent<Kind>(SNIPER_MONKEY);
+ tower->addComponent<ShotKind>(DART);
+ surface = gameData.assets["SniperMonkey"];
+ tower->addComponent<Visibility>(gameData.renderer, surface,
+ SDL_Rect{SIDEBAR_WIDTH + MAP_WIDTH + 100, 10, int(surface->w / 1.5), 0});
tower->addComponent<Action>(DRAG);
- tower->addComponent<Range>(30);
+ tower->addComponent<Range>(100);
+ tower->addComponent<AttackSpeed>(6);
+ tower->addComponent<Pierce>(5);
+ tower->addComponent<Damage>(1);
+ tower->addComponent<Distance>(300);
+ tower->addComponent<Type>(TOWER_T);
layers[MENU_LAYER].emplace_back(tower);
+
+
+ // Sequences
auto s = new Entity();
- s->addComponent<Sequence>(100, 10, 0);
- s->addComponent<Kind>(std::string("Ceramic"));
+ s->addComponent<Sequence>(1, 1, 0);
+ s->addComponent<Kind>(BAD);
s->addComponent<Type>(SEQUENCE_T);
- s->addComponent<Speed>(3.5);
- layers[SEQUENCES_LAYER].emplace_back(s);
- s = new Entity();
- s->addComponent<Sequence>(100, 10, 60 * 5);
- s->addComponent<Kind>(std::string("Blue"));
- s->addComponent<Type>(SEQUENCE_T);
- s->addComponent<Speed>(1.5);
- layers[SEQUENCES_LAYER].emplace_back(s);
- s = new Entity();
- s->addComponent<Sequence>(1000, 0.5);
- s->addComponent<Kind>(std::string("Pink"));
- s->addComponent<Type>(SEQUENCE_T);
- s->addComponent<Speed>(4.5);
layers[SEQUENCES_LAYER].emplace_back(s);
+// s = new Entity();
+// s->addComponent<Sequence>(100, 20.2, 60 * 5);
+// s->addComponent<Kind>(std::string("Blue"));
+// s->addComponent<Type>(SEQUENCE_T);
+// s->addComponent<Speed>(1.5);
+// layers[SEQUENCES_LAYER].emplace_back(s);
+
+
+ // Systems
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 MovementSystem);
systems.emplace_back(new RemoveEntitiesSystem);
systems.emplace_back(renderSystem);
}
Game::~Game() {
SDL_Quit();
}
void Game::update() {
for (auto &system : systems) {
system->update(layers, 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/Game.h b/src/Game.h
index 9f2a5b7..706aa4e 100644
--- a/src/Game.h
+++ b/src/Game.h
@@ -1,49 +1,50 @@
//
// Created by Ido Mozes on 18/06/2019.
//
#ifndef SDL2_GAME_GAME_H
#define SDL2_GAME_GAME_H
#include <iostream>
#include <cmath>
#include <fstream>
#include <memory>
#include <vector>
#include "SDL.h"
#include "SDL_image.h"
#include <comdef.h>
#include "Entity.h"
#include "System.h"
#include "systems/RenderSystem.h"
#include "systems/MovementSystem.h"
#include "systems/EventSystem.h"
#include "systems/BloonsSpawnSystem.h"
#include "systems/ShotsSpawnSystem.h"
#include "systems/DraggingSystem.h"
#include "systems/RemoveEntitiesSystem.h"
#include "systems/CollisionSystem.h"
+#include "systems/DamageSystem.h"
#include "GameData.h"
#include "boost/filesystem.hpp"
#include <iostream>
struct TempPoint{short X;short Y;};
class Game {
std::vector<std::unique_ptr<System>> systems;
Entities layers[N_LAYERS];
RenderSystem * renderSystem;
GameData gameData;
public:
explicit Game(bool fullscreen, float mapScale=1.5);
~Game();
void update();
bool running() { return gameData.isRunning; }
void loadMap();
};
#endif //SDL2_GAME_GAME_H
diff --git a/src/GameData.h b/src/GameData.h
index 0d55ec8..77dcacc 100644
--- a/src/GameData.h
+++ b/src/GameData.h
@@ -1,39 +1,39 @@
//
// 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"
constexpr char FREE = 0;
constexpr char OBSTACLE = 1;
constexpr char TOWER = 2;
-constexpr char BLOON = 3;
class GameData {
public:
bool isRunning = true;
bool isDragging = false;
int level = 0;
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;
SDL_Window *window = nullptr;
SDL_Renderer *renderer = nullptr;
- std::shared_ptr<Entity> selected;
+ EntityP selected;
~GameData();
};
#endif //SDL_GAME_GAMEDATA_H
diff --git a/src/Physics.h b/src/Physics.h
index ee4633a..a356ecc 100644
--- a/src/Physics.h
+++ b/src/Physics.h
@@ -1,35 +1,35 @@
//
// Created by Ido Mozes on 11/07/2019.
//
#ifndef SDL_GAME_PHYSICS_H
#define SDL_GAME_PHYSICS_H
#include <tuple>
#include <cmath>
#include "Component.h"
inline std::tuple<float, float> cartesianToPolar(float X, float Y) {
float alpha = atan2f(Y, X);
- float R = X / sinf(alpha);
+ float R = sqrtf(powf(X, 2) + powf(Y, 2));
return std::make_tuple(alpha, R);
}
inline std::tuple<float, float> polarToCartesian(float alpha, float R) {
return std::make_tuple(R * cosf(alpha), R * sinf(alpha));
}
inline float twoPointsDistance(Point point1, Point point2) {
return sqrtf(powf(point1.X - point2.X, 2) +
powf(point1.Y - point2.Y, 2));
}
inline float twoPointsAngle(Point point1, Point point2) {
return atan2f(point2.Y - point1.Y, point2.X - point1.X);
}
inline float radToDeg(float radians) {
return radians * (180.0 / 3.141592653589793238463);
}
#endif //SDL_GAME_PHYSICS_H
diff --git a/src/Settings.h b/src/Settings.h
index 65e3f60..8359337 100644
--- a/src/Settings.h
+++ b/src/Settings.h
@@ -1,15 +1,16 @@
//
// Created by Ido Mozes on 09/07/2019.
//
#ifndef SDL_GAME_SETTINGS_H
#define SDL_GAME_SETTINGS_H
enum Layers {
- BACKGROUND_LAYER,SEQUENCES_LAYER, SHADOW_LAYER, SHOTS_LAYER, TOWERS_LAYER, BLOONS_LAYER, MENU_LAYER,
+ BACKGROUND_LAYER, SEQUENCES_LAYER, SHADOW_LAYER, SHOTS_LAYER, TOWERS_LAYER, BLOONS_LAYER, MENU_LAYER,
N_LAYERS
};
constexpr int SIDEBAR_WIDTH = 150;
constexpr int MENU_WIDTH = 250;
constexpr int MAP_WIDTH = 686;
constexpr int MAP_HEIGHT = 511;
+constexpr float BPS = 1 / 3.0;
#endif //SDL_GAME_SETTINGS_H
diff --git a/src/System.cpp b/src/System.cpp
new file mode 100644
index 0000000..5f82815
--- /dev/null
+++ b/src/System.cpp
@@ -0,0 +1,188 @@
+//
+// Created by Ido Mozes on 15/07/2019.
+//
+
+#include "System.h"
+
+std::string getSurfaceName(EntityP &entity) {
+ std::string surfaceName;
+ int damageStateLives = getLives<SELF_LIVES>(entity) / 5;
+ switch (entity->getComponent<Type>()->value) {
+ case BLOON_T: {
+ auto[regrowP, camoP, fortifiedP, glueP, gumP, corrosiveP, lives] = entity->getComponentsP<Regrow, Camo, Fortified, Glue, Gum, Corrosive, 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 = getLives<TOTAL_LIVES>(entity);
+ if (int damageState = (maxLives - lives->value) / damageStateLives)
+ surfaceName += "DamageState" + std::to_string(damageState);
+ }
+ if (gumP)
+ surfaceName += "Gum";
+ else if (glueP)
+ surfaceName += "Glue";
+ else if (corrosiveP)
+ surfaceName += "Slime";
+ break;
+ }
+ case TOWER_T: {
+ switch (entity->getComponent<Kind>()->value) {
+ case DART_MONKEY:
+ surfaceName = "DartMonkey";
+ break;
+ case SUPER_MONKEY:
+ surfaceName = "SuperMonkey";
+ break;
+ case SNIPER_MONKEY:
+ surfaceName = "SniperMonkey";
+ break;
+ }
+ break;
+ }
+ case SHOT_T: {
+ switch (entity->getComponent<Kind>()->value) {
+ case DART:
+ surfaceName = "Dart";
+ break;
+ }
+ break;
+ }
+
+ }
+ return surfaceName;
+}
+
+float getSpeed(EntityP &entity) {
+ float speed;
+ switch (entity->getComponent<Type>()->value) {
+ case BLOON_T: {
+ auto[glueP, gumP, corrosiveP] = entity->getComponentsP<Glue, Gum, Corrosive>();
+ 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 (gumP or corrosiveP)
+ speed *= 0.8;
+ else if (glueP)
+ speed = 0;
+ break;
+ }
+ case SHOT_T: {
+ switch (entity->getComponent<Kind>()->value) {
+ case DART:
+ speed = 12;
+ break;
+ }
+ break;
+ }
+ }
+ return speed;
+}
+
diff --git a/src/System.h b/src/System.h
index b85f8c1..8fb65af 100644
--- a/src/System.h
+++ b/src/System.h
@@ -1,42 +1,149 @@
//
// Created by Ido Mozes on 23/06/2019.
//
#ifndef SDL2_GAME_SYSTEM_H
#define SDL2_GAME_SYSTEM_H
#include <initializer_list>
#include <vector>
#include <cmath>
#include "Entity.h"
#include "GameData.h"
+#include "components/IntegerComponents.h"
+#include "components/FloatComponents.h"
+#include "components/FlagComponents.h"
#include "components/Sequence.h"
-#include "components/Speed.h"
-#include "components/Kind.h"
#include "components/Position.h"
#include "components/Visibility.h"
#include "components/PathIndex.h"
#include "components/Velocity.h"
#include "components/Draggable.h"
#include "components/Action.h"
-#include "components/Range.h"
-#include "components/Type.h"
-#include "components/Strategy.h"
#include "components/RangeShadow.h"
-#include "eventComponents/MoveEntityEvent.h"
-#include "eventComponents/RemoveEntityEvent.h"
+#include "components/AttackSpeed.h"
+#include "components/DamageEvent.h"
+#include "components/PoppedBloons.h"
+#include "components/MoveEntityEvent.h"
-typedef std::vector<std::shared_ptr<Entity>> Entities;
+typedef std::vector<EntityP> Entities;
inline void
operator+=(Entities &originalVector, Entities &newVector) {
originalVector.insert(originalVector.end(), std::make_move_iterator(newVector.begin()),
std::make_move_iterator(newVector.end()));
}
+std::string getSurfaceName(EntityP &entity);
+
+enum ReturnValue {
+ TOTAL_LIVES, MIN_LIVES, SELF_LIVES
+};
+
+float getSpeed(EntityP &entity);
+
+template<ReturnValue returnValue>
+int getLives(EntityP &entity) {
+ int totalLives = 0;
+ int selfLives = 0;
+ int minLives = 0;
+ int additionalPreviousFortifiedLives = 0;
+ switch (entity->getComponent<Type>()->value) {
+ case BLOON_T: {
+ auto fortifiedP = entity->getComponent<Fortified>();
+ switch (entity->getComponent<Kind>()->value) {
+ case RED_BLOON:
+ totalLives = 1;
+ break;
+ case BLUE_BLOON:
+ totalLives = 2;
+ break;
+ case GREEN_BLOON:
+ totalLives = 3;
+ break;
+ case YELLOW_BLOON:
+ totalLives = 4;
+ break;
+ case PINK_BLOON:
+ totalLives = 5;
+ break;
+ case PURPLE_BLOON:
+ selfLives = 1;
+ totalLives = 11;
+ break;
+ case WHITE_BLOON:
+ selfLives = 1;
+ totalLives = 11;
+ break;
+ case BLACK_BLOON:
+ selfLives = 1;
+ totalLives = 11;
+ break;
+ case ZEBRA_BLOON:
+ selfLives = 1;
+ totalLives = 23;
+ break;
+ case LEAD_BLOON:
+ selfLives = 1;
+ totalLives = 23;
+ break;
+ case RAINBOW_BLOON:
+ selfLives = 1;
+ totalLives = 47;
+ break;
+ case CERAMIC_BLOON:
+ selfLives = 10;
+ totalLives = 104;
+ break;
+ case MOAB:
+ additionalPreviousFortifiedLives = 40;
+ selfLives = 200;
+ totalLives = 616;
+ break;
+ case BFB:
+ additionalPreviousFortifiedLives = 960;
+ selfLives = 1200;
+ totalLives = 3164;
+ break;
+ case DDT:
+ additionalPreviousFortifiedLives = 40;
+ selfLives = 400;
+ totalLives = 816;
+ break;
+ case ZOMG:
+ additionalPreviousFortifiedLives = 8640;
+ selfLives = 4000;
+ totalLives = 16656;
+ break;
+ case BAD:
+ additionalPreviousFortifiedLives = 26600;
+ selfLives = 20000;
+ totalLives = 55760;
+
+ break;
+ }
+ minLives = totalLives - selfLives + 1;
+ if (fortifiedP) {
+ totalLives += additionalPreviousFortifiedLives + selfLives;
+ selfLives *= 2;
+ minLives += additionalPreviousFortifiedLives;
+ }
+ break;
+ }
+ }
+ switch (returnValue) {
+ case TOTAL_LIVES:
+ return totalLives;
+ case MIN_LIVES:
+ return minLives;
+ case SELF_LIVES:
+ return selfLives;
+ }
+}
+
class System {
public:
virtual void update(Entities *entities, GameData &gameData) = 0;
};
#endif //SDL2_GAME_SYSTEM_H
diff --git a/src/components/Action.h b/src/components/Action.h
index dc31713..da2d893 100644
--- a/src/components/Action.h
+++ b/src/components/Action.h
@@ -1,28 +1,27 @@
//
// Created by Ido Mozes on 08/07/2019.
//
#ifndef SDL_GAME_ACTION_H
#define SDL_GAME_ACTION_H
#include "../Component.h"
enum ActionType {
DRAG, CLICK, DROP, SELECT
};
class Action : public Component {
public:
bool disabled;
ActionType actionType;
static constexpr ComponentType type = ComponentType::ACTION;
explicit Action(ActionType actionType, bool disabled = false) :actionType(actionType),
disabled(disabled) {}
- ~Action() override = default;
};
#endif //SDL_GAME_ACTION_H
diff --git a/src/components/AttackSpeed.cpp b/src/components/AttackSpeed.cpp
new file mode 100644
index 0000000..7e915f0
--- /dev/null
+++ b/src/components/AttackSpeed.cpp
@@ -0,0 +1,24 @@
+//
+// Created by Ido Mozes on 14/07/2019.
+//
+#include "AttackSpeed.h"
+
+void AttackSpeed::recharge() {
+ timeToRecharge = std::fmaxf(timeToRecharge - 1, 0);
+}
+
+int AttackSpeed::getAmountReady() {
+ int amountReady = 0;
+ if (timeToRecharge == 1) {
+ timeToRecharge = interval;
+ amountReady = 1;
+ } else if (timeToRecharge > 1) {
+ timeToRecharge -= 1;
+ } else {
+ amountReady = 1 + int((1 - timeToRecharge) / interval);
+ timeToRecharge = interval - fmodf((1 - timeToRecharge), interval);
+ if (timeToRecharge == 0)
+ timeToRecharge = interval;
+ }
+ return amountReady;
+}
\ No newline at end of file
diff --git a/src/components/AttackSpeed.h b/src/components/AttackSpeed.h
new file mode 100644
index 0000000..8ffda12
--- /dev/null
+++ b/src/components/AttackSpeed.h
@@ -0,0 +1,22 @@
+//
+// Created by Ido Mozes on 14/07/2019.
+//
+
+#ifndef SDL_GAME_ATTACKSPEED_H
+#define SDL_GAME_ATTACKSPEED_H
+
+#include <cmath>
+#include "../Component.h"
+
+class AttackSpeed : public Component {
+ float interval;
+ float timeToRecharge = 0;
+public:
+ static constexpr ComponentType type = ComponentType::ATTACK_SPEED;
+
+ explicit AttackSpeed(float amountPerSecond) : interval(60 / amountPerSecond) {}
+ void recharge();
+ int getAmountReady();
+};
+
+#endif //SDL_GAME_ATTACKSPEED_H
diff --git a/src/components/DamageEvent.h b/src/components/DamageEvent.h
new file mode 100644
index 0000000..0bacd9f
--- /dev/null
+++ b/src/components/DamageEvent.h
@@ -0,0 +1,19 @@
+//
+// Created by Ido Mozes on 16/07/2019.
+//
+
+#ifndef SDL_GAME_DAMAGEEVENT_H
+#define SDL_GAME_DAMAGEEVENT_H
+
+#include "../Component.h"
+
+class DamageEvent : public Component {
+public:
+ int damage;
+ EntityP shot;
+ static constexpr ComponentType type = ComponentType::DAMAGE_EVENT;
+
+ DamageEvent(int damage, EntityP &shot) : damage(damage), shot(shot) {}
+};
+
+#endif //SDL_GAME_DAMAGEEVENT_H
diff --git a/src/components/Draggable.h b/src/components/Draggable.h
index d6b4796..daa9614 100644
--- a/src/components/Draggable.h
+++ b/src/components/Draggable.h
@@ -1,16 +1,14 @@
//
// Created by Ido Mozes on 09/07/2019.
//
#ifndef SDL_GAME_DRAGGABLE_H
#define SDL_GAME_DRAGGABLE_H
#include "../Component.h"
class Draggable: public Component{
public:
bool isPlaceable = false;
static constexpr ComponentType type = ComponentType::DRAGGABLE;
- Draggable() = default;
- ~Draggable() override = default;
};
#endif //SDL_GAME_DRAGGABLE_H
diff --git a/src/components/FlagComponents.h b/src/components/FlagComponents.h
new file mode 100644
index 0000000..a3bd900
--- /dev/null
+++ b/src/components/FlagComponents.h
@@ -0,0 +1,20 @@
+//
+// 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(Regrow,REGROW);
+FLAG_COMPONENT(Glue,GLUE);
+FLAG_COMPONENT(Gum,GUM);
+FLAG_COMPONENT(Corrosive,CORROSIVE);
+#endif //SDL_GAME_FLAGCOMPONENTS_H
diff --git a/src/components/FloatComponents.h b/src/components/FloatComponents.h
new file mode 100644
index 0000000..824366b
--- /dev/null
+++ b/src/components/FloatComponents.h
@@ -0,0 +1,22 @@
+//
+// Created by Ido Mozes on 14/07/2019.
+//
+
+#ifndef SDL_GAME_FLOATCOMPONENTS_H
+#define SDL_GAME_FLOATCOMPONENTS_H
+#define FLOAT_COMPONENT(className, classType) class className : public FloatComponent { public: static constexpr ComponentType type = ComponentType::classType; using FloatComponent::FloatComponent; }
+
+#include "../Component.h"
+
+class FloatComponent : public Component {
+public:
+ float value;
+
+ explicit FloatComponent(float value) : value(value) {}
+
+};
+FLOAT_COMPONENT(Range,RANGE);
+FLOAT_COMPONENT(Speed,SPEED);
+FLOAT_COMPONENT(Spread,SPREAD);
+FLOAT_COMPONENT(Distance,DISTANCE);
+#endif //SDL_GAME_FLOATCOMPONENTS_H
diff --git a/src/components/IntegerComponents.h b/src/components/IntegerComponents.h
new file mode 100644
index 0000000..692bc78
--- /dev/null
+++ b/src/components/IntegerComponents.h
@@ -0,0 +1,66 @@
+//
+// 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,
+ ZEBRA_BLOON,
+ LEAD_BLOON,
+ RAINBOW_BLOON,
+ CERAMIC_BLOON,
+ MOAB,
+ BFB,
+ DDT,
+ ZOMG,
+ BAD
+};
+enum TowerKinds{
+ DART_MONKEY,
+ SUPER_MONKEY,
+ SNIPER_MONKEY,
+};
+enum ShotKinds{
+ DART,
+ BOMB,
+ SPRAY,
+ GUN,
+};
+
+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(Value,VALUE);
+INTEGER_COMPONENT(Kind,KIND);
+INTEGER_COMPONENT(ShotKind,SHOT_KIND);
+
+
+#endif //SDL_GAME_INTEGERCOMPONENTS_H
diff --git a/src/components/Kind.h b/src/components/Kind.h
deleted file mode 100644
index 8824d14..0000000
--- a/src/components/Kind.h
+++ /dev/null
@@ -1,22 +0,0 @@
-//
-// Created by Ido Mozes on 07/07/2019.
-//
-
-#ifndef SDL_GAME_KIND_H
-#define SDL_GAME_KIND_H
-
-#include "../Component.h"
-#include <string>
-
-class Kind : public Component {
-
-
-public:
- std::string value;
- static constexpr ComponentType type = ComponentType::KIND;
-
- explicit Kind(std::string value) :value(std::move(value)) {}
- ~Kind() override = default;
-};
-
-#endif //SDL_GAME_KIND_H
diff --git a/src/eventComponents/MoveEntityEvent.h b/src/components/MoveEntityEvent.h
similarity index 100%
rename from src/eventComponents/MoveEntityEvent.h
rename to src/components/MoveEntityEvent.h
diff --git a/src/components/PathIndex.h b/src/components/PathIndex.h
index 160187e..02a51c7 100644
--- a/src/components/PathIndex.h
+++ b/src/components/PathIndex.h
@@ -1,22 +1,21 @@
//
// Created by Ido Mozes on 03/07/2019.
//
#ifndef SDL_GAME_PATHINDEX_H
#define SDL_GAME_PATHINDEX_H
#include "../Component.h"
class PathIndex : public Component {
public:
int index;
float progress;
static constexpr ComponentType type = ComponentType::PATH_INDEX;
explicit PathIndex(int index) :index(index), progress(index) {}
- ~PathIndex() override = default;
};
#endif //SDL_GAME_PATHINDEX_H
diff --git a/src/components/PoppedBloons.h b/src/components/PoppedBloons.h
new file mode 100644
index 0000000..3e53987
--- /dev/null
+++ b/src/components/PoppedBloons.h
@@ -0,0 +1,14 @@
+//
+// Created by Ido Mozes on 15/07/2019.
+//
+
+#ifndef SDL_GAME_POPPEDBLOONS_H
+#define SDL_GAME_POPPEDBLOONS_H
+#include "../Component.h"
+#include <unordered_set>
+class PoppedBloons: public Component{
+public:
+ std::unordered_set<void *> value;
+ static constexpr ComponentType type = ComponentType::POPPED_BLOONS;
+};
+#endif //SDL_GAME_POPPEDBLOONS_H
diff --git a/src/components/Position.h b/src/components/Position.h
index df3dc1c..c945405 100644
--- a/src/components/Position.h
+++ b/src/components/Position.h
@@ -1,27 +1,27 @@
//
// Created by Ido Mozes on 02/07/2019.
//
#ifndef SDL_GAME_POSITION_H
#define SDL_GAME_POSITION_H
#include "../Component.h"
class Position : public Component {
public:
Point value;
static constexpr ComponentType type = ComponentType::POSITION;
- Position(float x, float y) : value{x,y} {};
+ Position(float x, float y) : value{x, y} {}
- ~Position() override = default;
+ explicit Position(Point value) : value(value) {}
void changePosition(float deltaX, float deltaY) {
value.X += deltaX;
value.Y += deltaY;
}
};
#endif //SDL_GAME_POSITION_H
diff --git a/src/components/Range.h b/src/components/Range.h
deleted file mode 100644
index e9067c9..0000000
--- a/src/components/Range.h
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Created by Ido Mozes on 10/07/2019.
-//
-
-#ifndef SDL_GAME_RANGE_H
-#define SDL_GAME_RANGE_H
-
-#include "../Component.h"
-
-class Range : public Component {
-public:
- float value;
- static constexpr ComponentType type = ComponentType::RANGE;
-
- explicit Range(float value) : value(value) {}
-
- ~Range() override = default;
-};
-
-#endif //SDL_GAME_RANGE_H
diff --git a/src/components/RangeShadow.h b/src/components/RangeShadow.h
index 1dc0d14..953139a 100644
--- a/src/components/RangeShadow.h
+++ b/src/components/RangeShadow.h
@@ -1,22 +1,21 @@
//
// Created by Ido Mozes on 10/07/2019.
//
#ifndef SDL_GAME_RANGESHADOW_H
#define SDL_GAME_RANGESHADOW_H
#include "../Component.h"
#include <memory>
class RangeShadow : public Component {
public:
- std::shared_ptr<Entity> entity;
+ EntityP entity;
static constexpr ComponentType type = ComponentType::RANGE_SHADOW;
- RangeShadow(std::shared_ptr<Entity> &entity) : entity(entity) {};
+ RangeShadow(EntityP &entity) : entity(entity) {};
- ~RangeShadow() override = default;
};
#endif //SDL_GAME_RANGESHADOW_H
diff --git a/src/components/Sequence.cpp b/src/components/Sequence.cpp
index 789c231..9be181f 100644
--- a/src/components/Sequence.cpp
+++ b/src/components/Sequence.cpp
@@ -1,32 +1,32 @@
//
// Created by Ido Mozes on 07/07/2019.
//
#include "Sequence.h"
int Sequence::getAmountReady() {
if (amount == 0)
return SEQUENCE_FINISHED;
int amountToReturn;
if (amountReady <= amount) {
amount -= amountReady;
amountToReturn = amountReady;
} else {
amountToReturn = amount;
amount = 0;
}
amountReady = 0;
if (timeToRecharge == 1) {
timeToRecharge = interval;
amountReady = 1;
} else if (timeToRecharge > 1) {
timeToRecharge -= 1;
} else {
amountReady = 1 + int((1 - timeToRecharge) / interval);
- timeToRecharge = fmodf((1 - timeToRecharge), interval);
+ timeToRecharge = interval - fmodf((1 - timeToRecharge), interval);
if(timeToRecharge == 0)
timeToRecharge = interval;
}
return amountToReturn;
}
diff --git a/src/components/Sequence.h b/src/components/Sequence.h
index 4a26ca3..b8cafc9 100644
--- a/src/components/Sequence.h
+++ b/src/components/Sequence.h
@@ -1,31 +1,30 @@
//
// Created by Ido Mozes on 07/07/2019.
//
#ifndef SDL_GAME_SEQUENCE_H
#define SDL_GAME_SEQUENCE_H
#include <cmath>
#include "../Component.h"
constexpr int SEQUENCE_FINISHED = -1;
class Sequence : public Component {
int amount;
float interval;
float timeToRecharge;
int amountReady;
public:
static constexpr ComponentType type = ComponentType::SEQUENCE;
- Sequence(int amount, float interval, float delay=0) : amount(amount), interval(interval),
+ Sequence(int amount, float amountPerSecond, float delay=0) : amount(amount), interval(60/amountPerSecond),
timeToRecharge(delay ? delay : interval),
amountReady(delay == 0) {}
- ~Sequence() override = default;
int getAmountReady();
};
#endif //SDL_GAME_SEQUENCE_H
diff --git a/src/components/Speed.h b/src/components/Speed.h
deleted file mode 100644
index db4ffd7..0000000
--- a/src/components/Speed.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Created by Ido Mozes on 03/07/2019.
-//
-
-#ifndef SDL_GAME_SPEED_H
-#define SDL_GAME_SPEED_H
-
-#include "../Component.h"
-
-
-class Speed : public Component {
-public:
- float value;
-
- static constexpr ComponentType type = ComponentType::SPEED;
-
- explicit Speed(float value) :value(value) {}
- ~Speed() override = default;
-};
-
-#endif //SDL_GAME_SPEED_H
diff --git a/src/components/Strategy.h b/src/components/Strategy.h
deleted file mode 100644
index 12b6052..0000000
--- a/src/components/Strategy.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// Created by Ido Mozes on 11/07/2019.
-//
-
-#ifndef SDL_GAME_STRATEGY_H
-#define SDL_GAME_STRATEGY_H
-#include "../Component.h"
-
-enum Strateies {
- FIRST, LAST, CLOSEST, STRONGEST
-};
-
-class Strategy : public Component {
-public:
- Strateies value;
- static constexpr ComponentType type = ComponentType::STRATEGY;
-
- Strategy(Strateies value) : value(value) {}
-
- ~Strategy() override = default;
-};
-
-#endif //SDL_GAME_STRATEGY_H
diff --git a/src/components/Type.h b/src/components/Type.h
deleted file mode 100644
index 00e5c0b..0000000
--- a/src/components/Type.h
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// Created by Ido Mozes on 09/07/2019.
-//
-
-#ifndef SDL_GAME_TYPE_H
-#define SDL_GAME_TYPE_H
-
-#include "../Component.h"
-
-enum Types {
- OBSTACLE_T, TOWER_T, BLOON_T, SHOT_T, SEQUENCE_T
-};
-
-class Type : public Component {
-public:
- Types value;
- static constexpr ComponentType type = ComponentType::TYPE;
-
- Type(Types value) : value(value) {}
-
- ~Type() override = default;
-};
-
-#endif //SDL_GAME_TYPE_H
diff --git a/src/components/Velocity.h b/src/components/Velocity.h
index c4e8e7a..58dd891 100644
--- a/src/components/Velocity.h
+++ b/src/components/Velocity.h
@@ -1,50 +1,48 @@
//
// Created by Ido Mozes on 02/07/2019.
//
#ifndef SDL_GAME_VELOCITY_H
#define SDL_GAME_VELOCITY_H
#include <cmath>
#include "../Physics.h"
#include "../Component.h"
class Velocity : public Component {
public:
Point value;
static constexpr ComponentType type = ComponentType::VELOCITY;
Velocity(float x, float y);
- ~Velocity() override = default;
-
void setVelocity(float x, float y) {
value={x,y};
}
void changeVelocity(float deltaX, float deltaY) {
value.X += deltaX;
value.Y += deltaY;
}
void turnDirection(float deltaRad);
void setDirection(float rad);
void setSpeed(float speed);
void changeSpeed(float deltaSpeed);
};
class Acceleration : public Velocity {
public:
static constexpr ComponentType type = ComponentType::ACCELERATION;
Acceleration(float x, float y) : Velocity(x, y) {}
};
#endif //SDL_GAME_VELOCITY_H
diff --git a/src/components/Visibility.h b/src/components/Visibility.h
index e1bac3e..37ab80c 100644
--- a/src/components/Visibility.h
+++ b/src/components/Visibility.h
@@ -1,44 +1,46 @@
//
// 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;
+ float angle = 0;
static constexpr ComponentType type = ComponentType::VISIBILITY;
- Visibility(SDL_Renderer *renderer, SDL_Surface *newSurface, std::optional<SDL_Rect> dstR = std::nullopt,float angle = 0);
+ Visibility(SDL_Renderer *renderer, SDL_Surface *newSurface, std::optional<SDL_Rect> dstR = std::nullopt,
+ float angle = 0);
~Visibility() override;
SDL_Texture *getTexture() { return texture; }
SDL_Rect *getDstRect() { return dstRect ? &dstRect.value() : nullptr; }
+ 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);
};
#endif //SDL2_GAME_VISIBILITY_H
diff --git a/src/eventComponents/RemoveEntityEvent.h b/src/eventComponents/RemoveEntityEvent.h
deleted file mode 100644
index 1537623..0000000
--- a/src/eventComponents/RemoveEntityEvent.h
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// Created by Ido Mozes on 10/07/2019.
-//
-
-#ifndef SDL_GAME_REMOVEENTITYEVENT_H
-#define SDL_GAME_REMOVEENTITYEVENT_H
-#include "../Component.h"
-
-class RemoveEntityEvent: public Component{
-public:
- static constexpr ComponentType type = ComponentType::REMOVE_ENTITY_EVENT;
- RemoveEntityEvent() = default;
- ~RemoveEntityEvent() override = default;
-};
-#endif //SDL_GAME_REMOVEENTITYEVENT_H
diff --git a/src/main.cpp b/src/main.cpp
index e754cb5..d34bc8e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,21 +1,21 @@
//#include <iostream>
#include "SDL.h"
#include "Game.h"
int main(int argc, char *argv[]) {
- const int FPS = 60, frameDelay = 1000 / FPS;
+ const int FPS = 120, frameDelay = 1000 / FPS;
Uint32 frameStart;
int frameTime;
- Game game(false, 1.5);
+ Game game(false, 2);
while (game.running()) {
frameStart = SDL_GetTicks();
game.update();
frameTime = SDL_GetTicks() - frameStart;
if (frameDelay > frameTime) {
SDL_Delay(frameDelay - frameTime);
}
}
return 0;
}
\ No newline at end of file
diff --git a/src/systems/BloonsSpawnSystem.cpp b/src/systems/BloonsSpawnSystem.cpp
index 47d1131..d03401d 100644
--- a/src/systems/BloonsSpawnSystem.cpp
+++ b/src/systems/BloonsSpawnSystem.cpp
@@ -1,30 +1,35 @@
//
// Created by Ido Mozes on 07/07/2019.
//
#include "BloonsSpawnSystem.h"
void BloonsSpawnSystem::update(Entities *layers, GameData &gameData) {
for (auto &entity: layers[SEQUENCES_LAYER]) {
- auto[sequence, kind, speed] = entity->getComponents<Sequence, Kind, Speed>().value();
+ auto[sequence, kind] = entity->getComponents<Sequence, Kind>().value();
+ auto [regrowP,camoP,fortifiedP] = entity->getComponentsP<Regrow,Camo,Fortified>();
int amount = sequence.getAmountReady();
for (int j = 0; j < amount; ++j) {
- auto *bloon = new Entity();
+ EntityP bloon(new Entity());
bloon->addComponent<Type>(BLOON_T);
- bloon->addComponent<Kind>(kind);
- bloon->addComponent<Position>(gameData.startingPoint.X, gameData.startingPoint.Y);
+ bloon->addComponent<Position>(gameData.startingPoint);
bloon->addComponent<PathIndex>(0);
- bloon->addComponent<Speed>(speed.value);
- SDL_Surface *surface = gameData.assets[kind.value];
+ bloon->addComponents(kind);
+ if (regrowP)
+ bloon->addComponent<Regrow>();
+ if (camoP)
+ bloon->addComponent<Camo>();
+ if (fortifiedP)
+ bloon->addComponent<Fortified>();
+ bloon->addComponent<Lives>(getLives<TOTAL_LIVES>(bloon));
+ SDL_Surface *surface = gameData.assets[getSurfaceName(bloon)];
bloon->addComponent<Visibility>(gameData.renderer, surface,
- SDL_Rect{int(gameData.startingPoint.X),
- int(gameData.startingPoint.Y),
- int(surface->w / 3), int(surface->h / 3)});
+ 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 4e36b18..ec94d66 100644
--- a/src/systems/CollisionSystem.cpp
+++ b/src/systems/CollisionSystem.cpp
@@ -1,62 +1,117 @@
//
// 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];
- std::shared_ptr<Entity> entityP(entity);
+ EntityP entityP(entity);
auto &previousEntity = layer[i - 1];
auto[position, range] = entity->getComponents<Position, Range>().value();
- float X = position.value.X - range.value;
-
- while (j >= 0 and X < layer[j]->getComponent<Position>()->value.X - layer[j]->getComponent<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) {
Entities &bloonsLayer = layers[BLOONS_LAYER];
Entities &shotsLayer = layers[SHOTS_LAYER];
insertionSort(bloonsLayer);
insertionSort(shotsLayer);
- std::vector<std::tuple<std::shared_ptr<Entity>, std::shared_ptr<Entity>>> collided;
+ std::vector<std::tuple<EntityP, EntityP, float>> collided;
int bloonIndex = 0;
for (auto &shot : shotsLayer) {
- auto[shotX, shotY] = shot->getComponent<Position>()->value;
+ 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[bloonX, bloonY] = bloon->getComponent<Position>()->value;
+ 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)
- collided.emplace_back(shot, bloon);
+ 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) {
- bloon->addComponent<RemoveEntityEvent>();
- shot->addComponent<RemoveEntityEvent>();
+ for (auto[shot, bloon, _] :collided) {
+ auto[pierce, damage] = shot->getComponents<Pierce, Damage>().value();
+ if (pierce.value > 0) {
+ bloon->addComponent<DamageEvent>(damage.value,shot);
+ 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
new file mode 100644
index 0000000..9015ddb
--- /dev/null
+++ b/src/systems/DamageSystem.cpp
@@ -0,0 +1,415 @@
+//
+// 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;
+}
+
+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) {
+ bloon->addComponent<RemoveEntityEvent>();
+ return;
+ }
+ auto &kind = bloon->getComponent<Kind>()->value;
+ auto &visibility = *bloon->getComponent<Visibility>();
+ auto[regrowP, camoP, fortifiedP, glueP, gumP, corrosiveP] = bloon->getComponentsP<Regrow, Camo, Fortified, Glue, Gum, Corrosive>();
+ SDL_Surface *surface;
+ switch (kind) {
+ case RED_BLOON:
+ lives -= damage;
+ 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;
+
+ kind = (fortifiedP ? lives / 2 : lives) - 1;
+ surface = gameData.assets[getSurfaceName(bloon)];
+ visibility.setDstRect(SDL_Rect{0, 0, surface->w / 3, 0});
+ visibility.loadTexture(gameData.renderer, surface);
+ bloon->getComponent<Range>()->value = std::max(surface->w / 6, surface->h / 6);
+ break;
+ }
+ case PURPLE_BLOON:
+ case WHITE_BLOON:
+ case BLACK_BLOON: {
+ if (!didBloonPop(bloon, lives, damage))
+ break;
+ auto &pathIndex = *bloon->getComponent<PathIndex>();
+ for (int i = 0; i < 2; ++i) {
+ EntityP newBloon(new Entity());
+ shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
+ newBloon->addComponent<Type>(BLOON_T);
+ newBloon->addComponent<Kind>(PINK_BLOON);
+ newBloon->addComponent<Lives>(lives / 2);
+ newBloon->addComponent<Position>(gameData.startingPoint);
+ newBloon->addComponent<PathIndex>(0);
+ newBloon->getComponent<PathIndex>()->progress =
+ i == 0 ? std::fmaxf(0, pathIndex.progress - 10) : std::fminf(gameData.path.size() - 1,
+ pathIndex.progress + 10);
+ if (regrowP)
+ newBloon->addComponent<Regrow>();
+ if (camoP)
+ newBloon->addComponent<Camo>();
+ if (gumP)
+ newBloon->addComponent<Gum>();
+ else if (glueP)
+ newBloon->addComponent<Glue>();
+ else if (corrosiveP)
+ newBloon->addComponent<Corrosive>();
+ surface = gameData.assets[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});
+ newBloons.emplace_back(newBloon);
+ damageBloon(newBloon, shot, i == 0 ? ceilf(damage / 2.0) : floorf(damage / 2.0), gameData, newBloons);
+ }
+ bloon->addComponent<RemoveEntityEvent>();
+ break;
+ }
+ case ZEBRA_BLOON: {
+ if (!didBloonPop(bloon, lives, damage))
+ break;
+ auto &pathIndex = *bloon->getComponent<PathIndex>();
+ for (int i = 0; i < 2; ++i) {
+ EntityP newBloon(new Entity());
+ shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
+ newBloon->addComponent<Type>(BLOON_T);
+ newBloon->addComponent<Kind>(i == 0 ? BLACK_BLOON : WHITE_BLOON);
+ newBloon->addComponent<Lives>(lives / 2);
+ newBloon->addComponent<Position>(gameData.startingPoint);
+ newBloon->addComponent<PathIndex>(0);
+ newBloon->getComponent<PathIndex>()->progress =
+ i == 0 ? std::fmaxf(0, pathIndex.progress - 10) : std::fminf(gameData.path.size() - 1,
+ pathIndex.progress + 10);
+ if (regrowP)
+ newBloon->addComponent<Regrow>();
+ if (camoP)
+ newBloon->addComponent<Camo>();
+ if (gumP)
+ newBloon->addComponent<Gum>();
+ else if (glueP)
+ newBloon->addComponent<Glue>();
+ else if (corrosiveP)
+ newBloon->addComponent<Corrosive>();
+ surface = gameData.assets[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});
+ newBloons.emplace_back(newBloon);
+ damageBloon(newBloon, shot, i == 0 ? ceilf(damage / 2.0) : floorf(damage / 2.0), gameData, newBloons);
+ }
+ bloon->addComponent<RemoveEntityEvent>();
+ break;
+ }
+ case LEAD_BLOON: {
+ if (!didBloonPop(bloon, lives, damage))
+ break;
+ auto &pathIndex = *bloon->getComponent<PathIndex>();
+ for (int i = 0; i < 2; ++i) {
+ EntityP newBloon(new Entity());
+ shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
+ newBloon->addComponent<Type>(BLOON_T);
+ newBloon->addComponent<Kind>(BLACK_BLOON);
+ newBloon->addComponent<Lives>(lives / 2);
+ newBloon->addComponent<Position>(gameData.startingPoint);
+ newBloon->addComponent<PathIndex>(0);
+ newBloon->getComponent<PathIndex>()->progress =
+ i == 0 ? std::fmaxf(0, pathIndex.progress - 10) : std::fminf(gameData.path.size() - 1,
+ pathIndex.progress + 10);
+ if (regrowP)
+ newBloon->addComponent<Regrow>();
+ if (camoP)
+ newBloon->addComponent<Camo>();
+ if (gumP)
+ newBloon->addComponent<Gum>();
+ else if (glueP)
+ newBloon->addComponent<Glue>();
+ else if (corrosiveP)
+ newBloon->addComponent<Corrosive>();
+ surface = gameData.assets[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});
+ newBloons.emplace_back(newBloon);
+ damageBloon(newBloon, shot, i == 0 ? ceilf(damage / 2.0) : floorf(damage / 2.0), gameData, newBloons);
+ }
+ bloon->addComponent<RemoveEntityEvent>();
+ break;
+ }
+ case RAINBOW_BLOON: {
+ if (!didBloonPop(bloon, lives, damage))
+ break;
+ auto &pathIndex = *bloon->getComponent<PathIndex>();
+ for (int i = 0; i < 2; ++i) {
+ EntityP newBloon(new Entity());
+ shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
+ newBloon->addComponent<Type>(BLOON_T);
+ newBloon->addComponent<Kind>(ZEBRA_BLOON);
+ newBloon->addComponent<Lives>(lives / 2);
+ newBloon->addComponent<Position>(gameData.startingPoint);
+ newBloon->addComponent<PathIndex>(0);
+ newBloon->getComponent<PathIndex>()->progress =
+ i == 0 ? std::fmaxf(0, pathIndex.progress - 10) : std::fminf(gameData.path.size() - 1,
+ pathIndex.progress + 10);
+ if (regrowP)
+ newBloon->addComponent<Regrow>();
+ if (camoP)
+ newBloon->addComponent<Camo>();
+ if (gumP)
+ newBloon->addComponent<Gum>();
+ else if (glueP)
+ newBloon->addComponent<Glue>();
+ else if (corrosiveP)
+ newBloon->addComponent<Corrosive>();
+ surface = gameData.assets[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});
+ newBloons.emplace_back(newBloon);
+ damageBloon(newBloon, shot, i == 0 ? ceilf(damage / 2.0) : floorf(damage / 2.0), gameData, newBloons);
+ }
+ bloon->addComponent<RemoveEntityEvent>();
+ break;
+ }
+ case CERAMIC_BLOON: {
+ if (didBloonPop(bloon, lives, damage, getLives<MIN_LIVES>(bloon))) {
+ auto &pathIndex = *bloon->getComponent<PathIndex>();
+ for (int i = 0; i < 2; ++i) {
+ EntityP newBloon(new Entity());
+ shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
+ newBloon->addComponent<Type>(BLOON_T);
+ newBloon->addComponent<Kind>(RAINBOW_BLOON);
+ newBloon->addComponent<Lives>(lives / 2);
+ newBloon->addComponent<Position>(gameData.startingPoint);
+ newBloon->addComponent<PathIndex>(0);
+ newBloon->getComponent<PathIndex>()->progress =
+ i == 0 ? std::fmaxf(0, pathIndex.progress - 10) : std::fminf(gameData.path.size() - 1,
+ pathIndex.progress + 10);
+ if (regrowP)
+ newBloon->addComponent<Regrow>();
+ if (camoP)
+ newBloon->addComponent<Camo>();
+ if (gumP)
+ newBloon->addComponent<Gum>();
+ else if (glueP)
+ newBloon->addComponent<Glue>();
+ else if (corrosiveP)
+ newBloon->addComponent<Corrosive>();
+ surface = gameData.assets[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});
+ newBloons.emplace_back(newBloon);
+ damageBloon(newBloon, shot, i == 0 ? ceilf(damage / 2.0) : floorf(damage / 2.0), gameData,
+ newBloons);
+ }
+ bloon->addComponent<RemoveEntityEvent>();
+ break;
+ } else {
+ surface = gameData.assets[getSurfaceName(bloon)];
+ visibility.loadTexture(gameData.renderer, surface);
+ }
+ break;
+ }
+ case MOAB: {
+ if (didBloonPop(bloon, lives, damage, getLives<MIN_LIVES>(bloon))) {
+ auto &pathIndex = *bloon->getComponent<PathIndex>();
+ for (int i = 0; i < 4; ++i) {
+ EntityP newBloon(new Entity());
+ shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
+ newBloon->addComponent<Type>(BLOON_T);
+ newBloon->addComponent<Kind>(CERAMIC_BLOON);
+ newBloon->addComponent<Lives>(lives / 4);
+ newBloon->addComponent<Position>(gameData.startingPoint);
+ newBloon->addComponent<PathIndex>(0);
+ newBloon->getComponent<PathIndex>()->progress =
+ i < 2 ? std::fmaxf(0, pathIndex.progress - 20 + 10 * (i % 2)) : std::fminf(
+ gameData.path.size() - 1, pathIndex.progress + 20 - 10 * (i % 2));
+ if (fortifiedP)
+ newBloon->addComponent<Fortified>();
+ surface = gameData.assets[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});
+ newBloons.emplace_back(newBloon);
+ damageBloon(newBloon, shot, i == 0 ? ceilf(damage / 4.0) : damage - ceilf(damage / 4.0) * 3,
+ gameData, newBloons);
+ }
+ bloon->addComponent<RemoveEntityEvent>();
+ break;
+ } else {
+ surface = gameData.assets[getSurfaceName(bloon)];
+ visibility.loadTexture(gameData.renderer, surface);
+ }
+ break;
+ }
+ case BFB:{
+ if (didBloonPop(bloon, lives, damage, getLives<MIN_LIVES>(bloon))) {
+ auto &pathIndex = *bloon->getComponent<PathIndex>();
+ for (int i = 0; i < 4; ++i) {
+ EntityP newBloon(new Entity());
+ shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
+ newBloon->addComponent<Type>(BLOON_T);
+ newBloon->addComponent<Kind>(MOAB);
+ newBloon->addComponent<Lives>(lives / 4);
+ newBloon->addComponent<Position>(gameData.startingPoint);
+ newBloon->addComponent<PathIndex>(0);
+ newBloon->getComponent<PathIndex>()->progress =
+ i < 2 ? std::fmaxf(0, pathIndex.progress - 20 + 10 * (i % 2)) : std::fminf(
+ gameData.path.size() - 1, pathIndex.progress + 20 - 10 * (i % 2));
+ if (fortifiedP)
+ newBloon->addComponent<Fortified>();
+ surface = gameData.assets[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});
+ newBloons.emplace_back(newBloon);
+ damageBloon(newBloon, shot, i == 0 ? ceilf(damage / 4.0) : damage - ceilf(damage / 4.0) * 3,
+ gameData, newBloons);
+ }
+ bloon->addComponent<RemoveEntityEvent>();
+ break;
+ } else {
+ surface = gameData.assets[getSurfaceName(bloon)];
+ visibility.loadTexture(gameData.renderer, surface);
+ }
+ break;
+ }
+ case DDT:{
+ if (didBloonPop(bloon, lives, damage, getLives<MIN_LIVES>(bloon))) {
+ auto &pathIndex = *bloon->getComponent<PathIndex>();
+ for (int i = 0; i < 4; ++i) {
+ EntityP newBloon(new Entity());
+ shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
+ newBloon->addComponent<Type>(BLOON_T);
+ newBloon->addComponent<Kind>(CERAMIC_BLOON);
+ newBloon->addComponent<Lives>(lives / 4);
+ newBloon->addComponent<Position>(gameData.startingPoint);
+ newBloon->addComponent<PathIndex>(0);
+ newBloon->getComponent<PathIndex>()->progress =
+ i < 2 ? std::fmaxf(0, pathIndex.progress - 20 + 10 * (i % 2)) : std::fminf(
+ gameData.path.size() - 1, pathIndex.progress + 20 - 10 * (i % 2));
+ if (fortifiedP)
+ newBloon->addComponent<Fortified>();
+ surface = gameData.assets[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});
+ newBloons.emplace_back(newBloon);
+ damageBloon(newBloon, shot, i == 0 ? ceilf(damage / 4.0) : damage - ceilf(damage / 4.0) * 3,
+ gameData, newBloons);
+ }
+ bloon->addComponent<RemoveEntityEvent>();
+ break;
+ } else {
+ surface = gameData.assets[getSurfaceName(bloon)];
+ visibility.loadTexture(gameData.renderer, surface);
+ }
+ break;
+ }
+ case ZOMG:{
+ if (didBloonPop(bloon, lives, damage, getLives<MIN_LIVES>(bloon))) {
+ auto &pathIndex = *bloon->getComponent<PathIndex>();
+ for (int i = 0; i < 4; ++i) {
+ EntityP newBloon(new Entity());
+ shot->getComponent<PoppedBloons>()->value.emplace(newBloon.get());
+ newBloon->addComponent<Type>(BLOON_T);
+ newBloon->addComponent<Kind>(BFB);
+ newBloon->addComponent<Lives>(lives / 4);
+ newBloon->addComponent<Position>(gameData.startingPoint);
+ newBloon->addComponent<PathIndex>(0);
+ newBloon->getComponent<PathIndex>()->progress =
+ i < 2 ? std::fmaxf(0, pathIndex.progress - 20 + 10 * (i % 2)) : std::fminf(
+ gameData.path.size() - 1, pathIndex.progress + 20 - 10 * (i % 2));
+ if (fortifiedP)
+ newBloon->addComponent<Fortified>();
+ surface = gameData.assets[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});
+ newBloons.emplace_back(newBloon);
+ damageBloon(newBloon, shot, i == 0 ? ceilf(damage / 4.0) : damage - ceilf(damage / 4.0) * 3,
+ gameData, newBloons);
+ }
+ bloon->addComponent<RemoveEntityEvent>();
+ break;
+ } else {
+ surface = gameData.assets[getSurfaceName(bloon)];
+ visibility.loadTexture(gameData.renderer, surface);
+ }
+ break;
+ }
+ case BAD:{
+ if (didBloonPop(bloon, lives, damage, getLives<MIN_LIVES>(bloon))) {
+ auto &pathIndex = *bloon->getComponent<PathIndex>();
+ 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<3?ZOMG:DDT);
+ if (fortifiedP)
+ newBloon->addComponent<Fortified>();
+ newBloon->addComponent<Lives>(getLives<TOTAL_LIVES>(newBloon));
+ newBloon->addComponent<Position>(gameData.startingPoint);
+ newBloon->addComponent<PathIndex>(0);
+ newBloon->getComponent<PathIndex>()->progress =
+ i < 2 ? std::fmaxf(0, pathIndex.progress - 20 + 10 * (i % 2)) : std::fminf(
+ gameData.path.size() - 1, pathIndex.progress + 20 - 10 * (i % 2));
+ surface = gameData.assets[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});
+ newBloons.emplace_back(newBloon);
+ damageBloon(newBloon, shot, i == 0 ? ceilf(damage / 4.0) : damage - ceilf(damage / 4.0) * 3,
+ gameData, newBloons);
+ }
+ bloon->addComponent<RemoveEntityEvent>();
+ break;
+ } else {
+ surface = gameData.assets[getSurfaceName(bloon)];
+ visibility.loadTexture(gameData.renderer, surface);
+ }
+ break;
+ }
+ }
+}
+
+void DamageSystem::update(Entities *layers, GameData &gameData) {
+ 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)
+ bloon->addComponent<RemoveEntityEvent>();
+ else {
+ damageBloon(bloon, damageEvent.shot, damageEvent.damage, gameData, newBloons);
+ bloon->removeComponent<DamageEvent>();
+ }
+ }
+ }
+ layers[BLOONS_LAYER] += newBloons;
+}
diff --git a/src/systems/DamageSystem.h b/src/systems/DamageSystem.h
new file mode 100644
index 0000000..0595918
--- /dev/null
+++ b/src/systems/DamageSystem.h
@@ -0,0 +1,12 @@
+//
+// Created by Ido Mozes on 15/07/2019.
+//
+
+#ifndef SDL_GAME_DAMAGESYSTEM_H
+#define SDL_GAME_DAMAGESYSTEM_H
+#include "../System.h"
+class DamageSystem : public System {
+public:
+ void update(Entities *layers, GameData &gameData) override;
+};
+#endif //SDL_GAME_DAMAGESYSTEM_H
diff --git a/src/systems/DraggingSystem.cpp b/src/systems/DraggingSystem.cpp
index e667275..42599d0 100644
--- a/src/systems/DraggingSystem.cpp
+++ b/src/systems/DraggingSystem.cpp
@@ -1,40 +1,40 @@
//
// Created by Ido Mozes on 09/07/2019.
//
#include "DraggingSystem.h"
-
void DraggingSystem::update(Entities *layers, GameData &gameData) {
- if(!gameData.isDragging)
+ if (!gameData.isDragging)
return;
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
mouseX = int(mouseX / gameData.mapScale);
mouseY = int(mouseY / gameData.mapScale);
for (int i = 0; i < N_LAYERS; ++i) {
for (auto &entity: layers[i]) {
if (auto components = entity->getComponents<Draggable, Visibility>()) {
auto[draggable, visibility] = components.value();
visibility.setPosition(mouseX - int(visibility.getDstRect()->w / 2.0),
mouseY - int(visibility.getDstRect()->h / 2.0));
bool freePosition = true;
- if (mouseX > SIDEBAR_WIDTH + MAP_WIDTH or mouseX < SIDEBAR_WIDTH)
+ if (mouseX >= SIDEBAR_WIDTH + MAP_WIDTH or mouseX < SIDEBAR_WIDTH)
freePosition = true;
else
- for (int x = mouseX - SIDEBAR_WIDTH - 4; x < mouseX - SIDEBAR_WIDTH + 5; ++x) {
- for (int y = mouseY - 4; y < mouseY + 5; ++y) {
+ for (int x = std::max(mouseX - SIDEBAR_WIDTH - 4, 0);
+ x < std::min(mouseX - SIDEBAR_WIDTH + 5, MAP_WIDTH - 1); ++x) {
+ for (int y = std::max(mouseY - 4, 0); y < std::min(mouseY + 5, MAP_HEIGHT - 1); ++y) {
if (gameData.mapData[x][y] == OBSTACLE or gameData.mapData[x][y] == TOWER) {
freePosition = false;
goto setIsPlaceable;
}
}
}
setIsPlaceable:
draggable.isPlaceable = freePosition;
}
}
}
}
\ No newline at end of file
diff --git a/src/systems/EventSystem.cpp b/src/systems/EventSystem.cpp
index c9f62c7..232a898 100644
--- a/src/systems/EventSystem.cpp
+++ b/src/systems/EventSystem.cpp
@@ -1,139 +1,137 @@
//
// 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();
if (action.disabled or (action.actionType != DROP and gameData.isDragging))
continue;
int entityX, entityY, w, h;
SDL_Rect *dstRect = visibility.getDstRect();
entityX = dstRect->x;
entityY = dstRect->y;
w = dstRect->w;
h = dstRect->h;
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) {
switch (action.actionType) {
case DRAG: {
- auto &kind = *entity->getComponent<Kind>();
- auto &range = *entity->getComponent<Range>();
+ auto[type, kind,shotKind, range, attackInterval, pierce, damage, distance] =
+ entity->getComponents<Type, Kind,ShotKind, Range, AttackSpeed, Pierce, Damage, Distance>().value();
auto draggable = new Entity();
- SDL_Surface *surface = gameData.assets[kind.value];
+ SDL_Surface *surface = gameData.assets[getSurfaceName(entity)];
draggable->addComponent<Visibility>(gameData.renderer, 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->addComponent<Kind>(kind);
- draggable->addComponent<Range>(range);
+ draggable->addComponents(type, kind, shotKind, range, attackInterval,
+ pierce, damage, distance);
draggable->addComponent<Strategy>(FIRST);
- std::shared_ptr<Entity> ptr(draggable);
+ 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: {
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 {
+ } 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) {
entity->addComponent<MoveEntityEvent>(TOWERS_LAYER);
- entity->addComponent<Type>(TOWER_T);
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)
+ 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;
}
}
}
}
}
}
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/MovementSystem.cpp b/src/systems/MovementSystem.cpp
index c2111bb..738f03d 100644
--- a/src/systems/MovementSystem.cpp
+++ b/src/systems/MovementSystem.cpp
@@ -1,74 +1,86 @@
//
// Created by Ido Mozes on 02/07/2019.
//
#include "MovementSystem.h"
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;
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;
-
- } else if (auto components2 = entity->getComponents<PathIndex, Speed>()) {
- auto[pathIndex, speed] =components2.value();
- pathIndex.progress += speed.value;
+ 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 (auto pathIndexP = entity->getComponent<PathIndex>()) {
+ auto &pathIndex =*pathIndexP;
+ pathIndex.progress += getSpeed(entity);
float deltaIndex = pathIndex.progress - pathIndex.index;
while (deltaIndex >= (gameData.path[pathIndex.index] % 2 == 0 ? 1 : sqrt(2))) {
switch (gameData.path[pathIndex.index]) {
case 0:
deltaX += 1;
break;
case 1:
deltaX += 1;
deltaY += 1;
break;
case 2:
deltaY += 1;
break;
case 3:
deltaX += -1;
deltaY += 1;
break;
case 4:
deltaX += -1;
break;
case 5:
deltaX += -1;
deltaY += -1;
break;
case 6:
deltaY += -1;
break;
case 7:
deltaX += 1;
deltaY += -1;
break;
}
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) {
entity->addComponent<RemoveEntityEvent>();
}
}
}
}
}
diff --git a/src/systems/ShotsSpawnSystem.cpp b/src/systems/ShotsSpawnSystem.cpp
index 5089de1..2a69003 100644
--- a/src/systems/ShotsSpawnSystem.cpp
+++ b/src/systems/ShotsSpawnSystem.cpp
@@ -1,62 +1,71 @@
//
// Created by Ido Mozes on 11/07/2019.
//
#include "ShotsSpawnSystem.h"
void ShotsSpawnSystem::update(Entities *layers, GameData &gameData) {
for (auto &entity: layers[TOWERS_LAYER]) {
- auto[kind, towerRange, towerPosition, strategy] = entity->getComponents<Kind, Range, Position, Strategy>().value();
+ auto[kind, shotKind, towerRange, towerPosition, strategy, attackSpeed, pierce, damage, distance, visibility] =
+ entity->getComponents<Kind, ShotKind, Range, Position, Strategy, AttackSpeed, Pierce, Damage, Distance, Visibility>().value();
float minDistance = MAP_HEIGHT + MAP_WIDTH;
float minProgress = gameData.path.size();
float maxProgress = -1;
Entity *closestBloon = nullptr, *firstBloon = nullptr, *lastBloon = nullptr;
for (auto &gameEntity: layers[BLOONS_LAYER]) {
float distance;
if (gameEntity->getComponent<Type>()->value == BLOON_T) {
auto[bloonRange, bloonPosition, pathIndex] = gameEntity->getComponents<Range, Position, PathIndex>().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 (pathIndex.progress > maxProgress) {
maxProgress = pathIndex.progress;
firstBloon = gameEntity.get();
}
}
}
if (closestBloon or firstBloon or lastBloon) {
Entity *target;
switch (strategy.value) {
case CLOSEST:
target = closestBloon;
break;
case FIRST:
target = firstBloon;
break;
case LAST:
target = lastBloon;
break;
}
- auto shot = new Entity();
- shot->addComponent<Position>(towerPosition.value.X, towerPosition.value.Y);
+ int amount = attackSpeed.getAmountReady();
float angle = twoPointsAngle(towerPosition.value, target->getComponent<Position>()->value);
- auto[velocityX, velocityY] = polarToCartesian(angle, 5);
- shot->addComponent<Velocity>(velocityX, velocityY);
- shot->addComponent<Type>(SHOT_T);
- shot->addComponent<Range>(5);
- SDL_Surface *surface = gameData.assets["Dart"];
- shot->addComponent<Visibility>(gameData.renderer, surface, SDL_Rect{0, 0, surface->w / 25},
- radToDeg(angle));
- layers[SHOTS_LAYER].emplace_back(shot);
- }
+ for (int i = 0; i < amount; ++i) {
+ 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(angle, getSpeed(shot));
+ shot->addComponent<Velocity>(velocityX, velocityY);
+ shot->addComponent<Range>(5);
+ shot->addComponents(pierce, damage, distance);
+ shot->addComponent<PoppedBloons>();
+ SDL_Surface *surface = gameData.assets[getSurfaceName(shot)];
+ shot->addComponent<Visibility>(gameData.renderer, surface, SDL_Rect{0, 0, surface->w / 25},
+ radToDeg(angle));
+ layers[SHOTS_LAYER].emplace_back(shot);
+ }
+ visibility.angle = radToDeg(angle) + 90;
+ } else
+ attackSpeed.recharge();
}
}
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jun 15, 11:33 PM (2 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72163
Default Alt Text
(99 KB)

Event Timeline