Author Topic: Quicksand custom entity  (Read 1587 times)

wrightmat

  • Sr. Member
  • ****
  • Posts: 263
    • View Profile
Quicksand custom entity
« on: January 19, 2015, 04:38:08 pm »
I'm looking to make a custom entity which behaves like quicksand (think Link to the Past's desert temple) - when the hero approaches it, he's slowly dragged into the center, then when he reached the center, he sinks (behavior like a hole, probably). I can't seem to figure it out. Any thoughts?

This is what I have so far, which isn't even close to working:
Code: [Select]
local entity = ...
local map = entity:get_map()
local hero = map:get_entity("hero")

-- Quicksand: entity which slows the hero until
-- he finally falls in

function entity:on_created()
  self:create_sprite("entities/quicksand")
  self:set_size(32, 32)
  self:set_origin(16, 16)
  ex, ey, el = self:get_position()
  self:get_sprite():set_animation("quicksand")
end

function entity:on_update()
  self:add_collision_test("overlapping", function()
    if hero:get_walking_speed() >= 8 then hero:set_walking_speed(hero:get_walking_speed()-1) end
    m = sol.movement.create("target")
    m:set_target(ex, ey)
    m:start(hero)
  end)
end

Christopho

  • Administrator
  • Hero Member
  • *****
  • Posts: 1177
    • View Profile
Re: Quicksand custom entity
« Reply #1 on: January 19, 2015, 05:33:29 pm »
- The variables ex, ey and el should be local to the file, otherwise they are global and all quicksand instances share them.
- The collision test should only react to the hero, not to other entities. Your current code tries to move the hero every time any entity overlaps the quicksand.
- Your code is creating a new collision test at each frame (on_update). You should create the collision test only once. Creating a new movement at each frame is also wrong.
- Starting a movement on the hero is probably a bad idea because an entity cannot have several movements at the same time. If you start a movement, then the player's movement from the keyboard/joypad is lost. And as soon as the player changes the state (like by using the sword), your movement is lost and the keyboard/joypad movement is back. A better approach should be to directly change the hero coordinates towards the quicksand.

Code: [Select]
local entity = ...
local map = entity:get_map()
local hero = map:get_entity("hero")

local ex, ey, el
local timer

-- Quicksand: entity which slows the hero until
-- he finally falls in
function entity:on_created()
  self:create_sprite("entities/quicksand")
  self:set_size(32, 32)
  self:set_origin(16, 16)
  ex, ey, el = self:get_position()
  self:get_sprite():set_animation("quicksand")

  self:add_collision_test("overlapping", function(quicksand, other)

    -- This callback will be repeatedly called while other is overlapping the quicksand

    if other:get_type() ~= "hero"
      return
    end
    local hero = other

    -- Only do this in some specific states (in particular, don't do it while jumping, flying with the hookshot, etc.)
    if hero:get_state() ~= "free" and hero:get_state() ~= "sword loading" ........(and maybe others)......... then
      return
    end

    -- Move the hero towards the quicksand's center every 200 ms while he is overlapping it.
    if timer == nil then
      timer = sol.timer.start(self, 200, function()
        hero:set_xy(........)   -- Some coordinates one pixel towards the center of the quicksand
        timer = nil  -- This variable "timer" ensures that only one timer is running.
      end)
    end

  end)
end

I did not test it, but this is an idea. I hope it can help!
(By the way, I still need to play your game! Sorry for the long time!)
« Last Edit: January 19, 2015, 05:37:35 pm by Christopho »

wrightmat

  • Sr. Member
  • ****
  • Posts: 263
    • View Profile
Re: Quicksand custom entity
« Reply #2 on: January 20, 2015, 12:46:21 am »
Works great, Christopho! Thanks!

One question - if I wanted to slow the hero's walking speed when he overlaps the quicksand (making it harder to get out), how would I go about returning his speed when he's no longer in the quicksand? Also, any advice on how to make the hero sink/fall when he gets to the center?

Updated (working) code:
Code: [Select]
local entity = ...
local map = entity:get_map()
local hero = map:get_entity("hero")

local ex, ey, el
local timer

-- Quicksand: entity which slows the hero until
-- he finally falls in

function entity:on_created()
  self:create_sprite("entities/quicksand")
  self:set_size(32, 32)
  self:set_origin(16, 16)
  ex, ey, el = self:get_center_position()
  self:get_sprite():set_animation("quicksand")

  self:add_collision_test("overlapping", function(quicksand, other)
    -- This callback will be repeatedly called while other is overlapping the quicksand

    if other:get_type() ~= "hero" then
      return
    end
    local hero = other

    -- Only do this in some specific states (in particular, don't do it while jumping, flying with the hookshot, etc.)
    if hero:get_state() ~= "free" and hero:get_state() ~= "sword loading" then
      return
    end

    --hero:set_walking_speed(44)

    -- Move the hero toward the quicksand's center every 20 ms while he is overlapping it.
    if timer == nil then
      timer = sol.timer.start(self, 20, function()
hx, hy, hl = hero:get_position()
if ex > hx then hx = hx + 1 else hx = hx - 1 end
if ey > hy then hy = hy + 1 else hy = hy - 1 end
        hero:set_position(hx, hy)
        timer = nil  -- This variable "timer" ensures that only one timer is running.
      end)
    end

  end)
end


Speaking of my game, I just (quietly) released a new version today! :)

Christopho

  • Administrator
  • Hero Member
  • *****
  • Posts: 1177
    • View Profile
Re: Quicksand custom entity
« Reply #3 on: January 20, 2015, 09:06:22 am »
One question - if I wanted to slow the hero's walking speed when he overlaps the quicksand (making it harder to get out), how would I go about returning his speed when he's no longer in the quicksand?
A way to do this is to create a second timer that checks the collision again (with if quicksand:overlaps(hero)) and if not, restore the speed. Warning: if the quicksand can die, the timer should belong to the hero and not to the quicksand, in order to be sure that it will be called.
Also, any advice on how to make the hero sink/fall when he gets to the center?
Call hero:freeze() to remove control from the player and then do what you want with the sprites of the hero. Like starting the animation "falling" (usually used with holes) or a custom one.