home *** CD-ROM | disk | FTP | other *** search
- /*
- ** MacWT -- a 3d game engine for the Macintosh
- ** © 1995, Bill Hayden and Nikol Software
- ** Free for non-commercial use - address questions to the e-mail address below
- **
- ** Mail: afn28988@freenet.ufl.edu (Bill Hayden)
- ** MacWT FTP site: ftp.circa.ufl.edu/pub/software/ufmug/mirrors/LocalSW/Hayden/
- ** WWW Page: http://grove.ufl.edu:80/~nikolsw
- **
- ** All of the above addresses are due to changes sometime in 1996, so stay tuned
- **
- ** based on wt, by Chris Laurel
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
-
- #include "wt.h"
- #include "fixed.h"
- #include "table.h"
- #include "view.h"
- #include "framebuf.h"
- #include "list.h"
- #include "world.h"
- #include "object.h"
- #include "collision.h"
-
- static double LineDistance( double cx, double cy, double ax, double ay, double bx, double by, Boolean *corner );
- static void get_vector_xy( double *vx, double *vy, Wall *wall );
-
- static Wall *s_wall = NULL;
-
-
-
- /*
- LineDistance returns the distance between a point c, and a line a-b.
- */
-
- static double LineDistance( double cx, double cy, double ax, double ay, double bx, double by, Boolean *corner )
- {
- double delta_x = bx-ax;
- double delta_y = by-ay;
- double line_len, r, s;
-
-
- /* the length of the line in **2 */
- line_len = delta_x * delta_x + delta_y * delta_y;
-
- r = ( (ay-cy)*(-delta_y) - (ax-cx)*delta_x ) / line_len;
-
- #if 0
- if ( r > 1.0 || r < 0.0)
- s = sqrt(fabs(ax - cx) + fabs(ay - cy));
- else if ( r < 0.0 )
- s = sqrt(fabs(bx - cx) + fabs(by - cy));
- else
- s = ((ay-cy)*(delta_x)-(ax-cx)*delta_y) / sqrt( line_len );
- #endif
-
- if ( r > 1.0 )
- {
- s = sqrt( (bx - cx)*(bx - cx) + (by - cy)*(by - cy) );
- *corner = true;
- }
- else if ( r < 0.0 )
- {
- s = sqrt( (ax - cx)*(ax - cx) + (ay - cy)*(ay - cy) );
- *corner = true;
- }
- else
- {
- s = ((ay-cy)*(delta_x)-(ax-cx)*delta_y) / sqrt( line_len );
- *corner = false;
- }
-
- return s;
- }
-
-
-
-
- static void get_vector_xy( double *vx, double *vy, Wall *wall )
- {
- double dx, dy, line_len;
-
-
- dx = (double)FIXED_TO_FLOAT(wall->vertex2->x - wall->vertex1->x);
- dy = (double)FIXED_TO_FLOAT(wall->vertex2->y - wall->vertex1->y);
-
- line_len = sqrt( dx*dx + dy*dy );
-
- *vx = dx / line_len;
- *vy = dy / line_len;
- }
-
-
- /*
- Check how MacWT should behave when an object slides against a wall.
- */
-
- static void slide_wall( double *x, double *y, double x2, double y2,
- double dist_old, double dist_new )
- {
- double percent, line_len;
- double vector_x, vector_y;
- double dx = x2-*x;
- double dy = y2-*y;
- double suck1, suck2;
-
-
- line_len = sqrt( dx*dx + dy*dy );
-
- /* (dist_old-dist_new) becomes one side in a triangle. */
- /* percent cannot be over 1.0. */
- /* How long is the distance towards the line compared to the line_length. */
- percent = (1.0 - fabs( dist_old - dist_new ) / line_len);
-
- get_vector_xy( &vector_x, &vector_y, s_wall );
-
- /* in what direction are the vectors compared to the walk ? */
- suck1 = (vector_x + dx)*(vector_x + dx) + (vector_y + dy)*(vector_y + dy);
- suck2 = (vector_x - dx)*(vector_x - dx) + (vector_y - dy)*(vector_y - dy);
-
- if ( suck1 > suck2 )
- {
- *x += percent * line_len * vector_x;
- *y += percent * line_len * vector_y;
- }
- else
- {
- *x -= percent * line_len * vector_x;
- *y -= percent * line_len * vector_y;
- }
-
- }
-
-
- void CheckCollision( Object *o )
- {
- Wall *wall = (Wall *) o->world->walls->table, *mem_wall;
- double tmp, min = 512.0;
- short i;
- //List *l;
- static double side = 0.0,
- x = 0.0,
- y = 0.0;
- Boolean corner, tmpCorner;
-
- if ( o->x == x && o->y == y )
- return;
-
- #if 0
- for (l = o->world->objects; l->next != NULL; l = l->next)
- {
- Object *obj = LIST_NODE(l, Object *);
-
- if (o == obj)
- continue;
-
- if ( (fabs(o->x - obj->x) < (o->xsize + obj->xsize)) ||
- (fabs(o->y - obj->y) < (o->ysize + obj->ysize)) )
- o->z = 2;
- }
- #endif
-
- for (i = 0; i < TABLE_SIZE(o->world->walls); i++, wall++ )
- {
-
- /* Check Distance */
- tmp = LineDistance( o->x, o->y, FIXED_TO_FLOAT(wall->vertex1->x ),
- FIXED_TO_FLOAT(wall->vertex1->y ),
- FIXED_TO_FLOAT(wall->vertex2->x ),
- FIXED_TO_FLOAT(wall->vertex2->y ),
- &corner );
-
- if ( fabs(tmp) < fabs( min ) )
- {
- min = tmp;
- mem_wall = wall;
- tmpCorner = corner;
- }
-
- }
-
- /* is there any point in checking further. */
- if ( fabs( min ) < o->xsize ) // Note that objects are assumed to be round
- {
- /* start by examining the wall */
- fixed floor;
- fixed ceiling;
-
- /* Check the other side of the object */
- if ( min > 0.0 )
- {
- floor = mem_wall->front->floor;
- ceiling = mem_wall->front->ceiling;
- }
- else
- {
- floor = mem_wall->back->floor;
- ceiling = mem_wall->back->ceiling;
- }
-
- if ( (min < o->xsize) && tmpCorner ) // object entering positive corner
- {
- o->x -= o->dx;
- o->y -= o->dy;
- o->dx = 0.0;
- o->dy = 0.0;
- }
-
- /* if the wall is less than the object height and the object has room */
-
- if ( FIXED_TO_FLOAT(floor) > (o->z + o->height) && fabs( min ) < fabs( side ))
- {
- s_wall = mem_wall;
- slide_wall( &x, &y, o->x, o->y, side, min );
-
- o->x = x;
- o->y = y;
-
- return;
- }
- else
- {
- o->z = FIXED_TO_FLOAT(floor);
- o->dz = 0.0;
- }
- }
-
- side = min;
- x = o->x;
- y = o->y;
-
- return;
- }
-