I made a test to compare the different ways of rendering bullets, without a doubt sprite batch is the winner. Sprite batches only seem to slow down a few frames every 1000 or so bullets. Rectangles freeze after a few hundred and continue to freeze repeatedly every few frames. Images freeze up for a long time when some are created after a lot already exist and then resume at a normal framerate. Note that image objects are NOT created each frame, I'm not sure why the freezing happens.
Code: Select all
local
line,
mouse,
bullet_image,
sprite_batch,
is_mouse_down,
bullet_list,
use_random_bullet,
render_mode_index,
render_mode,
frame_time,
longest_frame_time
local player = {x=love.graphics.getWidth(), y=0}
local sprite_batch_size = 65536
local bullet_color = {128,0,0,255}
local bullet_dimensions = {10,10}
local line_height = 12
local bullet_speed = 0.25
local bullet_quadrant = 3
local render_modes = {'Sprite Batch','Images','Rectangles'}
local function make_image()
local image_data = love.image.newImageData(unpack(bullet_dimensions))
image_data:mapPixel(function() return unpack(bullet_color) end)
return love.graphics.newImage(image_data)
end
local function normalize(x,y)
local length = math.sqrt(x^2 + y^2)
return x/length, y/length
end
local function random_vector(quadrant)
local x,y = normalize(math.random(-1000,1000), math.random(-1000,1000))
if quadrant == 1 then
x,y = math.abs(x),-math.abs(y)
elseif quadrant == 2 then
x,y = -math.abs(x),-math.abs(y)
elseif quadrant == 3 then
x,y = -math.abs(x),math.abs(y)
elseif quadrant == 4 then
x,y = math.abs(x),math.abs(y)*-1
end
return x,y
end
local function new_bullet(x,y, mx,my)
local vx,vy = normalize(mx-x, my-y)
vx,vy = vx*bullet_speed, vy*bullet_speed
table.insert(bullet_list, {x=x,y=y, vx=vx,vy=vy})
end
local function new_random_bullet(x,y)
local vx,vy = random_vector(bullet_quadrant)
vx,vy = vx*bullet_speed, vy*bullet_speed
table.insert(bullet_list, {x=x,y=y, vx=vx,vy=vy})
end
local function new_line()
local result = line*line_height
line = line+1
return result
end
function love.load()
frame_time = 0
longest_frame_time = 0
is_mouse_down = false
mouse = {x=0, y=0}
render_mode_index = 1
render_mode = 'Sprite Batch'
bullet_image = make_image()
bullet_list = {}
use_random_bullet = true
sprite_batch = love.graphics.newSpriteBatch(bullet_image, sprite_batch_size)
end
function love.update(dt)
frame_time = dt
if dt > longest_frame_time then
longest_frame_time = dt
end
mouse.x,mouse.y = love.mouse.getPosition()
if is_mouse_down then
if use_random_bullet then
new_random_bullet(player.x,player.y)
else
new_bullet(player.x,player.y, mouse.x,mouse.y)
end
end
if render_mode == 'Sprite Batch' then
sprite_batch:clear()
for _,bullet in ipairs(bullet_list) do
bullet.x,bullet.y = bullet.x+bullet.vx, bullet.y+bullet.vy
sprite_batch:add(bullet.x,bullet.y)
end
else
for _,bullet in ipairs(bullet_list) do
bullet.x,bullet.y = bullet.x+bullet.vx, bullet.y+bullet.vy
end
end
end
function love.draw()
line = 0
if render_mode == 'Sprite Batch' then
local rendered = #bullet_list > sprite_batch_size and
sprite_batch_size or
#bullet_list
love.graphics.draw(sprite_batch)
love.graphics.print('No. of rendered bullets: ' .. rendered, 0,new_line())
elseif render_mode == 'Images' then
for _,bullet in ipairs(bullet_list) do
love.graphics.draw(bullet_image, bullet.x,bullet.y)
end
love.graphics.setColor(255,255,255,255)
elseif render_mode == 'Rectangles' then
love.graphics.setColor(unpack(bullet_color))
for _,bullet in ipairs(bullet_list) do
local w,h = unpack(bullet_dimensions)
love.graphics.rectangle('fill', bullet.x,bullet.y, w,h)
end
love.graphics.setColor(255,255,255,255)
end
love.graphics.print('No. of bullets: ' .. #bullet_list, 0,new_line())
love.graphics.print('FPS: ' .. love.timer.getFPS(), 0,new_line())
love.graphics.print('FT: ' .. frame_time, 0,new_line())
love.graphics.print('Longest FT: ' .. longest_frame_time, 0,new_line())
love.graphics.print('Render mode: ' .. render_mode, 0,new_line())
end
function love.mousepressed(x,y, button)
is_mouse_down = true
end
function love.mousereleased(x,y, button)
is_mouse_down = false
end
function love.keypressed(key)
if key == 'escape' then
love.event.push('quit')
elseif key == 'right' then
render_mode_index = ((render_mode_index) % #render_modes) + 1
render_mode = render_modes[render_mode_index]
elseif key == 'left' then
render_mode_index = (render_mode_index - 1) % #render_modes
render_mode_index = render_mode_index == 0 and
#render_modes or
render_mode_index
render_mode = render_modes[render_mode_index]
elseif key == 'r' then
if use_random_bullet then
use_random_bullet = false
else
use_random_bullet = true
end
end
end
I did a little more testing and I noticed that rectangles render at the highest fps if the number of bullets don't change, but when the number of bullets changes it starts freezing.