1 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2 /* If you are missing that file, acquire a complete release at teeworlds.com. */
3 #include <base/system.h>
5 #include <base/vmath.h>
8 #include <engine/map.h>
9 #include <engine/kernel.h>
11 #include <game/mapitems.h>
12 #include <game/layers.h>
13 #include <game/collision.h>
15 CCollision::CCollision()
23 void CCollision::Init(class CLayers
*pLayers
)
26 m_Width
= m_pLayers
->GameLayer()->m_Width
;
27 m_Height
= m_pLayers
->GameLayer()->m_Height
;
28 m_pTiles
= static_cast<CTile
*>(m_pLayers
->Map()->GetData(m_pLayers
->GameLayer()->m_Data
));
30 for(int i
= 0; i
< m_Width
*m_Height
; i
++)
32 int Index
= m_pTiles
[i
].m_Index
;
40 m_pTiles
[i
].m_Index
= COLFLAG_DEATH
;
43 m_pTiles
[i
].m_Index
= COLFLAG_SOLID
;
46 m_pTiles
[i
].m_Index
= COLFLAG_SOLID
|COLFLAG_NOHOOK
;
49 m_pTiles
[i
].m_Index
= 0;
54 int CCollision::GetTile(int x
, int y
)
56 int Nx
= clamp(x
/32, 0, m_Width
-1);
57 int Ny
= clamp(y
/32, 0, m_Height
-1);
59 return m_pTiles
[Ny
*m_Width
+Nx
].m_Index
> 128 ? 0 : m_pTiles
[Ny
*m_Width
+Nx
].m_Index
;
62 bool CCollision::IsTileSolid(int x
, int y
)
64 return GetTile(x
, y
)&COLFLAG_SOLID
;
67 // TODO: rewrite this smarter!
68 int CCollision::IntersectLine(vec2 Pos0
, vec2 Pos1
, vec2
*pOutCollision
, vec2
*pOutBeforeCollision
)
70 float Distance
= distance(Pos0
, Pos1
);
74 for(int i
= 0; i
< End
; i
++)
77 vec2 Pos
= mix(Pos0
, Pos1
, a
);
78 if(CheckPoint(Pos
.x
, Pos
.y
))
82 if(pOutBeforeCollision
)
83 *pOutBeforeCollision
= Last
;
84 return GetCollisionAt(Pos
.x
, Pos
.y
);
89 *pOutCollision
= Pos1
;
90 if(pOutBeforeCollision
)
91 *pOutBeforeCollision
= Pos1
;
95 // TODO: OPT: rewrite this smarter!
96 void CCollision::MovePoint(vec2
*pInoutPos
, vec2
*pInoutVel
, float Elasticity
, int *pBounces
)
101 vec2 Pos
= *pInoutPos
;
102 vec2 Vel
= *pInoutVel
;
103 if(CheckPoint(Pos
+ Vel
))
106 if(CheckPoint(Pos
.x
+ Vel
.x
, Pos
.y
))
108 pInoutVel
->x
*= -Elasticity
;
114 if(CheckPoint(Pos
.x
, Pos
.y
+ Vel
.y
))
116 pInoutVel
->y
*= -Elasticity
;
124 pInoutVel
->x
*= -Elasticity
;
125 pInoutVel
->y
*= -Elasticity
;
130 *pInoutPos
= Pos
+ Vel
;
134 bool CCollision::TestBox(vec2 Pos
, vec2 Size
)
137 if(CheckPoint(Pos
.x
-Size
.x
, Pos
.y
-Size
.y
))
139 if(CheckPoint(Pos
.x
+Size
.x
, Pos
.y
-Size
.y
))
141 if(CheckPoint(Pos
.x
-Size
.x
, Pos
.y
+Size
.y
))
143 if(CheckPoint(Pos
.x
+Size
.x
, Pos
.y
+Size
.y
))
148 void CCollision::MoveBox(vec2
*pInoutPos
, vec2
*pInoutVel
, vec2 Size
, float Elasticity
)
151 vec2 Pos
= *pInoutPos
;
152 vec2 Vel
= *pInoutVel
;
154 float Distance
= length(Vel
);
155 int Max
= (int)Distance
;
157 if(Distance
> 0.00001f
)
159 //vec2 old_pos = pos;
160 float Fraction
= 1.0f
/(float)(Max
+1);
161 for(int i
= 0; i
<= Max
; i
++)
163 //float amount = i/(float)max;
167 vec2 NewPos
= Pos
+ Vel
*Fraction
; // TODO: this row is not nice
169 if(TestBox(vec2(NewPos
.x
, NewPos
.y
), Size
))
173 if(TestBox(vec2(Pos
.x
, NewPos
.y
), Size
))
176 Vel
.y
*= -Elasticity
;
180 if(TestBox(vec2(NewPos
.x
, Pos
.y
), Size
))
183 Vel
.x
*= -Elasticity
;
187 // neither of the tests got a collision.
188 // this is a real _corner case_!
192 Vel
.y
*= -Elasticity
;
194 Vel
.x
*= -Elasticity
;