chingu 0.7.0 → 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|