Forums Archived

The forums are being archived. See this topic for more information.

Drawable objects but not surfaces

Discussion about anything related to Rubygame

Drawable objects but not surfaces

Postby Groogy » Tue May 18, 2010 11:23 am

Hi! My first post ^^

Anyway, I faced a problem in Rubygame. I got this Camera instance that I want surfaces to be blitted on, but I don't want camera to be a surface and then copy itself onto the screen so I came up with the solution of a new module. I changed my Rubygame::Surface like:
Code: Select all
module Rubygame
  class Surface
    alias old_blit blit

    def blit target, pos, src_rect = nil
      if(target.include?(Drawable))
        target.draw self, pos, src_rect
      else
        old_blit target, pos, src_rect
      end
    end
  end
end


So instead of going trough SDL's normal blit function it calls the instance draw method(or whatever you want to call it) if the instance includes the module Drawable(trying to figure up a better name, maybe ReversedDraw). So now I can implement a class(like camera) that can modify the output before really drawing it to the screen without the need of having a surface in the middle.

Wondering if anyone has a better solution? And maybe if something similar can be implemented in rubygame at a later version? (I.E, If target is not a Surface then call target#draw, or something) SFML got a similar structure in how they draw their objects.

Example:
Code: Select all
class MyDrawable : public sf::Drawable {
    public
        sf::Sprite mySprite; // Let's assume we load an image into this sprite
       
    private:
        void Render(sf::RenderTarget& target) const {
            target.Draw(mySprite);
        }
};

void main() {
    MyDrawable mydraw;
    sf::RenderWindow window;
    // Setup the window
    // Load the image onto mySprite & stuff
    window.Draw(myDraw);
    // Update screen and sleep
}


And can someone help me come up with better names that represent the function of the module better?

Thanks
Groogy
 
Posts: 11
Joined: Tue May 18, 2010 10:57 am

Re: Drawable objects but not surfaces

Postby jacius » Wed May 19, 2010 5:31 am

Hi Groogy, and welcome! :)

I would caution against overriding Rubygame's Surface#blit method like that. It's a very fragile solution, and could easily break or cause problems in the future. Instead, why not just create your own classes that implement the "drawable" and "camera" functionality in the way you want?

For example, you could have something like this:

Code: Select all
class Camera
  def initialize( screen )
    @screen = screen
    @x_offset, @y_offset = 0, 0
  end

  def draw( mydrawable )
    mydrawable.draw( @screen, @x_offset, @y_offset )
  end
end

class Drawable
  def draw( target, x_offset=0, y_offset=0 )
    @image.blit( target, [@x + x_offset, @y + y_offset] )
  end
end

Then to draw a drawable, you'd just pass it to Camera#draw. Does that make sense?
User avatar
jacius
Site Admin
 
Posts: 131
Joined: Fri Feb 06, 2009 11:13 pm

Re: Drawable objects but not surfaces

Postby Groogy » Wed May 19, 2010 9:11 am

Yeah it does but I was hoping to be able to use the normal blit method.

Well I guess I'll adopt it to like this:
Code: Select all
class Camera
  def initialize
    @focus_on = [0, 0]
  end

  def draw surface, pos, src_rect = nil
    # Never mind this, only have this since my camera
    # is designed to also focus on objects, the position method
    # handles it so I don't need to know what we focus on.
    focus_pos = position
    pos = [focus_pos[0] - pos[0], focus_pos[1] - pos[1]]
    prepare_surface(surface) # Any effects that maybe should be applied.
    surface.blit(@screen, pos, src_rect)
  end
end

class GameController
  def update_graphics
    # Which in turn calls camera with the surface and position
    @actor.render_onto(@camera)
  end
end


I can't have it like you wrote since I want the camera to be able to manipulate the surface and control it. The camera isn't interested in the logical part of the actor but only the graphical representation, so the more I can split them apart the better.

**EDIT**
And we're back to where we started I realized. render_onto will call @image.blit(@camera) XD
Can you tell me why it's dangerous to alias the Surface#blit method?
Groogy
 
Posts: 11
Joined: Tue May 18, 2010 10:57 am

Re: Drawable objects but not surfaces

Postby jacius » Wed May 19, 2010 11:16 pm

Okay, if you want the Camera to have full control over the rendering, then you can simply put the call to Surface#blit inside the Camera's method, like you did in your latest code. I don't see why you need the @actor.render_onto, it seems redundant when you have Camera#draw.

As for the reasons you shouldn't override Surface#blit:
  • Your version assumes that the blit method will always take the same arguments as it does now. It could cause problems if the original blit method signature changed in a new version of Rubygame, for example to add a new optional argument.
  • It makes the behavior of the blit method less predictable, since it now does something completely different depending on whether the argument is a Drawable or not. This will make it harder to debug your program.
  • Surface#blit has a specific purpose, copying pixels from part of one Surface to part of another Surface. By overriding it, you're injecting a different behavior that doesn't match the original purpose.
  • Last but not least, it's just not kosher. You should only modify external classes when absolutely necessary (and in this case, it really isn't).
I'm sure if you just clearly plan out exactly what you want to accomplish, you'll be able to think of solutions that don't require modifying the blit method.
User avatar
jacius
Site Admin
 
Posts: 131
Joined: Fri Feb 06, 2009 11:13 pm

Re: Drawable objects but not surfaces

Postby Groogy » Thu May 20, 2010 4:29 am

jacius wrote:Okay, if you want the Camera to have full control over the rendering, then you can simply put the call to Surface#blit inside the Camera's method, like you did in your latest code. I don't see why you need the @actor.render_onto, it seems redundant when you have Camera#draw.

As for the reasons you shouldn't override Surface#blit:
  • Your version assumes that the blit method will always take the same arguments as it does now. It could cause problems if the original blit method signature changed in a new version of Rubygame, for example to add a new optional argument.
  • It makes the behavior of the blit method less predictable, since it now does something completely different depending on whether the argument is a Drawable or not. This will make it harder to debug your program.
  • Surface#blit has a specific purpose, copying pixels from part of one Surface to part of another Surface. By overriding it, you're injecting a different behavior that doesn't match the original purpose.
  • Last but not least, it's just not kosher. You should only modify external classes when absolutely necessary (and in this case, it really isn't).
I'm sure if you just clearly plan out exactly what you want to accomplish, you'll be able to think of solutions that don't require modifying the blit method.


Hmm okay I see more of the picture. I learned this way of aliasing methods from RPG Maker VX where you had to if you wanted to change something in the engine.

And about render_onto to be redundant, I do want Camera to be able to control the surface but I don't want it as public access... It's only C++ that has the concept friends right?

You might notice how I got the habit of making things more complex than it has to be? :P
Well you gotta learn new stuff somehow.

**EDIT**
Here's just a test and waiting for opinion ^^
Code: Select all
# So it will look something like this later on in the actor class
class Actor
  def update_graphics
    if $main.camera.visible? self
      $main.camera.draw @surface, self.position, self.clip
    end
  end
end


This was so much simpler than my first initial idea, I'm just gonna make Actor receives ClockTicked events on Actor#update which in turn calls Actor#update_graphics and pass the surface to the camera. You feel so stupid when there's something so simple as the answer.
Groogy
 
Posts: 11
Joined: Tue May 18, 2010 10:57 am


Return to Rubygame (General)

Who is online

Users browsing this forum: No registered users and 0 guests

cron