mnit_ballz: Collision gestion module
[nit.git] / examples / mnit_ballz / src / collision.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Geometric computations around vectors and points for collision detection
16 module collision
17
18 import geometry
19
20 # trigonometry
21
22 # Get the distance between `p1` and `p2`
23 fun distance(p1, p2: Point[Float]): Float
24 do
25 var x = p1.x - p2.x
26 var y = p1.y - p2.y
27 return ( x * x + y * y ).sqrt
28 end
29
30 # Get the magnitude (length) of `vector`
31 fun magnitude(vector: Point[Float]): Float do return ( vector.x * vector.x + vector.y * vector.y ).sqrt
32
33 # Get the unit vector of `vector`
34 fun unit_vector(vector: Point[Float]): Point[Float] do return new Point[Float](vector.x / magnitude(vector), vector.y / magnitude(vector))
35
36 # Get the dot product of vectors `v1` and `v2`
37 fun dot_product(v1, v2: Point[Float]): Float do return v1.x * v2.x + v1.y * v2.y
38
39 # Get the vector between `start_point` and `end_point`
40 fun vector_between(start_point, end_point: Point[Float]): Point[Float] do return new Point[Float](end_point.x - start_point.x, end_point.y - start_point.y)
41
42 # Returns the point on a line with endpoints `l1` and `l2` closest to `center`
43 fun point_closest_to_line(center, l1, l2: Point[Float]): Point[Float]
44 do
45 var luvector = unit_vector(vector_between(l1, l2))
46 var l_to_ball = vector_between(l1, center)
47
48 var projection = dot_product(l_to_ball, luvector)
49
50 if projection <= 0.0 then return l1
51 if projection >= distance(l1, l2) then return l2
52 return new Point[Float](l1.x + luvector.x * projection, l1.y + luvector.y * projection)
53 end
54
55 # Is the ball with the `center` and `radius` intersecting the line with the endpoints `l1` and `l2`?
56 fun is_intersecting(center, l1, l2: Point[Float], radius: Float): Bool
57 do
58 var closest = point_closest_to_line(center, l1, l2)
59 var distance = distance(center, closest)
60 return distance < radius
61 end
62
63 # Bouncing function, returns the new point of the center of the ball
64 fun bounce(center, l1, l2, offset: Point[Float]): Point[Float]
65 do
66 var bln = bounce_line_normal(center, l1, l2)
67 var dot = dot_product(offset, bln)
68 return new Point[Float](offset.x - (2.0 * dot * bln.x), offset.y - (2.0 * dot * bln.y))
69 end
70
71 private fun bounce_line_normal(center, l1, l2: Point[Float]): Point[Float]
72 do
73 var p = point_closest_to_line(center, l1, l2)
74 var v = vector_between(p, center)
75 return unit_vector(v)
76 end
77
78 # Rotate `p` around `center` through `angle`
79 fun rotate_point(p, center: Point[Float], angle: Float): Point[Float]
80 do
81 var s = angle.sin
82 var c = angle.cos
83
84 var nx = c * (p.x - center.x) - s * (p.y - center.y) + center.x
85 var ny = s * (p.x - center.x) + c * (p.y - center.y) + center.y
86 return new Point[Float](nx, ny)
87 end