Search code examples
rubylibgosu

Vector 'Players' rather than images using Chingu and Gosu


The Chingu example looks something like this:

require 'rubygems'
require 'chingu'

class Game < Chingu::Window
  def initialize
    super
    @player = Player.new
  end
end

class Player < Chingu::GameObject
  def initialize(options = {})
    super(options.merge(:image => Gosu::Image["player.png"])
  end
end

Game.new.show

If I want the Player object to be drawn with lines rather than images, how would I go about doing this?

The following code seems intuitive, but I can't get it to work!

class Player < Chingu::BasicGameObject
  def initialize(options = {})
    super
    @radius = options[:radius]
    @c = Gosu::Color.new(0xffff0000)
  end

  def draw
    $window.draw_rect([@x-1,@y+1,@x+1,@y+1,@x+1,@y-1,@x+1,@y+1],@c,1)
  end
end

Am I doing something wrong?


Solution

  • Let's figure it out.

    I assume these are incomplete snippets of your actual code, since the code as shown calls draw_rect with @x and @y set to nil, throwing an 'undefined method '-' for nil:nilClass' exception because you can't subtract anything from nil.)

    I suspect you are seeing a blank window with nothing drawn, because as written, your Player.draw will never get called.

    Why? Because Chingu provides automated drawing and updating for all its GameObjects, but only if you use GameObject.create instead of GameObject.new.

    (http://rdoc.info/projects/ippa/chingu)

    Chingu::GameObject

    Use this for all your in game objects. The player, the enemies, the bullets, the powerups, the loot laying around. It’s very reusable and doesn’t contain any game-logic (that’s up to you!). Only stuff to put it on screen a certain way. If you do GameObject.create() instead of new() Chingu will keep save the object in the “game_object”-list for automatic updates/draws.

    Chingu::BasicGameObject

    The new() vs create() behavior of GameObject comes from BasicGameObject.

    So we need to fix that. However...

    Now that Player.draw is getting properly called every frame by Chingu, we have find a new problem: the call to draw_rect doesn't work! This is what Ruby tells me:

    in draw_rect': undefined methodx' for [99, 101, 101, 101, 101, 99, 101, 101]:Array (NoMethodError)

    Hmmm... I can see what is getting passed into the draw_rect method, I wonder what it expects to receive? Let's look at the code.

    (http://github.com/ippa/chingu/blob/master/lib/chingu/helpers/gfx.rb)

      # Draws an unfilled rect in given color
      #
      def draw_rect(rect, color, zorder)
        $window.draw_line(rect.x, rect.y, color, rect.right, rect.y, color, zorder)
        $window.draw_line(rect.right, rect.y, color, rect.right, rect.bottom, color, zorder)
        $window.draw_line(rect.right, rect.bottom, color, rect.x, rect.bottom, color, zorder)
        $window.draw_line(rect.x, rect.bottom, color, rect.x, rect.y, color, zorder)
      end
    

    Ah, now it makes sense. draw_rect expects to be passed a Rectangle object, not a bunch of coordinates. Here it is:

    (http://rdoc.info/projects/ippa/chingu)

         Chingu::Rect
    
         Constructor Details
    
    - (Rect) initialize(*argv)
    
    Create a new Rect, attempting to extract its own information from the 
    given arguments.
    
    The arguments must fall into one of these cases:
    
    - 4 integers +(x, y, w, h)+.
    - 1 Rect or Array containing 4 integers +([x, y, w, h])+.
    - 2 Arrays containing 2 integers each +([x,y], [w,h])+.
    - 1 object with a +rect+ attribute which is a valid Rect object.
    
    All rect core attributes (x,y,w,h) must be integers.
    

    So we just need to create a Rect object first, and then call draw_rect with that Rect as the first parameter.

    Okay, let's do that. Here's the working code --

    require 'rubygems'
    require 'chingu'
    
    class Game < Chingu::Window
      def initialize
        super
        puts "initializing player..."
        @player = Player.create
      end
    
    end
    
    class Player < Chingu::BasicGameObject
      def initialize(options = {})
        super
        @x = 100
        @y = 100
        @rect = Chingu::Rect.new(@x, @y, 10, 10)
        @c = Gosu::Color.new(0xffff0000)
      end
    
      def draw
        puts "inside draw"
        puts @x, @y
        $window.draw_rect(@rect, @c, 1)
      end
    end
    
    Game.new.show
    

    Running it now shows a small red rectangle at 100,100.

    Hope that helps.

    c~