Post-0.10.0 feature wishlist

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Post-0.10.0 feature wishlist

Post by raidho36 »

You can always track your own time using timer function. It's a high resolution timer so there aren't repercussions to using it.
Fuzzlix
Citizen
Posts: 60
Joined: Thu Oct 13, 2016 5:36 pm

Re: Post-0.10.0 feature wishlist

Post by Fuzzlix »

raidho36 wrote:You can always track your own time using timer function. It's a high resolution timer so there aren't repercussions to using it.
Thats all true, but i dont want to track "my own time for something". I want to fine tune the love.run() loop.
One in most cases sufficiant way is vsync=true but this is somehow out of my control.
Please imagine the following situation: I create a chess like game. Most of the time the window needs no update. Therefore 20fps are more than enouth and my weak gpu will bcome less stressed. To maintain a constant loop time i need to know as exact as possible the time went by since the last love.update(). Knowing this time would allow me to sleep() until the next love.update() call. To figure this time out the getDelta() function is not helpfull because the returned deltatime is outdated (late by one loop).
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Post-0.10.0 feature wishlist

Post by zorg »

Fuzzlix wrote:
raidho36 wrote:You can always track your own time using timer function. It's a high resolution timer so there aren't repercussions to using it.
Thats all true, but i dont want to track "my own time for something". I want to fine tune the love.run() loop.
I'm pretty sure you do want to time how much time your code spends in the current love.run loop cycle.
You can't really do what you want to any other way. Fine-tuning love.run with dynamic sleep times, i mean.
Fuzzlix wrote:One in most cases sufficient way is vsync=true but this is somehow out of my control.
Well, that depends on the current screen's refresh rate, if it works, that is. I wouldn't rely on it a 100%.
Fuzzlix wrote:Please imagine the following situation: I create a chess like game. Most of the time the window needs no update. Therefore 20fps are more than enouth and my weak gpu will bcome less stressed.
Despite how the default love.run works, update time usually does not equal draw(render) time. Besides, with 20 FPS, your input will be choppy as well, even for a turn-based game as chess, 1/3th of a second of potential input delay is noticeable, and to be honest, quite irritating.

Also, until you benchmarked exactly how a simple chess game can melt down your GPU, i'd tend to say you're trying to over-optimize (prematurely) right now.
Fuzzlix wrote:To maintain a constant loop time i need to know as exact as possible the time went by since the last love.update(). Knowing this time would allow me to sleep() until the next love.update() call. To figure this time out the getDelta() function is not helpfull because the returned deltatime is outdated (late by one loop).
Maintaining a constant loop time means you not messing with love.run (and love.timer.sleep) though. Also, dynamically calculating how much time has elapsed and sleeping that amount will never sleep for exactly how much you want it to... OS schedulers won't be nice to your program, just because you'd ask nicely; there may and probably will be drifts in the timing.
By the way, as you saw in love.run, love.timer.step gets called in there, and getDelta basically uses that to compute the elapsed times.

Note that i'm not saying you shouldn't experiment with love.run, only that what you're trying to do doesn't really make much sense to me, for your use-case. It will probably bring you more bugs than whatever you intended for it to solve.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
pgimeno
Party member
Posts: 3549
Joined: Sun Oct 18, 2015 2:58 pm

Re: Post-0.10.0 feature wishlist

Post by pgimeno »

Fuzzlix wrote:It looks like, getDelta() returns the time between the last 2 step() calls? In this case the result of getDelta() would be outdated by one loop! Shure it is not a big issue but i cant get any information about the actual time spent since the last step() command and sometimes i need this information.
I suggest a new pair of functions which may be used in addition or as a replacement to the existing ones:

func1(): returning the time since the last step() command.
func2(): returning the time since the last step() command AND executing step().

Inside your love.run() you call...

Code: Select all

love.update(func2())
...to get the time spent since the last love.update(dt) and reset the timer automatically.
In the next love.run() loop you can call func1() as often you wish to get the time spent since the last love.update() call without the 1-loop-delay the getDelta() function has.
I don't think it makes sense to have such a function. Your func1() describes exactly [wiki]love.timer.getDelta[/wiki]() and your func2() can easily be implemented like this:

Code: Select all

function func2()
  love.timer.step()
  return love.timer.getDelta()
end
Or viceversa, if that's what you mean:

Code: Select all

function func2()
  local elapsed = love.timer.getDelta()
  love.timer.step()
  return elapsed
end
but then the returned time would be 1 frame behind.

Without having looked at the sources, my understanding is that the implementations of [wiki]love.timer.step[/wiki]() and [wiki]love.timer.getDelta[/wiki]() are functionally equivalent to the following:

Code: Select all

local frozenDelta = 0
local lastTime = love.timer.getTime()

function step()
  local oldTime = lastTime
  lastTime = love.timer.getTime()
  frozenDelta = lastTime - oldTime
end

function getDelta()
  return frozenDelta
end
How do you propose any new functions to work in terms of [wiki]love.timer.getTime[/wiki]()?
Fuzzlix
Citizen
Posts: 60
Joined: Thu Oct 13, 2016 5:36 pm

Re: Post-0.10.0 feature wishlist

Post by Fuzzlix »

pgimeno wrote: Or viceversa, if that's what you mean:

Code: Select all

function func2()
  local elapsed = love.timer.getDelta()
  love.timer.step()
  return elapsed
end
but then the returned time would be 1 frame behind.
Exactly! that is the state now. i can call getDelta() as often as i wish and i get the same result until i call step(). As you mentioned, this delta time is one frame late! THIS is the state now and i have no chance to get a information about the actual time spent since the last step() call. This limits my abilities to fine tune the love.run() loop.
pgimeno wrote: Without having looked at the sources, my understanding is that the implementations of [wiki]love.timer.step[/wiki]() and [wiki]love.timer.getDelta[/wiki]() are functionally equivalent to the following:

Code: Select all

local frozenDelta = 0
local lastTime = love.timer.getTime()

function step()
  local oldTime = lastTime
  lastTime = love.timer.getTime()
  frozenDelta = lastTime - oldTime
end

function getDelta()
  return frozenDelta
end
How do you propose any new functions to work in terms of [wiki]love.timer.getTime[/wiki]()?
Ok lets try it in pseudo code:

Code: Select all

local lastTime = love.timer.getTime();
function newStep()
  local t = lastTime;
  lastTime = love.timer.getTime();
  return lastTime - t;
end;

function newGetDelta()
  return love.timer.getTime() - lastTime;
end;
Multiple calls of newGetDelta() will return different results depending how long my code ran since the last newStep() call.
Fuzzlix
Citizen
Posts: 60
Joined: Thu Oct 13, 2016 5:36 pm

Re: Post-0.10.0 feature wishlist

Post by Fuzzlix »

I think i found out, whats so difficult to understand on my proposal: When i look at the [wiki]love.run[/wiki] example code for 0.10.0 the calls for step() and getDelta() are placed close together without any code between.

I want to sleep some time until the next update() and draw() calls need to run. In front of love.update() i call step() like the example code and i want to run the next love.update() exactly (lets say) 20ms later. I need to find out how long the last love.update() and love.draw() calls took for calculating the time, i need to sleep. Lets say, it took 5ms, i want to sleep 15ms and the next love.update() call will be issued 20ms past the previous one.
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: Post-0.10.0 feature wishlist

Post by bartbes »

Fuzzlix wrote: As you mentioned, this delta time is one frame late!
This is the way it's supposed to work, you then use the delta time to simulate the period between the start of the previous frame and this one. It works well, without any big surprises, and you get a consistent end result, one where all entities are at the "same position in time", the start of this frame.

That said, if you are intent on doing this, you can do so now. Instead of calling love.timer.step() (or in addition to), store the current time in a variable, then wherever you want to figure out how much time has passed since that point, get the current time and subtract that start time from it.
User avatar
slime
Solid Snayke
Posts: 3132
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Post-0.10.0 feature wishlist

Post by slime »

Fuzzlix wrote:
pgimeno wrote: Or viceversa, if that's what you mean:

Code: Select all

function func2()
  local elapsed = love.timer.getDelta()
  love.timer.step()
  return elapsed
end
but then the returned time would be 1 frame behind.
Exactly! that is the state now.
This example has one frame of delay compared to the default [wiki]love.run[/wiki]. In that example, the past delta is retrieved and then step is called which updates the internal delta, but it's not retrieved until the next frame.

With the default love.run, the delta time is calculated and then retrieved at the start of every frame. Since you need the delta time right after the start of the frame in order to use love.update, its latency cannot be reduced from that.

Keep in mind this is the time that an entire frame takes (which is generally what you want if you want your numbers in terms of real time). If you just want to compute the time that an update step takes, you can do that manually. You can also pretty easily have a fixed update rate and a variable display frame rate. This is a popular webpage which goes into detail about it: http://gafferongames.com/game-physics/f ... -timestep/
Fuzzlix
Citizen
Posts: 60
Joined: Thu Oct 13, 2016 5:36 pm

Re: Post-0.10.0 feature wishlist

Post by Fuzzlix »

