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.
- data/History.txt +1 -1
- data/README.rdoc +110 -49
- data/benchmarks/game_objects_benchmark.rb +50 -0
- data/chingu.gemspec +24 -12
- data/examples/example10_traits_retrofy.rb +6 -4
- data/examples/example11_animation.rb +14 -23
- data/examples/example12_trait_timer.rb +1 -1
- data/examples/example13_high_scores.rb +1 -1
- data/examples/example14_bounding_box_circle.rb +6 -10
- data/examples/example15_trait_timer2.rb +1 -1
- data/examples/example16_online_high_scores.rb +1 -1
- data/examples/example17_gosu_tutorial.rb +4 -4
- data/examples/example18_animation_trait.rb +98 -0
- data/examples/example19_edit_viewport.rb +223 -0
- data/examples/example19_game_objects.yml +1591 -0
- data/examples/example20_trait_inheritence_test.rb +58 -0
- data/examples/example3_parallax.rb +1 -1
- data/examples/example4_gamestates.rb +1 -1
- data/examples/example7_gfx_helpers.rb +14 -9
- data/examples/example8_traits.rb +4 -4
- data/examples/example9_collision_detection.rb +1 -1
- data/examples/game1.rb +33 -38
- data/examples/game_of_life.rb +291 -0
- data/examples/media/droid_11x15.bmp +0 -0
- data/examples/media/droid_11x15.gal +0 -0
- data/examples/media/heli.bmp +0 -0
- data/examples/media/heli.gal +0 -0
- data/examples/media/star_25x25_default.png +0 -0
- data/examples/media/star_25x25_explode.gal +0 -0
- data/examples/media/star_25x25_explode.png +0 -0
- data/examples/media/stone_wall.bmp +0 -0
- data/lib/chingu.rb +1 -1
- data/lib/chingu/animation.rb +78 -9
- data/lib/chingu/basic_game_object.rb +16 -8
- data/lib/chingu/game_object.rb +36 -7
- data/lib/chingu/game_object_list.rb +20 -3
- data/lib/chingu/game_state.rb +8 -7
- data/lib/chingu/game_states/edit.rb +177 -90
- data/lib/chingu/helpers/class_inheritable_accessor.rb +12 -5
- data/lib/chingu/helpers/game_object.rb +45 -4
- data/lib/chingu/helpers/gfx.rb +150 -172
- data/lib/chingu/helpers/input_client.rb +7 -0
- data/lib/chingu/inflector.rb +16 -2
- data/lib/chingu/traits/animation.rb +84 -0
- data/lib/chingu/traits/bounding_box.rb +16 -3
- data/lib/chingu/traits/bounding_circle.rb +18 -4
- data/lib/chingu/traits/collision_detection.rb +10 -1
- data/lib/chingu/traits/velocity.rb +26 -3
- data/lib/chingu/traits/viewport.rb +10 -9
- data/lib/chingu/viewport.rb +103 -22
- data/lib/chingu/window.rb +8 -2
- metadata +46 -16
- data/examples/example18_viewport.rb +0 -173
- data/examples/media/city1.csv +0 -2
- data/examples/media/plane.csv +0 -2
- data/examples/media/saucer.csv +0 -4
- data/examples/media/stickfigure.bmp +0 -0
- 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
|
-
|
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
|
-
|
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)
|
data/lib/chingu/viewport.rb
CHANGED
@@ -21,47 +21,128 @@
|
|
21
21
|
|
22
22
|
module Chingu
|
23
23
|
#
|
24
|
-
# A basic
|
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, :
|
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
|
-
@
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
47
|
-
|
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
|
-
@
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
58
|
-
|
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
|
-
|
64
|
-
|
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
|
data/lib/chingu/window.rb
CHANGED
@@ -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)
|