2

我一直在修补使用 Ruby 在 Gosu 中制作绘图应用程序,但我遇到了一些高 CPU 使用率。我知道一个可能的原因。

首先,我只是在每次用户单击鼠标按钮时(或者如果他们按住鼠标按钮,则每次屏幕刷新时,我认为这大约每秒发生 60 次)时向哈希添加一个原语。每次屏幕重绘时,我都会让程序循环遍历哈希并重绘所有基元。如果有人按住鼠标按钮,它只会将重叠的图元保持在彼此之上,而在其他情况下,图元只是分层。我可以看到这最终会如何消耗散列中的一堆内存。

我觉得最好的解决方案是使用某种较低级别的函数,该函数只需为屏幕上的像素着色,而不必将它们存储在哈希中。我不确定Gosu是否支持。有人可以在 Gosu 中帮我解决这个问题,还是建议使用不同的方法和/或其他程序?谢谢!

(以下是我的程序的完整代码。)

require 'Gosu'
require 'socket'

class GameWindow < Gosu::Window
  def initialize

    super 1280, 960, false
    self.caption = "Drawz Server"

    @background_image = Gosu::Image.new(self, "media/Space.png", true)


    @player = Player.new(self)
    # Platform is the blank image for the epicycle to be drawn on.
    @earth_image = Gosu::Image.new(self, "media/earth.bmp", true)
    @cursor_image = Gosu::Image.new(self, "media/cursor.bmp", true)

    puts "Please enter port..."
    port = gets.strip!
    puts "Server is running."

    # Initialized Instance variables for all methods.
    @square_drawing_number = 0
    @client_coordinates_array = []
    @client_coordinates_array_array = []
    @client_quad_hash = {}
    server = TCPServer.open("10.64.8.2", port)
    @client = server.accept

    manage_client_data = Thread.new do
            x = 0
            loop do
                @client_coordinates_array[x] = @client.gets
                x += 1
            end
        end

    @x = 0
    @quad_hash = {}
    # Start up value of things in draw method, because draw is called before update. Hence I put the start up values here so that when draw is called it has location of things in
    # its arguments.
    @cx = 0 
    @cy = 0
  end



class QuadCoords
    attr_reader :x1, :y1, :x2, :y2, :x3, :y3, :x4, :y4

    def initialize(x1, y1, x2, y2, x3, y3, x4, y4)
        @x1 = x1
        @y1 = y1
        @x2 = x2
        @y2 = y2
        @x3 = x3
        @y3 = y3
        @x4 = x4
        @y4 = y4
    end
end

    # Mean't to change location (x and y) and such of things in draw method.

    def update
        @cx = mouse_x
        @cy = mouse_y
        @x += 1
        # Adds square locations to hash which is then accessed by draw function to retrieve and draw squares.
        if button_down? Gosu::MsLeft
            @x += 1
            quad_coords_obj = QuadCoords.new(@cx - 5, @cy - 5, @cx, @cy - 5, @cx - 5, @cy, @cx, @cy)
            @quad_hash["quad#{@x}"] = quad_coords_obj
            # Sends location of squares to client for it to draw.
            @client.puts "#{quad_coords_obj.x1}---#{quad_coords_obj.y1}---#{quad_coords_obj.x2}---#{quad_coords_obj.y2}---#{quad_coords_obj.x3}---#{quad_coords_obj.y3}---#{quad_coords_obj.x4}---#{quad_coords_obj.y4}"
        end

        if @client_coordinates_array.length > @square_drawing_number
            new_squares_to_add = @client_coordinates_array.length - @square_drawing_number
            @client_coordinates_array[-1 * new_squares_to_add..-1].each do |value|
                @client_coordinates_array_array << value.split(/\---/)
            end
            x = 1
            new_squares_to_add.times do
                @x += 1
                @client_quad_coords_obj = QuadCoords.new(@client_coordinates_array_array[-1 * x][0].to_i,
                @client_coordinates_array_array[-1 * x][1].to_i,
                @client_coordinates_array_array[-1 * x][2].to_i,
                @client_coordinates_array_array[-1 * x][3].to_i,
                @client_coordinates_array_array[-1 * x][4].to_i,
                @client_coordinates_array_array[-1 * x][5].to_i, 
                @client_coordinates_array_array[-1 * x][6].to_i, 
                @client_coordinates_array_array[-1 * x][7].to_i)
                @client_quad_hash["quad#{@x}"] = @client_quad_coords_obj
                x += 1
                @square_drawing_number += 1
            end
        end


    end


  # Draw is called before update.
  def draw

    @background_image.draw(0,0,0)
    @earth_image.draw(295,215,1)
    # x1,y1 = Upper Left Hand Corner; x2,y2 = Lower Left Hand Corner; x3,y3 = Upper Right Hand Corner; x4,y4 = Lower Right Hand Corner
    @quad_hash.each_value do |value|
        draw_quad(value.x1, value.y1, 0xff00ffff, value.x2, value.y2, 0xff00ffff, value.x3, value.y3, 0xff00ffff, value.x4, value.y4, 0xff00ffff, z = 0, mode = :default)
    end

    @client_quad_hash.each_value do |value|
        draw_quad(value.x1, value.y1, 0xff00ff00, value.x2, value.y2, 0xff00ff00, value.x3, value.y3, 0xff00ff00, value.x4, value.y4, 0xff00ff00, z = 0, mode = :default)
    end

    @cursor_image.draw(@cx, @cy, 1)

  end

  def button_down(id)
    if id == Gosu::KbEscape
      close
    end
  end
end



class Player
    attr_accessor :x, :y, :update_called
  def initialize(window)
    @image = Gosu::Image.new(window, "media/Sun.bmp", false)
  end
end



window = GameWindow.new
window.show
4

2 回答 2

1

您可以使用 TexPlay 在 Gosu::Image 上绘图,然后渲染此图像。 http://banisterfiend.wordpress.com/2008/08/23/texplay-an-image-manipulation-tool-for-ruby-and-gosu/ 例如:

image1.paint {
  circle 20,20,10, :color => :red
  rect 40,40,50,50, :color => :green
  pixel 60,60, :color => :blue
}

还有其他选择:RMagick(更强大,但安装\分发更复杂)和 Ashton(它具有渲染到 OpenGL 纹理的方法,因此速度更快,但需要对 OpenGL 有一些了解)。

于 2013-04-17T05:40:39.887 回答
1

我建议使用我的 Ashton gem 直接渲染到纹理 - 与 TexPlay 或其他软件渲染不同,这是硬件加速的,所以非常快!使用 Ashton::Texture#render,您可以将绘制操作缓存到纹理中,就像将它们绘制到屏幕上一样快。

def initialize(...)
  # WindowBuffer is just an Ashton::Texture that is the same size as the window
  @draw_buffer = Ashton::WindowBuffer.new 
  ...
end

def update()
  @draw_buffer.render do
    # Perform new gosu drawing actions (e.g. draw_quad)
    # here to draw directly into the texture.
    # Both the local ones and the ones pulled from the network.
  end
end

def draw()
  # Since you are drawing things in the order they should appear,
  # you don't need to worry about Z values.
  @background_image.draw 0, 0, 0
  @earth_image.draw 295, 215, 0
  @draw_buffer.draw 0, 0, 0
  @cursor_image.draw @cx, @cy, 0
end

另请注意,打印文本实际上很慢,因此如果在每次更新/绘制中执行,将会影响您的 FPS。

于 2013-09-04T11:28:24.383 回答