ang 9.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/ang ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/ruby
2
+ require 'gosu'
3
+
4
+ Dir.chdir(File.dirname(__FILE__)+"/..")
5
+ load 'main.rb'
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/ruby
2
+ require 'gosu'
3
+
4
+ Dir.chdir(File.dirname(__FILE__)+"/../net")
5
+ load 'agent.rb'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/ruby
2
+ Dir.chdir(File.dirname(__FILE__)+"/../net")
3
+ load 'multicast_test.rb'
@@ -0,0 +1,11 @@
1
+ comments=ARGV.join(" ")
2
+ exit! if comments.size==0
3
+
4
+ version=File.read("VERSION").strip.to_f
5
+ version= ((version*100)+1).round*0.01
6
+ open("VERSION","w") { |f| f.print(version.to_s) }
7
+ puts "New Version=#{version}"
8
+
9
+ system("git","commit","-a","-m","#{comments}")
10
+ system("git push") # put your password in .git/config : http://name:passwd@github...
11
+ puts "\n\nDone"
data/main.rb ADDED
@@ -0,0 +1,379 @@
1
+ # Creative Commons BY-SA : Regis d'Aubarede <regis.aubarede@gmail.com># LGPL
2
+ ###########################################################################
3
+ # ANG.RB : planetoide game
4
+ #--------------------------------------------------------------------------
5
+ # install ruby
6
+ # install Gosu > gem install gosu
7
+ # download this > git http://github.com/rdaubarede/ang.git
8
+ # run > ruby main.rb
9
+ # do your own version :
10
+ # > loop { edit/main.rb ; ruby main.rb }
11
+ # make your disribution :
12
+ # > ocra main.rb
13
+ #
14
+ ###########################################################################
15
+ if RUBY_VERSION >= "3.0.0"
16
+ puts "Sorry, not ready for ruiby 3..."
17
+ exit(0)
18
+ end
19
+ ##################### Tuning ##########################
20
+
21
+ KK=0.5
22
+ SX=1280/KK # window size width
23
+ SY=900/KK # height
24
+ $INITIALE_SCORE=2000
25
+ $NB_STAR=35
26
+ $NB_PLANET=8
27
+ $RANGE_STAR_SIZE=(10..30) # more planet / bigger planets ==>> harder game!
28
+ $SCALE_PLAYER=0.8
29
+ $SIZE_TANK=5
30
+ $DD=false
31
+ #######################################################
32
+
33
+ require 'rubygems'
34
+ require 'gosu'
35
+
36
+ module ZOrder
37
+ Background, Stars, Player, UI = [0,1,2,3]
38
+ end
39
+ class Numeric
40
+ def minmax(min,max=nil)
41
+ (max=min;min=-min) if !max
42
+ return self if self>=min && self<=max
43
+ return(min) if self<min
44
+ return(max)
45
+ end
46
+ end
47
+ class Range ; def rand() self.begin+Kernel.rand((self.end-self.begin).abs) end ; end
48
+
49
+ # pseudo newton
50
+ def newton_xy1(p1,p2,a,b)
51
+ k1=1.5/200
52
+ k2=1.0/30000
53
+ dx,dy=[a.x-b.x,a.y-b.y]
54
+ d=Math::sqrt(dx ** 2 + dy ** 2)
55
+ f1=(k1*p1*p2/(d*d)).minmax(100)
56
+ f2=(k2*p1*p2/(d)).minmax(100)
57
+ teta=Math.atan2(dy,dx)
58
+ f=(f2<f1) ? f1 : f2
59
+ $DD=true if (f2>f1)
60
+ r=[-f*Math.cos(teta),-f*Math.sin(teta)]
61
+ r
62
+ end
63
+
64
+ # newton, with 'amortissement'
65
+ def newton_xy(p1,p2,a,b,k=1.0/300,dmin=10,dmax=10000)
66
+ dx,dy=[a.x-b.x,a.y-b.y]
67
+ d=dmin+Math::sqrt(dx ** 2 + dy ** 2)
68
+ return [0,0] if d>dmax
69
+ #f=(k*p1*p2/(d*d)).minmax(100) : k/d**2 not good for gameplay
70
+ f=(k*p1*p2/(d*d-dmin*dmin)).minmax(10)
71
+ teta=Math.atan2(dy,dx)
72
+ [-f*Math.cos(teta),-f*Math.sin(teta)]
73
+ end
74
+
75
+ # apply gravity between obj and a list l of planet
76
+ # k=coef gr&avity, >0 attraction, <0 repulsion
77
+ # dmaw : distance max, no attaction if distance>dmax
78
+ def motion(l,obj,k,dmax)
79
+ dx,dy=0,0
80
+ l.each do |o|
81
+ next if o==obj
82
+ next if block_given? && ! yield(o)
83
+ dx1,dy1= newton_xy(obj.r,o.r,obj,o,k,0,dmax)
84
+ dx+=dx1
85
+ dy+=dy1
86
+ end
87
+ obj.x+=dx
88
+ obj.y+=dy
89
+ return Math.sqrt(dx*dx+dy*dy)
90
+ end
91
+
92
+ ###########################################################################
93
+ # P l a y e r
94
+ ###########################################################################
95
+ # move by arrow keyboard acceleration commande,
96
+ # eat star, move with current speed, and attractive planets
97
+ class Player
98
+ attr_accessor :x,:y,:r,:score
99
+ def initialize(window,animation)
100
+ @animation = animation
101
+ @app=window
102
+ clear()
103
+ @r=15
104
+ self.restart()
105
+ end
106
+ def clear
107
+ @pos=1
108
+ end
109
+ def restart
110
+ @vel_x = @vel_y = @angle = @vangle = 0.0
111
+ @x = SX/2
112
+ @y = SY/2
113
+ @score = $INITIALE_SCORE
114
+ @lxy=[]
115
+ end
116
+ def warp(x, y) @x, @y = x, y ; end
117
+ def turn_left() @pos=3 ; @vangle -= 0.3 ; end
118
+ def turn_right() @pos=4 ; @vangle += 0.3 ; end
119
+ def accelerate(s)
120
+ @pos= s ? 0 : 2
121
+ @score-=3
122
+ @vel_x += 0.7*Gosu::offset_x(@angle, s ? 0.1 : -0.1)
123
+ @vel_y += 0.7*Gosu::offset_y(@angle, s ? 0.1 : -0.1)
124
+ end
125
+
126
+ def move(stars)
127
+ a=false
128
+ (a=true;@vel_x *= -1) if @x >= SX || @x <= 0
129
+ (a=true;@vel_y *= -1) if @y >= SY || @y <= 0
130
+ @x -= 10 if @x >= SX && @vel_x == 0
131
+ @y -= 10 if @y >= SY && @vel_y == 0
132
+ @x += 10 if @x <= 0 && @vel_x == 0
133
+ @y += 10 if @y <= 0 && @vel_y == 0
134
+
135
+ @angle+=@vangle
136
+ @vangle=@vangle*95.0/100
137
+ @lxy << [@x,@y] if @vel_x!=0 && @vel_y!=0
138
+ vx,vy=newton(stars)
139
+ @vel_x+=vx
140
+ @vel_y+=vy
141
+ @vel_x.minmax(-50,+50)
142
+ @vel_y.minmax(-50,+50)
143
+ @x += @vel_x
144
+ @y += @vel_y
145
+ if a
146
+ @vel_x*=1
147
+ @vel_y*=1
148
+ end
149
+
150
+ end
151
+ def newton(stars)
152
+ vx = vy = 0.0
153
+ stars.each do |star|
154
+ next if star.type
155
+ d=Gosu::distance(@x,@y,star.x,star.y)-15-star.r
156
+ dx,dy=*newton_xy1(15*15,star.r*star.r,self,star)
157
+ vx+=dx
158
+ vy+=dy
159
+ end
160
+ [vx,vy]
161
+ end
162
+
163
+ def draw(app,stars)
164
+ img = @animation[@pos]
165
+ img.draw_rot(@x, @y, ZOrder::Player, @angle, 0.5, 0.5, $SCALE_PLAYER,$SCALE_PLAYER)
166
+ x,y=newton(stars) ; app.draw_line(@x,@y, 0xffffffff,@x+x*1000,@y+y*1000,0xffffffff) # debug: mark gravity force
167
+ if app.pending?
168
+ @lxy.each_cons(2) { |p0,p1| app.draw_line(p0[0],p0[1], 0xffffff00 ,p1[0],p1[1], 0xffffff00 ) if p1} rescue nil
169
+ elsif @lxy.size>100
170
+ @lxy[(-1*[800,@lxy.size].min)..-1].each_cons(2) { |p0,p1|
171
+ app.draw_line(p0[0],p0[1], 0x33ffff00 ,p1[0],p1[1], 0x33ffff00 ) if p1
172
+ } rescue nil
173
+ end
174
+ @lxy=@lxy[-5000..-1] if @lxy.size>10000
175
+ end
176
+
177
+ def collect_stars(stars)
178
+ stars.reject! do |star|
179
+ next if star.x-@x > 200
180
+ next if star.x-@x < -200
181
+ next if star.y-@y > 200
182
+ next if star.y-@y < -200
183
+
184
+ if Gosu::distance(@x, @y, star.x, star.y) < (15+star.r) then
185
+ if star.type
186
+ @score += 120
187
+ true
188
+ else
189
+ if @vel_x !=0 || @vel_y!=0
190
+ @score -= 10
191
+ @x -= 25*@vel_x
192
+ @y -= 25*@vel_y
193
+ @x -= -2*25*@vel_x if @x >= SX && @vel_x == 0
194
+ @y -= -2*25*@vel_y if @y >= SY && @vel_y == 0
195
+ else
196
+ @x += (-10..+10).rand
197
+ @y += (-10..+10).rand
198
+ end
199
+ @vel_x=0
200
+ @vel_y=0
201
+ false
202
+ end
203
+ else
204
+ false
205
+ end
206
+ end
207
+ @app.looser if @score<=0
208
+ @app.winner(@score) if 0 == (stars.select { |s| s.type }.size )
209
+ end
210
+
211
+ end
212
+
213
+
214
+ ###########################################################################
215
+ # S t a r
216
+ ###########################################################################
217
+ class Star
218
+ attr_accessor :x, :y, :type,:r
219
+
220
+ def initialize(ls,type,animation)
221
+ @animation = animation
222
+ @ls=ls
223
+ @type=type
224
+ @r=@type ? $SIZE_TANK : $RANGE_STAR_SIZE.rand()
225
+ @no_img= type ? 1 : (rand()>0.5 && (@r>($RANGE_STAR_SIZE.max+$RANGE_STAR_SIZE.max)/2)) ? 0 : (rand(3)+2)
226
+ @rot=rand(180)
227
+ @color = Gosu::Color.new(0xff000000 )
228
+ @color.red = type ? 255 : 200
229
+ @color.green = type ? 0 : 200
230
+ @color.blue = type ? 0 : 200
231
+ @x = (SX/5..(SX-SX/5)).rand
232
+ @y = (SY/5..(SY-SY/5)).rand
233
+ end
234
+ def move(game,player,ls)
235
+ ox,oy=@x,@y
236
+ expand(game,player,ls)
237
+ @x=ox if @x>(SX-40) || @x<40
238
+ @y=oy if @y>(SY-40) || @y<40
239
+
240
+ end
241
+ def draw()
242
+ img = @animation[@no_img]
243
+ img.draw_rot(@x, @y, ZOrder::Stars, @rot, 0.5,0.5 ,@r/40.0, @r/40.0,@color)
244
+ end
245
+ def expand(game,player,ls)
246
+ return unless game.pending?(40)
247
+ motion(ls,self,-100.0,110) { |o| ! o.type} if type # Star <-> Planet
248
+ motion(ls,self,-10.0,50) { |o| o.type} # * <-> Star
249
+ motion(ls,self,-10.0,500) { |o| ! o.type } if !type # Planet <-> Planet
250
+
251
+ motion([player],self,-6,180) if type # Star <-> Player
252
+ end
253
+ end
254
+
255
+ ###########################################################################
256
+ # W i n d o w
257
+ ###########################################################################
258
+
259
+ class GameWindow < Gosu::Window
260
+ attr_reader :star,:ping
261
+ def initialize
262
+ super((SX*KK).to_i, (SY*KK).to_i, false)
263
+ self.caption = "Gosu Tutorial Game"
264
+
265
+ @lp=[]; 100.times { x=rand(SX) ; y=rand(SY); @lp<<x;@lp<<y }
266
+
267
+ @player_anim= Gosu::Image::load_tiles(self, "Starfighter.bmp", 50,50, false)
268
+ @player = Player.new(self,@player_anim)
269
+ @player.warp(320, 240)
270
+ @font = Gosu::Font.new(self, Gosu::default_font_name, (20/KK).round)
271
+ @font2 = Gosu::Font.new(self, Gosu::default_font_name, (40/KK).round)
272
+
273
+ @star_anim = Gosu::Image::load_tiles(self, "Star.bmp", 100,100, false)
274
+ @ping=0
275
+ @start=0
276
+ @mouse=nil
277
+ self.go("Start")
278
+ end
279
+
280
+ ######################## Game global state
281
+
282
+ def looser() ego("Game Over !") end
283
+ def winner(n) ego("Wiiiinner #{n}") end
284
+ def ego(text)
285
+ return if @ping < @start
286
+ puts "ego #{text}"
287
+ @text=text
288
+ @start=@ping+200
289
+ Thread.new { sleep 2 ; self.go("Start") }
290
+ end
291
+ def go(text)
292
+ @start=@ping+200
293
+ @text=text
294
+ @stars = Array.new
295
+ $NB_PLANET.times { @stars.push( Star.new(@stars,false,@star_anim) ) }
296
+ $NB_STAR.times { @stars.push( Star.new(@stars,true,@star_anim) ) }
297
+ @player.restart
298
+ end
299
+ def pending?(d=0) (@start+d > @ping) end
300
+
301
+ ######################## Global interactions : mouse/keyboard
302
+
303
+ def interactions()
304
+ @player.turn_left if button_down? Gosu::KbLeft or button_down? Gosu::GpLeft
305
+ @player.turn_right if button_down? Gosu::KbRight or button_down? Gosu::GpRight
306
+ @player.accelerate(true) if button_down? Gosu::KbUp or button_down? Gosu::GpButton0
307
+ @player.accelerate(false) if button_down? Gosu::KbDown or button_down? Gosu::GpButton1
308
+ #mouse_control
309
+ end
310
+ def mouse_control
311
+ n=[mouse_x,mouse_y]
312
+ @mouse=n unless @mouse
313
+ dx=n[0]-@mouse[0]
314
+ dy=n[1]-@mouse[1]
315
+ if Math.hypot(dx,dy)>D
316
+ @player.turn_left if dx<-D
317
+ @player.turn_right if dx>D
318
+ @player.accelerate(true) if dy<-D
319
+ @player.accelerate(false) if dx>D
320
+ end
321
+ @mouse=n
322
+ end
323
+ def button_down(id)
324
+ if id == Gosu::KbEscape
325
+ if @player.score==0
326
+ close
327
+ else
328
+ @player.score=0
329
+ end
330
+ end
331
+ end
332
+
333
+ ######################## Global draw : update()/draw() are invoked continuously by Gosu engine
334
+
335
+ def update
336
+ $DD=false
337
+ @ping+=1
338
+ @player.clear()
339
+ @stars.each { |star| star.move(self,@player,@stars) }
340
+ return if @ping<@start
341
+ interactions()
342
+ @player.move(@stars)
343
+ @player.collect_stars(@stars)
344
+ end
345
+
346
+ def draw
347
+ scale(KK,KK) {
348
+ draw_background
349
+ @player.draw(self,@stars)
350
+ @stars.each { |star| star.draw() }
351
+ draw_variable_background()
352
+ }
353
+ end
354
+ def draw_background
355
+ @lp.each_slice(2) do |x,y|
356
+ draw_triangle(
357
+ x, y, 0xAAFFFFFF,
358
+ x+(4..8).rand, y+(4..8).rand, 0xAAFFFFFF,
359
+ x+(4..8).rand, y, 0xAAFFFFFF)
360
+ end
361
+ end
362
+ def draw_variable_background()
363
+ if @ping<@start
364
+ @font2.draw(@text+ " ! !", SX/2, SY/2, ZOrder::UI, 1.0, 1.0, 0xf0f0f000)
365
+ @font.draw("", 10, 10, ZOrder::UI, 1.0, 1.0, 0xffffff00)
366
+ else
367
+ #----------- barr graph energies reserve level
368
+ h=5+(@player.score/2000.0)*(SY-10)
369
+ draw_quad(5, 5, 0xBB55FF55, 20/KK, 5, 0xBB55FF55, 20/KK, h, 0xBBFFFF55, 5 , h , 0xBBFFFF55)
370
+
371
+ #------------ textual energie reserve level
372
+ @font.draw("Score: #{@player.score}", 25/KK, 10/KK, ZOrder::UI, 1.0, 1.0, 0xffffff00)
373
+ draw_quad(20, 20, 0xFFFF00FF, 40, 20, 0xFFFF00FF, 40, 40, 0xFFFF00FF, 20 , 40 , 0xFFFF00FF) if $DD
374
+
375
+ end
376
+ end
377
+ end
378
+
379
+ GameWindow.new.show
@@ -0,0 +1,324 @@
1
+ # Creative Commons BY-SA : Regis d'Aubarede <regis.aubarede@gmail.com>
2
+ ###########################################################################
3
+ # ANG.RB : planetoide game
4
+ #--------------------------------------------------------------------------
5
+ # install ruby
6
+ # install Gosu > gem install gosu
7
+ # download this > git http://github.com/rdaubarede/ang.git
8
+ # run > ruby main.rb
9
+ # do your own version :
10
+ # > loop { edit/main.rb ; ruby main.rb }
11
+ # make your disribution :
12
+ # > ocra main.rb
13
+ #
14
+ ###########################################################################
15
+ require 'rubygems'
16
+ require 'gosu'
17
+
18
+ # KK=0.5
19
+ # SX=1280/KK
20
+ # SY=900/KK
21
+ KK=0.5
22
+ SX=640/KK
23
+ SY=480/KK
24
+
25
+ module ZOrder
26
+ Background, Stars, Player, UI = [0,1,2,3]
27
+ end
28
+ class Numeric
29
+ def minmax(min,max=nil)
30
+ (max=min;min=-min) if !max
31
+ return self if self>=min && self<=max
32
+ return(min) if self<min
33
+ return(max)
34
+ end
35
+ end
36
+ class Range ; def rand() self.begin+Kernel.rand((self.end-self.begin).abs) end ; end
37
+
38
+ def e(a,b) (20.0/(a-b)).minmax(-10,+10) end
39
+
40
+ def newton_xy(p1,p2,a,b)
41
+ k=1.0/40000
42
+ dx,dy=[a.x-b.x,a.y-b.y]
43
+ d=Math::sqrt(dx ** 2 + dy ** 2)
44
+ #f=(k*p1*p2/(d*d)).minmax(100) : k/d**2 not good for gameplay
45
+ f=(k*p1*p2/(d)).minmax(10)
46
+ teta=Math.atan2(dy,dx)
47
+ [-f*Math.cos(teta),-f*Math.sin(teta)]
48
+ end
49
+
50
+ ###########################################################################
51
+ # P l a y e r
52
+ ###########################################################################
53
+ # move by arrow keyboard acceleration commande,
54
+ # eat star, move with current speed, and attractive planets
55
+ class Player
56
+ attr_reader :x,:y,:r
57
+ attr_accessor :score
58
+ def initialize(window,animation)
59
+ @animation = animation
60
+ @app=window
61
+ @r=15
62
+ @pos=1
63
+ self.restart()
64
+ end
65
+ def restart
66
+ @vel_x = @vel_y = @angle = @vangle = 0.0
67
+ @x = SX/2
68
+ @y = SY/2
69
+ @score = 2000
70
+ @lxy=[]
71
+ end
72
+ def clear
73
+ @pos=1
74
+ end
75
+ def warp(x, y) @x, @y = x, y ; end
76
+ def turn_left() @pos=3 ; @vangle -= 0.3 ; end
77
+ def turn_right() @pos=4 ; @vangle += 0.3 ; end
78
+ def accelerate(s)
79
+ @pos= s ? 0 : 2
80
+ @score-=3
81
+ @vel_x += Gosu::offset_x(@angle, s ? 0.1 : -0.1)
82
+ @vel_y += Gosu::offset_y(@angle, s ? 0.1 : -0.1)
83
+ end
84
+
85
+ def move(stars)
86
+ @x += @vel_x
87
+ @y += @vel_y
88
+ @vel_x *= -1 if @x >= SX || @x <= 0
89
+ @vel_y *= -1 if @y >= SY || @y <= 0
90
+ @x -= 10 if @x >= SX && @vel_x == 0
91
+ @y -= 10 if @y >= SY && @vel_y == 0
92
+ @x += 10 if @x <= 0 && @vel_x == 0
93
+ @y += 10 if @y <= 0 && @vel_y == 0
94
+
95
+ #@vel_x *= 0.998
96
+ #@vel_y *= 0.998
97
+ @angle+=@vangle
98
+ @vangle=@vangle*95.0/100
99
+ @lxy << [@x,@y] if @vel_x!=0 && @vel_y!=0
100
+ vx,vy=newton(stars)
101
+ @vel_x+=vx
102
+ @vel_y+=vy
103
+ @vel_x.minmax(-50,+50)
104
+ @vel_y.minmax(-50,+50)
105
+ end
106
+ def newton(stars)
107
+ vx = vy = 0.0
108
+ stars.each do |star|
109
+ next if star.type
110
+ d=Gosu::distance(@x,@y,star.x,star.y)-15-star.r
111
+ dx,dy=*newton_xy(15*15,star.r*star.r,self,star)
112
+ vx+=dx
113
+ vy+=dy
114
+ end
115
+ [vx,vy]
116
+ end
117
+
118
+ def draw(app,stars)
119
+ img = @animation[@pos]
120
+ img.draw_rot(@x, @y, ZOrder::Player, @angle) # (@x, @y, ZOrder::Stars, 0, 0.5,0.5 ,@r/10, @r/10,@color)
121
+ #@image.draw_rot(@x, @y, ZOrder::Player, @angle)
122
+ x,y=newton(stars) ; app.draw_line(@x,@y, 0xffffffff,@x+x*1000,@y+y*1000,0xffffffff) # debug: mark gravity force
123
+ if app.is_pending
124
+ @lxy.each_cons(2) { |p0,p1| app.draw_line(p0[0],p0[1], 0xffffff00 ,p1[0],p1[1], 0xffffff00 ) if p1} rescue nil
125
+ elsif @lxy.size>100
126
+ @lxy[(-1*[300,@lxy.size].min)..-1].each_cons(2) { |p0,p1|
127
+ app.draw_line(p0[0],p0[1], 0x33ffff00 ,p1[0],p1[1], 0x33ffff00 ) if p1
128
+ } rescue nil
129
+ end
130
+ @lxy=@lxy[-5000..-1] if @lxy.size>10000
131
+ end
132
+
133
+ def collect_stars(stars)
134
+ stars.reject! do |star|
135
+ if Gosu::distance(@x, @y, star.x, star.y) < (15+star.r) then
136
+ if star.type
137
+ @score += 70
138
+ true
139
+ else
140
+ if @vel_x !=0 || @vel_y!=0
141
+ @score -= 10
142
+ @x -= 15*@vel_x
143
+ @y -= 15*@vel_y
144
+ else
145
+ @x += (-10..+10).rand
146
+ @y += (-10..+10).rand
147
+ end
148
+ @vel_x=0
149
+ @vel_y=0
150
+ false
151
+ end
152
+ else
153
+ false
154
+ end
155
+ end
156
+ @app.looser if @score<=0
157
+ @app.winner(@score) if 0 == (stars.select { |s| s.type }.size )
158
+ end
159
+
160
+ end
161
+
162
+
163
+ ###########################################################################
164
+ # S t a r
165
+ ###########################################################################
166
+ class Star
167
+ attr_reader :x, :y, :type,:r
168
+
169
+ def initialize(ls,type,animation)
170
+ @animation = animation
171
+ @ls=ls
172
+ @type=type
173
+ @r=@type ? 10 : (20..60).rand()
174
+ @color = Gosu::Color.new(0xff000000 )
175
+ @color.red = type ? 255 : 0
176
+ @color.green = type ? 0 : 200
177
+ @color.blue = type ? 0 : 200
178
+ @x = (SX/5..(SX-SX/5)).rand
179
+ @y = (SY/5..(SY-SY/5)).rand
180
+ end
181
+ def move(player)
182
+ expand(player)
183
+ end
184
+ def draw()
185
+ img = @animation[self.type ? 1 : 0 ]
186
+ img.draw_rot(@x, @y, ZOrder::Stars, 0, 0.5,0.5 ,@r/10, @r/10,@color)
187
+ end
188
+ def expand(p)
189
+ ox,oy=@x,@y
190
+ @ls.each do |s|
191
+ next if s==self
192
+ (@x+=e(@x,s.x) ; @y+=e(@y,s.y) ) if Gosu::distance(@x,@y,s.x,s.y)< ((s.type && self.type) ? 100 : 0 )
193
+ end
194
+ d=Gosu::distance(@x,@y,p.x,p.y)-@r-p.r
195
+ if @type
196
+ (@x+=-e(p.x,@x)/0.5 ; @y+=-e(p.y,@y)/0.5 ) if d> 20 && d < 180
197
+ else
198
+ (@x+=e(p.x,@x)/5.0 ; @y+=e(p.y,@y)/5.0 ) if d> 20 && d < 0
199
+ end
200
+ @x=ox if @x>600 || @x<40
201
+ @y=oy if @y>440 || @y<40
202
+ end
203
+ end
204
+
205
+ ###########################################################################
206
+ # W i n d o w
207
+ ###########################################################################
208
+
209
+ class GameWindow < Gosu::Window
210
+ attr_reader :star,:ping
211
+ def initialize
212
+ super((SX*KK).to_i, (SY*KK).to_i, false)
213
+ self.caption = "Gosu Tutorial Game"
214
+
215
+ @lp=[]; 100.times { x=rand(SX) ; y=rand(SY); @lp<<x;@lp<<y }
216
+ @player_anim= Gosu::Image::load_tiles(self, "Starfighter2.bmp", 50,50, false)
217
+ @player = Player.new(self,@player_anim)
218
+ @player.warp(320, 240)
219
+ @font = Gosu::Font.new(self, Gosu::default_font_name, (20/KK).round)
220
+ @font2 = Gosu::Font.new(self, Gosu::default_font_name, (40/KK).round)
221
+
222
+ @star_anim = Gosu::Image::load_tiles(self, "Star.png", 25,25, false)
223
+ @ping=0
224
+ @start=0
225
+ @mouse=nil
226
+ self.go("Start")
227
+ end
228
+
229
+ ######################## Game global state
230
+
231
+ def looser() ego("Loose") end
232
+ def winner(n) ego("Winne #{n}") end
233
+ def ego(text)
234
+ puts "ego #{text}"
235
+ @text=text
236
+ @start=@ping+50
237
+ Thread.new { sleep 2 ; self.go("Start") }
238
+ end
239
+ def go(text)
240
+ @start=@ping+200
241
+ @text=text
242
+ @stars = Array.new
243
+ 3.times { @stars.push( Star.new(@stars,false,@star_anim) ) }
244
+ 10.times { @stars.push( Star.new(@stars,true,@star_anim) ) }
245
+ @player.restart
246
+ end
247
+ def is_pending() (@start > @ping) end
248
+
249
+ ######################## Global interactions : mouse/keyboard
250
+
251
+ def interactions()
252
+ @player.turn_left if button_down? Gosu::KbLeft or button_down? Gosu::GpLeft
253
+ @player.turn_right if button_down? Gosu::KbRight or button_down? Gosu::GpRight
254
+ @player.accelerate(true) if button_down? Gosu::KbUp or button_down? Gosu::GpButton0
255
+ @player.accelerate(false) if button_down? Gosu::KbDown or button_down? Gosu::GpButton1
256
+ #mouse_control
257
+ end
258
+ def mouse_control
259
+ n=[mouse_x,mouse_y]
260
+ @mouse=n unless @mouse
261
+ dx=n[0]-@mouse[0]
262
+ dy=n[1]-@mouse[1]
263
+ if Math.hypot(dx,dy)>D
264
+ @player.turn_left if dx<-D
265
+ @player.turn_right if dx>D
266
+ @player.accelerate(true) if dy<-D
267
+ @player.accelerate(false) if dx>D
268
+ end
269
+ @mouse=n
270
+ end
271
+ def button_down(id)
272
+ if id == Gosu::KbEscape
273
+ if @player.score==0
274
+ close
275
+ else
276
+ @player.score=0
277
+ end
278
+ end
279
+ end
280
+
281
+ ######################## Global draw : update()/draw() are invoked continuously by Gosu engine
282
+
283
+ def update
284
+ @ping+=1
285
+ return if @ping<@start
286
+ @player.clear()
287
+ interactions()
288
+ @player.move(@stars)
289
+ @player.collect_stars(@stars)
290
+ @stars.each { |star| star.move(@player) }
291
+ end
292
+
293
+ def draw
294
+ scale(KK,KK) {
295
+ draw_background
296
+ @player.draw(self,@stars)
297
+ @stars.each { |star| star.draw() }
298
+ draw_variable_background()
299
+ }
300
+ end
301
+ def draw_background
302
+ @lp.each_slice(2) do |x,y|
303
+ draw_triangle(
304
+ x, y, 0xAAFFFFFF,
305
+ x+(3..5).rand, y+(3..5).rand, 0xAAFFFFFF,
306
+ x+(3..5).rand, y, 0xAAFFFFFF)
307
+ end
308
+ end
309
+ def draw_variable_background()
310
+ if @ping<@start
311
+ @font2.draw(@text+ " ! !", SX/2, SY/2, ZOrder::UI, 1.0, 1.0, 0xf0f0f000)
312
+ @font.draw("", 10, 10, ZOrder::UI, 1.0, 1.0, 0xffffff00)
313
+ else
314
+ #----------- barr graph energies reserve level
315
+ h=5+(@player.score/2000.0)*(SY-10)
316
+ draw_quad(5, 5, 0xBB55FF55, 20/KK, 5, 0xBB55FF55, 20/KK, h, 0xBBFFFF55, 5 , h , 0xBBFFFF55)
317
+
318
+ #------------ textual energie reserve level
319
+ @font.draw("Score: #{@player.score}", 25/KK, 10/KK, ZOrder::UI, 1.0, 1.0, 0xffffff00)
320
+ end
321
+ end
322
+ end
323
+
324
+ GameWindow.new.show