about summary refs log tree commit diff
path: root/src/game/collision.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/collision.cpp')
-rw-r--r--src/game/collision.cpp223
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;
+}