chingu 0.7.0 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/History.txt +1 -1
  2. data/README.rdoc +110 -49
  3. data/benchmarks/game_objects_benchmark.rb +50 -0
  4. data/chingu.gemspec +24 -12
  5. data/examples/example10_traits_retrofy.rb +6 -4
  6. data/examples/example11_animation.rb +14 -23
  7. data/examples/example12_trait_timer.rb +1 -1
  8. data/examples/example13_high_scores.rb +1 -1
  9. data/examples/example14_bounding_box_circle.rb +6 -10
  10. data/examples/example15_trait_timer2.rb +1 -1
  11. data/examples/example16_online_high_scores.rb +1 -1
  12. data/examples/example17_gosu_tutorial.rb +4 -4
  13. data/examples/example18_animation_trait.rb +98 -0
  14. data/examples/example19_edit_viewport.rb +223 -0
  15. data/examples/example19_game_objects.yml +1591 -0
  16. data/examples/example20_trait_inheritence_test.rb +58 -0
  17. data/examples/example3_parallax.rb +1 -1
  18. data/examples/example4_gamestates.rb +1 -1
  19. data/examples/example7_gfx_helpers.rb +14 -9
  20. data/examples/example8_traits.rb +4 -4
  21. data/examples/example9_collision_detection.rb +1 -1
  22. data/examples/game1.rb +33 -38
  23. data/examples/game_of_life.rb +291 -0
  24. data/examples/media/droid_11x15.bmp +0 -0
  25. data/examples/media/droid_11x15.gal +0 -0
  26. data/examples/media/heli.bmp +0 -0
  27. data/examples/media/heli.gal +0 -0
  28. data/examples/media/star_25x25_default.png +0 -0
  29. data/examples/media/star_25x25_explode.gal +0 -0
  30. data/examples/media/star_25x25_explode.png +0 -0
  31. data/examples/media/stone_wall.bmp +0 -0
  32. data/lib/chingu.rb +1 -1
  33. data/lib/chingu/animation.rb +78 -9
  34. data/lib/chingu/basic_game_object.rb +16 -8
  35. data/lib/chingu/game_object.rb +36 -7
  36. data/lib/chingu/game_object_list.rb +20 -3
  37. data/lib/chingu/game_state.rb +8 -7
  38. data/lib/chingu/game_states/edit.rb +177 -90
  39. data/lib/chingu/helpers/class_inheritable_accessor.rb +12 -5
  40. data/lib/chingu/helpers/game_object.rb +45 -4
  41. data/lib/chingu/helpers/gfx.rb +150 -172
  42. data/lib/chingu/helpers/input_client.rb +7 -0
  43. data/lib/chingu/inflector.rb +16 -2
  44. data/lib/chingu/traits/animation.rb +84 -0
  45. data/lib/chingu/traits/bounding_box.rb +16 -3
  46. data/lib/chingu/traits/bounding_circle.rb +18 -4
  47. data/lib/chingu/traits/collision_detection.rb +10 -1
  48. data/lib/chingu/traits/velocity.rb +26 -3
  49. data/lib/chingu/traits/viewport.rb +10 -9
  50. data/lib/chingu/viewport.rb +103 -22
  51. data/lib/chingu/window.rb +8 -2
  52. metadata +46 -16
  53. data/examples/example18_viewport.rb +0 -173
  54. data/examples/media/city1.csv +0 -2
  55. data/examples/media/plane.csv +0 -2
  56. data/examples/media/saucer.csv +0 -4
  57. data/examples/media/stickfigure.bmp +0 -0
  58. data/examples/media/stickfigure.png +0 -0
