1aefc7b4bd294a955f663a26e26e5083238e5e8b
[nit.git] / examples / shoot / src / shoot_logic.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_logic
18
19 import scene2d
20
21 # The ship of the player
22 class Player
23 super Sprite
24
25 # Where the player is going
26 var going_target = new GoingTarget
27
28 # Activate the `going_target`
29 fun goes_to(x,y: Int, speed: Int)
30 do
31 going_target.x = x
32 going_target.y = y
33 going_target.active = true
34 var angle = angle_to(going_target)
35 set_velocity(angle, speed)
36 end
37
38 # Current forture of the player
39 var money: Int writable = 0
40
41 # Number of basic bullets fired together
42 var nbshoots: Int writable = 1
43
44 # Time bebore the player shoot again a basic bullet (cooldown)
45 # Shoot if 0
46 var shoot_ttl = 0
47
48 # Number of missiles
49 var nbmissiles: Int writable = 0
50
51 # Time bebore the player shoot again a missile (cooldown)
52 # Shoot if 0
53 var missile_ttl = 0
54
55 # Remainind time when the player is protected from impacts
56 var protected_ttl = 0
57
58 # The associated play scene
59 # (mainly used to registed shoots)
60 var scene: PlayScene
61
62 init(scene: PlayScene) do
63 self.scene = scene
64 self.width = 2400
65 self.height = 2400
66 end
67
68 redef fun update
69 do
70 super
71
72 # Out of screen?
73 if self.y < 0 then
74 self.y = 0
75 self.vy = 0
76 else if self.y > scene.height then
77 self.y = scene.height
78 self.vy = 0
79 end
80 if self.x < 0 then
81 self.x = 0
82 self.vx = 0
83 else if self.x > scene.width then
84 self.x = scene.width
85 self.vx = 0
86 end
87
88 # Update of the player protection if any
89 if protected_ttl > 0 then protected_ttl -= 1
90
91 # Need to shoot basic bullets?
92 if shoot_ttl > 0 then
93 shoot_ttl -= 1
94 else
95 shoot_ttl = 30
96 for i in [0..nbshoots[ do
97 var shoot = new Shoot(scene)
98 shoot.x = x
99 shoot.y = top
100 shoot.vy = -500
101 shoot.vx = (i - nbshoots / 2) * 100
102 scene.player_shoots.add(shoot)
103 end
104 end
105
106 # Need to shoot missiles?
107 if missile_ttl > 0 then
108 missile_ttl -= 1
109 else if nbmissiles > 0 then
110 missile_ttl = 500 / nbmissiles
111 var shoot = new Missile(scene)
112 shoot.x = x
113 shoot.y = top
114 shoot.vy = -300
115 shoot.vx = 0
116 scene.player_shoots.add(shoot)
117 end
118
119 end
120
121 # Time before the player is respawned by the scene
122 var respawn_ttl: Int = 0
123
124 fun hit
125 do
126 if self.protected_ttl > 0 then return
127 self.scene.explosion(self.x, self.y, 10)
128 self.exists = false
129
130 # Reset the position for respawn
131 self.x = scene.width / 2
132 self.y = scene.height - 10000
133 self.vx = 0
134 self.vy = 0
135 self.respawn_ttl = 50
136 end
137
138 end
139
140 # Sprites that may be hit by the player.
141 # Eq. enemies, bullets, loots, etc.
142 class Hitable
143 super Sprite
144
145 # What do do when self is hit by the player.
146 # By defaut, do nothing
147 fun hit_by_player(player: Player) do end
148 end
149
150 # Destination for the player (pointer position)
151 class GoingTarget
152 super Hitable
153
154 # true in on move, false if player is at rest
155 var active writable = false
156
157 init do
158 self.width = 500
159 self.height = 500
160 end
161
162 redef fun hit_by_player(player)
163 do
164 if not active then return
165 active = false
166 player.vx = 0
167 player.vy = 0
168 end
169 end
170
171 # A bullet shooted by a ship
172 class Shoot
173 super Hitable
174
175 # Was the shoot fired by an enemy.
176 # Since there is no frendly fire, it is important to distinguish ownership
177 var enemy: Bool = false
178
179 # The scene of the sprite
180 # Is used with bound limits
181 var scene: PlayScene
182
183 init(scene: PlayScene)
184 do
185 self.scene = scene
186 self.width = 800
187 self.height = 800
188 end
189
190 redef fun update
191 do
192 super
193
194 # Out of screen ?
195 if self.y < -100 * 100 or self.y > scene.height + 10000 or self.x < -100 * 100 or self.x > scene.width + 10000 then
196 self.exists = false
197 end
198 end
199
200 redef fun hit_by_player(player)
201 do
202 player.hit
203 self.exists = false
204 end
205 end
206
207 # A advanced bullet that aims a target (player or enemy)
208 class Missile
209 super Shoot
210
211 # The target aquired by the missile
212 var target: nullable Sprite = null
213
214 # When ttl is 0 then the angle stay fixed
215 # The angle is updated toward the target if ttl>0
216 var ttl: Int = 200
217
218 redef fun update
219 do
220 super
221
222 # Do we still update the angle ?
223 if ttl <= 0 then return
224 ttl -= 1
225
226 # Do we have a target?
227 var target = self.target
228 if target == null or not target.exists then return
229
230 # Just update the angle
231 var angle = self.angle_to(target)
232 self.set_velocity(angle, 300)
233 end
234 end
235
236 # A enemy ship
237 # Various enemies exists, each kind has its own subclass
238 abstract class Enemy
239 super Hitable
240
241 # The scene of the ship
242 # Is used to store created bullets or to get info about the player
243 var scene: PlayScene
244
245 # Time bebore the enemy shoot again (cooldown)
246 # Shoot if 0
247 # The default value is used as a grace period to avoid a first shoot on
248 # the first update
249 var shoot_ttl = 50
250
251 init(scene: PlayScene)
252 do
253 self.width = 2400
254 self.height = 2400
255 self.scene = scene
256 scene.enemies.add(self)
257 end
258
259 redef fun update
260 do
261 super
262
263 # Out of screen ?
264 if self.y > scene.height + 10000 or self.x < -100 * 100 or self.x > scene.width + 10000 then
265 # Note: no control on the top to let ennemies appear
266 self.exists = false
267 end
268
269 # Need to shoot?
270 if shoot_ttl > 0 then
271 shoot_ttl -= 1
272 else
273 shoot
274 end
275 end
276
277 # Each enemy has its own kind of shoot strategy
278 # Note: is automatically called by update when shoot_ttl is expired
279 fun shoot do end
280
281 # Money given when the enemy is destroyed
282 fun loot: Int is abstract
283
284 # What to do when the enemy is hit by a player shoot (or by the player himself)?
285 # By default it kill the enemy in an explosion and generate a loot
286 fun hit
287 do
288 self.exists = false
289 scene.explosion(self.x, self.y, 5)
290 if 100.rand < 3 then
291 var upmissile = new UpMissile(scene)
292 upmissile.x = self.x
293 upmissile.y = self.y
294 upmissile.vx = 0
295 upmissile.vy = 0
296 scene.loots.add(upmissile)
297 scene.hitables.add(new LootArea(upmissile, 2000))
298 else
299 for i in [0..self.loot[ do
300 var money = new Money(scene)
301 money.x = self.x
302 money.y = self.y
303 money.set_velocity(100.rand.to_f*pi/50.0, (500+self.loot).rand)
304 scene.loots.add(money)
305 scene.hitables.add(new LootArea(money, 2000))
306 end
307 end
308 end
309
310 redef fun hit_by_player(player)
311 do
312 player.hit
313 hit
314 end
315 end
316
317 # Basic enemy, do not shoot
318 class Enemy0
319 super Enemy
320
321 redef fun loot do return 3
322
323 redef init(scene)
324 do
325 self.width = 3600
326 self.height = 3600
327 end
328 end
329
330 # Simple shooter of pairs of basic bullets
331 class Enemy1
332 super Enemy
333
334 redef init(scene)
335 do
336 self.width = 4400
337 self.height = 4400
338 end
339
340 redef fun shoot
341 do
342 # Next shoot
343 shoot_ttl = 50
344
345 # two bullets shoot each time
346 for dx in [-11, 11] do
347 var shoot = new Shoot(scene)
348 shoot.enemy = true
349 shoot.x = self.x + dx * 100
350 shoot.y = self.bottom
351 shoot.vy = 500
352 scene.enemy_shoots.add(shoot)
353 end
354 end
355
356 redef fun loot do return 5
357 end
358
359 # Enemy that shoot missiles
360 class Enemy2
361 super Enemy
362
363 redef init(scene)
364 do
365 self.width = 6000
366 self.height = 6000
367 end
368
369 redef fun shoot
370 do
371 # Next shoot
372 shoot_ttl = 200
373
374 # The missile targets the player
375 var shoot = new Missile(scene)
376 shoot.enemy = true
377 shoot.x = self.x
378 shoot.y = self.bottom
379 shoot.vy = 500
380 shoot.target = scene.player
381 scene.enemy_shoots.add(shoot)
382 end
383
384 redef fun loot do return 10
385 end
386
387 # Enemy that shoot rings of basic bullets
388 class Enemy3
389 super Enemy
390
391 redef init(scene)
392 do
393 self.width = 5800
394 self.height = 5800
395 end
396
397 redef fun shoot
398 do
399 # Next shoot
400 shoot_ttl = 50
401
402 for i in [0..10[ do
403 var shoot = new Shoot(scene)
404 shoot.enemy = true
405 shoot.x = self.x
406 shoot.y = self.bottom
407 shoot.set_velocity(pi/5.0*i.to_f, 500)
408 scene.enemy_shoots.add(shoot)
409 end
410 end
411
412 redef fun loot do return 20
413 end
414
415 # Enemy with a turret that shoot burst of bullets toward the player
416 class Enemy4
417 super Enemy
418
419 # The angle of the turret
420 var angle: Float = 0.0
421
422 redef init(scene)
423 do
424 self.width = 4200
425 self.height = 4200
426 end
427
428 redef fun update
429 do
430 super
431
432 # Rotate the turret toward the player
433 var target = scene.player
434 if target.exists then
435 angle = self.angle_to(target)
436 end
437 end
438
439 # Shoots come in burst
440 var nbshoots: Int = 0
441
442 redef fun shoot
443 do
444 # Next shoot: is there still bullets in the burst?
445 if self.nbshoots < 10 then
446 # Is ther
447 self.nbshoots += 1
448 shoot_ttl = 5
449 else
450 self.nbshoots = 0
451 shoot_ttl = 80
452 end
453
454 # Shoot with the turret angle
455 var shoot = new Shoot(scene)
456 shoot.enemy = true
457 shoot.x = self.x
458 shoot.y = self.y
459 shoot.set_velocity(angle, 500)
460 scene.enemy_shoots.add(shoot)
461 end
462
463 redef fun loot do return 20
464 end
465
466 # Enemy that rush directly on the player
467 class EnemyKamikaze
468 super Enemy
469
470 redef init(scene)
471 do
472 self.width = 3200
473 self.height = 3200
474 end
475
476 redef fun update
477 do
478 super
479
480 # Try to target the player
481 var target = scene.player
482 if not target.exists then return
483
484 var angle = self.angle_to(target)
485 self.set_velocity(angle, 600)
486 end
487
488 redef fun loot do return 5
489 end
490
491 # The boss has two semi-independent arms
492 class Boss
493 super Enemy
494
495 # Left arm
496 var left_part: BossPart
497
498 # Right arm
499 var right_part: BossPart
500
501 init(scene)
502 do
503 super
504 self.width = 140 * 100
505 self.height = 96 * 100
506 self.x = scene.width / 2
507 self.y = -100 * 100
508 self.left_part = new BossPart(self, -66*100)
509 self.right_part = new BossPart(self, 66*100)
510 end
511
512 var flick_ttl: Int = 0
513
514 redef fun update
515 do
516 if flick_ttl > 0 then flick_ttl -= 1
517
518 # Path of the boss (down then left<->right)
519 if self.y < 20000 then
520 self.vx = 0
521 self.vy = 100
522 else if self.vx == 0 then
523 self.vx = 100
524 self.vy = 0
525 else if self.x > scene.width - 10000 and self.vx > 0 then
526 self.vx = -self.vx
527 else if self.x < 10000 and self.vx < 0 then
528 self.vx = -self.vx
529 end
530
531 super
532 end
533
534 redef fun shoot
535 do
536 # Do not shoot if not ready
537 if self.vy != 0 then return
538
539 # Try to target the player
540 var target = scene.player
541 if not target.exists then return
542
543 # Next shoot: burst if no arms remains
544 if left_part.exists or right_part.exists then
545 shoot_ttl = 60
546 else
547 shoot_ttl = 20
548 end
549
550 # Shoot the player with a basic bullet
551 var shoot = new Shoot(scene)
552 shoot.enemy = true
553 shoot.x = self.x
554 shoot.y = self.bottom
555 var angle = shoot.angle_to(target)
556 shoot.set_velocity(angle, 500)
557 scene.enemy_shoots.add(shoot)
558 end
559
560 redef fun loot do return 100
561
562 var live: Int = 20
563
564 redef fun hit
565 do
566 # Protected while an arm remains
567 if left_part.exists or right_part.exists then return
568
569 if live > 0 then
570 live -= 1
571 flick_ttl = 2
572 else
573 super
574 scene.explosion(self.x, self.y, 30)
575 end
576 end
577 end
578
579 # An arm of a boss
580 class BossPart
581 super Enemy
582
583 # The associated boss
584 var boss: Boss
585
586 # Relative x coordonate (center to center) of the arm
587 var relx: Int
588
589 # Relative y coordonate (center to center) of the arm
590 var rely: Int = 36 * 100
591
592 var live: Int = 10
593
594 init(boss: Boss, relx: Int)
595 do
596 self.boss = boss
597 self.relx = relx
598 super(boss.scene)
599 self.width = 38 * 100
600 self.height = 48 * 100
601
602 # Alternate the shoots of the arms
603 if relx > 0 then
604 shoot_ttl += 300
605 end
606 self.x = boss.x + relx
607 self.y = boss.y + rely
608 end
609
610 redef fun update
611 do
612 self.x = boss.x + relx
613 self.y = boss.y + rely
614
615 super
616
617 if flick_ttl > 0 then flick_ttl -= 1
618 end
619
620 redef fun shoot
621 do
622 # Do not shoot if not ready
623 if self.boss.vy != 0 then return
624
625 # Next shoot
626 shoot_ttl = 600
627
628 # Shoot a missile that targets the player
629 var shoot = new Missile(scene)
630 shoot.enemy = true
631 shoot.x = self.x
632 shoot.y = self.bottom
633 shoot.vy = 500
634 shoot.target = scene.player
635 scene.enemy_shoots.add(shoot)
636 end
637
638 var flick_ttl: Int = 0
639
640 redef fun hit
641 do
642 if live > 0 then
643 live -= 1
644 flick_ttl = 2
645 else
646 super
647 end
648 end
649
650 redef fun loot do return 10
651 end
652
653 # Whatever reward or bonus that can be picked by the player
654 abstract class Loot
655 super Hitable
656
657 var scene: PlayScene
658
659 init(scene: PlayScene)
660 do
661 self.scene = scene
662 self.width = 400
663 self.height = 400
664 end
665
666 # Magnet effect: The loot will move to the target if set
667 # See LootArea for details
668 var target: nullable Sprite = null
669
670 redef fun update
671 do
672 super
673
674 # Out of screen ?
675 if self.y > scene.height + 10000 then
676 self.exists = false
677 end
678
679 var target = self.target
680 if target == null then
681 # Not magneted: deploy
682
683 # Heavy fuild friction to stops the explosion
684 # Loots are placed with a explosion, see `Enemy::hit'
685 self.vx = self.vx*7/8
686 self.vy = self.vy*7/8
687
688 # Background scroling
689 self.y += 50
690
691 else if target.exists then
692 # Magneted: rush toward the target
693 var angle = self.angle_to(target)
694 self.set_velocity(angle, 800)
695
696 else
697 # Magneted but dead target: reset the loot
698 self.vx = 0
699 self.vy = 0
700 self.target = null
701 end
702 end
703 end
704
705 # Basic money loot
706 class Money
707 super Loot
708
709 redef fun hit_by_player(player)
710 do
711 self.exists = false
712 player.money += 1
713 if player.money > 100 then
714 player.money -= 100
715 player.nbshoots += 1
716 end
717 end
718 end
719
720 # Increase the number of missiles
721 class UpMissile
722 super Loot
723
724 redef fun hit_by_player(player)
725 do
726 self.exists = false
727 player.nbmissiles += 1
728 end
729 end
730
731 # A loot area is an invisible field used to implement the magnet effets of loots
732 # The principle is:
733 # * the loot is an invisible sprite with a hitbox larger than the loot hitbox
734 # * the lootbox remains centered on the loot
735 # * when the player hit the lootarea, then the loot is set to target the player
736 # * when the player hit the loot, then the player gains effectively the loot
737 class LootArea
738 super Hitable
739
740 # The associated loot
741 var loot: Loot
742
743 init(loot: Loot, radius: Int)
744 do
745 self.loot = loot
746 self.width = radius * 2 + loot.width
747 self.height = radius * 2 + loot.height
748 end
749
750 redef fun update
751 do
752 # position remains centered on the loot
753 self.x = loot.x
754 self.y = loot.y
755
756 # No area if no loot
757 if not loot.exists then self.exists = false
758
759 # the super is useless but it is a good practice to call it
760 super
761 end
762
763 redef fun hit_by_player(player)
764 do
765 # Kill the area
766 self.exists = false
767
768 # The loot now targets the player
769 loot.target = player
770 end
771 end
772
773 # A non interactive element of an explosion
774 # A real explosion is made of many Explosion object
775 # Use the `PlayScene::explosion` method to generate a full explosion
776 class Explosion
777 super Sprite
778
779 # Time before the sprite vanishes
780 var ttl: Int = 10
781
782 redef fun update
783 do
784 # Heavy fuild friction to stops the explosion
785 self.vx = self.vx*7/8
786 self.vy = self.vy*7/8
787
788 # Background scrolling
789 self.y += 50
790
791 super
792
793 # Vanishes?
794 if ttl > 0 then
795 ttl -= 1
796 else
797 exists = false
798 end
799 end
800 end
801
802 # A star is a non-interactive background element
803 # Stars are used to simulate a continuous global scroling
804 class Star
805 super Sprite
806
807 # The scene of the sprite
808 # Is used with bound limits
809 var scene: ShotScene
810
811 init(scene: ShotScene)
812 do
813 self.scene = scene
814 # Randomely places stars on the plane
815 self.x = scene.width.rand
816 self.y = scene.height.rand
817 self.vy = 40.rand + 11
818 end
819
820 redef fun update
821 do
822 super
823
824 # Replace the star on the top
825 if self.y > scene.height then
826 self.y = 200.rand * -100
827 self.x = scene.width.rand
828 self.vy = 40.rand + 11
829 end
830 end
831 end
832
833 class ShotScene
834 super Scene
835
836 # When a scene need to be replaced, just assign the next_scene to a non null value
837 var next_scene: nullable ShotScene writable = null
838
839 # The width of the whole scene
840 var width: Int writable
841
842 # The height of the whole scene
843 var height: Int writable
844
845 init(w,h: Int)
846 do
847 width = w
848 height = h
849 end
850 end
851
852 # The main play state
853 class PlayScene
854 super ShotScene
855
856 # The player ship
857 var player: Player
858
859 # Shoots of the player
860 var player_shoots = new LiveGroup[Shoot]
861
862 # Enemy ships
863 var enemies = new LiveGroup[Enemy]
864
865 # Soots of the enemy
866 var enemy_shoots = new LiveGroup[Shoot]
867
868 # Collectible loots
869 var loots = new LiveGroup[Loot]
870
871 # Non active stuff like explosions
872 var pasive_stuff = new LiveGroup[LiveObject]
873
874 # Background stuff like stars
875 var background = new LiveGroup[LiveObject]
876
877 # All other hitable sprites
878 var hitables = new LiveGroup[Hitable]
879
880 # All sprites
881 var sprites = new LiveGroup[LiveObject]
882
883 init(w,h)
884 do
885 super
886 self.player = new Player(self)
887 player.x = self.width / 2
888 player.y = self.height - 10000
889 self.sprites.add(background)
890 self.sprites.add(pasive_stuff)
891 self.sprites.add(loots)
892 self.sprites.add(player_shoots)
893 self.sprites.add(enemy_shoots)
894 self.sprites.add(enemies)
895 self.sprites.add(self.player)
896 self.sprites.add(hitables)
897
898 for i in [0..100[ do
899 background.add(new Star(self))
900 end
901
902 hitables.add(player.going_target)
903 end
904
905 # Generate an explosion
906 fun explosion(x, y: Int, radius: Int)
907 do
908 # Project explosion parts from the given position
909 # The strong friction and the short ttl of each part will achieve the effect
910 for i in [0..radius[ do
911 var ex = new Explosion
912 ex.x = x
913 ex.y = y
914 ex.set_velocity(100.rand.to_f*pi/50.0, (50*radius).rand)
915 ex.ttl += radius.rand
916 pasive_stuff.add(ex)
917 end
918 end
919
920 var enemy_remains: Int = 15
921 var boss_wait_ttl: Int = 0
922 var boss: nullable Boss
923
924 redef fun update
925 do
926 sprites.gc
927 sprites.update
928
929 if enemy_remains == 0 then
930 if boss_wait_ttl > 0 then
931 boss_wait_ttl -= 1
932 else if boss == null then
933 boss = new Boss(self)
934 enemy_remains = 15
935 else if not boss.exists then
936 boss = null
937 end
938 else if 100.rand < 1 then
939 enemy_remains -= 1
940 if enemy_remains == 0 then
941 boss_wait_ttl = 500
942 end
943 var rnd = 100.rand
944 var enemy: Enemy
945 if rnd < 40 then
946 enemy = new Enemy0(self)
947 else if rnd < 60 then
948 enemy = new Enemy1(self)
949 else if rnd < 70 then
950 enemy = new EnemyKamikaze(self)
951 else if rnd < 90 then
952 enemy = new Enemy2(self)
953 else if rnd < 95 then
954 enemy = new Enemy3(self)
955 else
956 enemy = new Enemy4(self)
957 end
958 enemy.x = (self.width - 20000).rand + 10000
959 enemy.vy = 200.rand + 100
960 if 10.rand < 3 then
961 enemy.vx = 200.rand - 100
962 end
963 end
964
965 for ps in player_shoots do
966 if not ps.exists then continue
967 var target: nullable Enemy = null
968 var td = 100000 # big int
969 for e in enemies do
970 if not e.exists then continue
971 if ps.overlaps(e) then
972 ps.exists = false
973 e.hit
974 end
975 var d = (e.x - ps.x).abs + (e.y - ps.y).abs
976 if td > d then
977 target = e
978 td = d
979 end
980 end
981 if ps isa Missile and (ps.target == null or not ps.target.exists) then
982 ps.target = target
983 end
984 end
985
986 for e in enemies do
987 if not e.exists then continue
988 if player.exists and player.overlaps(e) then
989 e.hit_by_player(player)
990 end
991 end
992 for s in enemy_shoots do
993 if not s.exists then continue
994 if player.exists and player.overlaps(s) then
995 s.hit_by_player(player)
996 end
997 end
998 for l in loots do
999 if not l.exists then continue
1000 if player.exists and player.overlaps(l) then
1001 l.hit_by_player(player)
1002 end
1003 end
1004 for l in hitables do
1005 if not l.exists then continue
1006 if player.exists and player.overlaps(l) then
1007 l.hit_by_player(player)
1008 end
1009 end
1010 if not player.exists then
1011 if player.respawn_ttl > 0 then
1012 player.respawn_ttl -= 1
1013 else
1014 player.exists = true
1015 player.protected_ttl = 100
1016 self.sprites.add(self.player)
1017 end
1018 end
1019 end
1020 end
1021
1022 ###
1023
1024 class MenuScene
1025 super ShotScene
1026
1027 var sprites = new LiveGroup[LiveObject]
1028
1029 init(w,h)
1030 do
1031 super
1032 for i in [0..100[ do
1033 sprites.add(new Star(self))
1034 end
1035 end
1036
1037 var play: Bool writable = false
1038 var ttl: Int = 50
1039
1040 redef fun update
1041 do
1042 sprites.update
1043
1044 if not play then return
1045 if ttl > 0 then
1046 ttl -= 1
1047 return
1048 end
1049 next_scene = new PlayScene(width,height)
1050 end
1051 end
1052
1053 fun headless_run
1054 do
1055 print "Headless run"
1056 # Only run the playscene
1057 var scene = new PlayScene(80000,60000)
1058 # beefup the player
1059 scene.player.nbshoots = 5
1060 scene.player.nbmissiles = 5
1061 # play
1062 print "Play"
1063 var turns = 10
1064 if args.length > 0 then
1065 turns = args.first.to_i
1066 end
1067 for i in [0..turns[ do
1068 for j in [0..10000[ do
1069 scene.update
1070 end
1071 print "{i}: money={scene.player.money} enemies={scene.enemies.length} shoots={scene.player_shoots.length}"
1072 end
1073 print "Game Over"
1074 end
1075
1076 headless_run