Spinning wheel as Loading or Waiting indicator

A spinning wheel for indicating wait or loading. http://youtu.be/WueJTkQNfjI

Edit: Just updated version here, but please always check on Codea Community for the latest version.

Main tab

--Version: Alpha 1.3
--Comments: Fixed line cap mode issue

LineCaps = {ROUND, SQUARE, PROJECT}

function setup()
    stars = {}
    table.insert(stars, Star(WIDTH/4, HEIGHT*3/4, 50, 10, 0.6, 3, 400))
    table.insert(stars, Star(WIDTH*3/4, HEIGHT*3/4, 50, 170, 0.6, 12, 250))
    table.insert(stars, Star(WIDTH/4, HEIGHT/4, 50, 30, 0.5, 4, 150))
    table.insert(stars, Star(WIDTH*3/4, HEIGHT/4, 50, 160, 0, 8, 100))
    
    star = Star(WIDTH/2, HEIGHT/2, 100, 3)
    parameter.integer("Radio", 5, 500, 170)
    parameter.integer("Spikes", 2, 180, 4)
    parameter.integer("LineCapMode", 1, 3)
    parameter.number("LengthFactor", 0, 3, 0.5)
    parameter.number("WidthFactor", 0.1, 20, 2)
    parameter.integer("Speed", 10, 800, 400)
    parameter.integer("Background", 0, 255, 255)
end

function draw()
    background(Background, Background, Background)
    star.r = Radio
    star.spikes = Spikes
    star.lengthFactor = LengthFactor
    star.widthFactor = WidthFactor
    star.speed = Speed
    star.lineCap = LineCaps[LineCapMode]
    star:draw()
    
    for _,st in ipairs(stars) do
        st:draw()
    end
end

Star tab

Star = class()

function Star:init(x, y, r, spikes, lengthFactor, widthFactor, speed, lineCap)
    self.x = x
    self.y = y
    self.r = r
    self.spikes = self:valueOrDefault(spikes, 10)
    self.lengthFactor = self:valueOrDefault(lengthFactor, 0.5)
    self.widthFactor = self:valueOrDefault(widthFactor, 2)
    self.speed = self:valueOrDefault(speed, 400)
    self.lineCap = self:valueOrDefault(lineCap, ROUND)
    self.light = 0
    self.visible = true
end

function Star:valueOrDefault(value, defaultValue)
    if value then return value
    else return defaultValue end
end

function Star:draw()
    if self.visible then
        self.delta = 2 * math.pi / self.spikes
        self.shift = math.ceil(ElapsedTime * self.speed)
        pushMatrix()
            pushStyle()
                local x1, y1, x2, y2
                translate(self.x, self.y)
                for a = -math.pi, math.pi, self.delta do
                    x1 = math.cos(a) * self.r
                    y1 = math.sin(a) * self.r
                    x2 = x1 * self.lengthFactor
                    y2 = y1 * self.lengthFactor
                    
                    self.light = 255 * (a + math.pi) / (2 * math.pi)
                    self.light = math.mod(self.light + self.shift, 256)
                    stroke(self.light, self.light, self.light, 255)
                    lineCapMode(self.lineCap)
                    
                    strokeWidth(self.r * self.widthFactor / self.spikes)
                    line(x1, y1, x2, y2)
                end
            popStyle()
        popMatrix()
    end
end

I was looking for a loading icon. Thanks for sharing…

But we still have to use coroutines to draw the icon on the screen. :frowning:

@Saurabh - Yes, but the intention is to use it with asynchronous calls, e.g. when downloading resources. You just create an instance of the Star class (the spinning wheel) with parameters in the setup() function and invoke its draw() in your main draw(). Before calling any lengthy task set its visible attribute to true and at the end of the callback function that handless the lengthy event, set its visible attribute to false. The “icon” has been done. If this doesn’t make sense, I probably didn’t understand your need or what the problem is with coroutines.

Yeah understood.

What I meant was that I feel a bit lazy using coroutines. What I generally do to showing the loading icon before a big task is just one frame before that task draw the icon and then remove it in the next frame. So now, it is only there for one frame but the DeltaTime is so huge that it looks like its been draw there in all the frames.

The only drawback in this technique is that you can’t show any animation.

@LightDye nicely done!

@LightDye once again, an excellent job well polished! ^:)^ ^:)^ ^:)^

@Briarfox, @Jmv38 - Thank you :slight_smile:

@LightDye it runs only 18 fps on ipad1.
I have tweeked it a little bit to have 60fps:

function setup()
    stars = {}
    table.insert(stars, Star(WIDTH/4, HEIGHT*3/4, 50, 10, 0.6, 3, 150))
    table.insert(stars, Star(WIDTH*3/4, HEIGHT*3/4, 50, 170, 0.6, 12, 150))
    table.insert(stars, Star(WIDTH/4, HEIGHT/4, 50, 30, 0.5, 4, 150))
    table.insert(stars, Star(WIDTH*3/4, HEIGHT/4, 50, 160, 0, 8, 150))
end

function draw()
    background(255, 255, 255, 255)
    for _,st in ipairs(stars) do
        st:draw()
    end
end


Star = class()

function Star:init(x, y, r, spikes, lengthFactor, widthFactor, speed)
    self.x = x
    self.y = y
    self.r = r
    self.spikes = self:valueOrDefault(spikes, 10)
    self.lengthFactor = self:valueOrDefault(lengthFactor, 0.5)
    self.widthFactor = self:valueOrDefault(widthFactor, 2)
    self.speed = self:valueOrDefault(speed, 400)
    self.light = 0
    self.img = image(r*2,r*2)
    self:draw0()
end

function Star:valueOrDefault(value, defaultValue)
    if value then return value
    else return defaultValue end
end
local floor = math.floor
function Star:draw()
    pushMatrix()
    pushStyle()
    translate(self.x, self.y)
    local a = 360 / self.spikes * floor(ElapsedTime * self.speed * self.spikes /300)
    rotate(a)
    sprite(self.img)
    spriteMode(CENTER)
    popStyle()
    popMatrix()
end
function Star:draw0()
    self.delta = 2 * math.pi / self.spikes
    self.shift = math.ceil(ElapsedTime * self.speed)
    local LineCapMode = 1
    setContext(self.img)
    pushMatrix()
        pushStyle()
            local x1, y1, x2, y2
            translate(self.r, self.r)
            for a = -math.pi, math.pi, self.delta do
                x1 = math.cos(a) * self.r
                y1 = math.sin(a) * self.r
                x2 = x1 * self.lengthFactor
                y2 = y1 * self.lengthFactor

                self.light = 255 * (a + math.pi) / (2 * math.pi)
                self.light = math.mod(self.light + self.shift, 256)
                stroke(self.light, self.light, self.light, 255)
                lineCapMode(LineCapMode)

                strokeWidth(self.r * self.widthFactor / self.spikes)
                line(x1, y1, x2, y2)
            end
        popStyle()
    popMatrix()
    setContext()
end

@Jmv38 - Thank you, but I noticed that you based your changes on the code published on this page, rather than the latest version which is available through Codea Community. The version there fixes some issues, although its fps rate is probably the same, so could you please apply your changes again but using the latest version?

Probably 2 versions of the Star class need to exist: One for the demo app, highly configurable so that people can use it to design the icon by tweaking the parameters and another version that do most calculations in the init() function, not configurable at runtime, so that its fps rate is optimized, unless the first one can be optimized to run at 60 fps.

Thank you for indicating cc. Actually i have problems to download with cc, but i did it.
In the previous post i just intented to show you some tricks that maybe you dont know, to accelerate fps. Actually it is possible to do only one version with the fps and the parameters, but it needs a little bit of rewrite so the img is updated when the user change somthing.

Thanks @Jmv38 for showing me those tricks. Interesting techniques, I’m not familiar with them as I have no experience developing games and I never had to worry about optimising fps rates before. I tried your code and certainly improves the fps rate, but I noticed resolution loss. I need to play with this a bit more to tweak it.

@LightDye you are right, some of the images look less nice with my method, some are ok. But working on ipad1 the fps is critical for me!