AUTOMATIC QUAD DETECTOR

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
DebasishDatta
Prole
Posts: 17
Joined: Fri Nov 26, 2021 5:15 am

AUTOMATIC QUAD DETECTOR

Post by DebasishDatta »

can someone please help with love2d function which can detect a quad from RPG sprite automatically. currently I am guessing the quad dimension and generating it with love.graphics.newQuad(). Please help me in this regard.
User avatar
darkfrei
Party member
Posts: 1186
Joined: Sat Feb 08, 2020 11:09 pm

Re: AUTOMATIC QUAD DETECTOR

Post by darkfrei »

How good is your spritesheet?
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
walk.png (25.37 KiB) Viewed 4592 times
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
run.png (21.78 KiB) Viewed 4592 times
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
jump.png (38.61 KiB) Viewed 4592 times
https://ezgif.com/sprite-cutter
Image
Image
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
EngineerSmith
Prole
Posts: 38
Joined: Thu Dec 02, 2021 11:38 am
Contact:

Re: AUTOMATIC QUAD DETECTOR

Post by EngineerSmith »

Why would you need to guess the size of your quads? They should all be equal in size to allow easy animation. Just count the width and height of the first frame and that's the size of that quad for that animation. You could write a meta file which holds this information for each file and have a system that reads that meta file to find how the size (You'd have to write the file though).

Unless your sprites are separate pngs then you can use a texture atlas packer like mine https://github.com/EngineerSmith/Export-TextureAtlas then you can add it to your build pipeline which packs all the sprites together and outputs a file with all the quad data to read in
DebasishDatta
Prole
Posts: 17
Joined: Fri Nov 26, 2021 5:15 am

Re: AUTOMATIC QUAD DETECTOR

Post by DebasishDatta »

EngineerSmith , sorry to say , but I am not particularly clear with your explanation. For example, from your first picture how would you know what will be the size of the fist quad so that the figure of first cat fits in exactly.
User avatar
EngineerSmith
Prole
Posts: 38
Joined: Thu Dec 02, 2021 11:38 am
Contact:

Re: AUTOMATIC QUAD DETECTOR

Post by EngineerSmith »

I'd open it in my picture editing software of choice and draw a shape over it or you can just make an educated guess: if the sprite sheet only contains one animation like those cats in top most picture each frame would be (10 frames / 380 pixels width)X(60 pixels height) : 38x60
User avatar
milon
Party member
Posts: 472
Joined: Thu Jan 18, 2018 9:14 pm

Re: AUTOMATIC QUAD DETECTOR

Post by milon »

DebasishDatta wrote: Sun Dec 19, 2021 4:52 am can someone please help with love2d function which can detect a quad from RPG sprite automatically. currently I am guessing the quad dimension and generating it with love.graphics.newQuad(). Please help me in this regard.
That depends entirely on how you index your quads. Personally, I index them as a one-dimensional table that I create when I load the image. You can index them differently, but you'll need to adapt my code to fit your style. Note that all code I'm about to post assumes there's a 1 pixel border between sprites, as recommended on the wiki to prevent bleeding when things get rotated or scaled.

This is the function I use to create quads for a given image:

Code: Select all

function newQuadsList(tileSize, width, height)
    local tilesX = (width - 1) / (tileSize + 1)
    local tilesY = (height - 1) / (tileSize + 1)
    local quadsList = {}
    for y = 1, tilesY do
        for x = 1, tilesX do
            quadsList[(y - 1) * tilesX + x] = love.graphics.newQuad((x - 1) * (tileSize + 1) + 1, (y - 1) * (tileSize + 1) + 1, tileSize, tileSize, width, height)
        end
    end
    return quadsList
end

I also wrote a tool to help me with exactly this same problem - finding the quad index number for a given sprite. Here it is! It assumes sprites are 32x32 pixels, but you can change that before running it. Just run it, then drag & drop your picture on it and mouse over the quad you want to know about. Use arrow keys to scroll the image and ESC to quit.

