Corona For Newbies Part 3 covers dragging, confining an object to the screen and practical usage.
Tweet&getit is powered by Viuu
I no longer support Corona. These tutorials are provided as-is and I will not offer support for them.
If you would like to check out some tutorials I do provide support for please visit base.techority.com, which supports Lanica‘s Platino game engine.
*NOTE: If you have a problem with Twitter this download is also available here.
It isn’t a big, exciting part of the mini series but it is new and it does cover some very, VERY handy things you will all use at some point while making iPhone apps with Lua and the fabulous Corona SDK.
Below, as included in a readme.txt file in the download, is a brief note accompanying this installment in the Corona For Newbies mini series;
Thanks for downloading part three of Techority’s mini series, Corona for Newbies.
Today we’re covering how to drag an object, how to keep an object within the confines of your screen and how to put these things to practical use.
There is a lot more I’d like to cover, but that can wait until part 4 – I wanted to give you something to play with in the meantime.
Enjoy! (If you enjoy it enough, you can show thanks by liking Techority on Facebook or making a small donation to the site. $5 feeds a hungry Peach for a day!)
Part 4 will be out soon, so leave your suggestions at corona.Techority.com for me
Peach Pellen
http://twitter.com/peachpellen
I no longer support Corona. These tutorials are provided as-is and I will not offer support for them.
If you would like to check out some tutorials I do provide support for please visit base.techority.com, which supports Lanica‘s Platino game engine.
I hope you will enjoy Corona For Newbies Part 3, please leave requests for part 4 below, or email me.
Peach Pellen
PS – If you haven’t already, check out my templates! There’s a big, obvious button on the right hand side of the page!
How about scoring when touching a specific object or objects (versus anywhere on the screen, as in your exising score tutorial)?
[or did I miss something??]
Hah, hi Tim
You would add an event listener to the object/s in question in question rather than to the background ^-^;
Make sense? Let me know.
Peach
[...] Corona for Newbies, Part 3 – Dragging and Practical Usage [...]
This doesn’t pertain to this tutorial directly per say, but I am having a few problems.
I have a function that spawns a balloon every few seconds, and along with the balloon two other functions pertaining to it are created as well; Cull, which removes the balloon when it’s off screen and lowers the player’s HP, and Pop, which pops the balloon and adds to the score when touched. The problem is Cull doesn’t want to work with every other balloon as shown by a print function.
It seems Cull is being called, even after I remove the timer that calls it (I know it is successfully removed by testing earlier.) Of course, it tries to remove the balloon even though it no longer exists, so I tried removing the function as well as removing the balloon but no dice.
The really odd thing is that it:
1. Cull should not be called. (Possible scope problem?)
2. The ‘if’ statement at the begging of the code that dictates whether to continue the function is skipped. (I honestly don’t know how this is even possible!)
I thought the timer that calls the cull function could be calling other balloon’s cull functions just as they are being removed, but as I said I tried nil’ing out the cull function with no result. Nothing I do seems to work. Also, I should be using Tables and Arrays but their syntax and use with them is hard to grasp for me, I’m sure if you made a tutorial on the integration of tables and arrays to aid in handling basic functions many newbies such as myself would be thankful.
I’ll post the balloon code here, I guess.
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
local function insertBlueBalloon()
local blueBalloon = display.newImage("blue balloon.png")
blueBalloon.x = -100
blueBalloon.y = math.random(100, display.contentHeight - 100)
world:insert(blueBalloon)
-- Defines function that destroys Blue balloons when touched
local function popBlueBalloon(event)
if event.phase == "began" then
local poppingEffect = display.newImage("popped.png")
poppingEffect.x = event.target.x
poppingEffect.y = event.target.y
poppingEffect:scale(0.8, 0.8)
world:insert(poppingEffect)
score = score + (110 + event.target.x)
score = tonumber(string.format("%.0f", score))
scoreText.text = score
scoreText:setReferencePoint(display.CenterLeftReferencePoint)
scoreText.x = 25
event.target:removeSelf()
event.target = nil
timer.performWithDelay(1, function() collectgarbage("collect") end)
timer.cancel(c)
setHighScore()
-- Defines function that removes popping effect created from touch
local function removePoppingEffect()
poppingEffect:removeSelf()
poppingEffect = nil
end
timer.performWithDelay(100, removePoppingEffect)
end
end
local function cull()
if blueBalloon.x >= 400 then
blueBalloon:removeSelf() -- Nil comparison/upvalue index problem in this line, !!!prevents hp loss and culling 1/6 times!!!
blueBalloon = nil
timer.performWithDelay(1, function() collectgarbage("collect") end)
timer.cancel(c)
hp = hp - 1
print "HP lowered by 1."
else if blueBalloon.x <= 400 then
end
-- Checks to see if hp is zero, and if so, moves to correct screen
if hp < 1 then
timer.cancel(irb)
timer.cancel(ibb)
saveValue( "highscore.data", highScore )
director:changeScene("menu", "fade")
end
end
end
blueBalloon:addEventListener("touch", popBlueBalloon)
transition.to( blueBalloon, {time = 5000, x = display.contentWidth + 100, y = blueBalloon.y--[[, onComplete=cull--]]})
c = timer.performWithDelay(6000, cull, 1)
end
I’ve tried several things, which is partly responsible for why my code is so dang messy. I’m sure there are a million and one things screwed up with this code, but aside from this:
2
3
4
[File path]game.lua:172: in function '_listener'
?:Runtime error
[File path]game.lua:172: attempt to call method 'removeSelf' (a nil value)
It’s OK, your code isn’t too messy; you should see the stuff of mine I don’t post, haha.
Now, if it works with your game, I’d suggest using physics – have a wall out of sight that will kill any balloons on hit.
Alternatively, if you want to avoid physics there is likely something that could be put together – I’m exhausted right now so not the time to think on it – but if you are interested you could email me, I’ll take a look and see if I can fix it, then if I can – if you’re interested – I’d charge you a small fee. (I’d give you a quote before expecting any sort of commitment.)
Peach
Thanks. I am using physics for another type of balloon already, and I need the gravity to stay upwards. As far as I know gravity can’t be assigned to individual objects separately, so I decided to use a transition. Originally I used ‘onComplete=cull’ but guess what happened? Not only did the HP not go down and the cull function wrecked whenever I got that error, but the transition would stop randomly! Seriously. After popping a balloon, the next one would immediately glitch and stop at a random point on screen.
I’ve thought about adding physics to the blue balloons and as you said, adding a collision detector, but they’d collide with my red balloons going upwards. I could assign a bit to filter collisions, but that’s getting more complicated than I want to get. I’m thinking about reverting back to an ‘onComplete’ call, and just living with the random stopping. Make it a gameplay feature or something.
I don’t know, what’s better?
1. Letting the blue balloons move unimpeded, but half of them never removing themselves or lowering hp when they got across the screen…
or 2. Letting the glitched ones stop on a random spot on screen so that they’d at least be pop-able.
Also, the red balloons get the same problem, but their HP code almost always works and they don’t stop moving. I think I need to use more tables and arrays, but I have some trouble grasping the syntax.
I know that this:
2
3
4
5
6
7
8
9
tablename = { }
-- Sets values
tablename = {1, 7, 8, blah, orange, purple, whatever}
-- Retrieves values, [#] determines place
variable = tablename[1]
And that’s it. I fail when it come to making any practice use out of them, especially in handling functions. As you can see, I just kind of slap on functions within function within functions as things spawn… Of course this causes scope problems, etc.
—
Also, I know that physics don’t work between children of different display groups; is there anyway to make two groups affect each other? I’m thinking of making a platformer once I get better, but one thing stumps me: camera. I figured I’d put every tile into a ‘camera’ group as it spawned, and move the whole stage left and right as the character moves. This obviously would not work. If I made the player and other not movable objects into another group, and put both the camera and player groups into another group, would they affect each other then?
Example:
2
3
4
cameraGroup:insert(stageObject(s))
world:insert(playerGroup)
world:insert(cameraGroup)
I’m guessing not, because now they’re just in separate groups within a group. Another option would be to make a physicsGroup in which everything that was to interact with each other would be added, besides other groups.
So it would become:
2
3
physicsGroup:insert(stageObject(s))
cameraGroup:insert(stageObject(s))
I think that would work, as they’d share a group then…
Look at me ramble on. Dx Sorry for taking up so much of your time if you managed to read through this wall of text! e_e
So, I just woke up and that’s a lot of text, haha – but have you tried using a timer to remove the balloon, like in your function to remove it?
Also, is it possible the balloon is still in transition when you try to remove that?
Sorry if these are silly questions, my eyes are not letting me read all of the above right now – it’s like the drunk effect in World of Warcraft, haha XD
Peach
I guess I could use a timer with a one millisecond delay to call another function… Although I don’t see how it would help. I’ve looked at the code several times and it doesn’t seem to have anything wrong with it. Although another guy had a similar problem iirc, in the end it had some odd thing to do with looping, he also couldn’t use removeSelf from a table, the object directly, group etc. I tried collecting garbage after nil’ing out the balloon with a timer (no delay with timer for collection, oddly) but it doesn’t seem to help.
It is in transition when I remove it in my pop function, do you think that could be the problem? All though I’m not sure why that’d call my Cull function even after the timer that calls it, the only caller, is removed.
I’m guessing it’s some sort of scope + looping (it’s redone every few seconds) that’s the problem.
I always try a timer with issues like that – I had to use one recently on something similar. I shouldn’t have, it didn’t make sense, but it DID make it work.
As to it being in transition – YES. It is likely the issue – I should have read that before writing the above but just woke up.
Try canceling the transition BEFORE removing it; that should work. Let me know
Peach
Ok, it IS the transition most likely, and maybe the timer even. I noticed I’m not using local when defining variable timers and transitions. So, I tried to cancel it but it canceled all of my balloon transitions. I tried adding local but now it says it’s nil because it can’t find it. That’s really odd though because of where I defined them, it should be within scope.
I define the timers and transitions right after defining the balloon and it’s functions, I even tried defining them at the same time because defining them at the same time doesn’t seem to screw up the functions at all. Still can’t use local. I find that odd, I define three variables; a balloon, a timer, and a transition, yet I can only access the balloon. I’m kind of stumped. I’m guessing I’m somehow supposed to pass the timer & transition i want to cancel to the Pop function and Cull functions then?
Hmmmm, is your pop function within the same function used to spawn the balloon?
This might be worth posting on the Corona forums – I have some experience with it but there would be many better qualified to answer, I imagine.
There are a few threads talking about transitions and timers and dealing with their annoyances
Peach
Yeah, I’ll probably get an account on Ansca so I can use the forums when I get the energy to stop being lazy. The pop function is indeed within the spawn function. Which is why I’m saying my code is messy in a way, I always seem to have a hundred functions withing functions calling functions, and then wonder why there’s an error. e_e
Thanks for taking the time to try and help me. xD I know it must be annoying to have me post a thousand walls of text, and then be confronted by them as soon as you wake up. O:
The forums are great; they’ll be better now I’m on them in an official capacity ^-^; Haha.
You aren’t annoying at all; I just have trouble as I wake up and there’s a million emails waiting for me and yeah, easy to get overwhelmed I’m afraid.
Do check the forums though; I think they’ll hold the answer for you – there have been several posts related to this kind of thing.
Peach
I solved the blue balloon problem finally! Plus, the red balloon one that didn’t affect much on the terminal (Although it probably would’ve screwed everything up If I tried it on an iDevice).
For the blue balloon it was a scope and recursive problem. First off,
Does NOT equal:
<local function_name = function()
for recursive functions.
I know this because changing that ends up screwing me over. It seems using the first one, the shortcut, ends up defining things in a slightly different order, causing scope problems in very rare occasions. So, I swapped to the second way, after moving some stuff around, doing a few forward declarations, altering some local/global stuff, and TADA! Works like a charm...
Except the fact that after death and you fade to the next screen it seems to have tons of errors that have no permanent affect. Odd. I think I'm forgetting to remove something, but I'll fix it later.
Anyways, I have to say, THANK YOU!
You've been a great help. I never even thought about canceling the transition before removing the object, even though it was right in front of my face. Dx
Well, that's another obstacle or two cleared, and more knowledge for it.
Hey Ice Breaker,
Glad you got it worked out; good feeling, isn’t it?
Double check if you have any timers or Runtime listeners still going on that might cause the issues when you die. I do that all the time.
Better run, hectic day, lots going on.
Good luck with the other issues – and well done again!
Peach
I got the event listener to work for each item touched (versus the background)…how can I keep track of the individual touches to each object versus a total score? Say I’ve got 3 items on the screen – I’d like to keep track of how many touches I make to the left vs middle vs right object.
Thanks a million!
Hey Tim, that’s easy
For each object, lets say the same as in your example, do this;
left = 0
middle = 0
right = 0
Then in the touch function add one line;
left = left+1
Do that for each, where you’d normally print, play a sound, etc – and that will work. If you’d like to see it printed how many times something has been touched add a line;
print (left)
Make sense?
Gotcha…thanks.
Sooo…..do ya have any examples of how I could have the scores all print onto a different ‘page’?
For example, after touching the left, right & middle ‘x’ number of times, (using Director, of course), go to a different/next page to see the totals? :-}
Hey Tim,
I’m about to go back to bed (damn insomnia!) so I’m not totally with it right now; but is what you’re asking basically “How do I go to a gameover (or whatever) screen and on that screen display three different numbers, matching how many times my three things were touched?”
Is that about right? Let me know. I’ll check in again when I’m awake
Peach
Yep. Exactly!
OK, well rather than using “left” (like in the above examples I gave you) you would use _G.left (that’s a global variable.)
Then you’d change to a new screen/scene using director, add a background and then add some text, for example;
Make sense?
I have an array of buttons
mybutton[1] = display.newImage( ‘a.png’)
mybutton[2] = display.newImage( ‘b.png’)
I want to add listeners to each of the buttons
mybutton[1]:addEventListener(“tap”, onTap) throws an error
Any idea how to get it going? onTap function is declared elsewhere in the code.
Where is onTap defined? Above or below where you’re adding the listener? What’s the error?
Hi Peach, I’ve gone through all of your tutorials, and now I am going through them again. I bought a 2nd ed prog in Lua book, the reference manual etc.
Now I am really starting to tear things apart and I have a question
In the following code example, I display a box on screen and I drag it around. That’s fine and dandy.
What happens is when I touch the EDGE of the box, the box CENTERS on my mouse cursor in the simulator. I haven’t bought a Corona SDK license yet as I am waiting until I have enough of a app/game to actually put out there.
How would I just drag the edge of a box without centering on my cursor (or on a piece of hardware, a finger/thumb)?
This is from your part 3, Noobies guide to Corona, 1. Simple Dragging.
I also commented the code to the extreme to get MY understanding of how this works in my own words. Am I on the right track with how the function, drag stuff works?
Now I present, the code and comments below:
local boxpic = display.newImage (“box.png”)
boxpic.x = 230
boxpic.y = 230
–Creating a local function called ‘dragbox’ and tying touch events and tracking the object–
local function dragbox (event)
boxpic.x = event.x
boxpic.y = event.y
end
boxpic:addEventListener (“touch”, dragbox)
–[[
The local function we define with a name of choosing - in this case that's 'dragbox'
then we put in (event) *explained more below*
Then have to take the local variable we created earlier 'local boxpic' (which is what represents the box.png)
and then define how and when to track it. The how to track part is:
boxpic.x = event.x
boxpic.y = event.y
end
So basically what we are saying is I want to track the picture on whatever X and Y coordinates the picture is dragged to
the = event.x and event.y are tied to the "addEventListener"
Then we are defining what kind of event listener? in this case its "Touch", then we call the local function 'dragbox'
"touch" is on boxpic, we want to match the event coordinates.
What I understand about a touch even, is the event.x and event.y will follow the location of the touch -
>>>as long as it is on the boxpic!!!!!
--]]
I think I understand what you are asking – if so, look in the CoronaSDK folder at SampleCode, Interface, DragMe.
That doesn’t center the object being dragged on the touch.
Let me know if that’s what you wanted
(Sorry, I’m a little dopey today.)
@ peach
SampleCode, Interface Dragme = yep that was it.
I just launched the main.lua and it does allow me to drag edges…. I don’t know why I wanted to know I just did?
Anyway, thanks for the response I’ll dig through the code and figure it out. Thanks a bunch!
-Nick
Heh, well glad it was right even if you don’t know why you wanted to know
Peach
Hi Peach!
I checked out your tutorial and it makes sense now why you had those extra checks to make sure the objects don’t collapse into one position when you touch them as I was trying to create something similar. Any hints/tips on creating move on an object with some delays? The objects in your example will move to the exact position were your finger is touching, but I want to have a delay / some fluidity to it before reaching the position where your finger is pointing. I saw this feature on an app and wanted to do the same. Please get back to me when you’re rested and get some time.
Cheers!
Jen
Hey Jen,
A delay could be added by doing;
Although obviously x and y wouldn’t be 0
Is that what you mean by delay?
Peach
Ya it’s april 2012. I’m a honey badger.
For those who want pixel perfect dragging (i.e. meaning you can grab object from the corner and it won’t “snap” into place)
Drag the red box around, you’ll see
WEEEeEeEEeEeeEEeEeeEEeeeEeeEeeEeeEeeEeeeeEEee!
I SAID WEEEEEEEEEEEE
WEEE WEE ALL DAY LONG NICE AND STRONG OOOOO WEEEE YA YA.
lol. Ok, i’m calm now
WOOT!
here you go
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
68
69
70
71
72
73
74
75
76
77
78
local physics = require "physics"
physics.start(true)
physics.setGravity( 0, 10)
physics.setDrawMode( "normal")
--DECLARE WIDTH AND HEIGHT SHORTCUT VARIABLES
local _W = display.contentWidth
local _H = display.contentHeight
local ground = display.newRect (0, 400, _W,20)
physics.addBody(ground, "static")
ground:setFillColor (0,255,0)
local box = display.newRect (_W/2-50, _H/2, 100,100)
physics.addBody(box, "static")
box:setFillColor (255,0,0)
--======================================================================================
--------DRAG CODE (X AND Y TOUCH ACCURATE----
--======================================================================================
local function dragBody( event )
--print ("drag started")
local body = event.target
local phase = event.phase
local stage = display.getCurrentStage()
if "began" == phase then
stage:setFocus( body, event.id )
body.isFocus = true
--Change body to dynamic
event.target.bodyType = "dynamic"
-- Create a temporary touch joint and store it in the object for later reference
body.tempJoint = physics.newJoint( "touch", body, event.x, event.y )
--=====================
--=====================
--THIS PREVENTS ROTATION WHEN DRAGGING
--COMMENT OUT IF YOU DON'T WANT THIS
--body.isFixedRotation = true
--=====================
--=====================
elseif body.isFocus then
if "moved" == phase then
-- Update the joint to track the touch
body.tempJoint:setTarget( event.x, event.y )
elseif "ended" == phase or "cancelled" == phase then
stage:setFocus( body, nil )
body.isFocus = false
event.target:setLinearVelocity( 0, 0 )
event.target.angularVelocity = 0
--After the event ends, change body back to dynamic OR static.
event.target.bodyType = "dynamic"
--event.target.bodyType = "static"
-- Remove the joint when the touch ends
body.tempJoint:removeSelf()
--print ("drag ended")
end
end
-- Stop further propagation of touch event
return true
end
box:addEventListener( "touch", dragBody )
Why not to add the wrap function in the same dragging function? wouldn’t it fire only when it is needed? I am really a newbie on this, but it makes more sense to me to have it only when you need it.
Thanks for these tuts, you make look Corona really easy! I am considering a donation when I have some extra moolah
Hey Adrian, you are correct – I elaborate more on that in other tutorials however for the 4 original Corona For Newbies sets I deliberately broke things up as much as possible. People who have never programmed before seem to have an easier time memorizing and understanding code when it is all broken up in such a way. (I noticed on your site you’ve got some experience coding; more than me from the looks of things
)
In any case, you’re right – and that’s my reasoning for not doing so in this particular tut
Thanks for the kind words.