Drag and Drop for multiple objects / display group

Hey guys,

i want to develop an solitare card game and im using the basic drag and drop code with collision detection.

Every card is an object and has a tap eventListener that calls “dragCard”.

That code works perfect when i only drag and drop single cards but i have to drag and drop multi cards and the same time.

I really dont know how i can to that and now i’m trying to make a check in the eventListener if only one card or multi cards should be dragged. If multi cards should be dragged, i make a new display group and insert all cards in that new display group that should be draggen and at the end i want to chance the target(event.target) to this new display group instead of only dragging the single card but when i try my code in the game, i cant move anything after i want to dragg multi cards :confused:

maybe you can help me with my code or maybe you have a better solution for me how i can solve the multi drag problem.

local target local function dragCard( event ) local phase = event.phase if ( event.phase == "began" ) then if event.target.parent.numChildren == event.target.pos then target = event.target else local newGrp = display.newGroup() newGrp.color = event.target.cColor newGrp.cNumber = event.target.cNumber local diff = event.target.parent.numChildren - event.target.pos local num = event.target.parent.numChildren for i = 0, diff do local cardObj = event.target.parent[event.target.parent.numChildren] local index = (num-i) newGrp:insert(index , cardObj) end target = newGrp end local parent = target.parent display.getCurrentStage():setFocus( target ) target.isFocus = true target.x0 = event.x - target.x target.y0 = event.y - target.y target.xStart = target.x target.yStart = target.y target:toFront() elseif ( target.isFocus ) then if ( phase == "moved" ) then target.x = event.x - target.x0 target.y = event.y - target.y0 elseif ( phase == "ended" or phase == "cancelled" ) then display.getCurrentStage():setFocus( nil ) target.isFocus = false if ( hasCollided( event.target, hotSpots ) ) then -- Snap in place transition.to( event.target, {time=0, x=hotSpotX, y=hotSpotY} ) else -- Move back transition.to( event.target, {time=0, x=event.target.xOrig, y=event.target.yOrig} ) end end end return true end

and this part is my own code, the rest of the code is for single object dragging:

if event.target.parent.numChildren == event.target.pos then target = event.target else local newGrp = display.newGroup() newGrp.color = event.target.cColor newGrp.cNumber = event.target.cNumber local diff = event.target.parent.numChildren - event.target.pos local num = event.target.parent.numChildren for i = 0, diff do local cardObj = event.target.parent[event.target.parent.numChildren] local index = (num-i) newGrp:insert(index , cardObj) end target = newGrp end

I hope you understand my problem :slight_smile:

Thank you

Br,

a.jaks

Okay i think im close to solve this.

I have now a display group “dragGrp” and im adding a event listener:

dragGrp:addEventListener("touch", dragGrp)

My cards have a touch listener that calls the buildGrp fuction, a function where i fill the dragGrp, like you can see here:

dragGrp = display.newGroup() function buildGrp( event ) local target = event.target local phase = event.phase if ( phase == "began" ) then if (target.pos == disGrp.numChildren) then dragGrp:insert(target) end end end

In this case i just want catch the last card of the stack of cards for testing.

The function “dragGrp:touch(event)” is the same as the dragCard function from my previous post but without my own code.

Now the problem:

With this code, i need to click two time to start the dragging, the first click calls the buildGrp function and fills the group and the secound click calls the dragGrp:touch function and draggs the card.

Is there a way to trigger / simulate the dragGroup touch in my BuildGrp function? 

Or is it possible to combine the two functions so that i just need one fuction?

And if you have a idea for a other, better, solution, please let me know :slight_smile:

Can really no one help me how to drag multiple cards like in solitare?

Not even an idea?

@a.jaks,

Hi.  I read this when you first posted it and I want to help, but there are a few reasons I did not:

  1. You asked a question, but then said you wanted to implemented it with your own tap listener. i.e. It is kind of like saying, “Help me solve this, but solve it the way I think it should be solved.”  You probably didn’t mean this, but still that is what I got out of it.

  2. I’m actually a little unclear on the behavior you’re trying to achieve (see my questions below).

  3. At the end of the day, I pretty much solve all problems with SSK2 because I’m just so darn lazy and hate re-writing code when I can avoid it.  That said, I do want to help.  So let me ask some questions and we’ll see what can be done.