@@ -0,0 +1,84 @@
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
+ module Chingu
23
+ module Traits
24
+ #
25
+ # A chingu trait providing automatic loading of tile-animations
26
+ #
27
+ # For example:
28
+ # class FireBall; has_traits :animation; end;
29
+ #
30
+ # Will automatically load:
31
+ # - fire_ball.png into self.animations[:default]
32
+ # - fire_ball_exploding.png into self.animations[:exploding]
33
+ #
34
+ # Adds accessors animations -> Hash with all animations, hash-key is the name of the animation
35
+ #
36
+ module Animation
37
+
38
+ module ClassMethods
39
+
40
+ def initialize_trait(options = {})
41
+ trait_options[:animation] = {:directory => "media", :play => true, :delay => 100}.merge(options)
42
+ end
43
+
44
+ end
45
+
46
+ def setup_trait(options)
47
+ @animation_options = {:debug => false}.merge(options)
48
+ @animations = load_animations
49
+ super
50
+ end
51
+
52
+ #
53
+ # Try loading animation from class-name
54
+ #
55
+ def load_animations
56
+ animations = {}
57
+ glob = "#{trait_options[:animation][:directory]}/#{self.filename}_*"
58
+ puts "Animations? #{glob}" if trait_options[:animation][:debug]
59
+ Dir[glob].each do |tile_file|
60
+ #state = :default
61
+ if tile_file =~ /[a-zA-Z\_+]_*(\d+)x(\d+)_*([a-zA-Z]*)\.(bmp|png)/
62
+ #if tile_file =~ /_*([a-zA-Z]*)\.(bmp|png)\Z/
63
+ #if tile_file =~ /#{self.filename}\.(bmp|png)/
64
+ state = $3.length > 0 ? $3 : "default"
65
+ animations[state.to_sym] = Chingu::Animation.new(trait_options[:animation].merge(:file => tile_file))
66
+ end
67
+ end
68
+ return animations
69
+ end
70
+
71
+ def animation
72
+ @animations[:default]
73
+ end
74
+
75
+ #
76
+ # Returns all animations, then access invidual states with animations[:explode] etc.
77
+ #
78
+ def animations
79
+ @animations
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -38,6 +38,10 @@ module Chingu
38
38
  super
39
39
  end
40
40
 
41
+ def collision_at?(x, y)
42
+ bounding_box.collide_point?(x,y)
43
+ end
44
+
41
45
  #
42
46
  # Returns an instance of class Rect
43
47
  #
@@ -77,12 +81,21 @@ module Chingu
77
81
  #end
78
82
 
79
83
  def draw_trait
80
- if trait_options[:bounding_box][:debug]
81
- $window.draw_rect(self.bounding_box, Chingu::DEBUG_COLOR, Chingu::DEBUG_ZORDER)
82
- end
84
+ draw_debug if trait_options[:bounding_box][:debug]
83
85
  super
84
86
  end
85
87
 
88
+ #
89
+ # Visualises the bounding box as a red rectangle.
90
+ #
91
+ def draw_debug
92
+ if defined?(parent.viewport)
93
+ $window.draw_rect(self.bounding_box.move(-parent.viewport.x, -parent.viewport.y), Chingu::DEBUG_COLOR, Chingu::DEBUG_ZORDER)
94
+ else
95
+ $window.draw_rect(self.bounding_box, Chingu::DEBUG_COLOR, Chingu::DEBUG_ZORDER)
96
+ end
97
+ end
98
+
86
99
  end
87
100
  end
88
101
  end
@@ -40,6 +40,10 @@ module Chingu
40
40
  super
41
41
  end
42
42
 
43
+ def collision_at?(x, y)
44
+ Gosu.distance(self.x, self.y, x, y) < radius
45
+ end
46
+
43
47
  def radius
44
48
  return @cached_radius if @cached_radius
45
49
 
@@ -70,12 +74,22 @@ module Chingu
70
74
  def circle_bottom; self.y + self.radius; end
71
75
 
72
76
  def draw_trait
73
- if trait_options[:bounding_circle][:debug]
74
- $window.draw_circle(self.x, self.y, self.radius, Chingu::DEBUG_COLOR)
75
- end
77
+ draw_debug if trait_options[:bounding_circle][:debug]
76
78
  super
77
79
  end
