Making several conveyors change their direction ?

Started by garsim, August 30, 2013, 10:13:18 PM

Previous topic - Next topic
Hello,

I wanted to use the conveyors, but with a little difference : indeed, I want to make them change direction (east-north-west-south-east-etc.).

I have this map with twelve conveyors respectively called "conveyor_1", "conveyor_2", etc. and a sensor which activates the rotation when Link crosses it :



As the documentation doesn't seem to indicate a method set_direction for conveyors, I made a script in the map.lua which removes and create again the conveyors in a new direction :

local current_conveyor_direction = 0

-- Conveyors position
local random_conveyors = {
{ x = 376, y = 1261 },
{ x = 440, y = 1261 },
{ x = 504, y = 1261 },
{ x = 568, y = 1261 },
{ x = 376, y = 1325 },
{ x = 440, y = 1325 },
{ x = 504, y = 1325 },
{ x = 568, y = 1325 },
{ x = 376, y = 1389 },
{ x = 440, y = 1389 },
{ x = 504, y = 1389 },
{ x = 568, y = 1389 }
}

function change_conveyors_direction()
-- Destruct conveyors before creating them again in another direction
map:remove_entities("conveyor_")

-- Change the direction of conveyors (0 : east, 2 : north, 4 : west, 6 : south)
current_conveyor_direction = current_conveyor_direction + 2
if current_conveyor_direction > 7 then
current_conveyor_direction = 0
end

-- Create conveyors
    for i = 1, 12, 1 do
map:create_conveyor_belt{
name = "conveyor_" .. i,
layer = 1,
x = random_conveyors[i].x,
y = random_conveyors[i].y,
direction = current_conveyor_direction
}
    end

    sol.timer.start(2000, change_conveyors_direction)
end

-- Activate the change of direction when Link walks on the sensor
function active_random_conveyors:on_activated()
change_conveyors_direction()
active_random_conveyors:set_enabled(false)
end


But when the function change_conveyors_direction is called for the second time, the game crashes :
Error: an entity with name 'conveyor_1' already exists.

So is the function map:remove_entities("conveyor_") not working, or are the conveyors removed only at the end of the function ?

map:remove_entities() works, but entities are actually removed at the next cycle. For me, it is a bug that you can't re-use the name right now. So I entered it in the bug tracker: https://github.com/christopho/solarus/issues/282
I also entered another issue to implement conveyor:set_direction: https://github.com/christopho/solarus/issues/281

In the meantime, what you should do is to make with the map editor 4 conveyor in each spot (one for each direction), and use conveyor:set_enabled() to enable only one of them every time. Do you see what I mean?

In general, using set:enabled() is much easier than removing and re-creating entities. Actually, that's why this bug exist: I almost never remove and re-create entities in my games.

I hope it helps :)

That being said, your puzzle looks nice and your code is well commented. I hope you will share your game on this forum soon :P

August 31, 2013, 08:50:43 PM #2 Last Edit: August 31, 2013, 09:05:01 PM by garsim
Quote from: Christopho on August 31, 2013, 05:59:41 PMIn the meantime, what you should do is to make with the map editor 4 conveyor in each spot (one for each direction), and use conveyor:set_enabled() to enable only one of them every time. Do you see what I mean?

In general, using set:enabled() is much easier than removing and re-creating entities. Actually, that's why this bug exist: I almost never remove and re-create entities in my games.
I see. In fact, I was thinking about this possibility, but I considered that it was less complicated to remove and re-create than creating 4 entities for each conveyor. But if it's the best solution now, I guess I'll do this.  :P

But considering what you said about remove_entities(), maybe I also see another possibility : if I put the part of the first function where I re-create the conveyors in another callback function called one or two cycles after, maybe the problem of remove_entities will disappear. I'll try this, just in case.

Quote from: Christopho on August 31, 2013, 05:59:41 PMThat being said, your puzzle looks nice and your code is well commented. I hope you will share your game on this forum soon :P
Thank you.  :)
For now on, I essentially did mapping so I don't think there are many things to say about my project. But I eventually intended to share some scripts meantime (I'm currently working on a Beamos (from Alttp) implementation, maybe some quest developers would be interested).


Edit : finally, the alternative of waiting few cycles seems to work.  :) Of course it's not the best way to do this since there are a few cycles where the conveyors don't appear... but the player won't mind about two cycles missing I guess.  ;D

Here is the new code :

local map = ...
local brouillard
local mouvement_brouillard

local current_conveyor_direction = 0

-- Conveyors position
local random_conveyors = {
{ x = 376, y = 1261 },
{ x = 440, y = 1261 },
{ x = 504, y = 1261 },
{ x = 568, y = 1261 },
{ x = 376, y = 1325 },
{ x = 440, y = 1325 },
{ x = 504, y = 1325 },
{ x = 568, y = 1325 },
{ x = 376, y = 1389 },
{ x = 440, y = 1389 },
{ x = 504, y = 1389 },
{ x = 568, y = 1389 }
}

local function create_conveyors()
-- Remove conveyors before creating them again in another direction
local function remove_conveyors()
map:remove_entities("conveyor_")
sol.timer.start(2, create_conveyors) -- Cannot create the conveyors in the same cycle than the one when they disappear, have to wait.
end

-- Change the direction of conveyors (0 : east, 2 : north, 4 : west, 6 : south)
current_conveyor_direction = current_conveyor_direction + 2
if current_conveyor_direction > 7 then
current_conveyor_direction = 0
end

-- Create conveyors
    for i = 1, 12, 1 do
map:create_conveyor_belt{
name = "conveyor_" .. i,
layer = 1,
x = random_conveyors[i].x,
y = random_conveyors[i].y,
direction = current_conveyor_direction
}
    end

    sol.timer.start(1898, remove_conveyors)
end



-- Activate the change of direction when Link walks on the sensor
function active_random_conveyors:on_activated()
create_conveyors()
active_random_conveyors:set_enabled(false)
end

Where are the sensors ? On the conveyors, or between ? Because I was thinking : conveyors could have an event "on_activated", launched when the hero enters it.

It could be useful, to extrapolate a little the enigma presented here, in the following example :

Conveyors turn on themselves each 1s, but they must stop when the hero is on it (or just the one the hero took) : without the "on_activated" event, I suppose you have to place sensors on them, but that's a cheat more than a real solution (IMHO).

It's just a proposition...

In fact, there is just one sensor, which is used to activate the conveyor's rotation. But it could be launched from the start, when the map starts. So my first version didn't really need a sensor.

And there is indeed the little problem with the conveyor which can rotate even if the hero is on it, but I don't know if it's really frustrating or not. But I think it could be solved even without a "on_activated" event or twelve sensors ; I read in the documentation that there is a method "entity:get_distance(other_entity)" and it could be useful. For example, we can think about a function which calls "conveyor_x:get_distance(map:get_entity(hero))" and returns true if the distance is short enough (it would mean that the hero is on it).