Questions:

  1. Do you want to allow multiple cards to be dragged at the same time or just one at a time?
  2. When you ‘drop’ the card, should we just leave the card there, or should we detect if it was dropped over a ‘hot spot’/‘target’ and do something special.
  3. If we do something special, should we trigger an event, and/or move the card to better align with the hot-spot (i.e. snap to).
  4. If we don’t let the card just lie there after a drop and if we do have hot-spots.  What does the card do if we miss a spot?  Does it fly back to the original position?
  5. Can we drop more than one card consecutively on the same hot spot?
  6. If we use hot spots, do they have a ‘zone of attraction’ where a drop that is close-enough is considered a hit?

Oh, and be aware.  I have a huge collection of examples and answes  to various questions over the years:

@roaminggamer

thank you a lot that you want to help me.

I’m really sorry if my question is unclear, my english is not the best and i’m pretty new in corona SDK so its hard for me to ask in the right way :confused:
I also dont know SSK2 and how it could help me with my game :slight_smile:

Let me answer your questions:

  • Do you want to allow multiple cards to be dragged at the same time or just one at a time?

Yes, it should be like in a normal solitare game. When i drag the last card of a stack, only one card is dragged but when i drag the first card of a stack of 6 cards, all 6 cards should be dragged at the same time.

  • When you ‘drop’ the card, should we just leave the card there, or should we detect if it was dropped over a ‘hot spot’/‘target’ and do something special.

The collision with a hot spot should be detected and in this case, the card / cards should be inserted into the hot spot. I have a collision detection code from the internet, it works pretty good and in case of a collision, i insert the card in the hot spots display group. 

  • If we do something special, should we trigger an event, and/or move the card to better align with the hot-spot (i.e. snap to).

Sorry but i dont understand this question :confused:

Do you mean if the card should be moved over the hot spot? If yes, then the answer is yes.

  • If we don’t let the card just lie there after a drop and if we do have hot-spots.  What does the card do if we miss a spot?  Does it fly back to the original position?

Yeah thats right. It should move back to the previous position.

  • Can we drop more than one card consecutively on the same hot spot?

Yes.

  • If we use hot spots, do they have a ‘zone of attraction’ where a drop that is close-enough is considered a hit?

That is not needed, the size of the hot spot should be enought.

 

 

So i answered your questions but let me say that the most things of your questions already work with my code.

I have a collision detection, a move back function, and the cards will move to the hot spot when there is a collision. But all just works when i drag and drop single cards (no display groups) but i need to move multiple cards. Thats my problem, i dont know the best solution for a multi-cards drag and drop. I tryed to put all cards that should be moved into a seperate display group and move the whole display group but this dont work well, the dragged group is not on my mouse cursor and all other things also dont work the :confused:

 

Someone wrote that in a solitare game in corona sdk all cards should be display groups but does this make sense?
In my code all cards are images and the only display groups i have, are the spots where the cards are been dropped and the stack of cards.

 

As i said, im pretty new and if you know a better way the things should be done, please let me know :slight_smile:

Thank you :slight_smile:

Thanks for the responses.

I can see there is going to be a problem however.  I would like to suggest you start with something simpler than this card game.

The mechanics you describe are quite difficult to code in an elegant and error free fashion.  I know it ‘looks simple’, but trust me, it is not.  This is not a beginner game.

The whole “drag a card” to an arbitrary hot-spot that changes based on how many cards are present in a stack/set, and the concept of dragging a set or stack of cards where the number of grouped cards can change… is way beyond beginner stuff.

(Individually, these mechanics are not rocket science, but combining them into an actual game, and accounting for weird user actions and interactions (aka corner-cases), that is the trick.)

While I want to help you, there are fundamentals here that need to be addressed / taught / learned first.

I will be doing at least one card game in my ‘Fundamentals Series’, but it won’t be solitaire (too hard to explain and code in such a way that users can grok it).  So, the best I can do is say:

Sorry!

Final note.  SSK2 would help with this, because believe it or not there will be vector math involved.  A good (in my opinion) solution will also involve the use of user defined Runtime events.  Of course there is dragging-and-dropping (that is part of the title).  The list goes on.

