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
18 app_name
("Space Shooter")
19 app_version
(0, 1, git_revision
)
26 # mnit specific method to draw a sprite
27 # app is used to optain the assets and the display
28 # Each sprite should implements this method
29 fun draw_on_display
(app
: App) do end
31 # Helper function to draw an image centered on the current sprite position
32 fun draw_image
(app
: App, img
: Image)
34 app
.display
.blit_centered
(img
, (self.x
.to_f
/app
.scale
).to_i
, (self.y
.to_f
/app
.scale
).to_i
)
37 # Helper function to draw an image translated and rotated on the current sprite position
38 fun draw_rotated_image
(app
: App, img
: Image, dx
, dy
: Int, angle
: Float)
40 app
.display
.blit_rotated
(img
, self.x
.to_f
/app
.scale
, self.y
.to_f
/app
.scale
, angle
)
45 redef fun draw_on_display
(app
)
47 if protected_ttl
> 30 and protected_ttl
%10 > 5 then return # blink on protected
48 draw_image
(app
, app
.img_player
)
53 redef fun draw_on_display
(app
)
55 var img
= if enemy
then app
.img_enemy_shoot
else app
.img_player_shoot
61 redef fun draw_on_display
(app
)
63 var angle
= velocity_angle
64 var img
= if enemy
then app
.img_enemy_missile
else app
.img_player_missile
65 draw_rotated_image
(app
, img
, 0, 0, angle
)
70 redef fun draw_on_display
(app
)
72 draw_image
(app
, app
.img_enemy0
)
77 redef fun draw_on_display
(app
)
79 draw_image
(app
, app
.img_enemy1
)
84 redef fun draw_on_display
(app
)
86 draw_image
(app
, app
.img_enemy2
)
91 redef fun draw_on_display
(app
)
93 draw_image
(app
, app
.img_enemy3
)
98 redef fun draw_on_display
(app
)
100 draw_image
(app
, app
.img_enemy4
)
101 draw_rotated_image
(app
, app
.img_enemy4_turret
, 0, 0, self.angle
)
105 redef class EnemyKamikaze
106 redef fun draw_on_display
(app
)
108 var angle
= self.velocity_angle
109 draw_rotated_image
(app
, app
.img_enemy_kamikaze
, 0, 0, angle
)
114 redef fun draw_on_display
(app
)
116 if flick_ttl
> 0 then return
117 draw_image
(app
, app
.img_boss
)
122 redef fun draw_on_display
(app
)
124 if flick_ttl
> 0 then return
126 self.boss
.draw_image
(app
, app
.img_boss_right
)
128 self.boss
.draw_image
(app
, app
.img_boss_left
)
134 redef fun draw_on_display
(app
)
136 draw_image
(app
, app
.img_money
)
140 redef class UpMissile
141 redef fun draw_on_display
(app
)
143 draw_image
(app
, app
.img_upmissile
)
147 redef class Explosion
148 redef fun draw_on_display
(app
)
150 draw_image
(app
, app
.img_explosion
)
155 redef fun draw_on_display
(app
)
158 # More a star is fast, more it requires a bright image
162 else if self.vy
< 40 then
172 fun draw_on_display
(app
: App) do end
173 fun input
(app
: App, input_event
: InputEvent): Bool do return false
176 redef class PlayScene
177 redef fun draw_on_display
(app
)
179 app
.display
.clear
( 0.0, 0.0, 0.0 )
180 self.sprites
.draw
(app
)
181 for i
in [0..player
.money
[
183 app
.display
.blit
(app
.img_money
, 10, app
.display
.height-10-i
)
185 for i
in [1..player
.nbshoots
]
187 app
.display
.blit
(app
.img_player_shoot
, 30, app
.display
.height-10
- i
*10)
189 for i
in [1..player
.nbmissiles
]
191 app
.display
.blit
(app
.img_player_missile
, 40, app
.display
.height-10
- i
*20)
195 redef fun input
(app
, input_event
)
198 if input_event
isa KeyEvent then
199 if input_event
.is_arrow_down
then
200 if input_event
.is_down
then
205 else if input_event
.is_arrow_up
then
206 if input_event
.is_down
then
211 else if input_event
.is_arrow_left
then
212 if input_event
.is_down
then
217 else if input_event
.is_arrow_right
then
218 if input_event
.is_down
then
225 else if input_event
isa PointerEvent and input_event
.pressed
then
226 var x
= (input_event
.x
* app
.scale
).to_i
227 var y
= (input_event
.y
* app
.scale
).to_i
228 player
.goes_to
(x
, y
, speed
)
231 return false # unknown event, can be handled by something else
237 redef class MenuScene
238 redef fun draw_on_display
(app
)
240 var display
= app
.display
241 assert display
!= null
242 blit_fs
(display
, app
.img_splash
)
244 if not play
or ttl
%10 > 5 then
245 blit_fs
(display
, app
.img_splash_play
)
249 fun blit_fs
(d
: Display, img
: Image)
252 var h
= d
.height
.to_f
253 d
.blit_stretched
(img
, 0.0,0.0, 0.0,h
, w
,h
, w
,0.0)
256 redef fun input
(app
, input_event
)
258 if input_event
isa KeyEvent then
261 else if input_event
isa PointerEvent then
274 var debug
: Bool = false
276 redef fun draw_sprite
(s
: Sprite)
278 s
.draw_on_display
(self)
279 if debug
and s
.width
!= 0 and s
.height
!= 0 then
280 var left
= s
.left
.to_f
/scale
281 var right
= s
.right
.to_f
/scale
282 var top
= s
.top
.to_f
/scale
283 var bot
= s
.bottom
.to_f
/scale
284 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
322 scale
= (800.0 * 600.0 / display
.width
.to_f
/ display
.height
.to_f
).sqrt
* 100.0
324 debug
= args
.length
> 0 and args
.first
== "--debug"
326 # TODO load assets here
327 # ex: img = load_image( "img.png" )
328 # to get file located at assets/img.png before deployement
329 self.img_hitbox
= load_image
("hitbox.png")
331 self.img_splash
= load_image
("splash.png")
332 self.img_splash_play
= load_image
("splash_play.png")
334 self.img_player
= load_image
("player.png")
335 self.img_player_shoot
= load_image
("player_shoot.png")
336 self.img_player_missile
= load_image
("player_missile.png")
337 self.img_enemy0
= load_image
("enemy0.png")
338 self.img_enemy1
= load_image
("enemy1.png")
339 self.img_enemy2
= load_image
("enemy2.png")
340 self.img_enemy3
= load_image
("enemy3.png")
341 self.img_enemy4
= load_image
("enemy4.png")
342 self.img_enemy4_turret
= load_image
("enemy4_turret.png")
343 self.img_enemy_kamikaze
= load_image
("enemy_kamikaze.png")
344 self.img_enemy_shoot
= load_image
("enemy_shoot.png")
345 self.img_enemy_missile
= load_image
("enemy_missile.png")
346 self.img_money
= load_image
("money.png")
347 self.img_upmissile
= load_image
("up_missile.png")
348 self.img_explosion
= load_image
("explosion.png")
349 self.img_star0
= load_image
("star0.png")
350 self.img_star1
= load_image
("star1.png")
351 self.img_star2
= load_image
("star2.png")
352 self.img_boss
= load_image
("boss.png")
353 self.img_boss_left
= load_image
("boss_left.png")
354 self.img_boss_right
= load_image
("boss_right.png")
356 var w
= (display
.width
.to_f
* scale
).to_i
357 var h
= (display
.height
.to_f
* scale
).to_i
358 self.scene
= new MenuScene(w
, h
)
361 # Whole scaling to convert display pixels to game pixels
362 var scale
: Float = 200.0
364 redef fun load_image
(filename
)
367 res
.scale
= 100.0 / self.scale
371 redef fun frame_core
( display
)
372 # the arg display is not null but otherwise the same than self.display
376 var next
= self.scene
.next_scene
380 if not self.scene
.exists
then quit
= true
382 self.scene
.draw_on_display
(self)
385 var paused
: Bool = false
387 redef fun input
( input_event
)
389 if input_event
isa QuitEvent then # close window button
390 quit
= true # orders system to quit
391 return true # this event has been handled
392 else if input_event
isa KeyEvent then
393 if input_event
.to_c
== 'p' then
394 paused
= input_event
.is_down
395 return true # this event has been handled
396 else if input_event
.to_c
== 'q' then
397 quit
= true # orders system to quit
398 return true # this event has been handled
402 # Maybe the event is specific to the scene
403 return self.scene
.input
(self, input_event
)
407 if args
.length
> 0 and args
.first
== "--headless" then