Alternating alpha value depending on y position

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.
adge
Citizen
Posts: 54
Joined: Mon Dec 14, 2015 8:50 pm

Alternating alpha value depending on y position

Post by adge »

Hi there!

I got a mathematical problem and I cant quite get the solution.
I got an raster where the cells are 20x20 pixels big. The whole raster is 300x300 px big. So my raster got 15x15 cells.
On pressing the return button, a block at x=random(0,300) y=0 gets spawned with speed = random(1,20).

This block is stored in the table blocks = {} and gets deleted when exceeding the maximum y of 300.

Draw function:

Code: Select all

for i,block in ipairs(blocks) do
	love.graphics.rectangle("fill", math.floor(block.x/20)*20,math.floor(block.y/20)*20, 20, 20)
end	


As the code shows, every block is drawn in on cell as long his position is in it's cells coordinates.
So if the blocks position is between 20 and 40 pixels, the block will be drawn in the 20-40 raster. If his position is 41, he will be drawn in the 40-60 cell and so on.
Now I wanted to add an alternating alpha value so that the block will get darker the more he reaches the cells boundaries. From 20 to 30 the alpha value would change from 0 to 255. When the blocks y position reaches 31 the alpha value will decrease linear to 0 so that it's 0 when the blocks y equals 40.
However I can't do the math. First I thought a modulus division would do it but it didn't work since the modulus isn't alternating.

alpha = math.abs(math.sin(block.y*9))*255

The *9 is for converting the y position to a degree value the sin can work with.
I thought that way:

If y=10*9 = 90 then sin would be 1, times 255 would be 255 which is what I want.
If y= 20*9 = 180 then sin would be 0, times 255 would be 255 which is also what I want.
I think the math is correct but I don't know why it still does not work.

This is now true alternating but it's way to fast for the blocks actual movement. It blinks like ten times before the blocks position changes to the next cell beneath.
I attached the project to the post. So if you know how to solve this issue, then please tell me.

Press enter to spawn a block :D
Attachments
raster.love.zip
(886 Bytes) Downloaded 52 times
User avatar
pgimeno
Party member
Posts: 2614
Joined: Sun Oct 18, 2015 2:58 pm

Re: Alternating alpha value depending on y position

Post by pgimeno »

I think this will do it:

Code: Select all

alpha = 255 - math.abs(block.y % 20 - 10) / 10 * 255
The idea is:
1. find the local coordinate within the cell, that's block.y % 20. That's a value between 0 (inclusive) and 20 (not inclusive).
2. the center is 10 so subtracting 10 will give you a number between -10 and 10, which will be 0 at the center and -10 or 10 at the border (actually it will never be exactly 10, but it can be 9.999999...).
3. the absolute value of that will tell you the distance from the center as a number between 0 and 10.
4. dividing that by 10 will give you a ratio of how far it is from the center, with 1 being max and 0 being min.
5. multiplying that by 255 will give you a value between 0 and 255 which is usable as alpha.
6. However, it's reversed with respect to what you want, because alpha is opacity and you want it fully opaque when it's 0, so 255 minus that will give you the alpha you want.

One more note. random(0, 300) will give you 301 possible values, not 300. You probably want random(0, 299).

Edit: That's how to make it linear as you requested. If you want to make it sinusoidal instead of linear, then you can use math.pi/20 instead of 9, that is:

Code: Select all

alpha = math.abs(math.sin(block.y/20*math.pi))*255
Edit 2: Your reasoning for using 9 = 180/20 was correct, the problem is that Lua uses radians, not degrees.
Last edited by pgimeno on Fri Jan 29, 2016 10:43 pm, edited 1 time in total.
User avatar
Beelz
Party member
Posts: 234
Joined: Thu Sep 24, 2015 1:05 pm
Location: New York, USA
Contact:

Re: Alternating alpha value depending on y position

Post by Beelz »

Well seems his answer is better than what I came up with, but I already commented through your code so I'll post it anyways.

Also, you don't need to zip up the .love file to post it here, just makes more work. ;)
fixed.love
(1.16 KiB) Downloaded 75 times

Code: Select all

if self:hasBeer() then self:drink()
else self:getBeer() end
GitHub -- Website
adge
Citizen
Posts: 54
Joined: Mon Dec 14, 2015 8:50 pm

Re: Alternating alpha value depending on y position

Post by adge »

Thank you for your fast reply guys. @pgimeno, your solution works flawlessly, thank you very much.
@Beelz: thank you for commenting through my code. That helped me a lot.
Coding small projects and uploading them seems like a good way to learn if people are willing to comment through the code. This helps a lot. Thank you!

If it's ok I would like to ask a bunch of other questions.

