Need help with applying rotation with Tween

First of all I totally dig Codea. Been using it for less than a year with amazing results. Huge chunks of my code are take from the examples you guys have shared with the community here, couldn’t have got this far without you guys sharing so Thank you.

I am trying to create a turn based game in the vein of Advance Wars or Tabletop games.

In my game scene I move my “Actors” by tweening them between a list of points but I haven’t been able to implement rotating my actor yet. What I am trying to do (in the rotLeft() function) is Tween from my current position to the same position but at a different angle but it isn’t working.

Do you guys have any suggestions on how i can accomplish this? Here is my Actor class.


-- Actor

Actor = class()
function Actor:init(x, y, size, id, cellx, celly)
   self.angle = 0
   self.x = x
   self.y = y
   self.id = id
   self.size = size
   self.ctrlType = 0
   self.scale = 1.0
   self.ap = 4
   self.clipSize = 4
   self.bullVel = 60
   self.offset=1
   self.startTouch = false
   self.showMove = false
   self.move = false
   
       self.inactive = 0
       self.canMove = 1
       self.moving = 2
       self.fireing = 3
   self.state = self.inactive
   
       self.north = 0
       self.east = 1
       self.south = 2
       self.west = 3
   self.dir = self.north    
   self.moves = {}
   self.tab1 = {}
   self.buttons = {}
   self.bullets = {}
   self.grid = {}
   self.curBullet = self.clipSize
   self.selected = 0
   
   self:reload()
   self.index = vec2(cellx or 0, celly or 0)
   self.last = vec2(x,y)
   tweenObject =  vec3(x,y,self.rotation)
end

function Actor:reset()
   self.tab1 = {}    -- table for points
   self.moves ={}
   self.offset=1
   self.dx=0
   self.dy=0
   self.showMove = false
   self.move = false
   self.startTouch = false
   self.buttons = {}
end

function Actor:reload()
   for i=1,self.clipSize do
   local prog = Projectile()
   table.insert(self.bullets,prog)
   end
end

function Actor:fire()
  local bull = self.bullets[self.curBullet]
   bull:fire(self.bullVel, self.angle, self.x, self.y, 20)
   sound(SOUND_SHOOT, 17108)
   self.curBullet = self.curBullet - 1
   if self.curBullet < 1 then
       self.curBullet = self.clipSize
   end

end


function Actor:toggleShowMoves(grid)
   if self.showMove then
       self.grid = grid
       self:makeButtons(self.ap)
   else

   end
end

function Actor:draw()
   dir = self.dir
   state = self.state
   local a; local b
   local line=line

   for z=self.offset+1,#self.tab1 do

       pushStyle()
       stroke(255)
       strokeWidth(3)
       line(self.tab1[z-1].x,self.tab1[z-1].y,self.tab1[z].x,self.tab1[z].y)
       popStyle()

   end    
   for z=self.offset+1,#self.moves-1 do
       pushStyle()
       stroke(0, 255, 0, 255)
       strokeWidth(3)
       line(self.moves[z-1].x,self.moves[z-1].y,self.moves[z].x,self.moves[z].y)
       popStyle()
   end

   if self.move then    -- try to move at constant speed
       a=math.sqrt(self.dx*self.dx+self.dy*self.dy)
       b=5/a
   end
   pushMatrix()
   rotate(self.angle)
   scale(self.scale)
   batch:sprite("cmane",self.x,self.y)
   
   if self.selected > 0 then
       pushStyle()
       tint(64, 255, 0, 255)
       batch:sprite("mselect",self.x,self.y)
       popStyle()
   end
   
   if self.show then
       pushStyle()
       tint(253, 0, 255, 255)
       batch:sprite("jammed",self.x-20,self.y+20)
       popStyle()
   end
   
     if self.startTouch then
       pushStyle()
       tint(255, 0, 0, 255)
       batch:sprite("jammed",self.x-20,self.y+20)
       popStyle()
   end
   
   if self.showMove then
       pushStyle()
       tint(64, 255, 0, 255)
       batch:sprite("overwatch",self.x+20,self.y+20)
       popStyle()
   end
   popMatrix()
   self:takeMove()
   self:drawList(self.bullets)
   if self.ctrlType == 0 then
       if self.showMove then
           if self.selected > 0 then
               self:drawList(self.buttons)
           else
               self.showMove = false
           end
       end
   end
   
end

function Actor:rotLeft()
self:tweenSelfStep(0,self, {rotate = 270})
end

second part of the Actor class


function Actor:rotRight()
end

function Actor:over()
end

function Actor:makeButtons(ap)
   print("AP "..ap)
   self.buttons = {}
   self.startplace = vec2(0,0)
   self.endplace = vec2(0,0)
   self.xx = self.x -(ap * self.size)
   self.yy = self.y - (ap * self.size)
   
   for i = 0, (ap+ap) do
       for j = 0, (ap+ap) do
           if i == 4 and j == 4 then 
               
           else
               self.startplace = GameScene:cellAt(self.x, self.y,self.grid)
               self.endplace  = GameScene:cellAt(self.xx+(self.size*j),
               self.yy+(self.size*i),self.grid)

               if self.endplace then
                 local startx = self.startplace.x
                 local starty = self.startplace.y
                 local endx = self.endplace.x
                 local endy = self.endplace.y

               if self:isValid(self.endplace.x,self.endplace.y,self.grid) then
                   btnName = "moveButton" .. i .. j
                   btnName = TileButton(self.xx+(self.size*j),
                    self.yy+(self.size*i),
                    false, "mselect", i+j)
                   btnName.action = function()
                       self:addMoves(GameScene:findPath(actors,self.grid,
                       startx,
                       starty,
                       endx,endy)
                       ) 
                       self:toggleShowMoves(self.grid)
                   end
                   table.insert(self.buttons,btnName)
                   end
               end
           end
       end
   end
end

function Actor:isValid(posx, posy, grid)
   local cell = grid[posy][posx]
   if cell.state < 17 then
       return true
   end
   return false
end

function Actor:drawBullets()

   for i=1,#self.bullets do
       bull = self.bullets[i]
       bull:draw()
   end
end

function Actor:drawList(listOfStuff)
   for i,thing in ipairs(listOfStuff) do
       thing:draw()
   end
end

function Actor:chechState() -- doesnt work
   if self.state == 4 then
   elseif self.state == 1 then
   elseif self.state == 2 then
   elseif self.state == 3 then
   end 
end

function Actor:hit(p)
   local l = self.x - self.size/2
   local r = self.x + self.size/2
   local t = self.y + self.size/2
   local b = self.y - self.size/2
   if p.x > l and p.x < r and
      p.y > b and p.y < t then
       return true
   end
   
   return false
end

function Actor:touchActorButtons(touch,listOfButtons)
   for i,btn in ipairs(listOfButtons) do
       btn:touched(touch)
   end
end

