mnit: update examples to use maximim_fps
[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
24 class Hole
25 var game: Game
26
27 # Center of the hole
28 var x: Int
29 var y: Int
30
31 # Half width of the hit box
32 var dx = 200.0
33 # Heigth of the hit box
34 var dy = 800.0
35
36 # state
37 var up = false
38 var hitted = false
39 var trap = 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
65 # shot traps only at 50 points and up
66 trap = false
67 if game.points > 50 then
68
69 # After 50 points we have more and more traps until point 1000
70 var d = 1250-(game.points - 50)
71 if d < 200 then d = 200
72
73 if d.rand < 100 then trap = true
74 end
75 end
76 end
77
78 fun intercepts(event: PointerEvent): Bool
79 do
80 if not up or hitted then return false
81
82 var dx = (dx*display_scale).to_i
83 var dy = (dy*display_scale).to_i
84 var ex = event.x.to_i - display_offset_x
85 var ey = event.y.to_i - display_offset_y
86 return ex > x - dx and ex < x + dx and
87 ey > y - dy and ey < y
88 end
89
90 fun hit
91 do
92 if hitted then return
93
94 if trap then
95 up = false
96 game.points -= 5
97 if game.points < 0 then game.points = 0
98 else
99 hitted = true
100 game.points += 1
101 end
102 end
103 end
104
105 class Game
106 var holes = new Array[Hole].with_capacity(4)
107
108 # rule / const
109 var modifier_half_life = 1000.0
110 fun rows: Int do return 4
111 fun columns: Int do return 5
112
113 # state
114 var points = 0
115 var speed_modifier = 1.0
116
117 # configs
118 var dist_between_rows = 512
119 var dist_between_columns = 600
120 fun global_speed_modifier: Float do return 2.0
121
122 init
123 do
124 var dx = (dist_between_columns.to_f*display_scale).to_i
125 var dy = (dist_between_rows.to_f*display_scale).to_i
126 for x in [0 .. columns[ do
127 for y in [0 .. rows[ do
128 holes.add(new Hole(self, x*dx, y*dy))
129 end
130 end
131 end
132
133 fun do_turn do
134 for hole in holes do hole.do_turn
135
136 speed_modifier = modifier_half_life / (modifier_half_life+points.to_f) * global_speed_modifier
137 end
138 end
139
140 # Where all the UI stuff is done
141 class Screen
142 var empty_img: Image
143 var up_img: Image
144 var hit_img: Image
145 var trap_img: Image
146 var numbers: NumberImages
147
148 var sign_warning: Image
149 var sign_cute: Image
150 var sign_hits: Image
151
152 var game = new Game
153
154 init (app: App)
155 do
156 empty_img = app.load_image("images/empty.png")
157 up_img = app.load_image("images/up.png")
158 hit_img = app.load_image("images/hit.png")
159 trap_img = app.load_image("images/trap.png")
160 numbers = app.load_numbers("images/#.png")
161
162 sign_warning = app.load_image("images/sign-warning.png")
163 sign_cute = app.load_image("images/sign-cute.png")
164 sign_hits = app.load_image("images/sign-hits.png")
165 end
166
167 fun do_frame(display: Display)
168 do
169 display.clear(0.1, 0.65, 0.2)
170
171 sign_warning.scale = display_scale
172 sign_cute.scale = display_scale
173 sign_hits.scale = display_scale
174 for img in numbers.imgs do img.scale = display_scale
175
176 display.blit(sign_warning, (-120.0*display_scale).to_i, (-235.0*display_scale).to_i)
177 display.blit(sign_cute, (540.0*display_scale).to_i, (-180.0*display_scale).to_i)
178 display.blit(sign_hits, (1340.0*display_scale).to_i, (55.0*display_scale).to_i)
179 display.blit_number(numbers, game.points, (1460.0*display_scale).to_i, (270.0*display_scale).to_i)
180
181 for hole in game.holes do
182 # Hole
183 var img = empty_img
184 var dx = 512.0*display_scale
185 var dy = 512.0*display_scale
186 img.scale = display_scale
187 display.blit(img, hole.x-dx.to_i+display_offset_x, hole.y-dy.to_i+display_offset_y)
188
189 # Mole
190 var empty = false
191 if hole.hitted then
192 img = hit_img
193 dx = 256.0*display_scale
194 dy = 417.0*display_scale
195 else if hole.up then
196 if hole.trap then
197 img = trap_img
198 dx = 512.0*display_scale
199 dy = 830.0*display_scale
200 else
201 img = up_img
202 dx = 512.0*display_scale
203 dy = 830.0*display_scale
204 end
205 else empty = true
206
207 if not empty then
208 img.scale = display_scale
209 display.blit(img, hole.x-dx.to_i+display_offset_x, hole.y-dy.to_i+display_offset_y)
210 end
211 end
212 end
213
214 fun input(event: InputEvent): Bool
215 do
216 if event isa PointerEvent then
217 for hole in game.holes do
218 if hole.intercepts(event) then
219 if hole.up then hole.hit
220 return true
221 end
222 end
223 end
224
225 return false
226 end
227 end
228
229 redef class App
230
231 var screen: nullable Screen = null
232
233 redef fun window_created
234 do
235 super
236
237 maximum_fps = 50
238 init_screen_and_game
239 end
240
241 fun init_screen_and_game do screen = new Screen(self)
242
243 redef fun frame_core(display)
244 do
245 var screen = self.screen
246 if screen != null then
247 screen.game.do_turn
248 screen.do_frame(display)
249 end
250 end
251
252 redef fun input(ie)
253 do
254 var screen = screen
255 if ie isa QuitEvent or
256 (ie isa KeyEvent and ie.to_c == 'q') then
257 quit = true
258 return true
259 else if screen != null then
260 return screen.input(ie)
261 else
262 print "unknown input: {ie}"
263 return false
264 end
265 end
266 end
267
268 fun display_scale: Float do return 1.0
269
270 # Depends on the hole center in the uo image
271 fun display_offset_x: Int do return (512.0*display_scale).to_i
272
273 # Depends on the width of the holes
274 fun display_offset_y: Int do return (800.0*display_scale).to_i