chingu 0.7.6.4 → 0.7.6.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -49,13 +49,14 @@ class State1 < Chingu::GameState
49
49
  # This is another way of achieving the same thing as the out-commeted draw-code
50
50
  # Since .create is used, it's automatically updated and drawn
51
51
  #
52
- def setup
52
+ def initialize(options = {})
53
+ super
53
54
  Chingu::GameObject.create(:image => "ruby.png", :rotation_center => :top_left)
54
55
  end
55
56
 
56
57
  #def draw
57
58
  # Image["ruby.png"].draw(0,0,0)
58
- #end
59
+ #end
59
60
  end
60
61
 
61
62
  class State2 < Chingu::GameState
@@ -19,40 +19,31 @@ class Game < Chingu::Window
19
19
  end
20
20
 
21
21
  class FireCube < Chingu::GameObject
22
- traits :velocity, :collision_detection
23
- attr_accessor :color, :radius
22
+ traits :velocity, :collision_detection, :bounding_circle
23
+ attr_accessor :color
24
24
 
25
25
  def initialize(options)
26
26
  super
27
27
  @mode = :additive
28
28
 
29
+ @image = Image["circle.png"]
30
+
29
31
  # initialize with a rightwards velocity with some damping to look more realistic
30
- @velocity_x = options[:velocity_x] || 1 + rand(2)
31
- @velocity_y = options[:velocity_y] || 1 + rand(2)
32
+ self.velocity_x = options[:velocity_x] || 1 + rand(2)
33
+ self.velocity_y = options[:velocity_y] || 1 + rand(2)
34
+ self.factor = 2
32
35
 
33
- @box = Rect.new([@x, @y, 10, 10])
34
- @radius = 6
36
+ @color = Color::BLUE
35
37
 
36
- @blue = Color.new(255,100,255,255)
37
- @red = Color.new(255,255,10,10)
38
- @color = @blue
39
- end
40
-
41
- def bounding_box
42
- @box
43
- end
44
-
45
- def draw
46
- $window.fill_rect(@box, @color)
38
+ cache_bounding_circle # This does a lot for performance
47
39
  end
48
40
 
49
41
  def update
50
- @box.x, @box.y = @x, @y
51
- @color = @blue
42
+ @color = Color::BLUE
52
43
  end
53
44
 
54
45
  def die!
55
- @color = @red
46
+ @color = Color::RED
56
47
  end
57
48
 
58
49
  end
@@ -95,8 +86,7 @@ class ParticleState < Chingu::GameState
95
86
  cube1.die!
96
87
  cube2.die!
97
88
  end
98
-
99
- game_objects.destroy_if { |object| object.color.alpha == 0 }
89
+
100
90
  end
101
91
 
102
92
  def draw
data/lib/chingu.rb CHANGED
@@ -33,7 +33,7 @@ require_all "#{CHINGU_ROOT}/chingu/traits"
33
33
  require_all "#{CHINGU_ROOT}/chingu"
34
34
 
35
35
  module Chingu
36
- VERSION = "0.7.6.4"
36
+ VERSION = "0.7.6.5"
37
37
 
38
38
  DEBUG_COLOR = Gosu::Color.new(0xFFFF0000)
39
39
  DEBUG_ZORDER = 9999
data/lib/chingu/assets.rb CHANGED
@@ -33,7 +33,9 @@ module Gosu
33
33
  include Chingu::NamedResource
34
34
 
35
35
  def self.autoload(name)
36
- (path = find_file(name)) ? Gosu::Image.new($window, path, true) : nil
36
+ ret = (path = find_file(name)) ? Gosu::Image.new($window, path, true) : nil
37
+ raise "Can't load image \"#{name}\"" if ret.nil?
38
+ return ret
37
39
  end
38
40
  end
39
41
 
@@ -217,4 +217,4 @@ module Chingu
217
217
  end
218
218
  alias :destroy! :destroy
219
219
  end
