moles: improve the documentation
[nit.git] / examples / mnit_moles / src / moles.nit
1 # This file is part of NIT (http://www.nitlanguage.org).
2 #
3 # Copyright 2012-2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Classic moles game
18 #
19 # This is a minimal practical example of the mnit framework.
20 module moles
21
22 import mnit
23 import realtime
24
25 class Hole
26 var game: Game
27 var x: Int
28 var y: Int
29 var dim: Int
30
31 # state
32 var up = false
33 var hitted = false
34
35 init (g: Game, x, y: Int)
36 do
37 game = g
38 self.x = x
39 self.y = y
40 dim = game.img_dim
41 end
42
43 fun do_turn
44 do
45 if up then
46 if hitted then
47 if (20.0*game.speed_modifier).to_i.rand == 0 then
48 # dead / hide
49 hitted = false
50 up = false
51 end
52 else if (80.0*game.speed_modifier).to_i.rand == 0 then
53 # hide
54 up = false
55 end
56 else if (100.0*game.speed_modifier).to_i.rand == 0 then
57 # show up
58 up = true
59 end
60 end
61
62 fun intercepts(event: PointerEvent): Bool
63 do
64 var ex = event.x.to_i
65 var ey = event.y.to_i
66 return ex > x and ex < x + dim and
67 ey > y and ey < y + dim
68 end
69
70 fun hit
71 do
72 if hitted then return
73
74 if up then
75 hitted = true
76 game.points += 1
77 else abort # should not happen
78 end
79 end
80
81 class Game
82 var holes = new Array[Hole].with_capacity(4)
83
84 # rule / const
85 var modifier_half_life = 40.0
86 var rows = 5
87 var columns = 3
88
89 # state
90 var points = 0
91 var speed_modifier = 1.0
92
93 # configs
94 var img_ori_dim: Int = 256
95 fun img_dim: Int do return 210
96 fun global_speed_modifier: Float do return 2.0
97
98 init
99 do
100 var d = img_dim
101 for x in [0 .. rows[do
102 for y in [0 .. columns[do
103 holes.add(new Hole(self, x*d, y*d))
104 end
105 end
106 end
107
108 fun do_turn do
109 for hole in holes do hole.do_turn
110
111 speed_modifier = modifier_half_life / (modifier_half_life+points.to_f) * global_speed_modifier
112 end
113 end
114
115 # Where all the UI stuff is done
116 class Screen
117 var empty_img: Image
118 var up_img: Image
119 var hit_img: Image
120 var numbers: NumberImages
121
122 var game = new Game
123
124 init (app: App)
125 do
126 empty_img = app.load_image("images/empty.png")
127 up_img = app.load_image("images/up.png")
128 hit_img = app.load_image("images/hit.png")
129 numbers = app.load_numbers("images/#.png")
130
131 var scale = game.img_dim.to_f / game.img_ori_dim.to_f
132 empty_img.scale = scale
133 up_img.scale = scale
134 hit_img.scale = scale
135 end
136
137 fun do_frame(display: Display)
138 do
139 display.clear(0.0, 0.7, 0.0)
140
141 for hole in game.holes do
142 var img
143
144 if hole.hitted then
145 img = hit_img
146 else if hole.up then
147 img = up_img
148 else
149 img = empty_img
150 end
151
152 display.blit(img, hole.x, hole.y-64)
153 end
154
155 display.blit_number(numbers, game.points, 20, 20)
156 end
157
158 fun input(event: InputEvent): Bool
159 do
160 if event isa PointerEvent then
161 for hole in game.holes do
162 if hole.intercepts(event) then
163 if hole.up then hole.hit
164 return true
165 end
166 end
167 end
168
169 return false
170 end
171 end
172
173 class MyApp
174 super App
175
176 var screen: nullable Screen = null
177
178 var target_dt = 20000000
179
180 init do super
181
182 redef fun init_window
183 do
184 super
185
186 screen = new Screen(self)
187 end
188
189 redef fun frame_core(display)
190 do
191 var screen = self.screen
192 if screen != null then
193 var clock = new Clock
194
195 screen.game.do_turn
196 screen.do_frame(display)
197
198 var dt = clock.lapse
199 if dt.sec == 0 and dt.nanosec < target_dt then
200 var sleep_t = target_dt - dt.nanosec
201 sys.nanosleep(0, sleep_t)
202 end
203 end
204 end
205
206 redef fun input(ie)
207 do
208 var screen = screen
209 if ie isa QuitEvent or
210 (ie isa KeyEvent and ie.to_c == 'q') then
211 quit = true
212 return true
213 else if screen != null then
214 return screen.input(ie)
215 else
216 print "unknown input: {ie}"
217 return false
218 end
219 end
220 end
221
222 var app = new MyApp
223 app.main_loop