summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTom Black <[email protected]>2018-09-04 00:45:00 -0700
committerTom Black <[email protected]>2018-09-12 14:40:27 -0700
commit632e007e711ba8e4e7d9b3a39cd64e32ca58afd1 (patch)
treed28aeacc312c2e736ceb2028f21c234738cbfbf5
parent36754d58e1e17c11cc243f896d63cd9e1daf95ed (diff)
downloadruby2d-632e007e711ba8e4e7d9b3a39cd64e32ca58afd1.tar.gz
ruby2d-632e007e711ba8e4e7d9b3a39cd64e32ca58afd1.zip
Sprite enhancements
Add ability to flip the sprite, run a block after an animation, properly change the width and height, and other fixes.
-rw-r--r--ext/ruby2d/ruby2d.c20
-rw-r--r--lib/ruby2d/sprite.rb131
-rw-r--r--test/sprite.rb62
-rw-r--r--test/testcard.rb17
4 files changed, 180 insertions, 50 deletions
diff --git a/ext/ruby2d/ruby2d.c b/ext/ruby2d/ruby2d.c
index b44ba58..74c7823 100644
--- a/ext/ruby2d/ruby2d.c
+++ b/ext/ruby2d/ruby2d.c
@@ -368,14 +368,10 @@ static R_VAL ruby2d_sprite_ext_init(R_VAL self, R_VAL path) {
S2D_Log(S2D_INFO, "Init sprite: %s", RSTRING_PTR(path));
S2D_Sprite *spr = S2D_CreateSprite(RSTRING_PTR(path));
- // Get width and height from Ruby class. If set, use it, else choose the
- // native dimensions of the sprite image.
- R_VAL w = r_iv_get(self, "@width");
- R_VAL h = r_iv_get(self, "@height");
- r_iv_set(self, "@width" , r_test(w) ? w : INT2NUM(spr->width));
- r_iv_set(self, "@height", r_test(h) ? h : INT2NUM(spr->height));
-
+ r_iv_set(self, "@img_width" , INT2NUM(spr->width));
+ r_iv_set(self, "@img_height", INT2NUM(spr->height));
r_iv_set(self, "@data", r_data_wrap_struct(sprite, spr));
+
return R_NIL;
}
@@ -393,8 +389,14 @@ static R_VAL ruby2d_sprite_ext_render(R_VAL self) {
S2D_Sprite *spr;
r_data_get_struct(self, "@data", &sprite_data_type, S2D_Sprite, spr);
- spr->x = NUM2DBL(r_iv_get(self, "@x"));
- spr->y = NUM2DBL(r_iv_get(self, "@y"));
+ spr->x = NUM2DBL(r_iv_get(self, "@flip_x"));
+ spr->y = NUM2DBL(r_iv_get(self, "@flip_y"));
+
+ R_VAL w = r_iv_get(self, "@flip_width");
+ if (r_test(w)) spr->width = NUM2DBL(w);
+
+ R_VAL h = r_iv_get(self, "@flip_height");
+ if (r_test(h)) spr->height = NUM2DBL(h);
S2D_ClipSprite(
spr,
diff --git a/lib/ruby2d/sprite.rb b/lib/ruby2d/sprite.rb
index a9d9e98..f2d7075 100644
--- a/lib/ruby2d/sprite.rb
+++ b/lib/ruby2d/sprite.rb
@@ -15,26 +15,34 @@ module Ruby2D
end
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
+ @path = path
+ @x = opts[:x] || 0
+ @y = opts[:y] || 0
+ @z = opts[:z] || 0
+ @flip_x = @x
+ @flip_y = @y
+ @width = opts[:width] || nil
+ @height = opts[:height] || nil
+ @flip_width = @width
+ @flip_height = @height
+ @clip_x = opts[:clip_x] || 0
+ @clip_y = opts[:clip_y] || 0
+ @rotate = 0
+ @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
+ @last_frame = 0
+ @flip = nil
+ @done_proc = nil
+ @img_width = nil; @img_height = nil # set by `ext_init`
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
+ @clip_width = opts[:clip_width] || @img_width
+ @clip_height = opts[:clip_height] || @img_height
+ @animations[:default] = 0..(@img_width / @clip_width) - 1 # set default animation
@defaults = {
animation: @animations.first[0],
@@ -50,12 +58,47 @@ module Ruby2D
add
end
- def play(animation = nil, loop = nil)
- if !@playing || (animation != @playing_animation && animation != nil)
+ # Set the x coordinate
+ def x=(x)
+ @x = @flip_x = x
+ if @flip == :flip_h || @flip == :flip_hv
+ @flip_x = x + @width
+ end
+ end
+
+ # Set the y coordinate
+ def y=(y)
+ @y = @flip_y = y
+ if @flip == :flip_v || @flip == :flip_hv
+ @flip_y = y + @height
+ end
+ end
+
+ # Set the width
+ def width=(width)
+ @width = @flip_width = width
+ if @flip == :flip_h || @flip == :flip_hv
+ @flip_width = -width
+ end
+ end
+
+ # Set the height
+ def height=(height)
+ @height = @flip_height = height
+ if @flip == :flip_v || @flip == :flip_hv
+ @flip_height = -height
+ end
+ end
+
+ # Play an animation
+ def play(animation = nil, loop = nil, flip = nil, &done_proc)
+ if !@playing || (animation != @playing_animation && animation != nil) || flip != @flip
@playing = true
@playing_animation = animation || :default
frames = @animations[@playing_animation]
+ flip_sprite(flip)
+ @done_proc = done_proc
case frames
# When animation is a range, play through frames horizontally
@@ -79,11 +122,42 @@ module Ruby2D
end
# Stop the current animation and set to the default frame
- def stop
- @playing = false
- @playing_animation = @defaults[:animation]
- @current_frame = @defaults[:frame]
- set_frame
+ def stop(animation = nil)
+ if !animation || animation == @playing_animation
+ @playing = false
+ @playing_animation = @defaults[:animation]
+ @current_frame = @defaults[:frame]
+ set_frame
+ end
+ end
+
+ # Flip the sprite
+ def flip_sprite(flip)
+
+ # A width and height must be set for the sprite for this to work
+ unless @width && @height then return end
+
+ @flip = flip
+
+ # Reset flip values
+ @flip_x = @x
+ @flip_y = @y
+ @flip_width = @width
+ @flip_height = @height
+
+ case flip
+ when :flip_h # horizontal
+ @flip_x = @x + @width
+ @flip_width = -@width
+ when :flip_v # vertical
+ @flip_y = @y + @height
+ @flip_height = -@height
+ when :flip_hv # horizontal and vertical
+ @flip_x = @x + @width
+ @flip_width = -@width
+ @flip_y = @y + @height
+ @flip_height = -@height
+ end
end
# Reset frame to defaults
@@ -107,7 +181,7 @@ module Ruby2D
@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]
+ @frame_time = f[:time] || @defaults[:frame_time]
end
end
@@ -134,7 +208,12 @@ module Ruby2D
# Reset to the starting frame if all frames played
if @current_frame > @last_frame
@current_frame = @first_frame
- unless @loop then stop end
+ unless @loop
+ # Stop animation and play block, if provided
+ stop
+ if @done_proc then @done_proc.call end
+ @done_proc = nil
+ end
end
set_frame
diff --git a/test/sprite.rb b/test/sprite.rb
index 713375a..e62488b 100644
--- a/test/sprite.rb
+++ b/test/sprite.rb
@@ -6,17 +6,28 @@ else
media = "media"
end
-set title: "Ruby 2D — Sprite", width: 350, height: 150
+set title: "Ruby 2D — Sprite", width: 400, height: 300
+coin1 = Sprite.new(
+ "#{media}/coin.png",
+ clip_width: 84,
+ time: 300,
+ loop: true
+)
+
+coin1.play
-coin = Sprite.new(
+coin2 = Sprite.new(
"#{media}/coin.png",
+ y: 90,
+ width: 42,
+ height: 42,
clip_width: 84,
time: 300,
loop: true
)
-coin.play
+coin2.play
boom = Sprite.new(
"#{media}/boom.png",
@@ -28,6 +39,8 @@ boom = Sprite.new(
hero = Sprite.new(
"#{media}/hero.png",
x: 261,
+ width: 78,
+ height: 99,
clip_width: 78,
time: 250,
animations: {
@@ -39,7 +52,7 @@ hero = Sprite.new(
atlas = Sprite.new(
"#{media}/texture_atlas.png",
- x: 10, y: 100,
+ x: 50, y: 90,
animations: {
count: [
{
@@ -79,21 +92,58 @@ on :key_down do |e|
case e.key
when 'p'
- coin.play
+ coin1.play
+ coin2.play
boom.play
atlas.play :count
+ when 'b'
+ boom.play nil, nil, nil do
+ puts "Boom animation finished!"
+ end
when 's'
- coin.stop
+ coin1.stop
+ coin2.stop
hero.stop
atlas.stop
+ when 'left'
+ hero.play :walk, :loop, :flip_h
when 'right'
hero.play :walk, :loop
when 'up'
hero.play :climb, :loop
when 'down'
+ hero.play :climb, :loop, :flip_v
+ when 'h'
+ hero.play :climb, :loop, :flip_hv
+ when 'c'
hero.play :cheer
end
end
+on :key_held do |e|
+ case e.key
+ when 'a'
+ hero.play :walk, :loop, :flip_h
+ hero.x -= 1
+ when 'd'
+ hero.play :walk, :loop
+ hero.x += 1
+ when 'w'
+ hero.play :climb, :loop
+ hero.y -= 1
+ when 's'
+ hero.play :climb, :loop, :flip_v
+ hero.y += 1
+ when 'z'
+ hero.width = get(:mouse_x)
+ hero.height = get(:mouse_y)
+ end
+end
+
+on :key_up do |e|
+ if ['w', 'a', 's', 'd'].include? e.key
+ hero.stop
+ end
+end
show
diff --git a/test/testcard.rb b/test/testcard.rb
index 4e629bc..7ae153f 100644
--- a/test/testcard.rb
+++ b/test/testcard.rb
@@ -221,13 +221,14 @@ Text.new(x: 144, y: 202, text: "B", font: font, color: [0.0, 0.0, 1.0, 1.0])
fps = Text.new(x: 10, y: 470, text: "", font: font)
# Sprites
-s1 = Sprite.new(450, 200, "#{media}/sprite_sheet.png")
-s1.add(forwards: [
- [ 0, 0, 50, 50, 30],
- [ 50, 0, 50, 50, 40],
- [100, 0, 50, 50, 50],
- [150, 0, 50, 50, 60]
-])
+spr = Sprite.new(
+ "#{media}/sprite_sheet.png",
+ x: 450, y: 200,
+ clip_width: 50,
+ time: 500,
+ loop: true
+)
+spr.play
# Pointer for mouse
pointer = Square.new(size: 10)
@@ -293,8 +294,6 @@ update do
pointer_outline.color = [0, 1, 0, 0]
end
- s1.animate(:forwards)
-
if (get :frames) % 20 == 0
fps.text = "FPS: #{(get :fps).round(3)}"
end