shoot: mnit version
[nit.git] / examples / shoot / src / shoot.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 # Space shooter.
16 # This program is a fun game but also a good example of the scene2d module
17 module shoot
18
19 import mnit
20 import shoot_logic
21
22 redef class Sprite
23 # mnit specific method to draw a sprite
24 # app is used to optain the assets and the display
25 # Each sprite should implements this method
26 fun draw_on_display(app: ShootApp) do end
27
28 # Helper function to draw an image centered on the current sprite position
29 fun draw_image(app: ShootApp, img: Image)
30 do
31 app.display.blit_centered(img, self.x/100, self.y/100)
32 end
33
34 # Helper function to draw an image translated and rotated on the current sprite position
35 fun draw_rotated_image(app: ShootApp, img: Image, dx, dy: Int, angle: Float)
36 do
37 app.display.blit_rotated(img, self.x.to_f/100.0, self.y.to_f/100.0, angle)
38 end
39 end
40
41 redef class Player
42 redef fun draw_on_display(app)
43 do
44 if protected_ttl > 30 and protected_ttl%10 > 5 then return # blink on protected
45 draw_image(app, app.img_player)
46 end
47 end
48
49 redef class Shoot
50 redef fun draw_on_display(app)
51 do
52 var img = if enemy then app.img_enemy_shoot else app.img_player_shoot
53 draw_image(app, img)
54 end
55 end
56
57 redef class Missile
58 redef fun draw_on_display(app)
59 do
60 var angle = velocity_angle
61 var img = if enemy then app.img_enemy_missile else app.img_player_missile
62 draw_rotated_image(app, img, 0, 0, angle)
63 end
64 end
65
66 redef class Enemy0
67 redef fun draw_on_display(app)
68 do
69 draw_image(app, app.img_enemy0)
70 end
71 end
72
73 redef class Enemy1
74 redef fun draw_on_display(app)
75 do
76 draw_image(app, app.img_enemy1)
77 end
78 end
79
80 redef class Enemy2
81 redef fun draw_on_display(app)
82 do
83 draw_image(app, app.img_enemy2)
84 end
85 end
86
87 redef class Enemy3
88 redef fun draw_on_display(app)
89 do
90 draw_image(app, app.img_enemy3)
91 end
92 end
93
94 redef class Enemy4
95 redef fun draw_on_display(app)
96 do
97 draw_image(app, app.img_enemy4)
98 draw_rotated_image(app, app.img_enemy4_turret, 0, 0, self.angle)
99 end
100 end
101
102 redef class EnemyKamikaze
103 redef fun draw_on_display(app)
104 do
105 var angle = self.velocity_angle
106 draw_rotated_image(app, app.img_enemy_kamikaze, 0, 0, angle)
107 end
108 end
109
110 redef class Boss
111 redef fun draw_on_display(app)
112 do
113 if flick_ttl > 0 then return
114 draw_image(app, app.img_boss)
115 end
116 end
117
118 redef class BossPart
119 redef fun draw_on_display(app)
120 do
121 if flick_ttl > 0 then return
122 if relx > 0 then
123 self.boss.draw_image(app, app.img_boss_right)
124 else
125 self.boss.draw_image(app, app.img_boss_left)
126 end
127 end
128 end
129
130 redef class Money
131 redef fun draw_on_display(app)
132 do
133 draw_image(app, app.img_money)
134 end
135 end
136
137 redef class UpMissile
138 redef fun draw_on_display(app)
139 do
140 draw_image(app, app.img_upmissile)
141 end
142 end
143
144 redef class Explosion
145 redef fun draw_on_display(app)
146 do
147 draw_image(app, app.img_explosion)
148 end
149 end
150
151 redef class Star
152 redef fun draw_on_display(app)
153 do
154 # Simulate depth:
155 # More a star is fast, more it requires a bright image
156 var img: Image
157 if self.vy < 20 then
158 img = app.img_star0
159 else if self.vy < 40 then
160 img = app.img_star1
161 else
162 img = app.img_star2
163 end
164 draw_image(app, img)
165 end
166 end
167
168 redef class Scene
169 fun draw_on_display(app: ShootApp) do end
170 fun input(input_event: InputEvent): Bool do return false
171 end
172
173 redef class PlayScene
174 redef fun draw_on_display(app)
175 do
176 app.display.clear( 0.0, 0.0, 0.0 )
177 self.sprites.draw(app)
178 for i in [0..player.money[
179 do
180 app.display.blit(app.img_money, 10, 590-i)
181 end
182 for i in [1..player.nbshoots]
183 do
184 app.display.blit(app.img_player_shoot, 30, 590 - i*10)
185 end
186 for i in [1..player.nbmissiles]
187 do
188 app.display.blit(app.img_player_missile, 40, 590 - i*20)
189 end
190 end
191
192 redef fun input( input_event )
193 do
194 var speed = 400
195 if input_event isa KeyEvent then
196 if input_event.is_arrow_down then
197 if input_event.is_down then
198 player.vy = speed
199 else
200 player.vy = 0
201 end
202 else if input_event.is_arrow_up then
203 if input_event.is_down then
204 player.vy = -speed
205 else
206 player.vy = 0
207 end
208 else if input_event.is_arrow_left then
209 if input_event.is_down then
210 player.vx = -speed
211 else
212 player.vx = 0
213 end
214 else if input_event.is_arrow_right then
215 if input_event.is_down then
216 player.vx = speed
217 else
218 player.vx = 0
219 end
220 end
221 end
222 return false # unknown event, can be handled by something else
223 end
224 end
225
226 ###
227
228 redef class MenuScene
229 redef fun draw_on_display(app)
230 do
231 app.display.blit(app.img_splash, 0, 0)
232 sprites.draw(app)
233 if not play or ttl%10 > 5 then
234 app.display.blit(app.img_splash_play, 0, 0)
235 end
236 end
237
238 redef fun input(input_event)
239 do
240 if input_event isa KeyEvent then
241 play = true
242 return true
243 end
244 return false
245 end
246 end
247
248 ###
249
250 class ShootApp
251 super App
252 super View
253
254 var debug: Bool = false
255
256 redef fun draw_sprite(s: Sprite)
257 do
258 s.draw_on_display(self)
259 if debug and s.width != 0 and s.height != 0 then
260 var left = s.left.to_f/100.0
261 var right = s.right.to_f/100.0
262 var top = s.top.to_f/100.0
263 var bot = s.bottom.to_f/100.0
264 display.blit_stretched(img_hitbox, right, top, right, bot, left, bot, left, top)
265 end
266 end
267
268 init do super
269
270 var scene: Scene
271
272 var img_hitbox: Image
273
274 var img_splash: Image
275 var img_splash_play: Image
276
277 var img_player: Image
278 var img_player_shoot: Image
279 var img_player_missile: Image
280 var img_enemy0: Image
281 var img_enemy1: Image
282 var img_enemy2: Image
283 var img_enemy3: Image
284 var img_enemy4: Image
285 var img_enemy4_turret: Image
286 var img_enemy_kamikaze: Image
287 var img_enemy_shoot: Image
288 var img_enemy_missile: Image
289 var img_money: Image
290 var img_upmissile: Image
291 var img_explosion: Image
292 var img_star0: Image
293 var img_star1: Image
294 var img_star2: Image
295
296 var img_boss: Image
297 var img_boss_left: Image
298 var img_boss_right: Image
299
300 redef fun init_window
301 do
302 super
303
304 # TODO load assets here
305 # ex: img = load_image( "img.png" )
306 # to get file located at assets/img.png before deployement
307 self.img_hitbox = load_image("hitbox.png")
308
309 self.img_splash = load_image("splash.png")
310 self.img_splash_play = load_image("splash_play.png")
311
312 self.img_player = load_image("player.png")
313 self.img_player_shoot = load_image("player_shoot.png")
314 self.img_player_missile = load_image("player_missile.png")
315 self.img_enemy0 = load_image("enemy0.png")
316 self.img_enemy1 = load_image("enemy1.png")
317 self.img_enemy2 = load_image("enemy2.png")
318 self.img_enemy3 = load_image("enemy3.png")
319 self.img_enemy4 = load_image("enemy4.png")
320 self.img_enemy4_turret = load_image("enemy4_turret.png")
321 self.img_enemy_kamikaze = load_image("enemy_kamikaze.png")
322 self.img_enemy_shoot = load_image("enemy_shoot.png")
323 self.img_enemy_missile = load_image("enemy_missile.png")
324 self.img_money = load_image("money.png")
325 self.img_upmissile = load_image("up_missile.png")
326 self.img_explosion = load_image("explosion.png")
327 self.img_star0 = load_image("star0.png")
328 self.img_star1 = load_image("star1.png")
329 self.img_star2 = load_image("star2.png")
330 self.img_boss = load_image("boss.png")
331 self.img_boss_left = load_image("boss_left.png")
332 self.img_boss_right = load_image("boss_right.png")
333
334 self.scene = new MenuScene
335 end
336
337 redef fun frame_core( display )
338 # the arg display is not null but otherwise the same than self.display
339 do
340 if not paused then
341 self.scene.update
342 var next = self.scene.next_scene
343 if next != null then
344 self.scene = next
345 end
346 if not self.scene.exists then quit = true
347 end
348 self.scene.draw_on_display(self)
349
350 # Wait the next frame
351 sys.nanosleep(0, 16000000)
352 end
353
354 var paused: Bool = false
355
356 redef fun input( input_event )
357 do
358 if input_event isa QuitEvent then # close window button
359 quit = true # orders system to quit
360 return true # this event has been handled
361 else if input_event isa KeyEvent then
362 if input_event.to_c == 'p' then
363 paused = input_event.is_down
364 return true # this event has been handled
365 else if input_event.to_c == 'q' then
366 quit = true # orders system to quit
367 return true # this event has been handled
368 end
369 end
370
371 # Maybe the event is specific to the scene
372 return self.scene.input(input_event)
373 end
374 end
375
376 if args.length > 0 and args.first == "--headless" then
377 headless_run
378 return
379 end
380
381 var app = new ShootApp
382 app.debug = args.length > 0 and args.first == "--debug"
383 app.main_loop