windmill-gint/src/scene_map.cpp

850 lines
21 KiB
C++

#include "scene_map.hpp"
extern Game game;
extern Windmill windmill;
// import des map
extern Map map_village;
extern Map map_interieur_forgeron;
// import des objets
extern Object chaumiere1;
extern Object panneau1;
extern Object forgeron1;
//----------------------------------------------------------------------------------------------------
// CONSTRUCTOR
//----------------------------------------------------------------------------------------------------
Scene_Map::Scene_Map()
{
// debug
show_repere = false;
show_coordinates = false;
// histoire
vue_horloge = false;
vue_panneau_moulin = false;
parle_avec_forgeron = false;
}
//----------------------------------------------------------------------------------------------------
// LAUNCH
//----------------------------------------------------------------------------------------------------
void Scene_Map::launch()
{
time_scene = 0;
load_map();
windmill.set_camera(&camera);
// histoire
// ...
}
void Scene_Map::load_map()
{
// mise a jour de la map pour la scene
windmill.load_map(game.map);
// creation des bouding box 3D
//delete bbox;
free(bbox);
//bbox = new Bbox3D[game.map->list_object_length];
bbox = (Bbox3D*) malloc(game.map->list_object_length * sizeof(Bbox3D));
//if (bbox == NULL) debug_pop("ERROR ptr bbox NULL");
memset(bbox, 0, game.map->list_object_length * sizeof(Bbox3D));
for (int i=0; i<game.map->list_object_length; i++)
{
Object* current_object = game.map->object[i];
Bbox3D* current_bbox = &bbox[i];
int nb_poly = (current_object->collision < 0) ? current_object->modele_size : current_object->collision;
if (nb_poly > current_object->modele_size) nb_poly = current_object->modele_size;
for (int j=0; j<nb_poly; j++)
{
const Modele* current_modele = &current_object->modele[j];
for (int k=0; k<current_modele->type; k++)
{
Point point = windmill.get_point(current_modele, k);
current_bbox->x1 = min(current_bbox->x1, point.x);
current_bbox->y1 = min(current_bbox->y1, point.y);
current_bbox->z1 = min(current_bbox->z1, point.z);
current_bbox->x2 = max(current_bbox->x2, point.x);
current_bbox->y2 = max(current_bbox->y2, point.y);
current_bbox->z2 = max(current_bbox->z2, point.z);
}
}
if (current_object->axe == Z_BILLBOARD)
{
current_bbox->radius = max(current_bbox->y1, current_bbox->y2);
}
}
// mise a zero du temps sur la map
time_scene = 0;
}
//----------------------------------------------------------------------------------------------------
// DRAW
//----------------------------------------------------------------------------------------------------
void Scene_Map::draw()
{
//ML_clear_vram();
dclear(C_WHITE);
windmill.draw();
// MAP VILLAGE
if (game.map == &map_village)
{
if (vue_panneau_moulin)
{
//ML_rectangle(34, 15, 95, 50, 0, ML_WHITE, ML_WHITE);
//PrintXY(34, 20, "MOULIN DES", 0);
//PrintXY(52, 30, "RIBES", 0);
//PrintMini(45, 45, "NineStars", 0);
}
}
// MAP INTERIEUR FORGERON
if (game.map == &map_interieur_forgeron)
{
if (parle_avec_forgeron)
{
//Point point_ancrage = windmill.get_point(&forgeron1.modele, 0);
//ML_rectangle(50, 10, 118, 54, 1, ML_BLACK, ML_WHITE);
}
}
if (show_repere) windmill.show_repere();
if (show_coordinates) windmill.show_coordinates();
//ML_display_vram();
dupdate();
}
//----------------------------------------------------------------------------------------------------
// UPDATE
//----------------------------------------------------------------------------------------------------
void Scene_Map::update()
{
time_scene += 0.02;
// gestion des touches
/*if (input_trigger(K_EXIT))
{
scene = EXIT;
return;
}
if (input_trigger(K_MENU))
{
scene = SCENE_TITLE;
return;
}
if (input_trigger(K_F1))
{
scene = SCENE_MAP_DEBUG;
return;
}
if (input_trigger(K_F2))
{
show_repere = !show_repere;
}
if (input_trigger(K_F3))
{
show_coordinates = !show_coordinates;
}*/
// action du joueur sur la map
player_action();
// animation des objets sur la map
animation();
// mouvements du joueur
if (game.player.can_move)
{
player_move();
player_turn();
}
if (game.player.dissociate_camera == false)
{
camera.set(game.player.x, game.player.y, game.player.z + game.player.height, game.player.yaw, game.player.pitch);
}
//debug_display(id(windmill.object_cursor), 3);
//debug_display(windmill.poly_cursor, 4);
}
void Scene_Map::player_action()
{
// MAP VILLAGE
if (game.map == &map_village)
{
/*if (input_trigger(K_EXE))
{
if (action_object(object(20)))
{
if (vue_panneau_moulin)
{
game.player.can_move = true;
game.player.dissociate_camera = false;
windmill.set_camera(&camera);
} else {
game.player.can_move = false;
game.player.dissociate_camera = true;
look(&panneau1, 0, 8, 17, 270, -10);
windmill.set_camera(&camera_look);
}
vue_panneau_moulin = not vue_panneau_moulin;
}
}*/
}
// MAP INTERIEUR FORGERON
if (game.map == &map_interieur_forgeron)
{
/*if (input_trigger(K_EXE))
{
// interaction avec le forgeron
if (parle_avec_forgeron)
{
parle_avec_forgeron = false;
game.player.can_move = true;
game.player.dissociate_camera = false;
} else {
if (action_object(&forgeron1))
{
parle_avec_forgeron = true;
game.player.can_move = false;
game.player.dissociate_camera = true;
camera.set(-23, 4, game.player.height, 198, 0);
}
}
}*/
}
}
void Scene_Map::animation()
{
// MAP VILLAGE
if (game.map == &map_village)
{
object(6)->angle -= 1;
}
}
void Scene_Map::player_move()
{
/*///////////// METTRE DANS PLAYER ET RETURN LE FLAG
float new_x = game.player.x;
float new_y = game.player.y;
float new_z = game.player.z;
// deplacement
float front, side;
input_move(&front, &side);
// si des touches sont pressees
if (side != 0 or front != 0)
{
game.player.moving = true;
//game.player.translation_speed = min(game.player.translation_speed + 0.25, game.player.translation_speed_max);
if (game.player.translation_speed < game.player.translation_speed_max)
{
game.player.translation_speed += game.player.translation_acceleration; // acceleration
} else {
game.player.translation_speed = game.player.translation_speed_max;
}
// conversion dans le repere monde
float angle_rad = game.player.yaw * 3.1415 / 180.0;
float x = (front * cosf(angle_rad) - side * sinf(angle_rad)) * game.player.translation_speed;
float y = (front * sinf(angle_rad) + side * cosf(angle_rad)) * game.player.translation_speed;
new_x += x;
new_y += y;
} else {
game.player.moving = false;
game.player.translation_speed = 0;
}
// saut
if (input_press(K_8) and not game.player.jumping)
{
game.player.jump_speed = game.player.jump_speed_max;
game.player.jumping = true;
} else {
game.player.jump_speed -= 0.981; // gravite
}
new_z += game.player.jump_speed;
// collision
flag = collision(&new_x, &new_y, &new_z);
// contact avec le sol ou un objet
if (flag.type == COLLISION_GROUND or flag.type == COLLISION_ON)
{
game.player.jumping = false;
game.player.jump_speed = 0;
}
// hors terrain
if (flag.type == COLLISION_BOUND)
{
debug_display("trop loin", 2);
}
game.player.x = new_x;
game.player.y = new_y;
game.player.z = new_z;
*/
}
void Scene_Map::player_turn()
{/*
float yaw = 0;
float pitch = 0;
if (input_press(K_RIGHT)) yaw = -1;
if (input_press(K_LEFT)) yaw = 1;
if (input_press(K_DOWN)) pitch = -0.5;
if (input_press(K_UP)) pitch = 0.5;
if (yaw != 0 or pitch != 0)
{
game.player.turning = true;
if (game.player.rotation_speed < game.player.rotation_speed_max)
{
game.player.rotation_speed += float(game.player.rotation_speed_max / 10.0);
}
} else {
game.player.turning = false;
game.player.rotation_speed = 0;
}
yaw = game.player.yaw + yaw * game.player.rotation_speed;
pitch = game.player.pitch + pitch * game.player.rotation_speed;
if (yaw < 0) yaw += 360;
if (yaw >= 360) yaw -= 360;
if (pitch > 90) pitch = 90;
if (pitch < -90) pitch = -90;
game.player.yaw = yaw;
game.player.pitch = pitch;
*/
}
//-----------------------------------------------------------------------------
// COLLISION
// renvoie le type de la derniere collision detectee
// 0 rien
// 1 sol
// 2 cote objet
// 3 dessus objet
// 4 z_billboard
// 5 hors terrain
//-----------------------------------------------------------------------------
Collision_flag Scene_Map::collision(float* new_x, float* new_y, float* new_z)
{
Collision_flag flag;
float belly = game.player.belly;
float total_height = game.player.total_height;
flag.type = COLLISION_NONE;
flag.object = NULL;
if (*new_z <= 0)
{
*new_z = 0;
flag.type = COLLISION_GROUND;
}
for (int i = 0; i<game.map->list_object_length; i++)
{
Object* current_object = game.map->object[i];
// si une bbox a ete cree pour l objet
if (current_object->collision != 0)
{
Bbox3D* current_bbox = &bbox[i];
float cosinus, sinus;
float player_x, player_y, player_z;
float temp_new_x, temp_new_y, temp_new_z;
// si objet.axe != N
if (current_object->axe == Z)
{
float angle = 3.1415 * current_object->angle / 180.0;
cosinus = cosf(angle);
sinus = sinf(angle);
player_x = cosinus * (game.player.x-current_object->x) + sinus * (game.player.y-current_object->y);
player_y = - sinus * (game.player.x-current_object->x) + cosinus * (game.player.y-current_object->y);
player_z = game.player.z - current_object->z;
temp_new_x = cosinus * (*new_x-current_object->x) + sinus * (*new_y-current_object->y);
temp_new_y = - sinus * (*new_x-current_object->x) + cosinus * (*new_y-current_object->y);
temp_new_z = *new_z - current_object->z;
} else {
cosinus = 1;
sinus = 0;
player_x = game.player.x - current_object->x;
player_y = game.player.y - current_object->y;
player_z = game.player.z - current_object->z;
temp_new_x = *new_x - current_object->x;
temp_new_y = *new_y - current_object->y;
temp_new_z = *new_z - current_object->z;
}
if (temp_new_z > current_bbox->z2)
{
// player au dessus
// si je mets rien ici, on pourra pas sauter sur une caisse...
} else if (temp_new_z + total_height < current_bbox->z1)
{
// player en dessous
} else {
// détermine si INT ou EXT
//if (game.player.x > current_bbox->x1 and game.player.x < current_bbox->x2 and
// game.player.y > current_bbox->y1 and game.player.y < current_bbox->y2)
if (current_object->collision < 0)
{
// si player a l interieur de l objet
if (temp_new_x - belly < current_bbox->x1)
{
temp_new_x = current_bbox->x1 + belly;
}
if (temp_new_x + belly > current_bbox->x2)
{
temp_new_x = current_bbox->x2 - belly;
}
if (temp_new_y - belly < current_bbox->y1)
{
temp_new_y = current_bbox->y1 + belly;
}
if (temp_new_y + belly > current_bbox->y2)
{
temp_new_y = current_bbox->y2 - belly;
}
*new_x = cosinus * temp_new_x - sinus * temp_new_y + current_object->x;
*new_y = sinus * temp_new_x + cosinus * temp_new_y + current_object->y;
if (flag.type <= COLLISION_WALL)
{
flag.type = COLLISION_WALL;
flag.object = current_object;
}
} else {
if (current_object->axe == Z_BILLBOARD)
{
bool inside_after = belly < current_bbox->radius;
if (inside_after)
{
//debug_pop("collsiosn");
if (flag.type <= COLLISION_CARA)
{
flag.type = COLLISION_CARA;
flag.object = current_object;
}
}
} else {
bool inside_after = (temp_new_x + belly > current_bbox->x1 and temp_new_x - belly < current_bbox->x2 and
temp_new_y + belly > current_bbox->y1 and temp_new_y - belly < current_bbox->y2);
// si player a l exterieur de l objet
if (inside_after)
{
// player rentre dans objet par le haut
if (player_z >= current_bbox->z2 and temp_new_z < current_bbox->z2)
{
temp_new_z = current_object->z + current_bbox->z2;
*new_z = temp_new_z;
if (flag.type <= COLLISION_ON)
{
flag.type = COLLISION_ON;
flag.object = current_object;
}
} else {
// si on rentre dans l'objet
if (player_x < current_bbox->x1)
{
temp_new_x = current_bbox->x1 - belly;
}
if (player_x > current_bbox->x2) // modifier par un else ?
{
temp_new_x = current_bbox->x2 + belly;
}
if (player_y < current_bbox->y1)
{
temp_new_y = current_bbox->y1 - belly;
}
if (player_y > current_bbox->y2)
{
temp_new_y = current_bbox->y2 + belly;
}
// transformation inverse
*new_x = cosinus * temp_new_x - sinus * temp_new_y + current_object->x;
*new_y = sinus * temp_new_x + cosinus * temp_new_y + current_object->y;
if (flag.type <= COLLISION_WALL)
{
flag.type = COLLISION_WALL;
flag.object = current_object;
}
}
}
}
}
}
}
}
if (*new_x * *new_x + *new_y * *new_y > MAP_EXTERIOR_LIMIT * MAP_EXTERIOR_LIMIT)
{
flag.type = COLLISION_BOUND;
*new_x = game.player.x;
*new_y = game.player.y;
}
return flag;
}
/*Collision_flag Scene_Map::collision(float* new_x, float* new_y, float* new_z)
{
Collision_flag flag;
float belly = game.player.belly;
float total_height = game.player.total_height;
flag.type = COLLISION_NONE;
flag.object = NULL;
if (*new_z <= 0)
{
*new_z = 0;
flag.type = COLLISION_GROUND;
}
for (int i = 0; i<game.map->list_object_length; i++)
{
Object* current_object = game.map->object[i];
// si une bbox a ete cree pour l objet
if (current_object->for_collision != 0)
{
Bbox3D* current_bbox = &bbox[i];
float cosinus, sinus;
float player_x, player_y, player_z;
float temp_new_x, temp_new_y, temp_new_z;
// si objet.axe != N
if (current_object->axe == Z)
{
float angle = 3.1415 * current_object->angle / 180.0;
cosinus = cosf(angle);
sinus = sinf(angle);
player_x = cosinus * (game.player.x-current_object->x) + sinus * (game.player.y-current_object->y);
player_y = - sinus * (game.player.x-current_object->x) + cosinus * (game.player.y-current_object->y);
player_z = game.player.z - current_object->z;
temp_new_x = cosinus * (*new_x-current_object->x) + sinus * (*new_y-current_object->y);
temp_new_y = - sinus * (*new_x-current_object->x) + cosinus * (*new_y-current_object->y);
temp_new_z = *new_z - current_object->z;
} else {
cosinus = 1;
sinus = 0;
player_x = game.player.x - current_object->x;
player_y = game.player.y - current_object->y;
player_z = game.player.z - current_object->z;
temp_new_x = *new_x - current_object->x;
temp_new_y = *new_y - current_object->y;
temp_new_z = *new_z - current_object->z;
}
if (temp_new_z > current_bbox->z2)
{
// player au dessus
// si je mets rien ici, on pourra pas sauter sur une caisse...
} else if (temp_new_z + total_height < current_bbox->z1)
{
// player en dessous
} else {
// détermine si INT ou EXT
//if (game.player.x > current_bbox->x1 and game.player.x < current_bbox->x2 and
// game.player.y > current_bbox->y1 and game.player.y < current_bbox->y2)
if (current_object->type_collision == OUT)
{
// si player a l interieur de l objet
if (temp_new_x - belly < current_bbox->x1)
{
temp_new_x = current_bbox->x1 + belly;
}
if (temp_new_x + belly > current_bbox->x2)
{
temp_new_x = current_bbox->x2 - belly;
}
if (temp_new_y - belly < current_bbox->y1)
{
temp_new_y = current_bbox->y1 + belly;
}
if (temp_new_y + belly > current_bbox->y2)
{
temp_new_y = current_bbox->y2 - belly;
}
*new_x = cosinus * temp_new_x - sinus * temp_new_y + current_object->x;
*new_y = sinus * temp_new_x + cosinus * temp_new_y + current_object->y;
if (flag.type <= COLLISION_WALL)
{
flag.type = COLLISION_WALL;
flag.object = current_object;
}
}
if (current_object->type_collision == IN)
{
if (current_object->axe == Z_BILLBOARD)
{
bool inside_after = belly < current_bbox->radius;
if (inside_after)
{
//debug_pop("collsiosn");
if (flag.type <= COLLISION_CARA)
{
flag.type = COLLISION_CARA;
flag.object = current_object;
}
}
} else {
bool inside_after = (temp_new_x + belly > current_bbox->x1 and temp_new_x - belly < current_bbox->x2 and
temp_new_y + belly > current_bbox->y1 and temp_new_y - belly < current_bbox->y2);
// si player a l exterieur de l objet
if (inside_after)
{
// player rentre dans objet par le haut
if (player_z >= current_bbox->z2 and temp_new_z < current_bbox->z2)
{
temp_new_z = current_object->z + current_bbox->z2;
*new_z = temp_new_z;
if (flag.type <= COLLISION_ON)
{
flag.type = COLLISION_ON;
flag.object = current_object;
}
} else {
// si on rentre dans l'objet
if (player_x < current_bbox->x1)
{
temp_new_x = current_bbox->x1 - belly;
}
if (player_x > current_bbox->x2) // modifier par un else ?
{
temp_new_x = current_bbox->x2 + belly;
}
if (player_y < current_bbox->y1)
{
temp_new_y = current_bbox->y1 - belly;
}
if (player_y > current_bbox->y2)
{
temp_new_y = current_bbox->y2 + belly;
}
// transformation inverse
*new_x = cosinus * temp_new_x - sinus * temp_new_y + current_object->x;
*new_y = sinus * temp_new_x + cosinus * temp_new_y + current_object->y;
if (flag.type <= COLLISION_WALL)
{
flag.type = COLLISION_WALL;
flag.object = current_object;
}
}
}
}
}
}
}
}
if (*new_x * *new_x + *new_y * *new_y > MAP_EXTERIOR_LIMIT * MAP_EXTERIOR_LIMIT)
{
flag.type = COLLISION_BOUND;
*new_x = game.player.x;
*new_y = game.player.y;
}
return flag;
}*/
void Scene_Map::look(Object* object, float x, float y, float z, float yaw, float pitch)
{
Vertex vertex;
int cosinus, sinus;
vertex.set_xyz(x, y, z);
windmill.compute_object_angle(object, &cosinus, &sinus);
windmill.transform_model_to_world(&vertex, 1, object, cosinus, sinus);
camera_look.x = vertex.x;
camera_look.y = vertex.y;
camera_look.z = vertex.z;
camera_look.yaw = PI * (object->angle + yaw) / DEG;
camera_look.pitch = to_rad(pitch);
}
void Scene_Map::lerp_camera(Camera camera_start, Camera camera_end, float t)
{
camera_temp.x = (1-t) * camera_start.x + t * camera_end.x;
camera_temp.y = (1-t) * camera_start.y + t * camera_end.y;
camera_temp.z = (1-t) * camera_start.z + t * camera_end.z;
camera_temp.yaw = (1-t) * camera_start.yaw + t * camera_end.yaw;
camera_temp.pitch = (1-t) * camera_start.pitch + t * camera_end.pitch;
}
Object* Scene_Map::object(int id)
{
if (id < 0 or id >= game.map->list_object_length)
{
//debug_pop("ERROR id out of range");
return NULL;
}
return game.map->object[id];
}
int Scene_Map::id(Object* object)
{
if (object == NULL) return -1;
for (int i = 0; i<game.map->list_object_length; i++)
{
if (game.map->object[i] == object)
{
return i;
}
}
//debug_pop("ERROR object not found");
return -1;
}
bool Scene_Map::action_object(Object* object, int poly_id)
{
if (look_object(object, poly_id) == false) return false;
Point center_poly = windmill.get_center_poly(&object->modele[poly_id]);
return action_object(object, center_poly.x, center_poly.y, center_poly.z);
}
bool Scene_Map::action_object(Object* object, float x, float y, float z)
{
Vertex vertex;
int cosinus, sinus;
vertex.set_xyz(x, y, z);
windmill.compute_object_angle(object, &cosinus, &sinus);
windmill.transform_model_to_world(&vertex, 1, object, cosinus, sinus);
float dx = vertex.x - game.player.x;
float dy = vertex.y - game.player.y;
float dz = vertex.z - game.player.z;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
if (dz < 0) dz = -dz;
return (dx <= game.player.action_distance and dy <= game.player.action_distance);
}
bool Scene_Map::look_object(Object* object, int poly_id)
{
if (poly_id == -1)
{
return (object == windmill.object_cursor);
} else {
return (object == windmill.object_cursor and poly_id == windmill.poly_cursor);
}
}
//----------------------------------------------------------------------------------------------------
// TERMINATE
//----------------------------------------------------------------------------------------------------
void Scene_Map::terminate()
{
}
//----------------------------------------------------------------------------------------------------
// DESTRUCTOR
//----------------------------------------------------------------------------------------------------
Scene_Map::~Scene_Map()
{
// rien
}