How do I make an inventory with lots of "slots"?

@t0neg0d

Ok, I have finally started trying to make my inventory.

I am just using 1 DragElement and two DropElements (that is: an Element with setIsDragDropDropElement(true)). The DragElement is never detatched from the screen, to which it is a child. I use one Element as a container for the two DropElements, like you did. So:

Screen
– Element (container)
---- Two DropElements
– DragElement

A few questions/problems:

  1. The first time I drop my DragElement on a DropElement, the DragElement is not centered, but this happens:

    The DragElement (the fireball) snaps to the bottom of the DropElement, but not even vertically centered on the bottom. Also, the horizontal position depends on where I dropped it—the x-position do not change when it snaps.

  2. I can’t drop the DragElement on the DropElement that it was already dropped at. It does not snap the second time. But I want it to. But, maybe I can deal with that… hm.

  3. The second time I drop it (on the other DropElement, the one I did not drop it on the first time (but same thing happens regardless of which one I drop on first)), the DragElement disappears from view completely. This does not happen if I drop it anywhere else on the screen.

  4. What does setlockToParentBounds(false); do? I didn’t notice any difference when using it and not (in onDragEnd).

  5. Why is setlockToParentBounds(false); spelled with a small L in “lock”? :stuck_out_tongue:

  6. What is the Window for that you create last in layoutGUI?

@tuffe said: @t0neg0d

Ok, I have finally started trying to make my inventory.

I am just using 1 DragElement and two DropElements (that is: an Element with setIsDragDropDropElement(true)). The DragElement is never detatched from the screen, to which it is a child. I use one Element as a container for the two DropElements, like you did. So:

Screen
– Element (container)
---- Two DropElements
– DragElement

A few questions/problems:

  1. The first time I drop my DragElement on a DropElement, the DragElement is not centered, but this happens:

    The DragElement (the fireball) snaps to the bottom of the DropElement, but not even vertically centered on the bottom. Also, the horizontal position depends on where I dropped it—the x-position do not change when it snaps.

  2. I can’t drop the DragElement on the DropElement that it was already dropped at. It does not snap the second time. But I want it to. But, maybe I can deal with that… hm.

  3. The second time I drop it (on the other DropElement, the one I did not drop it on the first time (but same thing happens regardless of which one I drop on first)), the DragElement disappears from view completely. This does not happen if I drop it anywhere else on the screen.

  4. What does setlockToParentBounds(false); do? I didn’t notice any difference when using it and not (in onDragEnd).

  5. Why is setlockToParentBounds(false); spelled with a small L in “lock”? :stuck_out_tongue:

  6. What is the Window for that you create last in layoutGUI?

Just a quick response to let you know I saw this and will go over it in about 30 minutes and see what I can do to help!

Actually, I can answer a few of these now:

  1. setlockToParentBounds stops you from being able to drag (or move) an element outside of the bounds of it’s parent element (or the screen dimensions if that is the parent). Best way to understand this is: Create a window. Sedt the window to window.setlockToParentBounds(true); Add the window to the screen. Try and drag the window off the screen.

  2. Because I typed it wrong when I wrote it, released it this way and wasn’t willing to change it because it effects other peoples code :wink: Not a great reason, but the reason none-the-less

I’ll answer the others in just a bit… need time to be able to repo them to answer properly (aside from the last question, which I’ll have to go look at the code to answer).

Actually… for 5:

I’ll @Deprecated the current method and add the proper method as an alternative. I’ll likely never remove the current one, but it will at least stop any confusion.

Ok, this is done.

  1. Are you flagging the DragElement as de.setUseLockToDropElementCenter(true); ?

  2. When you say you can’t do this, do you mean that the event isn’t being triggered a second time when you pick up the DragElement and re-drop it on the current drop zone? Or, that it is not returning to the current drop zone when you release it someplace else? or?

  3. Can you verify that your cursor is over the drop element? Currently, it checks against the cursor location not the drag element itself. This is what I would consider wrong… but it is the way it currently works. I’ll try and get this updated to eval the drag element bounds against the drop element bounds soon(ish)

@t0neg0d

Oh, sorry, forgot setUseLockToDropElementCenter(true). Ok, with that, everything works as expected. But, without it, it seems a bit buggy (3 issues which are kind of the same as my original 1, 2, 3).

  1. The first time I drop the DropElement, it snaps (moves a bit), but not to the center. Why does it snap at all?
  2. The second time I drop in on the same element, onDragEnd is executed, but it does not snap, so it seemed like it didn’t react. This is kind of expected I guess, but then it shouldn’t snap the first time. It has nothing to do with returning (the setUseSpringBack(true) kind).
  3. If I drop it on the other (after having dropped it on the first) (but which one is first does not matter), it disappears when I expected it to snap. Maybe it moves out of view, because as I said, with setUseLockToDropElementCenter(true) it works.

Thank you!

@t0neg0d

Hi!

If I have a DragElement on top of a DropElement, is there any way to make a mouse click register on both, i.e. make it so that both elements’ onMouseLeftReleased are called?

What if I don’t want to have to hold down the mouse button to drag a DragElement. How would I make it follow the mouse cursor with just one click? I tried to figure it out but couldn’t. :stuck_out_tongue: I mean, I could just call onDragEnd/onDragStart on onMouseLeftPressed, or whatever, but I also want the icon to follow the mouse cursor, and that’s what I can’t figure out.

@tuffe said: @t0neg0d

Hi!

If I have a DragElement on top of a DropElement, is there any way to make a mouse click register on both, i.e. make it so that both elements’ onMouseLeftReleased are called?

What if I don’t want to have to hold down the mouse button to drag a DragElement. How would I make it follow the mouse cursor with just one click? I tried to figure it out but couldn’t. :stuck_out_tongue: I mean, I could just call onDragEnd/onDragStart on onMouseLeftPressed, or whatever, but I also want the icon to follow the mouse cursor, and that’s what I can’t figure out.

For question 1: I would forward the event from the drag element to the element that you are dropping on, by calling whatever method you want notified when the event happens.

For question 2: There sure is, I did this in the game I was working on… however I didn’t use drag elements at all. I set up a contain system that contained slots. The cursor also became a container that had a single slot. When I clicked on a movable item, it was removed from the scene (or inventory container) and added to the cursor container. If I clicked on another containers slot, it checked the cursor container for a viable object and removed it from the cursor container and added it to the container’s slot I was clicking on. This also had the benefit of allows for a “Loot All” type system that auto filled available container slots, etc, etc.

EDIT: A bit more info on this:

The base inventory slots where a single container with 8 slots.
This container was flagged as being able to contain other containers.
The bags were the other containers and contained however many slots they were created with.
These bags could be flagged as containers that could contain other containers, etc, etc.
There was a size system to limit what could be contained, etc.

Anyways, there are so many different ways of tackling this type of thing… and in personal experience the GUI library worked very well for this type of system.

@tuffe said: @t0neg0d

Oh, sorry, forgot setUseLockToDropElementCenter(true). Ok, with that, everything works as expected. But, without it, it seems a bit buggy (3 issues which are kind of the same as my original 1, 2, 3).

  1. The first time I drop the DropElement, it snaps (moves a bit), but not to the center. Why does it snap at all?
  2. The second time I drop in on the same element, onDragEnd is executed, but it does not snap, so it seemed like it didn’t react. This is kind of expected I guess, but then it shouldn’t snap the first time. It has nothing to do with returning (the setUseSpringBack(true) kind).
  3. If I drop it on the other (after having dropped it on the first) (but which one is first does not matter), it disappears when I expected it to snap. Maybe it moves out of view, because as I said, with setUseLockToDropElementCenter(true) it works.

Thank you!

On a side note, I’;m still setting up a test case for this (and one other report that has been out there for a bit) Hopefully will have some info on this today or tomorrow.

@t0neg0d said: For question 2: There sure is, I did this in the game I was working on... however I didn't use drag elements at all. I set up a contain system that contained slots. The cursor also became a container that had a single slot. When I clicked on a movable item, it was removed from the scene (or inventory container) and added to the cursor container. If I clicked on another containers slot, it checked the cursor container for a viable object and removed it from the cursor container and added it to the container's slot I was clicking on. This also had the benefit of allows for a "Loot All" type system that auto filled available container slots, etc, etc.

Ok. But how did you make the single container slot follow the mouse around? Did you just move it manually whenever there was a onMouseMove event?

And how can I make a DragElement follow the mouse, in exactly the same way it does when I hold the mouse? It doesn’t seem like Element or DragElement implement mouseMovementListener. Is there a method, like onDragStart or something that I can call manually to make the DragElement follow the mouse? I looked around but saw no code that seemed to do it. :stuck_out_tongue: Because this is really all I need. Your system seems to be overkill for me. :wink:

@tuffe said: Ok. But how did you make the single container slot follow the mouse around? Did you just move it manually whenever there was a onMouseMove event?

And how can I make a DragElement follow the mouse, in exactly the same way it does when I hold the mouse? It doesn’t seem like Element or DragElement implement mouseMovementListener. Is there a method, like onDragStart or something that I can call manually to make the DragElement follow the mouse? I looked around but saw no code that seemed to do it. :stuck_out_tongue: Because this is really all I need. Your system seems to be overkill for me. :wink:

I believe I did this… well… instead of believing I did it… let me check. One second.

Interesting. I choose a ButtonAdapter for the display and used setInterval() on the button. I overrided update in the Button (when you call setInterval, the Button becomes a JME Control and update is called at the set rate) and in the update loop I call:

[java]
setPosition(screen.getMouseXY().x+25,screen.getMouseXY().y-50);
[/java]

Soooo… the entire button looks like this:

[java]
cursorSlot = new ButtonAdapter(screen, “cursorSlot”,
Vector2f.ZERO,
new Vector2f(40,40),
Vector4f.ZERO,
null
) {
@Override
public void update(float tpf) {
setPosition(screen.getMouseXY().x+25,screen.getMouseXY().y-50);
}
};
cursorSlot.setFontSize(16);
cursorSlot.setIsEnabled(false);
cursorSlot.setInterval(1);
cursorSlot.setIsGlobalModal(true);

screen.addElement(cursorSlot);
cursorSlot.move(0,0,20);

[/java]

Looks as is I used ButtonAdapter for all slot display, setting the default image to null. I am likely calling setButtonIcon to display the item icons for the container slots.

EDIT: Yep, In the case of normal container slots, I set the button image to whatever the container slots are supposed to look like and then use the button icon to show the the item.

@t0neg0d But how does DragElement follow the mouse? :stuck_out_tongue: And can I make it follow the mouse in exactly the same way without holding the mouse? Then I’d call onDragEnd when a slot is clicked, and it would work exactly the same way as dragging with the mouse button down. No? :stuck_out_tongue: That is what I want.

Just to be clear: I want dragging to work as it does now. But I also want to be able to just click once on the DragElement to pick it up (follow the mouse) and click again on a slot to activate onDragEnd, and have it snap, and all that. Is that possible?

@tuffe said: @t0neg0d But how does DragElement follow the mouse? :P And can I make it follow the mouse in exactly the same way without holding the mouse? Then I'd call onDragEnd when a slot is clicked, and it would work exactly the same way as dragging with the mouse button down. No? :P That is what I want.

Just to be clear: I want dragging to work as it does now. But I also want to be able to just click once on the DragElement to pick it up (follow the mouse) and click again on a slot to activate onDragEnd, and have it snap, and all that. Is that possible?

I’m fairly sure you can do this. Just forward the mouse up event to the onDragEnd method when you click on the drop element. The real issue is knowing when you are clicking to drag and when you are clicking/releasing to pick up.

@t0neg0d Ok but what do I call on the first click, to make the DragElement follow the mouse until the next click?

@t0neg0d said: I'm fairly sure you can do this. Just forward the mouse up event to the onDragEnd method when you click on the drop element. The real issue is knowing when you are clicking to drag and when you are clicking/releasing to pick up.

It looks like one can not, at least not without some trouble. You see, all the code for putting a DragElement into a DropElement (changing position and parent of the DragElement) is in the method onMouseLeftReleased. It would be great if you could factor out that code and put it in another method so that one can with ease programatically put a DragElement in a DropElement.

Something like this: :slight_smile:

[java] //New method!
public void putIntoDropElement(Element dropEl) {
if (parentDroppable != null)
parentDroppable.removeChild(this);

    parentDroppable = dropEl;
    Vector2f pos = new Vector2f(getAbsoluteX(), getAbsoluteY());
    Element parent = getElementParent();
    if (parent != dropEl) {
        if (parent != null) {
            parent.removeChild(this);
        } else {
            screen.removeElement(this);
        }
        float nextY = (pos.y-dropEl.getAbsoluteY());
        nextY = -nextY;
        setPosition(pos.x-dropEl.getAbsoluteX(), nextY);
        dropEl.addChild(this);
        this.setZOrder(screen.getZOrderStepMinor());
    }
    if (lockToDropElementCenter) {
        Vector2f destination = new Vector2f(
                (dropEl.getWidth()/2)-(getWidth()/2),
                (dropEl.getHeight()/2)-(getHeight()/2));
        if (useLockToDropElementEffect) {
            slideTo = new Effect(Effect.EffectType.SlideTo, Effect.EffectEvent.Release, .15f);
            slideTo.setElement(this);
            slideTo.setEffectDestination(destination);
            screen.getEffectManager().applyEffect(slideTo);
        } else {
            setPosition(destination);
        }
        originalPosition = destination.clone();
    }
}

@Override
public void onMouseLeftReleased(MouseButtonEvent evt) {
	Element dropEl = screen.getDropElement();
	int index = -1;
	
	boolean success = onDragEnd(evt, dropEl);
	
	if (success) {
        putIntoDropElement(dropEl);
	} else {
		if (useSpringBack) {
			Vector2f destination = originalPosition.clone();
			if (useSpringBackEffect) {
				slideTo = new Effect(Effect.EffectType.SlideTo, Effect.EffectEvent.Release, .15f);
				slideTo.setElement(this);
				slideTo.setEffectDestination(destination);
				screen.getEffectManager().applyEffect(slideTo);
			} else {
				setPosition(destination);
			}
		}
	}
}[/java]

I removed some unnecessary code in the first if of putIntoDropElement, otherwise it’s the old code, just taken out of onMouseLeftReleased. I certainly don’t wanna sound whiny, because tonegodgui is great and hugely helpful to me, but: You might wanna try to factor out functionality like this more often. Maybe into even smaller methods than this. Many methods in tonegodgui is very long and hard to read, especially the ones with a lot of if statements, like for example Element’s resize method. In that very method, all the cases even look very similar.

And please don’t forget my question above this. :wink:

Cheers!

Not that I disagree with your method of doing this, but there is already a method for programatically adding a drag element to a drop element:

[java]
DragElement.bindToDroppable(someDropElement);
[/java]

As for your first question, I seriously would not go about what you are trying to do using drag element. I would extend button adapter and add the drag functionality after the fact.

@t0neg0d said: Not that I disagree with your method of doing this, but there is already a method for programatically adding a drag element to a drop element:

[java]
DragElement.bindToDroppable(someDropElement);
[/java]

Oh! I'm to tired right now to try to figure out why the code is so different from the code I extracted and put into my method. I thought there wasn't one, since it was not being used in onMouseLeftReleased.
@t0neg0d said: As for your first question, I seriously would not go about what you are trying to do using drag element. I would extend button adapter and add the drag functionality after the fact.
Hm, why is that? It seems to me that if I could only figure out how to get the DragElement to follow the mouse, all my problems would be solved. Is there a method I can call to make the DragElement stick to the mouse? If nothing else, by this point I'm pretty darn curious about how it is done (when one drags and drops normally), because I can't find the code. Where is the code that makes it stick to the mouse?! :P

@t0neg0d

If I understand it correctly, bindToDroppable simulates a mouse click, so that the onMouseLeftReleased function will execute. That seems a bit backwards, and has an unfortunate side effect for me; it triggers onDragEnd, which is not what I want when I set up my HUD. I would prefer if my putIntoDropElement existed instead. And if one would want onDragEnd to trigger, one could just call both putIntoDropElement and onDragEnd. Just my thoughts. :wink:

By the way, it would be awesome if you used git instead of svn, just like JME. :wink: But I understand if you don’t wanna change. :stuck_out_tongue:

The reason I say it would be easier to start with the base Element or some other control is setIsMovable(true) is a method of Element, meaning that any control can be draggable by flagging it as such.

Your other option would be to extend DragElement and override the methods to function as you have it above.

Personally, I would not use DragElement as a basis for my inventory because of the ease of making a control movable via the mouse. The click to pick up, click again to release is a bit harder to accomplish and I would want to have this functioning properly before adding in the ability to drag an Element around.

Gimme a couple to reread the 2 posts above to make sure that I answer any specific questions!

@tuffe said: By the way, it would be awesome if you used git instead of svn, just like JME. ;) But I understand if you don't wanna change. :P

I’m just curious because I see this come up a lot… but what is it that you think you’d get that you aren’t getting now? Just wondering if you know that you can already check out an SVN repository with GIT and get many of the GIT-related “benefits”.

1 Like

Ugh… just lost my reply. Let me try this again:

To set the position of the drag element in this way will require it to be done through an update loop. So, you have 2 (or more) options:

  1. Use an AppState to manage your inventory. Add a variable of type Element that you can update if it is not currently null. When the user clicks on a draggable, set this variable to the current drag element. In the update loop of the AppState, add code to set the position of the element if it is not null.

  2. extend DragElement and implement Control. In the update loop of the Control add the code for updating the position. If the user clicks on the drag element, add the element as a control to the scene (i.e. screen.getApplication().getGuiNode().addControl(this)). When the user clicks on a drop element, check to see if the Control exists… if it does, remove it from the scene. (This is similiar to the way Button adds itself as a Control IF setInterval() is called).

I’m sure there are other ways of accomplishing this aside from these two options. However, the position needs to be set via some form of update method that is called per frame.