Splinerider

My take on the flash game line rider using a ball and splines, check it out!
http://youtu.be/14uCT3_zQAc
Tell me what you think

Really great work :wink:

I think the video is being processed atm :wink: it’ll be up in a few minutes

Pretty cool, nice work!

Thanks I’ve added setting a marker and swipe off screen to delete and a few other things a bit smaller than that but seem to boost the overall performance by about 100 times by using meshes instead, gives quite a nice look but I prefered the lines with a cap on them, anyway heres the newer one: http://youtu.be/14uCT3_zQAc

very cool!

Very nice. Clean interface and nifty functionality.

That is awesome. I love the way you made those curvy shapes always been thinking how to make them. Now that you’ve made them I atleast know that there’s a way to do it!!

For your convenience heres how I do it:


-- spline

-- Use this function to perform your initial setup
function setup()
    Splines = {}
    table.insert(Splines,Spline({vec2(200,500),vec2(300,400),vec2(400,400),vec2(500,500)}))
    scr = vec2()
    touches = {}
end

function angleOfPoint( pt )
   local x, y = pt.x, pt.y
   local radian = math.atan2(y,x)
   local angle = radian*180/math.pi
   if angle < 0 then angle = 360 + angle elseif angle > 360 then angle = 0 + (angle-360) end
   return angle
end

function touched(t)
    for k,v in pairs(Splines) do
        v:touched(t)
    end
end

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

    -- This sets the line thickness
    strokeWidth(5)

    -- Do your drawing here
    for k,v in pairs(Splines) do
        v:drawPoints()
        v:draw()
    end
end

------------------

Points = class()

function Points:init(v)
    self.m = mesh()
    self.r = {}
    for i=1,#v*2 do
        if i <= 4 then
            self.p = v[i]
            self.r[i] = self.m:addRect(self.p.x,self.p.y,10,10,0)
            --self.texture = readImage("Documents:whitecircle")
            self.m:setColors(50,50,50,255)
        elseif i > 4 then
            self.p = v[i-4]
            self.r[i] = self.m:addRect(self.p.x,self.p.y,10,10,45/57.3)
            self.m:setColors(50,50,50,255)
        end
    end 
end


function Points:draw()
    self.m:draw()
end

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

--------------

Spline = class()

function Spline:init(v)
    -- you can accept and set parameters here
    self.v = v
    self.holding = {}
    self.moving = nil
    self.verts = {}
    self.newv = {}
    local n = 31
    local t = 0
    for i = 1,n do
        self.verts[i] = (1-t)^3 * v[1] + 3*(1-t)^2 *t * v[2] + 3*(1-t)* t^2 *v[3] + t^3*v[4]
        t=t+1/(n-1)
    end
    self.lines = Lines(self.verts,50)
    self.vlines = Lines(self.v,200)
    self.points = Points(self.v)
    self.spline = physics.body(CHAIN,false,unpack(self.verts))
end

function Spline:draw()
    self.lines:draw()
end

function Spline:drawPoints()
    self.vlines:draw()
    self.points:draw()
    self.p = vec2()
    for i = 1,#self.v do
        local pos = self.v[i]
        self.p = self.p + pos
    end
    strokeWidth(2)
    stroke(255,200)
    self.p = self.p/4
    fill(179, 21, 21, 150)
    ellipse(self.p.x,self.p.y,30)
end

function Spline:pos()
    return self.p
end

function Spline:touched(t)
    if t.state == BEGAN then
        for i=1,#self.v do
            local pos = self.v[i]+scr
            if vec2(t.x,t.y):dist(pos) < 25 then
                self.holding[i] = true
            end
        end
        if vec2(t.x,t.y):dist(self.p+scr) < 25 then
            self.moving = 1
            for i=1,#self.v do
                self.newv[i] = (self.v[i]-self.p)
            end
        end
        for i=1,#self.v do
            if self.v[i]:dist(self.p) < 20 then
                self.v[i] = self.v[i] + (self.v[i]-self.p):normalize()*20
            end
        end
    elseif t.state == MOVING and self.moving == 1 then
        tp = vec2(t.x,t.y)
                for i=1,#self.v do
                    self.v[i] = tp + self.newv[i]-scr
                end
                    local t = 0
                    local n = 31
                    local v = self.v
                    for i = 1,n do
                        self.verts[i] = (1-t)^3 * v[1] + 3*(1-t)^2 *t * v[2] + 3*(1-t)* t^2 *v[3] + t^3*v[4]
                        t=t+1/(n-1)
                    end
                    self.lines = Lines(self.verts,50)
                    self.vlines = Lines(self.v,200)
                    self.points = Points(self.v)
    elseif t.state == ENDED and self.moving == 1 then
        self.moving = nil
    end
    for i=1,#self.v do
        local pos = self.v[i]
        if t.state == MOVING and self.holding[i] then
            touches[2] = t
            tp = vec2(t.x,t.y)
            self.v[i] = tp-scr
            local t = 0
            local n = 31
            local v = self.v
            for i = 1,n do
                self.verts[i] = (1-t)^3 * (v[1]) + 3*(1-t)^2 *t * (v[2]) + 3*(1-t)* t^2 *(v[3])+ t^3*(v[4])
                t=t+1/(n-1)
            end
            self.lines = Lines(self.verts,50)
            self.vlines = Lines(self.v,200)
            self.points = Points(self.v)
        elseif t.state == ENDED and self.holding[i] then
            self.holding[i] = nil
        end
    end
end

------------------

Lines = class()

function Lines:init(v,col)
    self.m = mesh()
    self.r = {}
    for i=1,#v do
        if i > 1 then
            self.p = (v[i*1-1]+v[i*1])/2
            self.dir = (v[i*1]-v[i*1-1]):normalize()
            self.len = (v[i*1]-v[i*1-1]):len()
            self.r[i] = self.m:addRect(self.p.x,self.p.y,self.len+2,5,angleOfPoint(self.dir)/57.3)
            self.m:setColors(col,col,col,255)
        end 
    end
end

function Lines:draw()
    self.m:draw()
end

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

I plan to make a game out of it but its not that hard to make a game when you’ve got that!
Also note you can only use a table of four vertices in the Spline(v) function.

I hope you enjoy it and to make more curves just add them to the table of Splines.

Btw it runs about 60fps even with about 20 on the screen, if I bothered to use meshes with the ellipse in the middle I doubt it would go down at all until about 40

Thanks @Luatee. I’ll look into it.

Thanks @Luatee for the code. I hope you don’t mind if I borrow your curves equation. Making an equation that too cubic will be difficult for me. Here’s the code I wrote though its not exactly the same but its similar. (Long hold on new project and paste into project)



--# Main
function setup()
    p = Points(WIDTH/2-100,HEIGHT/2)
    BallSetup()
    parameter.boolean("start",false)
end

function draw()
    background(255)
    p:draw()
    BallDraw()
    if start then
        physics.resume()
    elseif not start then
        physics.pause()
    end
end

function touched(touch)
    tx = touch.x
    ty = touch.y
    touchPoint = false
    p:touched(touch)
    BallTouch(touch)
end

--# Points
Points = class()

function Points:init(x1,y1)
    self.px = {}
    self.py = {}
    self.x1 = x1
    self.y1 = y1
    self.x2 = self.x1+100
    self.y2 = self.y1-100
    self.x3 = self.x2+100
    self.y3 = self.y2
    self.x4 = self.x3+100
    self.y4 = self.y3+100
    n = 30
end

function Points:draw()
    pushStyle()
    fill(127, 127, 127, 255)
    ellipse(self.x1,self.y1,15)
    ellipse(self.x2,self.y2,15)
    ellipse(self.x3,self.y3,15)
    ellipse(self.x4,self.y4,15)
    popStyle()
    local t = 0
    for i=1,n do
        self.px[i] = (1-t)^3 * (self.x1) + 3*(1-t)^2 *t * (self.x2) + 3*(1-t)* t^2 *(self.x3)+ t^3*(self.x4)
        self.py[i] = (1-t)^3 * (self.y1) + 3*(1-t)^2 *t * (self.y2) + 3*(1-t)* t^2 *(self.y3)+ t^3*(self.y4)
        t=t+1/(n-1)
    end
    for i=1,n-1 do
        pushMatrix()
        pushStyle()
        stroke(0, 0, 0, 255)
        strokeWidth(5)
        line(self.px[i],self.py[i],self.px[i+1],self.py[i+1])
        self.body = physics.body(EDGE,vec2(self.px[i],self.py[i]), vec2(self.px[i-1],self.py[i-1]))
        popStyle()
        popMatrix()
    end
    pushStyle()
    stroke(73, 73, 73, 80)
    strokeWidth(7)
    line(self.x1,self.y1,self.x2,self.y2)
    line(self.x2,self.y2,self.x3,self.y3)
    line(self.x3,self.y3,self.x4,self.y4)
    popStyle()