I'm still pretty new to love2d and came from GameMaker where you never had to do stuff like this, so I don't really have a solution for that.
I'm trying to create a tile based level editor where you can build maps, load tiles, save maps, load maps and so on. To start I started with some simple button implementations to create a menu. These buttons don't have labels yet, they are just blue boxes. But If you klick on the first one, the state changes from menu to editor. In the editor state is another button drawn which gets you back to the menu state. However I think my code is a bit messy since I'm checking in the update function for for the state which then creates the state's buttons and adds them to the button table. Performance wise this seems like bad coding since the buttons are created and added to the table every frame. However I don't know how to do it either.
I searched the web and found a few "game states" libraries. But most of them just feel to big and heavy for what I need, moreover I would like to do my own to understand how it would work if I really needed one. But I wouldn't even know where to start.

For any reason my laptop wouldn't let me to attach the plain .love file. So I had to zip it. Again. I'm sorry.
Attachments
Level_editor.love.zip
(947 Bytes) Downloaded 49 times
User avatar
pgimeno
Party member
Posts: 2614
Joined: Sun Oct 18, 2015 2:58 pm

Re: Alternating alpha value depending on y position

Post by pgimeno »

I think that separating the states into different files is essential; otherwise you're maintaining several different parts of your program intermixed in a single file. It's even possible that one of these states needs to be broken down into more files.

You don't really need a library to manage states. Managing states can be done simply with a function like this (almost identical to the one I used for Thrust II Reloaded):

Code: Select all

local active

function activate(new)
    if active and active.deactivate then active.deactivate() end
    active = new
    if active.activate then active.activate() end
end
Then you hook the events like this:

Code: Select all

function love.update(dt)
    if active.update then active.update(dt) end
end
function love.draw()
    if active.draw then active.draw() end
end
-- and so on with all events you need
Each state would have code that would look like this:

Code: Select all

local state = {}

function state.update(dt)
  -- update code specific to this state
end

function state.draw()
  -- draw code specific to this state
end

-- if it needs to do something when activated:
function state.activate()
  -- do stuff when it's activated
end

-- if it needs to do something when deactivated:
function state.deactivate()
  -- do stuff when it's deactivated
end
...
return state
To load it, you would use this in main.lua:

Code: Select all

states = {}

states.mystate1 = require('mystate1')
states.mystate2 = require('mystate2')
...
You would start in love.load, by calling the state's load() if present, and then activating the first state with:

Code: Select all

function love.load(args)
  ...
  for k, v in pairs(states) do
    if v.load then v.load(args) end
  end
  activate(states.mystate1)
end
As for your buttons, you can define them in state.activate() or in state.load(), depending on whether they may change every time the menu is invoked or not. They can be local to that file, to prevent clashes with other modules, and you only need to create them once.

Code: Select all

UI = require("UI") -- includes UI.addButton to add a button to the given table and UI.draw to draw all buttons
local mainmenu = {} -- The state variable

local buttons
...
function mainmenu.activate()
  buttons = {}
  UI.addButton(buttons, ...)
  UI.addButton(buttons, ...)
end

function mainmenu.draw()
  UI.draw(buttons)
end

function mainmenu.mousedown(x, y, mousebutton)
  -- code to handle click here which possibly calls activate(states.otherstate)
end
...

return mainmenu
Note however that UIs typically handle events by themselves. Using a pre-made library for the UI is probably a better idea, or you can make your own one if you're brave enough.

Edit: I've attached an example using the Gspöt GUI:
Attachments
stateful.love
(10.24 KiB) Downloaded 55 times
adge
Citizen
Posts: 54
Joined: Mon Dec 14, 2015 8:50 pm

Re: Alternating alpha value depending on y position

Post by adge »

Hmmm....

is state.load() /update() and draw() the same as

love.load() / update() and draw() ?

How does this work? I thought these functions were reserved for the main.lua file.
If I got a main.lua and a state.lua file and both make use of a .update() function, wouldn't this then interfere? Thats funny about the documentation. Something like this is never mentioned but it should since it seems quite important.
Would state.graphics.rectangle() then also work??

I don't quite get whats that for:

Code: Select all

local active

function activate(new)
    if active and active.deactivate then active.deactivate() end
    active = new
    if active.activate then active.activate() end
end
I'm sorry to ask but could you please explain the code snippets you've posted a little bit more? Where are they all supposed to be added?
The example you posted seems to work fine but these "huge" libraries just kill me. I don't know whats happening there but I would like to.
User avatar
Beelz
Party member
Posts: 234
Joined: Thu Sep 24, 2015 1:05 pm
Location: New York, USA
Contact:

Re: Alternating alpha value depending on y position

Post by Beelz »

Basically what you are doing is creating a table in another file and returning it... So your other file could look something like this:

Code: Select all

local menu = {} -- the local table of functions

function menu.load()
	-- load menu here
end

function menu.update(dt)
	-- update menu here
end

function menu.draw()
	-- draw menu here
end
return menu
Then in 'main.lua' require your other file and you can use the functions from it:

Code: Select all

local menu = require 'menu' -- the file "menu.lua"

function love.load()
	menu.load()
end

function love.update(dt)
	menu.update(dt)
end

function love.draw()
	menu.draw()
end
adge wrote:Hmmm....

is state.load() /update() and draw() the same as

