Ohhh okay. I was wondering why you had the subtraction thing, thanks.s-ol wrote:You didn't implement what I mentioned in my comment by the way. It's not a big deal for a snake game, but it can already be a noticeable effect and make the game easier to play for some players than for others, depending on hardware.mynameisnotpaul wrote:I tried implementing this code but it just results in my snake thing not moving at all. I changed the code a bit from the OP but I still don't know why it doesn't work. This is the code for reference:s-ol wrote: This is also what I would recommend, except you describe it in a bit complicated of a way - you are just talking about substraction. I usually do it like this:
Code: Select all
local time = 0 function love.update (dt) time = time + dt if time >= time_to_do_stuff then -- do stuff time = time - time_to_do_stuff end end
Code: Select all
... function love.update (dt) time = time + dt ... if time > snakeHead.speed then time = 0 end end
For example, imagine someone is playing at a constant 60 fps. That means dt is 1/60, and so after 6 frames "time" is at 0.1, but nothing happens yet, and then at 7 frames you reset the timer to 0 and do something.
So for one, your time is actually inaccurate, with a 'speed' of 0.1 and 60fps it takes not 6/60 = 0.10 but 7/60 = 0.1166s per loop.
That's already a lot of drift, but it's not that bad since if you designed the game and tested it, it doesn't really matter if when you mean 0.1 you actuall get 0.116 seconds, as long as it's consistent. But it's not:
Let's do the same example for someone who plays at 50fps:
1/50 * 5 = 0.1
but because you used a > instead of a >= it will loop only at 6/50 again, which is 1.2s, again different.
If you change it and add the >= these two examples will behave the same, but for framerates that don't evenly multiply up to your time of 0.1, the "time = 0" approach is going to be inaccurate anyway, and if dt is changing all the time aswell. For example with 45fps:
4/45 = 0.088 (< 0.1)
5/45 = 0.111 (< 0.1)
now if you subtract 0.1 from the "time" variable, the next iteration will have exactly 0.1 seconds to run, but with the time = 0, you are forgetting the fact that 0.011 seconds have passed already.
All these rather small numbers don't look like much of a difference, but your game is already harder at some speeds than on others, and if you write code like this it probably will be extremely hard to build something multiplayer.
I think I mainly understand now, but I'm confused as to how math.floor works here. If it rounds the decimal to the closest lower integer, wouldn't it keep lowering it to 0? Because if math.floor() rounds down, and square.y = square.y + 10*0.0001 would make square.y = 0.001, and when that is /10 and floored, wouldn't that just go back to 0?zorg wrote:A very brief example:mynameisnotpaul wrote:Hi, thanks for helping I fixed everything else you said but could you explain what you mean by the flooring part with examples of my code? It would probably make me understand much better.zorg wrote:Note that this will result in the snake's position having non-integer coordinates most of the time, but that can be solved with drawing it out floored in love.draw. (You can also floor it to a "bigger" grid, like, every 20 pixels or so: math.floor(n/20)*20 for example)Edit: See s-ol's post below for what i mean the last meaningful line in love.update being "more correct".Code: Select all
local square = {} -- Our object local grid = 10 -- pixels local speed = 10 -- pixels/second function love.load() -- Let's define it to start in the window's top-left corner with a width and height of 10 pixels. square.x = 0 square.y = 0 square.w = 10 square.h = 10 end function love.update(dt) -- Let's just have the square move downwards constantly -- This will make the y coordinate part have a fractional part, and is basically the "real" position of the object. square.y = square.y + speed * dt -- dt makes it framerate independent, so it will always go with a speed of 10 px/s -- Also let's wrap it around, if we want to treat the game area as a torus... if square.y >= love.graphics.getHeight() then square.y = square.y - love.graphics.getHeight() -- or just make it = 0, but this is more "correct". end end function love.draw() -- Here comes the trickery, we only want to draw the square on the grid in a way, that it snaps to the grid's size that we defined. local x,y = math.floor(square.x/grid)*grid, math.floor(square.y/grid)*grid -- We only modify y above, but this is useable for both axes. love.graphics.rectangle('fill',x,y,square.w,square.h) end
Still, thanks a lot for helping !