// // Created by Tom Augier on 5/26/21. // Edited by Benjamin Henry on 5/26/21. // #include "Component/Collision/CollisionComponent.hpp" #include "System/Collision/CollisionSystem.hpp" #include "Map.hpp" #include #include #include #include #include namespace RAY3D = RAY::Drawables::Drawables3D; using namespace std::chrono_literals; namespace BBM { void MapGenerator::wallCollided(WAL::Entity &entity, const WAL::Entity &wall, CollisionComponent::CollidedAxis collidedAxis) { auto *mov = entity.tryGetComponent(); if (!mov) return; if (collidedAxis & CollisionComponent::CollidedAxis::X) mov->_velocity.x = 0; if (collidedAxis & CollisionComponent::CollidedAxis::Y) mov->_velocity.y = 0; if (collidedAxis & CollisionComponent::CollidedAxis::Z) mov->_velocity.z = 0; } void MapGenerator::wallDestroyed(WAL::Entity &entity, WAL::Wal &wal) { entity.scheduleDeletion(); auto &position = entity.getComponent().position; static std::map map = { {Bonus::BonusType::BOMBSTOCK, "assets/items/bombup"}, {Bonus::BonusType::SPEEDUP, "assets/items/speedup"}, {Bonus::BonusType::EXPLOSIONINC, "assets/items/fireup"} }; static std::vector> func = { &Bonus::BombUpBonus, &Bonus::SpeedUpBonus, &Bonus::ExplosionRangeBonus }; auto bonusType = Bonus::getRandomBonusType(); if (bonusType == Bonus::BonusType::NOTHING) return; if (!map.contains(bonusType)) return; wal.getScene()->scheduleNewEntity("Bonus") .addComponent(position) .addComponent(1, [](WAL::Entity &entity, WAL::Wal &wal) { entity.scheduleDeletion(); }) .addComponent(position.y) .addComponent([](WAL::Entity &bonus, const WAL::Entity &player, CollisionComponent::CollidedAxis axis) { bonus.scheduleDeletion(); }, func[bonusType - 1], 0.5, .5) .addComponent(5s, [](WAL::Entity &bonus, WAL::Wal &wal){ bonus.scheduleDeletion(); }) .addComponent(map.at(bonusType) + ".obj", false, std::make_pair(MAP_DIFFUSE, "assets/items/items.png")); } const std::string MapGenerator::assetsPath = "./assets/"; const std::string MapGenerator::wallAssetsPath = MapGenerator::assetsPath + "map/"; const std::string MapGenerator::imageExtension = ".png"; const std::string MapGenerator::objExtension = ".obj"; const std::string MapGenerator::breakableWallPath = MapGenerator::wallAssetsPath + "breakable_wall"; const std::string MapGenerator::unbreakableWallPath = MapGenerator::wallAssetsPath + "unbreakable_wall"; const std::string MapGenerator::floorPath = MapGenerator::wallAssetsPath + "floor"; const std::string MapGenerator::secondFloorPath = MapGenerator::wallAssetsPath + "upper_floor"; const std::string MapGenerator::stairsPath = MapGenerator::wallAssetsPath + "stairs"; const std::string MapGenerator::bumperPath = MapGenerator::wallAssetsPath + "bumper"; const std::string MapGenerator::holePath = MapGenerator::wallAssetsPath + "hole"; const std::string MapGenerator::secondFloorHolePath = MapGenerator::secondFloorPath + "_hole"; void MapGenerator::generateUnbreakableBlock(int width, int height, std::shared_ptr scene) { static const std::string unbreakableObj = unbreakableWallPath + objExtension; static const std::string unbreakablePng = unbreakableWallPath + imageExtension; for (int i = 0; i < width + 1; i++) { for (int j = 0; j < height + 1; j++) { if (!(i % 2) && !(j % 2)) { scene->addEntity("Unbreakable Wall") .addComponent(i, 0, j) .addComponent>() .addComponent( WAL::Callback(), &MapGenerator::wallCollided, 0.25, .75) .addComponent(unbreakableObj, false, std::make_pair(MAP_DIFFUSE, unbreakablePng)); } } } } void MapGenerator::generateWall(int width, int height, std::shared_ptr scene) { static const std::string unbreakableObj = unbreakableWallPath + objExtension; static const std::string unbreakablePnj = unbreakableWallPath + imageExtension; for (int i = 0; i < height; i++) { scene->addEntity("Bomb stopper") .addComponent(-1, 0, i) .addComponent>(); scene->addEntity("Bomb stopper") .addComponent(width + 1, 0, i) .addComponent>(); } for (int i = 0; i < width; i++) { scene->addEntity("Bomb stopper") .addComponent(i, 0, -1) .addComponent>(); scene->addEntity("Bomb stopper") .addComponent(i, 0, height + 1) .addComponent>(); } scene->addEntity("Bottom Wall") .addComponent(Vector3f((width + 1) / 2, 0, -1)) .addComponent( WAL::Callback(), &MapGenerator::wallCollided, Vector3f(-(width + 1) / 2 , 0.25, 0.25), Vector3f(width + 1, 2, 0.75)) .addComponent(unbreakableObj, false, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(width + 3, 1, 1)); scene->addEntity("Upper Wall") .addComponent(Vector3f((width + 1) / 2, 0, height + 1)) .addComponent( WAL::Callback(), &MapGenerator::wallCollided, Vector3f(-(width + 1) / 2 , 0.25, 0.25), Vector3f(width + 1, 2, 0.75)) .addComponent(unbreakableObj, false, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(width + 3, 1, 1)); scene->addEntity("Left Wall") .addComponent(Vector3f(width + 1, 0, height / 2)) .addComponent( WAL::Callback(), &MapGenerator::wallCollided, Vector3f(0.25, 0.25, -(height + 1) / 2 ), Vector3f(0.75, 2, height + 1)) .addComponent(unbreakableObj, false, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(1, 1, height + 1)); scene->addEntity("Right Wall") .addComponent(Vector3f(-1, 0, height / 2)) .addComponent( WAL::Callback(), &MapGenerator::wallCollided, Vector3f(0.25, 0.25, -(height + 1) / 2 ), Vector3f(0.75, 2, height + 1)) .addComponent(unbreakableObj, false, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(1, 1, height + 1)); } void MapGenerator::generateFloor(MapBlock map, int width, int height, std::shared_ptr scene) { static const std::string floorObj = floorPath + objExtension; static const std::string floorPng = floorPath + imageExtension; for (int i = 0; i < width + 1; i++) { for (int j = 0; j < height + 1; j++) { if (map[std::make_tuple(i, 0, j)] != HOLE && map[std::make_tuple(i, -1, j)] != BUMPER) scene->addEntity("Floor") .addComponent(Vector3f(i, -1, j)) .addComponent(floorObj, false, std::make_pair(MAP_DIFFUSE, floorPng)); } } } void MapGenerator::createElement(Vector3f coords, std::shared_ptr scene, BlockType blockType) { std::map elements = { {BREAKABLE, &createBreakable}, {UNBREAKABLE, &createUnbreakable}, {HOLE, &createHole}, {FLOOR, &createFloor}, {BUMPER, &createBumper}, {UPPERFLOOR, &createUpperFloor}, }; if (blockType == NOTHING || blockType == SPAWNER) return; auto element = elements.at(blockType); element(coords, std::move(scene)); } void MapGenerator::createBreakable(Vector3f coords, std::shared_ptr scene) { static const std::string breakableObj = breakableWallPath + objExtension; static const std::string breakablePng = breakableWallPath + imageExtension; scene->addEntity("Breakable Block") .addComponent(coords) .addComponent>() .addComponent(1, &MapGenerator::wallDestroyed) .addComponent( WAL::Callback(), &MapGenerator::wallCollided, 0.25, .75) .addComponent(breakableObj, false, std::make_pair(MAP_DIFFUSE, breakablePng)); } void MapGenerator::createFloor(Vector3f coords, std::shared_ptr scene) { static const std::string floorObj = floorPath + objExtension; static const std::string floorPng = floorPath + imageExtension; scene->addEntity("Floor") .addComponent(Vector3f(coords)) //.addComponent(1) .addComponent(floorObj, false, std::make_pair(MAP_DIFFUSE, floorPng)); } void MapGenerator::createUpperFloor(Vector3f coords, std::shared_ptr scene) { static const std::string floorObj = secondFloorPath + objExtension; static const std::string floorPng = secondFloorPath + imageExtension; scene->addEntity("Upper Floor") .addComponent(Vector3f(coords)) .addComponent(floorObj, false, std::make_pair(MAP_DIFFUSE, floorPng)); } void MapGenerator::createUnbreakable(Vector3f coords, std::shared_ptr scene) { static const std::string UnbreakableObj = unbreakableWallPath + objExtension; static const std::string UnbreakablePng = unbreakableWallPath + imageExtension; scene->addEntity("Unbreakable Block") .addComponent(coords) .addComponent>() .addComponent( WAL::Callback(), &MapGenerator::wallCollided, 0.25, .75) .addComponent(UnbreakableObj, false, std::make_pair(MAP_DIFFUSE, UnbreakablePng)); } void MapGenerator::createHole(Vector3f coords, std::shared_ptr scene) { static const std::string holeObj = holePath + objExtension; static const std::string holePng = holePath + imageExtension; static const std::string secondFloorObj = secondFloorHolePath + objExtension; static const std::string secondFloorPng = secondFloorHolePath + imageExtension; WAL::Entity &holeEntity = scene->addEntity("Hole Block"); holeEntity.addComponent(Vector3f(coords.x, coords.y - 1, coords.z)); if (coords.y == 0) holeEntity.addComponent(holeObj, false, std::make_pair(MAP_DIFFUSE, holePng)); else holeEntity.addComponent(secondFloorObj, false, std::make_pair(MAP_DIFFUSE, secondFloorPng)); /*.addComponent([](WAL::Entity &other, const WAL::Entity &entity) { if (other.hasComponent()) { auto &health = other.getComponent(); health.takeDmg(health.getHealthPoint()); } }, [](WAL::Entity &other, const WAL::Entity &entity){}); */ } void MapGenerator::createBumper(Vector3f coords, std::shared_ptr scene) { static const std::string bumperObj = bumperPath + objExtension; static const std::string bumperPng = bumperPath + imageExtension; scene->addEntity("Bumper Block") .addComponent(Vector3f(coords.x, coords.y, coords.z)) .addComponent(bumperObj, false, std::make_pair(MAP_DIFFUSE, bumperPng)); /* .addComponent([](const WAL::Entity &entity, WAL::Entity &other) { if (other.hasComponent()) { auto &movable = other.getComponent(); movable.addForce(Vector3f(0, 5, 0)); } }); */ } bool MapGenerator::isCloseToBlockType(std::map, BlockType> map, int x, int y, int z, BlockType blockType) { return (map[std::make_tuple(x - 1, y, z)] == blockType || map[std::make_tuple(x + 1, y, z)] == blockType || map[std::make_tuple(x, y, z + 1)] == blockType || map[std::make_tuple(x, y, z - 1)] == blockType); } MapGenerator::BlockType MapGenerator::getRandomBlockType() { double rnd = static_cast(std::rand()) / RAND_MAX; if (rnd > 0.95) return HOLE; if (rnd > 0.25) return BREAKABLE; return NOTHING; } MapGenerator::MapBlock MapGenerator::createHeight(MapBlock map, int width, int height) { double rnd = static_cast(std::rand()) / RAND_MAX; if (rnd > 0.60) { for (int i = 0; i < width + 1; i++) { map[std::make_tuple(i, 1, height)] = map[std::make_tuple(i, 0, height)]; map[std::make_tuple(i, 0, height)] = UPPERFLOOR; map[std::make_tuple(i, 1, 0)] = map[std::make_tuple(i, 0, 0)]; map[std::make_tuple(i, 0, 0)] = UPPERFLOOR; } map[std::make_tuple(0, -1, height - 1)] = BUMPER; map[std::make_tuple(0, -1, 1)] = BUMPER; map[std::make_tuple(width, -1, height - 1)] = BUMPER; map[std::make_tuple(width, -1, 1)] = BUMPER; map[std::make_tuple(width / 2, -1, height - 1)] = BUMPER; map[std::make_tuple(width / 2, -1, 1)] = BUMPER; } if (rnd > 0.30) { for (int i = width / 2 - width / 4; i < width / 2 + width / 4 + 1; i++) { for (int j = height / 2 - height / 4; j < height / 2 + height / 4 + 1; j++) { if (map[std::make_tuple(i, 0, j)] == FLOOR) continue; map[std::make_tuple(i, 1, j)] = map[std::make_tuple(i, 0, j)]; map[std::make_tuple(i, 0, j)] = UPPERFLOOR; } } map[std::make_tuple(width / 2 - width / 8, -1, height / 2 + height / 4 + 1)] = BUMPER; map[std::make_tuple(width / 2 + width / 8, -1, height / 2 - height / 4 - 1)] = BUMPER; map[std::make_tuple(width / 2 - width / 4 - 1, -1, height / 2 - height / 8)] = BUMPER; map[std::make_tuple(width / 2 + width / 4 + 1, -1, height / 2 + height / 8)] = BUMPER; } return map; } MapGenerator::MapBlock MapGenerator::createSpawner(MapBlock map, int width, int height) { map[std::make_tuple(0, 0, 0)] = SPAWNER; map[std::make_tuple(width, 0, 0)] = SPAWNER; map[std::make_tuple(0, 0, height)] = SPAWNER; map[std::make_tuple(width, 0, height)] = SPAWNER; return map; } MapGenerator::MapBlock MapGenerator::cleanBreakable(MapBlock map, int width, int height) { for (int i = 0; i < width + 1; i++) for (int j = 0; j < height; j++) { if (map[std::make_tuple(i, 0, j)] == BREAKABLE && map[std::make_tuple(i, -1, j)] == BUMPER) map[std::make_tuple(i, 0, j)] = NOTHING; } return (map); } MapGenerator::MapBlock MapGenerator::createMap(int width, int height) { MapBlock map; width = width % 2 ? width + 1 : width; height = height % 2 ? height + 1 : height; for (int i = 0; i < width; i++) for (int j = 0; j < height; j++) map[std::make_tuple(i, 0, j)] = NOTHING; map = createSpawner(map, width, height); for (int i = 0; i < width + 1; i++) { for (int j = 0; j < height + 1; j++) { if (map[std::make_tuple(i, 0, j)] == SPAWNER) continue; if (isCloseToBlockType(map, i, 0, j, SPAWNER)) { map[std::make_tuple(i, 0, j)] = NOTHING; } else { map[std::make_tuple(i, 0, j)] = getRandomBlockType(); } if (map[std::make_tuple(i, 0, j)] == UNBREAKABLE && isCloseToBlockType(map, i, 0, j, UNBREAKABLE)) map[std::make_tuple(i, 0, j)] = BREAKABLE; } } for (int i = 0; i < width + 1; i++) for (int j = 0; j < height + 1; j++) if (!((i + 1) % 2) && !((j + 1) % 2)) map[std::make_tuple(i, 0, j)] = UNBREAKABLE; map = createHeight(map, width, height); map = cleanBreakable(map, width, height); return (map); } void MapGenerator::loadMap(int width, int height, MapBlock map, const std::shared_ptr &scene) { generateWall(width, height, scene); generateFloor(map, width, height, scene); for (int x = 0; x < width + 1; x++) for (int z = 0; z < height + 1; z++) for (int y = -1; y < 1 + 1; y++) createElement(Vector3f(x, y, z), scene, map[std::make_tuple(x, y, z)]); } } // namespace BBM