home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / RAYCAST.ZIP / COLLISIO.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-24  |  8.2 KB  |  322 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include "sign.h"
  5. #include "ray.h"
  6. #include "fixed.h"
  7. #include "globals.h"
  8. #include "collisio.h"
  9. #include "isect.h"
  10. #include "blockmap.h"
  11. #include "message.h"
  12. #include "abs.h"
  13. #include "ground.h"
  14.  
  15. #define COLLINEAR         2
  16. #define FIXED_TO_FLOAT(x) (((float)(x))/ONE)
  17. #define FLOAT_TO_FIXED(x) (long)((float)(x)*ONE)
  18. #define FIXED_ONE_QUARTER (16)
  19. #define MAN_SIZE          (64)
  20. #define WALL_PASSABLE 8
  21. static plinedef s_wall = NULL;
  22.  
  23. #define VECTOR_LEN  15
  24.  
  25. /*
  26. -- ----------------------------------------------------------------------
  27. -  Function    : LineDistance
  28. -
  29. -  Parameters  :
  30. -
  31. -  Result      :
  32. -
  33. -  Description :
  34. -    Returns the distance between point c, and the line a-b.
  35. -- ----------------------------------------------------------------------
  36. */
  37. MYFIXED
  38. LineDistance( MYFIXED cx, MYFIXED cy, long ax, long ay, long bx, long by, long line_len )
  39. {
  40.   long delta_x = ax-bx;
  41.   long delta_y = ay-by;
  42.   MYFIXED s;
  43.  
  44.   /* If s becomes negative we are facing the line clockwise */
  45.   fixedmult64(cy-(by<<SHIFT), delta_x);
  46.   fixedma64((bx<<SHIFT)-cx, delta_y);
  47.   s=fixeddiv64(line_len);
  48.  
  49.  
  50. /*
  51.   printf( "R = %f S = %f\n", r, s );
  52. */
  53.  
  54.   return s;
  55. }
  56.  
  57. BOOL
  58. On_Line( MYFIXED cx, MYFIXED cy, long ax, long ay, long bx, long by )
  59. {
  60.   long delta_x = ax-bx;
  61.   long delta_y = ay-by;
  62.   long line_len;
  63.   MYFIXED r;
  64.  
  65.   /* the lenght of the line in **2 */
  66.   line_len = delta_x*delta_x+delta_y*delta_y;
  67.  
  68.   fixedmult64((ay<<SHIFT)-cy, delta_y);
  69.   fixedma64((ax<<SHIFT)-cx, delta_x);
  70.   r=fixeddiv64(line_len);
  71.  
  72.   if ( r < 0 || r > ONE)
  73.       return FALSE;
  74.   else return TRUE;
  75. }
  76.  
  77. void
  78. get_vector_xy( MYFIXED *vx, MYFIXED *vy, plinedef wall )
  79. {
  80.   long dx, dy, line_len;
  81.  
  82.   dx = Vector_List[wall->v[0]].x - Vector_List[wall->v[1]].x;
  83.   dy = Vector_List[wall->v[0]].y - Vector_List[wall->v[1]].y;
  84.          
  85.   line_len = wall->distance;
  86.  
  87.   *vx = fixeddiv(dx,line_len);
  88.   *vy = fixeddiv(dy,line_len);
  89.  
  90. /*
  91.   printf( "line_len %f, dx %f, dy %f\n", 
  92.      line_len, dx, dy );
  93. */
  94. }
  95.  
  96. /*
  97.   Check how it should behave when you sliding agains a wall. 
  98. */
  99.  
  100. void
  101. slide_wall( MYFIXED *x, MYFIXED *y, MYFIXED x2, MYFIXED y2,
  102.           MYFIXED dist_old, MYFIXED dist_new )
  103. {
  104.  
  105.   MYFIXED vector_x, vector_y;
  106.  
  107.  
  108.   // get percent moves in x & y per move in unit of distance along line
  109.   get_vector_xy( &vector_x, &vector_y, s_wall );
  110.  
  111.   // move along perpendicular to line, which to the best of my knowledge _always_ works
  112.   // for sliding
  113.  
  114.         *x  = x2+fixedmult(dist_old-dist_new,-vector_y);
  115.         *y  = y2+fixedmult(dist_old-dist_new, vector_x);
  116.   
  117. }
  118.  
  119. void Find_Closest_Line_In_List(MYFIXED x1, MYFIXED y1, plinedef * close_line,
  120.     MYFIXED * cur_min, pline_list search_list) {
  121. if (search_list==NULL)
  122.     return;
  123.  
  124. plinedef wall;
  125. MYFIXED tmp;
  126. int i; 
  127.  
  128. for (i = 0; i < search_list->line_count; i++) {
  129.      wall=search_list->lines[i];
  130.      /* Check Distance */
  131.      if (On_Line(x1, y1,
  132.          (Vector_List[wall->v[0]].x ),
  133.          (Vector_List[wall->v[0]].y ),
  134.          (Vector_List[wall->v[1]].x ),
  135.          (Vector_List[wall->v[1]].y)) ) {
  136.      tmp = LineDistance( x1, y1, 
  137.          (Vector_List[wall->v[0]].x ),
  138.          (Vector_List[wall->v[0]].y ),
  139.          (Vector_List[wall->v[1]].x ),
  140.          (Vector_List[wall->v[1]].y),
  141.                       wall->distance);
  142.      } else {
  143.          tmp=MAXMYFIXED;
  144.      }
  145.      if ( ABS(tmp) < ABS( *(cur_min) ) )
  146.         {
  147.     *(cur_min)      = tmp;
  148.     *(close_line) = wall; 
  149.         }
  150.  
  151.   }
  152. }
  153.  
  154. void
  155. checkwalls(pwall_collision_info the_collision)
  156. {
  157.     MYFIXED  side   = 0,
  158.                         x   = 0,
  159.                         y   = 0;
  160.  
  161.   plinedef mem_wall;
  162.   MYFIXED  x1, y1, dest, min = MAXMYFIXED;
  163.  
  164.   // we never want an object with 2*speed of a wall, or it may get through
  165.   long cur_speed=(the_collision->move_obj->type->stats.base_speed*2)<<SHIFT;
  166.   MYFIXED dest_x, dest_y;
  167.   USHORT block_x, block_y;
  168.  
  169.   x = the_collision->move_obj->x;
  170.   y = the_collision->move_obj->y;
  171.   x1 = x+the_collision->delta_vec->x;
  172.   y1 = y+the_collision->delta_vec->y;
  173.  
  174.   if ( x1 == x && y1 == y ) {
  175.      the_collision->found_collision=FALSE;
  176.      return;
  177.   }
  178.  
  179.   mem_wall=NULL;
  180.   
  181.   dest_x=x1;
  182.   dest_y=y1;
  183.   block_x=Block_X(dest_x);
  184.   block_y=Block_Y(dest_y);
  185.   
  186.   Find_Closest_Line_In_List(x1, y1, &mem_wall, &min, 
  187.       Get_Block_Line_List(block_x, block_y));
  188.  
  189.   // check surrounding blocks
  190.   if (dest_y-Block_Bottom_Line(dest_y)<(cur_speed)) {
  191.      Find_Closest_Line_In_List(x1,y1,&mem_wall, &min,
  192.          Get_Block_Line_List(block_x, block_y-1));
  193.      if (dest_x-Block_Left_Line(dest_x)<(cur_speed)) {
  194.          Find_Closest_Line_In_List(x1,y1,&mem_wall, &min,
  195.              Get_Block_Line_List(block_x-1, block_y-1));
  196.      }
  197.      if (dest_x-Block_Right_Line(dest_x)>(-cur_speed)) {
  198.          Find_Closest_Line_In_List(x1,y1,&mem_wall, &min,
  199.              Get_Block_Line_List(block_x+1, block_y-1));
  200.      }
  201.   } else if (dest_y-Block_Top_Line(dest_y)>(-cur_speed)) {
  202.      Find_Closest_Line_In_List(x1,y1,&mem_wall, &min,
  203.          Get_Block_Line_List(block_x, block_y+1));
  204.      if (dest_x-Block_Left_Line(dest_x)<(cur_speed)) {
  205.          Find_Closest_Line_In_List(x1,y1,&mem_wall, &min,
  206.              Get_Block_Line_List(block_x-1, block_y+1));
  207.      }
  208.      if (dest_x-Block_Right_Line(dest_x)>(-cur_speed)) {
  209.          Find_Closest_Line_In_List(x1,y1,&mem_wall, &min,
  210.              Get_Block_Line_List(block_x+1, block_y+1));
  211.      }
  212.   } else if (dest_x-Block_Left_Line(dest_x)<(cur_speed)) {
  213.       Find_Closest_Line_In_List(x1,y1,&mem_wall, &min,
  214.           Get_Block_Line_List(block_x-1, block_y));
  215.   } else if (dest_x-Block_Right_Line(dest_x)>(-cur_speed)) {
  216.       Find_Closest_Line_In_List(x1,y1,&mem_wall, &min,
  217.           Get_Block_Line_List(block_x+1, block_y));
  218.   }
  219.  
  220. the_collision->wall=mem_wall;
  221. the_collision->dis_from_line=min;
  222. if ( (mem_wall!=NULL) && (ABS( min ) < cur_speed) ) {
  223.     the_collision->found_collision=TRUE;
  224. } else {
  225.     the_collision->found_collision=FALSE;
  226. }
  227.  
  228. }
  229.  
  230. BOOL Intersect_Abs(pvector2 sv1, pvector2 dv1, pvector2 sv2, pvector2 dv2) {
  231.     long sv1d, dv1d, sv2d, dv2d;
  232.  
  233.     sv1d=(sv2->x-dv2->x)*(sv1->y-dv2->y)-(sv2->y-dv2->y)*(sv1->x-dv2->x);
  234.     dv1d=(sv2->x-dv2->x)*(dv1->y-dv2->y)-(sv2->y-dv2->y)*(dv1->x-dv2->x);
  235.     sv1d=(sv1->x-dv1->x)*(sv2->y-dv1->y)-(sv1->y-dv1->y)*(sv2->x-dv1->x);
  236.     sv1d=(sv1->x-dv1->x)*(dv2->y-dv1->y)-(sv1->y-dv1->y)*(dv2->x-dv1->x);
  237.  
  238.     if ( (SIGN(sv1d)!=SIGN(dv1d)) && (SIGN(sv2d)!=SIGN(dv2d)) ) {
  239.         return TRUE;
  240.     } else {
  241.         return FALSE;
  242.     }
  243. }
  244.  
  245. BOOL Passable_Wall(plinedef wall, pobject the_obj, MYFIXED dest_x,
  246.     MYFIXED dest_y, psector sec2) {
  247.  
  248. if (!(wall->attributes & WALL_PASSABLE)) 
  249.     return FALSE; 
  250. if (the_obj->z+the_obj->type->height>(sec2->ceil_height-
  251.     Ground_Height_XY(dest_x, dest_y, sec2))) 
  252.     return FALSE;
  253. if (Ground_Height(the_obj)+the_obj->type->stepping_height+the_obj->z < 
  254.     Ground_Height_XY(dest_x, dest_y, sec2))
  255.     return FALSE;
  256.  
  257. return TRUE;
  258. }
  259.  
  260. ULONG Do_Slide_Wall(pobject the_obj, pwall_collision_info the_collision) {
  261.   psector sec1, sec2;
  262.   plinedef wall;
  263.   MYFIXED min, side, cur_speed, dest;
  264.   MYFIXED source_x, source_y, dest_x, dest_y;
  265.  
  266.   source_x=the_obj->x;
  267.   source_y=the_obj->y;
  268.   dest_x=source_x+the_collision->delta_vec->x;
  269.   dest_y=source_y+the_collision->delta_vec->y;
  270.   wall=the_collision->wall;
  271.   min=the_collision->dis_from_line;
  272.   cur_speed=(the_obj->type->stats.base_speed*2) <<SHIFT;
  273.  
  274.   /* is there any point in checking further. */
  275.   side=LineDistance(source_x,source_y,       
  276.          (Vector_List[wall->v[0]].x ),
  277.          (Vector_List[wall->v[0]].y ),
  278.          (Vector_List[wall->v[1]].x ),
  279.          (Vector_List[wall->v[1]].y),
  280.                         wall->distance);
  281.  
  282.   if (side<0) {
  283.       sec1=wall->s[1]->sec;
  284.       sec2=wall->s[0]->sec;
  285.   } else {
  286.       sec1=wall->s[0]->sec;
  287.       sec2=wall->s[1]->sec;
  288.   }
  289.  
  290. ULONG message_res;
  291. BOOL impassible;
  292.  
  293. /* can we pass the wall */
  294. if (Passable_Wall(wall, the_obj, dest_x, dest_y, sec2))
  295. {
  296.     dest=-SIGN(side)*cur_speed;
  297.     impassible=FALSE;
  298. } else {
  299.     dest=SIGN(side)*cur_speed;
  300.     impassible=TRUE;
  301. }
  302.  
  303. message_res=Send_Specific_Message(NULL, the_obj, 
  304.     WALL_SLIDE_CONFIRM, (pdata)&impassible); 
  305.  
  306. if (message_res==STOP_SLIDE) {
  307.     return NORMAL_MESSAGE;
  308. }
  309. if (message_res!=NORMAL_MESSAGE) {
  310.     return message_res;
  311. }
  312.  
  313. s_wall = wall;
  314. slide_wall( &source_x, &source_y, dest_x, dest_y, dest, min );
  315. the_collision->delta_vec->x   =  source_x-the_obj->x ;
  316. the_collision->delta_vec->y   = source_y-the_obj->y ;
  317.  
  318. return NORMAL_MESSAGE;
  319. }
  320.  
  321.  
  322.