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

alexgleason

  • Newbie
  • *
  • Posts: 29
    • 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
  1. 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
  1. 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!

Diarandor

  • Hero Member
  • *****
  • Posts: 1018
  • 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
  1. for entity in map:get_entities_in_rectangle(x, y, width, height) do
  2.   if entity:get_type() == "custom_entity" and entity:get_model() == "trash" then
  3.     -- blablabla cats meow meow!
  4.   end
  5. 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

  • Newbie
  • *
  • Posts: 29
    • 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
  1. -- Get suckable entities
  2. function item:get_suckable_entities()
  3.  
  4.   local map  = self:get_map()
  5.  
  6.   -- Get entities in suckable rectangle
  7.   local entities = map:get_entities_in_rectangle(self:get_suckable_rectangle())
  8.  
  9.   -- Filter only suckable types
  10.   filtered = {}
  11.   for entity in entities do
  12.     for model in item:get_suckable_models() do
  13.       if entity:get_type() == "custom_entity" and entity:get_model() == model then
  14.         table.insert(filtered, entity)
  15.       end
  16.     end
  17.   end
  18.  
  19.   function filtered_entities()
  20.     local i = 0
  21.     local n = table.getn(filtered)
  22.     return function()
  23.       i = i + 1
  24.       if i <= n then return filtered[i] end
  25.     end
  26.   end
  27.  
  28.   return filtered_entities()
  29. 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 »

alexgleason

  • Newbie
  • *
  • Posts: 29
    • 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.

Christopho

  • Administrator
  • Hero Member
  • *****
  • Posts: 1137
    • 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