██▓▒­░⡷⠂𝚘𝚌𝚝𝚝 𝚒𝚗𝚜𝚒𝚍𝚎 𝚞𝚛 𝚠𝚊𝚕𝚕𝚜⠐⢾░▒▓██ on 2025-09-03T21:58:37Z [JSON]

Love2D fucking rectangles benchmark, normal and OOP...

Common part of the code:

local screenW, screenH
local sprites = {}
local tospawn = 200
local prespawn = false
local partialdraw = false

function love.load()
  screenW, screenH = love.graphics.getDimensions()
  if prespawn then makesprites(200000) end
end

function picklast(array, count)
  local result = {}
  local total = #array
  local start = math.max(1, total - count + 1)
  for i = start, total do
    table.insert(result, array[i])
  end
  return result
end

Normal implementation:

function love.update(dt)
  local start = love.timer.getTime()

  if not prespawn then makesprites(tospawn) end

  for _, sprite in ipairs(sprites) do
    sprite.x = sprite.x + sprite.dx * dt
    sprite.y = sprite.y + sprite.dy * dt

    -- Bounce off edges
    if sprite.x < 0 or sprite.x + sprite.width > screenW then sprite.dx = -sprite.dx end
    if sprite.y < 0 or sprite.y + sprite.height > screenH then sprite.dy = -sprite.dy end
  end

  print("Sprites:", #sprites, "Update:", love.timer.getTime() - start)
end

function love.draw()
  local list = partialdraw and picklast(sprites, 500) or sprites
  for _, rectangle in ipairs(list) do
    love.graphics.setColor(unpack(rectangle.color))
    love.graphics.rectangle("fill", rectangle.x, rectangle.y, rectangle.width, rectangle.height)
  end
  love.graphics.setColor(1, 1, 1)
  love.graphics.print("Sprites: " .. #sprites, 10, 10)
end

function makesprites(max)
  for i = 0, max do
    table.insert(sprites, {
      x = math.random(0, screenW),
      y = math.random(0, screenH),
      dx = math.random(-100, 100),
      dy = math.random(-100, 100),
      width = math.random(10, 30),
      height = math.random(10, 30),
      color = { math.random(), math.random(), math.random() },
    })
  end
end

OOP (classic) implementation:

Object = require "classic"

Point = Object:extend()
function Point:new(x, y)
  self.x = x or 0
  self.y = y or 0
end

Drawable = Object:extend()

Rectangle = Drawable:extend()
function Rectangle:new(width, height, color, mode)
  self.width = width
  self.height = height
  self.mode = mode or "fill"
  self.color = color
end
function Rectangle:draw(x, y)
  love.graphics.setColor(unpack(self.color))
  love.graphics.rectangle(self.mode, x, y, self.width, self.height)
end

Node = Object:extend()
function Node:new(x, y)
  Point.new(self, x, y)
end

Sprite = Node:extend()
function Sprite:new(x, y, drawable)
  Sprite.super.new(self, x, y)
  self.drawable = drawable
end
function Sprite:draw()
  self.drawable:draw(self.x, self.y)
end

function love.update(dt)
  local start = love.timer.getTime()

  if not prespawn then makesprites(tospawn) end

  for _, sprite in ipairs(sprites) do
    sprite.x = sprite.x + sprite.dx * dt
    sprite.y = sprite.y + sprite.dy * dt

    -- Bounce off edges
    if sprite.x < 0 or sprite.x + sprite.drawable.width > screenW then sprite.dx = -sprite.dx end
    if sprite.y < 0 or sprite.y + sprite.drawable.height > screenH then sprite.dy = -sprite.dy end
  end

  print("Sprites:", #sprites, "Update:", love.timer.getTime() - start)
end

function love.draw()
  local list = partialdraw and picklast(sprites, 500) or sprites
  for _, rectangle in ipairs(list) do
    rectangle:draw()
  end
  love.graphics.setColor(1, 1, 1)
  love.graphics.print("Sprites: " .. #sprites, 10, 10)
end

function makesprites(max)
  for i = 0, max do
    local sprite = Sprite(
      math.random(0, screenW),
      math.random(0, screenH),
      Rectangle(
        math.random(10, 30),
        math.random(10, 30),
        { math.random(), math.random(), math.random() }))
    sprite.dx = math.random(-100, 100)
    sprite.dy = math.random(-100, 100)
    table.insert(sprites, sprite)
  end
end