diff options
Diffstat (limited to 'src/game/collision.cpp')
| -rw-r--r-- | src/game/collision.cpp | 223 |
1 files changed, 169 insertions, 54 deletions
diff --git a/src/game/collision.cpp b/src/game/collision.cpp index 73f4a9c5..0dee57c8 100644 --- a/src/game/collision.cpp +++ b/src/game/collision.cpp @@ -1,87 +1,202 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +// copyright (c) 2007 magnus auvinen, see licence.txt for more info #include <base/system.h> -#include <base/math.hpp> -#include <base/vmath.hpp> +#include <base/math.h> +#include <base/vmath.h> #include <math.h> -#include <engine/e_common_interface.h> -#include <game/mapitems.hpp> -#include <game/layers.hpp> -#include <game/collision.hpp> +#include <engine/map.h> +#include <engine/kernel.h> -static TILE *tiles; -static int width = 0; -static int height = 0; +#include <game/mapitems.h> +#include <game/layers.h> +#include <game/collision.h> -int col_width() { return width; } -int col_height() { return height; } +CCollision::CCollision() +{ + m_pTiles = 0; + m_Width = 0; + m_Height = 0; + m_pLayers = 0; +} -int col_init() +void CCollision::Init(class CLayers *pLayers) { - width = layers_game_layer()->width; - height = layers_game_layer()->height; - tiles = (TILE *)map_get_data(layers_game_layer()->data); + m_pLayers = pLayers; + m_Width = m_pLayers->GameLayer()->m_Width; + m_Height = m_pLayers->GameLayer()->m_Height; + m_pTiles = static_cast<CTile *>(m_pLayers->Map()->GetData(m_pLayers->GameLayer()->m_Data)); - for(int i = 0; i < width*height; i++) + for(int i = 0; i < m_Width*m_Height; i++) { - int index = tiles[i].index; + int Index = m_pTiles[i].m_Index; - if(index > 128) + if(Index > 128) continue; - if(index == TILE_DEATH) - tiles[i].index = COLFLAG_DEATH; - else if(index == TILE_SOLID) - tiles[i].index = COLFLAG_SOLID; - else if(index == TILE_NOHOOK) - tiles[i].index = COLFLAG_SOLID|COLFLAG_NOHOOK; - else - tiles[i].index = 0; + switch(Index) + { + case TILE_DEATH: + m_pTiles[i].m_Index = COLFLAG_DEATH; + break; + case TILE_SOLID: + m_pTiles[i].m_Index = COLFLAG_SOLID; + break; + case TILE_NOHOOK: + m_pTiles[i].m_Index = COLFLAG_SOLID|COLFLAG_NOHOOK; + break; + default: + m_pTiles[i].m_Index = 0; + } } - - return 1; } - -int col_get(int x, int y) +int CCollision::GetTile(int x, int y) { - int nx = clamp(x/32, 0, width-1); - int ny = clamp(y/32, 0, height-1); + int nx = clamp(x/32, 0, m_Width-1); + int ny = clamp(y/32, 0, m_Height-1); - if(tiles[ny*width+nx].index > 128) - return 0; - return tiles[ny*width+nx].index; + return m_pTiles[ny*m_Width+nx].m_Index > 128 ? 0 : m_pTiles[ny*m_Width+nx].m_Index; } -int col_is_solid(int x, int y) +bool CCollision::IsTileSolid(int x, int y) { - return col_get(x,y)&COLFLAG_SOLID; + return GetTile(x,y)&COLFLAG_SOLID; } - // TODO: rewrite this smarter! -int col_intersect_line(vec2 pos0, vec2 pos1, vec2 *out_collision, vec2 *out_before_collision) +int CCollision::IntersectLine(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision) { - float d = distance(pos0, pos1); - vec2 last = pos0; + float d = distance(Pos0, Pos1); + vec2 Last = Pos0; for(float f = 0; f < d; f++) { float a = f/d; - vec2 pos = mix(pos0, pos1, a); - if(col_is_solid(round(pos.x), round(pos.y))) + vec2 Pos = mix(Pos0, Pos1, a); + if(CheckPoint(Pos.x, Pos.y)) { - if(out_collision) - *out_collision = pos; - if(out_before_collision) - *out_before_collision = last; - return col_get(round(pos.x), round(pos.y)); + if(pOutCollision) + *pOutCollision = Pos; + if(pOutBeforeCollision) + *pOutBeforeCollision = Last; + return GetCollisionAt(Pos.x, Pos.y); } - last = pos; + Last = Pos; } - if(out_collision) - *out_collision = pos1; - if(out_before_collision) - *out_before_collision = pos1; + if(pOutCollision) + *pOutCollision = Pos1; + if(pOutBeforeCollision) + *pOutBeforeCollision = Pos1; return 0; } + +// TODO: OPT: rewrite this smarter! +void CCollision::MovePoint(vec2 *pInoutPos, vec2 *pInoutVel, float Elasticity, int *pBounces) +{ + if(pBounces) + *pBounces = 0; + + vec2 Pos = *pInoutPos; + vec2 Vel = *pInoutVel; + if(CheckPoint(Pos + Vel)) + { + int Affected = 0; + if(CheckPoint(Pos.x + Vel.x, Pos.y)) + { + pInoutVel->x *= -Elasticity; + if(pBounces) + (*pBounces)++; + Affected++; + } + + if(CheckPoint(Pos.x, Pos.y + Vel.y)) + { + pInoutVel->y *= -Elasticity; + if(pBounces) + (*pBounces)++; + Affected++; + } + + if(Affected == 0) + { + pInoutVel->x *= -Elasticity; + pInoutVel->y *= -Elasticity; + } + } + else + { + *pInoutPos = Pos + Vel; + } +} + +bool CCollision::TestBox(vec2 Pos, vec2 Size) +{ + Size *= 0.5f; + if(CheckPoint(Pos.x-Size.x, Pos.y-Size.y)) + return true; + if(CheckPoint(Pos.x+Size.x, Pos.y-Size.y)) + return true; + if(CheckPoint(Pos.x-Size.x, Pos.y+Size.y)) + return true; + if(CheckPoint(Pos.x+Size.x, Pos.y+Size.y)) + return true; + return false; +} + +void CCollision::MoveBox(vec2 *pInoutPos, vec2 *pInoutVel, vec2 Size, float Elasticity) +{ + // do the move + vec2 Pos = *pInoutPos; + vec2 Vel = *pInoutVel; + + float Distance = length(Vel); + int Max = (int)Distance; + + if(Distance > 0.00001f) + { + //vec2 old_pos = pos; + float Fraction = 1.0f/(float)(Max+1); + for(int i = 0; i <= Max; i++) + { + //float amount = i/(float)max; + //if(max == 0) + //amount = 0; + + vec2 NewPos = Pos + Vel*Fraction; // TODO: this row is not nice + + if(TestBox(vec2(NewPos.x, NewPos.y), Size)) + { + int Hits = 0; + + if(TestBox(vec2(Pos.x, NewPos.y), Size)) + { + NewPos.y = Pos.y; + Vel.y *= -Elasticity; + Hits++; + } + + if(TestBox(vec2(NewPos.x, Pos.y), Size)) + { + NewPos.x = Pos.x; + Vel.x *= -Elasticity; + Hits++; + } + + // neither of the tests got a collision. + // this is a real _corner case_! + if(Hits == 0) + { + NewPos.y = Pos.y; + Vel.y *= -Elasticity; + NewPos.x = Pos.x; + Vel.x *= -Elasticity; + } + } + + Pos = NewPos; + } + } + + *pInoutPos = Pos; + *pInoutVel = Vel; +} |