Please note: SSK2 is most useful for people with a solid understanding of the fundamentals. It is, in a sense, a faster and shorter (coding wise) way to achieve what would typically require lots of coding. i.e. SSK2 is a collection of solutions to typical problems.   It isn’t a way to skip learning the fundamentals unfortunately.

Thank you for your answer.

I will take a look at SSK2 and your Fundamentals Series.

The thing is, i just need the drag and drop for the game, no other math or calculation. As i said, the game is working good, the only thing that i need is the multi drag and drop. Could this really be that complicated that i had to stop working on this game?

Im a programmer and i did a 2D corona SDK game in a group for the university so i have basic knowledge. 

I also have a solution to get all cards that should be draggen when clicked on one card that is in the back of the stack and i also put all these cards in a group, the collision detection with other hot spots also works as well as the positioning of the cards when dropped.

The only thing i need is to drag the group like it would be a single card or maybe a other solution, like a work around.

At the moment i touch a card and the eventListener is called, this listener builds the new display group and drags it. When i make a example with a whole display group that i drag, it works finde, also when i use the drag code for a single card but the comination in my code doesnt work. I build the group and drag the group instead of the single card and this causes the problem because the dragged group is not at the same position like the mouse cursor. I could imagine that i just need to set / change or add some values in the drag function and this would work well.

I’m saying the drag and drop functionality you describe isn’t simple to implement.  Sorry.

Dragging and dropping is easy, but morphing its behavior based on context is more difficult.

Can you describe this more precisely?
“the dragged group is not at the same position like the mouse cursor”
Is there some offset when you drag
Or the cards in the group do not move at all?

@a.jaks this is quite easy to implement if you think about it in a different way

I would suggest you have 7 display groups (representing each stack of cards).  Insert the cards in the order they would naturally stack and give each one an index, a colour and a value.  The first card would have index 1, the one on top of it index 2, etc.

Then implement a global touch handler that spans all the display groups.  On phase==“began” you would store which display group you have hit (i.e. which stack of cards) and the index, colour and value of the card that was hit.

To perform the multiple drag n drop it is now simply a case of iterating the objects in that display group and selecting all those with a higher index.  Drop the alpha a bit and add a fill effect to indicate to the user which cards have been selected.  You drag the first card and then manually adjust the x,y of all the linked cards in phase==“moved”.

The “can I drop logic” will be simply based on comparing the colour and value of the dragged card to top card in the display group you are now hovering over.  Maybe apply a new fill effect or add a green overlay?  On drop, remove the cards from one display group and insert into the new display group and index the new cards accordingly.

@Arteficio

the cards move but there are offset. This happens when i touch the card, not when i move the card / cards.

@adrianm

yeah thats what i already do. Every card has a position for the position in the current group it is in.

I already tried to move all linked cards while using a for loop and move all cards at the same time but the cards are offset then. I think the for loop causes this problem because its looping on every single frame and i think thats why the rest of the cards is offet :confused:

There will not be an offset if you move each dragged card by the delta x,y of the first cards movement.  If card 1 moves 10,10 and you move each card also by 10,10 then they will always stay in the same position relative to each other.

You do not need a drag group.  Cards only leave the group (card stack) they were in when you insert them into their new group.

I do a similar thing in my game with dragged objects where my UI stays locked to the dragged object even thought the elements (being dragged) are all in different layers. 

@adrianm

thanks! it worked!!!

As i said, i tried this befor but i made a mistake and now i did it right so everything works fine!

And in my opinion its the best solution, because i dont need to make a seperate display group and insert all the object multiple times :slight_smile:

Thank you so much! I was about to give up this project / game but you showed me that there is a easy solution for this :wink:

Okay i think im close to solve this.

I have now a display group “dragGrp” and im adding a event listener:

dragGrp:addEventListener("touch", dragGrp)

My cards have a touch listener that calls the buildGrp fuction, a function where i fill the dragGrp, like you can see here:

dragGrp = display.newGroup() function buildGrp( event ) local target = event.target local phase = event.phase if ( phase == "began" ) then if (target.pos == disGrp.numChildren) then dragGrp:insert(target) end end end

In this case i just want catch the last card of the stack of cards for testing.