220
- end
220
+ end
@@ -1,4 +1,5 @@
1
1
  class Array
2
+
2
3
  def each_collision(*args)
3
4
  list = (self + args).uniq
4
5
  collide_pair = []
@@ -31,7 +31,6 @@ module Chingu
31
31
  @game_objects = options[:game_objects] || []
32
32
  @add_game_objects = []
33
33
  @remove_game_objects = []
34
- #@game_objects_by_class = Hash.new
35
34
  end
36
35
 
37
36
  def to_s
@@ -40,34 +39,24 @@ module Chingu
40
39
 
41
40
  def of_class(klass)
42
41
  @game_objects.select { |game_object| game_object.is_a? klass }
43
- #@game_objects_by_class[klass] || []
44
42
  end
45
43
 
46
44
  def destroy_all
47
45
  @game_objects.clear
48
- #@game_objects_of_class.clear
49
46
  end
50
47
  alias :clear :destroy_all
51
48
  alias :remove_all :destroy_all
52
49
 
53
50
  def add_game_object(object)
54
- #@game_objects.push(object)
55
51
  @add_game_objects.push(object)
56
-
57
-
58
- #(@game_objects_by_class[object.class] ||= []).push(object)
59
52
  end
60
53
 
61
54
  def remove_game_object(object)
62
- #@game_objects.delete(object)
63
55
  @remove_game_objects.push(object)
64
-
65
- #@game_objects_by_class[object.class].delete(object)
66
56
  end
67
57
 
68
58
  def destroy_if
69
59
  @game_objects.reject! { |object| yield(object) }
70
- #@game_objects_by_class.delete_if { |klass, object| yield(object) }
71
60
  end
72
61
 
73
62
  def size
@@ -141,4 +130,4 @@ module Chingu
141
130
  @game_objects.each { |object| object.show! }
142
131
  end
143
132
  end
144
- end
133
+ end
@@ -78,7 +78,7 @@ module Chingu
78
78
  # Include the module, which will add the containing methods as instance methods
79
79
  include mod
80
80
 
81
- # Does sub-module "ClessMethods" exists?
81
+ # Does sub-module "ClassMethods" exists?
82
82
  # (eg: Chingu::Traits::Timer::ClassMethods)
83
83
  if mod.const_defined?("ClassMethods")
84
84
  # Add methods in scope ClassMethods as.. class methods!
@@ -100,6 +100,7 @@ module Chingu
100
100
  # .. and finalize() is called on the game state we're switching _from_.
101
101
  #
102
102
  def switch_game_state(state, options = {})
103
+ puts state.class
103
104
  options = {:setup => true, :finalize => true, :transitional => true}.merge(options)
104
105
 
105
106
  @previous_game_state = current_game_state
@@ -136,10 +136,13 @@ module Chingu
136
136
  if game_object.image
137
137
  game_object.size = [32,32]
138
138
  game_object.cache_bounding_box if game_object.respond_to?(:cache_bounding_box)
139
+ x += 40
140
+ else
141
+ puts "Skipping #{klass} - no image" if @debug
142
+ game_object.destroy
139
143
  end
140
- x += 40
141
144
  rescue
142
- puts "Couldn't use #{klass} in editor."
145
+ puts "Couldn't use #{klass} in editor: #{$!}"
143
146
  end
144
147
  end
145
148
  end
@@ -39,15 +39,13 @@ module Chingu
39
39
  @options = {:speed => 3}.merge(options)
40
40
 
41
41
  @new_game_state = new_game_state
42
- @new_game_state = new_game_state.new if new_game_state.is_a? Class
43
-
44
- #@manager = options[:game_state_manager] || self
45
- #@manager = game_state_manager
42
+ @new_game_state = new_game_state.new if new_game_state.is_a? Class
43
+ @new_game_state.game_objects.sync
46
44
  end
47
45
 
48
46
  def setup
49
47
  @color = Gosu::Color.new(0,0,0,0)
50
- ## if @manager.previous_game_state
48
+
51
49
  if previous_game_state
