love2d / love

LÖVE is an awesome 2D game framework for Lua.
https://love2d.org
Other
5.22k stars 405 forks source link

One number variant of setColor #1596

Open IsometricShahil opened 4 years ago

IsometricShahil commented 4 years ago
love.graphics.setColor(n)

will be the same as (if type(n) == "number")

love.graphics.setColor(n, n, n, 1.0)

This will be very useful to quickly set colors to white or black or gray

bjornbytes commented 4 years ago

lovr has a one number variant but it's for hexcodes:

love.graphics.setColor(0xc0ffee) -- (can add alpha as 2nd arg too)

For a while it seemed sketchy but now I can't really live without it

zorggn commented 4 years ago

Both could technically be implemented on the lua side, question is how useful it'd be to support it on the C++ side...

local oldsetcolor = love.graphics.setColor
function love.graphics.setColor(a,b,c,d)
  if type(a) == 'string' then
    local s = a:gsub('0x','')-- sub potential 0x from start of string
    -- if # of characters is 6, set rgb, if it's 8, set rgba
    if #s == 8 then
      d = tonumber(s:sub(7,8), 16)/255
    end
    a,b,c = tonumber(s:sub(1,2), 16)/255, tonumber(s:sub(3,4), 16)/255, tonumber(s:sub(5,6), 16)/255 -- probably there's a better solution; this is just an example
  elseif type(a) == 'number' and type(b) == 'nil' and type(c) == 'nil' then
    b, c = a, a -- set others to the same number
  end
  d = d or 1.0 -- default for alpha
  oldsetcolor(a,b,c,d)
end
MikuAuahDark commented 4 years ago

I don't think it's worth supporting this in C side since it's very trivial to be done in Lua side

local function GRAYSCALE(n, a)
    return n, n, n, a or 1
end

function love.draw()
    -- Sets color to 0.5, 0.5, 0.5, 1.0
    love.graphics.setColor(GRAYSCALE(0.5))
    love.graphics.print("grayscale 0.5")
end

We also can't add support for bjornbytes's lovr.graphics.setColor variant because LOVE 11.0 and later changes the color range from 0..255 to 0..1 but if you really need one for (constant) hexcodes, you can use my color.lua.

local color = require("color")

function love.draw()
    love.graphics.setColor(color.hex00FFFF)
    love.graphics.print("color.hex00FFFF")
end
hahawoo commented 3 years ago

This would be convenient, but I don't think that this would be LÖVEly (i.e. fit in with rest of the API) so I don't think it should be added.

But, it is true that it would be a convenient way to set the color to a grayscale color, especially black or white, I'm sure we've all written love.graphics.setColor(0, 0, 0) and love.graphics.setColor(1, 1, 1) countless times.

@zorggn and @MikuAuahDark both mention that it can be done with Lua. But why does this matter?

rude kind of touched on it in this interview:

LÖVE doesn't have tilemaps, UI, Camera, etc. The Animation object was even removed. Why do you choose to keep LÖVE to the basics like that?

"High level" things are (for me) mostly just in the way, and never work quite the way I need for a specific case. It's really easy to create a high level component which seems nice, but in reality is too inflexible for many cases, leaving lovers to develop their own e.g. tilemap component anyway, feeling sad that the built-in component is just uselessly standing there. So it's better if such things are made as third-party Lua libraries, so they're easier to modify or extend.

Also, there is an unwritten "emergent" guideline, which says that things which can be easily done in pure Lua should be done in pure Lua. This is affecting the API a bit, I think.

Of course this change to love.graphics.setColor isn't "high level" at all, but it is something that can be done in pure Lua.

If you look around LÖVE's API, there's not much that could be done in pure Lua unless it provides a significant performance benefit (i.e. particle systems or the physics engine), or it's just that useful (i.e. love.filesystem.read/write/append whose functionality could be replicated with File objects, but it would be quite inconvenient).

But why not have more convenience functions? One reason, which I think is related to the "high level" things that rude talked about, is that they might be a bit arbitrary, and not exactly what you want. What if I use transparency a lot, and I want love.graphics.setColor(0.5) to mean love.graphics.setColor(1, 1, 1, 0.5)? Or what if I type love.graphics.setColor(1, 1, 1) so often that I want love.graphics.setColor() without an argument to set the color to pure white? And why is the API encouraging me to color things in 256 shades of gray?

And if this convenience function is OK, why not \<insert other potential convenience function here>? For example, being able to set HSL colors would be convenient, but if this was also added, I would expect many more functions based on the same reasoning. And why this would be an issue brings me to the main reason why I think convenience functions should be limited in LÖVE's API: each one is simply one more thing to learn.

As a side note, LÖVE is similar to Lua in this regard. Compared with Python for example, there's a lot less to the language (and it doesn't have many "high level" libraries). Lua and LÖVE both being minimal like this has its pros and cons.

Another thing to consider is what precedent this sets within the API. For example, would love.graphics.setBackgroundColor(0) also behave like setColor? What about ImageData:setPixel(x, y, 0)? It's not obvious either way. These functions also take tables of color values, so would love.graphics.setColor({0}) work? And does `love.graphics.setColor(1, 0.5) set a white pixel with 50% opacity, or error? It's not obvious.