I’m thinking this is due to the iteration direction but then again, why would it be if its all done in one frame anyway?
--# Main
function setup()
r = Rope(vec2(50,600),vec2(700,350),40)
touches = {}
end
function touched(t)
if t.state == BEGAN then
table.insert(touches,t)
end
for k,v in pairs(touches) do
if v.id == t.id then
if k == 1 then
r.p1 = vec2(t.x,t.y)
elseif k == 2 then
r.p2 = vec2(t.x,t.y)
end
end
if t.state == ENDED then
table.remove(touches,k)
end
end
end
function draw()
background()
r:draw()
end
--# Rope
Rope = class()
function Rope:init(pos1,pos2,segamnt)
-- you can accept and set parameters here
self.p1 = pos1
self.p2 = pos2
self.m = mesh()
self.r = {}
self.dst = pos1:dist(pos2)
self.segamnt = segamnt
self.seglen = self.dst/segamnt
self.segtbl = {}
for i=1,segamnt do
self.segtbl[i] = {}
self.segtbl[i].pos = pos1+(pos2-pos1):normalize()*self.seglen*i
self.segtbl[i].vel = vec2()
self.segtbl[i].ang = 0
self.r[i] = self.m:addRect(self.segtbl[i].pos.x,self.segtbl[i].pos.y,5,self.seglen)
end
self.i = 0
end
function Rope:draw()
for i=1,self.segamnt do
local maxl = self.seglen
local prevpos = vec2()
local pos = self.segtbl[i].pos
local nextpos = vec2()
if i==1 then
prevpos = self.p1
nextpos = self.segtbl[i+1].pos
elseif i==self.segamnt then
prevpos = self.segtbl[i-1].pos
nextpos = self.p2
else
prevpos = self.segtbl[i-1].pos
nextpos = self.segtbl[i+1].pos
end
pos = self.segtbl[i].pos
local mlen = ((nextpos+prevpos)/2):dist(pos)
if mlen > 0 then
self.segtbl[i].pos = pos + (((nextpos+prevpos)/2)-pos):normalize()*mlen*1.8
end
self.segtbl[i].pos = self.segtbl[i].pos -vec2(0,1)
self.m:setRect(self.r[i],pos.x,pos.y,5,10,angleOfPoint(pos-prevpos)/mp)
end
self.m:draw()
end
function Rope:touched(touch)
-- Codea does not automatically call this method
end
--# SpecFuncs
mp = 180/math.pi
function angleOfPoint( pt )
local ang = math.atan2(pt.y,pt.x)*(180/math.pi)
if ang < 0 then ang = 360+ang elseif ang > 360 then ang = 0+(ang-360) end
return ang
end
Physical rope with 2 attached ends, first finger moves left point, second moves right point. The rope seems very static when moved with the first finger but if you use a second finger to move the other point you get the more desired elastic effect, but this is not correct due to its correcting itself backwards instead of forwards. I tried doing two seperate iterations over the table in both directions which gave a static effect on both sides but the second finger point dragged behind. Has anyone dealt with rope yet with good frame rates? If so please give me some advice as I have never tried simulating rope between two points only one. It’s easy to get the desired effects from one end. Thanks!
Very nice effect! Is the problem that the rope is less wavy when only using one finger?
If you use two touches and move one end, then keeping both touches, keep that end static and move the other, it acts the same as one finger movement. I don’t know why this is, but given that you also said ‘first finger moves left point, second moves right point’, I suspect the issue lay somewhere in that logic. Not sure if this helps!
I know its in the logic of the rope, and I mean the left side touch point, when moved will move every single other point on that rope in the frame because it follows the direction (left to right, i=1,40) so you get the nicer effect when it’s setting the position backwards because its opposite to the iteration direction (just a theory!) but I’d like this effect on both sides. It needs to be controllable from both ends with the same effect.
Edit: This should give you a good idea, if you hold with the left touch then tap somewhere on the screen with right touch away from the second point it will draw segment by segment each frame actually iterating backwards to set the positions, this is why it is frame by frame and not all at once in one frame, which is what the left touch does. So you can tap with the left touch and all segments are automatically reproduced in the one frame in the right position or tap with the right touch whilst holding left touch down to get this backwards frame by frame position setting which appears to give an elastic effect when dragging.
I’m not thinking it is the left or right touch moving that matters, but if it is the first or second. If you swap the rope’s ends over, then the right touch acts as the left does initially. So, it’s always r.p2 moving that gives the right effect?
I don’t understand enough about the code to change it, just observing the behaviour and thinking out loud.
Rope = class()
function Rope:init(pos1,pos2,segamnt)
-- you can accept and set parameters here
self.p1 = pos1
self.p2 = pos2
self.m = mesh()
self.r = {}
self.dst = pos1:dist(pos2)
self.segamnt = segamnt
self.seglen = self.dst/segamnt
self.segtbl = {}
for i=1,segamnt do
self.segtbl[i] = {}
self.segtbl[i].pos = pos1+(pos2-pos1):normalize()*self.seglen*i
self.segtbl[i].vel = vec2()
self.segtbl[i].ang = 0
self.r[i] = self.m:addRect(self.segtbl[i].pos.x,self.segtbl[i].pos.y,5,self.seglen)
end
self.i = 0
end
function Rope:draw()
for i=1,self.segamnt do
local n = self.segamnt+1-i
local maxl = self.seglen
local prevpos = vec2()
local pos = self.segtbl[i].pos
local nextpos = vec2()
local prevpos2 = vec2()
local nextpos2 = vec2()
if i==1 then
prevpos = self.p1
nextpos = self.segtbl[i+1].pos
elseif i==self.segamnt then
prevpos = self.segtbl[i-1].pos
nextpos = self.p2
else
prevpos = self.segtbl[i-1].pos
nextpos = self.segtbl[i+1].pos
end
if n==1 then
prevpos2 = self.segtbl[n+1].pos
nextpos2 = self.p1
elseif n==self.segamnt then
prevpos2 = self.p2
nextpos2 = self.segtbl[n-1].pos
else
prevpos2 = self.segtbl[n+1].pos
nextpos2 = self.segtbl[n-1].pos
end
pos = self.segtbl[i].pos
local mlen = ((nextpos+prevpos)/2):dist(pos)
local mlen2 = ((nextpos2+prevpos2)/2):dist(self.segtbl[n].pos)
if mlen2 > 0 then
self.segtbl[n].pos = self.segtbl[n].pos
+ (((nextpos2+prevpos2)/2)-self.segtbl[n].pos):normalize()*mlen2
end
if mlen > 0 then
self.segtbl[i].pos = pos + (((nextpos+prevpos)/2)-pos):normalize()*mlen
end
self.segtbl[i].pos = self.segtbl[i].pos -vec2(0,1)
self.m:setRect(self.r[i],pos.x,pos.y,5,10,angleOfPoint(pos-prevpos)/mp)
end
self.m:draw()
end
function Rope:touched(touch)
-- Codea does not automatically call this method
end
I would like it to be more efficient though and not as messy, any clues?
@JakAttak believe me even the first one is a lot more efficient than previous tests, I had 4 lines of code controlling the rope but now I only have one. I think I might just have to go with verlet.