Okay - you asked for it 
self.frameLoop = function(event) -- compute potential horizontal motion for next frame based on key input if self.dead == false then if self.leftKeyPressed == true then self.xVel = self.xVel - self.xAccel elseif self.rightKeyPressed == true then self.xVel = self.xVel + self.xAccel elseif touching == false then self.xVel = self.xVel \* self.friction end else self.xVel = self.xVel \* self.deadFriction end -- limit speed if self.xVel \> self.xMaxVel then self.xVel = self.xMaxVel elseif self.xVel \< -self.xMaxVel then self.xVel = -self.xMaxVel end if self.platform == false then self.xPosNext = self.xPos + self.xVel else self.xPosNext = self.xPos + self.xVel + self.super.objectsManager.platformList[self.platform].xOffset end -- compute potential vertical motion for next frame if self.jumpState == "falling" then self.yVel = self.yVel + self.yAccel jumpTouch = false elseif self.jumpState == "grounded" then if jumpTouch == true then jumpTouch = false self.jump() end end if self.yVel \> self.yMaxVel then self.yVel = self.yMaxVel elseif self.yVel \< -self.yMaxVel then self.yVel = -self.yMaxVel end -- set yPosNext if self.platform == false then -- move self with velocity self.yPosNext = self.yPos + self.yVel else -- move along with platform self.yPosNext = self.super.objectsManager.platformList[self.platform].mainGroup.y end -- first correct the vertical movement, based on current X and next Y position !!! local bottomRow = math.floor((self.yPosNext)/self.super.tileWorld.tileHeight)+1 -- row number is like visual --\> first row you see = row 1 local topRow = math.floor((self.yPosNext-self.collisionHeight)/self.super.tileWorld.tileHeight)+1 -- local leftColumn = math.floor((self.xPos-self.collisionWidth/2)/self.super.tileWorld.tileWidth)+1 -- column number is like visual --\> first column you see = column 1 local rightColumn = math.floor((self.xPos+self.collisionWidth/2)/self.super.tileWorld.tileWidth)+1 -- first column = column 0 so add 1 for Arraypos's if (self.jumpState == "falling") or (self.platform ~= false) then if self.yVel \> 0 then -- moving down -- check if bottom points are in a platform if self.platform == false then for i = 1, #self.super.objectsManager.platformList do local vDistance = self.yPosNext - self.super.objectsManager.platformList[i].mainGroup.y local hDistance = math.abs(self.xPosNext - self.super.objectsManager.platformList[i].mainGroup.x) if (vDistance \> 0) and (vDistance \< 64) then -- 64 for platform height if self.super.objectsManager.platformList[i].platformWidth == 3 then if (hDistance \< 236) then self.jumpState = "grounded" self.platform = i self.yPosNext = self.super.objectsManager.platformList[i].mainGroup.y if self.super.objectsManager.platformList[i].type == "dropform" then self.super.objectsManager.platformList[i].startDropformTimer() end end elseif self.super.objectsManager.platformList[i].platformWidth == 2 then if (hDistance \< 156) then self.jumpState = "grounded" self.platform = i self.yPosNext = self.super.objectsManager.platformList[i].mainGroup.y if self.super.objectsManager.platformList[i].type == "dropform" then self.super.objectsManager.platformList[i].startDropformTimer() end end end end -- if end -- for platformList end -- if self.platform == false branch -- repeat check for bottom points in a dropform!!! local botLeftTile = self.super.levelMap.tileData[bottomRow][leftColumn] local botRightTile = self.super.levelMap.tileData[bottomRow][rightColumn] if (botLeftTile ~= 1) or (botRightTile ~= 1) then -- one or more bottom corners will be on a NOT AIR tile, so there is a collision, -- and the hero is stopped and placed on top of the tile audio.play(landSound) self.yVel = 0 self.yPos = (bottomRow-1)\*94 self.jumpState = "grounded" print("hero grounded") self.platform = false else -- both bottom corners are on an air tile, so the hero is not stopped by a tile, -- BUT!!! if might be stopped by a platform!!! Let's check! for i = 1, #self.super.objectsManager.platformList do local vDistance = self.yPosNext - self.super.objectsManager.platformList[i].mainGroup.y local hDistance = math.abs(self.xPosNext - self.super.objectsManager.platformList[i].mainGroup.x) if (vDistance \> 0) and (vDistance \< 64) then -- 64 for platform height if self.super.objectsManager.platformList[i].type == "platformSlow3" then print("platform type = platformSlow3") if (hDistance \< 236) then print("platform in hDistance") self.jumpState = "grounded" self.platform = i self.yPosNext = self.super.objectsManager.platformList[i].mainGroup.y if self.super.objectsManager.platformList[i].dropform == true then self.super.objectsManager.platformList[i]:startTimer() end end elseif self.super.objectsManager.platformList[i].type == 2 then if (hDistance \< 156) then self.jumpState = "grounded" self.platform = i self.yPosNext = self.super.objectsManager.platformList[i].mainGroup.y if self.super.objectsManager.platformList[i].dropform == true then self.super.objectsManager.platformList[i]:startTimer() end end end end -- if end -- for platformList self.yPos = self.yPosNext end elseif self.yVel \< 0 then -- moving up local topLeftTile = self.super.levelMap.tileData[topRow][leftColumn] local topRightTile = self.super.levelMap.tileData[topRow][rightColumn] if (topLeftTile == 2) or (topRightTile == 2) then -- one or more top corners will be on a solid tile self.yVel = 0 -- WRONG!!! self.yPos = (math.floor(self.yPosNext/94)\*94)+64 else self.yPos = self.yPosNext end elseif self.yVel == 0 then -- no vertical movement self.yPos = self.yPosNext end -- if (self.jumpState == "falling" or platform is true) else -- if self == "grounded" end -- then correct the horizontal movement, based on corrected Y and next X position !!! bottomRow = math.floor((self.yPos-1)/self.super.tileWorld.tileHeight)+1 -- first row = row 0 which is good for row multiplier 0\*mapwidth for Arraypos's local midRow = math.floor((self.yPos-self.super.tileWorld.tileWidth)/self.super.tileWorld.tileHeight)+1 -- first row = row 0 which is good for row multiplier 0\*mapwidth for Arraypos's topRow = math.floor((self.yPos-self.collisionHeight)/self.super.tileWorld.tileHeight)+1 -- first row = row 0 which is good for row multiplier 0\*mapwidth for Arraypos's leftColumn = math.floor((self.xPosNext-self.collisionWidth/2)/self.super.tileWorld.tileWidth)+1 -- first column = column 0 so add 1 for Arraypos's rightColumn = math.floor((self.xPosNext+self.collisionWidth/2)/self.super.tileWorld.tileWidth)+1 -- first column = column 0 so add 1 for Arraypos's if self.xVel \> 0 then -- moving right local topRightTile = self.super.levelMap.tileData[topRow][rightColumn] local midRightTile = self.super.levelMap.tileData[midRow][rightColumn] local botRightTile = self.super.levelMap.tileData[bottomRow][rightColumn] if (topRightTile == 2) or (midRightTile == 2) or (botRightTile == 2) then -- one or more right corners will be on a solid tile -- check wether on platform and only bottom point colliding if (self.platform ~= false) and (topRightTile ~= 2) and (midRightTile ~= 2) then -- hitting only bottom point to get off platform! self.xPos = self.xPosNext else self.xVel = 0 self.xPos = (math.floor(self.xPosNext/126)\*126)+63 end else self.xPos = self.xPosNext end elseif self.xVel \< 0 then -- moving left local topLeftTile = self.super.levelMap.tileData[topRow][leftColumn] local midLeftTile = self.super.levelMap.tileData[midRow][leftColumn] local botLeftTile = self.super.levelMap.tileData[bottomRow][leftColumn] if (topLeftTile == 2) or (midLeftTile == 2) or (botLeftTile == 2) then -- one or more top corners will be on a solid tile -- check wether on platform and only bottom point colliding if (self.platform ~= false) and (topLeftTile ~= 2) and (midLeftTile ~= 2) then -- hitting only bottom point to get off platform! self.xPos = self.xPosNext else self.xVel = 0 self.xPos = (math.floor(self.xPosNext/126)\*126)+64 end else self.xPos = self.xPosNext end elseif self.xVel == 0 then -- no horizontal movement self.xPos = self.xPosNext end -- gate check here !!! for i = 1, #self.super.objectsManager.gateList do local gate = self.super.objectsManager.gateList[i] if gate.gateState == "closed" then -- start checking stuff -- if gate is OPEN we do nothing at all! :-) -- CHECK wether self is IN gate rect if math.abs(gate.mainGroup.x - self.xPos) \< 128 then -- in horizontal area so check V overlap if (gate.mainGroup.y - self.yPos) \< 192 and (gate.mainGroup.y - self.yPos) \> - 444 then -- Y also within gate if self.holdingKey == false then -- self is blocked because gate is closed and self is not holding a key -- BLOCK self!!! if self.xVel \< 0 then -- moving left self.xVel = 0 self.xPos = gate.mainGroup.x + 128 elseif self.xVel \> 0 then -- moving right self.xVel = 0 self.xPos = gate.mainGroup.x - 128 end else -- self is HOLDING A KEY! -- So check if it is the RIGHT KEY index for this gate if self.holdingKey.index == gate.index then -- self opens door and moves through print("opened gate!") gate.open() self.holdingKey.mainGroup.y = -1000 self.holdingKey.keyState = "used" self.holdingKey = false else -- self is holding a key with the wrong index -- BLOCK self!!! if self.xVel \< 0 then -- moving left self.xVel = 0 self.xPos = gate.mainGroup.x + 128 elseif self.xVel \> 0 then -- moving right self.xVel = 0 self.xPos = gate.mainGroup.x - 128 end end -- check if holding the right key end -- self holding key or not check ends end -- if self is in vertical rect check ends end -- if self is in horizontal rect check ends end -- if gate.gateState == CLOSED or OPEN check ends end -- for loop over all gates ENDS -- finally, check to see if self is still standing on solid tiles or on finish -- if not on solid or cloud, set jumpState to "falling" -- if on finish tile, level is completed! bottomRow = math.floor(((self.yPos)/self.super.tileWorld.tileHeight)+1) -- first row = row 0 which is good for row multiplier 0\*mapwidth for Arraypos's leftColumn = math.floor((self.xPos-self.collisionWidth/2)/self.super.tileWorld.tileWidth)+1 -- first column = column 0 so add 1 for Arraypos's rightColumn = math.floor((self.xPos+self.collisionWidth/2)/self.super.tileWorld.tileWidth)+1 -- first column = column 0 so add 1 for Arraypos's local botLeftTile = self.super.levelMap.tileData[bottomRow][leftColumn] local botRightTile = self.super.levelMap.tileData[bottomRow][rightColumn] if self.platform ~= false then -- self is standing on a platform local hDistance = math.abs(self.xPosNext - self.super.objectsManager.platformList[self.platform].mainGroup.x) if self.super.objectsManager.platformList[self.platform].platformWidth == 3 then if hDistance \> 236 then self.platform = false self.jumpState = "falling" self.yVel = self.littleJumpSpeed end elseif self.super.objectsManager.platformList[self.platform].platformWidth == 2 then if hDistance \> 156 then self.platform = false self.jumpState = "falling" self.yVel = self.littleJumpSpeed end end else -- self is not on a platform if (botLeftTile == 1) and (botRightTile == 1) and (self.jumpState == "grounded") then -- both bottom corners will be on an air tile self.yVel = -10 self.jumpState = "falling" print("both corners on air") elseif (botLeftTile == 8) and (botRightTile == 8) and (self.jumpState == "grounded") then if self.finished == false then --print("level finished! Victory!") self.super.super.audioManager.playVictorySound() -- write unlocked and score into levelTable data and SAVE! -- set current level unlocked from PLAYABLE to PLAYED --levelTable.data[levelMap.number][3]=2 -- set next level unlocked from LOCKED to PLAYABLE --levelTable.data[levelMap.number+1][3]=1 -- set scores (temp to Gold Silver Bronze!) --levelTable.data[levelMap.number][7]=3 --levelTable.data[levelMap.number][8]=2 --levelTable.data[levelMap.number][9]=1 -- then SAVE the levelTable --levelTable.save() self.finished = true Runtime:removeEventListener("enterFrame", self.frameLoop) if (system.getInfo("environment") == "device") then -- disable touch controls for the hero character -- but this is done in the levelViewClass code! else -- disable key controls for the hero character Runtime:removeEventListener("key", self.keyListener) end self.super.gameInterface.popLevelEndScreen() end elseif (botLeftTile == 4) or (botRightTile == 4) and (self.jumpState == "grounded") then -- self is on death tile with one or two corners if self.dead == false then self.die() end else -- self is still standing on solid, cloud, ice or jump with one or both bottom corners end end -- draw self within it's own group (in turn within the maingroup) -- animate self running motion if self.dead == false then if self.jumpState == "grounded" then if self.xVel \> 4 then self.standingStill = false self.mainGroup.xScale = 1 self.runPhase = self.runPhase + self.xVel self.bodyGroup.y = 10 + math.abs(math.sin(self.runPhase/100))\*-32 self.leftArmGroup.rotation = math.sin(self.runPhase/100)\*60 self.leftForeArm.rotation = -40+math.sin(self.runPhase/100-2)\*30 self.rightArmGroup.rotation = math.sin(self.runPhase/100)\*-60 self.rightForeArm.rotation = -40+math.sin(self.runPhase/100-2)\*-30 self.leftLegGroup.rotation = math.sin(self.runPhase/100)\*-60 self.leftShinGroup.rotation = 60+math.sin(self.runPhase/100-1.5)\*-60 self.rightLegGroup.rotation = math.sin(self.runPhase/100)\*60 self.rightShinGroup.rotation = 60+math.sin(self.runPhase/100-1.5)\*60 self.head.rotation = 10+math.abs(math.sin(self.runPhase/100))\*-16 elseif self.xVel \< -4 then self.standingStill = false self.mainGroup.xScale = -1 self.runPhase = self.runPhase + self.xVel self.bodyGroup.y = 10 + math.abs(math.sin(self.runPhase/100))\*-32 self.leftArmGroup.rotation = math.sin(self.runPhase/100)\*60 self.leftForeArm.rotation = -40+math.sin(self.runPhase/100+2)\*30 self.rightArmGroup.rotation = math.sin(self.runPhase/100)\*-60 self.rightForeArm.rotation = -40+math.sin(self.runPhase/100+2)\*-30 self.leftLegGroup.rotation = math.sin(self.runPhase/100)\*-60 self.leftShinGroup.rotation = 60+math.sin(self.runPhase/100+1.5)\*-60 self.rightLegGroup.rotation = math.sin(self.runPhase/100)\*60 self.rightShinGroup.rotation = 60+math.sin(self.runPhase/100+1.5)\*60 self.head.rotation = 10+math.abs(math.sin(self.runPhase/100))\*-16 else if self.standingStill == false then --print("stand still") self.standingStill = true transition.to(self.bodyGroup, {time = 200, y = 15}) transition.to(self.head, {time = 150, rotation = 15}) transition.to(self.rightLegGroup, {time = 100, rotation = -35}) -- front leg forward transition.to(self.rightShinGroup, {time = 200, rotation = 45}) -- front shin straight transition.to(self.rightFoot, {time = 200, rotation = -10}) -- front shin straight transition.to(self.leftLegGroup, {time = 100, rotation = 5}) -- back leg backward transition.to(self.leftShinGroup, {time = 200, rotation = 25}) -- front shin straight transition.to(self.leftFoot, {time = 200, rotation = -30}) -- front shin straight transition.to(self.leftArmGroup, {time = 200, rotation = 10})-- back arm forward transition.to(self.leftForeArm, {time = 200, rotation = -60})-- back forearm forwar d transition.to(self.rightArmGroup, {time = 200, rotation = 15})-- right arm forward transition.to(self.rightForeArm, {time = 200, rotation = -85})-- right forearm forward else -- stand still motion -- used for testing limbs and joints positions --self.mainGroup.xScale = 4 --self.mainGroup.yScale = 4 --self.rightForeArm.rotation = self.rightForeArm.rotation + 1 --self.rightArmGroup.rotation = self.rightArmGroup.rotation + 1 --self.leftForeArm.rotation = self.leftForeArm.rotation - 1 --self.leftArmGroup.rotation = self.leftArmGroup.rotation - 1 --self.rightFoot.rotation = self.rightFoot.rotation + 1 --self.rightShinGroup.rotation = self.rightShinGroup.rotation + 1 --self.rightLegGroup.rotation = self.rightLegGroup.rotation + 1 --self.leftFoot.rotation = self.leftFoot.rotation - 1 --self.leftShinGroup.rotation = self.leftShinGroup.rotation - 1 --self.leftLegGroup.rotation = self.leftLegGroup.rotation - 100 --self.head.rotation = self.head.rotation + 1 --self.torso.rotation = self.torso.rotation - 1 end end end end end -- self.frameLoop