Author Topic: How to filter an entity iterator?  (Read 323 times)

alexgleason

  • Full Member
  • ***
  • Posts: 102
  • Vegan on a Desert Island
    • View Profile
    • Vegan on a Desert Island
How to filter an entity iterator?
« on: September 24, 2018, 12:03:15 am »
So I've used:

Code: ( lua) [Select]
map:get_entities_in_rectangle(x, y, width, height)
which gave me back a nice entity iterator.

The problem is, I only want some of those entities. For example, I might want only entities where:

Code: ( lua) [Select]
entity:get_type() == "custom_entity" and entity:get_model() == "trash"
I know how to loop through it and build a new array, but I'd like to learn how to create a new entity iterator. Is it possible to do this without dumping the contents of the first iterator into an array first? I'm new to Lua and trying to figure this out. :)

Thanks!
RIP Aaron Swartz

Diarandor

  • Hero Member
  • *****
  • Posts: 1035
  • Cats are cool! (ΦωΦ)
    • View Profile
Re: How to filter an entity iterator?
« Reply #1 on: September 24, 2018, 12:24:34 am »
The best way to do that is exactly the way you are doing it:
Code: (Lua) [Select]
for entity in map:get_entities_in_rectangle(x, y, width, height) do
  if entity:get_type() == "custom_entity" and entity:get_model() == "trash" then
    -- blablabla cats meow meow!
  end
end
Always put the stronger condition in the outer built-in iterator, because that one is optimized. (For instance, getting first the custom entities and later the "rectangle overlapping" condition would be slightly slower). In this case you cannot do it with only 1 loop (you need to filter with "if" conditions).
“If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you.”

alexgleason

  • Full Member
  • ***
  • Posts: 102
  • Vegan on a Desert Island
    • View Profile
    • Vegan on a Desert Island
Re: How to filter an entity iterator?
« Reply #2 on: September 24, 2018, 12:55:36 am »
What I'm trying to do is actually return a new entity iterator. For context, I'm making an item similar to the gust jar in Minish Cap. I'm wanting item:get_suckable_entities() to return an entity iterator containing items of a certain type in a certain region so I can loop over it.

I just managed to finish writing this code:

Code: ( lua) [Select]
-- Get suckable entities
function item:get_suckable_entities()

  local map  = self:get_map()

  -- Get entities in suckable rectangle
  local entities = map:get_entities_in_rectangle(self:get_suckable_rectangle())

  -- Filter only suckable types
  filtered = {}
  for entity in entities do
    for model in item:get_suckable_models() do
      if entity:get_type() == "custom_entity" and entity:get_model() == model then
        table.insert(filtered, entity)
      end
    end
  end

  function filtered_entities()
    local i = 0
    local n = table.getn(filtered)
    return function()
      i = i + 1
      if i <= n then return filtered[i] end
    end
  end

  return filtered_entities()
end

It totally works, but I was hoping there would be a way to achieve this without dumping everything into a filtered table first and then creating a new iterator out of that table.

Thanks for your reply. :)

EDIT: My full code is now here for context https://gitlab.com/voadi/voadi/blob/master/data/items/vacuum.lua
« Last Edit: September 24, 2018, 01:18:27 am by alexgleason »
RIP Aaron Swartz

alexgleason

  • Full Member
  • ***
  • Posts: 102
  • Vegan on a Desert Island
    • View Profile
    • Vegan on a Desert Island
Re: How to filter an entity iterator?
« Reply #3 on: September 25, 2018, 09:22:41 pm »
This library seems to do what I want, but it doesn't look possible in normal Lua: https://github.com/starwing/luaiter

It has a fitlerout(func, iter) function.
RIP Aaron Swartz

Christopho

  • Administrator
  • Hero Member
  • *****
  • Posts: 1162
    • View Profile
Re: How to filter an entity iterator?
« Reply #4 on: September 25, 2018, 09:35:34 pm »
We are planning to do this in Solarus 1.7: https://gitlab.com/solarus-games/solarus/issues/843