ang 9.19.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+