52
50
  @fading_in = false
53
51
  @alpha = 0.0
@@ -55,7 +53,7 @@ module Chingu
55
53
  @fading_in = true
56
54
  @alpha = 255.0
57
55
  end
58
- # @new_game_state.update # Make sure states game logic is run Once (for a correct draw())
56
+
59
57
  update # Since draw is called before update
60
58
  end
61
59
 
@@ -77,7 +75,6 @@ module Chingu
77
75
  if @fading_in
78
76
  @new_game_state.draw
79
77
  else
80
- ## @manager.previous_game_state.draw
81
78
  previous_game_state.draw
82
79
  end
83
80
 
@@ -88,7 +85,6 @@ module Chingu
88
85
  end
89
86
 
90
87
  if @fading_in && @alpha == 0
91
- ##@manager.switch_game_state(@new_game_state, :transitional => false)
92
88
  switch_game_state(@new_game_state, :transitional => false)
93
89
  end
94
90
 
data/lib/chingu/text.rb CHANGED
@@ -51,7 +51,7 @@ module Chingu
51
51
  #
52
52
  # Takes the standard GameObject-hash-arguments but also:
53
53
  # :text - a string of text
54
- # :font_name|:font - Name of a system font, or a filename to a TTF file (must contain �/�, does not work on Linux).
54
+ # :font_name|:font - Name of a system font, or a filename to a TTF file (must contain ? does not work on Linux).
55
55
  # :height|:size - Height of the font in pixels.
56
56
  # :line_spacing - Spacing between two lines of text in pixels.
57
57
  # :max_width - Width of the bitmap that will be returned. Text will be split into multiple lines to avoid drawing over the right border. When a single word is too long, it will be truncated.
@@ -47,11 +47,8 @@ module Chingu
47
47
  end
48
48
 
49
49
  def radius
50
- return @cached_radius if @cached_radius
51
-
52
- width = self.image.width * self.factor_x.abs
53
- height = self.image.height * self.factor_y.abs
54
- radius = (width + height) / 4
50
+ return @cached_radius if @cached_radius
51
+ radius = (self.width + self.height) / 4
55
52
  radius = radius * trait_options[:bounding_circle][:scale] if trait_options[:bounding_circle][:scale]
56
53
  return radius
57
54
  end
@@ -61,7 +58,6 @@ module Chingu
61
58
  end
62
59
 
63
60
  def cache_bounding_circle
64
- @cached_radius = nil
65
61
  @cached_radius = self.radius
66
62
  end
67
63
 
@@ -111,7 +111,7 @@ module Chingu
111
111
  #
112
112
  def each_collision(*klasses)
113
113
  Array(klasses).each do |klass|
114
- (klass.respond_to?(:all) ? klass.all : klass).each do |object|
114
+ (klass.respond_to?(:all) ? klass.all : Array(klass)).each do |object|
115
115
  yield(self, object) if collides?(object)
116
116
  end
117
117
  end
@@ -119,7 +119,7 @@ module Chingu
119
119
 
120
120
  def first_collision(*klasses)
121
121
  Array(klasses).each do |klass|
122
- (klass.respond_to?(:all) ? klass.all : klass).each do |object|
122
+ (klass.respond_to?(:all) ? klass.all : Array(klass)).each do |object|
123
123
  return object if collides?(object)
124
124
  end
125
125
  end
@@ -132,7 +132,7 @@ module Chingu
132
132
  #
133
133
  def each_bounding_circle_collision(*klasses)
134
134
  Array(klasses).each do |klass|
135
- (klass.respond_to?(:all) ? klass.all : klass).each do |object|
135
+ (klass.respond_to?(:all) ? klass.all : Array(klass)).each do |object|
136
136
  next unless self.collidable && object.collidable
137
137
  yield(self, object) if Gosu.distance(self.x, self.y, object.x, object.y) < self.radius + object.radius
138
138
  end
@@ -145,7 +145,7 @@ module Chingu
145
145
  #
146
146
  def each_bounding_box_collision(*klasses)
147
147
  Array(klasses).each do |klass|
148
- (klass.respond_to?(:all) ? klass.all : klass).each do |object|
148
+ (klass.respond_to?(:all) ? klass.all : Array(klass)).each do |object|
149
149
  return false unless self.collidable && object.collidable
150
150
  yield(self, object) if self.bounding_box.collide_rect?(object.bounding_box)
151
151
  end
@@ -159,7 +159,7 @@ module Chingu
159
159
  #
160
160
  def each_bounding_circle_collision(*klasses)
161
161
  Array(klasses).each do |klass|
162
- object2_list = (klass.respond_to?(:all) ? klass.all : klass)
162
+ object2_list = (klass.respond_to?(:all) ? klass.all : Array(klass))
163
163
  #total_radius = object1.radius + object2.radius # possible optimization?
164
164
 
165
165
  self.all.each do |object1|
@@ -177,7 +177,7 @@ module Chingu
177
177
  #
178
178
  def each_bounding_box_collision(*klasses)
179
179
  Array(klasses).each do |klass|
180
- object2_list = (klass.respond_to?(:all) ? klass.all : klass)
180
+ object2_list = (klass.respond_to?(:all) ? klass.all : Array(klass))
181
181
  self.all.each do |object1|
182
182
  object2_list.each do |object2|
183
183
  next if object1 == object2 # Don't collide objects with themselves
@@ -233,7 +233,7 @@ module Chingu
233
233
  # end
234
234
  # end
235
235
  #end
236
- object2_list = (klass.respond_to?(:all) ? klass.all : klass)
236
+ object2_list = (klass.respond_to?(:all) ? klass.all : Array(klass))
237
237
  self.all.each do |object1|
238
238
  object2_list.each do |object2|
239
239
  next if object1 == object2 # Don't collide objects with themselves
@@ -58,8 +58,9 @@ module Chingu
58
58
  #
59
59
  # Sets X and Y velocity with one single call. Takes an Array-argument with 2 values.
60
60
  #
61
- def velocity=(velocity)
62
- @velocity_x, @velocity_y = velocity
61
+ def velocity=(value)
62
+ @velocity_x, @velocity_y = value && return if value.is_a? Array
63
+ @velocity_x, @velocity_y = value, value
63
64
  end
64
65
 
65
66
  def velocity; [@velocity_x, @velocity_y]; end
@@ -67,8 +68,9 @@ module Chingu
67
68
  #
68
69
  # Sets X and Y acceleration with one single call. Takes an Array-argument with 2 values.
69
70
  #
70
- def acceleration=(acceleration)
71
- @acceleration_x, @acceleration_y = acceleration
71
+ def acceleration=(value)
72
+ @acceleration_x, @acceleration_y = value && return if value.is_a? Array
73
+ @acceleration_x, @acceleration_y = value, value
72
74
  end
73
75
 
74
76
  def acceleration; [@acceleration_x, @acceleration_y]; end
@@ -76,8 +78,9 @@ module Chingu
76
78
  #
77
79
  # Sets X and Y acceleration with one single call. Takes an Array-argument with 2 values.
78
80
  #
79
- def max_velocity=(max_velocity)
80
- @max_velocity_x, @max_velocity_y = max_velocity
81
+ def max_velocity=(value)
82
+ @max_velocity_x, @max_velocity_y = value && return if value.is_a? Array
83
+ @max_velocity_x, @max_velocity_y = value, value
81
84
  end
82
85
 
83
86
  def max_velocity; [@max_velocity_x, @max_velocity_y]; end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ module Chingu
4
+
5
+ describe FPSCounter do
6
+
7
+ it { should respond_to(:fps) }
8
+ it { should respond_to(:milliseconds_since_last_tick) }
9
+ it { should respond_to(:ticks) }
10
+
11
+ describe "#register_tick" do
12
+ before do
13
+ Gosu.stub(:milliseconds).and_return(1000)
14
+ subject { FPSCounter.new }
15
+ end
16
+
17
+ it "increases the tick counter" do
18
+ expect {
19
+ subject.register_tick
20
+ }.to change(subject, :ticks).from(0).to(1)
21
+ end
22
+
23
+ it "keeps track of the fps" do
24
+ expect {
25
+ subject.register_tick
26
+ Gosu.stub(:milliseconds).and_return(1500)
27
+ subject.register_tick
28
+ Gosu.stub(:milliseconds).and_return(2000)
29
+ subject.register_tick
30
+ }.to change(subject, :fps).from(0).to(3) # #register_tick has been called 3 times within 1 second = 3 FPS
31
+ end
32
+
33
+ it "calculates how many milliseconds passed since last game loop iteration and returns that value" do
34
+ Gosu.stub(:milliseconds).and_return(2000)
35
+ subject.register_tick.should equal 1000
36
+ subject.milliseconds_since_last_tick.should eql(1000)
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ module Chingu
4
+
5
+ describe GameObject do
6
+
7
+ before(:all) do
8
+ @game = Chingu::Window.new
9
+ end
10
+
11
+ it { should respond_to(:x) }
12
+ it { should respond_to(:y) }
13
+ it { should respond_to(:angle) }
14
+ it { should respond_to(:center_x) }
15
+ it { should respond_to(:center_y) }
16
+ it { should respond_to(:factor_x) }
17
+ it { should respond_to(:factor_y) }
18
+ it { should respond_to(:zorder) }
19
+ it { should respond_to(:mode) }
20
+ it { should respond_to(:color) }
21
+
22
+ describe "a newly created GameObject" do
23
+ before do
24
+ subject { GameObject.new }
25
+ end
26
+
27
+ it "should have default values" do
28
+ subject.angle.should == 0
29
+ subject.x.should == 0
30
+ subject.y.should == 0
31
+ subject.factor_x.should == 1
32
+ subject.factor_y.should == 1
33
+ subject.center_x.should == 0.5
34
+ subject.center_y.should == 0.5
35
+ subject.mode.should == :default
36
+ subject.image.should == nil
37
+ subject.color.to_s.should == Gosu::Color::WHITE.to_s
38
+ subject.alpha.should == 255
39
+ end
40
+
41
+ it "should wrap angle at 360" do
42
+ subject.angle.should == 0
43
+ subject.angle += 30
44
+ subject.angle.should == 30
45
+ subject.angle += 360
46
+ subject.angle.should == 30
47
+ end
48
+
49
+ it "shouldn't allow alpha below 0" do
50
+ subject.alpha = -10
51
+ subject.alpha.should == 0
52
+ end
53
+
54
+ it "shouldn't allow alpha above 255" do
55
+ subject.alpha = 1000
56
+ subject.alpha.should == 255
57
+ end
58
+
59
+ end
60
+
61
+ describe "GameObject with an image" do
62
+ before do
63
+ p Image.autoload_dirs
64
+ subject { GameObject.new(:image => "rect_20x20.png") }
65
+ end
66
+
67
+ it "should have width,height & size" do
68
+ subject.height.should == 20
69
+ subject.width.should == 20
70
+ subject.size.should == [20,20]
71
+ end
72
+
73
+ it "should adapt width,height & size to scaling" do
74
+ subject.factor = 2
75
+ subject.height.should == 40
76
+ subject.width.should == 40
77
+ subject.size.should == [40,40]
78
+ end
79
+
80
+ it "should adapt factor_x/factor_y to new size" do
81
+ subject.size = [10,40] # half the width, double the height
82
+ subject.height.should == 10
83
+ subject.width.should == 40
84
+ subject.factor_x.should == 0.5
85
+ subject.factor_y.should == 2
86
+ end
87
+
88
+ end
89
+
90
+ after(:all) do
91
+ $window.close
92
+ end
93
+
94
+ end
95
+
96
+ end