chingu 0.9rc4 → 0.9rc5
Sign up to get free protection for your applications and to get access to all the features.
- data/chingu.gemspec +2 -2
- data/examples/example28_networking.rb +5 -0
- data/lib/chingu.rb +1 -1
- data/lib/chingu/basic_game_object.rb +2 -2
- data/lib/chingu/game_states/network_client.rb +40 -14
- data/lib/chingu/game_states/network_server.rb +27 -11
- data/lib/chingu/traits/sprite.rb +5 -3
- data/lib/chingu/traits/timer.rb +23 -15
- data/lib/chingu/viewport.rb +1 -1
- data/spec/chingu/game_object_list_spec.rb +7 -0
- data/spec/chingu/input_spec.rb +1 -0
- data/spec/chingu/network_spec.rb +20 -4
- metadata +10 -10
data/chingu.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{chingu}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.9rc5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["ippa"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-05-28}
|
13
13
|
s.description = %q{OpenGL accelerated 2D game framework for Ruby. Builds on Gosu (Ruby/C++) which provides all the core functionality. Chingu adds simple yet powerful game states, prettier input handling, deployment safe asset-handling, a basic re-usable game object and stackable game logic.}
|
14
14
|
s.email = %q{ippa@rubylicio.us}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -16,6 +16,7 @@ class Game < Chingu::Window
|
|
16
16
|
@server = Server.new
|
17
17
|
|
18
18
|
@server.start("0.0.0.0", 1234)
|
19
|
+
#@client.connect("192.168.0.1", 1234)
|
19
20
|
@client.connect("127.0.0.1", 1234)
|
20
21
|
end
|
21
22
|
|
@@ -50,6 +51,10 @@ class Client < GameStates::NetworkClient
|
|
50
51
|
puts "Client Got: #{msg.inspect}"
|
51
52
|
end
|
52
53
|
|
54
|
+
def on_connection_refused
|
55
|
+
puts "connection refused"
|
56
|
+
end
|
57
|
+
|
53
58
|
end
|
54
59
|
|
55
60
|
#
|
data/lib/chingu.rb
CHANGED
@@ -118,7 +118,7 @@ module Chingu
|
|
118
118
|
# Disable automatic calling of update() and update_trait() each game loop
|
119
119
|
#
|
120
120
|
def pause!
|
121
|
-
@parent.game_objects.pause_game_object(self) if @parent &&
|
121
|
+
@parent.game_objects.pause_game_object(self) if @parent && !@paused
|
122
122
|
@paused = true
|
123
123
|
end
|
124
124
|
alias :pause :pause!
|
@@ -127,7 +127,7 @@ module Chingu
|
|
127
127
|
# Enable automatic calling of update() and update_trait() each game loop
|
128
128
|
#
|
129
129
|
def unpause!
|
130
|
-
@parent.game_objects.unpause_game_object(self) if @parent && @paused
|
130
|
+
@parent.game_objects.unpause_game_object(self) if @parent && @paused
|
131
131
|
@paused = false
|
132
132
|
end
|
133
133
|
alias :unpause :unpause!
|
@@ -28,7 +28,7 @@ module Chingu
|
|
28
28
|
# Uses nonblocking polling TCP and YAML to communicate.
|
29
29
|
# If your game state inherits from NetworkClient you'll have the following methods available:
|
30
30
|
#
|
31
|
-
# connect(ip, port) # Start a
|
31
|
+
# connect(ip, port) # Start a nonblocking connection. only connect() uses previosly given ip:port
|
32
32
|
# send_data(data) # Send raw data on the network, nonblocking
|
33
33
|
# send_msg(whatever ruby data) # Will get YAML'd and sent to server
|
34
34
|
# handle_incoming_data(max_size) # Nonblocking read of incoming server data
|
@@ -72,6 +72,8 @@ module Chingu
|
|
72
72
|
class NetworkClient < Chingu::GameState
|
73
73
|
attr_reader :latency, :socket, :packet_counter, :packet_buffer, :ip, :port
|
74
74
|
alias_method :address, :ip
|
75
|
+
|
76
|
+
def connected?; @connected; end
|
75
77
|
|
76
78
|
def initialize(options = {})
|
77
79
|
super
|
@@ -82,6 +84,7 @@ module Chingu
|
|
82
84
|
@max_read_per_update = options[:max_read_per_update] || 50000
|
83
85
|
|
84
86
|
@socket = nil
|
87
|
+
@connected = false
|
85
88
|
@latency = 0
|
86
89
|
@packet_counter = 0
|
87
90
|
@packet_buffer = NetworkServer::PacketBuffer.new
|
@@ -89,11 +92,35 @@ module Chingu
|
|
89
92
|
|
90
93
|
#
|
91
94
|
# Default network loop:
|
92
|
-
# 1)
|
93
|
-
# 2)
|
94
|
-
# 3) #
|
95
|
+
# 1) Try to complete outgoing connection if connect() has been called
|
96
|
+
# 2) read raw data from server with #handle_incoming_data
|
97
|
+
# 3) #handle_incoming_data call #on_data(data)
|
98
|
+
# 4) #on_data(data) will call #on_msgs(msg)
|
95
99
|
#
|
96
100
|
def update
|
101
|
+
|
102
|
+
if @socket and not @connected
|
103
|
+
begin
|
104
|
+
# Start/Check on our nonblocking tcp connection
|
105
|
+
@socket.connect_nonblock(@sockaddr)
|
106
|
+
rescue Errno::EINPROGRESS #rescue IO::WaitWritable
|
107
|
+
rescue Errno::EALREADY
|
108
|
+
if IO.select([@socket],nil,nil,0.1).nil?
|
109
|
+
@socket = nil
|
110
|
+
on_connection_refused
|
111
|
+
end
|
112
|
+
rescue Errno::EISCONN
|
113
|
+
@connected = true
|
114
|
+
on_connect
|
115
|
+
rescue Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EINVAL
|
116
|
+
@socket = nil
|
117
|
+
on_connection_refused
|
118
|
+
rescue Errno::ETIMEDOUT
|
119
|
+
@socket = nil
|
120
|
+
on_timeout
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
97
124
|
handle_incoming_data
|
98
125
|
super
|
99
126
|
end
|
@@ -109,16 +136,9 @@ module Chingu
|
|
109
136
|
@ip = ip if ip
|
110
137
|
@port = port if port
|
111
138
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
on_connect
|
116
|
-
end
|
117
|
-
rescue Errno::ECONNREFUSED
|
118
|
-
on_connection_refused
|
119
|
-
rescue Timeout
|
120
|
-
on_timeout
|
121
|
-
end
|
139
|
+
# Set up our @socket, update() will handle the actual nonblocking connection
|
140
|
+
@socket = Socket.new(Socket::Constants::AF_INET, Socket::Constants::SOCK_STREAM, 0)
|
141
|
+
@sockaddr = Socket.sockaddr_in(@port, @ip)
|
122
142
|
|
123
143
|
return self
|
124
144
|
end
|
@@ -127,6 +147,7 @@ module Chingu
|
|
127
147
|
# Called when connect() fails with connection refused (closed port)
|
128
148
|
#
|
129
149
|
def on_connection_refused
|
150
|
+
puts "[on_connection_refused() #{@ip}:#{@port}]" if @debug
|
130
151
|
connect(@ip, @port)
|
131
152
|
end
|
132
153
|
|
@@ -134,6 +155,7 @@ module Chingu
|
|
134
155
|
# Called when connect() recieves no initial answer from server
|
135
156
|
#
|
136
157
|
def on_timeout
|
158
|
+
puts "[on_timeout() #{@ip}:#{@port}]" if @debug
|
137
159
|
connect(@ip, @port)
|
138
160
|
end
|
139
161
|
|
@@ -163,6 +185,8 @@ module Chingu
|
|
163
185
|
packet, sender = @socket.recvfrom(amount)
|
164
186
|
on_data(packet)
|
165
187
|
rescue Errno::ECONNABORTED, Errno::ECONNRESET
|
188
|
+
@connected = false
|
189
|
+
@socket = nil
|
166
190
|
on_disconnect
|
167
191
|
end
|
168
192
|
end
|
@@ -195,6 +219,8 @@ module Chingu
|
|
195
219
|
@socket.write([data.length].pack(NetworkServer::PACKET_HEADER_FORMAT))
|
196
220
|
@socket.write(data)
|
197
221
|
rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE, Errno::ENOTCONN
|
222
|
+
@connected = false
|
223
|
+
@socket = nil
|
198
224
|
on_disconnect
|
199
225
|
end
|
200
226
|
end
|
@@ -111,8 +111,7 @@ module Chingu
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
attr_reader :socket, :sockets, :ip, :port
|
115
|
-
|
114
|
+
attr_reader :socket, :sockets, :ip, :port, :max_connections
|
116
115
|
alias_method :address, :ip
|
117
116
|
|
118
117
|
def initialize(options = {})
|
@@ -121,10 +120,11 @@ module Chingu
|
|
121
120
|
@ip = options[:ip] || "0.0.0.0"
|
122
121
|
@port = options[:port] || DEFAULT_PORT
|
123
122
|
@debug = options[:debug]
|
123
|
+
@max_read_per_update = options[:max_read_per_update] || 20000
|
124
|
+
@max_connections = options[:max_connections] || 256
|
125
|
+
|
124
126
|
@socket = nil
|
125
127
|
@sockets = []
|
126
|
-
@max_read_per_update = options[:max_read_per_update] || 20000
|
127
|
-
|
128
128
|
@packet_buffers = Hash.new
|
129
129
|
end
|
130
130
|
|
@@ -197,9 +197,13 @@ module Chingu
|
|
197
197
|
def handle_incoming_connections
|
198
198
|
begin
|
199
199
|
while socket = @socket.accept_nonblock
|
200
|
-
@sockets
|
201
|
-
|
202
|
-
|
200
|
+
if @sockets.size < @max_connections
|
201
|
+
@sockets << socket
|
202
|
+
@packet_buffers[socket] = PacketBuffer.new
|
203
|
+
on_connect(socket)
|
204
|
+
else
|
205
|
+
socket.close
|
206
|
+
end
|
203
207
|
end
|
204
208
|
rescue IO::WaitReadable, Errno::EINTR
|
205
209
|
end
|
@@ -215,7 +219,7 @@ module Chingu
|
|
215
219
|
begin
|
216
220
|
packet, sender = socket.recvfrom(max_size)
|
217
221
|
on_data(socket, packet)
|
218
|
-
rescue Errno::ECONNABORTED, Errno::ECONNRESET
|
222
|
+
rescue Errno::ECONNABORTED, Errno::ECONNRESET, IOError
|
219
223
|
@packet_buffers[socket] = nil
|
220
224
|
|
221
225
|
on_disconnect(socket)
|
@@ -271,11 +275,21 @@ module Chingu
|
|
271
275
|
#
|
272
276
|
def disconnect_client(socket)
|
273
277
|
socket.close
|
278
|
+
@sockets.delete socket
|
279
|
+
@packet_buffers.delete socket
|
280
|
+
on_disconnect(socket)
|
281
|
+
rescue Errno::ENOTCONN
|
274
282
|
end
|
275
283
|
|
276
284
|
# Ensure that the buffer is cleared of data to write (call at the end of update or, at least after all sends).
|
277
285
|
def flush
|
278
|
-
@sockets.each
|
286
|
+
@sockets.each do |socket|
|
287
|
+
begin
|
288
|
+
socket.flush
|
289
|
+
rescue IOError
|
290
|
+
disconnect_client(socket)
|
291
|
+
end
|
292
|
+
end
|
279
293
|
end
|
280
294
|
|
281
295
|
#
|
@@ -283,10 +297,12 @@ module Chingu
|
|
283
297
|
#
|
284
298
|
def stop
|
285
299
|
return unless @socket
|
286
|
-
|
300
|
+
|
301
|
+
@sockets.each {|socket| disconnect_client(socket) }
|
302
|
+
@sockets = []
|
287
303
|
@socket.close
|
304
|
+
@socket = nil
|
288
305
|
rescue Errno::ENOTCONN
|
289
|
-
end
|
290
306
|
end
|
291
307
|
alias close stop
|
292
308
|
|
data/lib/chingu/traits/sprite.rb
CHANGED
@@ -71,7 +71,9 @@ module Chingu
|
|
71
71
|
def to_s
|
72
72
|
"#{self.class.to_s} @ #{x.to_i} / #{y.to_i} " <<
|
73
73
|
"(#{width.to_i} x #{height.to_i}) - " <<
|
74
|
-
"
|
74
|
+
"ratio: #{sprintf("%.2f",width.to_f/height.to_f)} " <<
|
75
|
+
"scale: #{sprintf("%.2f", factor_x)}/#{sprintf("%.2f", factor_y)} " <<
|
76
|
+
"angle: #{angle.to_i} zorder: #{zorder} alpha: #{alpha}"
|
75
77
|
end
|
76
78
|
|
77
79
|
def color=(color)
|
@@ -205,7 +207,7 @@ module Chingu
|
|
205
207
|
# Disable automatic calling of draw and draw_trait each game loop
|
206
208
|
#
|
207
209
|
def hide!
|
208
|
-
@parent.game_objects.hide_game_object(self) if @parent && @visible
|
210
|
+
@parent.game_objects.hide_game_object(self) if @parent && @visible
|
209
211
|
@visible = false
|
210
212
|
end
|
211
213
|
|
@@ -213,7 +215,7 @@ module Chingu
|
|
213
215
|
# Enable automatic calling of draw and draw_trait each game loop
|
214
216
|
#
|
215
217
|
def show!
|
216
|
-
@parent.game_objects.show_game_object(self) if @parent &&
|
218
|
+
@parent.game_objects.show_game_object(self) if @parent && !@visible
|
217
219
|
@visible = true
|
218
220
|
end
|
219
221
|
|
data/lib/chingu/traits/timer.rb
CHANGED
@@ -24,16 +24,16 @@ module Chingu
|
|
24
24
|
|
25
25
|
#
|
26
26
|
# A chingu trait providing timer-methods to its includer, examples:
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
27
|
+
# during(300) { @color = Color.new(0xFFFFFFFF) } # forces @color to white ever update for 300 ms
|
28
|
+
# after(400) { self.destroy! } # destroy object after 400 ms
|
29
|
+
# between(1000,2000) { self.rotate(10) } # starting after 1 second, call rotate(10) each update during 1 second
|
30
30
|
#
|
31
31
|
# All the above can be combined with a 'then { do_something }'. For example, a classic shmup damage effect:
|
32
|
-
#
|
32
|
+
# during(100) { @color.alpha = 100 }.then { @color.alpha = 255 }
|
33
33
|
#
|
34
34
|
module Timer
|
35
35
|
|
36
|
-
def setup_trait(options)
|
36
|
+
def setup_trait(options)
|
37
37
|
#
|
38
38
|
# Timers are saved as an array of arrays where each entry contains:
|
39
39
|
# [name, start_time, end_time (or nil if one-shot), &block]
|
@@ -44,7 +44,7 @@ module Chingu
|
|
44
44
|
end
|
45
45
|
|
46
46
|
#
|
47
|
-
# Executes block each update during 'time' milliseconds
|
47
|
+
# Executes block each update during 'time' milliseconds
|
48
48
|
#
|
49
49
|
def during(time, options = {}, &block)
|
50
50
|
if options[:name]
|
@@ -59,7 +59,7 @@ module Chingu
|
|
59
59
|
end
|
60
60
|
|
61
61
|
#
|
62
|
-
# Executes block after 'time' milliseconds
|
62
|
+
# Executes block after 'time' milliseconds
|
63
63
|
#
|
64
64
|
def after(time, options = {}, &block)
|
65
65
|
if options[:name]
|
@@ -89,7 +89,7 @@ module Chingu
|
|
89
89
|
end
|
90
90
|
|
91
91
|
#
|
92
|
-
# Executes block every 'delay' milliseconds
|
92
|
+
# Executes block every 'delay' milliseconds
|
93
93
|
#
|
94
94
|
def every(delay, options = {}, &block)
|
95
95
|
if options[:name]
|
@@ -98,13 +98,17 @@ module Chingu
|
|
98
98
|
end
|
99
99
|
|
100
100
|
ms = Gosu::milliseconds()
|
101
|
-
@_repeating_timers << [options[:name], ms + delay, delay, block]
|
101
|
+
@_repeating_timers << [options[:name], ms + delay, delay, options[:during] ? ms + options[:during] : nil, block]
|
102
|
+
if options[:during]
|
103
|
+
@_last_timer = [options[:name], nil, ms + options[:during]]
|
104
|
+
return self
|
105
|
+
end
|
102
106
|
end
|
103
107
|
|
104
108
|
#
|
105
|
-
# Executes block after the last timer ends
|
109
|
+
# Executes block after the last timer ends
|
106
110
|
# ...use one-shots start_time for our trailing "then".
|
107
|
-
# ...use durable timers end_time for our trailing "then".
|
111
|
+
# ...use durable timers end_time for our trailing "then".
|
108
112
|
#
|
109
113
|
def then(&block)
|
110
114
|
start_time = @_last_timer[2].nil? ? @_last_timer[1] : @_last_timer[2]
|
@@ -142,16 +146,20 @@ module Chingu
|
|
142
146
|
ms = Gosu::milliseconds()
|
143
147
|
|
144
148
|
@_timers.each do |name, start_time, end_time, block|
|
145
|
-
block.call
|
149
|
+
block.call if ms > start_time && (end_time == nil || ms < end_time)
|
146
150
|
end
|
147
151
|
|
148
152
|
index = 0
|
149
|
-
@_repeating_timers.each do |name, start_time, delay, block|
|
153
|
+
@_repeating_timers.each do |name, start_time, delay, end_time, block|
|
150
154
|
if ms > start_time
|
151
155
|
block.call
|
152
|
-
@_repeating_timers[index] = [name, ms + delay, delay, block]
|
156
|
+
@_repeating_timers[index] = [name, ms + delay, delay, end_time, block]
|
157
|
+
end
|
158
|
+
if end_time && ms > end_time
|
159
|
+
@_repeating_timers.delete_at index
|
160
|
+
else
|
161
|
+
index += 1
|
153
162
|
end
|
154
|
-
index += 1
|
155
163
|
end
|
156
164
|
|
157
165
|
# Remove one-shot timers (only a start_time, no end_time) and all timers which have expired
|
data/lib/chingu/viewport.rb
CHANGED
@@ -63,6 +63,13 @@ module Chingu
|
|
63
63
|
@game.game_objects.draw
|
64
64
|
end
|
65
65
|
|
66
|
+
it "should keep track of visible game objects with show!()" do
|
67
|
+
go = GameObject.create(:visible => false)
|
68
|
+
go.show!
|
69
|
+
go.should_receive(:draw)
|
70
|
+
@game.game_objects.draw
|
71
|
+
end
|
72
|
+
|
66
73
|
it "should call draw() on all visible game objects" do
|
67
74
|
GameObject.create.should_receive(:draw)
|
68
75
|
GameObject.create(:visible => false).should_not_receive(:draw)
|
data/spec/chingu/input_spec.rb
CHANGED
@@ -8,6 +8,7 @@ describe Chingu::Input do
|
|
8
8
|
gosu_inputs = input_names.inject({}) {|hash, name| hash[name] = Gosu.const_get name; hash }
|
9
9
|
|
10
10
|
gosu_inputs.each_value do |code|
|
11
|
+
next if code==0 # todo, check into this, spooner? ;)
|
11
12
|
symbols = described_class::CONSTANT_TO_SYMBOL[code]
|
12
13
|
symbols.should_not be_empty
|
13
14
|
symbols.each {|s| s.should be_kind_of Symbol }
|
data/spec/chingu/network_spec.rb
CHANGED
@@ -22,6 +22,15 @@ module Chingu
|
|
22
22
|
@server.stop
|
23
23
|
end
|
24
24
|
|
25
|
+
it "client should timeout when connecting to blackhole ip" do
|
26
|
+
@client = Chingu::GameStates::NetworkClient.new(:ip => "1.2.3.4", :port => 1234, :debug => true)
|
27
|
+
@client.connect
|
28
|
+
|
29
|
+
#@client.should_receive(:on_timeout) ## gives on_connection_refused instead, kind of ok.
|
30
|
+
@client.should_receive(:on_connection_refused)
|
31
|
+
@client.update while @client.socket
|
32
|
+
end
|
33
|
+
|
25
34
|
it "should call on_start_error() if failing" do
|
26
35
|
@server = described_class.new(:ip => "1.2.3.999", :port => 12345678) # crazy ip:port
|
27
36
|
@server.should_receive(:on_start_error)
|
@@ -38,6 +47,8 @@ module Chingu
|
|
38
47
|
@client.should_receive(:on_connect)
|
39
48
|
@server.start
|
40
49
|
@client.connect
|
50
|
+
|
51
|
+
@client.update until @client.connected?
|
41
52
|
@server.update
|
42
53
|
|
43
54
|
@client.stop
|
@@ -51,6 +62,7 @@ module Chingu
|
|
51
62
|
@client = described_class.new(:ip => "127.0.0.1", :port => 55421) # closed we assume
|
52
63
|
@client.should_receive(:on_connection_refused)
|
53
64
|
@client.connect
|
65
|
+
5.times { @client.update }
|
54
66
|
end
|
55
67
|
end
|
56
68
|
|
@@ -59,6 +71,8 @@ module Chingu
|
|
59
71
|
@server = Chingu::GameStates::NetworkServer.new(:port => 9999).start
|
60
72
|
@client = Chingu::GameStates::NetworkClient.new(:ip => "127.0.0.1", :port => 9999).connect
|
61
73
|
@client2 = Chingu::GameStates::NetworkClient.new(:ip => "127.0.0.1", :port => 9999).connect
|
74
|
+
@client.update until @client.connected?
|
75
|
+
@client2.update until @client2.connected?
|
62
76
|
end
|
63
77
|
|
64
78
|
after :each do
|
@@ -73,7 +87,7 @@ module Chingu
|
|
73
87
|
data.each {|packet| @server.should_receive(:on_msg).with(an_instance_of(TCPSocket), packet) }
|
74
88
|
data.each {|packet| @client.send_msg(packet) }
|
75
89
|
|
76
|
-
@server.update
|
90
|
+
5.times { @server.update }
|
77
91
|
end
|
78
92
|
end
|
79
93
|
end
|
@@ -85,7 +99,7 @@ module Chingu
|
|
85
99
|
@server.update # Accept the client before sending, so we know of its socket.
|
86
100
|
data.each { |packet| @server.send_msg(@server.sockets[0], packet) }
|
87
101
|
|
88
|
-
@client.update
|
102
|
+
5.times { @client.update }
|
89
103
|
end
|
90
104
|
end
|
91
105
|
end
|
@@ -102,8 +116,10 @@ module Chingu
|
|
102
116
|
|
103
117
|
data.each {|packet| @server.broadcast_msg(packet) }
|
104
118
|
|
105
|
-
|
106
|
-
|
119
|
+
5.times do
|
120
|
+
@client.update
|
121
|
+
@client2.update
|
122
|
+
end
|
107
123
|
end
|
108
124
|
end
|
109
125
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chingu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9rc5
|
5
5
|
prerelease: 3
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-05-28 00:00:00.000000000 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: gosu
|
17
|
-
requirement: &
|
17
|
+
requirement: &24886884 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 0.7.27.1
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *24886884
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rspec
|
28
|
-
requirement: &
|
28
|
+
requirement: &24886572 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 2.1.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *24886572
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: watchr
|
39
|
-
requirement: &
|
39
|
+
requirement: &24886188 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *24886188
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: rcov
|
50
|
-
requirement: &
|
50
|
+
requirement: &24885792 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,7 +55,7 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *24885792
|
59
59
|
description: OpenGL accelerated 2D game framework for Ruby. Builds on Gosu (Ruby/C++)
|
60
60
|
which provides all the core functionality. Chingu adds simple yet powerful game
|
61
61
|
states, prettier input handling, deployment safe asset-handling, a basic re-usable
|