chingu 0.9rc3 → 0.9rc4
Sign up to get free protection for your applications and to get access to all the features.
- data/chingu.gemspec +3 -2
- data/examples/example7_gfx_helpers.rb +15 -0
- data/lib/chingu.rb +1 -1
- data/lib/chingu/classic_game_object.rb +1 -1
- data/lib/chingu/console.rb +1 -22
- data/lib/chingu/fpscounter.rb +13 -1
- data/lib/chingu/game_object.rb +1 -1
- data/lib/chingu/game_object_list.rb +8 -24
- data/lib/chingu/game_state_manager.rb +9 -2
- data/lib/chingu/game_states/network_client.rb +21 -20
- data/lib/chingu/game_states/network_server.rb +70 -40
- data/lib/chingu/helpers/fps_counter.rb +39 -0
- data/lib/chingu/helpers/game_object.rb +120 -134
- data/lib/chingu/helpers/game_state.rb +9 -27
- data/lib/chingu/helpers/gfx.rb +134 -52
- data/lib/chingu/window.rb +2 -23
- data/spec/chingu/network_spec.rb +4 -5
- metadata +11 -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.9rc4"
|
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-03-07}
|
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 = [
|
@@ -151,6 +151,7 @@ Gem::Specification.new do |s|
|
|
151
151
|
"lib/chingu/game_states/popup.rb",
|
152
152
|
"lib/chingu/gosu_ext/image.rb",
|
153
153
|
"lib/chingu/helpers/class_inheritable_accessor.rb",
|
154
|
+
"lib/chingu/helpers/fps_counter.rb",
|
154
155
|
"lib/chingu/helpers/game_object.rb",
|
155
156
|
"lib/chingu/helpers/game_state.rb",
|
156
157
|
"lib/chingu/helpers/gfx.rb",
|
@@ -19,6 +19,7 @@ class Game < Chingu::Window
|
|
19
19
|
push_game_state(FillGradient)
|
20
20
|
push_game_state(FillGradientRect)
|
21
21
|
push_game_state(FillGradientMultipleColors)
|
22
|
+
push_game_state(DrawCircle)
|
22
23
|
push_game_state(Particles)
|
23
24
|
end
|
24
25
|
|
@@ -27,6 +28,20 @@ class Game < Chingu::Window
|
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
31
|
+
class DrawCircle < Chingu::GameState
|
32
|
+
def draw
|
33
|
+
$window.caption = "circles and arcs (space to continue)"
|
34
|
+
draw_circle(0, 0, 300, Color::RED)
|
35
|
+
fill_circle($window.width, $window.height, 200, Color::RED)
|
36
|
+
|
37
|
+
colors = [Color::RED, Color::YELLOW, Color::GREEN, Color::BLUE]
|
38
|
+
0.step(360, 90).each_cons(2).zip(colors).each do |(a1, a2), color|
|
39
|
+
fill_arc(400, 100, 100, a1, a2, color)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
30
45
|
class Fill < Chingu::GameState
|
31
46
|
def draw
|
32
47
|
$window.caption = "fill (space to continue)"
|
data/lib/chingu.rb
CHANGED
data/lib/chingu/console.rb
CHANGED
@@ -25,6 +25,7 @@ module Chingu
|
|
25
25
|
#
|
26
26
|
#
|
27
27
|
class Console
|
28
|
+
include Chingu::Helpers::FPSCounter # Adds FPSCounter delegators
|
28
29
|
include Chingu::Helpers::GameState # Easy access to the global game state-queue
|
29
30
|
include Chingu::Helpers::GameObject # Adds game_objects_of_class etc ...
|
30
31
|
|
@@ -73,28 +74,6 @@ module Chingu
|
|
73
74
|
game_state_manager.inside_state || game_state_manager.current_game_state || self
|
74
75
|
end
|
75
76
|
|
76
|
-
#
|
77
|
-
# Frames per second, access with $window.fps or $window.framerate
|
78
|
-
#
|
79
|
-
def fps
|
80
|
-
@fps_counter.fps
|
81
|
-
end
|
82
|
-
alias :framerate :fps
|
83
|
-
|
84
|
-
#
|
85
|
-
# Total amount of game iterations (ticks)
|
86
|
-
#
|
87
|
-
def ticks
|
88
|
-
@fps_counter.ticks
|
89
|
-
end
|
90
|
-
|
91
|
-
#
|
92
|
-
# Mathematical short name for "milliseconds since last tick"
|
93
|
-
#
|
94
|
-
def dt
|
95
|
-
@milliseconds_since_last_tick
|
96
|
-
end
|
97
|
-
|
98
77
|
#
|
99
78
|
# Chingus core-logic / loop. Gosu will call this each game-iteration.
|
100
79
|
#
|
data/lib/chingu/fpscounter.rb
CHANGED
@@ -26,7 +26,19 @@ module Chingu
|
|
26
26
|
# register_tick() must be called every game loop iteration
|
27
27
|
#
|
28
28
|
class FPSCounter
|
29
|
-
|
29
|
+
attr_reader :milliseconds_since_last_tick
|
30
|
+
alias :dt :milliseconds_since_last_tick
|
31
|
+
|
32
|
+
#
|
33
|
+
# Frames per second, access with $window.fps or $window.framerate
|
34
|
+
#
|
35
|
+
attr_reader :fps
|
36
|
+
alias :framerate :fps
|
37
|
+
|
38
|
+
#
|
39
|
+
# Total amount of game iterations (ticks)
|
40
|
+
#
|
41
|
+
attr_reader :ticks
|
30
42
|
|
31
43
|
def initialize
|
32
44
|
@current_second = Gosu::milliseconds / 1000
|
data/lib/chingu/game_object.rb
CHANGED
@@ -19,6 +19,7 @@
|
|
19
19
|
#
|
20
20
|
#++
|
21
21
|
|
22
|
+
require 'forwardable'
|
22
23
|
|
23
24
|
module Chingu
|
24
25
|
#
|
@@ -26,18 +27,21 @@ module Chingu
|
|
26
27
|
# An instance of GameObjectList is automaticly created as "game_objects" if using Chingu::Window
|
27
28
|
#
|
28
29
|
class GameObjectList
|
30
|
+
extend Forwardable
|
31
|
+
|
29
32
|
attr_reader :visible_game_objects, :unpaused_game_objects
|
30
33
|
|
31
34
|
def initialize(options = {})
|
32
35
|
@game_objects = options[:game_objects] || []
|
33
36
|
@visible_game_objects = []
|
34
37
|
@unpaused_game_objects = []
|
35
|
-
|
36
|
-
#@game_objects = {}
|
37
|
-
#@visible_game_objects = {}
|
38
|
-
#@unpaused_game_objects = {}
|
39
38
|
end
|
40
39
|
|
40
|
+
def_delegator :@game_objects, :size
|
41
|
+
def_delegator :@game_objects, :empty?
|
42
|
+
def_delegator :@game_objects, :first
|
43
|
+
def_delegator :@game_objects, :last
|
44
|
+
|
41
45
|
def to_s
|
42
46
|
"#{@game_objects.size} game objects."
|
43
47
|
end
|
@@ -69,10 +73,6 @@ module Chingu
|
|
69
73
|
@game_objects.push(object)
|
70
74
|
@visible_game_objects.push(object) if object.respond_to?(:visible) && object.visible
|
71
75
|
@unpaused_game_objects.push(object) if object.respond_to?(:paused) && !object.paused
|
72
|
-
|
73
|
-
#@game_objects[object] = true
|
74
|
-
#@visible_game_objects[object] = true if object.respond_to?(:visible) && object.visible
|
75
|
-
#@unpaused_game_objects[object] = true if object.respond_to?(:paused) && !object.paused
|
76
76
|
end
|
77
77
|
|
78
78
|
def remove_game_object(object)
|
@@ -85,14 +85,6 @@ module Chingu
|
|
85
85
|
@game_objects.select { |object| object.destroy if yield(object) }
|
86
86
|
end
|
87
87
|
|
88
|
-
def size
|
89
|
-
@game_objects.size
|
90
|
-
end
|
91
|
-
|
92
|
-
def empty?
|
93
|
-
@game_objects.empty?
|
94
|
-
end
|
95
|
-
|
96
88
|
def update
|
97
89
|
@unpaused_game_objects.each { |go| go.update_trait; go.update; }
|
98
90
|
end
|
@@ -131,14 +123,6 @@ module Chingu
|
|
131
123
|
@game_objects.map { |object| yield object }
|
132
124
|
end
|
133
125
|
|
134
|
-
def first
|
135
|
-
@game_objects.first
|
136
|
-
end
|
137
|
-
|
138
|
-
def last
|
139
|
-
@game_objects.last
|
140
|
-
end
|
141
|
-
|
142
126
|
#
|
143
127
|
# Disable automatic calling of update() and update_trait() each game loop for all game objects
|
144
128
|
#
|
@@ -236,8 +236,15 @@ module Chingu
|
|
236
236
|
# Pops through all game states until matching a given game state
|
237
237
|
#
|
238
238
|
def pop_until_game_state(new_state)
|
239
|
-
|
240
|
-
|
239
|
+
if new_state.is_a? Class
|
240
|
+
raise ArgumentError, "No state of given class is on the stack" unless @game_states.map {|s| s.class }.include? new_state
|
241
|
+
|
242
|
+
@game_states.pop until current_game_state.is_a? new_state
|
243
|
+
|
244
|
+
else
|
245
|
+
raise ArgumentError, "State is not on the stack" unless @game_states.include? new_state
|
246
|
+
|
247
|
+
@game_states.pop while current_game_state != new_state
|
241
248
|
end
|
242
249
|
end
|
243
250
|
|
@@ -71,18 +71,20 @@ module Chingu
|
|
71
71
|
#
|
72
72
|
class NetworkClient < Chingu::GameState
|
73
73
|
attr_reader :latency, :socket, :packet_counter, :packet_buffer, :ip, :port
|
74
|
+
alias_method :address, :ip
|
74
75
|
|
75
76
|
def initialize(options = {})
|
76
77
|
super
|
77
78
|
@timeout = options[:timeout] || 4
|
78
79
|
@debug = options[:debug]
|
79
80
|
@ip = options[:ip] || "0.0.0.0"
|
80
|
-
@port = options[:port] ||
|
81
|
+
@port = options[:port] || NetworkServer::DEFAULT_PORT
|
82
|
+
@max_read_per_update = options[:max_read_per_update] || 50000
|
81
83
|
|
82
84
|
@socket = nil
|
83
85
|
@latency = 0
|
84
86
|
@packet_counter = 0
|
85
|
-
@packet_buffer =
|
87
|
+
@packet_buffer = NetworkServer::PacketBuffer.new
|
86
88
|
end
|
87
89
|
|
88
90
|
#
|
@@ -110,7 +112,6 @@ module Chingu
|
|
110
112
|
begin
|
111
113
|
status = Timeout::timeout(@timeout) do
|
112
114
|
@socket = TCPSocket.new(@ip, @port)
|
113
|
-
@socket.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
|
114
115
|
on_connect
|
115
116
|
end
|
116
117
|
rescue Errno::ECONNREFUSED
|
@@ -154,14 +155,14 @@ module Chingu
|
|
154
155
|
# Call this from your update() to read from socket.
|
155
156
|
# handle_incoming_data will call on_data(raw_data) when stuff comes on on the socket.
|
156
157
|
#
|
157
|
-
def handle_incoming_data(amount =
|
158
|
+
def handle_incoming_data(amount = @max_read_per_update)
|
158
159
|
return unless @socket
|
159
160
|
|
160
161
|
if IO.select([@socket], nil, nil, 0.0)
|
161
162
|
begin
|
162
163
|
packet, sender = @socket.recvfrom(amount)
|
163
164
|
on_data(packet)
|
164
|
-
rescue Errno::ECONNABORTED
|
165
|
+
rescue Errno::ECONNABORTED, Errno::ECONNRESET
|
165
166
|
on_disconnect
|
166
167
|
end
|
167
168
|
end
|
@@ -171,17 +172,10 @@ module Chingu
|
|
171
172
|
# on_data(data) will be called from handle_incoming_data() by default.
|
172
173
|
#
|
173
174
|
def on_data(data)
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
YAML::load_documents(@packet_buffer) { |msg| on_msg(msg) if msg }
|
179
|
-
@packet_buffer = msgs.last
|
180
|
-
else
|
181
|
-
@packet_buffer << msgs.join
|
182
|
-
end
|
183
|
-
rescue ArgumentError
|
184
|
-
puts "Bad YAML recieved:\n#{data}"
|
175
|
+
@packet_buffer.buffer_data data
|
176
|
+
|
177
|
+
while packet = @packet_buffer.next_packet
|
178
|
+
on_msg(Marshal.load(packet))
|
185
179
|
end
|
186
180
|
end
|
187
181
|
|
@@ -190,16 +184,23 @@ module Chingu
|
|
190
184
|
# Can be whatever ruby-structure that responds to #to_yaml
|
191
185
|
#
|
192
186
|
def send_msg(msg)
|
193
|
-
|
194
|
-
data = msg.to_yaml + "--- \n"
|
195
|
-
send_data(data)
|
187
|
+
send_data(Marshal.dump(msg))
|
196
188
|
end
|
197
189
|
|
198
190
|
#
|
199
191
|
# Send whatever raw data to the server
|
200
192
|
#
|
201
193
|
def send_data(data)
|
202
|
-
|
194
|
+
begin
|
195
|
+
@socket.write([data.length].pack(NetworkServer::PACKET_HEADER_FORMAT))
|
196
|
+
@socket.write(data)
|
197
|
+
rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE, Errno::ENOTCONN
|
198
|
+
on_disconnect
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Ensure that the buffer is cleared of data to write (call at the end of update or, at least after all sends).
|
203
|
+
def flush
|
203
204
|
@socket.flush
|
204
205
|
end
|
205
206
|
|
@@ -69,20 +69,62 @@ module Chingu
|
|
69
69
|
# A good idea is to have a socket-ivar in your Player-model and a Player.find_by_socket(socket)
|
70
70
|
#
|
71
71
|
class NetworkServer < Chingu::GameState
|
72
|
-
|
72
|
+
PACKET_HEADER_LENGTH = 4
|
73
|
+
PACKET_HEADER_FORMAT = "N"
|
74
|
+
DEFAULT_PORT = 7778
|
75
|
+
|
76
|
+
class PacketBuffer
|
77
|
+
def initialize
|
78
|
+
@data = '' # Buffered data.
|
79
|
+
@length = nil # Length of the next packet. nil if header not read yet.
|
80
|
+
end
|
81
|
+
|
82
|
+
# Add data string to the buffer.
|
83
|
+
def buffer_data(data)
|
84
|
+
@data << data
|
85
|
+
end
|
86
|
+
|
87
|
+
# Call after adding data with #buffer_data until there are no more packets left.
|
88
|
+
def next_packet
|
89
|
+
# Read the header to find out the length of the next packet.
|
90
|
+
unless @length
|
91
|
+
if @data.length >= PACKET_HEADER_LENGTH
|
92
|
+
@length = @data[0...PACKET_HEADER_LENGTH].unpack(PACKET_HEADER_FORMAT)[0]
|
93
|
+
@data[0...PACKET_HEADER_LENGTH] = ''
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# If there is enough data after the header for the full packet, return it.
|
98
|
+
if @length and @length <= @data.length
|
99
|
+
begin
|
100
|
+
packet = @data[0...@length]
|
101
|
+
@data[0...@length] = ''
|
102
|
+
@length = nil
|
103
|
+
return packet
|
104
|
+
rescue TypeError => ex
|
105
|
+
puts "Bad data received:\n#{@data.inspect}"
|
106
|
+
raise ex
|
107
|
+
end
|
108
|
+
else
|
109
|
+
return nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
attr_reader :socket, :sockets, :ip, :port
|
115
|
+
|
116
|
+
alias_method :address, :ip
|
73
117
|
|
74
118
|
def initialize(options = {})
|
75
119
|
super
|
76
120
|
|
77
121
|
@ip = options[:ip] || "0.0.0.0"
|
78
|
-
@port = options[:port] ||
|
122
|
+
@port = options[:port] || DEFAULT_PORT
|
79
123
|
@debug = options[:debug]
|
80
124
|
@socket = nil
|
81
125
|
@sockets = []
|
82
|
-
@buffered_output = YAML::Stream.new
|
83
126
|
@max_read_per_update = options[:max_read_per_update] || 20000
|
84
|
-
|
85
|
-
@packet_counter = 0
|
127
|
+
|
86
128
|
@packet_buffers = Hash.new
|
87
129
|
end
|
88
130
|
|
@@ -94,7 +136,6 @@ module Chingu
|
|
94
136
|
@port = port if port
|
95
137
|
begin
|
96
138
|
@socket = TCPServer.new(@ip, @port)
|
97
|
-
@socket.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
|
98
139
|
on_start
|
99
140
|
rescue
|
100
141
|
on_start_error($!)
|
@@ -134,11 +175,9 @@ module Chingu
|
|
134
175
|
if @socket && !@socket.closed?
|
135
176
|
handle_incoming_connections
|
136
177
|
handle_incoming_data
|
137
|
-
super
|
138
|
-
handle_outgoing_data
|
139
|
-
else
|
140
|
-
super
|
141
178
|
end
|
179
|
+
|
180
|
+
super
|
142
181
|
end
|
143
182
|
|
144
183
|
#
|
@@ -157,10 +196,11 @@ module Chingu
|
|
157
196
|
|
158
197
|
def handle_incoming_connections
|
159
198
|
begin
|
160
|
-
socket = @socket.accept_nonblock
|
161
|
-
|
162
|
-
|
163
|
-
|
199
|
+
while socket = @socket.accept_nonblock
|
200
|
+
@sockets << socket
|
201
|
+
@packet_buffers[socket] = PacketBuffer.new
|
202
|
+
on_connect(socket)
|
203
|
+
end
|
164
204
|
rescue IO::WaitReadable, Errno::EINTR
|
165
205
|
end
|
166
206
|
end
|
@@ -177,6 +217,7 @@ module Chingu
|
|
177
217
|
on_data(socket, packet)
|
178
218
|
rescue Errno::ECONNABORTED, Errno::ECONNRESET
|
179
219
|
@packet_buffers[socket] = nil
|
220
|
+
|
180
221
|
on_disconnect(socket)
|
181
222
|
end
|
182
223
|
end
|
@@ -187,28 +228,12 @@ module Chingu
|
|
187
228
|
# on_data(data) will be called from handle_incoming_data() by default.
|
188
229
|
#
|
189
230
|
def on_data(socket, data)
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
else
|
197
|
-
@packet_buffers[socket] << msgs.join
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
#
|
203
|
-
# Send all buffered outgoing data
|
204
|
-
#
|
205
|
-
def handle_outgoing_data
|
206
|
-
# the "---" part is a little hack to make server understand the YAML is fully transmitted.
|
207
|
-
|
208
|
-
data = @buffered_output.emit
|
209
|
-
if data.size > 0
|
210
|
-
@sockets.each { |socket| send_data(socket, data + "--- \n") }
|
211
|
-
@buffered_output = YAML::Stream.new
|
231
|
+
buffer = @packet_buffers[socket]
|
232
|
+
|
233
|
+
buffer.buffer_data data
|
234
|
+
|
235
|
+
while packet = buffer.next_packet
|
236
|
+
on_msg(socket, Marshal.load(packet))
|
212
237
|
end
|
213
238
|
end
|
214
239
|
|
@@ -217,7 +242,8 @@ module Chingu
|
|
217
242
|
# Output is buffered and dispatched once each server-loop
|
218
243
|
#
|
219
244
|
def broadcast_msg(msg)
|
220
|
-
|
245
|
+
data = Marshal.dump(msg)
|
246
|
+
@sockets.each {|s| send_data(s, data) }
|
221
247
|
end
|
222
248
|
|
223
249
|
#
|
@@ -225,8 +251,7 @@ module Chingu
|
|
225
251
|
# 'msg' must responds to #to_yaml
|
226
252
|
#
|
227
253
|
def send_msg(socket, msg)
|
228
|
-
|
229
|
-
send_data(socket, msg.to_yaml + "--- \n")
|
254
|
+
send_data(socket, Marshal.dump(msg))
|
230
255
|
end
|
231
256
|
|
232
257
|
#
|
@@ -234,8 +259,8 @@ module Chingu
|
|
234
259
|
#
|
235
260
|
def send_data(socket, data)
|
236
261
|
begin
|
262
|
+
socket.write([data.length].pack(PACKET_HEADER_FORMAT))
|
237
263
|
socket.write(data)
|
238
|
-
socket.flush
|
239
264
|
rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE, Errno::ENOTCONN
|
240
265
|
on_disconnect(socket)
|
241
266
|
end
|
@@ -247,6 +272,11 @@ module Chingu
|
|
247
272
|
def disconnect_client(socket)
|
248
273
|
socket.close
|
249
274
|
end
|
275
|
+
|
276
|
+
# Ensure that the buffer is cleared of data to write (call at the end of update or, at least after all sends).
|
277
|
+
def flush
|
278
|
+
@sockets.each {|s| s.flush }
|
279
|
+
end
|
250
280
|
|
251
281
|
#
|
252
282
|
# Stops server
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Chingu -- OpenGL accelerated 2D game framework for Ruby
|
4
|
+
# Copyright (C) 2009 ippa / ippa@rubylicio.us
|
5
|
+
#
|
6
|
+
# This library is free software; you can redistribute it and/or
|
7
|
+
# modify it under the terms of the GNU Lesser General Public
|
8
|
+
# License as published by the Free Software Foundation; either
|
9
|
+
# version 2.1 of the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This library is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this library; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
+
#
|
20
|
+
#++
|
21
|
+
|
22
|
+
require 'forwardable'
|
23
|
+
|
24
|
+
module Chingu
|
25
|
+
module Helpers
|
26
|
+
|
27
|
+
#
|
28
|
+
# Convenience-methods for classes that have an FPS counter
|
29
|
+
# Mixed into Chingu::Window and Chingu::Console
|
30
|
+
#
|
31
|
+
module FPSCounter
|
32
|
+
extend Forwardable
|
33
|
+
def_delegator :@fps_counter, :ticks
|
34
|
+
def_delegators :@fps_counter, :fps, :framerate # TODO: switch to Gosu::fps
|
35
|
+
def_delegators :@fps_counter, :dt, :milliseconds_since_last_tick
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -1,135 +1,121 @@
|
|
1
|
-
#--
|
2
|
-
#
|
3
|
-
# Chingu -- OpenGL accelerated 2D game framework for Ruby
|
4
|
-
# Copyright (C) 2009 ippa / ippa@rubylicio.us
|
5
|
-
#
|
6
|
-
# This library is free software; you can redistribute it and/or
|
7
|
-
# modify it under the terms of the GNU Lesser General Public
|
8
|
-
# License as published by the Free Software Foundation; either
|
9
|
-
# version 2.1 of the License, or (at your option) any later version.
|
10
|
-
#
|
11
|
-
# This library is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
-
# Lesser General Public License for more details.
|
15
|
-
#
|
16
|
-
# You should have received a copy of the GNU Lesser General Public
|
17
|
-
# License along with this library; if not, write to the Free Software
|
18
|
-
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
-
#
|
20
|
-
#++
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
#
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
def
|
47
|
-
@game_objects.
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
attr_hash[attr] = game_object.send(attr)
|
122
|
-
rescue NoMethodError
|
123
|
-
# silently ignore attributes that doesn't exist on the particular game object
|
124
|
-
end
|
125
|
-
end
|
126
|
-
objects << {game_object.class.to_s => attr_hash}
|
127
|
-
end
|
128
|
-
|
129
|
-
File.open(file, 'w') { |out| YAML.dump(objects, out) }
|
130
|
-
end
|
131
|
-
|
132
|
-
end
|
133
|
-
|
134
|
-
end
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Chingu -- OpenGL accelerated 2D game framework for Ruby
|
4
|
+
# Copyright (C) 2009 ippa / ippa@rubylicio.us
|
5
|
+
#
|
6
|
+
# This library is free software; you can redistribute it and/or
|
7
|
+
# modify it under the terms of the GNU Lesser General Public
|
8
|
+
# License as published by the Free Software Foundation; either
|
9
|
+
# version 2.1 of the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This library is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this library; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
+
#
|
20
|
+
#++
|
21
|
+
|
22
|
+
require 'forwardable'
|
23
|
+
|
24
|
+
module Chingu
|
25
|
+
module Helpers
|
26
|
+
|
27
|
+
#
|
28
|
+
# Convenience-methods for classes that hold game objects
|
29
|
+
# Mixed into Chingu::Window and Chingu::GameState
|
30
|
+
#
|
31
|
+
module GameObject
|
32
|
+
extend Forwardable
|
33
|
+
|
34
|
+
attr_reader :game_objects
|
35
|
+
|
36
|
+
def_delegator :@game_objects, :add_game_object
|
37
|
+
def_delegator :@game_objects, :remove_game_object
|
38
|
+
def_delegator :@game_objects, :show_game_object
|
39
|
+
def_delegator :@game_objects, :hide_game_object
|
40
|
+
def_delegator :@game_objects, :pause_game_object
|
41
|
+
def_delegator :@game_objects, :unpause_game_object
|
42
|
+
|
43
|
+
#
|
44
|
+
# Fetch game objects of a certain type/class
|
45
|
+
#
|
46
|
+
def game_objects_of_class(klass)
|
47
|
+
@game_objects.select { |game_object| game_object.is_a? klass }
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Creates game objects from a Chingu-spezed game objects file (created with game state 'Edit')
|
52
|
+
#
|
53
|
+
def load_game_objects(options = {})
|
54
|
+
file = options[:file] || self.filename + ".yml"
|
55
|
+
debug = options[:debug]
|
56
|
+
except = Array(options[:except]) || []
|
57
|
+
|
58
|
+
require 'yaml'
|
59
|
+
|
60
|
+
puts "* Loading game objects from #{file}" if debug
|
61
|
+
if File.exists?(file)
|
62
|
+
objects = YAML.load_file(file)
|
63
|
+
objects.each do |object|
|
64
|
+
object.each_pair do |klassname, attributes|
|
65
|
+
begin
|
66
|
+
klass = Kernel::const_get(klassname)
|
67
|
+
unless klass.class == "GameObject" && !except.include?(klass)
|
68
|
+
puts "Creating #{klassname.to_s}: #{attributes.to_s}" if debug
|
69
|
+
object = klass.create(attributes)
|
70
|
+
object.options[:created_with_editor] = true if object.options
|
71
|
+
end
|
72
|
+
rescue
|
73
|
+
puts "Couldn't create class '#{klassname}'"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Save given game_objects to a file. Hashoptions
|
82
|
+
#
|
83
|
+
# :file - a String, name of file to write to, default is current game_state class name.
|
84
|
+
# :game_objects - an Array, game objects to save
|
85
|
+
# :classes - an Array, save only game objects of theese classes
|
86
|
+
#
|
87
|
+
# NOTE: To save a color do: :color => game_object.color.argb
|
88
|
+
#
|
89
|
+
def save_game_objects(options = {})
|
90
|
+
#
|
91
|
+
# TODO: Move this to GameObjectList#save ?
|
92
|
+
#
|
93
|
+
file = options[:file] || "#{self.class.to_s.downcase}.yml"
|
94
|
+
game_objects = options[:game_objects]
|
95
|
+
classes = options[:classes]
|
96
|
+
attributes = options[:attributes] || [:x, :y, :angle, :zorder, :factor_x, :factor_y, :alpha]
|
97
|
+
|
98
|
+
require 'yaml'
|
99
|
+
objects = []
|
100
|
+
game_objects.each do |game_object|
|
101
|
+
# Only save specified classes, if given.
|
102
|
+
next if classes and !classes.empty? and !classes.include?(game_object.class)
|
103
|
+
|
104
|
+
attr_hash = {}
|
105
|
+
attributes.each do |attr|
|
106
|
+
begin
|
107
|
+
attr_hash[attr] = game_object.send(attr)
|
108
|
+
rescue NoMethodError
|
109
|
+
# silently ignore attributes that doesn't exist on the particular game object
|
110
|
+
end
|
111
|
+
end
|
112
|
+
objects << {game_object.class.to_s => attr_hash}
|
113
|
+
end
|
114
|
+
|
115
|
+
File.open(file, 'w') { |out| YAML.dump(objects, out) }
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
135
121
|
end
|
@@ -19,6 +19,7 @@
|
|
19
19
|
#
|
20
20
|
#++
|
21
21
|
|
22
|
+
require 'forwardable'
|
22
23
|
|
23
24
|
module Chingu
|
24
25
|
module Helpers
|
@@ -29,33 +30,14 @@ module Chingu
|
|
29
30
|
# It will make call new() on a class, and just push an object.
|
30
31
|
#
|
31
32
|
module GameState
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def pop_game_state(options = {})
|
41
|
-
game_state_manager.pop_game_state(options)
|
42
|
-
end
|
43
|
-
|
44
|
-
def switch_game_state(state, options = {})
|
45
|
-
game_state_manager.switch_game_state(state, options)
|
46
|
-
end
|
47
|
-
|
48
|
-
def transitional_game_state(state, options = {})
|
49
|
-
game_state_manager.transitional_game_state(state, options)
|
50
|
-
end
|
51
|
-
|
52
|
-
def current_game_state
|
53
|
-
game_state_manager.current_game_state
|
54
|
-
end
|
55
|
-
|
56
|
-
def clear_game_states
|
57
|
-
game_state_manager.clear_game_states
|
58
|
-
end
|
33
|
+
extend Forwardable
|
34
|
+
def_delegator :game_state_manager, :game_states
|
35
|
+
def_delegator :game_state_manager, :push_game_state
|
36
|
+
def_delegator :game_state_manager, :pop_game_state
|
37
|
+
def_delegator :game_state_manager, :switch_game_state
|
38
|
+
def_delegator :game_state_manager, :transitional_game_state
|
39
|
+
def_delegator :game_state_manager, :current_game_state
|
40
|
+
def_delegator :game_state_manager, :clear_game_states
|
59
41
|
end
|
60
42
|
|
61
43
|
end
|
data/lib/chingu/helpers/gfx.rb
CHANGED
@@ -27,7 +27,7 @@ module Chingu
|
|
27
27
|
# All drawings depend on the global variable $window which should be an instance of Gosu::Window or Chingu::Window
|
28
28
|
#
|
29
29
|
module GFX
|
30
|
-
|
30
|
+
|
31
31
|
#
|
32
32
|
# Fills whole window with specified 'color' and 'zorder'
|
33
33
|
#
|
@@ -48,52 +48,33 @@ module Chingu
|
|
48
48
|
# :orientation - Either :vertical (top to bottom) or :horizontal (left to right)
|
49
49
|
#
|
50
50
|
|
51
|
-
def fill(
|
51
|
+
def fill(material, zorder = 0, mode = :default)
|
52
52
|
#
|
53
53
|
# if only 1 color-argument is given, assume fullscreen simple color fill.
|
54
54
|
#
|
55
|
-
if
|
56
|
-
|
57
|
-
|
58
|
-
$window.width, $window.height, options,
|
59
|
-
0, $window.height, options, zorder, :default)
|
55
|
+
if material.is_a?(Gosu::Color)
|
56
|
+
rect = Rect.new([0, 0, $window.width, $window.height])
|
57
|
+
_fill_rect(rect, material, material, material, material, zorder, mode)
|
60
58
|
else
|
61
|
-
fill_gradient(
|
59
|
+
fill_gradient(material)
|
62
60
|
end
|
63
61
|
end
|
64
62
|
|
65
63
|
#
|
66
64
|
# Draws an unfilled rect in given color
|
67
65
|
#
|
68
|
-
def draw_rect(rect, color, zorder)
|
69
|
-
|
70
|
-
|
71
|
-
$window.draw_line(rect.right, rect.bottom, color, rect.x, rect.bottom, color, zorder)
|
72
|
-
$window.draw_line(rect.x, rect.bottom, color, rect.x, rect.y, color, zorder)
|
66
|
+
def draw_rect(rect, color, zorder = 0, mode = :default)
|
67
|
+
rect = Rect.new(rect) unless rect.is_a? Rect
|
68
|
+
_stroke_rect(rect, color, color, color, color, zorder, mode)
|
73
69
|
end
|
74
70
|
|
75
71
|
|
76
|
-
#
|
77
|
-
# Draws an unfilled circle, thanks shawn24!
|
78
|
-
#
|
79
|
-
CIRCLE_STEP = 10
|
80
|
-
def draw_circle(cx,cy,r,color)
|
81
|
-
0.step(360, CIRCLE_STEP) do |a1|
|
82
|
-
a2 = a1 + CIRCLE_STEP
|
83
|
-
$window.draw_line cx + Gosu.offset_x(a1, r), cy + Gosu.offset_y(a1, r), color, cx + Gosu.offset_x(a2, r), cy + Gosu.offset_y(a2, r), color, 9999
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
72
|
#
|
88
73
|
# Fills a given Rect 'rect' with Color 'color', drawing with zorder 'zorder'
|
89
74
|
#
|
90
|
-
def fill_rect(rect, color, zorder = 0)
|
91
|
-
rect = Rect.new(rect)
|
92
|
-
|
93
|
-
rect.right, rect.y, color,
|
94
|
-
rect.right, rect.bottom, color,
|
95
|
-
rect.x, rect.bottom, color,
|
96
|
-
zorder, :default)
|
75
|
+
def fill_rect(rect, color, zorder = 0, mode = :default)
|
76
|
+
rect = Rect.new(rect) unless rect.is_a? Rect
|
77
|
+
_fill_rect(rect, color, color, color, color, zorder, mode)
|
97
78
|
end
|
98
79
|
|
99
80
|
#
|
@@ -105,46 +86,147 @@ module Chingu
|
|
105
86
|
# :orientation - Either :vertical (top to bottom) or :horizontal (left to right)
|
106
87
|
#
|
107
88
|
def fill_gradient(options)
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
}
|
116
|
-
options = default_options.merge(options)
|
89
|
+
options = { :from => Gosu::Color::BLACK,
|
90
|
+
:to => Gosu::Color::WHITE,
|
91
|
+
:orientation => :vertical,
|
92
|
+
:rect => [0, 0, $window.width, $window.height],
|
93
|
+
:zorder => 0,
|
94
|
+
:mode => :default
|
95
|
+
}.merge!(options)
|
117
96
|
|
118
97
|
rect = Rect.new(options[:rect])
|
119
98
|
colors = options[:colors] || options.values_at(:from, :to)
|
99
|
+
zorder = options[:zorder]
|
100
|
+
mode = options[:mode]
|
120
101
|
|
121
102
|
case options[:orientation]
|
122
103
|
when :vertical
|
123
104
|
rect.height /= colors.count - 1
|
124
105
|
colors.each_cons(2) do |from, to|
|
125
|
-
|
126
|
-
rect.right, rect.top, from,
|
127
|
-
rect.right, rect.bottom, to,
|
128
|
-
rect.left, rect.bottom, to,
|
129
|
-
options[:zorder], options[:mode]
|
130
|
-
)
|
106
|
+
_fill_rect(rect, from, to, to, from, zorder, mode)
|
131
107
|
rect.top += rect.height
|
132
108
|
end
|
133
109
|
when :horizontal
|
134
110
|
rect.width /= colors.count - 1
|
135
111
|
colors.each_cons(2) do |from, to|
|
136
|
-
|
137
|
-
rect.left, rect.bottom, from,
|
138
|
-
rect.right, rect.bottom, to,
|
139
|
-
rect.right, rect.top, to,
|
140
|
-
options[:zorder], options[:mode]
|
141
|
-
)
|
112
|
+
_fill_rect(rect, from, from, to, to, zorder, mode)
|
142
113
|
rect.left += rect.width
|
143
114
|
end
|
144
115
|
else
|
145
116
|
raise ArgumentError, "bad gradient orientation: #{options[:orientation]}"
|
146
117
|
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Draws an unfilled circle, thanks shawn24!
|
123
|
+
#
|
124
|
+
def draw_circle(cx, cy, r, color, zorder = 0, mode = :default)
|
125
|
+
draw_arc(cx, cy, r, 0, 360, color, zorder, mode)
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Draws an unfilled arc from a1 to a2
|
130
|
+
#
|
131
|
+
def draw_arc(cx, cy, r, from, to, color, zorder = 0, mode = :default)
|
132
|
+
from, to = to, from if from > to
|
133
|
+
$window.translate(cx, cy) do
|
134
|
+
$window.scale(r) do
|
135
|
+
detail = _circle_segments(r)
|
136
|
+
_walk_arc(from, to, detail) do |x1, y1, x2, y2|
|
137
|
+
$window.draw_line(x1, y1, color,
|
138
|
+
x2, y2, color,
|
139
|
+
zorder, mode)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
# Draws a filled circle
|
147
|
+
#
|
148
|
+
def fill_circle(cx, cy, r, color, zorder = 0, mode = :default)
|
149
|
+
fill_arc(cx, cy, r, 0, 360, color, zorder, mode)
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Draws a filled arc from a1 to a2
|
154
|
+
#
|
155
|
+
def fill_arc(cx, cy, r, from, to, color, zorder = 0, mode = :default)
|
156
|
+
from, to = to, from if from > to
|
157
|
+
$window.translate(cx, cy) do
|
158
|
+
$window.scale(r) do
|
159
|
+
detail = _circle_segments(r)
|
160
|
+
_walk_arc(from, to, detail) do |x1, y1, x2, y2|
|
161
|
+
$window.draw_triangle(0, 0, color,
|
162
|
+
x1, y1, color,
|
163
|
+
x2, y2, color,
|
164
|
+
zorder, mode)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
147
168
|
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def _fill_rect(rect, color_a, color_b, color_c, color_d, zorder, mode)
|
173
|
+
left, top = *rect.topleft
|
174
|
+
right, bottom = *rect.bottomright
|
175
|
+
$window.draw_quad(left, top, color_a,
|
176
|
+
left, bottom, color_b,
|
177
|
+
right, bottom, color_c,
|
178
|
+
right, top, color_d,
|
179
|
+
zorder, mode)
|
180
|
+
end
|
181
|
+
|
182
|
+
def _stroke_rect(rect, color_a, color_b, color_c, color_d, zorder, mode)
|
183
|
+
left, top = *rect.topleft
|
184
|
+
right, bottom = *rect.bottomright
|
185
|
+
$window.draw_line(left, top, color_a, left, bottom, color_b, zorder, mode)
|
186
|
+
$window.draw_line(left, bottom, color_b, right, bottom, color_c, zorder, mode)
|
187
|
+
$window.draw_line(right, bottom, color_c, right, top, color_d, zorder, mode)
|
188
|
+
$window.draw_line(right, top, color_d, left, top, color_a, zorder, mode)
|
189
|
+
end
|
190
|
+
|
191
|
+
#
|
192
|
+
# Calculates a reasonable number of segments for a circle of the given
|
193
|
+
# radius. Forgive the use of a magic number.
|
194
|
+
#
|
195
|
+
# Adapted from SiegeLord's "An Efficient Way to Draw Approximate Circles
|
196
|
+
# in OpenGL" <http://slabode.exofire.net/circle_draw.shtml>.
|
197
|
+
#
|
198
|
+
def _circle_segments(r)
|
199
|
+
10 * Math.sqrt(r)
|
200
|
+
end
|
201
|
+
|
202
|
+
#
|
203
|
+
# Appriximates an arc as a series of line segments and passes each segment
|
204
|
+
# to the block. Makes clever use of a transformation matrix to avoid
|
205
|
+
# repeated calls to sin and cos.
|
206
|
+
#
|
207
|
+
# Adapted from SiegeLord's "An Efficient Way to Draw Approximate Circles
|
208
|
+
# in OpenGL" <http://slabode.exofire.net/circle_draw.shtml>.
|
209
|
+
#
|
210
|
+
def _walk_arc(from, to, detail, &block)
|
211
|
+
walk_segments = ((to - from).to_f * (detail - 1) / 360).floor
|
212
|
+
|
213
|
+
theta = 2 * Math::PI / detail
|
214
|
+
c = Math.cos(theta)
|
215
|
+
s = Math.sin(theta)
|
216
|
+
|
217
|
+
x1 = Gosu.offset_x(from, 1)
|
218
|
+
y1 = Gosu.offset_y(from, 1)
|
219
|
+
|
220
|
+
0.upto(walk_segments) do
|
221
|
+
x2 = c * x1 - s * y1
|
222
|
+
y2 = s * x1 + c * y1
|
223
|
+
|
224
|
+
block[x1, y1, x2, y2]
|
225
|
+
|
226
|
+
x1, y1 = x2, y2
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
148
230
|
end
|
149
231
|
|
150
232
|
end
|
data/lib/chingu/window.rb
CHANGED
@@ -32,6 +32,7 @@ module Chingu
|
|
32
32
|
# - Tracking of button_up/button_down etc to enable Chingus pretty inputhandling
|
33
33
|
#
|
34
34
|
class Window < Gosu::Window
|
35
|
+
include Chingu::Helpers::FPSCounter # Adds FPSCounter delegators
|
35
36
|
include Chingu::Helpers::GFX # Adds fill(), fade() etc to each game state
|
36
37
|
include Chingu::Helpers::GameState # Easy access to the global game state-queue
|
37
38
|
include Chingu::Helpers::GameObject # Adds game_objects_of_class etc ...
|
@@ -96,28 +97,6 @@ module Chingu
|
|
96
97
|
game_state_manager.inside_state || game_state_manager.current_game_state || self
|
97
98
|
end
|
98
99
|
|
99
|
-
#
|
100
|
-
# Frames per second, access with $window.fps or $window.framerate
|
101
|
-
#
|
102
|
-
def fps
|
103
|
-
@fps_counter.fps # TODO: switch to Gosu::fps
|
104
|
-
end
|
105
|
-
alias :framerate :fps
|
106
|
-
|
107
|
-
#
|
108
|
-
# Total amount of game iterations (ticks)
|
109
|
-
#
|
110
|
-
def ticks
|
111
|
-
@fps_counter.ticks
|
112
|
-
end
|
113
|
-
|
114
|
-
#
|
115
|
-
# Mathematical short name for "milliseconds since last tick"
|
116
|
-
#
|
117
|
-
def dt
|
118
|
-
@milliseconds_since_last_tick
|
119
|
-
end
|
120
|
-
|
121
100
|
#
|
122
101
|
# Chingus core-logic / loop. Gosu will call this each game-iteration.
|
123
102
|
#
|
@@ -216,4 +195,4 @@ module Chingu
|
|
216
195
|
$window = nil
|
217
196
|
end
|
218
197
|
end
|
219
|
-
end
|
198
|
+
end
|
data/spec/chingu/network_spec.rb
CHANGED
@@ -6,7 +6,8 @@ def data_set
|
|
6
6
|
"a String" => ["Woof!"],
|
7
7
|
"an Array" => [[1, 2, 3]],
|
8
8
|
"a stream of packets" => [{ :foo => :bar }, "Woof!", [1, 2, 3]],
|
9
|
-
"huge packet" => [[:frogspawn] * 1000]
|
9
|
+
"huge packet" => [[:frogspawn] * 1000],
|
10
|
+
"100 small packets" => 100.times.map { rand(100000) },
|
10
11
|
}
|
11
12
|
end
|
12
13
|
|
@@ -94,15 +95,13 @@ module Chingu
|
|
94
95
|
it "should send/recv #{name}" do
|
95
96
|
@server.update # Accept the clients, so know about their existence to broadcast.
|
96
97
|
|
97
|
-
# Data should be cached.
|
98
|
-
data.each {|packet| @server.broadcast_msg(packet) }
|
99
|
-
|
100
98
|
data.each do |packet|
|
101
99
|
@client.should_receive(:on_msg).with(packet)
|
102
100
|
@client2.should_receive(:on_msg).with(packet)
|
103
101
|
end
|
104
102
|
|
105
|
-
@server.
|
103
|
+
data.each {|packet| @server.broadcast_msg(packet) }
|
104
|
+
|
106
105
|
@client.update
|
107
106
|
@client2.update
|
108
107
|
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.9rc4
|
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-03-07 00:00:00.000000000 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: gosu
|
17
|
-
requirement: &
|
17
|
+
requirement: &25121820 !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: *25121820
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rspec
|
28
|
-
requirement: &
|
28
|
+
requirement: &25121472 !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: *25121472
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: watchr
|
39
|
-
requirement: &
|
39
|
+
requirement: &25120920 !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: *25120920
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: rcov
|
50
|
-
requirement: &
|
50
|
+
requirement: &25120464 !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: *25120464
|
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
|
@@ -201,6 +201,7 @@ files:
|
|
201
201
|
- lib/chingu/game_states/popup.rb
|
202
202
|
- lib/chingu/gosu_ext/image.rb
|
203
203
|
- lib/chingu/helpers/class_inheritable_accessor.rb
|
204
|
+
- lib/chingu/helpers/fps_counter.rb
|
204
205
|
- lib/chingu/helpers/game_object.rb
|
205
206
|
- lib/chingu/helpers/game_state.rb
|
206
207
|
- lib/chingu/helpers/gfx.rb
|