"Questions that don't deserve their own thread" thread

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.
Locked
User avatar
Tchey
Prole
Posts: 25
Joined: Sun Jan 10, 2016 10:44 am
Contact:

Re: "Questions that don't deserve their own thread" thread

Post by Tchey »

Oh, that was simple. (i.Thank .. " you.")
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: "Questions that don't deserve their own thread" thread

Post by zorg »

also, string formatting is faster than concatenation, so be aware of that.
alternatively you could store data in tables, and table.concat those all at once, that's fast.
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
Beelz
Party member
Posts: 234
Joined: Thu Sep 24, 2015 1:05 pm
Location: New York, USA
Contact:

Re: "Questions that don't deserve their own thread" thread

Post by Beelz »

In theory, what do you think is the best way to do checkpoints for a racing game be? Not looking for code, just a general thought on the best way to implement them... I figure probably give each checkpoint it's own self:update function to check for items passing through, but my gut is saying there's a better way. I don't know, what do you guys think?

Code: Select all

if self:hasBeer() then self:drink()
else self:getBeer() end
GitHub -- Website
bobbyjones
Party member
Posts: 730
Joined: Sat Apr 26, 2014 7:46 pm

Re: "Questions that don't deserve their own thread" thread

Post by bobbyjones »

Make a table of check points. Then have the racer object check if it collides with one of them. If you have a lot of checkpoints you could probably use bump to speed it up. This is what I would do anyways.
User avatar
aloisdeniel
Prole
Posts: 17
Joined: Sat Jan 30, 2016 5:57 pm
Contact:

Re: "Questions that don't deserve their own thread" thread

Post by aloisdeniel »

Hello, I wonder how its less performant to use pairs instead of ipairs.

For example, for storing a tiled map, I often see something like :

Code: Select all


local map = {
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  {0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0 },
  {0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0 },
}

for y,row in ipairs(map)  do
  for x,tile in ipairs(row) do
      -- draw tile to x,y
  end
end
But, it could also be stored like (that involves less loops) :

Code: Select all

local map = {
  [2] = { [5] = 1, [6] = 2, [7] = 1 },
  [3] = { [5] = 1, [6] = 2, [7] = 1 },
}

for y,row in pairs(map)  do
  for x,tile in pairs(row) do
      -- draw tile to x,y
  end
end
I know it depends on the number of empty slot etc ... but dors anyone know the real impact of *pairs* ?
My LÖVE libraries : pixelatlas, pixelmap
bobbyjones
Party member
Posts: 730
Joined: Sat Apr 26, 2014 7:46 pm

Re: "Questions that don't deserve their own thread" thread

Post by bobbyjones »

Pairs is really slow in luajit. Iirc it's like 4x slower. It also makes the code around it slower by not allowing it to be JIT compiled. Although it is slower it probably will not matter if you are only looping through a few objects. If it's over 100 you probably would want to start benchmarking it to make sure its not effecting your game.
User avatar
pgimeno
Party member
Posts: 3637
Joined: Sun Oct 18, 2015 2:58 pm

Re: "Questions that don't deserve their own thread" thread

Post by pgimeno »

Your question is more complex than it seems, and it would probably deserve its own thread.

There are cases in which a sparse table (by that I mean a table in which not all values are defined) makes more sense than a (dense) sequence (one in which all values from 1 to some N are defined). Whether that's your case depends on your application, and judging what's best can be quite tough, and ultimately only resolvable by testing. It's even possible that the result of the testing reveals your application behaves faster with one method in some parts and faster with the other in some other parts, making the decision even harder.

Your example is not comparing equals to equals. To draw a map, if the screen covers the whole of the map then in order to use the sparse method, you need to pre-fill the background with the default tile and then go through each tile the way you've indicated. Whether that pre-filling voids the gains obtained by making the map sparse is an issue. However, I've found that LuaJIT performs better with ipairs than with pairs in your specific example, but with Lua it's the contrary:

Code: Select all

require 'socket'
local gettime = socket.gettime

function test(use_ipairs)
  local map
  if use_ipairs then
    map = {
      {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
      {0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0 },
      {0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0 },
    }
  else
    map = {
      [2] = { [5] = 1, [6] = 2, [7] = 1 },
      [3] = { [5] = 1, [6] = 2, [7] = 1 },
    }
  end

  local starttime
  local endtime
  local sum = 0

  starttime = gettime()
  if use_ipairs then
    for i = 1, 1000000 do
      for k, v in ipairs(map) do
        for k, v in ipairs(v) do
          sum = sum + v
        end
      end
    end
  else
    for i = 1, 1000000 do
      for k, v in pairs(map) do
        for k, v in pairs(v) do
          sum = sum + v
        end
      end
    end
  end
  endtime = gettime()

  return endtime - starttime, sum
end

-- Ensure both branches are pre-compiled
test(false)
test(true)

print("With  pairs:", test(false))
print("With ipairs:", test(true))
A typical result:

Code: Select all

$ love .
With  pairs:	0.12001514434814	8000000
With ipairs:	0.094685077667236	8000000

$ luajit main.lua 
With  pairs:	0.12058019638062	8000000
With ipairs:	0.094517946243286	8000000

$ lua main.lua 
With  pairs:	1.1777708530426	8000000
With ipairs:	3.2261650562286	8000000
For maps bigger than the screen, you don't iterate over all tiles; you iterate over the visible portion of the tiles. That means that you typically don't use pairs or ipairs for that. You use loops with numeric indexes.

Code: Select all

for y = top, top + height - 1 do
  for x = left, left + width - 1 do
    -- draw the tile
  end
end
In that case, for the sparse table Lua still has to do a hash lookup for every coordinate, and chances are that a sequence will perform much better.

After changing the loops in the test function like this, to accommodate for that kind of map:

Code: Select all

  starttime = gettime()
  if use_ipairs then
    for i = 1, 1000000 do
      for y = 1, 3 do
        for x = 1, 11  do
          sum = sum + map[y][x]
        end
      end
    end
  else
    for i = 1, 1000000 do
      for y = 1, 3 do
        if map[y] then
          for x = 1, 11  do
            if map[y][x] then
              sum = sum + map[y][x]
            end
          end
        end
      end
    end
  end
  endtime = gettime()
ipairs trumps pairs even under Lua:

Code: Select all

$ luajit main.lua 
With  pairs:	0.18178987503052	8000000
With ipairs:	0.046344995498657	8000000

$ lua main.lua 
With  pairs:	3.0706739425659	8000000
With ipairs:	2.5100657939911	8000000
bobbyjones
Party member
Posts: 730
Joined: Sat Apr 26, 2014 7:46 pm

Re: "Questions that don't deserve their own thread" thread

Post by bobbyjones »

I wonder if things have changed since this benchmark. Your numbers suggest that things have.
bobbyjones
Party member
Posts: 730
Joined: Sat Apr 26, 2014 7:46 pm

Re: "Questions that don't deserve their own thread" thread

Post by bobbyjones »

One more way to store that data is to just insert {tiledID,x,y} into an array which would be a smaller table to iterate over and you can take advantage of ipairs.
adge
Citizen
Posts: 54
Joined: Mon Dec 14, 2015 8:50 pm

Re: "Questions that don't deserve their own thread" thread

Post by adge »

I'm just wondering if you could pass a function to a function in lua?
Locked

Who is online

Users browsing this forum: No registered users and 5 guests