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/assets.rb
CHANGED
@@ -30,7 +30,15 @@ module Gosu
|
|
30
30
|
(path = find_file(name)) ? Gosu::Image.new($window, path, true) : nil
|
31
31
|
end
|
32
32
|
end
|
33
|
+
|
34
|
+
class Song
|
35
|
+
include Chingu::NamedResource
|
33
36
|
|
37
|
+
def self.autoload(name)
|
38
|
+
(path = find_file(name)) ? Gosu::Song.new($window, path) : nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
34
42
|
class Sample
|
35
43
|
include Chingu::NamedResource
|
36
44
|
|
data/lib/chingu/fpscounter.rb
CHANGED
@@ -1,21 +1,41 @@
|
|
1
1
|
module Chingu
|
2
|
+
#
|
3
|
+
# Calculates a fps and a tick-time for use in update-calls
|
4
|
+
# register_tick() must be called every game loop iteration
|
5
|
+
#
|
2
6
|
class FPSCounter
|
3
|
-
attr_reader :fps
|
7
|
+
attr_reader :fps, :milliseconds_since_last_tick, :ticks
|
4
8
|
|
5
9
|
def initialize
|
6
10
|
@current_second = Gosu::milliseconds / 1000
|
7
11
|
@accum_fps = 0
|
8
12
|
@fps = 0
|
13
|
+
@ticks = 0
|
14
|
+
|
15
|
+
@milliseconds_since_last_tick = 0
|
16
|
+
@last_value = Gosu::milliseconds
|
9
17
|
end
|
10
18
|
|
19
|
+
#
|
20
|
+
# This should be called once every game-iteration, preferable in update()
|
21
|
+
#
|
11
22
|
def register_tick
|
12
23
|
@accum_fps += 1
|
24
|
+
@ticks += 1
|
13
25
|
current_second = Gosu::milliseconds / 1000
|
14
26
|
if current_second != @current_second
|
15
27
|
@current_second = current_second
|
16
28
|
@fps = @accum_fps
|
17
29
|
@accum_fps = 0
|
18
30
|
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Calculate how many milliseconds passed since last game loop iteration.
|
34
|
+
# useful in update()-calls
|
35
|
+
#
|
36
|
+
@milliseconds_since_last_tick = Gosu::milliseconds - @last_value
|
37
|
+
@last_value = Gosu::milliseconds
|
38
|
+
return @milliseconds_since_last_tick
|
19
39
|
end
|
20
40
|
end
|
21
41
|
end
|
data/lib/chingu/game_object.rb
CHANGED
@@ -6,10 +6,12 @@ module Chingu
|
|
6
6
|
# All objects that inherits from this class will automaticly be updated and drawn.
|
7
7
|
#
|
8
8
|
class GameObject
|
9
|
-
attr_accessor :image, :x, :y, :angle, :center_x, :center_y, :factor_x, :factor_y, :mode
|
10
|
-
attr_accessor :update, :draw
|
9
|
+
attr_accessor :image, :x, :y, :angle, :center_x, :center_y, :factor_x, :factor_y, :color, :mode
|
10
|
+
attr_accessor :update, :draw
|
11
11
|
attr_reader :options
|
12
12
|
|
13
|
+
include Chingu::InputClient
|
14
|
+
|
13
15
|
#
|
14
16
|
# Class-level default values.
|
15
17
|
# This allows you to set default-values that affect all created GameObjects after that.
|
@@ -17,12 +19,20 @@ module Chingu
|
|
17
19
|
#
|
18
20
|
# in Gosu::Window#initialize: GameObject.center_x = GameObject.center_y = 0
|
19
21
|
#
|
22
|
+
@@x = nil
|
23
|
+
@@y = nil
|
20
24
|
@@zorder = 100
|
21
25
|
@@center_x = 0.5
|
22
26
|
@@center_y = 0.5
|
23
27
|
@@factor_x = 1.0
|
24
28
|
@@factor_y = 1.0
|
25
29
|
|
30
|
+
def self.x; @@x; end
|
31
|
+
def self.x=(value); @@x = value; end
|
32
|
+
|
33
|
+
def self.y; @@y; end
|
34
|
+
def self.y=(value); @@y = value; end
|
35
|
+
|
26
36
|
def self.zorder; @@zorder; end
|
27
37
|
def self.zorder=(value); @@zorder = value; end
|
28
38
|
|
@@ -41,18 +51,18 @@ module Chingu
|
|
41
51
|
#
|
42
52
|
# Create a new GameObject. Arguments are given in hash-format:
|
43
53
|
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
54
|
+
# :x screen x-coordinate (default 0, to the left)
|
55
|
+
# :y screen y-coordinate (default 0, top of screen)
|
56
|
+
# :angle angle of object, used in draw_rot, (default 0, no rotation)
|
57
|
+
# :zorder a gameclass "foo" with higher zorder then gameclass "bar" is drawn on top of "foo".
|
58
|
+
# :center_x relative horizontal position of the rotation center on the image.
|
59
|
+
# 0 is the left border, 1 is the right border, 0.5 is the center (default 0.5)
|
60
|
+
# :center_y see center_x. (default 0.5)
|
61
|
+
# :factor_x horizontal zoom-factor, use >1.0 to zoom in. (default 1.0, no zoom).
|
62
|
+
# :factor_y vertical zoom-factor, use >1.0 to zoom in. (default 1.0, no zoom).
|
53
63
|
#
|
54
|
-
#
|
55
|
-
#
|
64
|
+
# :update [true|false] Automaticly call #update on object each gameloop. Default +true+.
|
65
|
+
# :draw [true|false] Automaticly call #update on object each gameloop. Default +true+.
|
56
66
|
#
|
57
67
|
def initialize(options = {})
|
58
68
|
@options = options
|
@@ -61,8 +71,8 @@ module Chingu
|
|
61
71
|
@image = options[:image] if options[:image].is_a? Gosu::Image
|
62
72
|
@image = Image[options[:image]] if options[:image].is_a? String
|
63
73
|
|
64
|
-
@x = options[:x] || 0
|
65
|
-
@y = options[:y] || 0
|
74
|
+
@x = options[:x] || @@x || 0
|
75
|
+
@y = options[:y] || @@y || 0
|
66
76
|
@angle = options[:angle] || 0
|
67
77
|
@zorder = options[:zorder] || @@zorder
|
68
78
|
@center_x = options[:center_x] || options[:center] || @@center_x
|
@@ -72,6 +82,9 @@ module Chingu
|
|
72
82
|
@color = options[:color] || 0xFFFFFFFF
|
73
83
|
@mode = options[:mode] || :default # :additive is also available.
|
74
84
|
|
85
|
+
# Shortcuts for draw_rot arguments
|
86
|
+
@factor = 1
|
87
|
+
|
75
88
|
# gameloop/framework logic
|
76
89
|
@update = options[:update] || true
|
77
90
|
@draw = options[:draw] || true
|
@@ -85,9 +98,32 @@ module Chingu
|
|
85
98
|
@parent.add_game_object(self) if @parent
|
86
99
|
end
|
87
100
|
|
101
|
+
def factor=(factor)
|
102
|
+
@factor = factor
|
103
|
+
@factor_x = @factor_y = @factor
|
104
|
+
end
|
105
|
+
alias :zoom= :factor=
|
106
|
+
def factor
|
107
|
+
@factor
|
108
|
+
end
|
109
|
+
alias :zoom :factor
|
88
110
|
|
89
|
-
|
90
|
-
|
111
|
+
#
|
112
|
+
# Returns true if game object is inside the game window, false if outside
|
113
|
+
#
|
114
|
+
def inside_window?(x = @x, y = @y)
|
115
|
+
x >= 0 && x <= $window.width && y >= 0 && y <= $window.height
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
#
|
120
|
+
#
|
121
|
+
def outside_window?(x = @x, y = @y)
|
122
|
+
not inside_window?(x,y)
|
123
|
+
end
|
124
|
+
|
125
|
+
def update(time = 1)
|
126
|
+
# Objects gamelogic here, 'time' is the time passed between 2 iterations of the main game loop
|
91
127
|
end
|
92
128
|
|
93
129
|
#
|
data/lib/chingu/game_state.rb
CHANGED
@@ -1,39 +1,115 @@
|
|
1
1
|
module Chingu
|
2
|
+
#
|
3
|
+
# Chingu incorporates a basic push/pop game state system (as discussed here: http://www.gamedev.net/community/forums/topic.asp?topic_id=477320).
|
4
|
+
# Game states is a way of organizing your intros, menus, levels.
|
5
|
+
# Game states aren't complicated. In Chingu a GameState is a class that behaves mostly like your default Gosu::Window (or in our case Chingu::Window) game loop.
|
6
|
+
#
|
7
|
+
# # A simple GameState-example
|
8
|
+
# class Intro < Chingu::GameState
|
9
|
+
# def update
|
10
|
+
# # game logic here
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# def draw
|
14
|
+
# # screen manipulation here
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # Called when we enter the game state
|
18
|
+
# def setup
|
19
|
+
# @player.angle = 0 # point player upwards
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # Called when we leave the current game state
|
23
|
+
# def finalize
|
24
|
+
# push_game_state(Menu) # switch to game state "Menu"
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
|
2
29
|
class GameState
|
3
|
-
include Chingu::GameStateHelpers
|
4
|
-
include Chingu::DrawHelpers
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
30
|
+
include Chingu::GameStateHelpers # Easy access to the global game state-queue
|
31
|
+
include Chingu::DrawHelpers # Adds fill(), fade() etc to each game state
|
32
|
+
include Chingu::GameObjectHelpers # adds game_objects_of_class etc ...
|
33
|
+
include Chingu::InputDispatcher # dispatch-helpers
|
34
|
+
include Chingu::InputClient
|
35
|
+
|
36
|
+
attr_reader :options # so jlnr can access his :level-number
|
37
|
+
attr_reader :game_objects, :do_setup
|
9
38
|
|
10
39
|
def initialize(options = {})
|
11
40
|
@options = options
|
12
|
-
@
|
13
|
-
|
41
|
+
@do_setup = options[:setup] || true
|
42
|
+
|
43
|
+
@game_objects = Set.new
|
44
|
+
@input_clients = Set.new # Set is like a unique Array with Hash lookupspeed
|
45
|
+
|
14
46
|
$window.game_state_manager.inside_state = self
|
15
|
-
setup
|
16
47
|
end
|
17
48
|
|
18
|
-
|
19
|
-
|
49
|
+
#
|
50
|
+
# An unique identifier for the GameState-class,
|
51
|
+
# Used in game state manager to keep track of created states.
|
52
|
+
#
|
53
|
+
def to_sym
|
54
|
+
self.class.to_s.to_sym
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_game_object(object)
|
58
|
+
@game_objects << object
|
59
|
+
end
|
60
|
+
def remove_game_object(object)
|
61
|
+
@input_clients.delete(object)
|
20
62
|
end
|
21
63
|
|
22
64
|
def setup
|
65
|
+
# Your game state setup logic here.
|
23
66
|
end
|
24
67
|
|
68
|
+
#
|
69
|
+
# Called when a button is pressed and a game state is active
|
70
|
+
#
|
25
71
|
def button_down(id)
|
72
|
+
dispatch_button_down(id, self)
|
73
|
+
@input_clients.each { |object| dispatch_button_down(id, object) }
|
26
74
|
end
|
27
75
|
|
76
|
+
#
|
77
|
+
# Called when a button is released and a game state active
|
78
|
+
#
|
28
79
|
def button_up(id)
|
80
|
+
dispatch_button_up(id, self)
|
81
|
+
@input_clients.each { |object| dispatch_button_up(id, object) }
|
29
82
|
end
|
30
|
-
|
31
|
-
|
32
|
-
|
83
|
+
|
84
|
+
#
|
85
|
+
# Calls update on each game object that has current game state as parent (created inside that game state)
|
86
|
+
#
|
87
|
+
def update(time = 1)
|
88
|
+
dispatch_input_for(self)
|
89
|
+
@input_clients.each { |game_object| dispatch_input_for(game_object) }
|
90
|
+
|
91
|
+
@game_objects.each { |object| object.update(time) }
|
33
92
|
end
|
34
93
|
|
94
|
+
#
|
95
|
+
# Calls Draw on each game object that has current game state as parent (created inside that game state)
|
96
|
+
#
|
35
97
|
def draw
|
36
98
|
@game_objects.each { |object| object.draw }
|
37
99
|
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Closes game state by poping it off the stack (and activating the game state below)
|
103
|
+
#
|
104
|
+
def close
|
105
|
+
pop_game_state
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Closes main window and terminates the application
|
110
|
+
#
|
111
|
+
def close_game
|
112
|
+
$window.close
|
113
|
+
end
|
38
114
|
end
|
39
115
|
end
|
@@ -1,47 +1,103 @@
|
|
1
|
-
module Chingu
|
1
|
+
module Chingu
|
2
|
+
#
|
3
|
+
# GameStateManger is responsible for keeping track of game states with a simple pop/push stack.
|
4
|
+
#
|
5
|
+
# Chingu::Window automatically creates a @game_state_manager and makes it accessible in our game loop.
|
6
|
+
# By default the game loop calls update() / draw() on @game_state_manager
|
7
|
+
#
|
2
8
|
class GameStateManager
|
3
9
|
attr_accessor :inside_state
|
4
|
-
attr_reader :states
|
10
|
+
attr_reader :states, :created_states
|
5
11
|
|
6
12
|
def initialize
|
7
13
|
@inside_state = nil
|
8
14
|
@states = []
|
15
|
+
@created_states = {}
|
9
16
|
end
|
10
17
|
|
11
18
|
#
|
12
19
|
# Gets the currently active gamestate (top of stack)
|
13
20
|
#
|
14
|
-
def
|
21
|
+
def current_state
|
15
22
|
@states.last
|
16
23
|
end
|
17
24
|
|
18
25
|
#
|
19
|
-
# Adds a state to the
|
26
|
+
# Adds a state to the game state-stack and activates it
|
20
27
|
#
|
21
|
-
def push_state(state)
|
22
|
-
|
28
|
+
def push_state(state, options = {})
|
29
|
+
new_state = nil
|
30
|
+
|
31
|
+
#
|
32
|
+
# If state is a GameState-instance, just queue it
|
33
|
+
#
|
34
|
+
if state.is_a? Chingu::GameState
|
35
|
+
new_state = state
|
36
|
+
#
|
37
|
+
# If state is a GameState-class, create/initialize it once (@created_states keeps track of this)
|
38
|
+
#
|
39
|
+
elsif state.superclass == Chingu::GameState
|
40
|
+
|
41
|
+
if @created_states[state.to_s]
|
42
|
+
new_state = @created_states[state.to_s]
|
43
|
+
else
|
44
|
+
new_state = state.new(options)
|
45
|
+
@created_states[state.class.to_s] = new_state
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# If the new state is all good
|
51
|
+
#
|
52
|
+
if new_state
|
53
|
+
# Give the soon-to-be-disabled state a chance to clean up by calling finalize() on it.
|
54
|
+
current_state.finalize if current_state.respond_to? :finalize
|
55
|
+
|
56
|
+
# Call setup
|
57
|
+
new_state.setup if new_state.do_setup
|
58
|
+
|
59
|
+
# Push new state on top of stack and therefore making it active
|
60
|
+
@states.push(new_state)
|
61
|
+
end
|
23
62
|
end
|
24
63
|
|
25
64
|
#
|
26
|
-
# Pops a state off the
|
27
|
-
#
|
28
|
-
def pop_state
|
65
|
+
# Pops a state off the game state-stack, activating the previous one.
|
66
|
+
#
|
67
|
+
def pop_state(options = {})
|
68
|
+
#
|
69
|
+
# Give the soon-to-be-disabled state a chance to clean up by calling finalize() on it.
|
70
|
+
#
|
71
|
+
current_state.finalize if current_state.respond_to? :finalize
|
72
|
+
|
73
|
+
#
|
74
|
+
# Activate the game state "bellow" current one with a simple Array.pop
|
75
|
+
#
|
29
76
|
@states.pop
|
77
|
+
|
78
|
+
# Call setup on the new current state
|
79
|
+
current_state.setup unless options[:setup] == false
|
30
80
|
end
|
31
81
|
|
32
82
|
#
|
33
|
-
# Returns the previous
|
83
|
+
# Returns the previous game state
|
34
84
|
#
|
35
85
|
def previous_state
|
36
|
-
@states[@states.index(
|
86
|
+
@states[@states.index(current_state)-1]
|
37
87
|
end
|
38
|
-
|
39
88
|
alias :prev_state previous_state
|
40
89
|
|
41
90
|
#
|
42
|
-
#
|
91
|
+
# Remove all game states from stack
|
92
|
+
#
|
93
|
+
def clear_states
|
94
|
+
@states.clear
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Pops through all game states until matching a given game state
|
43
99
|
#
|
44
|
-
def
|
100
|
+
def pop_until_game_state(new_state)
|
45
101
|
while (state = @states.pop)
|
46
102
|
break if state == new_state
|
47
103
|
end
|
@@ -58,27 +114,27 @@ module Chingu
|
|
58
114
|
# Called before #update when the user pressed a button while the window had the focus.
|
59
115
|
#
|
60
116
|
def button_down(id)
|
61
|
-
|
117
|
+
current_state.button_down(id) if current_state
|
62
118
|
end
|
63
119
|
|
64
120
|
#
|
65
121
|
# Called when the user released a button.
|
66
122
|
#
|
67
123
|
def button_up(id)
|
68
|
-
|
124
|
+
current_state.button_up(id) if current_state
|
69
125
|
end
|
70
126
|
|
71
127
|
#
|
72
128
|
# Calls #update on the current gamestate, if there is one.
|
73
129
|
#
|
74
|
-
def update
|
75
|
-
|
130
|
+
def update(time = 1)
|
131
|
+
current_state.update(time) if current_state
|
76
132
|
end
|
77
133
|
#
|
78
134
|
# Calls draw() on the current gamestate, if there is one.
|
79
135
|
#
|
80
136
|
def draw
|
81
|
-
|
137
|
+
current_state.draw if current_state
|
82
138
|
end
|
83
139
|
end
|
84
140
|
end
|