#include "scene.hpp" #include "interpolation.hpp" #include "bat.hpp" #include "dragon.hpp" #include "terrain.hpp" #include "projectile.hpp" #include "sapin.hpp" #include "settings.hpp" using namespace cgp; void scene_structure::initialize() { //CAMERA camera_control.initialize(inputs, window); // Give access to the inputs and window global state to the camera controler //First person camera_control.camera_model.position_camera = { 0,0,evaluate_terrain_height(0,0)+10}; camera_control.camera_model.set_rotation_axis({ 0,0,1 }); global_frame.initialize_data_on_gpu(mesh_primitive_frame()); //SKYBOX //skybox_debug.png for debugging image_structure image_skybox_template = image_load_file("assets/skybox2.jpg"); std::vector<image_structure> image_grid = image_split_grid(image_skybox_template, 4, 3); image_structure image_skybox_template2 = image_load_file("assets/skyboxNight.jpeg"); std::vector<image_structure> image_grid2 = image_split_grid(image_skybox_template2, 4, 3); skybox.initialize_data_on_gpu(); //x neg, x pos, y neg, y pos, z neg, z pos skybox.texture.initialize_cubemap_on_gpu(image_grid[7].rotate_90_degrees_counterclockwise(), image_grid[1].rotate_90_degrees_clockwise(), image_grid[4].rotate_90_degrees_clockwise().rotate_90_degrees_clockwise(), image_grid[10], image_grid[3], image_grid[5].rotate_90_degrees_clockwise().rotate_90_degrees_clockwise()); skybox.texture2.initialize_cubemap_on_gpu(image_grid2[7].rotate_90_degrees_counterclockwise(), image_grid2[1].rotate_90_degrees_clockwise(), image_grid2[4].rotate_90_degrees_clockwise().rotate_90_degrees_clockwise(), image_grid2[10], image_grid2[3], image_grid2[5].rotate_90_degrees_clockwise().rotate_90_degrees_clockwise()); //TERRAIN int N_terrain_samples = 500; mesh const terrain_mesh = create_terrain_mesh(N_terrain_samples); terrain.initialize_data_on_gpu(terrain_mesh); // terrain.material.color = { 0.6f,0.85f,0.5f }; terrain de couleur de base verte terrain.material.color = { 1,1,1 }; terrain.material.phong.specular = 0.0f; // non-specular terrain material terrain.shader.load(project::path + "shaders/mesh_multi_texture/mesh_multi_texture.vert.glsl", project::path + "shaders/mesh_multi_texture/mesh_multi_texture.frag.glsl"); terrain.texture.load_and_initialize_texture_2d_on_gpu(project::path + "assets/grass.jpg", GL_REPEAT, GL_MIRRORED_REPEAT); terrain.supplementary_texture["image_texture_rock"].load_and_initialize_texture_2d_on_gpu(project::path + "assets/rocks3.jpg", GL_REPEAT, GL_MIRRORED_REPEAT); terrain.supplementary_texture["image_texture_snow"].load_and_initialize_texture_2d_on_gpu(project::path + "assets/snow.jpg", GL_REPEAT, GL_MIRRORED_REPEAT); //OBJECTS //GRASS grass_position = generate_positions_on_terrain(num_grass()); mesh quadrangle_mesh; quadrangle_mesh.position = { {0,0,0},{1, 0, 0}, {1,0,1}, {0, 0,1} }; quadrangle_mesh.uv = { {0,0},{1,0}, {1,1}, {0,1} }; quadrangle_mesh.connectivity = { {0,1,2}, {0,2,3} }; quadrangle_mesh.fill_empty_field(); // (fill with some default values the other buffers (colors, normals) that we didn't filled before) // Convert the mesh structure into a mesh_drawable structure grass.initialize_data_on_gpu(quadrangle_mesh); grass.texture.load_and_initialize_texture_2d_on_gpu(project::path + "assets/grass.png", GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER); //CROSSHAIR mesh crosshair_mesh; crosshair_mesh.position = { {-1,-1,-1},{1, -1, -1}, {1,-1,1}, {-1, -1, 1} }; for (int i = 0; i < 4; i++) crosshair_mesh.position[i] *= 0.05f; crosshair_mesh.uv = { {0,0},{1,0}, {1,1}, {0,1} }; crosshair_mesh.connectivity = { {0,1,2}, {0,2,3} }; crosshair_mesh.fill_empty_field(); crosshair.initialize_data_on_gpu(crosshair_mesh); crosshair.texture.load_and_initialize_texture_2d_on_gpu(project::path + "assets/crosshair.png", GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER); //BATS & DRAGONS bats.initialize_bats(); dragons.initialize_dragons(); vec3 bat_pos1 = { 0,0,evaluate_terrain_height(0,0) + 20 }; float bat_size1 = 0.2f; numarray<vec3> bat_keypos1 = { {-1,1,0}, {0,1,0}, {1,1,0}, {1,2,0}, {2,2,0}, {2,2,1}, {2,0,1.5}, {1.5,-1,1}, {1.5,-1,0}, {1,-1,0}, {0,-0.5,0}, {-1,1,0} }; numarray<float> bat_keytimes1 = { 0.0f, 1.0f, 2.0f, 2.5f, 3.0f, 3.5f, 3.75f, 4.5f, 5.0f, 6.0f, 7.0f, 8.0f }; bats.add_bat(bat_pos1, bat_size1, bat_keypos1, bat_keytimes1); vec3 dragon_pos = { 5,5,evaluate_terrain_height(0,0) + 10 }; float dragon_size = 0.5f; numarray<vec3> dragon_keypos = { {terrain_length()/2, terrain_length() / 2, evaluate_terrain_height(terrain_length() / 2,terrain_length() / 2)}, {-2,0,0}, {-1.6,1,0}, {-1.3,1.3,0}, {-0.8,1.8,0}, {0,2,0}, {0.8,1.8,0}, {1.3,1.3,0}, {1.6,1,0}, {2,0,0}, {1.3,-1.3,0}, {0,-2,0}, {-1.3,-1.3,0}}; numarray<float> dragon_keytimes = { 0.0f, 10.0f, 11.0f, 12.0f, 12.5f, 13.0f, 13.5f, 13.75f, 14.5f, 15.0f, 16.0f, 17.0f, 18.0f }; dragons.add_dragon(dragon_pos, dragon_size, dragon_keypos, dragon_keytimes); //PROJECTILES projectiles.initialize(); //PROJECTILE MENU menu_icons.resize(5); image_structure electroball = image_split_grid(image_load_file("assets/electroball.png"), 4, 2)[5]; std::vector<image_structure> icons = { projectiles.fire_grid[0], projectiles.ice_grid[3], projectiles.rock_grid[0], electroball, projectiles.water_grid[0] }; mesh menu_icon_mesh; menu_icon_mesh.position = { {-1,-1,-1},{1, -1, -1}, {1,-1,1}, {-1, -1, 1} }; float factor = 0.2f; for (int i = 0; i < 4; i++) menu_icon_mesh.position[i] = menu_icon_mesh.position[i] * factor - vec3{ 1 - factor, 0, 1 - 2*factor } + vec3{ 0.04,0,0 }; menu_icon_mesh.uv = { {0,0},{1,0}, {1,1}, {0,1} }; menu_icon_mesh.connectivity = { {0,1,2}, {0,2,3} }; menu_icon_mesh.fill_empty_field(); menu_frame.initialize_data_on_gpu(menu_icon_mesh); menu_frame.texture.load_and_initialize_texture_2d_on_gpu(project::path + "assets/select_rect.png", GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER); for (int i = 0; i < 4; i++) menu_icon_mesh.position[i] -= vec3{ 0.04,0,0 }; for (int icon = 0; icon < 5; icon++) { menu_icons[icon].initialize_data_on_gpu(menu_icon_mesh); menu_icons[icon].texture.initialize_texture_2d_on_gpu(icons[icon], GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER); for (int i = 0; i < 4; i++) menu_icon_mesh.position[i] += vec3{ 2.2 * factor, 0, 0 }; } //SAPIN tree_position = generate_positions_on_terrain(num_trees()); sapin1.initialize_sapin(); sapin1.sapin["Trunk"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0 }, Pi / 2); //Initialise hitbox sphere (PLEASE STORE THE HITBOX_SPHERE IN HITBOX!!!) hitbox_sphere.initialize_data_on_gpu(mesh_primitive_sphere(1)); //HEALTHBAR mesh background_mesh = mesh_primitive_quadrangle({ 0,0,0 }, { 1.1, 0, 0 }, { 1.1,0,0.4 }, { 0, 0,0.4 }); mesh death_mesh = mesh_primitive_quadrangle({ 0.05,-0.005,0.05 }, { 1.05, -0.005, 0.05 }, { 1.05,-0.005,0.35 }, { 0.05, -0.005,0.35 }); mesh health_mesh = mesh_primitive_quadrangle({ 0.05,-0.01,0.05 }, { 1.05, -0.01, 0.05 }, { 1.05,-0.01,0.35 }, { 0.05, -0.01,0.35 }); mesh_drawable background; background.initialize_data_on_gpu(background_mesh); mesh_drawable health; health.initialize_data_on_gpu(health_mesh); health.material.color = {0,1,0}; mesh_drawable death; death.initialize_data_on_gpu(death_mesh); death.material.color = { 1,0,0 }; healthbar.add(background, "Background"); healthbar.add(health, "Health", "Background"); healthbar.add(death, "Death", "Background"); //SMOKE image_structure smoke_animation; smoke_animation = image_load_file("assets/smoke.png"); smoke_grid = image_split_grid(smoke_animation, 12, 6); cgp::mesh sphere_mesh = mesh_primitive_sphere(15); smoke.initialize_data_on_gpu(sphere_mesh); //DRAGON FIRE mesh fire_mesh = mesh_primitive_cone(3, 15, {0,0,0}, {-1,0,0}, false); image_structure fire_breath_animation; fire_breath_animation = image_load_file("assets/dragon/fire.png"); fire_breath_grid = image_split_grid(fire_breath_animation, 6, 5); fire_breath.initialize_data_on_gpu(fire_mesh); fire_breath.material.color = {1,1,1}; } void scene_structure::display_frame() { // Update the current time timer.update(); glDepthMask(GL_FALSE); draw(skybox, day_time(), environment); glDepthMask(GL_TRUE); //Walk or Fly if (!gui.fly) { vec3 eye_level = camera_control.camera_model.position_camera; eye_level[2] = evaluate_terrain_height(eye_level[0], eye_level[1]) + 0.75; camera_control.camera_model.position_camera = eye_level; } // Default light (current position of camera) environment.light = camera_control.camera_model.position(); if (gui.display_frame) draw(global_frame, environment); draw(terrain, environment); if (gui.display_wireframe) draw_wireframe(terrain, environment); //Trees with render distance for (int i = 0; i < num_trees(); i++) { if (norm(tree_position[i]-camera_control.camera_model.position_camera) < 75 ) { sapin1.sapin["Trunk"].transform_local.translation = tree_position[i]; sapin1.sapin.update_local_to_global_coordinates(); draw(sapin1.sapin, environment); } } display_bats(); display_dragons(); display_grass(); //Important to draw grass before projectiles (otherwise you see them through projectiles) display_projectiles(); display_crosshair(); if(camera_control.inputs->keyboard.is_pressed(GLFW_KEY_Q)) projectile_menu(); } void scene_structure::display_bats() { bats.update_mvt(); for (int i = 0; i < bats.N; i++) { if (!bats.bats_prop[i].isdead) { //Wing animation bats.bat_mesh["Bat wing left1"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0 }, 0.5 * cos(5 * bats.bats_prop[i].timer_mvt.t)); bats.bat_mesh["Bat wing right1"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0 }, -0.5 * cos(5 * bats.bats_prop[i].timer_mvt.t)); //Rescale bats.bat_mesh["Bat base"].drawable.model.scaling = bats.bats_prop[i].size; bats.bat_mesh["Bat wing left1"].drawable.model.scaling = bats.bats_prop[i].size; bats.bat_mesh["Bat wing right1"].drawable.model.scaling = bats.bats_prop[i].size; //Make sure wings are at the right distance bats.bat_mesh["Bat wing left1"].transform_local.translation = { -0.25f * bats.bats_prop[i].size, 0, 0 }; bats.bat_mesh["Bat wing right1"].transform_local.translation = { 0.25f * bats.bats_prop[i].size, 0, 0 }; //Orientation and position of the bat along the path bats.bats_prop[i].rot = rotation_transform::from_vector_transform({ 0,-1,0 }, normalize(bats.bats_prop[i].pos_futur - bats.bats_prop[i].pos)); bats.bat_mesh["Bat base"].transform_local.rotation = bats.bats_prop[i].rot; bats.bat_mesh["Bat base"].transform_local.translation = bats.bats_prop[i].pos; bats.bat_mesh.update_local_to_global_coordinates(); draw(bats.bat_mesh, environment); display_healthbar(bats.bats_prop[i].hp, bats.bats_prop[i].max_hp, bats.bats_prop[i].pos); if (gui.display_wireframe) { draw_wireframe(bats.bat_mesh, environment); } if (gui.display_hitbox) { display_hitbox(bats.bats_prop[i].bat_hitbox, bats.bats_prop[i].pos, bats.bats_prop[i].rot); } } else{ if (bats.bats_prop[i].death_time == -1) bats.bats_prop[i].death_time = timer.t; float since_death = timer.t - bats.bats_prop[i].death_time; if (since_death < 3) { display_death(bats.bats_prop[i].pos, bats.bats_prop[i].size * double(10+ since_death)/15, since_death*9); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); bats.bat_mesh["Bat base"].drawable.material.alpha = double(3 - since_death) / 4; bats.bat_mesh["Bat wing left1"].drawable.material.alpha = double(3 - since_death) / 4; bats.bat_mesh["Bat wing right1"].drawable.material.alpha = double(3 - since_death) / 4; bats.bat_mesh["Bat base"].transform_local.rotation = bats.bats_prop[i].rot; bats.bat_mesh["Bat base"].transform_local.translation = bats.bats_prop[i].pos; bats.bat_mesh.update_local_to_global_coordinates(); draw(bats.bat_mesh, environment); // Don't forget to re-activate the depth-buffer write glDepthMask(true); glDisable(GL_BLEND); } } } } void scene_structure::display_dragons() { dragons.update_mvt(); for (int i = 0; i < dragons.N; i++) { if (!dragons.dragons_prop[i].isdead) { //Wing animation dragons.dragon_mesh["Dragon wing left"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0.5 }, 0.5 * cos(5 * dragons.dragons_prop[i].timer_mvt.t)); dragons.dragon_mesh["Dragon wing right"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0.5 }, -0.5 * cos(5 * dragons.dragons_prop[i].timer_mvt.t)); //Mouth animation dragons.dragon_mesh["Dragon mouth"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0 }, 0.05 * cos(dragons.dragons_prop[i].timer_mvt.t)); //Start shooting fire at random if mouth open with proba 1/10 because it's calculated in every frame if (!dragons.dragons_prop[i].isfiring && cos(dragons.dragons_prop[i].timer_mvt.t) < -0.8) { if (rand_interval(0, 1) < 1.0/10) { dragons.dragons_prop[i].isfiring = true; dragons.dragons_prop[i].time_fire = 0; } } //Tail animation dragons.dragon_mesh["Dragon tailmiddle"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0.5 }, 0.05 * cos(2 * dragons.dragons_prop[i].timer_mvt.t)); dragons.dragon_mesh["Dragon tailend"].transform_local.rotation = rotation_transform::from_axis_angle({ 0.5,1,0.5 }, -0.01 * cos(2 * dragons.dragons_prop[i].timer_mvt.t)); //Rescale dragons.dragon_mesh["Dragon base"].drawable.model.scaling = dragons.dragons_prop[i].size; dragons.dragon_mesh["Dragon wing left"].drawable.model.scaling = dragons.dragons_prop[i].size; dragons.dragon_mesh["Dragon wing right"].drawable.model.scaling = dragons.dragons_prop[i].size; dragons.dragon_mesh["Dragon mouth"].drawable.model.scaling = dragons.dragons_prop[i].size; dragons.dragon_mesh["Dragon tailmiddle"].drawable.model.scaling = dragons.dragons_prop[i].size; dragons.dragon_mesh["Dragon tailend"].drawable.model.scaling = dragons.dragons_prop[i].size; //Make sure wings are at the right distance dragons.dragon_mesh["Dragon wing left"].transform_local.translation = { 0, -0.3f * dragons.dragons_prop[i].size, 0 }; dragons.dragon_mesh["Dragon wing right"].transform_local.translation = { 0, 0.3f * dragons.dragons_prop[i].size, 0 }; //Orientation and position of the bat along the path dragons.dragons_prop[i].rot = rotation_transform::from_vector_transform({ 1,0,0 }, normalize(dragons.dragons_prop[i].pos_futur - dragons.dragons_prop[i].pos)); dragons.dragon_mesh["Dragon base"].transform_local.rotation = dragons.dragons_prop[i].rot; dragons.dragon_mesh["Dragon base"].transform_local.translation = dragons.dragons_prop[i].pos; dragons.dragon_mesh.update_local_to_global_coordinates(); draw(dragons.dragon_mesh, environment); display_healthbar(dragons.dragons_prop[i].hp, dragons.dragons_prop[i].max_hp, dragons.dragons_prop[i].pos); if (gui.display_wireframe) { draw_wireframe(dragons.dragon_mesh, environment); } if (gui.display_hitbox) { display_hitbox(dragons.dragons_prop[i].dragon_hitbox, dragons.dragons_prop[i].pos, dragons.dragons_prop[i].rot); } //Shoot fire if (dragons.dragons_prop[i].isfiring) { if (dragons.dragons_prop[i].time_fire < dragons.dragons_prop[i].duration_fire) { display_fire_breath(dragons.dragons_prop[i].pos, dragons.dragons_prop[i].rot, dragons.dragons_prop[i].time_fire, dragons.dragons_prop[i].duration_fire); dragons.dragons_prop[i].time_fire++; } else dragons.dragons_prop[i].isfiring = false; } } else { if (dragons.dragons_prop[i].death_time == -1) dragons.dragons_prop[i].death_time = timer.t; float since_death = timer.t - dragons.dragons_prop[i].death_time; if (since_death < 3) { display_death(dragons.dragons_prop[i].pos, dragons.dragons_prop[i].size * 0.5 * double(10+ since_death)/15, since_death*9); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); dragons.dragon_mesh["Dragon base"].drawable.material.alpha = double(3 - since_death)/4; dragons.dragon_mesh["Dragon mouth"].drawable.material.alpha = double(3 - since_death)/4; dragons.dragon_mesh["Dragon wing left"].drawable.material.alpha = double(3 - since_death)/4; dragons.dragon_mesh["Dragon wing right"].drawable.material.alpha = double(3 - since_death)/4; dragons.dragon_mesh["Dragon tailmiddle"].drawable.material.alpha = double(3 - since_death)/4; dragons.dragon_mesh["Dragon tailend"].drawable.material.alpha = double(3 - since_death)/4; dragons.dragon_mesh["Dragon base"].transform_local.rotation = dragons.dragons_prop[i].rot; dragons.dragon_mesh["Dragon base"].transform_local.translation = dragons.dragons_prop[i].pos; dragons.dragon_mesh.update_local_to_global_coordinates(); draw(dragons.dragon_mesh, environment); // Don't forget to re-activate the depth-buffer write glDepthMask(true); glDisable(GL_BLEND); } } } } void scene_structure::display_fire_breath(vec3 pos, rotation_transform rot, int t, int duration) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); fire_breath.texture.initialize_texture_2d_on_gpu(fire_breath_grid[5 * (t/15) + (t/3)%5], GL_REPEAT, GL_REPEAT); fire_breath.model.scaling_xyz = { double(t + 20) / (duration + 20),1,1 }; fire_breath.model.rotation = rot; fire_breath.model.translation = pos + 20 * double(t + 20) / (duration + 20) * rot * vec3(1, 0, 0); draw(fire_breath, environment); glDepthMask(true); glDisable(GL_BLEND); } void scene_structure::display_hitbox(hitbox H, vec3 shift, rotation_transform rot) { for (int i = 0; i < H.N; i++) { hitbox_sphere.model.scaling = H.r[i]; hitbox_sphere.model.translation = rot * H.center[i] + shift; draw_wireframe(hitbox_sphere, environment); } } void scene_structure::display_healthbar(int hp, int max_hp, vec3 pos) { auto const& camera = camera_control.camera_model; // Placement : towards camera healthbar["Background"].transform_local.translation = pos + (1 / norm(camera.position() - pos)) * (camera.position() - pos) + vec3(0,0,-0.5); // Health levels healthbar["Health"].drawable.model.scaling_xyz = { double(hp)/max_hp, 1, 1}; // Healthbar facing camera rotation_transform R = rotation_transform::from_frame_transform({ 1,0,0 }, { 0,0,1 }, camera.right(), camera.up()); healthbar["Background"].transform_local.rotation = R; healthbar.update_local_to_global_coordinates(); draw(healthbar, environment); } void scene_structure::display_grass() { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); auto const& camera = camera_control.camera_model; vec3 const right = camera.right(); for (int i = 0; i < num_grass(); i++) { grass.model.translation = grass_position[i]; rotation_transform R = rotation_transform::from_frame_transform({ 1,0,0 }, { 0,0,1}, right, {0,0,1}); grass.model.rotation = R; draw(grass, environment); } glDepthMask(true); glDisable(GL_BLEND); } void scene_structure::display_crosshair() { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); auto const& camera = camera_control.camera_model; crosshair.model.translation = camera.position_camera + camera.front(); rotation_transform R = rotation_transform::from_frame_transform({ 1,0,0 }, { 0,0,1 }, camera.right(), camera.up()); crosshair.model.rotation = R; draw(crosshair, environment); glDepthMask(true); glDisable(GL_BLEND); } void scene_structure::display_gui() { ImGui::Checkbox("Frame", &gui.display_frame); ImGui::Checkbox("Wireframe", &gui.display_wireframe); ImGui::Checkbox("Hitbox", &gui.display_hitbox); ImGui::Checkbox("Fly", &gui.fly); ImGui::SliderFloat("K", &gui.k, 0.0f, 10.0f); ImGui::SliderFloat("Speed", &gui.speed, 0.0f, 10.0f); } void scene_structure::display_projectiles() { vec3 const right = camera_control.camera_model.right(); rotation_transform R = rotation_transform::from_frame_transform({ cos(ball_turn_speed * timer.t + 90),sin(ball_turn_speed * timer.t + 90),0 }, { 0,0,1 }, right, { 0,0,1 }); rotation_transform R2 = rotation_transform::from_frame_transform({ cos(ball_turn_speed * timer.t -90), sin(ball_turn_speed * timer.t - 90),0 }, { 0,0,1 }, right, { 0,0,1 }); //Permet d'avoir une vitesse de jeu ind�pendante des fps, contrairement � timer.scale delta_sim_time = timer.t - prev_sim_time; prev_sim_time = timer.t; //Plus de pr�cision pour la collision int iter_num = 40; for(int iter=0; iter<iter_num; iter++){ projectiles.simulate(delta_sim_time / iter_num); for (int i = 0; i < projectiles.N; i++) { if (projectiles.projectiles_prop[i].is_active) { for (int j = 0; j < bats.N; j++) { if (bats.bats_prop[j].bat_hitbox.is_in_hitbox(projectiles.projectiles_prop[i].pos, bats.bats_prop[j].pos, bats.bats_prop[j].rot)) { projectiles.projectiles_prop[i].is_active = false; bats.bats_prop[j].hp--; if (bats.bats_prop[j].hp == 0) bats.bats_prop[j].isdead = true; } } for (int j = 0; j < dragons.N; j++) { if (dragons.dragons_prop[j].dragon_hitbox.is_in_hitbox(projectiles.projectiles_prop[i].pos, dragons.dragons_prop[j].pos, dragons.dragons_prop[j].rot)) { projectiles.projectiles_prop[i].is_active = false; dragons.dragons_prop[j].hp--; if (dragons.dragons_prop[j].hp == 0) dragons.dragons_prop[j].isdead = true; } } } } } //Animation des projectiles en fonction du type for (int i = 0; i < projectiles.N; i++) { projectiles.mesh.model.translation = projectiles.projectiles_prop[i].pos; projectiles.mesh.material.color = projectiles.projectiles_prop[i].color; draw(projectiles.mesh, environment); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); if (projectiles.projectiles_prop[i].elemental_type == projectile::projectile_type::fire) { if (fmod(timer.t, ball_reset_speed) > 0.1) projectiles.projectiles_prop[i].change_animation = true; if (fmod(timer.t, ball_reset_speed) < 0.1 && projectiles.projectiles_prop[i].change_animation) { projectiles.projectiles_prop[i].change_animation = false; projectiles.fireball.texture.update(projectiles.fire_grid[std::rand()%12]); } projectiles.fireball.model.translation = projectiles.projectiles_prop[i].pos; draw(projectiles.fireball, environment); projectiles.fireball.model.rotation = R; draw(projectiles.fireball, environment); projectiles.fireball.model.rotation = R2; draw(projectiles.fireball, environment); } else if (projectiles.projectiles_prop[i].elemental_type == projectile::projectile_type::water) { if (fmod(timer.t, ball_reset_speed) > 0.1) projectiles.projectiles_prop[i].change_animation = true; if (fmod(timer.t, ball_reset_speed) < 0.1 && projectiles.projectiles_prop[i].change_animation) { projectiles.projectiles_prop[i].change_animation = false; projectiles.waterball.texture.update(projectiles.water_grid[std::rand() % 6]); } projectiles.waterball.model.translation = projectiles.projectiles_prop[i].pos; draw(projectiles.waterball, environment); projectiles.waterball.model.rotation = R; draw(projectiles.waterball, environment); projectiles.waterball.model.rotation = R2; draw(projectiles.waterball, environment); } else if (projectiles.projectiles_prop[i].elemental_type == projectile::projectile_type::ice) { if (fmod(timer.t, ball_reset_speed) > 0.1) projectiles.projectiles_prop[i].change_animation = true; if (fmod(timer.t, ball_reset_speed) < 0.1 && projectiles.projectiles_prop[i].change_animation) { projectiles.projectiles_prop[i].change_animation = false; projectiles.iceball.texture.update(projectiles.ice_grid[std::rand() % 6]); } projectiles.iceball.model.translation = projectiles.projectiles_prop[i].pos; draw(projectiles.iceball, environment); projectiles.iceball.model.rotation = R; draw(projectiles.iceball, environment); projectiles.iceball.model.rotation = R2; draw(projectiles.iceball, environment); } else if (projectiles.projectiles_prop[i].elemental_type == projectile::projectile_type::electric) { projectiles.electroball.model.translation = projectiles.projectiles_prop[i].pos; draw(projectiles.electroball, environment); projectiles.electroball.model.rotation = R; draw(projectiles.electroball, environment); projectiles.electroball.model.rotation = R2; draw(projectiles.electroball, environment); } else if (projectiles.projectiles_prop[i].elemental_type == projectile::projectile_type::rock) { projectiles.rockball.model.translation = projectiles.projectiles_prop[i].pos; draw(projectiles.rockball, environment); projectiles.rockball.model.rotation = R; draw(projectiles.rockball, environment); projectiles.rockball.model.rotation = R2; draw(projectiles.rockball, environment); } glDepthMask(true); glDisable(GL_BLEND); } } void scene_structure::display_death(vec3 pos, double size, int t) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); smoke.texture.initialize_texture_2d_on_gpu(smoke_grid[t], GL_REPEAT, GL_REPEAT); smoke.model.translation = pos; smoke.model.scaling = size; smoke.model.rotation = rotation_transform::from_frame_transform({ cos(smoke_turn_speed * timer.t + 90),sin(smoke_turn_speed * timer.t + 90),0 }, { 0,0,1 }, camera_control.camera_model.right(), {0,0,1}); draw(smoke, environment); smoke.model.scaling = size/3; smoke.model.translation = pos + vec3(-1, -1, 0.5); draw(smoke, environment); smoke.model.translation = pos + vec3(0.5, -0.5, 1); draw(smoke, environment); smoke.model.translation = pos + vec3(-0.5, 0.5, 0.5); draw(smoke, environment); smoke.model.translation = pos + vec3(1, 0.5, -0.5); draw(smoke, environment); glDepthMask(true); glDisable(GL_BLEND); } void scene_structure::projectile_menu() { //Moves icon and changes projectile type, menu_change makes sure one click corresponds to one change if (camera_control.inputs->mouse.click.right) { if (!menu_change) { current_menu = (current_menu + 1) % 5; std::cout << current_menu; menu_change = true; } } else { menu_change = false; } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); auto const& camera = camera_control.camera_model; for (int icon = 0; icon < 5; icon++) { menu_icons[icon].model.translation = camera.position_camera + 2*camera.front(); rotation_transform R = rotation_transform::from_frame_transform({ 1,0,0 }, { 0,0,1 }, camera.right(), camera.up()); menu_icons[icon].model.rotation = R; draw(menu_icons[icon], environment); } std::vector<float> shifts = { 0.08f, 0.44f, 0.83f, 1.23f, 1.65f }; menu_frame.model.translation = camera.position_camera + 1.8f*camera.front() + shifts[current_menu] * camera.right() + 0.06f * camera.up(); rotation_transform R = rotation_transform::from_frame_transform({ 1,0,0 }, { 0,0,1 }, camera.right(), camera.up()); menu_frame.model.rotation = R; draw(menu_frame, environment); glDepthMask(true); glDisable(GL_BLEND); } void scene_structure::mouse_move_event() { if (!inputs.keyboard.shift) camera_control.action_mouse_move(environment.camera_view); } void scene_structure::mouse_click_event() { if (camera_control.inputs->mouse.click.left){ projectiles.add_ball(camera_control.camera_model.position_camera + 2*camera_control.camera_model.front(), 20*camera_control.camera_model.front(), current_menu); } camera_control.action_mouse_click(environment.camera_view); } void scene_structure::keyboard_event() { camera_control.action_keyboard(environment.camera_view); if(camera_control.inputs->keyboard.shift) { projectiles.reset(); } } void scene_structure::idle_frame() { //parameters to make sure the player doesn't walk outside the map vec4 dir_h = { evaluate_terrain_height(camera_control.camera_model.position_camera.x - camera_control.camera_model.front().y * 0.1, camera_control.camera_model.position_camera.y + camera_control.camera_model.front().x * 0.1), evaluate_terrain_height(camera_control.camera_model.position_camera.x + camera_control.camera_model.front().y * 0.1, camera_control.camera_model.position_camera.y - camera_control.camera_model.front().x * 0.1), evaluate_terrain_height(camera_control.camera_model.position_camera.x - camera_control.camera_model.front().x * 0.1, camera_control.camera_model.position_camera.y - camera_control.camera_model.front().y * 0.1), evaluate_terrain_height(camera_control.camera_model.position_camera.x + camera_control.camera_model.front().x * 0.1, camera_control.camera_model.position_camera.y + camera_control.camera_model.front().y * 0.1) }; if (camera_control.inputs->keyboard.ctrl) { camera_control.idle_frame(environment.camera_view, 10, gui.fly, dir_h); } else { camera_control.idle_frame(environment.camera_view, gui.speed, gui.fly, dir_h); } } float scene_structure::day_time() { return fmod(13+0.3*timer.t, 24); // Sends the time back in hours, starts at day (13pm) }