ecdc64a11ab6e5d8ae5473d6b75e4402d5bf46d8
[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
28 # Center of the hole
29 var x: Int
30 var y: Int
31
32 # Half width of the hit box
33 var dx = 200.0
34 # Heigth of the hit box
35 var dy = 800.0
36
37 # state
38 var up = false
39 var hitted = false
40
41 init (g: Game, x, y: Int)
42 do
43 game = g
44 self.x = x
45 self.y = y
46 end
47
48 fun do_turn
49 do
50 if up then
51 if hitted then
52 if (20.0*game.speed_modifier).to_i.rand == 0 then
53 # dead / hide
54 hitted = false
55 up = false
56 end
57 else if (80.0*game.speed_modifier).to_i.rand == 0 then
58 # hide
59 up = false
60 end
61 else if (100.0*game.speed_modifier).to_i.rand == 0 then
62 # show up
63 up = true
64 end
65 end
66
67 fun intercepts(event: PointerEvent): Bool
68 do
69 if not up or hitted then return false
70
71 var dx = (dx*display_scale).to_i
72 var dy = (dy*display_scale).to_i
73 var ex = event.x.to_i - display_offset_x
74 var ey = event.y.to_i - display_offset_y
75 return ex > x - dx and ex < x + dx and
76 ey > y - dy and ey < y
77 end
78
79 fun hit
80 do
81 if hitted then return
82
83 if up then
84 hitted = true
85 game.points += 1
86 else abort # should not happen
87 end
88 end
89
90 class Game
91 var holes = new Array[Hole].with_capacity(4)
92
93 # rule / const
94 var modifier_half_life = 40.0
95 fun rows: Int do return 4
96 fun columns: Int do return 5
97
98 # state
99 var points = 0
100 var speed_modifier = 1.0
101
102 # configs
103 var dist_between_rows = 512
104 var dist_between_columns = 600
105 fun global_speed_modifier: Float do return 2.0
106
107 init
108 do
109 var dx = (dist_between_columns.to_f*display_scale).to_i
110 var dy = (dist_between_rows.to_f*display_scale).to_i
111 for x in [0 .. columns[ do
112 for y in [0 .. rows[ do
113 holes.add(new Hole(self, x*dx, y*dy))
114 end
115 end
116 end
117
118 fun do_turn do
119 for hole in holes do hole.do_turn
120
121 speed_modifier = modifier_half_life / (modifier_half_life+points.to_f) * global_speed_modifier
122 end
123 end
124
125 # Where all the UI stuff is done
126 class Screen
127 var empty_img: Image
128 var up_img: Image
129 var hit_img: Image
130 var numbers: NumberImages
131
132 var game = new Game
133
134 init (app: App)
135 do
136 empty_img = app.load_image("images/empty.png")
137 up_img = app.load_image("images/up.png")
138 hit_img = app.load_image("images/hit.png")
139 numbers = app.load_numbers("images/#.png")
140 end
141
142 fun do_frame(display: Display)
143 do
144 display.clear(0.0, 0.7, 0.0)
145
146 for hole in game.holes do
147 var img
148 var dx
149 var dy
150
151 if hole.hitted then
152 img = hit_img
153 dx = 256.0*display_scale
154 dy = 417.0*display_scale
155 else if hole.up then
156 img = up_img
157 dx = 512.0*display_scale
158 dy = 830.0*display_scale
159 else
160 img = empty_img
161 dx = 256.0*display_scale
162 dy = 244.0*display_scale
163 end
164
165 img.scale = display_scale
166 display.blit(img, hole.x-dx.to_i+display_offset_x, hole.y-dy.to_i+display_offset_y)
167 end
168
169 display.blit_number(numbers, game.points, 20, 20)
170 end
171
172 fun input(event: InputEvent): Bool
173 do
174 if event isa PointerEvent then
175 for hole in game.holes do
176 if hole.intercepts(event) then
177 if hole.up then hole.hit
178 return true
179 end
180 end
181 end
182
183 return false
184 end
185 end
186
187 class MyApp
188 super App
189
190 var screen: nullable Screen = null
191
192 var target_dt = 20000000
193
194 init do super
195
196 redef fun init_window
197 do
198 super
199
200 init_screen_and_game
201 end
202
203 fun init_screen_and_game do screen = new Screen(self)
204
205 redef fun frame_core(display)
206 do
207 var screen = self.screen
208 if screen != null then
209 var clock = new Clock
210
211 screen.game.do_turn
212 screen.do_frame(display)
213
214 var dt = clock.lapse
215 if dt.sec == 0 and dt.nanosec < target_dt then
216 var sleep_t = target_dt - dt.nanosec
217 sys.nanosleep(0, sleep_t)
218 end
219 end
220 end
221
222 redef fun input(ie)
223 do
224 var screen = screen
225 if ie isa QuitEvent or
226 (ie isa KeyEvent and ie.to_c == 'q') then
227 quit = true
228 return true
229 else if screen != null then
230 return screen.input(ie)
231 else
232 print "unknown input: {ie}"
233 return false
234 end
235 end
236 end
237
238 fun display_scale: Float do return 1.0
239
240 # Depends on the hole center in the uo image
241 fun display_offset_x: Int do return (512.0*display_scale).to_i
242
243 # Depends on the width of the holes
244 fun display_offset_y: Int do return (800.0*display_scale).to_i
245
246 var app = new MyApp
247 app.main_loop