Need some help with Tween

First, the code:


--# Button
Button = class()

function Button:init(x, y, w, h, font_choice, label)
    -- you can accept and set parameters here
    self.x = x
    self.y = y
    self.w = w
    self.h = h
    self.half_box_width = self.x + (.5 * w)
    self.half_box_height = self.y + (.5 * h)
    self.font_choice = font_choice
    self.label = label
end

function Button:draw()
    fill(29, 28, 138, 255)
    rect(self.x, self.y, self.w, self.h)
    font(self.font_choice)
    fontSize(10)
    fill(255, 255, 255)
    text(self.label, self.half_box_width, self.half_box_height)
end

function Button:touched(touch)
    -- Codea does not automatically call this method
end

function Button:bbox(x, y)
    local left = self.x - self.w
    local right = self.x + self.w
    local bottom = self.y - self.h
    local top = self.y + self.h
    
    if x >= left and x <= right then
        if y >= bottom and y <= top then
            return true
        end
    else
        return false
    end
end

--# Main

-- Use this function to perform your initial setup
function setup()
    mainShip = Ship(WIDTH/2, HEIGHT/2, 100, 54, "Space Art:Green Ship")
    commit_button = Button(0, 0, 100, 100, "ArielMT", "Commit")
    orders = {}
    order_position = 0
    commit_orders = false
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(5)

    -- Do your drawing here
    mainShip:draw()
    commit_button:draw()
    if commit_orders then
        print(commit_orders)
        Movement:draw(orders, mainShip)
        commit_orders = false
        order_position = 0
        orders = {}
    end
    if order_position > 0 then
        line(mainShip.x, mainShip.y, orders[1].x, orders[1].y)
        for line_pos = 2, order_position do
            prev_pos = line_pos - 1
            line(orders[prev_pos].x, orders[prev_pos].y, orders[line_pos].x, orders[line_pos].y)
        end
    end
end

function touched(touch)
    if mainShip:bbox(touch.x, touch.y) then
        print("Ship Touched")
    elseif touch.state == ENDED and commit_button:bbox(touch.x, touch.y) then
        print("COMMITED")
        commit_orders = true
        print("In touch, commit_orders = ")
        print(commit_orders)
    elseif touch.state == ENDED then
        order_position = order_position + 1
        table.insert(orders, touch)
        --for i,v in pairs(orders) do
        --    print(i, v)
        --end
    end
end

--# Movement
Movement = class()

function Movement:init()

end

function Movement:draw(orders, unit)
    self.orders = orders
    self.unit = unit
    local total_orders = table.maxn(self.orders)
    for current_order = 1, total_orders do
        print(current_order, total_orders)
        local move_to = {x = self.orders[current_order].x, y = self.orders[current_order].y}
        tween(0.5, unit, move_to)
        for i,v in pairs(move_to) do
            print(i,v)
        end
    end
    print("Unit is now located at: x = " .. self.unit.x .. "and y = " .. self.unit.y)
end

function Movement:touched(touch)

end

--# Ship
Ship = class()

function Ship:init(x, y, w, h, spriteName)
    -- you can accept and set parameters here
    self.x = x
    self.y = y
    self.w = w
    self.h = h
    self.spriteName = spriteName
end

function Ship:draw()
    -- Codea does not automatically call this method
    sprite(self.spriteName, self.x, self.y)
end

function Ship:bbox(x, y)
    local left = self.x - self.w
    local right = self.x + self.w
    local bottom = self.y - self.h
    local top = self.y + self.h
    
    if x >= left and x <= right then
        if y >= bottom and y <= top then
            return true
        end
    else
        return false
    end
end

function Ship:touched(touch)
    -- Codea does not automatically call this method
end

My goal is, every touch draws a line, starting from a unit (in this case, mainShip). When the Commit button is hit, mainShip should animate to each point in the orders table, sequentially.

Currently, tween is animating to the 2nd entry directly, skipping the first entry (if orders has 2 touches in it) or a random entry if orders has more than 2 entries. I can’t really use tween.sequence or tween.path since I don’t know how many entries are going to be in orders, so I can’t make variables for each of the points (it also doesn’t go into nested tables, as far as I can tell, in tween.path and tween.sequence).

So, is there another way that I’m not seeing?

.@athros The problem you’re having is your trying to do everything in the loop from inside of the draw function. So it goes thru the loop and when the loop is done, it draws the tween for the last entry. I was able to make it work kind of by drawing the first tween, waiting long enough for it to reach the 1st point, then doing the second tween, waiting, etc. Maybe you need to use tween.path instead.

.@athros does this code help? This animates a ship through your touched points using tween(). It relies on the tween callback function to trigger movement to the next point.

Just keep tapping the screen to add points on the path.

--# Main
-- TweenPoints

-- Use this function to perform your initial setup
function setup()
    waypoints = {}
    ship = Ship()
end

-- Draws a waypoint
function drawWaypoint(p)
    pushStyle()
    ellipseMode(CENTER)
    
    fill(255)
    noStroke()
    ellipse(p.x,p.y,30)
    
    noFill()
    stroke(255)
    strokeWidth(6)
    ellipse(p.x,p.y,50)
    
    popStyle()
end

function nextWaypoint()
    -- Clear the first waypoint in the list
    table.remove(waypoints, 1)
    
    if #waypoints >= 1 then
        -- Animate the ship to the next
        tween(1.0, ship, {pos=waypoints[1]}, tween.easing.linear, nextWaypoint)
    end
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(5)

    -- Do your drawing here
    for k,v in pairs(waypoints) do
        drawWaypoint(v)
    end
    
    ship:draw()
end

function touched(touch)
    if touch.state == ENDED and touch.tapCount == 1 then
        -- Add a waypoint
        table.insert( waypoints, vec2(touch.x, touch.y) )
        
        -- If this is the first waypoint
        -- Start animating our ship to it immediately
        if #waypoints == 1 then
            tween(1.0, ship, {pos=waypoints[1]}, tween.easing.linear, nextWaypoint)
        end
    end
end

--# Ship
Ship = class()

function Ship:init(p)
    -- you can accept and set parameters here
    self.pos = p or vec2(0,0)
end

function Ship:draw()
    pushStyle()
    
    sprite("Tyrian Remastered:Plane Boss", self.pos.x, self.pos.y)
    
    popStyle()
end

. @Simeon I was just about to post a solution, but I like yours better. I didn’t think about the callback function, so it good to see an example of it being used.

:open_mouth:

@Simeon - Along with a couple other things! The # syntax (which I don’t quite understand - Lua docs, or Codea docs?), and how you do table inserts with touches.

Thank you for the answer!

@dave1707 - Thank you for responding as well! I appreciate you taking the time to do so.


--# Main

function setup()
    mainShip = Ship(vec2(WIDTH/2, HEIGHT/2), 100, 54, "Space Art:Green Ship")
    commit_button = Button(0, 0, 100, 100, "ArielMT", "Commit")
    orders = {}
    order_position = 0
end

function draw() 
    background(40, 40, 50)
    strokeWidth(5)
    mainShip:draw()
    commit_button:draw()
    if order_position > 0 then
        line(mainShip.pos.x, mainShip.pos.y, orders[1].x, orders[1].y)
        for line_pos = 2, order_position do
            prev_pos = line_pos - 1
            line(orders[prev_pos].x, orders[prev_pos].y, orders[line_pos].x, orders[line_pos].y)
        end
    end
end

function touched(touch)
    if mainShip:bbox(touch.x, touch.y) then
        print("Ship Touched")
    elseif touch.state == ENDED and commit_button:bbox(touch.x, touch.y) then
        print("COMMITED")
        tween(1, mainShip, {pos=orders[1]}, tween.easing.linear, nextWaypoint)
    elseif touch.state == ENDED then
        order_position = order_position + 1
        table.insert(orders, vec2(touch.x, touch.y))
    end
end

function nextWaypoint()
    table.remove(orders, 1)
    order_position = order_position - 1
    if #orders >= 1 then
        tween(1, mainShip, {pos=orders[1]}, tween.easing.linear, nextWaypoint)
    end
end
--# Button
Button = class()

function Button:init(x, y, w, h, font_choice, label)
    -- you can accept and set parameters here
    self.x = x
    self.y = y
    self.w = w
    self.h = h
    self.half_box_width = self.x + (.5 * w)
    self.half_box_height = self.y + (.5 * h)
    self.font_choice = font_choice
    self.label = label
end

function Button:draw()
    fill(29, 28, 138, 255)
    rect(self.x, self.y, self.w, self.h)
    font(self.font_choice)
    fontSize(10)
    fill(255, 255, 255)
    text(self.label, self.half_box_width, self.half_box_height)
end

function Button:touched(touch)
    -- Codea does not automatically call this method
end

function Button:bbox(x, y)
    local left = self.x - self.w
    local right = self.x + self.w
    local bottom = self.y - self.h
    local top = self.y + self.h
    
    if x >= left and x <= right then
        if y >= bottom and y <= top then
            return true
        end
    else
        return false
    end
end

--# Ship
Ship = class()

function Ship:init(pos, w, h, spriteName)
    -- you can accept and set parameters here
    self.pos = pos or vec2(100, 100)
    self.w = w
    self.h = h
    self.spriteName = spriteName
    
end

function Ship:draw()
    -- Codea does not automatically call this method
    sprite(self.spriteName, self.pos.x, self.pos.y)
end

function Ship:bbox(x, y)
    local left = self.pos.x - self.w
    local right = self.pos.x + self.w
    local bottom = self.pos.y - self.h
    local top = self.pos.y + self.h
    
    if x >= left and x <= right then
        if y >= bottom and y <= top then
            return true
        end
    else
        return false
    end
end

function Ship:touched(touch)
    -- Codea does not automatically call this method
end

Adjusted code. Works as expected now. Thanks again for the solution!