Let’s see if we can get this thing to cycle around on the screen. I think it’s in hand now. (Didn’t work, stopped in middle.)

Nota Bene:
As of Monday AM, I’m publishing this for the record. What follows, and in fact what went before, isn’t working out. This morning’s article works out.

(Sunday Afternoon): We’ve got most of the pieces in place, albeit often probably in not quite the right place. We have a function moveMe that (according to one test) will compute where to move the center of a circle to another position, given the distance that the circle rolls. (The function is probably more capable than that, but it does t least do the job for the center.)

And we can draw circles. At present, for setting them up, I have this rather ad-hoc code:

function setup()
    --CodeaUnit_Detailed = false
    --CodeaUnit_Lock = false
    if CodeaUnit then 
        _.execute()
    end
    center = Point(WIDTH/2, HEIGHT/2)
    local outer = Circle(250, center)
    center:add(outer)
    local inner = Circle(100, outer)
    inner.x = WIDTH/2
    inner.y = HEIGHT/2 - 250 + 100
    outer:add(inner)
end

And we draw them where we find them:

function Circle:draw( ownerX, ownerY)
    --pushMatrix()
    --pushStyle()
    stroke(255)
    ellipse(self.x, self.y, self.radius)
    for i,c in ipairs(self.children) do
        c:draw()
    end
    --popStyle()
    --popMatrix()
end

I believe that if we were to give the circle another value,, the angle it should rotate through in one second, we could make it roll. I was going to just make it roll once, using “touch”, but let’s “roll” the dice and just set it loose. We can always undo.

Let’s call it rollAngle, in radians, and scale it by DeltaTime as we use it. I’ll give the little circle a non-zero value.

function Circle:init(radius, owner)
    -- you can accept and set parameters here
    self.owner = owner
    self.radius = radius
    self.angle = 0
    self.x = 0
    self.y = 0
    self.rollAngle = 0
    self.children = {}
end

function Circle:move()
    self.angle = self.angle + DeltaTime*self.rollAngle
    self:getNewPosition()
    for i,c in ipairs(self.children) do
        c: move()
    end
end

function Circle:getNewPosition()
    self.x, self.y = self.owner:moveMe(self, self.rollAngle*DeltaTime*self.radius)
end

I don’t think we’re using self.angle at all yet. That will come. But the change to getNewPosition should move us a bit along our path on every time through. What’s a good value to try in rollAngle? 6.28 would be one revolution per second. Let’s try 0.5, should be pretty slow but visible.

Bah. The small circle drifts off to the left. Let’s make everything much smaller just to see better what’s going on.

I’ll spare you the movie. It’s going up and to the left at a 45 degree angle. That is as if we were not applying the actual x and y in our calculation. Or …

OK belay that plan, back to the drawing board. I have two questions here. First, my test, I thought, would send a positive rotation up and to the right, not up and to the left.

Second … whatever our current tested code does, it’s only a function of where “inside” the circle the center point is assumed to be, so it will only apply that same step. It can only move diagonally. That isn’t exactly a question. Assume I’ve ended it with “right?”.

Think of the small circle as pinned to a stick from the center of the big circle to its edge. When the little circle rolls, we do compute the angle, myAngle, that the stick rotates:

function Circle:moveMe(child,d)
    local myAngle = d/self.radius
    local newPos = vec2(child.x, child.y):rotate(myAngle)
    return newPos.x, newPos.y
end

But we don’t preserve that angle. We can’t preserve it in the big circle, it has more than one child. Therefore we must accumulate that angle in the small circle, and use it in moveMe.

We’re definitely violating the Law of Demeter here, but for now, I think we must do that, and then unwind the violation with some refactoring.

Let’s return myAngle from moveMe and accumulate it in getPosition and use it in moveMe.

But what is it we really want to do?

Nota Bene:
Monday AM: This turns out to be a good question. Belay all this. It isn’t working out.