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/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
 
@@ -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
@@ -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, :input
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
- # :x screen x-coordinate (default 0, to the left)
45
- # :y screen y-coordinate (default 0, top of screen)
46
- # :angle angle of object, used in draw_rot, (default 0, no rotation)
47
- # :zorder a gameclass "foo" with higher zorder then gameclass "bar" is drawn on top of "foo".
48
- # :center_x relative horizontal position of the rotation center on the image.
49
- # 0 is the left border, 1 is the right border, 0.5 is the center (default 0.5)
50
- # :center_y see center_x. (default 0.5)
51
- # :factor_x horizontal zoom-factor, use >1.0 to zoom in. (default 1.0, no zoom).
52
- # :factor_y vertical zoom-factor, use >1.0 to zoom in. (default 1.0, no zoom).
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
- # :update [true|false] Automaticly call #update on object each gameloop. Default +true+.
55
- # :draw [true|false] Automaticly call #update on object each gameloop. Default +true+.
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
- def update
90
- # Objects gamelogic here
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
  #
@@ -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 # Easy access to the global game_state-queue
4
- include Chingu::DrawHelpers # Adds fill(), fade() etc to each gamestate.
5
-
6
- attr_reader :options # so jac can access his :level-number
7
- attr_reader :game_objects
8
- attr_accessor :input
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
- @game_objects = Array.new
13
- @input = options[:input]
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
- def add_game_object(game_object)
19
- @game_objects.push(game_object) unless @game_objects.include?(game_object)
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
- def update
32
- @game_objects.each { |object| object.update }
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 state
21
+ def current_state
15
22
  @states.last
16
23
  end
17
24
 
18
25
  #
19
- # Adds a state to the gamestate-stack
26
+ # Adds a state to the game state-stack and activates it
20
27
  #
21
- def push_state(state)
22
- @states.push(state)
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 gamestate-stack
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 gamestate
83
+ # Returns the previous game state
34
84
  #
35
85
  def previous_state
36
- @states[@states.index(state)-1]
86
+ @states[@states.index(current_state)-1]
37
87
  end
38
-
39
88
  alias :prev_state previous_state
40
89
 
41
90
  #
42
- # Pops through all gamestates until matching a given gamestate
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 switch_state(new_state)
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
- state.button_down(id) if state
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
- state.button_up(id) if state
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
- state.update if state
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
- state.draw if state
137
+ current_state.draw if current_state
82
138
  end
83
139
  end
84
140
  end