Simple animation using Crystal CrSfml

is it possible to modify the following code to display all the intermediate positions of shape (rectangle) and not only the last one :slight_smile:

require "crsfml"

# create the window
window = SF::RenderWindow.new(SF::VideoMode.new(800, 600), "My window")

# run the program as long as the window is open
while window.open?
  # check all the window's events that were triggered since the last iteration of the loop
  while event = window.poll_event
    # "close requested" event: we close the window
    if event.is_a? SF::Event::Closed
      window.close
    end
  end

  # clear the window with black color
  window.clear(SF::Color::Black)

  # draw everything here...
  shape = SF::RectangleShape.new(SF.vector2(50, 50))
  shape.fill_color = SF.color(100, 250, 50)

  # set the absolute position of the entity
  (0..10).each do |i|
    window.clear(SF::Color::Black)
    shape.position = SF.vector2(10 * i, 50)
    window.draw(shape)
    sleep(0.1)
  end

  # end the current frame
  window.display
end

1 Like

Answer to my own question :slight_smile:

require "crsfml"

# create the window
window = SF::RenderWindow.new(SF::VideoMode.new(800, 600), "Simple animation test")

# Define shape to be draen
shape = SF::RectangleShape.new(SF.vector2(50, 50))
shape.fill_color = SF.color(100, 250, 50)

# coroutine and channel to produce coordinates aynchronouly
channel = Channel(Int32).new

spawn do
    (0..10).each do |i|
        channel.send(i)
        sleep(0.2)
    end
    channel.close()
end

# Window loop
while window.open?
    # check all the window's events that were triggered since the last iteration of the loop
    while event = window.poll_event
        # "close requested" event: we close the window
        if event.is_a? SF::Event::Closed
        window.close
        end
    end

    # clear the window with black color
    window.clear(SF::Color::Black)

    # set the absolute position of the entity
    if x_position = channel.receive?
        shape.position = SF.vector2(10 * x_position, 50)
        window.draw(shape)
    else window.close()
    end 

    # end the current frame
    window.display
end

I don’t think there’s a good reason to use channels for this. You can just move the window.display inside the loop where you set the x position:

require "crsfml"

# create the window
window = SF::RenderWindow.new(SF::VideoMode.new(800, 600), "My window")

# run the program as long as the window is open
while window.open?
  # check all the window's events that were triggered since the last iteration of the loop
  while event = window.poll_event
    # "close requested" event: we close the window
    if event.is_a? SF::Event::Closed
      window.close
    end
  end

  # clear the window with black color
  window.clear(SF::Color::Black)

  # draw everything here...
  shape = SF::RectangleShape.new(SF.vector2(50, 50))
  shape.fill_color = SF.color(100, 250, 50)

  # set the absolute position of the entity
  (0..10).each do |i|
    window.clear(SF::Color::Black)
    shape.position = SF.vector2(10 * i, 50)
    window.draw(shape)
    sleep(0.1)

    # end the current frame
    window.display
  end
end

EDIT

Actually, though, I recommend setting things up beforehand and modifying them in the loop:

require "crsfml"

# create the window
window = SF::RenderWindow.new(SF::VideoMode.new(800, 600), "My window")

# set up everything that doesn't need to change
shape = SF::RectangleShape.new(SF.vector2(50, 50))
shape.fill_color = SF.color(100, 250, 50)
shape.position = SF.vector2(0, 50)

# run the program as long as the window is open
while window.open?
  # check all the window's events that were triggered since the last iteration of the loop
  while event = window.poll_event
    # "close requested" event: we close the window
    if event.is_a? SF::Event::Closed
      window.close
    end
  end

  # clear the window with black color
  window.clear(SF::Color::Black)

  # set the absolute position of the entity, looping back when reaching the end
  if shape.position.x >= 100
    shape.position = SF.vector2(0, 50)
  else
    shape.position += SF.vector2(10, 0)
  end

  window.draw(shape)

  # end the current frame
  window.display
  sleep(0.1)
end
1 Like

Even better, you can use SFML time handling, as described here, to create smooth movement:

require "crsfml"

# create the window
window = SF::RenderWindow.new(SF::VideoMode.new(800, 600), "My window")

# set up everything that doesn't need to change
shape = SF::RectangleShape.new(SF.vector2(50, 50))
shape.fill_color = SF.color(100, 250, 50)
shape.position = SF.vector2(-50, 50)

shape_velocity_per_second = SF.vector2(100, 0)

# program clock
clock = SF::Clock.new

# run the program as long as the window is open
while window.open?
  # check all the window's events that were triggered since the last iteration of the loop
  while event = window.poll_event
    # "close requested" event: we close the window
    if event.is_a? SF::Event::Closed
      window.close
    end
  end

  # clear the window with black color
  window.clear(SF::Color::Black)

  # set the absolute position of the entity, wrapping around the window edge
  if shape.position.x >= 800
    shape.position = SF.vector2(-50, 50)
  else
    shape.position += shape_velocity_per_second * clock.restart.as_seconds
  end

  window.draw(shape)

  # end the current frame
  window.display
end
1 Like