1 # This file is part of NIT ( http://www.nitlanguage.org ).
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 # This program is a fun game but also a good example of the scene2d module
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
28 # Helper function to draw an image centered on the current sprite position
29 fun draw_image
(app
: ShootApp, img
: Image)
31 app
.display
.blit_centered
(img
, (self.x
.to_f
/app
.scale
).to_i
, (self.y
.to_f
/app
.scale
).to_i
)
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)
37 app
.display
.blit_rotated
(img
, self.x
.to_f
/app
.scale
, self.y
.to_f
/app
.scale
, angle
)
42 redef fun draw_on_display
(app
)
44 if protected_ttl
> 30 and protected_ttl
%10 > 5 then return # blink on protected
45 draw_image
(app
, app
.img_player
)
50 redef fun draw_on_display
(app
)
52 var img
= if enemy
then app
.img_enemy_shoot
else app
.img_player_shoot
58 redef fun draw_on_display
(app
)
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
)
67 redef fun draw_on_display
(app
)
69 draw_image
(app
, app
.img_enemy0
)
74 redef fun draw_on_display
(app
)
76 draw_image
(app
, app
.img_enemy1
)
81 redef fun draw_on_display
(app
)
83 draw_image
(app
, app
.img_enemy2
)
88 redef fun draw_on_display
(app
)
90 draw_image
(app
, app
.img_enemy3
)
95 redef fun draw_on_display
(app
)
97 draw_image
(app
, app
.img_enemy4
)
98 draw_rotated_image
(app
, app
.img_enemy4_turret
, 0, 0, self.angle
)
102 redef class EnemyKamikaze
103 redef fun draw_on_display
(app
)
105 var angle
= self.velocity_angle
106 draw_rotated_image
(app
, app
.img_enemy_kamikaze
, 0, 0, angle
)
111 redef fun draw_on_display
(app
)
113 if flick_ttl
> 0 then return
114 draw_image
(app
, app
.img_boss
)
119 redef fun draw_on_display
(app
)
121 if flick_ttl
> 0 then return
123 self.boss
.draw_image
(app
, app
.img_boss_right
)
125 self.boss
.draw_image
(app
, app
.img_boss_left
)
131 redef fun draw_on_display
(app
)
133 draw_image
(app
, app
.img_money
)
137 redef class UpMissile
138 redef fun draw_on_display
(app
)
140 draw_image
(app
, app
.img_upmissile
)
144 redef class Explosion
145 redef fun draw_on_display
(app
)
147 draw_image
(app
, app
.img_explosion
)
152 redef fun draw_on_display
(app
)
155 # More a star is fast, more it requires a bright image
159 else if self.vy
< 40 then
169 fun draw_on_display
(app
: ShootApp) do end
170 fun input
(app
: ShootApp, input_event
: InputEvent): Bool do return false
173 redef class PlayScene
174 redef fun draw_on_display
(app
)
176 app
.display
.clear
( 0.0, 0.0, 0.0 )
177 self.sprites
.draw
(app
)
178 for i
in [0..player
.money
[
180 app
.display
.blit
(app
.img_money
, 10, app
.display
.height-10-i
)
182 for i
in [1..player
.nbshoots
]
184 app
.display
.blit
(app
.img_player_shoot
, 30, app
.display
.height-10
- i
*10)
186 for i
in [1..player
.nbmissiles
]
188 app
.display
.blit
(app
.img_player_missile
, 40, app
.display
.height-10
- i
*20)
192 redef fun input
(app
, input_event
)
195 if input_event
isa KeyEvent then
196 if input_event
.is_arrow_down
then
197 if input_event
.is_down
then
202 else if input_event
.is_arrow_up
then
203 if input_event
.is_down
then
208 else if input_event
.is_arrow_left
then
209 if input_event
.is_down
then
214 else if input_event
.is_arrow_right
then
215 if input_event
.is_down
then
222 else if input_event
isa PointerEvent then
223 var x
= (input_event
.x
* app
.scale
).to_i
224 var y
= (input_event
.y
* app
.scale
).to_i
225 player
.goes_to
(x
, y
, speed
)
228 return false # unknown event, can be handled by something else
234 redef class MenuScene
235 redef fun draw_on_display
(app
)
237 var display
= app
.display
238 assert display
!= null
239 blit_fs
(display
, app
.img_splash
)
241 if not play
or ttl
%10 > 5 then
242 blit_fs
(display
, app
.img_splash_play
)
246 fun blit_fs
(d
: Display, img
: Image)
249 var h
= d
.height
.to_f
250 d
.blit_stretched
(img
, 0.0,0.0, 0.0,h
, w
,h
, w
,0.0)
253 redef fun input
(app
, input_event
)
255 if input_event
isa KeyEvent then
258 else if input_event
isa PointerEvent then
272 var debug
: Bool = false
274 redef fun draw_sprite
(s
: Sprite)
276 s
.draw_on_display
(self)
277 if debug
and s
.width
!= 0 and s
.height
!= 0 then
278 var left
= s
.left
.to_f
/scale
279 var right
= s
.right
.to_f
/scale
280 var top
= s
.top
.to_f
/scale
281 var bot
= s
.bottom
.to_f
/scale
282 display
.blit_stretched
(img_hitbox
, right
, top
, right
, bot
, left
, bot
, left
, top
)
290 var img_hitbox
: Image
292 var img_splash
: Image
293 var img_splash_play
: Image
295 var img_player
: Image
296 var img_player_shoot
: Image
297 var img_player_missile
: Image
298 var img_enemy0
: Image
299 var img_enemy1
: Image
300 var img_enemy2
: Image
301 var img_enemy3
: Image
302 var img_enemy4
: Image
303 var img_enemy4_turret
: Image
304 var img_enemy_kamikaze
: Image
305 var img_enemy_shoot
: Image
306 var img_enemy_missile
: Image
308 var img_upmissile
: Image
309 var img_explosion
: Image
315 var img_boss_left
: Image
316 var img_boss_right
: Image
318 redef fun window_created
322 scale
= (800.0 * 600.0 / display
.width
.to_f
/ display
.height
.to_f
).sqrt
* 100.0
324 # TODO load assets here
325 # ex: img = load_image( "img.png" )
326 # to get file located at assets/img.png before deployement
327 self.img_hitbox
= load_image
("hitbox.png")
329 self.img_splash
= load_image
("splash.png")
330 self.img_splash_play
= load_image
("splash_play.png")
332 self.img_player
= load_image
("player.png")
333 self.img_player_shoot
= load_image
("player_shoot.png")
334 self.img_player_missile
= load_image
("player_missile.png")
335 self.img_enemy0
= load_image
("enemy0.png")
336 self.img_enemy1
= load_image
("enemy1.png")
337 self.img_enemy2
= load_image
("enemy2.png")
338 self.img_enemy3
= load_image
("enemy3.png")
339 self.img_enemy4
= load_image
("enemy4.png")
340 self.img_enemy4_turret
= load_image
("enemy4_turret.png")
341 self.img_enemy_kamikaze
= load_image
("enemy_kamikaze.png")
342 self.img_enemy_shoot
= load_image
("enemy_shoot.png")
343 self.img_enemy_missile
= load_image
("enemy_missile.png")
344 self.img_money
= load_image
("money.png")
345 self.img_upmissile
= load_image
("up_missile.png")
346 self.img_explosion
= load_image
("explosion.png")
347 self.img_star0
= load_image
("star0.png")
348 self.img_star1
= load_image
("star1.png")
349 self.img_star2
= load_image
("star2.png")
350 self.img_boss
= load_image
("boss.png")
351 self.img_boss_left
= load_image
("boss_left.png")
352 self.img_boss_right
= load_image
("boss_right.png")
354 var w
= (display
.width
.to_f
* scale
).to_i
355 var h
= (display
.height
.to_f
* scale
).to_i
356 self.scene
= new MenuScene(w
, h
)
359 # Whole scaling to convert display pixels to game pixels
360 var scale
: Float = 200.0
362 redef fun load_image
(filename
)
365 res
.scale
= 100.0 / self.scale
369 redef fun frame_core
( display
)
370 # the arg display is not null but otherwise the same than self.display
374 var next
= self.scene
.next_scene
378 if not self.scene
.exists
then quit
= true
380 self.scene
.draw_on_display
(self)
382 # Wait the next frame
383 sys
.nanosleep
(0, 16000000)
386 var paused
: Bool = false
388 redef fun input
( input_event
)
390 if input_event
isa QuitEvent then # close window button
391 quit
= true # orders system to quit
392 return true # this event has been handled
393 else if input_event
isa KeyEvent then
394 if input_event
.to_c
== 'p' then
395 paused
= input_event
.is_down
396 return true # this event has been handled
397 else if input_event
.to_c
== 'q' then
398 quit
= true # orders system to quit
399 return true # this event has been handled
403 # Maybe the event is specific to the scene
404 return self.scene
.input
(self, input_event
)
408 if args
.length
> 0 and args
.first
== "--headless" then
413 var app
= new ShootApp
414 app
.debug
= args
.length
> 0 and args
.first
== "--debug"