78
-
80
+
81
+ #
82
+ # Visualises the bounding circle as a red circle.
83
+ #
84
+ def draw_debug
85
+ x,y = self.x, self.y # Do we need to take center_x/center_y into consideration here?
86
+ if defined?(parent.viewport)
87
+ $window.draw_circle(x - parent.viewport.x, y - parent.viewport.y, self.radius, Chingu::DEBUG_COLOR)
88
+ else
89
+ $window.draw_circle(x, y, self.radius, Chingu::DEBUG_COLOR)
90
+ end
91
+ end
92
+
79
93
  end
80
94
  end
81
95
  end
@@ -106,7 +106,16 @@ module Chingu
106
106
  end
107
107
  end
108
108
  end
109
-
109
+
110
+ def first_collision(*klasses)
111
+ Array(klasses).each do |klass|
112
+ klass.all.each do |object|
113
+ return object if collides?(object)
114
+ end
115
+ end
116
+ return nil
117
+ end
118
+
110
119
  #
111
120
  # Explicit radius-collision
112
121
  # Works like each_collsion but with inline-code for speedups
@@ -38,20 +38,42 @@ module Chingu
38
38
  end
39
39
 
40
40
  def setup_trait(options)
41
- @velocity_options = {:debug => false}.merge(options)
41
+ @velocity_options = {:debug => false}.merge(options)
42
42
 
43
43
  @velocity_x = options[:velocity_x] || 0
44
44
  @velocity_y = options[:velocity_y] || 0
45
+ self.velocity = options[:velocity] if options[:velocity]
46
+
45
47
  @acceleration_x = options[:acceleration_x] || 0
46
48
  @acceleration_y = options[:acceleration_y] || 0
49
+ self.acceleration = options[:acceleration] if options[:acceleration]
50
+
47
51
  @max_velocity = options[:max_velocity] || 1000
48
52
  super
49
53
  end
50
54
 
55
+ #
56
+ # Sets X and Y velocity with one single call. Takes an Array-argument with 2 values.
57
+ #
58
+ def velocity=(velocity)
59
+ @velocity_x, @velocity_y = velocity
60
+ end
61
+
62
+ def velocity; [@velocity_x, @velocity_y]; end
63
+
64
+ #
65
+ # Sets X and Y acceleration with one single call. Takes an Array-argument with 2 values.
66
+ #
67
+ def acceleration=(acceleration)
68
+ @acceleration_x, @acceleration_y = acceleration
69
+ end
70
+
71
+ def acceleration; [@acceleration_x, @acceleration_y]; end
72
+
51
73
  #
52
74
  # Modifies X & Y of parent
53
75
  #
54
- def update_trait
76
+ def update_trait
55
77
  @velocity_y += @acceleration_y if (@velocity_y + @acceleration_y).abs < @max_velocity
56
78
  @velocity_x += @acceleration_x if (@velocity_x + @acceleration_x).abs < @max_velocity
57
79
 
@@ -61,10 +83,11 @@ module Chingu
61
83
  #
62
84
  # if option :apply is false, just calculate velocities, don't apply them to x/y
63
85
  #
64
- if trait_options[:velocity][:apply]
86
+ unless trait_options[:velocity][:apply] == false
65
87
  self.y += @velocity_y
66
88
  self.x += @velocity_x
67
89
  end
90
+
68
91
  super
69
92
  end
70
93
 
@@ -45,24 +45,25 @@ module Chingu
45
45
 
46
46
  super
47
47
  end
48
-
49
- #
50
- # Returns true if object is inside view port, false if outside
51
- # TODO: add view port height and width! (and use clip_to when painting?)
52
- #
53
- # This is a very flawed implementation, it Should take inte account objects
54
- # height,width,factor_x,factor_y,center_x,center_y as well...
55
- #
48
+
56
49
  def inside_viewport?(object)
