I'm trying to make a crab that throws a stone using the roth code for an octorok but everytime I run it the sprite disappears during the "shooting" animation with the error:
Error: In timer callback: [string "enemies/crab.lua"]:53: attempt to call global 'go' (a nil value)
Your errors says that you have an error in line 53 because the function go is not defined before (in other words, it is equal to nil). If you still have problems with this, post the code here, so we can help you.
Here is the code:
local enemy = ...
local can_shoot = true
function enemy:on_created()
enemy:set_life(3)
enemy:set_damage(2)
enemy:create_sprite("enemies/" .. enemy:get_breed())
end
local function go_hero()
local sprite = enemy:get_sprite()
sprite:set_animation("walking")
local movement = sol.movement.create("target")
movement:set_speed(64)
movement:start(enemy)
end
local function shoot()
local map = enemy:get_map()
local hero = map:get_hero()
if not enemy:is_in_same_region(hero) then
return true -- Repeat the timer.
end
local sprite = enemy:get_sprite()
local x, y, layer = enemy:get_position()
local direction = sprite:get_direction()
-- Where to create the projectile.
local dxy = {
{ 8, -4 },
{ 0, -13 },
{ -8, -4 },
{ 0, 0 },
}
sprite:set_animation("shooting")
enemy:stop_movement()
sol.timer.start(enemy, 300, function()
sol.audio.play_sound("stone")
local stone = enemy:create_enemy({
breed = "crab_stone",
x = dxy[direction + 1][1],
y = dxy[direction + 1][2],
})
go(direction)
sol.timer.start(enemy, 500, go_hero)
end)
end
function enemy:on_restarted()
local map = enemy:get_map()
local hero = map:get_hero()
go_hero()
can_shoot = true
sol.timer.start(enemy, 100, function()
local hero_x, hero_y = hero:get_position()
local x, y = enemy:get_center_position()
if can_shoot then
local aligned = (math.abs(hero_x - x) < 16 or math.abs(hero_y - y) < 16)
if aligned and enemy:get_distance(hero) < 200 then
shoot()
can_shoot = false
sol.timer.start(enemy, 1500, function()
can_shoot = true
end)
end
end
return true -- Repeat the timer.
end)
end
function enemy:on_movement_changed(movement)
local direction4 = movement:get_direction4()
local sprite = self:get_sprite()
sprite:set_direction(direction4)
end
Do you still get an error or does it work now? And, in case you get an error or something is wrong, what is it?
The error is still
Error: In timer callback: [string "enemies/crab.lua"]:53: attempt to call global 'go' (a nil value)
which is what I dont understand since the go value is supposed to be based on direction as far as I know... The sprite just disappears when its supposed to shoot the rock
You have a 'go' function in line 51 which is not defined in the script.
Ahh I see what you mean now.. I was able to get it work now thanks :)
I'm receiving a similar error message from the octorok script, only instead it is giving an error for method 'go' instead of global 'go'. Also in my case, the octorok moves as it should until the hero gets close to it, then it stops moving. It continues to animate the walking animation, but it is unable to move. It also does not shoot a projectile, but the stone sound can be heard. The hero can even kill it like a normal enemy.
Here's the code:
-- Octorok: shoots stones.
local enemy = ...
local children = {}
local can_shoot = true
function enemy:on_created()
enemy:set_life(3)
enemy:set_damage(2)
enemy:create_sprite("enemies/" .. enemy:get_breed())
end
local function go_hero()
local sprite = enemy:get_sprite()
sprite:set_animation("walking")
local movement = sol.movement.create("target")
movement:set_speed(64)
movement:start(enemy)
end
local function shoot()
local map = enemy:get_map()
local hero = map:get_hero()
if not enemy:is_in_same_region(hero) then
return true -- Repeat the timer.
end
local sprite = enemy:get_sprite()
local x, y, layer = enemy:get_position()
local direction = sprite:get_direction()
-- Where to create the projectile.
local dxy = {
{ 8, -4 },
{ 0, -13 },
{ -8, -4 },
{ 0, 0 },
}
sprite:set_animation("shooting")
enemy:stop_movement()
sol.timer.start(enemy, 300, function()
sol.audio.play_sound("stone")
local stone = enemy:create_enemy({
breed = "octorok_stone",
x = dxy[direction + 1][1],
y = dxy[direction + 1][2],
})
children[#children + 1] = stone
stone:go(direction)
sol.timer.start(enemy, 500, go_hero)
end)
end
function enemy:on_restarted()
local map = enemy:get_map()
local hero = map:get_hero()
go_hero()
can_shoot = true
sol.timer.start(enemy, 100, function()
local hero_x, hero_y = hero:get_position()
local x, y = enemy:get_center_position()
if can_shoot then
local aligned = (math.abs(hero_x - x) < 16 or math.abs(hero_y - y) < 16)
if aligned and enemy:get_distance(hero) < 200 then
shoot()
can_shoot = false
sol.timer.start(enemy, 1500, function()
can_shoot = true
end)
end
end
return true -- Repeat the timer.
end)
end
function enemy:on_movement_changed(movement)
local direction4 = movement:get_direction4()
local sprite = self:get_sprite()
sprite:set_direction(direction4)
end
local previous_on_removed = enemy.on_removed
function enemy:on_removed()
if previous_on_removed then
previous_on_removed(enemy)
end
for _, child in ipairs(children) do
child:remove()
end
end
In a previous message, it was mentioned that 'go' has to be defined. Is this the case here as well? If so, I do not know how to do this
Quote from: ffomega on April 01, 2017, 11:58:57 PM
I'm receiving a similar error message from the octorok script, only instead it is giving an error for method 'go' instead of global 'go'. Also in my case, the octorok moves as it should until the hero gets close to it, then it stops moving. It continues to animate the walking animation, but it is unable to move. It also does not shoot a projectile, but the stone sound can be heard. The hero can even kill it like a normal enemy.
Here's the code:
-- Octorok: shoots stones.
local enemy = ...
local children = {}
local can_shoot = true
function enemy:on_created()
enemy:set_life(3)
enemy:set_damage(2)
enemy:create_sprite("enemies/" .. enemy:get_breed())
end
local function go_hero()
local sprite = enemy:get_sprite()
sprite:set_animation("walking")
local movement = sol.movement.create("target")
movement:set_speed(64)
movement:start(enemy)
end
local function shoot()
local map = enemy:get_map()
local hero = map:get_hero()
if not enemy:is_in_same_region(hero) then
return true -- Repeat the timer.
end
local sprite = enemy:get_sprite()
local x, y, layer = enemy:get_position()
local direction = sprite:get_direction()
-- Where to create the projectile.
local dxy = {
{ 8, -4 },
{ 0, -13 },
{ -8, -4 },
{ 0, 0 },
}
sprite:set_animation("shooting")
enemy:stop_movement()
sol.timer.start(enemy, 300, function()
sol.audio.play_sound("stone")
local stone = enemy:create_enemy({
breed = "octorok_stone",
x = dxy[direction + 1][1],
y = dxy[direction + 1][2],
})
children[#children + 1] = stone
stone:go(direction)
sol.timer.start(enemy, 500, go_hero)
end)
end
function enemy:on_restarted()
local map = enemy:get_map()
local hero = map:get_hero()
go_hero()
can_shoot = true
sol.timer.start(enemy, 100, function()
local hero_x, hero_y = hero:get_position()
local x, y = enemy:get_center_position()
if can_shoot then
local aligned = (math.abs(hero_x - x) < 16 or math.abs(hero_y - y) < 16)
if aligned and enemy:get_distance(hero) < 200 then
shoot()
can_shoot = false
sol.timer.start(enemy, 1500, function()
can_shoot = true
end)
end
end
return true -- Repeat the timer.
end)
end
function enemy:on_movement_changed(movement)
local direction4 = movement:get_direction4()
local sprite = self:get_sprite()
sprite:set_direction(direction4)
end
local previous_on_removed = enemy.on_removed
function enemy:on_removed()
if previous_on_removed then
previous_on_removed(enemy)
end
for _, child in ipairs(children) do
child:remove()
end
end
In a previous message, it was mentioned that 'go' has to be defined. Is this the case here as well? If so, I do not know how to do this
Ahoy there! I am not sure of what could be wrong (I haven't tested the script). Could you post the message error (explicitly) so that we can know in which line it happens?
With the given info I can only say that the problem might be happening in line 55, "stone:go(direction)", so make sure that the "go" function is defined in your stone script.
I am not sure if you have this problem now but, if you see that your "shooting" animation is not started, then try to swap lines 45 and 46, in this order:
enemy:stop_movement()
sprite:set_animation("shooting")
(If an enemy is walking the engine might change its animation to the "walking" animation, so I would stop the movement before changing the animation, just in case.)
I tried swapping lines 45 and 46 and no changed happened. Here is the exact error message. It only appears when the hero gets close enough to the octorok to trigger it to shoot at him.
Error: In timer callback: [string "enemies/Octoroks/octorok.lua"]:55: attempt to call method 'go' (a nil value)
Quote from: ffomega on April 02, 2017, 01:50:36 AM
I tried swapping lines 45 and 46 and no changed happened. Here is the exact error message. It only appears when the hero gets close enough to the octorok to trigger it to shoot at him.
Error: In timer callback: [string "enemies/Octoroks/octorok.lua"]:55: attempt to call method 'go' (a nil value)
-The swap of lines was to make sure that the change of animation is performed, not for your current problem.
-Your error in line 55 confirms what I said. So open your "
octorok_stone.lua" enemy spript (the one for the stone, not the octorok) and take a look inside. The "enemy:go()" function has to be missing there, or has a different name.
Here's the code for the octorok stone:
-- Stone shot by Octorok.
local enemy = ...
function enemy:on_created()
enemy:set_life(1)
enemy:set_damage(2)
enemy:create_sprite("enemies/" .. enemy:get_breed())
enemy:set_size(8, 8)
enemy:set_origin(4, 4)
enemy:set_invincible()
enemy:set_obstacle_behavior("flying")
end
function enemy:on_obstacle_reached()
enemy:remove()
end
function enemy:go(direction4)
local angle = direction4 * math.pi / 2
local movement = sol.movement.create("straight")
movement:set_speed(192)
movement:set_angle(angle)
movement:set_smooth(false)
movement:start(enemy)
enemy:get_sprite():set_direction(direction4)
end
You are trying to call go() from another script.
You can access the other entities' code as soon as they are created.
local stone = enemy:create_enemy({
breed = "crab_stone",
x = dxy[direction + 1][1],
y = dxy[direction + 1][2],
})
Good point, the enemy here is stone, so
go(direction)
is wrong. Because in the rock script, this is what appear
enemy:go(direction4)
It's not global and it is also not local, it is proper to this entity
The solution:
Just call
stone:go(direction)
If the error persists, then it is related to a line in enemy:go(), yet for what I've seen the enemy:go looks ok
@MetalZelda: I think you have read the original post by Starlock and not the last one by ffomega by mistake (in ffomega's script there is no "crab_stone" enemy). Better to point this out before all of us become crazy XD.
@ffomega: I have not been able yet to find the problem and all the code seems correct to me, but there has to be something that we have not found yet. Another possibility is that your enemy is not correctly created because some properties were missing in the property list:
local stone = enemy:create_enemy({
breed = "octorok_stone",
x = dxy[direction + 1][1],
y = dxy[direction + 1][2],
})
You did not define the "direction" and "layer", which are mandatory to create the enemy (if the Lua API is right); probably there is an engine bug if the engine did not give you another bug telling that these properties were missing. So try to add these properties and tell us if this solves the bug or not.
I am getting out of ideas, so let's hope that this fixes the problem :-[
I may have figured out the problem.
I want to create ten different versions of this enemy (and all others for my enemy package) As of right now, the scripts for both enemies (octorok and the stone) have not been rewritten.
To keep all enemies sorted neatly, however, I want to place them all in their own separate folders--in this case, a folder named "Octoroks". It is when I place the enemy script for both the octorok and the stone in its own directory when I begin seeing this problem. If I move the enemy script outside of the Octoroks folder (leaving it in the root directory of "enemies"), it works as intended, so the problem lies in the location of the octorok script. Any ideas on how I can resolve this problem?
Quote from: ffomega on April 02, 2017, 06:48:45 PM
I may have figured out the problem.
I want to create ten different versions of this enemy (and all others for my enemy package).
To keep all enemies sorted neatly, however, I want to place them all in their own separate folders--in this case, a folder named "Octoroks". It is when I place the enemy script for both the octorok and the stone in its own directory when I begin seeing this problem. If I move the enemy script outside of the Octoroks folder (leaving it in the root directory of "enemies"), it works as intended, so the problem lies in the location of the octorok script. Any ideas on how I can resolve this problem?
Nice, you found the problem, I think. The problem is then that your enemy breed is not correct, so it is not correctly created. In the line:
breed = "octorok_stone"
try to write the full path to the file. It should be something like:
breed = "Octoroks/octorok_stone"
but that depends on your folder.
That solved the problem!! Thank you very much :)
@Christopho: This might be an engine bug when the breed path does not exist. Maybe the error is not being displayed.