summaryrefslogtreecommitdiffhomepage
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ruby2d/sprite.rb171
1 files changed, 107 insertions, 64 deletions
diff --git a/lib/ruby2d/sprite.rb b/lib/ruby2d/sprite.rb
index 7c66f97..a9d9e98 100644
--- a/lib/ruby2d/sprite.rb
+++ b/lib/ruby2d/sprite.rb
@@ -2,11 +2,12 @@
module Ruby2D
class Sprite
+ include Renderable
- attr_accessor :x, :y, :clip_x, :clip_y, :clip_w, :clip_h, :data
- attr_reader :z
+ attr_accessor :x, :y, :width, :height, :loop,
+ :clip_x, :clip_y, :clip_width, :clip_height, :data
- def initialize(x, y, path, z=0)
+ def initialize(path, opts = {})
unless RUBY_ENGINE == 'opal'
unless File.exists? path
@@ -14,88 +15,130 @@ module Ruby2D
end
end
- @x, @y, @path = x, y, path
- @clip_x, @clip_y, @clip_w, @clip_h = 0, 0, 0, 0
- @default = nil
- @animations = {}
- @current_animation = nil
- @current_frame = 0
- @current_frame_time = 0
- @z = z
-
- ext_init(path)
- if Module.const_defined? :DSL
- Application.add(self)
- end
+ @path = path
+ @x = opts[:x] || 0
+ @y = opts[:y] || 0
+ @z = opts[:z] || 0
+ @width = opts[:width] || nil
+ @height = opts[:height] || nil
+ @start_time = 0.0
+ @loop = opts[:loop] || false
+ @frame_time = opts[:time] || 300
+ @animations = opts[:animations] || {}
+ @playing = false
+ @current_frame = opts[:default] || 0
+ @last_frame = 0
+
+ ext_init(@path)
+ @clip_x = opts[:clip_x] || 0
+ @clip_y = opts[:clip_y] || 0
+ @clip_width = opts[:clip_width] || @width
+ @clip_height = opts[:clip_height] || @height
+ @animations[:default] = 0..(@width / @clip_width) - 1 # set default animation
+
+ @defaults = {
+ animation: @animations.first[0],
+ frame: @current_frame,
+ frame_time: @frame_time,
+ clip_x: @clip_x,
+ clip_y: @clip_y,
+ clip_width: @clip_width,
+ clip_height: @clip_height,
+ loop: @loop
+ }
+
+ add
end
- def start(x, y, w, h)
- @default = [x, y, w, h]
- clip(x, y, w, h)
- end
+ def play(animation = nil, loop = nil)
+ if !@playing || (animation != @playing_animation && animation != nil)
+
+ @playing = true
+ @playing_animation = animation || :default
+ frames = @animations[@playing_animation]
+
+ case frames
+ # When animation is a range, play through frames horizontally
+ when Range
+ @first_frame = frames.first || @defaults[:frame]
+ @current_frame = frames.first || @defaults[:frame]
+ @last_frame = frames.last
+ # When array...
+ when Array
+ @first_frame = 0
+ @current_frame = 0
+ @last_frame = frames.length - 1
+ end
- def add(animations)
- @animations.merge!(animations)
- end
+ # Set looping
+ @loop = loop == :loop || @defaults[:loop] ? true : false
- def animate(animation)
- if @current_animation != animation
- @current_frame = 0
- @current_frame_time = 0
- @current_animation = animation
+ set_frame
+ restart_time
end
- animate_frames(@animations[animation])
end
- def reset
- clip(@default[0], @default[1], @default[2], @default[3])
- @current_animation = nil
+ # Stop the current animation and set to the default frame
+ def stop
+ @playing = false
+ @playing_animation = @defaults[:animation]
+ @current_frame = @defaults[:frame]
+ set_frame
end
- # TODO: Sprite already has an `add` method, have to reconsile
- # def add
- # if Module.const_defined? :DSL
- # Application.add(self)
- # end
- # end
+ # Reset frame to defaults
+ def reset_clipping_rect
+ @clip_x = @defaults[:clip_x]
+ @clip_y = @defaults[:clip_y]
+ @clip_width = @defaults[:clip_width]
+ @clip_height = @defaults[:clip_height]
+ end
- def remove
- if Module.const_defined? :DSL
- Application.remove(self)
+ # Set the position of the clipping retangle based on the current frame
+ def set_frame
+ frames = @animations[@playing_animation]
+ case frames
+ when Range
+ reset_clipping_rect
+ @clip_x = @current_frame * @clip_width
+ when Array
+ f = frames[@current_frame]
+ @clip_x = f[:x] || @defaults[:clip_x]
+ @clip_y = f[:y] || @defaults[:clip_y]
+ @clip_width = f[:width] || @defaults[:clip_width]
+ @clip_height = f[:height] || @defaults[:clip_height]
+ @frame_time = f[:time] || @defaults[:frame_time]
end
end
- def width
- @current_animation ? @animations[@current_animation][@current_frame][2] : @default[2]
+ # Calculate the time in ms
+ def elapsed_time
+ (Time.now.to_f - @start_time) * 1000
end
- def height
- @current_animation ? @animations[@current_animation][@current_frame][3] : @default[3]
+ # Restart the timer
+ def restart_time
+ @start_time = Time.now.to_f
end
- private
+ # Update the sprite animation, called by `Sprite#ext_render`
+ def update
+ if @playing
- def clip(x, y, w, h)
- @clip_x, @clip_y, @clip_w, @clip_h = x, y, w, h
- end
+ # Advance the frame
+ unless elapsed_time <= (@frame_time || @defaults[:frame_time])
+ @current_frame += 1
+ restart_time
+ end
- def animate_frames(frames)
- if @current_frame_time < frames[@current_frame][4]
- clip_with_current_frame(frames)
- @current_frame_time += 1
- else
- @current_frame += 1
- if @current_frame == frames.length
- @current_frame = 0
+ # Reset to the starting frame if all frames played
+ if @current_frame > @last_frame
+ @current_frame = @first_frame
+ unless @loop then stop end
end
- clip_with_current_frame(frames)
- @current_frame_time = 0
- end
- end
- def clip_with_current_frame(frames)
- clip(frames[@current_frame][0], frames[@current_frame][1],
- frames[@current_frame][2], frames[@current_frame][3])
+ set_frame
+ end
end
end