Code: Select all

-- Quad Finder
-- Helps determine a tile's position & quad number within its image
-- Assumes a 1px border between each tile!


-- User Input
local tiles = {w=32, h=32}  -- Size in pixels of tiles in image


-- Initialize
love.keyboard.setKeyRepeat(true)
image, mouse, screen = {}, {}, {}
screen.w, screen.h = love.graphics.getDimensions()
love.window.setMode(screen.w, screen.h, {resizable=true})
image.x, image.y, mouse.x, mouse.y = 0, 0, 0, 0
mouse.tile, mouse.tileX, mouse.tileY, image.file = "na", "na", "na", "na"
screen.foot = 35

function updateFooter()
    if image.img then
        screen.text = "Quad:"..mouse.tile.."   tile:"..mouse.tileX..","..mouse.tileY.."   mouse:"..mouse.x..","..mouse.y.."\nsize:"..image.w.."x"..image.h.."   file:"..image.file
    else
        screen.text = "Drag & drop a picture here!"
    end
end

function love.resize(w, h)
    screen.w, screen.h = w, h
end

function love.load()
    updateFooter()
end

function love.keypressed(key)
    if     key == "left"  or key == "a" and image.x < 0 then image.x = image.x + 10
    elseif key == "right" or key == "d" and image.x + image.w > screen.w then image.x = image.x - 10
    elseif key == "up"    or key == "w" and image.y < 0 then image.y = image.y + 10
    elseif key == "down"  or key == "s" and image.y + image.h > screen.h - screen.foot then image.y = image.y - 10
    elseif key == "escape" then love.event.quit()
    end
end

function love.filedropped(file)
    image.x, image.y = 0, 0
    if image.img then image.img:release(); image.img = nil end
    image.img = love.graphics.newImage(file)
    image.w, image.h = image.img:getDimensions()
    if type(file) ~= "string" then file = file:getFilename() end
    image.file = file
    image.tilesX = (image.w - 1) / (tiles.w + 1)
    image.tilesY = (image.h - 1) / (tiles.h + 1)
    assert(image.tilesX == math.floor(image.tilesX), "Incorrect image or tile size supplied!\nImage is "..image.w.."x"..image.h.."\nExpected tile size was "..tiles.w.."x"..tiles.h.."\nResulting image tile size: "..image.tilesX.." x "..image.tilesY)
    updateFooter()
end

function love.mousemoved(x, y, dx, dy)
    if not image.img then return end
    
    -- update x-axis
    mouse.x = x - image.x
    if mouse.x > image.w then
        mouse.tileX = "na"
    else
        mouse.tileX = mouse.x / (tiles.w + 1)
        if mouse.tileX == math.floor(mouse.tileX) then
            mouse.tileX = "na"
        else
            mouse.tileX = math.floor(mouse.tileX) + 1
        end
    end
    
    -- update y-axis
    mouse.y = y - image.y
    if mouse.y > image.h then
        mouse.tileY = "na"
    else
        mouse.tileY = mouse.y / (tiles.h + 1)
        if mouse.tileY == math.floor(mouse.tileY) then
            mouse.tileY = "na"
        else
            mouse.tileY = math.floor(mouse.tileY) + 1
        end
    end
    
    -- update hover tile
    if mouse.tileX == "na" or mouse.tileY == "na" then
        mouse.tile = "na"
    else
        mouse.tile = (mouse.tileY - 1) * image.tilesX + mouse.tileX
    end
    
    updateFooter()
end

function love.draw()
    if image.img then love.graphics.draw(image.img, image.x, image.y) end
    love.graphics.setColor(0, 0, 0)
    love.graphics.rectangle("fill", 0, screen.h - screen.foot, screen.w, screen.foot)
    love.graphics.setColor(1, 1, 1)
    love.graphics.print(screen.text, 10, screen.h - screen.foot + 3)
end
Any code samples/ideas by me should be considered Public Domain (no attribution needed) license unless otherwise stated.
DebasishDatta
Prole
Posts: 17
Joined: Fri Nov 26, 2021 5:15 am

Re: AUTOMATIC QUAD DETECTOR

Post by DebasishDatta »

milon wrote: Mon Dec 20, 2021 6:26 pm
DebasishDatta wrote: Sun Dec 19, 2021 4:52 am can someone please help with love2d function which can detect a quad from RPG sprite automatically. currently I am guessing the quad dimension and generating it with love.graphics.newQuad(). Please help me in this regard.
That depends entirely on how you index your quads. Personally, I index them as a one-dimensional table that I create when I load the image. You can index them differently, but you'll need to adapt my code to fit your style. Note that all code I'm about to post assumes there's a 1 pixel border between sprites, as recommended on the wiki to prevent bleeding when things get rotated or scaled.

This is the function I use to create quads for a given image:

Code: Select all

function newQuadsList(tileSize, width, height)
    local tilesX = (width - 1) / (tileSize + 1)
    local tilesY = (height - 1) / (tileSize + 1)
    local quadsList = {}
    for y = 1, tilesY do
        for x = 1, tilesX do
            quadsList[(y - 1) * tilesX + x] = love.graphics.newQuad((x - 1) * (tileSize + 1) + 1, (y - 1) * (tileSize + 1) + 1, tileSize, tileSize, width, height)
        end
    end
    return quadsList
end

I also wrote a tool to help me with exactly this same problem - finding the quad index number for a given sprite. Here it is! It assumes sprites are 32x32 pixels, but you can change that before running it. Just run it, then drag & drop your picture on it and mouse over the quad you want to know about. Use arrow keys to scroll the image and ESC to quit.

Code: Select all

-- Quad Finder
-- Helps determine a tile's position & quad number within its image
-- Assumes a 1px border between each tile!


-- User Input
local tiles = {w=32, h=32}  -- Size in pixels of tiles in image


-- Initialize
love.keyboard.setKeyRepeat(true)
image, mouse, screen = {}, {}, {}
screen.w, screen.h = love.graphics.getDimensions()
love.window.setMode(screen.w, screen.h, {resizable=true})
image.x, image.y, mouse.x, mouse.y = 0, 0, 0, 0
mouse.tile, mouse.tileX, mouse.tileY, image.file = "na", "na", "na", "na"
screen.foot = 35

function updateFooter()
    if image.img then
        screen.text = "Quad:"..mouse.tile.."   tile:"..mouse.tileX..","..mouse.tileY.."   mouse:"..mouse.x..","..mouse.y.."\nsize:"..image.w.."x"..image.h.."   file:"..image.file
    else
        screen.text = "Drag & drop a picture here!"
    end
end

function love.resize(w, h)
    screen.w, screen.h = w, h
end

function love.load()
    updateFooter()
end

function love.keypressed(key)
    if     key == "left"  or key == "a" and image.x < 0 then image.x = image.x + 10
    elseif key == "right" or key == "d" and image.x + image.w > screen.w then image.x = image.x - 10
    elseif key == "up"    or key == "w" and image.y < 0 then image.y = image.y + 10
    elseif key == "down"  or key == "s" and image.y + image.h > screen.h - screen.foot then image.y = image.y - 10
    elseif key == "escape" then love.event.quit()
    end
end

function love.filedropped(file)
    image.x, image.y = 0, 0
    if image.img then image.img:release(); image.img = nil end
    image.img = love.graphics.newImage(file)
    image.w, image.h = image.img:getDimensions()
    if type(file) ~= "string" then file = file:getFilename() end
    image.file = file
    image.tilesX = (image.w - 1) / (tiles.w + 1)
    image.tilesY = (image.h - 1) / (tiles.h + 1)
    assert(image.tilesX == math.floor(image.tilesX), "Incorrect image or tile size supplied!\nImage is "..image.w.."x"..image.h.."\nExpected tile size was "..tiles.w.."x"..tiles.h.."\nResulting image tile size: "..image.tilesX.." x "..image.tilesY)
    updateFooter()
end

function love.mousemoved(x, y, dx, dy)
    if not image.img then return end
    
    -- update x-axis
    mouse.x = x - image.x
    if mouse.x > image.w then
        mouse.tileX = "na"
    else
        mouse.tileX = mouse.x / (tiles.w + 1)
        if mouse.tileX == math.floor(mouse.tileX) then
            mouse.tileX = "na"
        else
            mouse.tileX = math.floor(mouse.tileX) + 1
        end
    end
    
    -- update y-axis
    mouse.y = y - image.y
    if mouse.y > image.h then
        mouse.tileY = "na"
    else
        mouse.tileY = mouse.y / (tiles.h + 1)
        if mouse.tileY == math.floor(mouse.tileY) then
            mouse.tileY = "na"
        else
            mouse.tileY = math.floor(mouse.tileY) + 1
        end
    end
    
    -- update hover tile
    if mouse.tileX == "na" or mouse.tileY == "na" then
        mouse.tile = "na"
    else
        mouse.tile = (mouse.tileY - 1) * image.tilesX + mouse.tileX
    end
    
    updateFooter()
end

function love.draw()
    if image.img then love.graphics.draw(image.img, image.x, image.y) end
    love.graphics.setColor(0, 0, 0)
    love.graphics.rectangle("fill", 0, screen.h - screen.foot, screen.w, screen.foot)
    love.graphics.setColor(1, 1, 1)
    love.graphics.print(screen.text, 10, screen.h - screen.foot + 3)
end
That's very nice. Your code is a god one too. But if you know any function in love2d which can detect an optimum quad from an image file , that would be better, otherwise we have to manually fixed the image file first , then able to perform our operations e.g extracting quads etc.
User avatar
dusoft
Party member
Posts: 539
Joined: Fri Nov 08, 2013 12:07 am
Location: Europe usually
Contact:

Re: AUTOMATIC QUAD DETECTOR

Post by dusoft »

DebasishDatta wrote: Tue Dec 21, 2021 4:18 am That's very nice. Your code is a god one too. But if you know any function in love2d which can detect an optimum quad from an image file , that would be better, otherwise we have to manually fixed the image file first , then able to perform our operations e.g extracting quads etc.
There is nothing like that as previously said. You could however do background color pixel detection between quads, e.g. iterating over X axis and looking (approximating) for space between images. Once you find a pattern of repeated background color over certain intervals (e.g. each 33px is white, while 32px and 34px are colored and same applies for 65px etc.), you could split quads based on that. This requires some fuzzy detection work.
User avatar
Nikki
Citizen
Posts: 83
Joined: Wed Jan 25, 2017 5:42 pm

Re: AUTOMATIC QUAD DETECTOR

Post by Nikki »

What are the tiles you are looking at? could you post an example?
DebasishDatta
Prole
Posts: 17
Joined: Fri Nov 26, 2021 5:15 am

Re: AUTOMATIC QUAD DETECTOR

Post by DebasishDatta »

dusoft wrote: Tue Dec 21, 2021 10:36 am
DebasishDatta wrote: Tue Dec 21, 2021 4:18 am That's very nice. Your code is a god one too. But if you know any function in love2d which can detect an optimum quad from an image file , that would be better, otherwise we have to manually fixed the image file first , then able to perform our operations e.g extracting quads etc.
There is nothing like that as previously said. You could however do background color pixel detection between quads, e.g. iterating over X axis and looking (approximating) for space between images. Once you find a pattern of repeated background color over certain intervals (e.g. each 33px is white, while 32px and 34px are colored and same applies for 65px etc.), you could split quads based on that. This requires some fuzzy detection work.
Ok, thank you for your suggestion.
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests