ang 9.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.txt +88 -0
- data/README.md +86 -0
- data/Rakefile.rb +228 -0
- data/Star.bmp +0 -0
- data/Star.png +0 -0
- data/Starfighter.bmp +0 -0
- data/Starfighter2.bmp +0 -0
- data/VERSION +1 -0
- data/ang.gemspec +48 -0
- data/bin/ang +5 -0
- data/bin/angm +5 -0
- data/bin/angm_net_test +3 -0
- data/commit.rb +11 -0
- data/main.rb +379 -0
- data/main_screencast.rb +324 -0
- data/net/Star.bmp +0 -0
- data/net/Starfighter.bmp +0 -0
- data/net/agent.rb +339 -0
- data/net/essai.rb +10 -0
- data/net/missile.rb +51 -0
- data/net/multicast_test.rb +74 -0
- data/net/net.rb +199 -0
- data/net/player.rb +166 -0
- data/net/star.rb +76 -0
- data/net/tools.rb +58 -0
- metadata +93 -0
data/bin/ang
ADDED
data/bin/angm
ADDED
data/bin/angm_net_test
ADDED
data/commit.rb
ADDED
@@ -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
|
data/main_screencast.rb
ADDED
@@ -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
|