zorg wrote:
Fuzzlix wrote:One in most cases sufficient way is vsync=true but this is somehow out of my control.
Well, that depends on the current screen's refresh rate, if it works, that is. I wouldn't rely on it a 100%.
True! and using vsync i am fixed to the screen refresh rate.
zorg wrote:
Fuzzlix wrote:Please imagine the following situation: I create a chess like game. Most of the time the window needs no update. Therefore 20fps are more than enouth and my weak gpu will bcome less stressed.
Despite how the default love.run works, update time usually does not equal draw(render) time. Besides, with 20 FPS, your input will be choppy as well, even for a turn-based game as chess, 1/3th of a second of potential input delay is noticeable, and to be honest, quite irritating.

Also, until you benchmarked exactly how a simple chess game can melt down your GPU, i'd tend to say you're trying to over-optimize (prematurely) right now.
All true :) It was a example to visualize a game that is more a round based strategy game than a jump and run game. When waiting for user input i have to update some (lets say) sprite animations (4..8 changes/sec).
zorg wrote:Note that i'm not saying you shouldn't experiment with love.run, only that what you're trying to do doesn't really make much sense to me, for your use-case. It will probably bring you more bugs than whatever you intended for it to solve.
Ok lets talk about pros and cons:
At least one pro: love.update() allways will get the correct delta time no matter what i do in my own love.run().

the standard love.run becomes simpler:

Code: Select all

 ...
-- Update dt, as we'll be passing it to update
	if love.timer then
		dt = love.timer.step() -- no need for love.timer.getDelta() anymore
	end
-- Call update and draw
	if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled

	if love.graphics and love.graphics.isActive() then
		love.graphics.clear(love.graphics.getBackgroundColor())
		love.graphics.origin()
		if love.draw then love.draw() end
		love.graphics.present()
	end

	if love.timer then love.timer.sleep(0.001) end
You see, the changes to existing code are minimal and give freedom to the programmer to implement somthing like - lets say - this:

Code: Select all

local fps = 20 -- or whatever you want as fps.
local sleepTime = 1 / fps;

 ...

-- Update dt, as we'll be passing it to update
	if love.timer then
		love.timer.sleep(max(sleepTime - (love.timer.getDelta()), 0.001));
		dt = love.timer.step() -- no need for love.timer.getDelta() anymore
	end
-- Call update and draw
	if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled

	if love.graphics and love.graphics.isActive() then
		love.graphics.clear(love.graphics.getBackgroundColor())
		love.graphics.origin()
		if love.draw then love.draw() end
		love.graphics.present()
	end
	--if love.timer then love.timer.sleep(0.001) end
If var fps is global, you can adjust the loop rate dynamically, which may help to save power on mobile devices.

But it is not more or less than an answer on the stated question: "What feature do you want to see in the next release."
It is up to you, guys, to judge. :)
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Post-0.10.0 feature wishlist

Post by zorg »

In any case, here's my love.run, just to contrast:

Code: Select all

love.run = function()
	if love.math then
		love.math.setRandomSeed(os.time())
	end
 
	if love.load then love.load(arg) end
 
	-- We don't want the first frame's dt to include time taken by love.load.
	if love.timer then love.timer.step() end

	local dt = 0.0    -- delta time
 
 	local tr = 1/100  -- tick rate
 	local fr = 1/75   -- frame rate

	local da = 0.0    -- draw accumulator
	local ua = 0.0    -- update accumulator
 
	-- Main loop time.
	while true do
		-- Process events.
		if love.event then
			love.event.pump()
			for name, a,b,c,d,e,f in love.event.poll() do
				if name == "quit" then
					if not love.quit or not love.quit() then
						return a
					end
				end
				love.handlers[name](a,b,c,d,e,f)
			end
		end
 
		-- Update dt, as we'll be passing it to update
		if love.timer then
			love.timer.step()
			dt = love.timer.getDelta()
			da = da + dt
			ua = ua + dt
		end
 
		-- Call audio
		if love.atomic then love.atomic(dt) end

		-- Call update
		if ua > tr then
			if love.update then
				love.update(tr) -- will pass 0 if love.timer is disabled
			end
			ua = ua % tr
		end
 
 		-- Call draw
 		if da > fr then
			if love.graphics and love.graphics.isActive() then
				love.graphics.clear(love.graphics.getBackgroundColor())
				love.graphics.origin()
				if love.draw then love.draw() end -- no interpolation
				love.graphics.present()
			end
			da = da % fr
		end
 
 		-- Optimal sleep time, anything higher does not go below 0.40 % cpu
 		-- utilization; 0.001 results in 0.72 %, so this is an improvement. (on my computer anyway, results may vary)
		if love.timer then love.timer.sleep(0.002) end
	end
end
Note that this isn't perfect either, but it does the job i want it to do. :3
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 100 guests