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.
@@ -0,0 +1,199 @@
1
+ # Creative Commons BY-SA : Regis d'Aubarede <regis.aubarede@gmail.com>
2
+ ###########################################################################
3
+ # reseau sharing for ANG
4
+ # NetClient: singleton inteface main <=> net
5
+ # MCast : multicasting encapsulation
6
+ ###########################################################################
7
+ require "thread"
8
+ require "socket"
9
+ require "ipaddr"
10
+ require "zlib" # if message is too big for a datagram, zip it
11
+ (puts "ruby version must be 1.9.3 or best (patched for multicast)";exit(1)) if RUBY_VERSION < "1.9.3"
12
+
13
+ ################ Net manager : multicast member, send to all, receive from any ##############
14
+ class NetClient
15
+ class << self
16
+ def init(game)
17
+ @is_master=true
18
+ @trace=false
19
+ @event_stack = Queue.new
20
+ @players,@players_ip,@game={},{},game
21
+ @queue= Queue.new
22
+ @mcast=MCast.new(self)
23
+ Thread.new { dispatch() }
24
+ end
25
+ def set_trace(on)
26
+ @trace=on
27
+ end
28
+ def is_master() @is_master end
29
+ def reinit_master(lid)
30
+ @is_master=true unless lid.any? {|id| id<$id}
31
+ end
32
+ # invoked by MCast, data is string (ruby literal)
33
+ # ["move",id,time,[x,y],[vx,vy],[a,va]]
34
+ def receive_data(data)
35
+ return if !(data && data[0,1]=="[")
36
+ bdata=eval( data )
37
+ log("Received: #{bdata.inspect[0..100]} / length=#{data.size} bytes") if @trace
38
+ if Array===bdata && bdata.length>1
39
+ code,id,*bdata=bdata
40
+ if id==$id
41
+ log(" This message is from myself ! so, multicast seem ok")if @trace
42
+ return
43
+ end
44
+ @is_master=false if id<$id
45
+ @event_stack << [code,id,bdata]
46
+ end
47
+ end
48
+ # event recived by multicast, are evaluated here,
49
+ # event_invoke() must be called in main thread loop
50
+ def event_invoke()
51
+ while @event_stack.size>0
52
+ code,id,bdata=*(@event_stack.pop)
53
+ invoke(code,id,bdata)
54
+ end
55
+ end
56
+ def wait_and_invoke()
57
+ code,id,bdata=*(@event_stack.pop)
58
+ invoke(code,id,bdata)
59
+ end
60
+ def invoke(code,id,bdata)
61
+ case code
62
+ when "move"
63
+ @game.update_payers(id,bdata)
64
+ when "connect"
65
+ @game.init_player(id)
66
+ @game.send_positions(id)
67
+ when "success"
68
+ @game.receive_success(id)
69
+ when "echec"
70
+ @game.receive_echec(id)
71
+ when "positions"
72
+ @game.get_positions(id,bdata) if id < $id
73
+ when "star_delete"
74
+ @game.star_deleted(bdata[0])
75
+ when "nmissile"
76
+ @game.new_missile(bdata)
77
+ when "emissile"
78
+ @game.end_missile(bdata[0])
79
+ when "comment"
80
+ @game.display_comment(bdata[0])
81
+ when "dead-pl"
82
+ @game.receive_echec(bdata[0])
83
+ when "echo"
84
+ recho(bdata)
85
+ when "recho"
86
+ @game.recho(id,*bdata) rescue p $!
87
+ when "quit"
88
+ @game.recho(id,*bdata) rescue nil
89
+ else
90
+ puts "recieved unknown message #{[code,id,data].join(", ")}"
91
+ end rescue (puts $!.to_s + "\n "+ $!.backtrace.join("\n "))
92
+ end
93
+ def dispatch()
94
+ @mcast.send_message(1,["connect",$id])
95
+ loop do
96
+ begin
97
+ m=@queue.pop
98
+ #log "#{$id} send to serveur : ",m
99
+ @mcast.send_message(1,m)
100
+ rescue Exception => e
101
+ puts e.to_s + "\n "+ e.backtrace.join("\n ")
102
+ end
103
+ end
104
+ end
105
+ def connect() @mcast.send_message(1,["connect",$id]) end
106
+ def player_is_moving(data) @queue.push(["move",$id,*data]) end
107
+ def send_success() @queue.push(["success",$id]) end
108
+ def send_echec() @queue.push(["echec",$id]) end
109
+ def send_position(data) @queue.push(["positions",$id,*data]) end
110
+ def star_deleted(index) @queue.push(["star_delete",$id,index]) end
111
+ def comment(text) @queue.push(["comment",$id,text]) end
112
+ def new_missile(data) @queue.push(["nmissile",$id,*data]) end
113
+ def end_missile(data) @queue.push(["emissile",$id,*data]) end
114
+ def dead_player(data) @queue.push(["dead-pl",$id,*data]) end
115
+ def echo(data) @queue.push(["echo",$id,*data]) end
116
+ def recho(data) @queue.push(["recho",$id,*data]) end
117
+ def is_stoping()
118
+ @queue.pop while (@queue.size>2)
119
+ @queue.push(["quit",$id])
120
+ Thread.new { sleep(1) ; exit! }
121
+ end
122
+ end
123
+ end
124
+
125
+
126
+ class MCast
127
+ MULTICAST_ADDR = "224.6.1.89"
128
+ BIND_ADDR = "0.0.0.0"
129
+ PORT = 6811
130
+
131
+ def initialize(client)
132
+ @client = client
133
+ socket
134
+ listen()
135
+ end
136
+
137
+ def send_message(n,content)
138
+ message = content.inspect
139
+ if message.size>1024
140
+ message= "#" + Zlib::Deflate.new(9).deflate(message, Zlib::FINISH)
141
+ if message.size>1024
142
+ puts "message size too big for a datagram !"
143
+ return
144
+ end
145
+ end
146
+ socket.send(message, 0, MULTICAST_ADDR, PORT)
147
+ (n-1).times { sleep(0.02); socket.send(message, 0, MULTICAST_ADDR, PORT) }
148
+ end
149
+
150
+ private
151
+
152
+ def listen
153
+ socket.bind(BIND_ADDR, PORT) rescue nil
154
+
155
+ Thread.new do
156
+ loop do
157
+ message, x = socket.recvfrom(1024)
158
+ if message[0,1]=="#"
159
+ zstream = Zlib::Inflate.new
160
+ message = zstream.inflate(message[1..-1])
161
+ zstream.finish
162
+ zstream.close
163
+ end
164
+ @client.receive_data(message)
165
+ end
166
+ end
167
+ end
168
+
169
+
170
+ def socket
171
+ @socket ||= UDPSocket.open.tap do |socket|
172
+ begin
173
+ socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1) rescue nil
174
+ socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1) rescue nil
175
+
176
+ ctx="bind()"
177
+ socket.bind(BIND_ADDR, PORT) if RUBY_PLATFORM =~ /(win|w)32$/ # for winxp
178
+
179
+ ctx="IP_ADD_MEMBERSHIP"
180
+ socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, bind_address)
181
+ ctx="IP_MULTICAST_TTL"
182
+ socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, 1)
183
+ rescue Exception => e
184
+ puts "******************************************"
185
+ puts "Multicast seem problematic on your system :"
186
+ puts " in #{ctx} : #{$!.to_s}"
187
+ puts "Did you have installed last version of Ruby (1.9.3p362 is ok)"
188
+ puts "Or your network is deconnected..."
189
+ puts "******************************************"
190
+ sleep 5
191
+ exit(1)
192
+ end
193
+ end
194
+ end
195
+
196
+ def bind_address
197
+ IPAddr.new(MULTICAST_ADDR).hton + IPAddr.new(BIND_ADDR).hton
198
+ end
199
+ end
@@ -0,0 +1,166 @@
1
+ # Creative Commons BY-SA : Regis d'Aubarede <regis.aubarede@gmail.com>
2
+ ###########################################################################
3
+ # P l a y e r
4
+ ###########################################################################
5
+ # move by arrow keyboard acceleration commande,
6
+ # eat star, move with current speed, and attractive planets
7
+ class Player
8
+ attr_accessor :x,:y,:r,:local,:score,:id
9
+ def initialize(window,animation,local)
10
+ @local = local
11
+ @top=0
12
+ @pos=1
13
+ @animation = animation
14
+ @app=window
15
+ clear()
16
+ @id=(Time.now.to_f*1000).to_i*1000+rand(1000)
17
+ @r=15
18
+ self.restart()
19
+ end
20
+ def restart
21
+ @vel_x = @vel_y = @angle = @vangle = 0.0
22
+ @x = SX/2
23
+ @y = SY/2
24
+ @vx,@vy=[0,0]
25
+ @score = $INITIALE_SCORE
26
+ @lxy=[]
27
+ @now=Time.now.to_f * 1000
28
+ @top=0
29
+ end
30
+ def clear() @pos=1 end
31
+ def dead
32
+ @vangle=1000
33
+ NetClient.dead_player([id])
34
+ end
35
+ def fire_missile
36
+ v=Math.sqrt(@vel_x*@vel_x+@vel_y*@vel_y)
37
+ v=6 if v.abs<6
38
+ vx=Gosu::offset_x(@angle,v)
39
+ vy=Gosu::offset_y(@angle,v)
40
+ Missile.new(@app,@animation,@local,nil,@x+10*vx,@y+10*vy,vx*1.2,vy*1.2,@r)
41
+ end
42
+ def warp(x, y) @x, @y = x, y ; end
43
+ def turn_left() @pos=3 ; @vangle -= 0.3 ; end
44
+ def turn_right() @pos=4 ; @vangle += 0.3 ; end
45
+ def accelerate(s)
46
+ @pos= s ? 0 : 2
47
+ @score-=3
48
+ @vel_x += Gosu::offset_x(@angle, s ? 0.1 : -0.1)
49
+ @vel_y += Gosu::offset_y(@angle, s ? 0.1 : -0.1)
50
+ end
51
+ def receive_button(command)
52
+ @top=5
53
+ @command=command
54
+ end
55
+
56
+ def move(stars,now)
57
+ return if @x==-1000 && @y==-1000
58
+ if @local
59
+ a=false
60
+ (a=true;@vel_x *= -1) if @x >= SX || @x <= 0
61
+ (a=true;@vel_y *= -1) if @y >= SY || @y <= 0
62
+ @x = SX-10 if @x >= SX && @vel_x.abs < 0.01
63
+ @y = SY-10 if @y >= SY && @vel_y.abs < 0.01
64
+ @x = 10 if @x <= 0 && @vel_x.abs < 0.01
65
+ @y = 10 if @y <= 0 && @vel_y.abs < 0.01
66
+
67
+ @angle+=@vangle
68
+ @vangle=@vangle*95.0/100
69
+ @lxy << [@x,@y] if @vel_x!=0 && @vel_y!=0
70
+ vx,vy=newton(stars)
71
+ @vel_x+=vx
72
+ @vel_y+=vy
73
+ @vel_x.minmax(-50,+50)
74
+ @vel_y.minmax(-50,+50)
75
+ @x += @vel_x
76
+ @y += @vel_y
77
+ n=now*1000
78
+ delta=n-@now
79
+ if delta >= $NET_TRANSMIT
80
+ @top+=1
81
+ NetClient.player_is_moving([@top,n,[@x,@y],[@vel_x,@vel_y],[vx,vy],[@angle,@vangle],@score])
82
+ @now=n
83
+ end
84
+ else
85
+ @vel_x+=@vx
86
+ @vel_y+=@vy
87
+ @vx,@vy=[@vx/2,@vy/2]
88
+ @x += @vel_x
89
+ @y += @vel_y
90
+ @angle+=@vangle
91
+ @vangle=@vangle*95.0/100
92
+ end
93
+ end
94
+ def update_by_net(data)
95
+ top,t,pos,vel,acc,ang,@score=*data
96
+ return if top<=@top
97
+ @top=top
98
+
99
+ #puts "delta #{Time.now.to_f*1000-t} ms"
100
+
101
+ @x,@y=(pos[0]+@x)/2,(pos[1]+@y)/2
102
+ @vel_x,@vel_y=vel[0]/2,vel[1]/2
103
+ @vx,@vy=acc
104
+ @angle,@vangle=ang
105
+ end
106
+
107
+ def newton(stars)
108
+ vx = vy = 0.0
109
+ stars.each do |star|
110
+ next if star.type
111
+ d=Gosu::distance(@x,@y,star.x,star.y)-15-star.r
112
+ dx,dy=*newton_xy1(15*15,star.r*star.r,self,star)
113
+ vx+=dx
114
+ vy+=dy
115
+ end
116
+ [vx,vy]
117
+ end
118
+ def draw(app,stars)
119
+ img = @animation[@pos]
120
+ img.draw_rot(@x, @y, ZOrder::Player, @angle)
121
+ x,y=newton(stars) ; app.draw_line(@x,@y, 0xffffffff,@x+x*1000,@y+y*1000,0xffffffff) # debug: mark gravity force
122
+ if app.pending?
123
+ @lxy.each_cons(2) { |p0,p1| app.draw_line(p0[0],p0[1], 0xffffff00 ,p1[0],p1[1], 0xffffff00 ) if p1} rescue nil
124
+ elsif @lxy.size>100
125
+ @lxy[(-1*[800,@lxy.size].min)..-1].each_cons(2) { |p0,p1|
126
+ app.draw_line(p0[0],p0[1], 0x33ffff00 ,p1[0],p1[1], 0x33ffff00 ) if p1
127
+ } rescue nil
128
+ end
129
+ @lxy=@lxy[-5000..-1] if @lxy.size>10000
130
+ end
131
+
132
+ def collect_stars(stars)
133
+ stars.reject! do |star|
134
+ next(false) if star.x-@x > 200
135
+ next(false) if star.x-@x < -200
136
+ next(false) if star.y-@y > 200
137
+ next(false) if star.y-@y < -200
138
+
139
+ if Gosu::distance(@x, @y, star.x, star.y) < (15+star.r) then
140
+ if star.type
141
+ @score += 120
142
+ NetClient.star_deleted(star.index)
143
+ true
144
+ else
145
+ if @vel_x !=0 || @vel_y!=0
146
+ @score -= 10
147
+ @x -= 15*@vel_x
148
+ @y -= 15*@vel_y
149
+ @x -= -2*10*@vel_x if @x >= SX && @vel_x == 0
150
+ @y -= -2*10*@vel_y if @y >= SY && @vel_y == 0
151
+ else
152
+ @x += (-10..+10).rand
153
+ @y += (-10..+10).rand
154
+ end
155
+ @vel_x=0
156
+ @vel_y=0
157
+ false
158
+ end
159
+ else
160
+ false
161
+ end
162
+ end
163
+ @app.finish if @score<=0
164
+ end
165
+
166
+ end
@@ -0,0 +1,76 @@
1
+ # Creative Commons BY-SA : Regis d'Aubarede <regis.aubarede@gmail.com>
2
+ ###########################################################################
3
+ # S t a r
4
+ ###########################################################################
5
+ class Star
6
+ attr_accessor :x, :y, :type,:r
7
+
8
+ def initialize(ls,type,animation)
9
+ @animation = animation
10
+ @index=ls.size
11
+ @ls=ls
12
+ @type=type
13
+ @r=@type ? 10 : $RANGE_STAR_SIZE.rand()
14
+ @no_img= type ? 1 : (rand()>0.5 && @r>35) ? 0 : (rand(3)+2)
15
+ @rot=rand(180)
16
+ ok=(@type || rand()<0.4)
17
+ p "nok" unless ok
18
+ @show= ok ? 1000 : 0
19
+ @color = Gosu::Color.new(0xff000000 )
20
+ @color.red = type ? 255 : 200
21
+ @color.green = type ? 0 : 200
22
+ @color.blue = type ? 0 : 200
23
+ @x = (SX/7..(SX-SX/7)).rand
24
+ @y = (SY/7..(SY-SY/7)).rand
25
+ #@x = (index % 10) * (SX/10)
26
+ #@y = (index / 10) * (SY/10)
27
+ end
28
+ def index() @index end
29
+
30
+ ########### Net
31
+
32
+ def self.create(anim,no_img,r,rot)
33
+ Star.new([],10,anim).reinit(no_img,r,rot)
34
+ end
35
+ def reinit(no_img,r,rot,colors)
36
+ @no_img,@r,@rot = no_img,r,rot
37
+ @color.red,@color.green,@color.blue=*colors
38
+ self
39
+ end
40
+ def serialize(i)
41
+ [i,[@no_img,@r,@rot,[@color.red,@color.green,@color.blue]],[@x,@y]]
42
+ end
43
+
44
+ def update(x,y) @x,@y=x,y end
45
+
46
+ def get_pos()
47
+ [@x.to_i,@y.to_i,@type,@index,@r,@no_img]
48
+ end
49
+ def set_pos(pos)
50
+ @x,@y,@type,@index,@r,@no_img=*pos
51
+ end
52
+ ####### serveur side behavior
53
+ def move(game,ls)
54
+ ox,oy=@x,@y
55
+ expand(game,ls)
56
+ @x=ox if @x>(SX-40) || @x<40
57
+ @y=oy if @y>(SY-40) || @y<40
58
+
59
+ end
60
+ def expand(game,ls)
61
+ return unless game.pending?(40)
62
+ motion(ls,self,-100.0,110) { |o| ! o.type} if type # Star <-> Planet
63
+ motion(ls,self,-10.0,50) { |o| o.type} # * <-> Star
64
+ motion(ls,self,-10.0,500) { |o| ! o.type } if !type # Planet <-> Planet
65
+ end
66
+
67
+ ####### draw client+server side
68
+ def draw()
69
+ @show+=0.3 if @show<1000
70
+ return unless @show>600
71
+ img = @animation[@no_img]
72
+ fx=(@r/40.0)*(@show/1000.0)
73
+ img.draw_rot(@x, @y, ZOrder::Stars, @rot, 0.5,0.5 ,fx,fx,@color)
74
+ end
75
+ end
76
+
@@ -0,0 +1,58 @@
1
+ # Creative Commons BY-SA : Regis d'Aubarede <regis.aubarede@gmail.com>
2
+
3
+ module ZOrder
4
+ Background, Stars, Player, UI = [0,1,2,3]
5
+ end
6
+ class Numeric
7
+ def minmax(min,max=nil)
8
+ (max=min;min=-min) if !max
9
+ return self if self>=min && self<=max
10
+ return(min) if self<min
11
+ return(max)
12
+ end
13
+ end
14
+ class Range ; def rand() self.begin+Kernel.rand((self.end-self.begin).abs) end ; end
15
+
16
+ # pseudo newton
17
+ def newton_xy1(p1,p2,a,b)
18
+ k1=1.0/40
19
+ k2=1.0/40000
20
+ dx,dy=[a.x-b.x,a.y-b.y]
21
+ d=Math::sqrt(dx ** 2 + dy ** 2)
22
+ f1=(k1*p1*p2/(d*d+100)).minmax(100)
23
+ f2=(k2*p1*p2/(d)).minmax(100)
24
+ f=0.8*[f1,f2].max
25
+ #p [f,f1,f2]
26
+ teta=Math.atan2(dy,dx)
27
+ r=[-f*Math.cos(teta),-f*Math.sin(teta)]
28
+ r
29
+ end
30
+
31
+ # newton, with 'amrtissement'
32
+ def newton_xy(p1,p2,a,b,k=1.0/300,dmin=10,dmax=10000)
33
+ dx,dy=[a.x-b.x,a.y-b.y]
34
+ d=dmin+Math::sqrt(dx ** 2 + dy ** 2)
35
+ return [0,0] if d>dmax
36
+ #f=(k*p1*p2/(d*d)).minmax(100) : k/d**2 not good for gameplay
37
+ f=(k*p1*p2/(d*d-dmin*dmin)).minmax(10)
38
+ teta=Math.atan2(dy,dx)
39
+ [-f*Math.cos(teta),-f*Math.sin(teta)]
40
+ end
41
+
42
+ # apply gravity between obj and a list l of planet
43
+ # k=coef gr&avity, >0 attraction, <0 repulsion
44
+ # dmaw : distance max, no attaction if distance>dmax
45
+ def motion(l,obj,k,dmax)
46
+ dx,dy=0,0
47
+ l.each do |o|
48
+ next if o==obj
49
+ next if block_given? && ! yield(o)
50
+ dx1,dy1= newton_xy(obj.r,o.r,obj,o,k,0,dmax)
51
+ dx+=dx1
52
+ dy+=dy1
53
+ end
54
+ obj.x+=dx
55
+ obj.y+=dy
56
+ return Math.sqrt(dx*dx+dy*dy)
57
+ end
58
+