The function “dragGrp:touch(event)” is the same as the dragCard function from my previous post but without my own code.

Now the problem:

With this code, i need to click two time to start the dragging, the first click calls the buildGrp function and fills the group and the secound click calls the dragGrp:touch function and draggs the card.

Is there a way to trigger / simulate the dragGroup touch in my BuildGrp function? 

Or is it possible to combine the two functions so that i just need one fuction?

And if you have a idea for a other, better, solution, please let me know :slight_smile:

Can really no one help me how to drag multiple cards like in solitare?

Not even an idea?

@a.jaks,

Hi.  I read this when you first posted it and I want to help, but there are a few reasons I did not:

  1. You asked a question, but then said you wanted to implemented it with your own tap listener. i.e. It is kind of like saying, “Help me solve this, but solve it the way I think it should be solved.”  You probably didn’t mean this, but still that is what I got out of it.

  2. I’m actually a little unclear on the behavior you’re trying to achieve (see my questions below).

  3. At the end of the day, I pretty much solve all problems with SSK2 because I’m just so darn lazy and hate re-writing code when I can avoid it.  That said, I do want to help.  So let me ask some questions and we’ll see what can be done.

Questions:

  1. Do you want to allow multiple cards to be dragged at the same time or just one at a time?
  2. When you ‘drop’ the card, should we just leave the card there, or should we detect if it was dropped over a ‘hot spot’/‘target’ and do something special.
  3. If we do something special, should we trigger an event, and/or move the card to better align with the hot-spot (i.e. snap to).
  4. If we don’t let the card just lie there after a drop and if we do have hot-spots.  What does the card do if we miss a spot?  Does it fly back to the original position?
  5. Can we drop more than one card consecutively on the same hot spot?
  6. If we use hot spots, do they have a ‘zone of attraction’ where a drop that is close-enough is considered a hit?

Oh, and be aware.  I have a huge collection of examples and answes  to various questions over the years:

@roaminggamer

thank you a lot that you want to help me.

I’m really sorry if my question is unclear, my english is not the best and i’m pretty new in corona SDK so its hard for me to ask in the right way :confused:
I also dont know SSK2 and how it could help me with my game :slight_smile:

Let me answer your questions:

  • Do you want to allow multiple cards to be dragged at the same time or just one at a time?

Yes, it should be like in a normal solitare game. When i drag the last card of a stack, only one card is dragged but when i drag the first card of a stack of 6 cards, all 6 cards should be dragged at the same time.

  • When you ‘drop’ the card, should we just leave the card there, or should we detect if it was dropped over a ‘hot spot’/‘target’ and do something special.

The collision with a hot spot should be detected and in this case, the card / cards should be inserted into the hot spot. I have a collision detection code from the internet, it works pretty good and in case of a collision, i insert the card in the hot spots display group. 

  • If we do something special, should we trigger an event, and/or move the card to better align with the hot-spot (i.e. snap to).

Sorry but i dont understand this question :confused:

Do you mean if the card should be moved over the hot spot? If yes, then the answer is yes.

  • If we don’t let the card just lie there after a drop and if we do have hot-spots.  What does the card do if we miss a spot?  Does it fly back to the original position?

Yeah thats right. It should move back to the previous position.

  • Can we drop more than one card consecutively on the same hot spot?

Yes.

  • If we use hot spots, do they have a ‘zone of attraction’ where a drop that is close-enough is considered a hit?

That is not needed, the size of the hot spot should be enought.

 

 

So i answered your questions but let me say that the most things of your questions already work with my code.

I have a collision detection, a move back function, and the cards will move to the hot spot when there is a collision. But all just works when i drag and drop single cards (no display groups) but i need to move multiple cards. Thats my problem, i dont know the best solution for a multi-cards drag and drop. I tryed to put all cards that should be moved into a seperate display group and move the whole display group but this dont work well, the dragged group is not on my mouse cursor and all other things also dont work the :confused:

 

Someone wrote that in a solitare game in corona sdk all cards should be display groups but does this make sense?
In my code all cards are images and the only display groups i have, are the spots where the cards are been dropped and the stack of cards.

 

As i said, im pretty new and if you know a better way the things should be done, please let me know :slight_smile:

Thank you :slight_smile: