chingu 0.8.0.5 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/benchmarks/array_vs_hash.rb +20 -0
- data/benchmarks/game_object_list_benchmark.rb +92 -0
- data/benchmarks/game_objects_benchmark.rb +48 -12
- data/benchmarks/lookup_benchmark.rb +9 -0
- data/benchmarks/trait_benchmark.rb +62 -0
- data/benchmarks/window_benchmark.rb +37 -0
- data/chingu.gemspec +10 -2
- data/examples/example17_gosu_tutorial.rb +3 -2
- data/examples/example21_sidescroller_with_edit.rb +6 -4
- data/examples/example23_chipmunk.rb +1 -0
- data/lib/chingu.rb +1 -1
- data/lib/chingu/animation.rb +2 -1
- data/lib/chingu/basic_game_object.rb +25 -9
- data/lib/chingu/game_object_list.rb +42 -26
- data/lib/chingu/game_object_map.rb +31 -8
- data/lib/chingu/helpers/game_object.rb +14 -0
- data/lib/chingu/traits/retrofy.rb +18 -10
- data/lib/chingu/traits/simple_sprite.rb +252 -0
- data/lib/chingu/traits/sprite.rb +22 -11
- data/spec/chingu/basic_game_object_spec.rb +27 -11
- data/spec/chingu/console_spec.rb +5 -1
- data/spec/chingu/game_object_list_spec.rb +19 -1
- data/spec/chingu/game_object_map_spec.rb +96 -0
- data/spec/chingu/game_object_spec.rb +2 -0
- metadata +11 -4
@@ -8,6 +8,8 @@ module Chingu
|
|
8
8
|
# It will also acts as a container for the trait-system of chingu.
|
9
9
|
#
|
10
10
|
class BasicGameObject
|
11
|
+
class << self; attr_accessor :instances; end
|
12
|
+
|
11
13
|
include Chingu::Helpers::ClassInheritableAccessor # adds classmethod class_inheritable_accessor
|
12
14
|
|
13
15
|
attr_reader :options, :paused
|
@@ -16,7 +18,7 @@ module Chingu
|
|
16
18
|
class_inheritable_accessor :trait_options
|
17
19
|
@trait_options = Hash.new
|
18
20
|
def trait_options; self.class.trait_options; end
|
19
|
-
|
21
|
+
|
20
22
|
#
|
21
23
|
# Adds a trait or traits to a certain game class
|
22
24
|
# Executes a standard ruby "include" the specified module
|
@@ -66,7 +68,10 @@ module Chingu
|
|
66
68
|
def initialize(options = {})
|
67
69
|
@options = options
|
68
70
|
@parent = options[:parent]
|
69
|
-
|
71
|
+
|
72
|
+
self.class.instances ||= Array.new
|
73
|
+
self.class.instances << self
|
74
|
+
|
70
75
|
#
|
71
76
|
# A GameObject either belong to a GameState or our mainwindow ($window)
|
72
77
|
#
|
@@ -79,7 +84,7 @@ module Chingu
|
|
79
84
|
# which then will pass it on to the next setup_trait() with a super-call.
|
80
85
|
setup_trait(options)
|
81
86
|
|
82
|
-
setup
|
87
|
+
setup
|
83
88
|
end
|
84
89
|
|
85
90
|
#
|
@@ -99,6 +104,12 @@ module Chingu
|
|
99
104
|
#
|
100
105
|
instance.parent.add_game_object(instance) if instance.parent
|
101
106
|
|
107
|
+
#
|
108
|
+
# Keep track of instances in class-variable
|
109
|
+
# Used for quick access to all isntances of a certain class, for example Enemy.all
|
110
|
+
#
|
111
|
+
#instances ||= Array.new
|
112
|
+
#instances << instance
|
102
113
|
|
103
114
|
return instance
|
104
115
|
end
|
@@ -107,6 +118,7 @@ module Chingu
|
|
107
118
|
# Disable automatic calling of update() and update_trait() each game loop
|
108
119
|
#
|
109
120
|
def pause!
|
121
|
+
@parent.game_objects.pause_game_object(self) if @parent && @paused == false
|
110
122
|
@paused = true
|
111
123
|
end
|
112
124
|
alias :pause :pause!
|
@@ -115,6 +127,7 @@ module Chingu
|
|
115
127
|
# Enable automatic calling of update() and update_trait() each game loop
|
116
128
|
#
|
117
129
|
def unpause!
|
130
|
+
@parent.game_objects.unpause_game_object(self) if @parent && @paused == true
|
118
131
|
@paused = false
|
119
132
|
end
|
120
133
|
alias :unpause :unpause!
|
@@ -153,8 +166,10 @@ module Chingu
|
|
153
166
|
# Bullet.all.each do {} # Iterate through all bullets in current game state
|
154
167
|
#
|
155
168
|
def self.all
|
156
|
-
|
157
|
-
|
169
|
+
instances ? instances.dup : []
|
170
|
+
# instances ? instances.keys : [] # for hash instance
|
171
|
+
# $window.current_scope.game_objects.of_class(self).dup # old school way
|
172
|
+
end
|
158
173
|
|
159
174
|
#
|
160
175
|
# As Array.each on the instances of the current class
|
@@ -177,12 +192,11 @@ module Chingu
|
|
177
192
|
all.select { |object| yield object }
|
178
193
|
end
|
179
194
|
|
180
|
-
|
181
195
|
#
|
182
196
|
# Returns the total amount of game objects based on this class
|
183
197
|
#
|
184
198
|
def self.size
|
185
|
-
|
199
|
+
all.size
|
186
200
|
end
|
187
201
|
|
188
202
|
#
|
@@ -200,7 +214,8 @@ module Chingu
|
|
200
214
|
# Bullet.destroy_all # Removes all Bullet objects from the game
|
201
215
|
#
|
202
216
|
def self.destroy_all
|
203
|
-
|
217
|
+
all.each { |game_object| game_object.parent.remove_game_object(game_object) }
|
218
|
+
instances.clear if instances
|
204
219
|
end
|
205
220
|
|
206
221
|
#
|
@@ -208,7 +223,8 @@ module Chingu
|
|
208
223
|
# If the object isn't being managed by Chingu (ie. you're doing manual update/draw calls) the object is only frozen, not removed from any updae cycle (because you are controlling that).
|
209
224
|
#
|
210
225
|
def destroy
|
211
|
-
@parent.remove_game_object(self)
|
226
|
+
@parent.remove_game_object(self) if @parent
|
227
|
+
self.class.instances.delete(self)
|
212
228
|
end
|
213
229
|
alias :destroy! :destroy
|
214
230
|
end
|
@@ -26,11 +26,16 @@ module Chingu
|
|
26
26
|
# An instance of GameObjectList is automaticly created as "game_objects" if using Chingu::Window
|
27
27
|
#
|
28
28
|
class GameObjectList
|
29
|
+
attr_reader :visible_game_objects, :unpaused_game_objects
|
29
30
|
|
30
31
|
def initialize(options = {})
|
31
32
|
@game_objects = options[:game_objects] || []
|
32
|
-
@
|
33
|
-
@
|
33
|
+
@visible_game_objects = []
|
34
|
+
@unpaused_game_objects = []
|
35
|
+
|
36
|
+
#@game_objects = {}
|
37
|
+
#@visible_game_objects = {}
|
38
|
+
#@unpaused_game_objects = {}
|
34
39
|
end
|
35
40
|
|
36
41
|
def to_s
|
@@ -42,23 +47,42 @@ module Chingu
|
|
42
47
|
end
|
43
48
|
|
44
49
|
def destroy_all
|
45
|
-
@game_objects.
|
50
|
+
@game_objects.each { |game_object| game_object.destroy }
|
46
51
|
end
|
47
52
|
alias :clear :destroy_all
|
48
53
|
alias :remove_all :destroy_all
|
49
54
|
|
55
|
+
def show_game_object(object)
|
56
|
+
@visible_game_objects.push(object)
|
57
|
+
end
|
58
|
+
def hide_game_object(object)
|
59
|
+
@visible_game_objects.delete(object)
|
60
|
+
end
|
61
|
+
def pause_game_object(object)
|
62
|
+
@unpaused_game_objects.delete(object)
|
63
|
+
end
|
64
|
+
def unpause_game_object(object)
|
65
|
+
@unpaused_game_objects.push(object)
|
66
|
+
end
|
67
|
+
|
50
68
|
def add_game_object(object)
|
51
69
|
@game_objects.push(object)
|
52
|
-
|
70
|
+
@visible_game_objects.push(object) if object.respond_to?(:visible) && object.visible
|
71
|
+
@unpaused_game_objects.push(object) if object.respond_to?(:paused) && !object.paused
|
72
|
+
|
73
|
+
#@game_objects[object] = true
|
74
|
+
#@visible_game_objects[object] = true if object.respond_to?(:visible) && object.visible
|
75
|
+
#@unpaused_game_objects[object] = true if object.respond_to?(:paused) && !object.paused
|
53
76
|
end
|
54
77
|
|
55
78
|
def remove_game_object(object)
|
56
79
|
@game_objects.delete(object)
|
57
|
-
|
80
|
+
@visible_game_objects.delete(object)
|
81
|
+
@unpaused_game_objects.delete(object)
|
58
82
|
end
|
59
83
|
|
60
84
|
def destroy_if
|
61
|
-
@game_objects.
|
85
|
+
@game_objects.select { |object| object.destroy if yield(object) }
|
62
86
|
end
|
63
87
|
|
64
88
|
def size
|
@@ -68,27 +92,28 @@ module Chingu
|
|
68
92
|
def empty?
|
69
93
|
@game_objects.empty?
|
70
94
|
end
|
95
|
+
|
96
|
+
def update
|
97
|
+
@unpaused_game_objects.each { |go| go.update_trait; go.update; }
|
98
|
+
end
|
99
|
+
def force_update
|
100
|
+
@game_objects.each { |go| go.update_trait; go.update; }
|
101
|
+
end
|
71
102
|
|
72
103
|
def draw
|
73
|
-
@
|
74
|
-
|
75
|
-
|
76
|
-
|
104
|
+
@visible_game_objects.each { |go| go.draw_trait; go.draw; }
|
105
|
+
end
|
106
|
+
def force_draw
|
107
|
+
@game_objects.each { |go| go.draw_trait; go.draw }
|
77
108
|
end
|
78
109
|
|
79
110
|
def draw_relative(x=0, y=0, zorder=0, angle=0, center_x=0, center_y=0, factor_x=0, factor_y=0)
|
80
|
-
@
|
111
|
+
@visible_game_objects.each do |object|
|
81
112
|
object.draw_trait
|
82
113
|
object.draw_relative(x, y, zorder, angle, center_x, center_y, factor_x, factor_y)
|
83
114
|
end
|
84
115
|
end
|
85
116
|
|
86
|
-
def update
|
87
|
-
@game_objects.select { |object| not object.paused }.each do |object|
|
88
|
-
object.update_trait
|
89
|
-
object.update
|
90
|
-
end
|
91
|
-
end
|
92
117
|
|
93
118
|
def each
|
94
119
|
@game_objects.dup.each { |object| yield object }
|
@@ -146,14 +171,5 @@ module Chingu
|
|
146
171
|
end
|
147
172
|
alias :show :show!
|
148
173
|
|
149
|
-
private
|
150
|
-
|
151
|
-
def sync
|
152
|
-
@game_objects += @add_game_objects
|
153
|
-
@add_game_objects.clear
|
154
|
-
|
155
|
-
@game_objects -= @remove_game_objects
|
156
|
-
@remove_game_objects.clear
|
157
|
-
end
|
158
174
|
end
|
159
175
|
end
|
@@ -23,14 +23,32 @@ module Chingu
|
|
23
23
|
#
|
24
24
|
# ** This class is under heavy development, API will most likely change! **
|
25
25
|
#
|
26
|
-
# GameObjectMap can
|
27
|
-
# You can
|
26
|
+
# GameObjectMap can map any set of game objects into a 2D-array for fast lookup.
|
27
|
+
# You can choose gridsize with the :grid-parameter, defaults to [32,32].
|
28
|
+
# The smaller the grid the more memory GameObjectMap will eat.
|
29
|
+
#
|
30
|
+
# The game objects sent to GameObjectMap must respond to #bb (as provided by trait :bounding_box)
|
31
|
+
# This is needed to calcuate what cells in the grid each game object covers.
|
28
32
|
#
|
29
33
|
# Basic usage:
|
30
34
|
# @map = GameObjectMap.new(:game_objects => TerrainObject.all, :grid => [32, 32])
|
31
35
|
# @map.at(100, 100) # returns one TerrainObject at x/y: 100/100
|
32
36
|
# @map.game_object(player) # returns one TerrainObject which collides with player.bounding_box
|
33
37
|
#
|
38
|
+
# A GameObjectMap is ment to be used for static non-moving objects, where a map can be calculated once and then used for fast lookups.
|
39
|
+
# This makes GameObjectMap very well suited for terrain for a player to walk on / collide with.
|
40
|
+
#
|
41
|
+
# One cell in the GameObjectMap can only be occupied by one game object.
|
42
|
+
# If you need many objects at the same cell, use 2 GameObjectMaps, something like:
|
43
|
+
#
|
44
|
+
# @terrain = GameObjectMap.new(:game_objects => Terrain.all)
|
45
|
+
# @mines = GameObjectMap.new(:game_objects => Mine.all)
|
46
|
+
#
|
47
|
+
# @player.stop_falling if @terrain.at(@player.x, @player)
|
48
|
+
# @player.die if @mine.at(@player.x, @player)
|
49
|
+
#
|
50
|
+
# Take note, since there can be only 1 game object per cell a huge game object could very well "cover out" another smaller game objects occupying the same cells.
|
51
|
+
#
|
34
52
|
# ** This class is under heavy development, API will most likely change! **
|
35
53
|
#
|
36
54
|
class GameObjectMap
|
@@ -52,7 +70,7 @@ module Chingu
|
|
52
70
|
@game_object_positions = {}
|
53
71
|
|
54
72
|
@game_objects.each do |game_object|
|
55
|
-
puts "#{game_object.class} @ #{game_object.x}
|
73
|
+
puts "#{game_object.class} @ #{game_object.x}/#{game_object.y} - #{game_object.bb}" if @debug
|
56
74
|
insert(game_object)
|
57
75
|
end
|
58
76
|
end
|
@@ -73,15 +91,17 @@ module Chingu
|
|
73
91
|
@map[x] ||= []
|
74
92
|
(start_y ... stop_y).each do |y|
|
75
93
|
@map[x][y] = game_object
|
94
|
+
puts "#{game_object.class} => map[#{x}][#{y}]" if @debug
|
76
95
|
end
|
77
96
|
end
|
78
97
|
end
|
79
98
|
|
80
99
|
#
|
81
|
-
# Removes a specific game object from the map
|
100
|
+
# Removes a specific game object from the map, replace the cell-value with nil
|
82
101
|
#
|
83
102
|
def delete(game_object)
|
84
103
|
range_x, range_y = @game_object_positions[game_object]
|
104
|
+
return unless range_x && range_y
|
85
105
|
|
86
106
|
range_x.each do |x|
|
87
107
|
range_y.each do |y|
|
@@ -92,7 +112,7 @@ module Chingu
|
|
92
112
|
alias :clear_game_object :delete
|
93
113
|
|
94
114
|
#
|
95
|
-
# Clear game object
|
115
|
+
# Clear the game object residing in the cell given by real world coordinates x/y
|
96
116
|
#
|
97
117
|
def clear_at(x, y)
|
98
118
|
lookup_x = (x / @grid[0]).to_i
|
@@ -101,14 +121,17 @@ module Chingu
|
|
101
121
|
end
|
102
122
|
|
103
123
|
#
|
104
|
-
# Gets
|
124
|
+
# Gets game object from map that resides on real world coordinates x/y
|
105
125
|
#
|
106
126
|
def at(x, y)
|
107
127
|
lookup_x = (x / @grid[0]).to_i
|
108
128
|
lookup_y = (y / @grid[1]).to_i
|
109
|
-
@map[lookup_x][lookup_y] rescue nil
|
129
|
+
@map[lookup_x][lookup_y] rescue nil # Benchmark this against @map[lookup_x] && @map[lookup_x][lookup_y] => prob faster
|
110
130
|
end
|
111
131
|
|
132
|
+
#
|
133
|
+
# Return the first game object occupying any of the cells that given 'game_object' covers
|
134
|
+
#
|
112
135
|
def from_game_object(game_object)
|
113
136
|
start_x = (game_object.bb.left / @grid[0]).to_i
|
114
137
|
stop_x = (game_object.bb.right / @grid[0]).to_i
|
@@ -126,7 +149,7 @@ module Chingu
|
|
126
149
|
end
|
127
150
|
|
128
151
|
#
|
129
|
-
# Yields
|
152
|
+
# Yields all game objects occupying any of the cells that given 'game_object' covers
|
130
153
|
#
|
131
154
|
def each_collision(game_object)
|
132
155
|
start_x = (game_object.bb.left / @grid[0]).to_i
|
@@ -40,6 +40,20 @@ module Chingu
|
|
40
40
|
@game_objects
|
41
41
|
end
|
42
42
|
|
43
|
+
def show_game_object(object)
|
44
|
+
@game_objects.show_game_object(object)
|
45
|
+
end
|
46
|
+
def hide_game_object(object)
|
47
|
+
@game_objects.hide_game_object(object)
|
48
|
+
end
|
49
|
+
def pause_game_object(object)
|
50
|
+
@game_objects.pause_game_object(object)
|
51
|
+
end
|
52
|
+
def unpause_game_object(object)
|
53
|
+
@game_objects.unpause_game_object(object)
|
54
|
+
end
|
55
|
+
|
56
|
+
|
43
57
|
#
|
44
58
|
# Fetch game objects of a certain type/class
|
45
59
|
#
|
@@ -29,24 +29,32 @@ module Chingu
|
|
29
29
|
#
|
30
30
|
module Retrofy
|
31
31
|
|
32
|
-
def setup_trait(options)
|
33
|
-
|
34
|
-
|
32
|
+
#def setup_trait(options)
|
33
|
+
# @retrofy_options = {:debug => false}.merge(options)
|
34
|
+
# super
|
35
|
+
#end
|
36
|
+
|
37
|
+
def retrofied_x=(x)
|
38
|
+
self.x = x / self.factor
|
35
39
|
end
|
36
|
-
|
37
|
-
def
|
38
|
-
|
40
|
+
|
41
|
+
def retrofied_y=(y)
|
42
|
+
self.y = y / self.factor
|
43
|
+
end
|
44
|
+
|
45
|
+
def real_x
|
46
|
+
(self.x / self.factor).to_i
|
39
47
|
end
|
40
48
|
|
41
|
-
def
|
42
|
-
(self.
|
49
|
+
def real_y
|
50
|
+
(self.y / self.factor).to_i
|
43
51
|
end
|
44
52
|
|
45
|
-
def
|
53
|
+
def retrofied_x
|
46
54
|
(self.x * self.factor).to_i
|
47
55
|
end
|
48
56
|
|
49
|
-
def
|
57
|
+
def retrofied_y
|
50
58
|
(self.y * self.factor).to_i
|
51
59
|
end
|
52
60
|
|
@@ -0,0 +1,252 @@
|
|
1
|
+
#--
|
2
|
+
# Part of Chingu -- OpenGL accelerated 2D game framework for Ruby
|
3
|
+
# Copyright (C) 2009 ippa / ippa@rubylicio.us
|
4
|
+
#
|
5
|
+
# Written/Refactored by Jakub Hozak - jakub.hozak@gmail.com
|
6
|
+
#
|
7
|
+
#++
|
8
|
+
|
9
|
+
module Chingu
|
10
|
+
module Traits
|
11
|
+
|
12
|
+
#
|
13
|
+
# A Chingu trait providing ability to be drawn as an image.
|
14
|
+
#
|
15
|
+
# Example:
|
16
|
+
#
|
17
|
+
# class Rocket < BasicGameObject
|
18
|
+
# trait :simple_sprite
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Rocket.create(:x => 100, :y => 200)
|
22
|
+
#
|
23
|
+
# Options:
|
24
|
+
# :image - actual sprite to draw
|
25
|
+
# - see #image= for details as this method is used to set this option
|
26
|
+
#
|
27
|
+
# Introducing Variables:
|
28
|
+
# :x, :y, :zorder, :factor_x, :factor_y, :mode, :color, :visible
|
29
|
+
#
|
30
|
+
module SimpleSprite
|
31
|
+
module ClassMethods
|
32
|
+
def initialize_trait(options = {})
|
33
|
+
trait_options[:sprite] = options
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_accessor :x, :y, :angle, :factor_x, :factor_y, :zorder, :mode, :color
|
38
|
+
attr_reader :factor, :center, :height, :width, :image
|
39
|
+
attr_accessor :visible # kill this? force use of setter
|
40
|
+
|
41
|
+
def setup_trait(object_options = {})
|
42
|
+
@visible = true unless options[:visible] == false
|
43
|
+
self.image = options[:image] if options[:image]
|
44
|
+
self.color = options[:color] || ::Gosu::Color::WHITE.dup
|
45
|
+
self.alpha = options[:alpha] if options[:alpha]
|
46
|
+
self.mode = options[:mode] || :default
|
47
|
+
self.x = options[:x] || 0
|
48
|
+
self.y = options[:y] || 0
|
49
|
+
self.zorder = options[:zorder] || 100
|
50
|
+
|
51
|
+
self.factor = options[:factor] || options[:scale] || $window.factor || 1.0
|
52
|
+
self.factor_x = options[:factor_x].to_f if options[:factor_x]
|
53
|
+
self.factor_y = options[:factor_y].to_f if options[:factor_y]
|
54
|
+
|
55
|
+
if self.image
|
56
|
+
self.width = options[:width] if options[:width]
|
57
|
+
self.height = options[:height] if options[:height]
|
58
|
+
self.size = options[:size] if options[:size]
|
59
|
+
end
|
60
|
+
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Let's have some useful information in to_s()
|
66
|
+
#
|
67
|
+
def to_s
|
68
|
+
"#{self.class.to_s} @ #{x.to_i} / #{y.to_i} " <<
|
69
|
+
"(#{width.to_i} x #{height.to_i}) - " <<
|
70
|
+
" ratio: #{sprintf("%.2f",width/height)} scale: #{sprintf("%.2f", factor_x)}/#{sprintf("%.2f", factor_y)} angle: #{angle.to_i} zorder: #{zorder} alpha: #{alpha}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def color=(color)
|
74
|
+
@color = color.is_a?(Gosu::Color) ? color : Gosu::Color.new(color || 0xFFFFFFFF)
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Accepts String, callable object or any-other non-nil capable
|
79
|
+
# of drawing itself on screen.
|
80
|
+
#
|
81
|
+
# Examples:
|
82
|
+
# image = 'rocket.png'
|
83
|
+
# image = Gosu::Image.new($window, 'rocket.png')
|
84
|
+
#
|
85
|
+
# image = lambda do
|
86
|
+
# # TexPlay is library for Gosu image generation
|
87
|
+
# TexPlay.create_image($window,10,10).paint { circle(5,5,5, :color => :red) }
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
def image=(image)
|
91
|
+
raise ArgumentError.new("No image set") if image.nil?
|
92
|
+
|
93
|
+
@image = if String === image
|
94
|
+
# 1) Try loading the image the normal way
|
95
|
+
# 2) Try looking up the picture using Chingus Image-cache
|
96
|
+
Gosu::Image.new($window, image,false) rescue Gosu::Image[image]
|
97
|
+
elsif image.respond_to? :call
|
98
|
+
image.call
|
99
|
+
else
|
100
|
+
image
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Get all settings from a game object in one array.
|
106
|
+
# Complemented by the GameObject#attributes= setter.
|
107
|
+
# Makes it easy to clone a objects x,y,angle etc.
|
108
|
+
#
|
109
|
+
def attributes
|
110
|
+
[@x, @y, @angle, @factor_x, @factor_y, @color, @mode, @zorder]
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Set all attributes on 1 line
|
115
|
+
# Mainly used in combination with game_object1.attributes = game_object2.attributes
|
116
|
+
#
|
117
|
+
def attributes=(attributes)
|
118
|
+
self.x, self.y, self.angle, self.factor_x, self.factor_y, self.color, self.mode, self.zorder = *attributes
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Set an effective width for the object on screen.
|
123
|
+
# Chingu does this by setting factor_x depending on imge.width and width given.
|
124
|
+
# Usually better to have a large image and make it smaller then the other way around.
|
125
|
+
#
|
126
|
+
def width=(width)
|
127
|
+
@factor_x = width.to_f / @image.width.to_f if @image
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
# Get effective width by calculating it from image-width and factor_x
|
132
|
+
#
|
133
|
+
def width
|
134
|
+
(@image.width * @factor_x).abs if @image
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
# Set an effective height for the object on screen.
|
139
|
+
# Chingu does this by setting factor_x depending on imge.width and width given.
|
140
|
+
# Usually better to have a large image and make it smaller then the other way around.
|
141
|
+
#
|
142
|
+
def height=(height)
|
143
|
+
@factor_y = height.to_f / @image.height.to_f if @image
|
144
|
+
end
|
145
|
+
|
146
|
+
#
|
147
|
+
# Get effective height by calculating it from image-width and factor
|
148
|
+
#
|
149
|
+
def height
|
150
|
+
(@image.height.to_f * @factor_y).abs if @image
|
151
|
+
end
|
152
|
+
|
153
|
+
# Set width and height in one swoop
|
154
|
+
def size=(size)
|
155
|
+
self.width, self.height = *size
|
156
|
+
end
|
157
|
+
|
158
|
+
# Get objects width and height in an array
|
159
|
+
def size
|
160
|
+
[self.width, self.height]
|
161
|
+
end
|
162
|
+
|
163
|
+
# Quick way of setting both factor_x and factor_y
|
164
|
+
def factor=(factor)
|
165
|
+
@factor = @factor_x = @factor_y = factor
|
166
|
+
end
|
167
|
+
alias scale= factor=
|
168
|
+
alias scale factor
|
169
|
+
|
170
|
+
|
171
|
+
# Get objects alpha-value (internally stored in @color.alpha)
|
172
|
+
def alpha
|
173
|
+
@color.alpha
|
174
|
+
end
|
175
|
+
|
176
|
+
# Set objects alpha-value (internally stored in @color.alpha)
|
177
|
+
# If out of range, set to closest working value. this makes fading simpler.
|
178
|
+
def alpha=(value)
|
179
|
+
value = 0 if value < 0
|
180
|
+
value = 255 if value > 255
|
181
|
+
@color.alpha = value
|
182
|
+
end
|
183
|
+
|
184
|
+
#
|
185
|
+
# Sets angle, normalize it to between 0..360
|
186
|
+
#
|
187
|
+
def angle=(value)
|
188
|
+
if value < 0
|
189
|
+
value = 360+value
|
190
|
+
elsif value > 360
|
191
|
+
value = value-360
|
192
|
+
end
|
193
|
+
@angle = value
|
194
|
+
end
|
195
|
+
|
196
|
+
#
|
197
|
+
# Disable automatic calling of draw and draw_trait each game loop
|
198
|
+
#
|
199
|
+
def hide!
|
200
|
+
@parent.game_objects.hide_game_object(self) if @parent && @visible == true
|
201
|
+
@visible = false
|
202
|
+
end
|
203
|
+
|
204
|
+
#
|
205
|
+
# Enable automatic calling of draw and draw_trait each game loop
|
206
|
+
#
|
207
|
+
def show!
|
208
|
+
@parent.game_objects.show_game_object(self) if @parent && @visible == false
|
209
|
+
@visible = true
|
210
|
+
end
|
211
|
+
|
212
|
+
#
|
213
|
+
# Returns true if visible (not hidden)
|
214
|
+
#
|
215
|
+
def visible?
|
216
|
+
@visible == true
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
# Returns true if object is inside the game window, false if outside
|
221
|
+
def inside_window?(x = @x, y = @y)
|
222
|
+
x >= 0 && x <= $window.width && y >= 0 && y <= $window.height
|
223
|
+
end
|
224
|
+
|
225
|
+
# Returns true object is outside the game window
|
226
|
+
def outside_window?(x = @x, y = @y)
|
227
|
+
not inside_window?(x,y)
|
228
|
+
end
|
229
|
+
|
230
|
+
#
|
231
|
+
# Our encapsulation of GOSU's image.draw_rot, uses the objects variables to draw it on screen if @visible is true
|
232
|
+
#
|
233
|
+
def draw
|
234
|
+
@image.draw(@x, @y, @zorder, @factor_x, @factor_y, @color, @mode) if @image
|
235
|
+
end
|
236
|
+
|
237
|
+
#
|
238
|
+
# Works as #draw() but takes offsets for all draw_rot()-arguments. Used among others by the viewport-trait.
|
239
|
+
#
|
240
|
+
def draw_relative(x=0, y=0, zorder=0, factor_x=0, factor_y=0)
|
241
|
+
@image.draw(@x+x, @y+y, @zorder+zorder, @factor_x+factor_x, @factor_y+factor_y, @color, @mode) if @image
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# Works as #draw() but takes x/y arguments. Used among others by the edit-game state.
|
246
|
+
#
|
247
|
+
def draw_at(x, y)
|
248
|
+
draw_relative(x,y)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|