Not logged inGosu Forums
Forum back to libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Exchange / Drawing animation until it's completed
- - By wanderinweezard Date 2013-10-18 01:54
What is a good way to draw a particular animation without repeating the sequence?  Think of like a spell effect or an explosion sequence.

In the example with Gosu:

@cur_image = @animation[Gosu::milliseconds / @delay % @animation.size]

This causes an animation to repeat, assuming that you keep drawing the object.  So the approach I took in the source I've linked to was to establish a time-to-live (ttl) value for the lightning bolt I'm drawing.  I specify a 100 millisecond delay (if I understand the formula right) and multiply that by the number of frames (@animation.size).  Then, when I first create the object that represents the lightning bolt - I capture the Gosu::milliseconds value.  Each time I call my update() method on the lightning bolt, i check if Gosu::milliseconds minus the start time is greater than my calculated time-to-live value.  What I'm having happen is the lightning bolt ends up repeating some of the first few frames before it stops being drawn.

A few questions:
1) I'm assuming I misunderstand how the formula I've pasted here works - if my animation is repeating a bit.  Can you help me identify what I can improve here so the animation only draws each frame once and then leaves?

2)  Is there a better way to do this?  I know Chingu has a way to tell the animation not to repeat, but I'm still trying to learn how to do it myself before adopting too many tools.

Here is a link to my Github for this test-program:  Github Link
Parent - By jlnr (dev) Date 2013-10-18 03:03
I haven't checked out your code, but instead of trying to change the formula above, you could just use this:

# object initialisation
@tick = 0

# update
@tick += 1
somehow_remove_object if @tick >= @animation.size

# drawing
@cur_image = @animation[@tick].draw
Parent - By shawn42 Date 2013-10-18 19:09
You can take a look at how Gamebox handles it in its animation behavior.

hope that helps
Parent - By wanderinweezard Date 2013-10-19 00:46
Thanks for the feedback - I'll give these a shot.
Parent - - By ml Date 2013-10-19 02:17
Hey I just cloned the git repo and tried it out. Looks really good. Nicely done on the manually-created collision detection system.

I'm going to take some time to look at the code and try to figure it out. On a quick test run, here's what I tried:

  if elapsed_time > @ttl then
    @draw_me = false
    puts elapsed_time
    puts @ttl
  end

@ttl and elapsed_time seem to be off by 2 to 10ish each time - just a few milliseconds.

Holding space while moving creates an interesting effect.

As to why the numbers are off, I'll take a look at it and try to figure it out. I think the solution suggested by jlnr ought to be able get the job done.
Parent - - By wanderinweezard Date 2013-10-19 09:51
Thanks for checking it out.  I did just push another update.  Visually - I'm getting the desired behavior now and I think the bolts that are finished drawing are being removed from the array of bolts.  This should mean the object will get cleared by the garbage collector at some point, right?
Parent - - By ml Date 2013-10-19 21:27 Edited 2013-10-19 21:41
Ya, it's working even better now. Before the bolts were all showing the same animation at the same time, and it was starting in the middle of the animation sometimes. Now each bolt has its own animation. I added a print message to check if the bolts are getting destroyed, and it looks like they are. I could be wrong, but I think this bit of code is taking care of getting rid of the old ones:

@bolts.reject! do |bolt|
  if bolt.done == true then
    true
  else
    false
  end
end

Depending on the effect you're going for, it might be good to add a short cool down period, so that it fires only one bolt at a time. Right now it's hard to fire only one -- you have to press the spacebar very quickly.

P.S. You could try something like this:

(initialize)
@cool_down = 0

(update)
if button_down? Gosu::KbSpace then
  if @cool_down == 0
    @bolts.push(Bolt.new(self, @player.x + 50, @player.y + (@player.height / 2)))
    @cool_down = 20
  end
end

if @cool_down > 0
  @cool_down -= 1
end
Parent - - By wanderinweezard Date 2013-10-20 01:24
Great idea on the cooldown.  I wasn't sure why the bolt looked unusual - i guess it was because it was drawing so many.
Parent - By ml Date 2013-10-20 01:49
Holding down space while moving the character gives a sense of what's going on.
Parent - - By shawn42 Date 2013-10-22 18:10
You can clean the reject code up a bit:

@bolts.reject! &:done

;)

Keep up the good work.
Parent - - By wanderinweezard Date 2013-10-24 00:24
Can you explain the & :done bit please?  Still pretty new to Ruby
Parent - - By RunnerPack Date 2013-10-24 01:53
Parent - By wanderinweezard Date 2013-10-24 09:45
Thanks for the link! I'll check it out
Parent - By shawn42 Date 2013-10-28 16:49
Yeah, that link sums it up nicely. (Basically calling #to_proc on the symbol)
Parent - By RavensKrag Date 2013-10-29 12:21
Alternatively, you could check if a certain amount of time has past since the last bolt:


def initialize
  @time_between_shots = 100

  @time = 0
end

def update
  @time += Gosu::milliseconds

  if button_down? Gosu::KbSpace
    if @time >= @time_between_shots
      # put code to fire off more bolts here
     
      @time = 0
    end
  end
end


Same principle, but this way makes more sense to me personally.
This method is also framerate independent, because it uses the millisecond timer, instead of counting game ticks.
Up Topic Gosu / Gosu Exchange / Drawing animation until it's completed

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill