Drag-and-Drop item interaction

Here is the little big project I’ve been working on recently.

overworld1.blend (957 KB)
(Note: if no text shows up when you click on things, try playing in Standalone, or re-starting Blender grumble grumble)

It’s an isometric top-down adventure/RPG sort of deal. So far I have the basic movement system down (hold or click RMB to move) and some basic world item interaction (LMB on an object to get its description blurb).

What I want to do is emulate the drag-and-drop nature of item interaction seen in the older Ultima games; where one would grab nearby objects with their mouse and drag them into their inventory to pick them up, or drag them from the inventory back into the world to drop them. The process is not unlike moving icons around your desktop and dragging them into folders.

The brown square in the corner of the GUI represents the player’s backpack. Items (the cyan box in the middle of the house is an ‘item’) should be able to be dragged into there from the world, given the player is within grabbing range of the object. I don’t want to set up a grid or cell system to store the item objects in; I want the items to land just where they are on the backpack plane when the button is let go of and the dragging action is done. In the future, this method will also be used to equip/remove items from your body, using a paperdoll.
While the item is being dragged, it should follow (or even replace!) the mouse cursor. I have seen some tutorials and other threads about setting up an in-game mouse cursor, so I will probably start by digging into those.

Does anybody have any ideas how I could go about doing this? I don’t really know where I would start…

yeah,

a. make a mesh for each item that is the inventory version(sprite sheet?)
b. replace mesh on the cursor object
c.set a property in the cursor system that is the game object

clicking again does
if ‘property’ in own[‘gameObject’]:
behavior.

so the placment is contextual

I actually have a demo in resources, that I can’t find :smiley:

I can make a example if you need it, you want to use a mouse over any or a ray or?

another hand thing… quick use containers that you can drop the item in if the contain a property you name, then hitting key 1 uses quick item etc.

I believe this was a case of me drastically over-thinking what I was trying to accomplish.

I can take advantage of the fact that orthographic projection has no depth perception as it were, so an object’s apparent size is uniform no matter its distance from the camera. Upon realizing this, everything else just sort of fell into place :smiley:

An attribute self.activeThing keeps track of the object currently being grabbed/dragged. A mouse-over sensor is kept as self.screenSpace, and senses an invisible plane placed in front of the camera.

In the player’s class’ main-loop is this:

if self.activeThing:
self.grab()

which calls:

def grab(self):
self.activeThing.worldPosition = self.screenSpace.hitPosition

The main-loop also calls self.interact() which now looks like this:


    def interact(self):
        if self.mOT.positive:
            item = self.mOT.hitObject
            if self.Lc.positive and not self.activeThing:
                self.getSpeech(item['Desc'])
                if self.own.getDistanceTo(self.marker) <= 4 or item in self.inventory:
                    self.activeThing = item
                    self.placer.worldPosition = self.activeThing.worldPosition

        if self.LcO.positive and self.activeThing:
            if self.packSpace.positive:
                self.activeThing.worldPosition = self.packSpace.hitPosition
                self.activeThing.localPosition.z += 0.5
                self.activeThing.setParent(self.pack)
                self.activeThing = None

            elif self.own.getDistanceTo(self.marker) <= 4:
                self.activeThing.worldPosition = self.marker.worldPosition
                if self.activeThing in self.inventory:
                    self.activeThing.removeParent()
                self.activeThing = None
            else:
                self.activeThing.worldPosition = self.placer.worldPosition
                self.activeThing = None

mOT is another mouse-over sensor which just detects objects with the ‘thing’ property (which contains their python class for handling Things). A placer is set to the worldposition of any item that has begun to become interacted with – if you try to drag the item to an invalid location, it snaps back to this placer.
packSpace works just like screenSpace, but detects the backpack object. Items dropped over this will become children of that object. The player’s inventory is kept as a list which is the children of the backpack object.

When you let go of LMB, it checks to see if you are packSpace.positive: if so then it’s placed on packSpace.hitPosition and parented to the pack.
Or it checks to see if you’re mousing over the ground, and the distance from your ground marker is within range. If so, it sets the thing to your marker worldPosition.
If you don’t drop it in a valid location, it will return to the spot you initially picked it up from (self.placer.worldPosition)

The object you see on the ground is the same object you see follow the cursor, is the same object you see sitting in your backpack.
How cool is that?

[EDIT] Oops. I forgot that the ‘mOT’ sensor detects the property ‘Desc’, so every object (trees, rocks, walls, the player!) can be picked up and dragged around! Another condition in the if statement to determine activeThing fixed that quick.

Attachments

overworld1_1.blend (971 KB)