57
- object.x >= @viewport.x && object.x <= (@viewport.x + $window.width) &&
50
+ puts "Deprecated, use self.viewport.inside?() instead"
51
+ object.x >= @viewport.x && object.x <= (@viewport.x + $window.width) &&
58
52
  object.y >= @viewport.y && object.y <= (@viewport.y + $window.height)
59
53
  end
60
54
 
61
55
  # Returns true object is outside the view port
62
56
  def outside_viewport?(object)
57
+ puts "Deprecated, use self.viewport.outside?() instead"
63
58
  not inside_viewport?(object)
64
59
  end
65
60
 
61
+ # Take care of laggy viewport movements
62
+ def update_trait
63
+ @viewport.move_towards_target
64
+ super
65
+ end
66
+
66
67
  #
67
68
  # Override game states default draw that draws objects relative to the viewport.
68
69
  # It only draws game objects inside the viewport. (GOSU does no such optimizations)
@@ -21,47 +21,128 @@
21
21
 
22
22
  module Chingu
23
23
  #
24
- # A basic Viewport class
24
+ # A basic viewport class
25
25
  #
26
26
  # TODO:
27
27
  # Implement use of viewports angle, center_x, center_y, factor_x, factor_y
28
28
  #
29
29
  class Viewport
30
- attr_accessor :x, :y, :x_min, :x_max, :y_min, :y_max
31
- #attr_accessor :angle, :center_x, :center_y, :factor_x, :factor_y
30
+ attr_accessor :x, :y, :x_target, :y_target, :x_lag, :y_lag, :game_area
32
31
 
33
32
  def initialize(options = {})
34
33
  @x = options[:x] || 0
35
- @y = options[:y] || 0
36
- @angle = options[:angle] || 0
37
-
38
- #self.factor = options[:factor] || options[:scale] || 1.0
39
- #@factor_x = options[:factor_x] if options[:factor_x]
40
- #@factor_y = options[:factor_y] if options[:factor_y]
34
+ @y = options[:y] || 0
35
+ @x_target = options[:x_target]
36
+ @y_target = options[:y_target]
37
+ @x_lag = options[:x_lag] || 0
38
+ @y_lag = options[:y_lag] || 0
39
+ @game_area = Chingu::Rect.new(options[:game_area]||[@x, @y, $window.width, $window.height])
40
+ end
41
+
42
+ #
43
+ # Set x_lag and y_lag to value 'lag'
44
+ #
45
+ def lag=(lag)
46
+ @x_lag = @y_lag = lag
47
+ end
48
+
49
+ #
50
+ # Center the viewport around the given object (it must respont to x/y)
51
+ # Center will fail if object is in the corners of the game area
52
+ #
53
+ def center_around(object)
54
+ self.x = object.x - $window.width / 2
55
+ self.y = object.y - $window.height / 2
56
+ end
57
+
58
+ #
59
+ # Set a Rect that represents the borders of the game world.
60
+ # The viewport can only move within this Rect.
61
+ #
62
+ def game_area=(rect)
63
+ @game_area = Rect.new(rect)
64
+ end
65
+
66
+ #
67
+ # Set a game world by giving it a game object
68
+ # The game objects image will be the rectangle the viewport can move within.
69
+ #
70
+ def game_area_object=(game_object)
71
+ image = (game_object.is_a? Gosu::Image) ? game_object : game_object.image
72
+ @game_area = Rect.new(0,0,
73
+ (image.width*$window.factor) - $window.width,
74
+ (image.height*$window.factor) - $window.height
75
+ )
76
+ end
77
+
78
+ #
79
+ # Returns true if object is inside view port, false if outside
80
+ # TODO: add view port height and width! (and use clip_to when painting?)
81
+ #
82
+ # This is a very flawed implementation, it Should take inte account objects
83
+ # height,width,factor_x,factor_y,center_x,center_y as well...
84
+ #
85
+ def inside?(object)
86
+ object.x >= @x && object.x <= (@x + $window.width) &&
87
+ object.y >= @y && object.y <= (@y + $window.height)
88
+ end
89
+
90
+ # Returns true object is outside the view port
91
+ def outside?(object)
92
+ not inside_viewport?(object)
93
+ end
41
94
 