function Actor:touched(t,grid)
   self:touchActorButtons(t,self.buttons)
   

   if t.state==ENDED and self:hit(t) then
       if DEBUG then
           tempVec = vec2(GameScene:cellAt(self.x,self.y,grid).x,
           GameScene:cellAt(self.x,self.y,grid).y)
           print("Raw pos: "..t.x..","..t.y)
           print("I am at: "..self.x..","..self.y)
           print("At cell: "..tempVec.x..","..tempVec.y)
       end
   end

   if self.ctrlType == 0 then
       if t.state==BEGAN and self:hit(t) and not en then
           self:setSelected()
           self.startTouch = true

           if t.tapCount==2 then
         --  print("Double Tap")
               self.tab1 = {}
               self:fire()
           end

           if self.x==0 and self.y==0 then
               self.x=t.x
               self.y=t.y
           end
               
           if self.selected > 0 then
               self.showMove = true
               self:toggleShowMoves(grid)
           end            
       elseif t.state==MOVING then

       elseif t.state==ENDED and self.startTouch then

           if self.tab1[1] == nil then

           else
               self.dx=(self.tab1[self.offset].x-self.x)
               self.dy=(self.tab1[self.offset].y-self.y)
               self.move=true
           end
       else
       end

   elseif self.ctrlType == 1 then
       if t.state==BEGAN and self:hit(t) and not en then
           if t.tapCount==2 then
            --   print("Double Tap")
                 self.tab1 = {}
           end

           if self.x==0 and self.y==0 then
               self.x=t.x
               self.y=t.y
           end

       self.startTouch = true
       elseif t.state==MOVING and self.startTouch then
            self.hx=t.x
            self.hy=t.y
           if self:calcDist() then -- limit points in the table
               table.insert(self.tab1,vec2(t.x,t.y))    -- insert points in table
           end
       elseif t.state==ENDED and self.startTouch then
           if self.tab1[1] == nil then
               print("Err. no self.tab1 to index")
           else
               self.dx=(self.tab1[self.offset].x-self.x)
               self.dy=(self.tab1[self.offset].y-self.y)
               self.move=true
               self.startTouch = false
           end
       else
           print("ctrl 1")
           self:reset()
       end
   else
       print("self.ctrlType unknown")
   end

end

function Actor:isSelected()
   if self.selected > 0 then
       return true
   else
       return false
   end
end

function Actor:setSelected()
   self.selected = 1
   print("selected: "..tostring(self.selected))
   for i,itm in ipairs(actors) do
       if itm.id ~= self.id then
       itm.selected = 0
       itm.startTouch = false
       itm.buttons = {}
       end
   end
end

function Actor:addMoves(table)
   if table == nil then
   print("-- Error: table is nill")
   else
   if #table > 1 then
       
   for i,vec in ipairs(table) do
       self.tab1[i] = vec
   end
   end
   end
end

function Actor:takeMove()
   if self.move then
       self.buttons = {}
       if self.offset==#self.tab1+1 then
           print("Reset")
           self:reset()
           self.selected = 0
           return
       end
       
       a=math.abs(self.tab1[self.offset].x-self.x)    -- calc new x,y direction
       b=math.abs(self.tab1[self.offset].y-self.y)
       ab=math.sqrt(a*a+b*b)
       local target = self.tab1[self.offset]
       self:tweenSelfStep(self.id,target)
       
       if ab<4 then
           local mypos = GameScene:posAt(self.x,self.y,self.grid)          
           self.offset = self.offset + 1
           self.ap = self.ap - 1
           print("AP: "..self.ap)
           local mycell = GameScene:cellAt(self.x,self.y,self.grid)
           print(mycell)
       end

   end
end

function Actor:tweenSelfStep(id,target)
   for i,act in ipairs(actors) do
       if act.id == id then
           self.move = false
           print("tweening: "..id)
               tween( 0.25 , act, target, tween.easing.quadInOut,
                   function()
                      self.index = GameScene:cellAt(self.x,self.y,self.grid)
                      self.move = true 
                   end )
       end
   end
end

Third part of the Actor Class


function Actor:takeMoves()
   local a; local b; local ab

   if self.move then
       if self.offset==#self.tab1 then
           self:reset()
           local mypos = GameScene:posAt(self.mx,self.my,self.grid)
               self.mx = mypos.x
               self.my = mypos.y
           return
       end

       a=math.abs(self.tab1[self.offset].x-self.mx)    -- calc new x,y direction
       b=math.abs(self.tab1[self.offset].y-self.my)
       ab=math.sqrt(a*a+b*b)
       print(self.offset..".) a,b,ab: "..a..","..b..","..ab)
       print(self.offset..".) mx,my: "..self.mx..","..self.my)
       if ab<4 then
           local mypos = GameScene:posAt(self.mx,self.my,self.grid)          
           
           self.offset = self.offset + 1
           self.dx=self.tab1[self.offset].x-self.mx
           self.dy=self.tab1[self.offset].y-self.my
           local mycell = GameScene:cellAt(self.mx,self.my,self.grid)
           GameScene:setPos(mycell)

       end
       
   end
