Skip to content

Commit

Permalink
Solved the grid problem by revamping the intersection finder: it gets…
Browse files Browse the repository at this point in the history
… the line from the character's current to its next position, rotates them into the viewing plane, and checks for intersection with grid lines (that are rotated into the same viewing angle too).
  • Loading branch information
penguin673 committed Dec 21, 2008
1 parent 7f9ca73 commit 554cedd
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 152 deletions.
190 changes: 42 additions & 148 deletions echo_character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,177 +305,71 @@ void echo_char::next_grid()
grid1per = 1;
}

/** Utility method that finds the point that is the intersection between the
* ray that starts at "prev_pos" and is in the direction of unit vector "vec",
* and the plane with y-coordinate "level_y".
* @param prev_pos The position the ray starts from.
* @param vec UNIT vector that the ray points in.
* @param level_y The y_coordinate of the
*/
static vector3f* end_pt(vector3f* prev_pos, vector3f* vec, float level_y)
{
if(vec->y != 0)
{
float delta_y = level_y - prev_pos->y;
if((delta_y > 0 && vec->y < 0) || (delta_y < 0 && vec->y > 0))
return(NULL);
vec = (*vec) * (delta_y / vec->y);
}
else
return(NULL);
vector3f* ret = *prev_pos + vec;
delete vec;
CHKPTR(ret);
return(ret);
}

static grid* check_level(GRID_PTR_SET* level, vector3f* pos, vector3f* my_end_pt, vector3f angle)
{
GRID_PTR_SET::iterator it = level->begin(), end = level->end();
grid* g = NULL;
while(it != end)
{
g = *it;
if(g->is_pt_on(angle, my_end_pt))
{
return(g);
}
it++;
}
return(NULL);
}

static grid* check_levels_above(LEVEL_MAP* levels_above, vector3f* pos, vector3f* vec, vector3f angle)
{
if(levels_above->size() < 1)
return(NULL);
LEVEL_MAP::iterator it = levels_above->begin(), end = levels_above->end();
vector3f* pt = NULL;
grid* g = NULL;
while(it != end)
{
pt = end_pt(pos, vec, it->first);
if(pt == NULL)
{
pt = new vector3f();
CHKPTR(pt);
pt->set(pos);
}
g = check_level(it->second, pos, pt, angle);
delete pt;
if(g != NULL)
return(g);
it++;
}
return(NULL);
}

static grid* check_levels_below(LEVEL_MAP* levels_below, vector3f* pos, vector3f* vec, vector3f angle)
{
if(levels_below->size() < 1)
return(NULL);
LEVEL_MAP::iterator it = levels_below->end(), end = levels_below->begin();
vector3f* pt = NULL;
grid* g = NULL;
do
{
it--;
pt = end_pt(pos, vec, it->first);
if(pt == NULL)
{
pt = new vector3f();
CHKPTR(pt);
pt->set(pos);
}
if(g != NULL)
return(g);
}
while(it != end);
return(NULL);
}

void echo_char::step()
{
gfx_color3f(0.5f, 0.5f, 0.5f);
if(speed == SPEED_FALL_FROM_SKY)
{
draw(fall_position);
if(fall_position->y < target_y)
if(!paused)
{
if(typeid(*grid1) == typeid(hole))
initialize_falling(fall_position);
if(fall_position->y < target_y)
{
if(typeid(*grid1) == typeid(hole))
initialize_falling(fall_position);
else
land(grid1, true);
}
else
land(grid1, true);
}
else
{
if(!paused)
{
/// Do the falling...
fall_position->y -= actual_speed * WAIT / 1000;
}
if(!paused)
}
actual_speed += ACCEL * WAIT / 1000;
}
}
else if(speed == SPEED_FALL)
{
vector3f* relative_pos = fall_position->rotate_xy(echo_ns::angle);
draw(relative_pos);
if(relative_pos->y < echo_ns::get_lowest_level() - 5)
{
reset();
}
else
vector3f* absolute_pos = fall_position->rotate_xy(echo_ns::angle);
draw(absolute_pos);
if(!paused)
{
//check for available places to fall onto
grid* cam_grid = NULL;
vector3f* cam_real = echo_ns::angle.angle_to_real();
vector3f* cam_vec = (*relative_pos) - cam_real;
vector3f* neg_cam_vec = cam_vec->negate();
if(cam_real->y > 0) //viewing downwards
if(absolute_pos->y < echo_ns::get_lowest_level() - 5)
{
LEVEL_MAP* levels_below = echo_ns::current_stage->get_levels_lower_than(relative_pos->y);
cam_grid = check_levels_below(levels_below, relative_pos, cam_vec, echo_ns::angle);
delete levels_below;
if(cam_grid == NULL || typeid(*cam_grid) == typeid(hole))
{
LEVEL_MAP* levels_above = echo_ns::current_stage->get_levels_higher_than(relative_pos->y);
cam_grid = check_levels_above(levels_above, relative_pos, neg_cam_vec, echo_ns::angle);
delete levels_above;
}
reset();
}
else //viewing up
else
{
LEVEL_MAP* levels_above = echo_ns::current_stage->get_levels_higher_than(relative_pos->y);
cam_grid = check_levels_above(levels_above, relative_pos, cam_vec, echo_ns::angle);
delete levels_above;
if(cam_grid == NULL || typeid(*cam_grid) == typeid(hole))
//check for available places to fall onto
grid* cam_grid = NULL;
vector3f* next_absolute_pos = new vector3f();
CHKPTR(next_absolute_pos);
next_absolute_pos->set(absolute_pos);
next_absolute_pos->y -= actual_speed * WAIT / 1000;

vector3f* p1 = absolute_pos->neg_rotate_xy(echo_ns::angle);
vector3f* p2 = next_absolute_pos->neg_rotate_xy(echo_ns::angle);
cam_grid = echo_ns::current_stage->get_grid_intersection(p1, p2, echo_ns::angle);

if(cam_grid != NULL && typeid(*cam_grid) != typeid(hole))
{
LEVEL_MAP* levels_below = echo_ns::current_stage->get_levels_lower_than(relative_pos->y);
cam_grid = check_levels_below(levels_below, relative_pos, neg_cam_vec, echo_ns::angle);
delete levels_below;
delete fall_position;
fall_position = NULL;
land(cam_grid, true);
}
}
delete cam_real;
delete neg_cam_vec;
delete cam_vec;
if(cam_grid != NULL && typeid(*cam_grid) != typeid(hole))
{
delete fall_position;
fall_position = NULL;
land(cam_grid, true);
}
else if(!paused)
{
//do the falling...
relative_pos->y -= actual_speed * WAIT / 1000;
actual_speed += ACCEL * WAIT / 1000;
//renew the fall_position
delete fall_position;
fall_position = relative_pos->neg_rotate_yx(echo_ns::angle);
else
{
//do the falling...
actual_speed += ACCEL * WAIT / 1000;
//renew the fall_position
delete fall_position;
fall_position = next_absolute_pos->neg_rotate_yx(echo_ns::angle);
}
delete next_absolute_pos;
}
}
//delete the vector
delete relative_pos;
delete absolute_pos;
}
else if(grid1 != NULL)
{
Expand Down
22 changes: 22 additions & 0 deletions echo_ingame_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <libgen.h>
#endif
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
Expand Down Expand Up @@ -71,7 +72,27 @@ STATUS echo_execdir(char** save)
GetModuleFileName(NULL, exe, MAX_PATH);
return(echo_parentdir(exe, save));
#elif ECHO_OSX
/// Just use cwd
*save = NULL;
int size = 0;
char* result = 0;
do
{
size += PATH_MAX;
if(*save != NULL)
delete *save;
*save = new char[size];
CHKPTR(*save);
result = getcwd(*save, size * sizeof(char));
}
while(result == NULL && errno == ERANGE);
if(result == NULL)
return(FAIL);
else
return(WIN);
#else

//*
//copied from l-portable

//step 1: get the directory of this binary
Expand Down Expand Up @@ -120,6 +141,7 @@ STATUS echo_execdir(char** save)
strcpy(*save, pwd);
return(WIN);
}
// */
#endif
}
return(FAIL);
Expand Down
3 changes: 3 additions & 0 deletions echo_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,10 @@ static grid* parse_grid(echo_xml_element* txe, stage* st, DEPENDENCY_MAP* map, e
if(echo_xml_get_int_attribute(txe, "noland", &noland) == WIN)
{
if(noland)
{
new_grid->set_land(0);
LD_PRINT("it's not land-able!\n");
}
}
if(!escroot)
{
Expand Down
67 changes: 66 additions & 1 deletion echo_math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,47 @@ vector3f* vector3f::rotate_xy(vector3f rot)
return(ret);
}

vector3f* vector3f::neg_rotate_xy(vector3f rot)
{
if(rot.x == 0 && rot.y == 0 && rot.z == 0)
{
vector3f* ret = new vector3f(x, y, z);
CHKPTR(ret);
return(ret);
}
vector3f* ret = new vector3f(x
, y * ECHO_COSF(-rot.x) - z * ECHO_SINF(-rot.x)
, y * ECHO_SINF(-rot.x) + z * ECHO_COSF(-rot.x));
CHKPTR(ret);
float z_save = ret->z;
ret->z = ret->z * ECHO_COSF(-rot.y) - ret->x * ECHO_SINF(-rot.y);
ret->x = z_save * ECHO_SINF(-rot.y) + ret->x * ECHO_COSF(-rot.y);
return(ret);
}

void vector3f::set(float my_x, float my_y, float my_z)
{
x = my_x;
y = my_y;
z = my_z;
}

vector3f* vector3f::rotate_yx(vector3f rot)
{
//float rad_x = -TO_RAD(rot.x), rad_y = -TO_RAD(rot.y);
if(rot.x == 0 && rot.y == 0 && rot.z == 0)
{
vector3f* ret = new vector3f(x, y, z);
CHKPTR(ret);
return(ret);
}
vector3f* ret = new vector3f(z * ECHO_SINF(rot.y) + x * ECHO_COSF(rot.y), y
, z * ECHO_COSF(rot.y) - x * ECHO_SINF(rot.y));
CHKPTR(ret);
float y_save = ret->y;
ret->y = ret->y * ECHO_COSF(rot.x) - ret->z * ECHO_SINF(rot.x);
ret->z = y_save * ECHO_SINF(rot.x) + ret->z * ECHO_COSF(rot.x);
return(ret);
}
vector3f* vector3f::neg_rotate_yx(vector3f rot)
{
//float rad_x = -TO_RAD(rot.x), rad_y = -TO_RAD(rot.y);
Expand Down Expand Up @@ -299,6 +333,37 @@ STATUS IK_angle(float length1, float length2, float distance, float* angle)
return(WIN);
}

/// Adapted from http://www.idevgames.com/forum/showthread.php?t=7458
int lineSeg_intersect(vector3f* a1, vector3f* a2, vector3f* b1, vector3f* b2)
{
float a1yb1y = a1->y - b1->y;
float a1xb1x = a1->x - b1->x;
float a2xa1x = a2->x - a1->x;
float a2ya1y = a2->y - a1->y;

//----------------------------------------------------------------------

float crossa = a1yb1y * (b2->x - b1->x) - a1xb1x * (b2->y - b1->y);
float crossb = a2xa1x * (b2->y - b1->y) - a2ya1y * (b2->x - b1->x);

//----------------------------------------------------------------------

if(crossb == 0)
return(false);
else if(fabs(crossa) > fabs(crossb) || crossa * crossb < 0)
return(false);
else
{
crossa = a1yb1y * a2xa1x - a1xb1x * a2ya1y;
if(fabs(crossa) > fabs(crossb) || crossa * crossb < 0)
return(false);
}

//----------------------------------------------------------------------

return(true);
}

//-----------ANGLE_RANGE----------

angle_range::angle_range(vector3f* my_v1, vector3f* my_v2)
Expand Down
4 changes: 4 additions & 0 deletions echo_math.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ class vector3f
vector3f* angle_xy();
//rotate from the screen to the world via the camera angle
vector3f* rotate_xy(vector3f rot);
vector3f* neg_rotate_xy(vector3f rot);
//rotate from the world to the screen via the camera angle
vector3f* neg_rotate_yx(vector3f rot);
vector3f* rotate_yx(vector3f rot);
//rotate around y axis, putting it in a new vector
vector3f* rotate_about_y(float angle);
//rotate around y axis, putting answers bak in myself
Expand Down Expand Up @@ -105,6 +107,8 @@ class angle_range
#define VECPTR_TO_RANGE(v) (new angle_range(v, v))

STATUS IK_angle(float length1, float length2, float distance, float* angle);
int lineSeg_intersect(vector3f* a1, vector3f* a2, vector3f* b1, vector3f* b2);

float echo_sin(int deg);
float echo_cos(int deg);
float echo_sin(float deg);
Expand Down
Loading

0 comments on commit 554cedd

Please sign in to comment.