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.