end

function Actor:moveCircle()
   local a; local b; local ab
   local startX
   local startY

   if self.move then
       if self.offset==#self.tab1-1 then
           self:reset()
           return
       end

       a=math.abs(self.tab1[self.offset].x-self.mx)    -- calc new x,y direction
       b=math.abs(self.tab1[self.offset].y-self.my)
       ab=math.sqrt(a*a+b*b)
       
       if ab<5 then
           self.offset = self.offset + 1
           startX = self.dx
           startY = self.dy
           self.dx=self.tab1[self.offset].x-self.mx
           self.dy=self.tab1[self.offset].y-self.my
           local vecself= vec2(self.tab1[self.offset-1].x,self.tab1[self.offset-1].y)
           local vecother = vec2(self.tab1[self.offset].x,self.tab1[self.offset].y)
           local vec = vecother - vecself
           self.angle = math.deg(vec:angleBetween(vec2(0,1)))
       end
   end
end

function printTables(table)
    for i=1,#table do
       print(i..".) table.x,y: "..table[i].x..","..table[i].y)
   end
end

function Actor:calcDist()
   local t=#self.tab1
   local a; local b
       if t>1 then
           a=self.hx-self.tab1[t].x
           b=self.hy-self.tab1[t].y

           if a*a+b*b>1024 then 
               return true
           end
       return false
       end
   return true

end

function Actor:fillMoveList()
  print("filling list")
   
   local last = vec2(self.x,self.y)
      table.insert(self.moves,last)
   for z=self.offset+1,#self.tab1-1 do
       
       local startX = self.tab1[z-1].x
       local startY = self.tab1[z-1].y
       local nextX = self.tab1[z].x
       local nextY = self.tab1[z].y
       local diffX = startX - nextX
       local diffY = startY - nextY
       local buffer = 20
       
       local up = vec2(last.x,(last.y + self.size))
       local right = vec2((last.x + self.size),last.y)
       local down = vec2(last.x,(last.y - self.size))
       local left = vec2((last.x - self.size),last.y)
       
       print("diff x,y: "..diffX..","..diffY)
       if diffX < -buffer then
           print("Right")
           table.insert(self.moves,right)
           print("adding point: "..right.x..","..right.y)
           last = right
       elseif diffX > buffer then
           print("Left")
           table.insert(self.moves,left)
           last = left
       elseif diffY < -buffer then
           print("Up")
           table.insert(self.moves,up)
           last = up
       elseif diffY > buffer then
           print("Down")
           table.insert(self.moves,down)
           last = down
       end
   end    
end

it seems to me you are providing self as the target for tweening. My understanding is that target needs to be a table of key value pairs.

Isn’t self a table of key-value pairs?

maybe, but not the ones he wants. He needs to provide the set of numeric values he actually wants to tween. Self includes all sorts of stuff including text, which doesn’t tween very well :stuck_out_tongue:

self totally works, now I just have to figure out how to also apply rotation.

this is what my rotLeft function looks like now,

function Actor:rotLeft()
    local target = {x=self.x+10, y=self.y+10}
    self.move = false
    tween(0.25,self,target,tween.easing.quadInOut, function() print("Moved") end)

   __ self:tweenSelfStep(0,self, {rotate = 270})
end

self works fine as the subject, but you had it as target originally, now you have a target of an x,y vector which is ok

to rotate, if you are in 3D, you would provide enough vector changes to rotate the object, whereas if you are in 2D you’d perhaps need to rotate your viewpoint. In other words, I don’t think tween is going to take care of the details, and you’ll need to figure them out