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