love.load() / update() and draw() ?

How does this work? I thought these functions were reserved for the main.lua file.
If I got a main.lua and a state.lua file and both make use of a .update() function, wouldn't this then interfere? Thats funny about the documentation. Something like this is never mentioned but it should since it seems quite important.
Would state.graphics.rectangle() then also work??
The menu's functions are called from within Love's callbacks(or more likely a state manager inside the main callbacks). It does not change the main functions like 'love.graphics.rectangle' in any way. It's just for the state handling and sometimes readability.

And for for snippet question that is to change states.

Code: Select all

if self:hasBeer() then self:drink()
else self:getBeer() end
GitHub -- Website
User avatar
pgimeno
Party member
Posts: 2614
Joined: Sun Oct 18, 2015 2:58 pm

Re: Alternating alpha value depending on y position

Post by pgimeno »

Basically what Beelz said. Here's the gist of the idea. Let's make a simpler example with one single event, love.draw(). I've tried to explain every part. To simplify understanding, let's put everything in a single file.

Code: Select all

states = {} -- start with an empty table

-- Menu
states.menu = {} -- add an element to the table 'states', an empty table in the field 'menu'
-- now add to the empty table a function that we can call from love.draw
function states.menu.draw()
    -- when in this state, draw a rectangle
    love.graphics.rectangle("fill", 50, 70, 30, 20)
end
-- per the Lua manual, the above is equivalent to:
-- states.menu.draw = function ()
--     love.graphics.rectangle("fill", 50, 70, 30, 20)
-- end
-- so we're just setting a field in the states.menu table
-- whose value is a function

-- Editor - same idea
states.editor = {}
function states.editor.draw()
    -- when in this state, draw a circle
    love.graphics.circle("fill", 50, 70, 20)
end

-- This variable is set to the active state
local active = states.menu
-- now 'active' has one field: active.draw, which is a function,
-- because states.menu.draw is a function too

-- love.draw is used to draw. We just call active.draw() so that the active
-- state's draw function will do the drawing.
function love.draw()
    -- active.draw() will call states.menu.draw() or states.editor.draw()
    -- depending on whether the value of 'active' is states.menu or
    -- states.editor; in this case we've initialized it to states.menu so the
    -- following line will call states.menu.draw() and draw a rectangle at
    -- the start of the program.
    active.draw()
end

function love.keypressed(k)
    -- Changing the value of 'active' will change which function
    -- active.draw() will call, either states.menu.draw or states.editor.draw
    if k == "left" then active = states.menu end
    if k == "right" then active = states.editor end
end
The basic idea is pretty much the same as in this simpler example:

Code: Select all

local function Draw_the_menu() -- equivalent to states.menu.draw() above
    -- when in this state, draw a rectangle
    love.graphics.rectangle("fill", 50, 70, 30, 20)
end

local function Draw_the_editor()
    -- when in this state, draw a circle
    love.graphics.circle("fill", 50, 70, 20)
end

local Draw_whatever_is_active = Draw_the_menu

function love.draw()
    Draw_whatever_is_active()
end

function love.keypressed(k)
    if k == "left" then Draw_whatever_is_active = Draw_the_menu end
    if k == "right" then Draw_whatever_is_active = Draw_the_editor end
end
The main difference is that it's using tables to organize the states and their events.
adge wrote:The example you posted seems to work fine but these "huge" libraries just kill me. I don't know whats happening there but I would like to.
You have to read the documentation of the library to know how to use it. For GUIs, Gspöt is one of the shortest and most versatile I've seen. It requires you to pass certain events to the library, and that's done in main.lua. If you only want buttons, maybe it's best if you write your own library.
adge
Citizen
Posts: 54
Joined: Mon Dec 14, 2015 8:50 pm

Re: Alternating alpha value depending on y position

Post by adge »

OK!

I didn't know that active.draw() would be the same as states.editor.draw() if you set active to states.editor.
I didn't know that setting active to states.menu would just replace the words states and menu with active. I thought you would still have to write everything in order to call a tables function. Thats why I got confused with the first code snippets postet by pgimeno because active also replaced state.menu.

What i still don't understand is:

Code: Select all

local active

function activate(new)
    if active and active.deactivate then active.deactivate() end
    active = new
    if active.activate then active.activate() end
end
First the if checks if active is not nil and then if active.deactivate is true? But active.deactivate is not set so it would be set to deactivate?
And then if the variable activate in active is true it sets the activated state to true again??
Also I see a lot blahblah:blah. Is this like a function call from a class or something?
User avatar
Beelz
Party member
Posts: 234
Joined: Thu Sep 24, 2015 1:05 pm
Location: New York, USA
Contact:

Re: Alternating alpha value depending on y position

Post by Beelz »

What it's doing is checking if the current state has a "deactivate" function(that stops background music for example), then switches the state and checks if there is a "activate" function on entry into that state. If there is, fire it.

Code: Select all

if self:hasBeer() then self:drink()
else self:getBeer() end
GitHub -- Website
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 28 guests