lib: move game.nit as lib/scene2d.nit
[nit.git] / lib / scene2d.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 # 2D management of game elements
16 #
17 # TODO: collision framework (with quad tree?)
18 module scene2d
19
20 # The root class of the living objects (sprites, group of sprites, etc.)
21 abstract class LiveObject
22 # Compute the position, state and appearance.
23 fun update do end
24
25 # Controls whether `update' and `draw' are automatically called by `LiveGroup'
26 var exists writable = true
27
28 # Redefine this method to asks how to draw on a view
29 fun draw(view: View) is abstract
30 end
31
32
33 # The basic atomic living and moving object.
34 #
35 # A sprite has a position and a velocity
36 class Sprite
37 super LiveObject
38
39 # x coordinate of the center point
40 var x: Int writable = 0
41
42 # y coordinate of the center point
43 var y: Int writable = 0
44
45 # width of the sprite
46 var width: Int writable = 100
47
48 # height of the sprite
49 var height: Int writable = 100
50
51 fun left: Int do return x - width/2
52 fun right: Int do return x + width/2
53 fun top: Int do return y - height/2
54 fun bottom: Int do return y + height/2
55
56 # x velocity (applied by `update')
57 var vx: Int writable = 0
58
59 # y velocity (applied by `update')
60 var vy: Int writable = 0
61
62 redef fun update
63 do
64 self.x += self.vx
65 self.y += self.vy
66 end
67
68 redef fun draw(view) do view.draw_sprite(self)
69
70 # Is self overlaps (or contains) an other sprite
71 # `x', `y', `width', and `height' of both sprites are considered
72 fun overlaps(other: Sprite): Bool
73 do
74 return self.right > other.left and self.left < other.right and self.bottom > other.top and self.top < other.bottom
75 end
76
77 # Return the current angle of velocity
78 # Often used to rotate the displayed image with the correct angle
79 fun velocity_angle: Float
80 do
81 return atan2(self.vx.to_f, -self.vy.to_f)
82 end
83
84 # Return the angle to target an other sprite
85 fun angle_to(target: Sprite): Float
86 do
87 return atan2((target.x-self.x).to_f, (self.y-target.y).to_f)
88 end
89
90 # Update of vx and vy toward a given angle and magnitude
91 fun set_velocity(angle: Float, maginude: Int)
92 do
93 var magf = maginude.to_f
94 self.vx = (angle.sin * magf).to_i
95 self.vy = (angle.cos * -magf).to_i
96 end
97
98 end
99
100 # Organizational class to manage groups of sprites and other live objects.
101 class LiveGroup[E: LiveObject]
102 super LiveObject
103 super List[E]
104
105 init
106 do
107 end
108
109 # Recursively update each live objects that `exists'
110 redef fun update
111 do
112 for x in self do if x.exists then x.update
113 end
114
115 # Remove all live Objects that do not exists
116 # Call this to cleanup the live group
117 fun gc
118 do
119 var i = self.iterator
120 while i.is_ok do
121 var e = i.item
122 if not e.exists then
123 i.delete
124 else if e isa LiveGroup[LiveObject] then
125 e.gc
126 end
127 i.next
128 end
129 end
130
131 # Recursively draw each live objects that `exists'
132 redef fun draw(view)
133 do
134 for x in self do if x.exists then x.draw(view)
135 end
136 end
137
138 # A state in the game logic
139 # A scene manage a bunch of live objects
140 class Scene
141 super LiveObject
142 end
143
144 # Abstract view do draw sprites
145 #
146 # Concrete views are specific for each back-end.
147 # View can also be used to implements camera and other fun things.
148 interface View
149 # Draw a specific sprite on the view
150 #
151 # This method must be implemented for each specific view.
152 # A traditional way of implementation is to use a double-dispatch mechanism
153 #
154 # Exemple:
155 # class MyView
156 # redef fun draw_sprite(s) do s.draw_on_myview(self)
157 # end
158 # redef class Sprite
159 # # How to draw a sprite on my specific view
160 # fun draw_on_myview(myview: MyView) is abstract
161 # end
162 fun draw_sprite(s: Sprite) is abstract
163 end