Not logged inGosu Forums
Forum back to libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Exchange / Using Window#needs_redraw?
- - By NYU Date 2017-01-13 21:36 Edited 2017-01-13 21:48
Hello again.

I'm trying to use the method Window#needs_redraw?. Actually, I don't use the Window#draw method but a Thread in Window#initialize and I need to "freeze" the drawing of the screen. My first idea was to Gosu#record the screen but since I'm using Gosu#clip_to, that's not possible.

So I wanted to control if the screen was redrawn or not. I tried this code:
def needs_redraw?
    false
end

And it's working: the screen is not drawn anymore. However, when I tried to implement my function:
def needs_redraw?
    if Graphics.needs_redraw?
        Graphics.needs_redraw = false
        true
    else
        false
    end
end

Gosu is throwing me an error: /lib/gosu/patches.rb:152:in `tick': SWIG director type mismatch in output value of type 'bool' (RuntimeError)

What am I doing wrong ? I don't get it. I'm returning a bool and I didn't find any understandable explanation on Google.

Also. Is using a Thread a good idea or should I use something else ?

Thank you for your attention,
NYU.
Parent - - By jlnr (dev) Date 2017-01-15 10:08 Edited 2017-01-15 10:16
You are right, it seems that needs_redraw? is currently broken. Oops! I've opened a ticket here: https://github.com/gosu/gosu/issues/376

What is your use case? In general, everything that involves a Thread is usually a bad idea with Ruby/Gosu, unless you use it purely for game logic. The needs_redraw? method doesn't guarantee that draw will not be called (even though it does that in recent versions of Gosu), it's just an optimisation hint.
Parent - - By NYU Date 2017-01-15 10:52
The code I need to use while and a method to update the graphic part inside this while. Since I'm just porting an existing project to Gosu, the Thread was the trick I found to use the previous code.

Here is a little example:

class Game < Gosu::Window
  def initialize
    super
    @main = Thread.new do
      require_relative 'some_file.rb'
      while true
        # ... Do something ; all the game will be here
        Graphics.update
        break if # ...
      end
    end
  end
end


The point is to call draw only when Graphics.update is called. So, Graphics.update is coded like that:

def update
  unless @frozen
    # Do some stuff
    @needs_redraw = true
  end
  sleep 1.0/Graphics.fps
end


Do you have any suggestion to improve that ?
Parent - - By jlnr (dev) Date 2017-01-15 14:50
I see how that could work with record, but not without it. You cannot draw outside of Window#draw, and you can only create Gosu resources (Image etc.) on the main thread currently.

I think there's a better solution actually, it's a bit experimental but I added it exactly for this use case: Window#tick

Basically, your game would become:

class Game < Gosu::Window
  def draw
    # drawing needs to happen here, but maybe you can call into another function...
  end
end

game = Game.new(...)

while true
  # ... Do something
  game.tick # this will call Window#update and Window#draw
  break if # ...
end
Parent - - By NYU Date 2017-01-15 20:23 Edited 2017-01-15 20:41
Also, when I stop to call #tick, the game crashes. So. How can I freeze the game ? And so how can I close the window ?

Because I used break unless window.tick, but if I'm freezing the game, it's not working anymore.
Parent - - By jlnr (dev) Date 2017-01-16 02:50
Usually tick is used like this from within Window#show:

def show # pseudo-implementation
  while tick
    sleep 0.016
  end
  # stops when tick returns false
end


When tick returns false the game should end, because either Window#close was called, or the user clicked the [x] in the window corner.

If you just keep calling tick, the window will re-appear.

What do you mean by "crashes"? Is there an error? It's hard to understand if the structure works for you because I don't know what happens in # ... Do something :)
Parent - - By NYU Date 2017-01-16 06:44
Hum. I see...

By crashes, I mean that the program is not responding if I stop calling tick (to do some expensive calculation and use of MiniMagick -- file conversion, etc. -- and to setup all my objects -- images).

So... The correct alternative would be a #render_to_image method to hide changes on the screen. Ashton allows a render to texture, I think ; but I can't get it work -- Ruby OpenGL is not compiling.
For another project, I used to work with this wrapper but I failed to make Ashton compatible with. It's saying ashton/shader.rb:109:in enable': undefined method z' for Gosu::Window. And then... I don't want to use an old version of Ruby just for Ashton.
Parent - - By jlnr (dev) Date 2017-01-16 06:52
#render_to_image would only help you if you could use it on a background thread, which I don't think Ashton allows.

Can you somehow run the expensive MiniMagick file conversions when you build your game, so that it will start fast enough to not appear stuck?
Parent - By NYU Date 2017-01-16 06:59
The MiniMagick thing is user-dependent: I convert user's own files.

I can also do the conversion before showing the game. But during the game, I still need to hide some changes on the screen during a moment.
I need Ashton to achieve that or I need to replace Gosu#clip_to to use Gosu#record.
Parent - - By jlnr (dev) Date 2017-01-16 07:20
Or, you can keep Gosu::Window running in parallel to your thread, and only interlock when you need to run something on the main thread (create images, read a value from button_down? etc.), and when you want to redraw the screen.

https://gist.github.com/jlnr/89953f1199080ccaa5bd8fe6d66ea188

It relies on needs_redraw?, which mysteriously works on my computer but I'm using a dev version of Gosu, so maybe it'll be broken for you until 0.11.1 is out. But does that seem like a good workaround?

Feels like a hack, but was fun to write - I don't usually use Ruby's threading API :)
Parent - - By NYU Date 2017-01-16 08:40
That's a possible workaround, but it's really laggy and definitely not usable in a game. I will just do my conversions before any Window#tick. :)

However, I still need to "freeze" the game. Is Ashton really broken with Ruby 2.3.x and the last version of Gosu, or did I make a mistake ?

This is what I need for the game:
1) Convert user's files
2) The game is running
3) Freeze the screen (game is running behind)
4) Transition to the game (with a shader if I get Ashton to work)

But maybe should I create a new subject for Ashton ?
Parent - By jlnr (dev) Date 2017-01-16 15:13
Hmm. Why is it laggy? The interlocked threads shouldn't introduce more than 16ms of delay in the worst case.
If I remove the sleep calls, it runs at 30 FPS, and it'd run at 60 FPS with more careful scheduling of the draw/update blocks, but of course that depends on the game's actual code.

I want to support render-to-image in Gosu (without Ashton) at some point, but that's not something that'll happen in the next months, I'm afraid: https://github.com/gosu/gosu/issues/317

If the only problem with record {} is that it doesn't work with clip_to, can you maybe record several macros and remember with which clip rect the macros need to be rendered?
Parent - - By NYU Date 2017-01-16 17:19 Edited 2017-01-16 19:19
I don't know why it's laggy. And it doesn't fit really well the rest of the code, even if the way it's coded is interesting.

Here is what I coded previously, for instance.

class Graphics

  @views = [] # An array containing all my views
  @recorded_views = [] # An array containing all my views recorded

  def draw_frozen
    @recorded_views.each do |v|
      v[3].draw v.x, v.y, v.z
    end
  end

  def draw
    if @frozen
      draw_frozen
      return
    end
    @views.each do |v|
      # Draw here
    end
  end

  def freeze
    @frozen = true
    @recorded_views = []
    @views.each do |v|
      @recorded_views << [v.x, v.y, v.z, Gosu.record(v.width,v.height){ # Draw here }]
    end
  end

  def transition(duration)
    duration.times do
      # I need to find a way to create a transition.
      sleep 1
    end
    @frozen = false
  end

  def update
    sleep 0.016
  end

end


class GameWindow < Gosu::Window

  def initialize
    # Init ...
    main = Thread.new do
      img = Gosu::Image.new 'img.png'
      while
        # Updating
        Graphics.update
        if #...
          Graphics.freeze
          # Change something
          Graphics.transition(5) # Transition during 5 seconds
        end
      end
    end
  end

  def draw
    Graphics.draw
  end

end
Parent - - By jlnr (dev) Date 2017-01-17 04:38
Hmm. Then I'm out of ideas, sorry. This structure will likely crash sooner or later because it calls record and Image.new on a background thread, which is not supported by Gosu (yet?). Specifically, Window#draw and record cannot run in parallel right now, they use the same internal data structure.
Parent - By NYU Date 2017-01-17 18:50
Hum, I see... I think I should code my own engine in OpenGL (or perhaps SDL ?). It will take some time, but I think it's the more suitable solution.
Parent - - By jlnr (dev) Date 2017-01-20 15:20
Some late feedback on the needs_redraw? method: it's not actually broken, the error message is just extremely misleading.

What is happening is that if an exception is raised in needs_redraw? (e.g. typo in a method name), then this exception will be swallowed by a safety mechanism inside Gosu, and SWIG will print the wrong error message.
Parent - - By NYU Date 2017-01-20 15:46
I see. However, I think Gosu is not suitable for what I want. Thank you for all, I will continue will a full-OpenGL custom engine.
Parent - - By jlnr (dev) Date 2017-01-20 17:43
No worries, I just wanted to report back on this bug while I was fixing it (the error message will be correct in Gosh 0.11.2). Good luck with your custom OpenGL engine, that's how Gosu started too :)
Parent - By NYU Date 2017-01-23 14:36
Thank you. I don't know yet where I'm going exactly, but I'm going somewhere. :)
Up Topic Gosu / Gosu Exchange / Using Window#needs_redraw?

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill