[SOLVED] path drawing for 2 different objects

I am trying to make my current draw path method work for 2 objects which have there own goals… So far I was able to draw a red line for a red circle and it goes to the red goal… A white line for the white circle that goes to the white goal…

My issue that I am having is that when I start to draw another path for the other ball while one ball is in motion it cancels the path and motion of the ball that is in motion first…

Does anybody now how I can have both paths move simultaneously?

Here is the code I have so far

[lua]local move
local anim
local moveObject

local maxPoints = 2
local lineThickness = 5
local endPoints = {}
local path
local traced = 1
local animate
local posCount = 1
local messageTween
local goalReached = false
local goalsAchieved = 0
local chosenObject
local canDraw = false
local firstGoal = 0
local secondGoal = 0

local newText
local winTxt = display.newText(“SCORE 5 EACH TO WIN”, 0,0, nil, 50)
winTxt.x = 700; winTxt.y = 200
local function tween2()
local reAppear = function()
stars1Tween = transition.to( winTxt, { time=600, alpha=0.1, onComplete=tween2 })
end

stars1Tween = transition.to( winTxt, { time=600, alpha=1.0, onComplete=reAppear })

end

tween2()

local goalCount = display.newText(string.format(“BALL 1: %05d”, 0), 0, 0, native.systemFontBold, 40)
goalCount:setTextColor(255, 255, 255, 255)
goalCount.x = 150
goalCount.y = 650

local goal2Count = display.newText(string.format(“BALL 2: %05d”, 0), 0, 0, native.systemFontBold, 40)
goal2Count:setTextColor(255, 255, 255, 255)
goal2Count.x = 500
goal2Count.y = 650
–create a circle ball
local ball = display.newCircle( 150, 150, 15 )
ball.oX = 150; ball.oY = 150
ball.goal = “goal”
ball.count = goalCount
ball.nums = 0
ball.text = “BALL 1”
ball.path = {}

local ball2 = display.newCircle(300,150,20)
ball2:setFillColor(255,0,0)
ball2.oX = 300; ball2.oY = 150
ball2.goal = “goal2”
ball2.count = goal2Count
ball2.nums = 0
ball2.text = “BALL 2”
ball2.path = {}

local function onTouch(self,event)

if event.phase == “began” then

chosenObject = self

chosenObject.isFocus = true
canDraw = true

print(chosenObject)

elseif event.phase == “ended” then

chosenObject = nil

chosenObject.isFocus = false
canDraw = false

end

end

ball.touch = onTouch

ball:addEventListener(“touch”, ball)

ball2.touch = onTouch
ball2:addEventListener(“touch”, ball2)

local function drawLine(event)

– When the person starts to draw a line, reset everything.
– path contains x and y coordinates, and the line object that starts there.
– traced increments for each traced point.
– endpoints is a table of 2 items. the last point is in endpoints[2], the current point is in
– endpoint[1] and the code below (in the “moved block” ) pushes the last end point out, moves the
– current endpoint to the last end point, and adds the current touch location into the first/current end point

local path = chosenObject.path
if event.phase == “began” then
local chosenObject = chosenObject
if canDraw == true then
print("#path " … #path)
while #chosenObject.path > 0 do
if chosenObject.path[#chosenObject.path].line ~= nil then
chosenObject.path[#chosenObject.path].line:removeSelf()
chosenObject.path[#chosenObject.path].line = nil
end
table.remove(path)
end
while #endPoints > 1 do
table.remove(endPoints)
end
traced = 1
print("traced: " … traced)
end
elseif event.phase == “moved” then
if chosenObject.isFocus == true and canDraw == true then

– init endPoints[1] with the current x,y and initialize the line;
– the insert will automatically push theh previous endPoint[1] to endPoint[2]
– then below that it purges any points more than 2.

– traced is the current line in the path, initiailze it as a table and store the x,y of the move.
– Then loop through the two end points, getting the two x,y’s and create

print("moved " … traced)
table.insert(endPoints, 1, {x = event.x, y = event.y, line= nil})
path[traced] = {}
path[traced].x = event.x
path[traced].y = event.y

if(#endPoints > maxPoints) then
table.remove(endPoints)
end

– this for loop didn’t make much sense to me. Its looping through 2 items but it makes a line from each of the points to the
– current x, y. So lets say endPoints[1].x = current x (300), and endPoints[1].y (300) = current y, and endPoints[2].x = 100 and
– endPoints[2].y = 100 then you would get a line from 100, 100 to the current x, y (which mathmatically should be the current )
– the table.insert above is setting endPoints[1] to the current x.y.

– So the first time through the loop, it draws a ZERO length line from 300, 300 to 300, 300, stores the resulting object into
– path[traced].line. Then it make’s a second pass, creating a line from 100, 100 to 300, 300 and overwrites the first 0 lenght
– line. This creates a memory leak.
– I’ve rewritten the block to make sure we have two end points (on the first move there is only 1) and it only makes the one
– necessary line.

–[[
for k,v in ipairs(endPoints) do
local line = display.newLine(v.x, v.y, event.x, event.y)
line:setColor( 255, 255, 255, 255 )
line.width = lineThickness
path[traced].line = line
end
]]–
if #endPoints > 1 then
local line = display.newLine(endPoints[1].x, endPoints[1].y, endPoints[2].x, endPoints[2].y)

if chosenObject.goal == “goal” then
line:setColor( 255, 255, 255)
elseif chosenObject.goal == “goal2” then
line:setColor( 255,0,0)
end
line.width = lineThickness
path[traced].line = line
end
traced = traced + 1
end
elseif(event.phase == “ended”) then

– now when we are done, and the player lifts his finger (lets go the mouse button), we want to move the ball
– only if the goal is reached. A separate event handler below will set the flag “goalReached” when it detects a touch
– event over it. We now text against that flag and if its set, then call the move code.
– If we haven’t reached the goal, then clear every thing. Free up all the line segments, remove theh entries from the
– path table, reset “traced” (the index counter of points) to 1.
– regardless, clear the endPoints array since we are done with it regardless.
if canDraw == true then
if tostring(goalReached) == tostring(chosenObject.goal) then

moveObject(chosenObject)
else

chosenObject = nil
canDraw = false
goalReached = false
print("goal not reached " … #path)
while (#path > 0) do
if path[#path].line then
print("removing line: " … #path)
path[#path].line.isVisible = false
path[#path].line:removeSelf()
path[#path].line = nil
end
table.remove(path)
end
traced = 1
end
while(#endPoints > 0) do
print("removing endPOints: " … #endPoints)
table.remove(endPoints)
–path.isVisible = true
end
end
end
end

Runtime:addEventListener(“touch”, drawLine)

–moving the object – this is where animation takes place

– this function gets called “traced” number of times, in other words, once for each line segment below based on a timer below.
– posCount is a separate index through the list of path x,y points so we move the ball to the x, y from theh path, then we remove
– the line that is connected to this point and increment posCount for the next line segment.
– we only get here if we end up at our goal, so once posCount is greater than the number of “traced” items (done looping, no more
– timers will fire), now we can count having achieved the goal, update the display and set the ball back to its original loccation.
– or some other location. If you need to spawn a new ball (in this example you don’t) you would remove the ball and create a new one

function moveObject(chosenObject)
local chosenObject = chosenObject
local function animate()

if posCount < traced then
print (“posCount: " … posCount … " traced: " … traced)
chosenObject.x = chosenObject.path[posCount].x
chosenObject.y = chosenObject.path[posCount].y
if chosenObject.path[posCount].line then
chosenObject.path[posCount].line.isVisible = false
chosenObject.path[posCount].line:removeSelf()
chosenObject.path[posCount].line = nil
end
posCount = posCount + 1
else
chosenObject.nums = chosenObject.nums + 1
if chosenObject.goal == “goal” then
firstGoal = firstGoal + 1
elseif chosenObject.goal == “goal2” then
secondGoal = secondGoal + 1
end
goalReached = false
canDraw = false
if chosenObject then
chosenObject.count.text = string.format(chosenObject.text…”: %05d", chosenObject.nums)
chosenObject.x = chosenObject.oX
chosenObject.y = chosenObject.oY
chosenObject = false
if animater then
timer.cancel(animater)
end
end
end

end

posCount = 1

transition.to(chosenObject, { time=500, x=chosenObject.path[1].x, y=chosenObject.path[1].y, onComplete=animate })

animater = timer.performWithDelay( 10, animate, traced )
end


– Called by the move function to call moveObject “traced” number of times in 10 millisecond steps.

–[[function anim(chosenObject)
animate = timer.performWithDelay( 10, moveObject, traced )
end–]]


– to move ball when we click the animate text
– This is forward declared since we actually call it above now.
– it uses a transition over half a second to move the ball to the first x, y in the path array. The net effect of this
– is to move the ball to where the user starts touching. I’m not sure you want this behavior. I would more likely put the event
– listener that draws the line as an event listener of the ball instead of a runTime listener. That way, it would only start the line
– from where the ball is.

–[[move = function()
posCount = 1
transition.to(chosenObject, { time=500, x=path[1].x, y=path[1].y, onComplete=anim(chosenObject) })
print(“goal reached”)

return true
end
–]]

– event listener for touch events over the goal. Simply sets a flag when the movement ends. Might want to consider
– also seeing of event.phase is “moving” too. Though I think that was creating problems earlier when I was messing with that.
– Seems to be working correctly as is though.

local function isGoalReached(self, event)
print("goal reached by goal event listener " … event.phase)
if event.phase == “ended” then
goalReached = self.name;
else goalReached = false
end
end

–create a text which when clicked will animate the object
– draw the target and setup an event listener for touch events, calling isGoalReached

local goal = display.newText( “Goal!”, 100, 50, nil, 40 )
goal.x = 100; goal.y = 425
goal.name = “goal”

local goal2 = display.newText(" GOAL 2", 0,0, nil, 50)
goal2.x = 500; goal2.y = 500
goal2:setTextColor(255,0,0)
goal2.name = “goal2”

goal.touch = isGoalReached
goal:addEventListener(“touch”, goal)

goal2.touch = isGoalReached
goal2:addEventListener(“touch”, goal2)

local function check()
if chosenObject then
if chosenObject.nums >= 5 then
chosenObject.count.text = “WIN”
end
end

if firstGoal >= 5 and secondGoal >= 5 then
winTxt.text = “YOU ARE A WINNER :)”
if chosenObject then
goalReached = false
end
end
end
Runtime:addEventListener(“enterFrame”, check)[/lua]

THANKS FOR ANY HELP ON THIS!! [import]uid: 51459 topic_id: 17735 reply_id: 317735[/import]

I haven’t had a chance to dig in-depth with your code, but it sounds like you’re having both objects use the same path table, and perhaps the same function to cancel the paths.

What you could do is ensure each object uses their own table for paths, that way the other doesn’t get reset you you begin a new one.

Also, I released the ‘Martian Control’ sample quite a while back that might help you, if you have the time to dissect a pretty large chunk of code:

http://developer.anscamobile.com/code/martian-control [import]uid: 52430 topic_id: 17735 reply_id: 67620[/import]

Hey jonathanbeebe Can you give me a little sample on how to ensure that each object uses its own table for paths… I actually have been studying your martian controls since april and managed to make my own smoothPath that works wonders with this rocket I designed!.. This is the only thing now holding me back and I feel like I have tried everything… Any help with this would go a looooong way THANKS:) [import]uid: 51459 topic_id: 17735 reply_id: 67625[/import]

Seems like all objects are using the same endPoints table? Why not give each object their own endPoints table in a similar way that you gave each one their own path table… [import]uid: 52430 topic_id: 17735 reply_id: 67628[/import]

Thanks Beebe!! for making it so much clearer!! I am going to run some tests and post if all go’s well:) [import]uid: 51459 topic_id: 17735 reply_id: 67635[/import]

READ NEXT POST MORE UP TO DATE [import]uid: 51459 topic_id: 17735 reply_id: 67719[/import]

I found out the problem… chosenObject.path table is not being cleared when its suppose too be!!

Any help around this would be great Jonathan!!

[lua]local chosenObject
local move
local anim
local moveObject
local lineThickness = 5
local messageTween
local goalReached = false
local goalsAchieved = 0
local firstGoal = 0
local secondGoal = 0

local newText
local winTxt = display.newText(“SCORE 5 EACH TO WIN”, 0,0, nil, 50)
winTxt.x = 700; winTxt.y = 200

local function tween2()
local reAppear = function()
stars1Tween = transition.to( winTxt, { time=600, alpha=0.1, onComplete=tween2 })
end

stars1Tween = transition.to( winTxt, { time=600, alpha=1.0, onComplete=reAppear })

end

tween2()

local goalCount = display.newText(string.format(“BALL 1: %05d”, 0), 0, 0, native.systemFontBold, 40)
goalCount:setTextColor(255, 255, 255, 255)
goalCount.x = 150
goalCount.y = 650

local goal2Count = display.newText(string.format(“BALL 2: %05d”, 0), 0, 0, native.systemFontBold, 40)
goal2Count:setTextColor(255, 255, 255, 255)
goal2Count.x = 500
goal2Count.y = 650

–create a circle ball
local ball = display.newCircle( 150, 150, 15 )
ball.oX = 150; ball.oY = 150
ball.goal = “goal”
ball.count = goalCount
ball.nums = 0
ball.text = “BALL 1”
ball.path = {}
ball.endPoints = {}
ball.traced = 1
ball.posCount = 1
ball.maxPoints = 2

local ball2 = display.newCircle(300,150,20)
ball2:setFillColor(255,0,0)
ball2.oX = 300; ball2.oY = 150
ball2.goal = “goal2”
ball2.count = goal2Count
ball2.nums = 0
ball2.text = “BALL 2”
ball2.path = {}
ball2.endPoints = {}
ball2.traced = 1
ball2.posCount = 1
ball2.maxPoints = 2

local function onTouch(self,event)
if event.phase == “began” then
chosenObject = self
chosenObject.isFocus = true
canDraw = true
print(chosenObject)
elseif event.phase == “ended” then
chosenObject = nil
chosenObject.isFocus = false

end
end

ball.touch = onTouch
ball:addEventListener(“touch”, ball)

ball2.touch = onTouch
ball2:addEventListener(“touch”, ball2)

local function drawLine(event)

– When the person starts to draw a line, reset everything.
– path contains x and y coordinates, and the line object that starts there.
– chosenObject.traced increments for each chosenObject.traced point.
– endpoints is a table of 2 items. the last point is in endpoints[2], the current point is in
– endpoint[1] and the code below (in the “moved block” ) pushes the last end point out, moves the
– current endpoint to the last end point, and adds the current touch location into the first/current end point

if event.phase == “began” then
print("#path " … #chosenObject.path)
while #chosenObject.path > 0 do
if chosenObject.path[#chosenObject.path].line ~= nil then
chosenObject.path[#chosenObject.path].line:removeSelf()
chosenObject.path[#chosenObject.path].line = nil
end
table.remove(chosenObject.path)
end
while #chosenObject.endPoints > 1 do
table.remove(chosenObject.endPoints)
end
chosenObject.traced = 1
print("chosenObject.traced: " … chosenObject.traced)

elseif event.phase == “moved” then
if chosenObject.isFocus == true then
– init endPoints[1] with the current x,y and initialize the line;
– the insert will automatically push theh previous endPoint[1] to endPoint[2]
– then below that it purges any points more than 2.

– chosenObject.traced is the current line in the path, initiailze it as a table and store the x,y of the move.
– Then loop through the two end points, getting the two x,y’s and create

–print("moved " … chosenObject.traced)

table.insert(chosenObject.endPoints, 1, {x = event.x, y = event.y, line= nil})
chosenObject.path[chosenObject.traced] = {}
chosenObject.path[chosenObject.traced].x = event.x
chosenObject.path[chosenObject.traced].y = event.y

if(#chosenObject.endPoints~= 0 and #chosenObject.endPoints > chosenObject.maxPoints) then
table.remove(chosenObject.endPoints)
end

– this for loop didn’t make much sense to me. Its looping through 2 items but it makes a line from each of the points to the
– current x, y. So lets say chosenObject.endPoints[1].x = current x (300), and chosenObject.endPoints[1].y (300) = current y, and chosenObject.endPoints[2].x = 100 and
– chosenObject.endPoints[2].y = 100 then you would get a line from 100, 100 to the current x, y (which mathmatically should be the current )
– the table.insert above is setting chosenObject.endPoints[1] to the current x.y.

– So the first time through the loop, it draws a ZERO length line from 300, 300 to 300, 300, stores the resulting object into
– path[chosenObject.traced].line. Then it make’s a second pass, creating a line from 100, 100 to 300, 300 and overwrites the first 0 lenght
– line. This creates a memory leak.
– I’ve rewritten the block to make sure we have two end points (on the first move there is only 1) and it only makes the one
– necessary line.

–[[
for k,v in ipairs(chosenObject.endPoints) do
local line = display.newLine(v.x, v.y, event.x, event.y)
line:setColor( 255, 255, 255, 255 )
line.width = lineThickness
path[chosenObject.traced].line = line
end
]]–
if chosenObject ~= nil then
if #chosenObject.endPoints > 1 then
line = display.newLine(chosenObject.endPoints[1].x, chosenObject.endPoints[1].y, chosenObject.endPoints[2].x, chosenObject.endPoints[2].y)

if chosenObject.goal == “goal” then
line:setColor( 255, 255, 255)
elseif chosenObject.goal == “goal2” then
line:setColor( 255,0,0)
end
line.width = lineThickness
chosenObject.path[chosenObject.traced].line = line
end
chosenObject.traced = chosenObject.traced + 1
end
end
elseif(event.phase == “ended”) then

– now when we are done, and the player lifts his finger (lets go the mouse button), we want to move the ball
– only if the goal is reached. A separate event handler below will set the flag “goalReached” when it detects a touch
– event over it. We now text against that flag and if its set, then call the move code.
– If we haven’t reached the goal, then clear every thing. Free up all the line segments, remove theh entries from the
– chosenObject.path table, reset “chosenObject.traced” (the index counter of points) to 1.
– regardless, clear the chosenObject.endPoints array since we are done with it regardless.
if tostring(goalReached) == tostring(chosenObject.goal) then

moveObject(chosenObject)
else
chosenObject.isFocus = false
if chosenObject ~= nil then
print("goal not reached " … #chosenObject.path)
if chosenObject then
while (#chosenObject.path > 0) do
–if chosenObject.path[#chosenObject.path].line then
print("removing line: " … #chosenObject.path)
chosenObject.path[#chosenObject.path].line.isVisible = false
chosenObject.path[#chosenObject.path].line:removeSelf()
chosenObject.path[#chosenObject.path].line = nil
–end
table.remove(chosenObject.path)
end
chosenObject.traced = 1
end
end
while(#chosenObject.endPoints > 0) do
print("removing endPOints: " … #chosenObject.endPoints)
table.remove(chosenObject.endPoints)
end
chosenObject = nil
end
end
end
Runtime:addEventListener(“touch”, drawLine)

–moving the object – this is where animation takes place

– this function gets called “chosenObject.traced” number of times, in other words, once for each line segment below based on a timer below.
– chosenObject.posCount is a separate index through the list of chosenObject.path x,y points so we move the ball to the x, y from theh chosenObject.path, then we remove
– the line that is connected to this point and increment chosenObject.posCount for the next line segment.
– we only get here if we end up at our goal, so once chosenObject.posCount is greater than the number of “chosenObject.traced” items (done looping, no more
– timers will fire), now we can count having achieved the goal, update the display and set the ball back to its original loccation.
– or some other location. If you need to spawn a new ball (in this example you don’t) you would remove the ball and create a new one

function moveObject(chosenObject)
local function animate()
if chosenObject then
local chosenObject = chosenObject
if chosenObject.posCount < chosenObject.traced then
print ("chosenObject.posCount: " … chosenObject.posCount … " chosenObject.traced: " … chosenObject.traced)
chosenObject.x = chosenObject.path[chosenObject.posCount].x
chosenObject.y = chosenObject.path[chosenObject.posCount].y
if chosenObject.path[chosenObject.posCount].line then
chosenObject.path[chosenObject.posCount].line.isVisible = false
chosenObject.path[chosenObject.posCount].line:removeSelf()
chosenObject.path[chosenObject.posCount].line = nil
end
chosenObject.posCount = chosenObject.posCount + 1
else
chosenObject.nums = chosenObject.nums + 1
if chosenObject.goal == “goal” then
firstGoal = firstGoal + 1
elseif chosenObject.goal == “goal2” then
secondGoal = secondGoal + 1
end
goalReached = false

if chosenObject then
chosenObject.count.text = string.format(chosenObject.text…": %05d", chosenObject.nums)
chosenObject.x = chosenObject.oX
chosenObject.y = chosenObject.oY
chosenObject = false
if animater then
timer.cancel(animater)
end
end
end
end
end
chosenObject.posCount = 1
transition.to(chosenObject, { time=500, x=chosenObject.path[1].x, y=chosenObject.path[1].y, onComplete=animate })

animater = timer.performWithDelay( 10, animate, chosenObject.traced )

end


– Called by the move function to call moveObject “chosenObject.traced” number of times in 10 millisecond steps.

–[[function anim(chosenObject)
animate = timer.performWithDelay( 10, moveObject, chosenObject.traced )
end–]]


– to move ball when we click the animate text
– This is forward declared since we actually call it above now.
– it uses a transition over half a second to move the ball to the first x, y in the chosenObject.path array. The net effect of this
– is to move the ball to where the user starts touching. I’m not sure you want this behavior. I would more likely put the event
– listener that draws the line as an event listener of the ball instead of a runTime listener. That way, it would only start the line
– from where the ball is.

–[[move = function()
chosenObject.posCount = 1
transition.to(chosenObject, { time=500, x=chosenObject.path[1].x, y=chosenObject.path[1].y, onComplete=anim(chosenObject) })
print(“goal reached”)

return true
end
–]]

– event listener for touch events over the goal. Simply sets a flag when the movement ends. Might want to consider
– also seeing of event.phase is “moving” too. Though I think that was creating problems earlier when I was messing with that.
– Seems to be working correctly as is though.

local function isGoalReached(self, event)
print("goal reached by goal event listener " … event.phase)
if event.phase == “ended” then
goalReached = self.name;
else goalReached = false
end
end

–create a text which when clicked will animate the object
– draw the target and setup an event listener for touch events, calling isGoalReached

local goal = display.newText( “Goal!”, 100, 50, nil, 40 )
goal.x = 100; goal.y = 425
goal.name = “goal”

local goal2 = display.newText(" GOAL 2", 0,0, nil, 50)
goal2.x = 500; goal2.y = 500
goal2:setTextColor(255,0,0)
goal2.name = “goal2”

goal.touch = isGoalReached
goal:addEventListener(“touch”, goal)

goal2.touch = isGoalReached
goal2:addEventListener(“touch”, goal2)

local function check()
if chosenObject then
if chosenObject.nums >= 5 then
chosenObject.count.text = “WIN”
end
end

if firstGoal >= 5 and secondGoal >= 5 then
winTxt.text = “YOU ARE A WINNER :)”
if chosenObject then
goalReached = false
end
end
end
Runtime:addEventListener(“enterFrame”, check)[/lua] [import]uid: 51459 topic_id: 17735 reply_id: 67764[/import]

Before you do anything (as far as creating a new line), try clearing out the existing chosenObject’s path. [import]uid: 52430 topic_id: 17735 reply_id: 67791[/import]

THANKS For all the HELP BEEBE!!

I am going to try and nail this issue tonight!! I’ll keep you posted!! :slight_smile: [import]uid: 51459 topic_id: 17735 reply_id: 67793[/import]

EVERYTHING is fixed!!! [import]uid: 51459 topic_id: 17735 reply_id: 67950[/import]

@jakescarano where/how did you clear the path at? [import]uid: 108842 topic_id: 17735 reply_id: 71878[/import]

look at line 175
[lua] if tostring(goalReached) == tostring(chosenObject.goal) then

moveObject(chosenObject)
else
chosenObject.isFocus = false
if chosenObject ~= nil then
print("goal not reached " … #chosenObject.path)
if chosenObject then
while (#chosenObject.path > 0) do
–if chosenObject.path[#chosenObject.path].line then
print("removing line: " … #chosenObject.path)
chosenObject.path[#chosenObject.path].line.isVisible = false
chosenObject.path[#chosenObject.path].line:removeSelf()
chosenObject.path[#chosenObject.path].line = nil
–end
table.remove(chosenObject.path)
end
chosenObject.traced = 1
end
end
while(#chosenObject.endPoints > 0) do
print("removing endPOints: " … #chosenObject.endPoints)
table.remove(chosenObject.endPoints)
end
chosenObject = nil
end
end
end
Runtime:addEventListener(“touch”, drawLine)[/lua] [import]uid: 51459 topic_id: 17735 reply_id: 71880[/import]

Its in the drawLine function… Good luck… ) [import]uid: 51459 topic_id: 17735 reply_id: 71881[/import]