end

function Points:touched(touch)
    if tx>self.x1-30 and tx<self.x1+30 and ty>self.y1-30 and ty<self.y1+30 then
        touchPoint = true
        self.x1 = tx
        self.y1 = ty
    end
    if tx>self.x2-30 and tx<self.x2+30 and ty>self.y2-30 and ty<self.y2+30 then
        touchPoint = true
        self.x2 = tx
        self.y2 = ty
    end
    if tx>self.x3-30 and tx<self.x3+30 and ty>self.y3-30 and ty<self.y3+30 then
        touchPoint = true
        self.x3 = tx
        self.y3 = ty
    end
    if tx>self.x4-30 and tx<self.x4+30 and ty>self.y4-30 and ty<self.y4+30 then
        touchPoint = true
        self.x4 = tx
        self.y4 = ty
    end
end

--# Ball
function BallSetup()
    ball = physics.body(CIRCLE,20)
    ball.x = WIDTH/2
    ball.y = HEIGHT/2
    ball.restitution = 0
    ball.friction = 0
    ball.gravityScale = 2
end

function BallDraw()
    pushStyle()
    fill(255, 0, 0, 255)
    stroke(0, 0, 0, 255)
    strokeWidth(3)
    ellipse(ball.x,ball.y,40)
    popStyle()
end

function BallTouch(touch)
    if not touchPoint then
        ball.x = tx
        ball.y = ty
    end
end

Just checked that out thats a good way of doing it but make sure when you’re holding the ball to set its velocity to vec2(0,0) the BallTouch function but other than that its a good way of doing it, I prefer to keep it in the class though as its easy to create many of these curves.

Also the equation itself is standard so feel free to use it, but if you create a game using the classes then all I ask is credit, thanks!

Yeah I made the game using classes I just posted this to show it to you. Thanks for the idea and main part of the games code @Luatee. But now I am into a problem how should I move the screen along with the ball. I am trying to use translate but it’s not working. I tried using FPS but then the movement was becoming jerky. I’ll be grateful if you could help.

@Luatee how did you move the splines along with the cycle without using FPS I did as in the code below. But the movement becomes jerky and inaccurate as I am using DeltaTime. Could you help me out??https://gist.github.com/Saurabh96jun/5655889

Well the red circle in the middle (The one I assume you’re talking about), I just found the midpoint of all the vectors (the average) so you divide all the points by 4 assuming you have 4 points in total. Then create variable in the class called self.moving and then set it to true in the touched function using a statement such as if touchpos:dist(self.p) < 25 then blah blah end, then create a set of new vectors (we’ll call them newvecs, which is a table of four vectors) which consist of each vertex/point minus the midpoint (I call the midpoint self.p) and then move self.p to your touchpos and then add the contents of newvecs to self.p and set each vertex to this new value and it should work. If you dont understand the above then feel free to send me a message me on here.

Thanks @Luatee

Here’s a newer version what do you guys think? http://youtu.be/dg_t9V5S-y8
I’ve added a few things and I think its overall better than before…

That looks fantastic @Luatee. I love the little pedalling animation you have going on the bike rider. It seems to correlate to the speed of the bike, nice touch.

Thanks Simeon, I’ve mainly been experimenting with adding realistic motion to the body and such but also get the legs in sync, I have made it to go to how much he would realistically need to pedal using the spacing of splines Bézier curve points. But yeah Im going to try and get most of it sorted and maybe make it a bit less grey haha looks quite depressing atm