I ported this nice AS2 follow-object script by Philip Radvan
see the original post here http://www.freeactionscript.com/2009/04/enemy-behavior-run-away-follow-player/
fin.lua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | local fin = {} local radians = 180/math.pi --> precalculate radians fin.distanceBetween = function ( pos1, pos2 ) local sqrt = math.sqrt if not pos1 or not pos2 then return end if not pos1.x or not pos1.y or not pos2.x or not pos2.y then return end local factor = { x = pos2.x - pos1.x, y = pos2.y - pos1.y } return sqrt( ( factor.x * factor.x ) + ( factor.y * factor.y ) ) end fin.doFollow = function (follower, targetObject, missileSpeed, turnRate, doRotate, runAway) local missileSpeed = missileSpeed or 8 local turnRate = turnRate or 0.8 -- get distance between follower and target local target = targetObject local distanceX = target.object.x - follower.object.x; local distanceY = target.object.y - follower.object.y; -- get total distance as one number local distanceTotal = fin.distanceBetween (follower.object, target.object) -- calculate how much to move local moveDistanceX = turnRate * distanceX / distanceTotal; local moveDistanceY = turnRate * distanceY / distanceTotal; -- increase current speed follower.moveX = follower.moveX + moveDistanceX; follower.moveY = follower.moveY + moveDistanceY; -- get total move distance local totalmove = math.sqrt(follower.moveX * follower.moveX + follower.moveY * follower.moveY); -- apply easing follower.moveX = missileSpeed*follower.moveX/totalmove; follower.moveY = missileSpeed*follower.moveY/totalmove; -- move follower (or runner) if runAway then follower.object.x = follower.object.x - follower.moveX; follower.object.y = follower.object.y - follower.moveY; if doRotate == true then follower.object.rotation = math.atan2(follower.moveY, follower.xMove) * radians; end else follower.object.x = follower.object.x + follower.moveX; follower.object.y = follower.object.y + follower.moveY; if doRotate == true then follower.object.rotation = (math.atan2(follower.moveY, follower.moveX) * radians)+180; end end -- !!!!! you got to check if we hit the target - here or in main game logic !!!!! end return fin |
usage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | -- require the module local fin = require("fin") -- fin.doFollow (missileDisplayObject, targetDisplayObject [, missileSpeed, turnRate, doRotate, runAway]) -- example: local obj1 = {} local obj2 = {} obj1.object = display.newCircle( 200, 200, 20 ) -- touch object obj2.object = display.newCircle( 200, 200, 5 ) -- follower object -- you also have to setup initial speed for each follower object obj2.moveX = 2 obj2.moveY = 2 function mainLogic () -- in your game logic loop call the function fin.doFollow -- follower and target must be display object tables! -- tinker with missileSpeed and turnRate -- example 1: -- obj2 runs away from obj1, rotating fin.doFollow (obj2, obj1, 5, 1, true, true) -- example 2: -- obj2 follows obj1, rotating --> fin.doFollow (obj2, obj1, 5, 1, true, false) end function onTouch( event ) local phase = event.phase if "began" == phase or "moved" == phase then obj1.object.x = event.x obj1.object.y = event.y elseif "cancelled" == phase then end end Runtime:addEventListener( "enterFrame", mainLogic ); Runtime:addEventListener( "touch" , onTouch ) |
If you want to see this in action, just check out our game
PARALLAX http://youtu.be/rCtAaB-ct30
this function makes some nice heat seeking missiles :)
any questions?
-finefin
EDIT: here's a sample project. http://dl.dropbox.com/u/4175049/_fixed/doFollow.zip
I also edited the example above.
EDIT II: added doRotate and runAway parameters, also changed the algorithms to use precalculated radians
EDIT III: fixed yMove -> moveY
I edited my post, you should get it now ;)
Very useful, tyvm!
Hi canupa,
Thanks for sharing.
Can your code be used for my game for free?
Thanks
@mila,
long(ish) answer: feel free to copy, paste, rewrite, tweak, evolve, share, use, publish, utilize, avail, devote yourself to, link to and talk about it! As stated, credits go to Mr. Radvan from freeactionscript.com - you can find some game code gold there and ActionScript isn't much different than LUA. Porting that function was quite a no-brainer...
short answer: absolutely! ;)
have fun
-finefin
Hi Manupa, than k you soooo much.
I am testing your sample project, I like to have more followerObject, say I added one more ,followerObject4.object, but when I run the program, the one I added not showing up, what I am doing wrong, pls see the code:(Thanks in advance)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | local fin = require("fin") -- create some objects local touchObject = {} local followerObject = {} local followerObject2 = {} local followerObject3 = {} local followerObject4 = {} touchObject.object = display.newCircle( display.contentWidth/2, display.contentHeight/2, 20 ) followerObject.object = display.newCircle( 200, 200, 8 ) followerObject2.object = display.newCircle( 200, 200, 4 ) followerObject3.object = display.newCircle( 200, 200, 12 ) followerObject4.object = display.newCircle( 200, 200, 16 ) -- define individual/initial speed followerObject.moveX = 2 followerObject.moveY = 2 followerObject2.moveX = -2 followerObject2.moveY = -2 followerObject3.moveX = 2 followerObject3.moveY = 2 followerObject4.moveX = 2 followerObject4.moveY = 2 function mainLogic () -- fin.doFollow (missileDisplayObject, targetDisplayObject [, missileSpeed, turnRate]) fin.doFollow (followerObject, touchObject ,5, 1) fin.doFollow (followerObject2, touchObject ,10, 1.2) fin.doFollow (followerObject3, touchObject ,3, 0.3) fin.doFollow (followerObject4, touchObject ,12, 0.8) end function onTouch( event ) local phase = event.phase if "began" == phase or "moved" == phase then touchObject.object.x = event.x touchObject.object.y = event.y elseif "cancelled" == phase then end end Runtime:addEventListener( "enterFrame", mainLogic ); Runtime:addEventListener( "touch" , onTouch ) |
Hi canupa.com,
Please disregard my previous question, it works fine, My bad, I did something wrong, I added more FollowerObjects, working fine......
Wow, I've been looking for something like this for a while!
Thanks so much! I'll try it out tonight and hopefully everything goes smoothly :)
I'd really like to see enemy avoidance added to this lib. i'd kick you down some $$ via paypal to make it worth your while. :) Always loved the flocking/avoidance algorithms!!
@mroberti + all
I added a runAway flag in the doFollow function. This, again, was quite a no-brainer (just take a look at line 49ff. - really simple!)
so I give it to you for free ;)
If you want to say thank you and support us, just load/buy our apps and leave some nice reviews
http://itunes.apple.com/de/artist/canupa/id334723985
THAT would be really appreciated!
cheers!
-finefin
[SOLVED]
Misnamed xMove and moveX. :) Rename them all the same throughout the code and it works perfectly!
@mroberti oh right, I forgot about that ;) ...fixed
Could you add some sample display objects (rects, circles or whatever) to demonstrate this?
I was looking at it, and was a bit confused :)
ng