ippa-chingu 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -1
- data/README.rdoc +120 -30
- data/chingu.gemspec +5 -5
- data/examples/example1.rb +7 -1
- data/examples/example2.rb +17 -8
- data/examples/example3.rb +1 -1
- data/examples/example4.rb +74 -26
- data/lib/chingu/assets.rb +8 -0
- data/lib/chingu/fpscounter.rb +21 -1
- data/lib/chingu/game_object.rb +53 -17
- data/lib/chingu/game_state.rb +90 -14
- data/lib/chingu/game_state_manager.rb +75 -19
- data/lib/chingu/helpers.rb +127 -19
- data/lib/chingu/input.rb +4 -4
- data/lib/chingu/parallax.rb +4 -1
- data/lib/chingu/text.rb +16 -6
- data/lib/chingu/window.rb +104 -104
- metadata +3 -3
data/lib/chingu/helpers.rb
CHANGED
@@ -1,41 +1,149 @@
|
|
1
1
|
module Chingu
|
2
|
-
|
2
|
+
|
3
|
+
module InputClient
|
4
|
+
def input=(input_map)
|
5
|
+
@input = input_map
|
6
|
+
@parent.add_input_client(self) if @parent
|
7
|
+
end
|
8
|
+
|
9
|
+
def input
|
10
|
+
@input
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module InputDispatcher
|
15
|
+
def add_input_client(object)
|
16
|
+
@input_clients << object
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove_input_client(object)
|
20
|
+
@input_clients.delete(object)
|
21
|
+
end
|
22
|
+
|
23
|
+
def dispatch_button_down(id, object)
|
24
|
+
return if object.nil? || object.input.nil?
|
25
|
+
|
26
|
+
object.input.each do |symbol, action|
|
27
|
+
if Input::SYMBOL_TO_CONSTANT[symbol] == id
|
28
|
+
dispatch_action(action, object)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def dispatch_button_up(id, object)
|
34
|
+
return if object.nil? || object.input.nil?
|
35
|
+
|
36
|
+
object.input.each do |symbol, action|
|
37
|
+
if symbol.to_s.include? "released_"
|
38
|
+
symbol = symbol.to_s.sub("released_", "").to_sym
|
39
|
+
if Input::SYMBOL_TO_CONSTANT[symbol] == id
|
40
|
+
dispatch_action(action, object)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Dispatches input-mapper for any given object
|
48
|
+
#
|
49
|
+
def dispatch_input_for(object, prefix = "holding_")
|
50
|
+
return if object.nil? || object.input.nil?
|
51
|
+
|
52
|
+
object.input.each do |symbol, action|
|
53
|
+
if symbol.to_s.include? prefix
|
54
|
+
symbol = symbol.to_s.sub(prefix, "").to_sym
|
55
|
+
if $window.button_down?(Input::SYMBOL_TO_CONSTANT[symbol])
|
56
|
+
dispatch_action(action, object)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
3
61
|
|
4
62
|
#
|
5
|
-
#
|
63
|
+
# For a given object, dispatch "action".
|
64
|
+
# An action can be:
|
6
65
|
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
66
|
+
# * Symbol (:p, :space), translates into a method-call
|
67
|
+
# * Proc/Lambda, call() it
|
68
|
+
# * GameState-instance, push it on top of stack
|
69
|
+
# * GameState-inherited class, create a new instance, cache it and push it on top of stack
|
11
70
|
#
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
71
|
+
def dispatch_action(action, object)
|
72
|
+
# puts "Dispatch Action: #{action} - Objects class: #{object.class.to_s}"
|
73
|
+
if action.is_a? Symbol
|
74
|
+
object.send(action)
|
75
|
+
elsif action.is_a? Proc
|
76
|
+
action.call
|
77
|
+
elsif action.is_a? Chingu::GameState
|
78
|
+
push_game_state(action)
|
79
|
+
elsif action.superclass == Chingu::GameState
|
80
|
+
push_game_state(action)
|
17
81
|
end
|
18
82
|
end
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# push_game_state accepts either a class inherited from GameState or an object-instance from such a class.
|
87
|
+
#
|
88
|
+
# push_game_state(Intro):
|
89
|
+
# game state mananger will create a new Intro-object first time called and cache it.
|
90
|
+
#
|
91
|
+
# push_game_state(Intro.new):
|
92
|
+
# The first line ends up calling "new" to Intro before activating the newly created game state.
|
93
|
+
# Each time 'push_game_state(Intro.new)' is called a new Intro-object will be created.
|
94
|
+
# Usefull for stuff like: push_game_state(Level.new(:level_nr => 11))
|
95
|
+
#
|
96
|
+
module GameStateHelpers
|
97
|
+
def push_game_state(state, options = {})
|
98
|
+
$window.game_state_manager.push_state(state, options)
|
99
|
+
end
|
19
100
|
|
20
|
-
def
|
21
|
-
$window.game_state_manager.pop_state
|
101
|
+
def pop_game_state(options = {})
|
102
|
+
$window.game_state_manager.pop_state(options)
|
22
103
|
end
|
23
104
|
|
24
|
-
def
|
25
|
-
$window.game_state_manager.
|
105
|
+
def current_game_state
|
106
|
+
$window.game_state_manager.current_state
|
26
107
|
end
|
27
108
|
|
28
|
-
def
|
109
|
+
def previous_game_state
|
29
110
|
$window.game_state_manager.previous_state
|
30
111
|
end
|
112
|
+
|
113
|
+
def clear_game_states
|
114
|
+
$window.game_state_manager.clear_states
|
115
|
+
end
|
31
116
|
end
|
32
117
|
|
118
|
+
#
|
119
|
+
# Various helper-methods to manipulate the screen
|
120
|
+
#
|
33
121
|
module DrawHelpers
|
34
|
-
|
35
|
-
|
36
|
-
|
122
|
+
#
|
123
|
+
# Fills whole window with color 'c'
|
124
|
+
#
|
125
|
+
def fill(c)
|
126
|
+
$window.draw_quad(0,0,c,$window.width,0,c,$window.width,$window.width,c,0,$window.height,c,0,:default)
|
127
|
+
end
|
128
|
+
|
129
|
+
#
|
130
|
+
# Fills a given Rect 'r' with color 'c'
|
131
|
+
#
|
132
|
+
def fill_rect(r, c)
|
133
|
+
$window.draw_quad(r.x,r.y,c, r.right,r.y,c, r.right,r.bottom,c, r.x,r.bottom,c,0,:default)
|
134
|
+
end
|
37
135
|
|
38
136
|
def fade(options = {})
|
39
137
|
end
|
40
138
|
end
|
139
|
+
|
140
|
+
module GameObjectHelpers
|
141
|
+
#
|
142
|
+
# Fetch game objects of a certain type/class
|
143
|
+
#
|
144
|
+
def game_objects_of_class(klass)
|
145
|
+
@game_objects.select { |game_object| game_object.is_a? klass }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
41
149
|
end
|
data/lib/chingu/input.rb
CHANGED
@@ -19,14 +19,14 @@ module Chingu
|
|
19
19
|
|
20
20
|
KbBackspace => [:backspace],
|
21
21
|
KbDelete => [:delete, :del],
|
22
|
-
KbDown => [:down],
|
22
|
+
KbDown => [:down_arrow, :down],
|
23
23
|
KbEnd => [:end],
|
24
24
|
KbEnter => [:enter],
|
25
25
|
KbEscape => [:escape, :esc],
|
26
26
|
|
27
27
|
KbHome => [:home],
|
28
28
|
KbInsert => [:insert, :ins],
|
29
|
-
KbLeft => [:left],
|
29
|
+
KbLeft => [:left_arrow, :left],
|
30
30
|
KbLeftAlt => [:left_alt, :lalt],
|
31
31
|
KbLeftControl => [:left_control, :left_ctrl, :lctrl],
|
32
32
|
KbLeftShift => [:left_shift, :lshift],
|
@@ -40,13 +40,13 @@ module Chingu
|
|
40
40
|
KbPageUp => [:page_up],
|
41
41
|
# KbPause => [:pause],
|
42
42
|
KbReturn => [:return],
|
43
|
-
KbRight => [:right],
|
43
|
+
KbRight => [:right_arrow, :right],
|
44
44
|
KbRightAlt => [:right_alt, :ralt],
|
45
45
|
KbRightControl => [:right_control, :right_ctrl, :rctrl],
|
46
46
|
KbRightShift => [:right_shift, :rshift],
|
47
47
|
KbSpace => [:" ", :space],
|
48
48
|
KbTab => [:tabulator, :tab],
|
49
|
-
KbUp => [:up],
|
49
|
+
KbUp => [:up_arrow, :up],
|
50
50
|
|
51
51
|
MsLeft => [:left_mouse_button, :mouse_left],
|
52
52
|
MsMiddle => [:middle_mouse_button, :mouse_middle],
|
data/lib/chingu/parallax.rb
CHANGED
data/lib/chingu/text.rb
CHANGED
@@ -13,7 +13,17 @@ module Chingu
|
|
13
13
|
#
|
14
14
|
class Text < Chingu::GameObject
|
15
15
|
attr_accessor :text
|
16
|
-
attr_reader :height, :
|
16
|
+
attr_reader :height, :gosu_font
|
17
|
+
|
18
|
+
@@size = nil
|
19
|
+
@@font = nil
|
20
|
+
def self.font; @@font; end
|
21
|
+
def self.font=(value); @@font = value; end
|
22
|
+
|
23
|
+
def self.size; @@size; end
|
24
|
+
def self.size=(value); @@size = value; end
|
25
|
+
def self.height; @@size; end
|
26
|
+
def self.height=(value); @@size = value; end
|
17
27
|
|
18
28
|
#
|
19
29
|
# Takes the standard GameObject-hash-arguments but also:
|
@@ -24,21 +34,21 @@ module Chingu
|
|
24
34
|
def initialize(options)
|
25
35
|
super(options)
|
26
36
|
@text = options[:text] || "-No text specified-"
|
27
|
-
@
|
28
|
-
@height = options[:height] || options[:size] ||
|
37
|
+
@font = options[:font] || @@font || "verdana"
|
38
|
+
@height = options[:height] || options[:size] || @@size || default_font_name()
|
29
39
|
|
30
|
-
@
|
40
|
+
@gosu_font = Gosu::Font.new($window, @font, @height)
|
31
41
|
end
|
32
42
|
|
33
43
|
def draw
|
34
|
-
@
|
44
|
+
@gosu_font.draw_rot(@text, @x.to_i, @y.to_i, @zorder, @angle, @factor_x, @factor_y, @color, @mode)
|
35
45
|
end
|
36
46
|
|
37
47
|
#
|
38
48
|
# Returns the width, in pixels, the given text would occupy if drawn.
|
39
49
|
#
|
40
50
|
def width
|
41
|
-
@
|
51
|
+
@gosu_font.text_width(@text, @factor_x)
|
42
52
|
end
|
43
53
|
|
44
54
|
end
|
data/lib/chingu/window.rb
CHANGED
@@ -1,11 +1,22 @@
|
|
1
1
|
module Chingu
|
2
2
|
class Window < Gosu::Window
|
3
|
-
|
4
|
-
include Chingu::
|
3
|
+
# adds push_game_state, pop_game_state, current_game_state and previous_game_state
|
4
|
+
include Chingu::GameStateHelpers
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
# adds fill() etc...
|
7
|
+
include Chingu::DrawHelpers
|
8
|
+
|
9
|
+
# adds game_objects_of_class etc ...
|
10
|
+
include Chingu::GameObjectHelpers
|
11
|
+
|
12
|
+
# Input dispatch helpers
|
13
|
+
include Chingu::InputDispatcher
|
14
|
+
|
15
|
+
# input= and input
|
16
|
+
include Chingu::InputClient
|
17
|
+
|
18
|
+
attr_reader :root, :game_state_manager, :game_objects, :milliseconds_since_last_tick
|
19
|
+
|
9
20
|
|
10
21
|
#
|
11
22
|
# See http://www.libgosu.org/rdoc/classes/Gosu/Window.html
|
@@ -26,136 +37,125 @@ module Chingu
|
|
26
37
|
Gosu::Image.autoload_dirs = [".", File.join(@root, "gfx"), File.join(@root, "media")]
|
27
38
|
Gosu::Sample.autoload_dirs = [".", File.join(@root, "sound"), File.join(@root, "media")]
|
28
39
|
Gosu::Tile.autoload_dirs = [".", File.join(@root, "gfx"), File.join(@root, "media")]
|
40
|
+
Gosu::Song.autoload_dirs = [".", File.join(@root, "sfx"), File.join(@root, "media")]
|
29
41
|
|
30
|
-
@game_objects =
|
31
|
-
@
|
32
|
-
|
33
|
-
@ticks = 0
|
34
|
-
@last_tick = Gosu::milliseconds
|
42
|
+
@game_objects = Set.new
|
43
|
+
@input_clients = Set.new # Set is like a unique Array with Hash lookupspeed
|
35
44
|
|
36
45
|
@fps_counter = FPSCounter.new
|
37
46
|
@game_state_manager = GameStateManager.new
|
38
47
|
|
39
|
-
@update_list = []
|
40
|
-
@draw_list = []
|
41
|
-
|
42
48
|
self.input = { :escape => close }
|
43
49
|
end
|
44
50
|
|
45
|
-
def add_game_object(
|
46
|
-
@game_objects
|
51
|
+
def add_game_object(object)
|
52
|
+
@game_objects << object
|
47
53
|
end
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
def remove_game_object(object)
|
55
|
+
@input_clients.delete(object)
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Frames per second
|
60
|
+
#
|
55
61
|
def fps
|
56
62
|
@fps_counter.fps
|
57
63
|
end
|
58
|
-
|
59
|
-
#
|
60
|
-
# By default button_up sends the keyevent to the GameStateManager
|
61
|
-
# .. Which then is responsible to send it to the right GameState(s)
|
62
|
-
#
|
63
|
-
def button_up(id)
|
64
|
-
@game_state_manager.button_up(id)
|
65
|
-
end
|
66
|
-
|
64
|
+
alias :framerate :fps
|
67
65
|
|
68
66
|
#
|
69
|
-
#
|
70
|
-
# .. Which then is responsible to send it to the right GameState(s)
|
67
|
+
# Total amount of game iterations (ticks)
|
71
68
|
#
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
def ticks
|
70
|
+
@fps_counter.ticks
|
71
|
+
end
|
75
72
|
|
76
|
-
|
77
73
|
#
|
78
|
-
#
|
74
|
+
# Chingus core-logic / loop. Gosu will call this each game-iteration.
|
79
75
|
#
|
80
76
|
def update
|
81
|
-
@fps_counter.register_tick
|
82
|
-
update_tick
|
83
|
-
|
84
77
|
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
# - ... and all GameObjects connected to it
|
78
|
+
# Register a tick with our rather standard tick/framerate counter.
|
79
|
+
# Returns the amount of milliseconds since last tick. This number is used in all update()-calls.
|
80
|
+
# Without this self.fps would return an incorrect value.
|
81
|
+
# If you override this in your Chingu::Window class, make sure to call super.
|
90
82
|
#
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
@
|
102
|
-
|
83
|
+
@milliseconds_since_last_tick = @fps_counter.register_tick
|
84
|
+
|
85
|
+
#
|
86
|
+
# Dispatch inputmap for main window
|
87
|
+
#
|
88
|
+
dispatch_input_for(self)
|
89
|
+
|
90
|
+
#
|
91
|
+
# Dispatch input for all input-clients handled by to main window (game objects with input created in main win)
|
92
|
+
#
|
93
|
+
@input_clients.each { |game_object| dispatch_input_for(game_object) }
|
94
|
+
|
95
|
+
|
96
|
+
#
|
97
|
+
# Call update(milliseconds_since_last_tick) on all game objects belonging to the main window.
|
98
|
+
#
|
99
|
+
update_game_objects
|
100
|
+
|
101
|
+
#
|
102
|
+
# Call update(milliseconds_since_last_tick) on all game objects belonging to the current game state.
|
103
|
+
#
|
104
|
+
update_game_state_manager
|
103
105
|
end
|
104
106
|
|
107
|
+
#
|
108
|
+
# Chingus main screen manupulation method.
|
109
|
+
# If you override this in your Chingu::Window class, make sure to call super.
|
110
|
+
# Gosu will call this each game-iteration just after #update
|
111
|
+
#
|
105
112
|
def draw
|
113
|
+
#
|
114
|
+
# Draw all game objects associated with the main window.
|
115
|
+
#
|
106
116
|
@game_objects.each { |object| object.draw }
|
117
|
+
|
118
|
+
#
|
119
|
+
# Let the game state manager call draw on the active game state (if any)
|
120
|
+
#
|
107
121
|
@game_state_manager.draw
|
108
122
|
end
|
109
|
-
|
110
|
-
private
|
111
123
|
|
112
124
|
#
|
113
|
-
#
|
125
|
+
# Call update() on all game objects in main game window.
|
114
126
|
#
|
115
|
-
def
|
116
|
-
|
117
|
-
|
118
|
-
object.input.each do |symbol, action|
|
119
|
-
if button_down?(Input::SYMBOL_TO_CONSTANT[symbol])
|
120
|
-
#puts "#{object.to_s} :#{symbol.to_s} => #{action.to_s}"
|
121
|
-
#puts "[#{action.class.to_s} - #{action.class.superclass.to_s}]"
|
122
|
-
if action.is_a? Symbol
|
123
|
-
object.send(action)
|
124
|
-
elsif action.is_a? Proc
|
125
|
-
action.call
|
126
|
-
elsif action.is_a? Chingu::GameState
|
127
|
-
push_gamestate(action)
|
128
|
-
elsif action.superclass == Chingu::GameState
|
129
|
-
push_gamestate(action)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
127
|
+
def update_game_objects
|
128
|
+
@game_objects.each { |object| object.update(@milliseconds_since_last_tick) }
|
133
129
|
end
|
134
130
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
131
|
+
#
|
132
|
+
# Call update() on our game_state_manger
|
133
|
+
# -> call update on active state
|
134
|
+
# -> call update on all game objects in that state
|
135
|
+
#
|
136
|
+
def update_game_state_manager
|
137
|
+
@game_state_manager.update(@milliseconds_since_last_tick)
|
138
|
+
end
|
139
139
|
|
140
140
|
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
#
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
#
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
141
|
+
#
|
142
|
+
# By default button_up sends the keyevent to the GameStateManager
|
143
|
+
# .. Which then is responsible to send it to the right GameState(s)
|
144
|
+
#
|
145
|
+
def button_up(id)
|
146
|
+
dispatch_button_up(id, self)
|
147
|
+
@input_clients.each { |object| dispatch_button_up(id, object) }
|
148
|
+
@game_state_manager.button_up(id)
|
149
|
+
end
|
150
|
+
|
151
|
+
#
|
152
|
+
# By default button_down sends the keyevent to the GameStateManager
|
153
|
+
# .. Which then is responsible to send it to the right GameState(s)
|
154
|
+
#
|
155
|
+
def button_down(id)
|
156
|
+
dispatch_button_down(id, self)
|
157
|
+
@input_clients.each { |object| dispatch_button_down(id, object) }
|
158
|
+
@game_state_manager.button_down(id)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|