Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Problem with tweening color

edited February 2013 in General Posts: 26

Am I trying to do something incorrect?
Also noticed the color() selector doesn't occur on the "tween(2, tweentest, {fillColor = color(0, 233, 233, 255)})" line.

-- tween test

-- Use this function to perform your initial setup
function setup()

    tweentest = {x = 100,y = 100, fillColor = color(206, 33, 33, 255), red = 206, green =33, blue = 33, alpha = 255}

    -- uncommenting the following line causes an error.
    --tween(2, tweentest, {fillColor = color(0, 233, 233, 255)})

    tween(2, tweentest, {red = 0, green = 233, blue = 255, alpha = 255},{loop = tween.loop.pingpong})
    tween(2,tweentest,{x = 600, y =300},{easing = tween.easing.linear, loop = tween.loop.pingpong})


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


    -- the following fill works
    -- This sets the line thickness

    -- Do your drawing here 


  • SimeonSimeon Admin Mod
    edited February 2013 Posts: 5,387

    The reason this doesn't work is because the color type does not provide arithmetic operators. So for example:

    myColor1 = color(0,0,100)
    myColor2 = color(100,100,100)
    myColor3 = myColor1 + myColor2

    Does not work.

    This is not that obvious and perhaps we should look at adding arithmetic operators to color.

    For the moment, simply change your fillColor to a vec4 type instead, and then set the fill as follows:

    fill( tweentest.fillColor.x, tweentest.fillColor.y, tweentest.fillColor.z )
  • Ok I understand. Color tweening is shown in the box example for tween in the reference. So that's why I was trying it out.

  • SimeonSimeon Admin Mod
    Posts: 5,387

    .@Reyals123 sorry about that, that's a mistake on our part. We'll add arithmetic operators to color to allow tween to work with it.

  • I can work around that easily enough I just thought I was screwing something up and just wasn't seeing the problem.

  • JohnJohn Admin Mod
    Posts: 622

    The Tween library was originally designed to work on table properties (specifically numbers), an alternative is to do the following:

    object = {fillColor = color(255,255,255,255)}
    tween(2, object.fillColor, {r = 255, g = 0, b = 255})
  • Thanks John, the reference under tween needs to have your code snippet as the example for color.

  • Hi! I’m just flagging this up again, as I’ve been trying to tween colours, couldn’t get it to work (getting weird results) and found this post. Wondering if this is till the problem?

  • dave1707dave1707 Mod
    Posts: 8,464

    @pjholden Try this.

    function setup()
    function draw()
        text("Tap screen to start the color change",WIDTH/2,HEIGHT-100)
    function touched(t)
        if t.state==BEGAN then 
  • Cheers dave, i’d Already worked around it (more or less doing what you’ve suggested) just wondering if, as Simeon said upthread (in 2013!) a fix ever came up for it (I’m assuming it never did)

  • Posts: 490

    @pjholden What problems are you seeing? I just tried the following and saw what I expected to see (a rectangle fading in to purple).

    function setup()
        t = { colour = color(40,40,50)}
        tween(5,t, {colour = color(255,0,255)})
    function draw()
  • dave1707dave1707 Mod
    edited October 2017 Posts: 8,464

    @LoopSpace It doesn’t work, it just looked like it did. Red should go from 40 to 255, green from 40 to 0, and blue from 50 to 255. Run the code below and watch the r,g,b values.

    This doesn’t work.

    function setup()"t.colour.r")"t.colour.g")"t.colour.b")
        t = { colour = color(40,40,50)}
        tween(5,t, {colour = color(255,0,255)})
    function draw()

    This does work.

    function setup()"t.r")"t.g")"t.b") t = { r=40,g=40,b=50} tween(5,t, {r=255,g=0,b=255}) end function draw() background(40,40,50) fill(t.r,t.g,t.b) rect(WIDTH/2,HEIGHT/2,100) end
  • I usually notice the alpha values, they go particularly screwy.

    As it is, I ended up seperati g out RGBA values in to their components, so I could tween them and corners of a rectangle as part of a single tween (mostly so I could hold the tween’s ID in a single variable which I then reset to zero after it’s finished tweeting, so I can easily check if the thing is animating or not)

    self.animating = tween( .7, self, 
            { focusX = self.panels[self.currentPanel].x, 
              focusY = self.panels[self.currentPanel].y,
            focusW = self.panels[self.currentPanel].w,
             focusH = self.panels[self.currentPanel].h,
            focusZoom = zoom,
        focusBGR = self.panels[self.currentPanel].bg.r,
        focusBGG = self.panels[self.currentPanel].bg.g,
        focusBGB = self.panels[self.currentPanel].bg.b,
         focusBGA = self.panels[self.currentPanel].bg.a
            self.animating = false
  • Posts: 490

    Interesting. It appears that the arithmetic operators on colours are clipped to the 0-255 range. That shouldn't be a problem as tweening is affine, except that the implementation of tweening converts the natural affine relationship into a linear one and that takes colours out of the 0-255 range temporarily.

    The proper fix would be to change tween.lua in the following ways:

    local function easeWithTween(self, subject, target, initial)
      local t,b,c,d
      for k,v in pairs(target) do
        if type(v)=='table' then
          easeWithTween(self, subject[k], v, initial[k])
          t,b,c,d = self.running, initial[k], v, self.time -- third argument changed from v - initial[k]
          if self.loop then
            t = self.loop(t,d)
          subject[k] = self.easing(t,b,c,d)

    and then the easing functions need to be changed, eg for the linear one:

    local function linear(t, b, c, d) return c * (t / d) + (1 - t / d) * b end

    If the second colour is greater than the first, (ie all components of the target colour are bigger than or equal to the corresponding components of the initial colour) then a simple solution is to pass an easing function with correct bracketting. Using my earlier code:

    tween(5,t, {colour = color(255,0,255)}, function(t,b,c,d) return (t/d)*c + b end)

    Lastly, an option is to modify the arithmetic operators on the color userdata to remove the clipping:

    local mt = getmetatable(color())
    mt.__add = function(c1,c2)
      return color(c1.r+c2.r, c1.g+c2.g, c1.b+c2.b, c1.a+c2.a)
    mt.__sub = function(c1,c2)
      return color(c1.r-c2.r, c1.g-c2.g, c1.b-c2.b, c1.a-c2.a)
    mt.__mul = function(c1,c2)
      if type(c2) == "number" then
        c1,c2 = c2,c1
      return color(c1*c2.r, c1*c2.g, c1*c2.b, c1*c2.a)
    mt.__div = function(c1,c2)
      return color(c1.r/c2, c1.g/c2, c1.b/c2, c1.a/c2)

    This has the advantage that it can be used with Codea as-is.
    Though of course, this might break other things that rely on colours having their values clipped.

Sign In or Register to comment.