Help: Enemy disappearing

Started by wizard_wizzle (aka ZeldaHistorian), March 19, 2014, 02:13:40 AM

Previous topic - Next topic
March 19, 2014, 02:13:40 AM Last Edit: March 19, 2014, 02:19:11 AM by wrightmat
Hoping for a little help on one of my bosses. For some reason he keeps disappearing when that's not what I'm intending with my script, so I must be missing something. It seems to happen primarily as he's finishing the "opening" phase.

Enemy script:
local enemy = ...

-- Gohma: Boss who has to be shot in the eye with an arrow to be hurt

function enemy:on_created()
  self:set_life(9)
  self:set_damage(2)
  self:create_sprite("enemies/gohma")
  self:set_hurt_style("boss")
  self:set_size(64, 32)
  self:set_origin(32, 29)
  self:set_attack_consequence("sword", "protected")
  self:get_sprite():set_animation("walking")
end

function enemy:check_action()
  local action = math.random(10)
  if self:get_life() > 6 then
    -- first phase: if less than three hits then mostly just move around (slowly), and create tektites
    local son_name = self:get_name().."_son"
    self:create_enemy{
      name = son_name,
      breed = "tektite_green",
      treasure_name = "heart"
    }
    if action >= 1 and action <= 7 then self:go(96) else self:blink() end
  elseif self:get_life() > 3 and self:get_life() <= 6 then
    -- second phase: if more than 3 but less than 6 hits then blink a lot more, and create tektites
    if action >= 1 and action <= 7 then self:blink() else self:go(96) end
    local son_name = self:get_name().."_son"
    self:create_enemy{
      name = son_name,
      breed = "tektite_green"
    }
  elseif self:get_life() < 3 and self:get_life() > 0 then
    -- final phase: if more than 6 hits then move a lot faster, and create tektites!
    if action >= 1 and action <= 6 then self:blink() else self:go(128) end
    local son_name = self:get_name().."_son"
    self:create_enemy{
      name = son_name,
      breed = "tektite_green"
    }
  end
  sol.timer.start(self, 100, function() self:open() end)
end

function enemy:go(speed)
  self:get_sprite():set_animation("walking")
  self:set_attack_consequence("arrow", 1)
  local m = sol.movement.create("random")
  m:set_speed(speed)
  m:set_max_distance(24)
  m:start(self)
end

function enemy:blink()
  self:set_attack_consequence("arrow", "protected")
  self:get_sprite():set_animation("blinking")
end

function enemy:open()
  self:set_attack_consequence("arrow", 1)
  self:get_sprite():set_animation("opening")
end

function enemy:on_restarted()
  self:get_sprite():set_animation("walking")
  self:check_action()
end

function enemy:on_obstacle_reached()
  self:check_action()
end

function enemy:on_animation_finished(sprite, animation)
  self:set_attack_consequence("arrow", "protected")
  if animation == "blinking" then
    self:get_sprite():set_animation("closed")
    sol.timer.start(self, random(6)*1000, function() self:open() end)
    self:go(64)
  elseif animation == "opening" then
    self:get_sprite():set_animation("walking")
    sol.timer.start(self, 1000, function() self:check_action() end)
  end
end


Sprite file:
animation{
  name = "walking",
  src_image = "enemies/gohma.png",
  frame_delay = 200,
  frame_to_loop_on = 0,
  directions = {
    { x = 0, y = 128, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
    { x = 0, y = 64, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
    { x = 0, y = 96, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
    { x = 0, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
  },
}

animation{
  name = "shaking",
  src_image = "enemies/gohma.png",
  frame_delay = 100,
  frame_to_loop_on = 0,
  directions = {
    { x = 64, y = 128, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
    { x = 64, y = 64, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
    { x = 64, y = 96, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
    { x = 64, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
  },
}

animation{
  name = "hurt",
  src_image = "enemies/gohma.png",
  frame_delay = 100,
  frame_to_loop_on = 0,
  directions = {
    { x = 256, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
    { x = 256, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
    { x = 256, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
    { x = 256, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
  },
}

animation{
  name = "closed",
  src_image = "enemies/gohma.png",
  frame_delay = 200,
  frame_to_loop_on = 0,
  directions = {
    { x = 256, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
    { x = 256, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
    { x = 256, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
    { x = 256, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
  },
}

animation{
  name = "blinking",
  src_image = "enemies/gohma.png",
  frame_delay = 150,
  directions = {
    { x = 0, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 3 },
    { x = 0, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 3 },
    { x = 0, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 3 },
    { x = 0, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 3 },
  },
}

animation{
  name = "opening",
  src_image = "enemies/gohma.png",
  frame_delay = 150,
  directions = {
    { x = 128, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
    { x = 128, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
    { x = 128, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
    { x = 128, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
  },
}

animation{
  name = "immobilized",
  src_image = "enemies/gohma.png",
  directions = {
    { x = 0, y = 128, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29 },
    { x = 0, y = 64, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29 },
    { x = 0, y = 96, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29 },
    { x = 0, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29 },
  },
}

March 19, 2014, 07:14:31 AM #1 Last Edit: March 19, 2014, 07:27:00 AM by Renkineko
I don't see anything strange in your script... Think to print a lot when you are debugging to know exactly what is wrong. Can you show us the image for the sprite ? It may be a problem with the sprite declaration of the walking animation, but I suppose you double checked it...

Not related, but in you check action, you don't need to repeat the opposite if in you elseif statement... Like "if self:get_life() > 6 then ... elseif self:get_life() > 3 then ... else ...". It's just coding style, and if you think it's easier to read after it's ok but it's not useful in a programming way (in my opinion). In the same way, the creation of the sons in the check_action seems to be always true, so maybe not repeat this code ? I'm not sure to have read it correctly but that's how I understand the check action :)

Nice boss by the way ^^

Try to add self:set_optimization_distance(0) in on_created. The default optimization distance is often the source of problems with bosses and I will try to remove it in 1.3.
See http://www.solarus-games.org/doc/1.2/lua_api_entity.html#lua_api_entity_set_optimization_distance

Christopho- no luck on the optimization distance trick, thanks though.

Renkineko- I did double check the sprite, but I always could have missed something!

https://github.com/wrightmat/zbom/blob/master/data/sprites/enemies/gohma.png

March 20, 2014, 07:46:28 AM #4 Last Edit: March 24, 2014, 07:08:10 AM by Renkineko
Ok so I cloned your repository because I did not understand where the problem was, and I did a lot of printing everywhere. With this, I saw that you never enter in the function enemy:on_animation_finished. So after checking on the documentation, this event does not exist, you have to do the "on_animation_finished" on the sprite and not on the enemy :) so the good method should be something like :



function enemy:blink()
  self:set_attack_consequence("arrow", "protected")
  local sprite = self:get_sprite()
  sprite:set_animation("blinking")
 
  function sprite:on_animation_finished(animation)
    enemy:set_attack_consequence("arrow", "protected")
    sprite:set_animation("closed")
    sol.timer.start(enemy, random(6)*1000, function() enemy:open() end)
    enemy:go(64)
  end
end

function enemy:open()
  self:set_attack_consequence("arrow", 1)
  local sprite = self:get_sprite()
  sprite:set_animation("opening")
  function sprite:on_animation_finished(animation)
    enemy:set_attack_consequence("arrow", "protected")
    sprite:set_animation("walking")
    sol.timer.start(enemy, 1000, function() enemy:check_action() end)
  end
end


With this code, your enemy exists and is hell in a cell :p As I said : doing a lot of print everywhere can help to resolve the problem. For information, here is the file I had before knowing where the problem was :


local enemy = ...

-- Gohma: Boss who has to be shot in the eye with an arrow to be hurt

function enemy:on_created()
  self:set_life(9)
  self:set_damage(2)
  self:create_sprite("enemies/gohma")
  self:set_hurt_style("boss")
  self:set_size(64, 32)
  self:set_origin(32, 29)
  self:set_attack_consequence("sword", "protected")
  self:get_sprite():set_animation("walking")
  self:set_optimization_distance(0)
end

function enemy:check_action()
  local action = math.random(10)
  print('action : ', action)
  if self:get_life() > 6 then
    print('first phase, creating son')
    -- first phase: if less than three hits then mostly just move around (slowly), and create tektites
    local son_name = self:get_name().."_son"
    self:create_enemy{
      name = son_name,
      breed = "tektite_green",
      treasure_name = "heart"
    }
    if action >= 1 and action <= 7 then
      print('go somewhere')
      self:go(96)
    else
      print('will blink')
      self:blink()
    end
  elseif self:get_life() > 3 and self:get_life() <= 6 then
    -- second phase: if more than 3 but less than 6 hits then blink a lot more, and create tektites
    if action >= 1 and action <= 7 then self:blink() else self:go(96) end
    local son_name = self:get_name().."_son"
    self:create_enemy{
      name = son_name,
      breed = "tektite_green"
    }
  elseif self:get_life() < 3 and self:get_life() > 0 then
    -- final phase: if more than 6 hits then move a lot faster, and create tektites!
    if action >= 1 and action <= 6 then self:blink() else self:go(128) end
    local son_name = self:get_name().."_son"
    self:create_enemy{
      name = son_name,
      breed = "tektite_green"
    }
  end
  sol.timer.start(self, 100, function()
    print('open what, i do not know')
    self:open()
  end)
end

function enemy:go(speed)
  print('enemy go to ',speed)
  self:get_sprite():set_animation("walking")
  self:set_attack_consequence("arrow", 1)
  local m = sol.movement.create("random")
  m:set_speed(speed)
  m:set_max_distance(24)
  m:start(self)
end

function enemy:blink()
  print('enemy is blinking')
  self:set_attack_consequence("arrow", "protected")
  self:get_sprite():set_animation("blinking")
end

function enemy:open()
  print ('enemy is opening')
  self:set_attack_consequence("arrow", 1)
  self:get_sprite():set_animation("opening")
end

function enemy:on_restarted()
  print('enemy:restarting')
  self:get_sprite():set_animation("walking")
  self:check_action()
end

function enemy:on_obstacle_reached()
  print('oh, an obstacle...')
  self:check_action()
end

function enemy:on_animation_finished(sprite, animation)
  print('animation finished : ', sprite, animation)
  self:set_attack_consequence("arrow", "protected")
  if animation == "blinking" then
    print('animation was blinking, we will close')
    self:get_sprite():set_animation("closed")
    sol.timer.start(self, random(6)*1000, function() self:open() end)
    self:go(64)
  elseif animation == "opening" then
    print('animation was opening, we will walk')
    self:get_sprite():set_animation("walking")
    sol.timer.start(self, 1000, function() self:check_action() end)
  end
end


And the game was pretty chatty, so it can be useful :] Good luck for the boss settings.

Wow, thanks so much Renkineko!

If you were referring to the difficulty of the boss - now that the script works, I've fine-tuned the boss's difficulty level :-)

You're welcome :) and yep I was referring the difficulty of the boss, but I knew you will update it when the script works properly, you can't modify an enemy if you can't test it first :p good luck o/