Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: rongel on Mon 25/08/2014 16:31:09

Title: Drag and drop puzzle help
Post by: rongel on Mon 25/08/2014 16:31:09
Hi!

I'm trying to do simple drag & drop puzzle. I have a room (without characters), and some objects that you are supposed to drag to right places. Currently i'm using following script:

Code (ags) Select

function oMyItem_Interact(){
  while(mouse.IsButtonDown(eMouseLeft)){
    oMyItem.X = mouse.x;
    oMyItem.Y = mouse.y;
    Wait(1);


That works for dragging the item around (even though my item "jumps" a bit annoyingly every time it's clicked). But how can I drop the item in the right place so that new command is activated? For example if my puzzle had a draggable key and I would drop it over a lock, what is the best way to make it work? I have read the forums, but haven't found an answer (many of the old links are not working anymore...)

Anyway, all help is welcome, thanks in advance!
Title: Re: Drag and drop puzzle help
Post by: Crimson Wizard on Mon 25/08/2014 16:43:34
You do that in a non-optimal way: you are locking the dragging process inside one function, thus blocking the rest of the game.
Instead, I suggest to perform processing in "repeatedly_execute":
Code (ags) Select

bool WasDragging;
int OldMyItemX;
int OldMyItemY;

function room_RepExec()
{
    if (mouse.IsButtonDown(eMouseLeft)) {
        // have we pressed a button over our object?
        if (!WasDragging && Object.GetAtScreenXY(mouse.x, mouse.y) == oMyItem) {
            // just started draggin? remember where you took it
            OldMyItemX = oMyItem.X;
            OldMyItemY = oMyItem.Y;
            WasDragging = true;
        }
        else if (WasDragging) {
            // mouse button still pressed? continue dragging
            oMyItem.X = mouse.x;
            oMyItem.Y = mouse.y;
        }
    } else if (WasDragging) {
        // was dragging but mouse button now released? drop it
        WasDragging = false;
        // ... you drop code here ...
        // for example:
        if (oMyItem.IsCollidingWithObject(oLock))
            UnlockTheLock(); // success!
        else {
            // failure (return the item on previous place?)
            oMyItem.X = OldMyItemX;
            oMyItem.Y = OldMyItemY;
        }
    }
}



To solve the "jumping" problem, remember the offset between mouse coordinates and object's coordinates at the moment you take it:
Code (ags) Select

int DragOffsetX; <-------------------------
int DragOffsetY; <-------------------------

<...>
    if (mouse.IsButtonDown(eMouseLeft)) {
        // have we pressed a button over our object?
        if (!WasDragging && Object.GetAtScreenXY(mouse.x, mouse.y) == oMyItem) {
            // just started draggin? remember where you took it
            OldMyItemX = oMyItem.X;
            OldMyItemY = oMyItem.Y;
            DragOffsetX = mouse.x - oMyItem.X; <-------------------------
            DragOffsetY = mouse.y - oMyItem.Y; <-------------------------
            WasDragging = true;
        }
        else if (WasDragging) {
            // mouse button still pressed? continue dragging
            oMyItem.X = mouse.x - DragOffsetX; <-------------------------
            oMyItem.Y = mouse.y - DragOffsetY; <-------------------------
        }
    }


EDIT: duh! fixed silly mistake.
EDIT2: fixed typos.
Title: Re: Drag and drop puzzle help
Post by: rongel on Mon 25/08/2014 18:25:00
Thanks for the super-quick answer!

That is quite heavy stuff... I did try your example, but my object didn't move anywhere, but at least no script errors!

Is the onMyItem a new item, what is it's difference with oMyItem? And is UnlockTheLock(); just a place for any command, for example: Display("Succes!");

Anyway, thanks for the info, I'll keep trying!


Title: Re: Drag and drop puzzle help
Post by: Crimson Wizard on Mon 25/08/2014 18:32:25
Quote from: rongel on Mon 25/08/2014 18:25:00
Is the onMyItem a new item, what is it's difference with oMyItem?
That's a typo!

Quote from: rongel on Mon 25/08/2014 18:25:00
And is UnlockTheLock(); just a place for any command, for example: Display("Succes!");
Yes, it's an example of calling your custom function. Just put your own code there.

Sorry, I did not really test the code, just typed it by memory. I am going to check it out myself now :).

Another mistake: in rooms you usually use "function room_RepExec()". Create one by going to Room's events and create the handler for "Repeatedly execute" (like you did for Object's interact event).
Then paste function contents there.
Title: Re: Drag and drop puzzle help
Post by: rongel on Mon 25/08/2014 19:42:57
Ok, finally fot it working!

Well mostly, for some reason nothing happens when I drag my "key" to my "lock", the key just jumps back to it's starting location. Hmm?

EDIT:

Does (oMyItem.X == oLock.X && oMyItem.Y == oLock.Y) mean that they have to be exactly on the same position? My lock object is large, but does that mean I need to find the exact pixel?
Title: Re: Drag and drop puzzle help
Post by: Crimson Wizard on Mon 25/08/2014 20:29:56
Quote from: rongel on Mon 25/08/2014 19:42:57
Does (oMyItem.X == oLock.X && oMyItem.Y == oLock.Y) mean that they have to be exactly on the same position? My lock object is large, but does that mean I need to find the exact pixel?
Yes,... that was a bad example.
Of course, in normal situation you would need to compare to rectangle bounds, or do a pixel-perfect detection.
Code (ags) Select

if (oMyItem.IsCollidingWithObject(oLock))
Title: Re: Drag and drop puzzle help
Post by: rongel on Mon 25/08/2014 20:57:11
Got it working, thanks! :-D

Maybe it needs a bit fine tuning, but overall it's great, I hope this helps others as well!
Title: Re: Drag and drop puzzle help
Post by: Tremulas on Sat 26/03/2016 20:47:48
Can we apply isCollidingWithObject on inventory items ?
Title: Re: Drag and drop puzzle help
Post by: Crimson Wizard on Sat 26/03/2016 21:08:19
Quote from: Tremulas on Sat 26/03/2016 20:47:48
Can we apply isCollidingWithObject on inventory items ?

No. InventoryItem cannot really collide with anything, nor be placed anywhere in the room. It exists in "separate dimension" (so to say), not related to characters and objects.
Title: Re: Drag and drop puzzle help
Post by: Kumpel on Sat 26/03/2016 21:12:32
To actually place items somewhere in a room you have to combine them with objects representing that item. And these objects are of course appliable with isCollidingWithObject.

Or am I misunderstanding your question?
Title: Re: Drag and drop puzzle help
Post by: Tremulas on Sun 27/03/2016 10:33:17
Actually I was wondering if I could use IsCollidingWithObject and the whole Drag and Drop System in my Inventory ,to combine inventory items .
Title: Re: Drag and drop puzzle help
Post by: Crimson Wizard on Sun 27/03/2016 15:19:00
Quote from: Tremulas on Sun 27/03/2016 10:33:17
Actually I was wondering if I could use IsCollidingWithObject and the whole Drag and Drop System in my Inventory ,to combine inventory items .
No, InventoryItems cannot be moved, dragged etc. They simply do not have coordinates as such. Conceptually they are part of linear list.
The inventory window is displaying them arranged in grid using its own logic, but items themselves do not posess such property as "position on screen".

You might need to script something that represents inventory item (similar to how room object may represent an item lying in the room).
For example, you could create graphical Overlay to drag item image around; but you will have to test whether this overlay is above another item yourself, calculating item position in window using InventoryWindow properties, such as its coordinates, ItemWidth and ItemHeight values.

Unfortunately I do not have much free time right now, but I may post some experimental example of script later, unless someone else will before.
Title: Re: Drag and drop puzzle help
Post by: Tremulas on Sun 27/03/2016 15:26:00
Ok , thank you so much for the information. I'll be looking forward for your example script in case I wont find a solution !

Thanks again !
Title: Re: Drag and drop puzzle help
Post by: Crimson Wizard on Mon 28/03/2016 20:56:47
Hmmmmm... I forgot that overlays are always drawn behind GUI.
Perhaps using cursor graphic is the only way to visually depict dragging inventory item (same as when you select ActiveInventory).
Title: Re: Drag and drop puzzle help
Post by: Amir on Sun 29/05/2022 01:04:30
Hi,
I'm trying to do the same but for all objects in room 22. In global script because I have a button in the room, if all objects are on the right place and the player push the button, then bingo. I use isCollidingWithObject for that as well. But the code doesn't work. What am I doing wrong? Could someone fix the code please?

Code (ags) Select

bool WasDragging;
int OldMyItemX;
int OldMyItemY;
function repeatedly_execute()
{
if ((mouse.IsButtonDown(eMouseLeft)) && (cBerny.Room == 22))
  {
    Object *obj = Object.GetAtScreenXY(mouse.x, mouse.y);
        // have we pressed a button over our object?
        if ((obj != null) && (!WasDragging))
       
        {
            // just started draggin? remember where you took it
            OldMyItemX = obj.X;
            OldMyItemY = obj.Y;
            WasDragging = true;
           
        }
       
        else if (WasDragging)
        {
            // mouse button still pressed? continue dragging
            OldMyItemX = mouse.x;
            OldMyItemY = mouse.y;

        }   
       
    }
   
    else if (WasDragging) 
    {
    // was dragging but mouse button now released? drop it
    WasDragging = false;
    } 
}


And for the button

Code (ags) Select

function bBuecher_OnClick(GUIControl *control, MouseButton button)
{
if (object[2].IsCollidingWithObject(object[9]))  && (object[3].IsCollidingWithObject(object[10])) && (object[4].IsCollidingWithObject(object[11]))

Player.Say("Bingo");

}
Title: Re: Drag and drop puzzle help
Post by: Crimson Wizard on Sun 29/05/2022 01:44:35
Quote from: Amir on Sun 29/05/2022 01:04:30But the code doesn't work.
I think you pasted the code incorrectly, this part seem wrong:
Code (ags) Select

            // mouse button still pressed? continue dragging
            OldMyItemX = mouse.x;
            OldMyItemY = mouse.y;

should be
Code (ags) Select

            // mouse button still pressed? continue dragging
            obj.X = mouse.x;
            obj.Y = mouse.y;


For the correct results you should also remember the dragged object in a variable when the dragging starts, and use that here instead of local "obj" instead, because if player moves mouse too fast, the cursor will appear no over the dragged object and local "obj" will be null.

By the way, this code assumes non-scrolling room, where screen coordinates match room coordinates.


On a side note, have you tried the Drag & Drop module? It already has all the functionality:
https://www.adventuregamestudio.co.uk/forums/index.php?topic=53332.0
Title: Re: Drag and drop puzzle help
Post by: Amir on Sun 29/05/2022 06:04:02
Yes, with obj.X and Y I’m getting the problem null pointer referenced. All rooms of the puzzles are non-scrolling rooms.
Is there no solution to this before I try the module? I like this code. Small but nice and an abbreviation of the module.
Title: Re: Drag and drop puzzle help
Post by: Crimson Wizard on Sun 29/05/2022 12:14:59
Quote from: Amir on Sun 29/05/2022 06:04:02
Yes, with obj.X and Y I’m getting the problem null pointer referenced.
Is there no solution to this before I try the module?

Like I mentioned, for the correct results you should also remember the dragged object in a variable when the dragging starts, and use that here instead of local "obj" instead.
It should probably be like:
Code (ags) Select

bool WasDragging;
int OldMyItemX;
int OldMyItemY;
Object *DraggedObj;
function repeatedly_execute()
{
  if ((mouse.IsButtonDown(eMouseLeft)) && (cBerny.Room == 22))
  {
        Object *obj = Object.GetAtScreenXY(mouse.x, mouse.y);
        // have we pressed a button over our object?
        if ((obj != null) && (!WasDragging))
        {
            // just started draggin? remember where you took it
            OldMyItemX = obj.X;
            OldMyItemY = obj.Y;
            DraggedObj = obj;
            WasDragging = true;
        }
        else if (WasDragging)
        {
            // mouse button still pressed? continue dragging
            DraggedObj.X = mouse.x;
            DraggedObj.Y = mouse.y;
        }
    }
    else if (WasDragging) 
    {
       // was dragging but mouse button now released? drop it
       WasDragging = false;
       DraggedObj = null;
    } 
}




Actually, in this case WasDragging may perhaps be omited and DraggedObj used instead in conditions. A cleaner version of the code would look like:

Code (ags) Select

Object *DraggedObj;
int OldPosX;
int OldPosY;

function repeatedly_execute()
{
    if ((mouse.IsButtonDown(eMouseLeft)) && (cBerny.Room == 22))
    {
        // was not dragging yet?
        if (DraggedObj == null)
        {
            // have we pressed a button over some object?
            Object *obj = Object.GetAtScreenXY(mouse.x, mouse.y);
            if (obj != null)
            {
                // just started draggin? remember what and where you hooked up
                OldPosX = obj.X;
                OldPosY = obj.Y;
                DraggedObj = obj;
            }
        }
        else if (DraggedObj != null)
        {
            // mouse button still pressed? continue dragging
            DraggedObj.X = mouse.x;
            DraggedObj.Y = mouse.y;
        }
    }
    else if (DraggedObj != null) 
    {
       // was dragging but mouse button now released? drop it
       DraggedObj = null;
    } 
}
Title: Re: Drag and drop puzzle help
Post by: Amir on Sun 29/05/2022 20:25:15
Quoteyou should also remember the dragged object in a variable when the dragging starts

Sorry, I understood that differently. I could not have created this arranging on my own. Thank u very very much.

I just had to add this so that the object is centered on MY mouse cursor. (if anyone needs it)
Code (ags) Select

DraggedObj.X = mouse.x-14;
DraggedObj.Y = mouse.y+30;