ReFreezed wrote: ↑Thu Mar 03, 2022 11:42 am
I didn't intend for my example to show how scaled sprites can look better when using subpixels, but sure, you could use subpixels for that purpose I guess.
Short story: can you extend the first example with moving camera and screenToWorldMouseXY / worldToScreenMouseXY ?
So I can extract the code and re-use that, I have most of the code now but that part is still not working.
Long story:
After your example and some weeks later... I finally have implemented your code.
Most of the time I had problem with font scaling and get the correct mouse coordinates when scaling the window or using fullscreen.
I don't use a hardware cursor (image), but I draw somethings using the mouse coordinates.
But that is not the problem anymore, that is working.
Now I spend some time creating the moving 'camera' but now i'm confused.
Maybe your can solve this last part for me?
canvas.lua
Code: Select all
function Canvas:new(data)
self.name = data.name
self.x = data.x or 0
self.y = data.y or 0
self.width = data.width or love.graphics.getWidth()
self.height = data.height or love.graphics.getHeight()
self.subpixels = data.subpixels
self.integerScaling = data.integerScaling
-- the real canvas
self.canvas = love.graphics.newCanvas(self.width * self.subpixels, self.height * self.subpixels)
self.canvas:setFilter("nearest", "nearest")
-- calculated
self.scale = 1
self.scaledWidth = nil
self.scaledHeight = nil
entityManager:add(self)
end
function Canvas:setSubpixels(s)
self.subpixels = s
end
function Canvas:setX(x)
self.x = x
end
function Canvas:setY(y)
self.y = y
end
function Canvas:getX()
return self.x
end
function Canvas:getY()
return self.y
end
function Canvas:getSubpixels()
return self.subpixels
end
---
-- This is without the subpixels
function Canvas:getHeight()
return self.height
end
---
-- This is without the subpixels
function Canvas:getWidth()
return self.width
end
---
-- This is with the optional subpixels and current render
function Canvas:getRenderHeight()
return self:getCanvas():getHeight()
end
---
-- This is with the optional subpixels and current render
function Canvas:getRenderWidth()
return self:getCanvas():getWidth()
end
---
-- The calculated width scaled
function Canvas:getScaledWidth()
return self.scaledWidth
end
---
-- The calculated height scaled
function Canvas:getScaledHeight()
return self.scaledHeight
end
---
-- The love canvas object
function Canvas:getCanvas()
return self.canvas
end
---
-- The calculated scale factor
function Canvas:getScale()
return self.scale
end
-- return width and height
function Canvas:getDimensions()
return self.canvas:getDimensions()
end
function Canvas:scaleMath()
local _, _, windowWidth, windowHeight = love.window.getSafeArea()
local canvasWidth, canvasHeight = self:getDimensions()
-- Fill as much of the window as possible with the canvas while preserving the aspect ratio.
self.scale = math.min(windowWidth / canvasWidth, windowHeight / canvasHeight)
-- self.scale = windowHeight / canvasHeight -- This would fill the height and possibly cut off the sides.
if self.integerScaling then
self.scale = math.floor(self.scale * self:getSubpixels()) / self:getSubpixels()
self.scale = math.max(self.scale, 1 / self:getSubpixels()) -- Avoid self.scale =0 if the window is tiny!
end
self.scaledWidth = canvasWidth * self.scale
self.scaledHeight = canvasHeight * self.scale
-- center canvas
self:setX(math.floor((windowWidth - self.scaledWidth) / 2))
self:setY(math.floor((windowHeight - self.scaledHeight) / 2))
end
-- function Canvas:release(args)
-- end
return Canvas
config.lua (snippet)
Code: Select all
self.canvas = {}
self.canvas.width = 320
self.canvas.height = 180
self.canvas.integerScaling = true
self.canvas.subpixels = 4
conf.lua
Code: Select all
-- 1x 320x180
-- 2x 640x360
-- 4x 1280x720 -- < minimal target height
-- 6x 1920x1080 (fullHD)
-- 12x 3840x2160 (4K)
t.window.width = 1280 -- The window width (number)
t.window.height = 720 -- The window height (number)
camera.lua (snippet)
I was trying to implement a follow player x,y like
https://github.com/a327ex/STALKER-X
But then with less code, without all the functions, to understand what is happening, and I only need the follow player
Code: Select all
function Camera:follow(x, y)
self.targetX, self.targetY = x, y
end
function Camera:setBounds(x, y, w, h)
self.bound = true
self.bounds_min_x = x
self.bounds_min_y = y
self.bounds_max_x = x + w
self.bounds_max_y = y + h
end
function Camera:attach()
-- extend inside the main.lua below the canvas things
love.graphics.translate(math.floor(self.width / 2), math.floor(self.height / 2))
love.graphics.translate(-math.floor(self.x), -math.floor(self.y))
end
function Camera:update(dt)
if self.targetX == nil or self.targetY == nil then
return
end
self.x, self.y = self.targetX, self.targetY
-- if self.bound then
-- self.x = math.min(math.max(self.x, self.bounds_min_x + self.width / 2), self.bounds_max_x - self.width / 2)
-- self.y = math.min(math.max(self.y, self.bounds_min_y + self.height / 2), self.bounds_max_y - self.height / 2)
-- end
end
main.lua (snippet)
Code: Select all
function draw()
self.canvas:scaleMath()
-- Draw to the canvas
love.graphics.push("all")
love.graphics.setCanvas(self.canvas:getCanvas())
love.graphics.clear()
love.graphics.scale(self.canvas:getSubpixels())
self.camera:attach() -- at the moment without push/pop
self.world:draw()
love.graphics.pop()
love.graphics.clear(0, 0, 0)
love.graphics.draw(self.canvas:getCanvas(), self.canvas:getX(), self.canvas:getY(), 0, self.canvas:getScale())
end
function love.mousepressed(xOrg, yOrg, button, istouch, presses)
local x, y = xOrg, yOrg
if self.cursor then
x, y = self.cursor:getScreenToWorldXY(x, y)
end
self.world:mousePressedEvent(
{
x = x,
y = y,
button = button,
istouch = istouch,
presses = presses
}
)
end
function love.resize(w, h)
-- calculate so we have the new variables
self.canvas:scaleMath()
-- forward to other entities
self.world:windowResizeEvent(
{
w = w,
h = h
}
)
end
cursor.lua (snippet)
Code: Select all
function Cursor:getScreenToWorldXY(x, y)
return self:getScreenToWorldX(x), self:getScreenToWorldY(y)
end
function Cursor:getScreenToWorldX(x)
x = x or love.mouse.getX()
return ((x - self.gameCanvas:getX()) / self.gameCanvas:getSubpixels()) / self.gameCanvas:getScale()
-- I have to do something here with the self.camera.x
end
function Cursor:getScreenToWorldY(y)
y = y or love.mouse.getY()
return ((y - self.gameCanvas:getY()) / self.gameCanvas:getSubpixels()) / self.gameCanvas:getScale()
-- I have to do something here with the self.camera.y
end
Inside cursor.lua I have to include the camera x and y. I try several things but this is what is happening right now:
- I click at the right side
- Player is moving to the right side (camera moves to the left side, looks good for now)
- The cursor position is not correct anymore
I do mean local x, y = self:getScreenToWorldXY() is not correct.
First I thought , just do things like this but it don't work.
Code: Select all
function Cursor:getScreenToWorldX(x)
x = x or love.mouse.getX()
x = ((x - self.gameCanvas:getX()) / self.gameCanvas:getSubpixels()) / self.gameCanvas:getScale()
if self.camera then
x = x - self.camera.x
end
end