Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: 2D Walls with perspective trough vertex array speed problem  (Read 2315 times)

0 Members and 1 Guest are viewing this topic.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
2D Walls with perspective trough vertex array speed problem
« on: August 21, 2012, 07:02:15 pm »
Hi!

I have a game as a side project for fun that I also use to verify that the Ruby binding is working as intended. Anyway I've reached a problem I would need an outside look on as my thought process has become stuck. The problem is a general programming problem so even if you don't know any Ruby you will be able to help me with new ideas that I couldn't think of ;)

As I normally work with 3D and so on I thought it would be fun to see if I could make a game with fake 3D and build a game from that. That has already been solved and works just fine and efficiently. Problem I have to solve is that when the camera moves the order of the walls have to be rearranged so they draw over each other correctly(since SFML doesn't allow the use of depth buffer). Since this is being done in Ruby it's pretty slow. As soon as the rebuild runs the update time spikes and this builds linearly with the amount of walls I have. Currently the spike isn't that big, just takes Ruby around 1000 microseconds to build the walls you see on the image.



But that's only 28 walls. The plan is to have a big and vivid world filled with this. So let's say worst-case scenario is a big city with large buildings so at any given time we might have around 500 walls showing on the screen. That would result in around 17.8 milliseconds of thinking time and resulting on less than 60 FPS on my hardware which is all of the latest. Of course that's not acceptable as it won't work as the development progresses. What I want is solutions in how to make this work better, I am out of ideas.

class TileArea
  def rebuild_wall_vertexes(camera_position)
    for layer in @wall_vertex_arrays
      layer.clear
    end
    for wall in @walls
      rect = wall.display_rect
   
      min_tex = wall.type.texture_offset
      max_tex = SFML::Vector2.new(min_tex.x + WallType::Size.x, min_tex.y + WallType::Size.y)
      layer = @wall_vertex_arrays[wall.position.z]
   
      wall.sort_directions(camera_position)
      for direction in wall.directions
        case direction
        when :south then
          layer.append(SFML::Vertex.new([rect.left, rect.top + rect.height], [min_tex.x, min_tex.y]))
          layer.append(SFML::Vertex.new([rect.left, rect.top + rect.height], [min_tex.x, max_tex.y]))
          layer.append(SFML::Vertex.new([rect.left + rect.width, rect.top + rect.height], [max_tex.x, max_tex.y]))
          layer.append(SFML::Vertex.new([rect.left + rect.width, rect.top + rect.height], [max_tex.x, min_tex.y]))
        when :north then
          layer.append(SFML::Vertex.new([rect.left, rect.top], [min_tex.x, min_tex.y]))
          layer.append(SFML::Vertex.new([rect.left, rect.top], [min_tex.x, max_tex.y]))
          layer.append(SFML::Vertex.new([rect.left + rect.width, rect.top], [max_tex.x, max_tex.y]))
          layer.append(SFML::Vertex.new([rect.left + rect.width, rect.top], [max_tex.x, min_tex.y]))
        when :west then
          layer.append(SFML::Vertex.new([rect.left, rect.top + rect.height], [min_tex.x, min_tex.y]))
          layer.append(SFML::Vertex.new([rect.left, rect.top + rect.height], [min_tex.x, max_tex.y]))
          layer.append(SFML::Vertex.new([rect.left, rect.top], [max_tex.x, max_tex.y]))
          layer.append(SFML::Vertex.new([rect.left, rect.top], [max_tex.x, min_tex.y]))
        when :east then
          layer.append(SFML::Vertex.new([rect.left + rect.width, rect.top], [min_tex.x, min_tex.y]))
          layer.append(SFML::Vertex.new([rect.left + rect.width, rect.top], [min_tex.x, max_tex.y]))
          layer.append(SFML::Vertex.new([rect.left + rect.width, rect.top + rect.height], [max_tex.x, max_tex.y]))
          layer.append(SFML::Vertex.new([rect.left + rect.width, rect.top + rect.height], [max_tex.x, min_tex.y]))
        end
      end
    end
  end
end

class Wall
  def sort_directions(camera_position)
    position_x = @position.x * WallType::Size.x + WallType::Size.x / 2
    position_y = @position.y * WallType::Size.y + WallType::Size.y / 2
    if(camera_position.y > position_y && (@directions.first == :south || @directions.last == :north))
       @directions.reverse!
    elsif(camera_position.y < position_y && (@directions.last == :south || @directions.first == :north))
      @directions.reverse!
    end
  end
end
 

The rebuild method is only called when needed and even only on specific intervals. The vertex code can be optimized with not clearing and reusing the already in place vertexes but it doesn't give much(I tried but there is a visual bug in rbSFML that will be fixed soon and then I'll apply it). As far as I can see I need an architectural change in order to make the better of this. Any crazy idea is accepted. Keep in mind I am only interested in a solution for the walls visible on screen.

I have backup solutions but I would like to try and not do them as they are more or less just brute-forcing by providing more power instead of actually solving the problem.
« Last Edit: August 21, 2012, 07:06:44 pm by Groogy »
Developer and Maker of rbSFML and Programmer at Paradox Development Studio