42
- #self.center = options[:center] || 0.5
43
- #@rotation_center = options[:rotation_center]
44
- #self.rotation_center(options[:rotation_center]) if options[:rotation_center]
95
+ #
96
+ # Returns true object is inside the game area
97
+ # The "game area" is the full map/world/area from which the viewport shows a slice
98
+ # The viewport can't show anything outside the game area
99
+ #
100
+ def inside_game_area?(object)
101
+ object.x >= @game_area.x && object.x <= (@game_area.width + $window.width) &&
102
+ object.y >= @game_area.x && object.y <= (@game_area.height + $window.height)
103
+ end
45
104
 
46
- #@center_x = options[:center_x] if options[:center_x]
47
- #@center_y = options[:center_y] if options[:center_y]
105
+ # Returns true object is outside the game area
106
+ def outside_game_area?(object)
107
+ not inside_game_area?(object)
108
+ end
109
+
110
+ #
111
+ # Modify viewports x and y from target_x / target_y and x_lag / y_lag
112
+ # Use this to have the viewport "slide" after the player
113
+ #
114
+ def move_towards_target
115
+ if @x_target && @x != @x_target
116
+ x_step = @x_target - @x
117
+ self.x = @x + x_step * (1.0 - @x_lag)
118
+ end
48
119
 
49
- @x_min = nil
50
- @x_max = nil
51
- @y_min = nil
52
- @y_max = nil
120
+ if @y_target && @y != @y_target
121
+ y_step = @y_target - @y
122
+ self.y = @y + y_step * (1.0 - @y_lag)
123
+ end
53
124
  end
54
125
 
126
+ #
127
+ # Viewports X setter with boundschecking
128
+ #
55
129
  def x=(x)
56
130
  @x = x
57
- @x = @x_min if @x_min && @x < @x_min
58
- @x = @x_max if @x_max && @x > @x_max
131
+ if @game_area
132
+ @x = @game_area.x if @x < @game_area.x
133
+ @x = @game_area.width if @x > @game_area.width
134
+ end
59
135
  end
60
136
 
137
+ #
138
+ # Viewports Y setter with boundschecking
139
+ #
61
140
  def y=(y)
62
141
  @y = y
63
- @y = @y_min if @y_min && @y < @y_min
64
- @y = @y_max if @y_max && @y > @y_max
142
+ if @game_area
143
+ @y = @game_area.y if @y < @game_area.y
144
+ @y = @game_area.height if @y > @game_area.height
145
+ end
65
146
  end
66
147
 
67
148
  end
@@ -20,7 +20,6 @@
20
20
  #++
21
21
 
22
22
  module Chingu
23
-
24
23
  #
25
24
  # See http://www.libgosu.org/rdoc/classes/Gosu/Window.html
26
25
  #
@@ -40,6 +39,7 @@ module Chingu
40
39
  include Chingu::Helpers::InputClient # Window has its own inputmap
41
40
 
42
41
  attr_reader :root, :game_state_manager, :game_objects, :milliseconds_since_last_tick
42
+ attr_accessor :factor
43
43
 
44
44
  def initialize(width = 800, height = 600, fullscreen = false, update_interval = 16.666666)
45
45
  fullscreen ||= ARGV.include?("--fullscreen")
@@ -56,9 +56,15 @@ module Chingu
56
56
 
57
57
  @fps_counter = FPSCounter.new
58
58
  @game_state_manager = GameStateManager.new
59
- @milliseconds_since_last_tick = 0
59
+ @milliseconds_since_last_tick = 0
60
+ @factor = 1
61
+
62
+ setup
60
63
  end
61
64
 
65
+ # Placeholder to be overwritten
66
+ def setup; end;
67
+
62
68
  #
63
69
  # Returns self inside GameState.initialize (a game state is not 'active' inside initialize())
64
70
  # Or returns current active game state (as in a switched to or pushed game state)