6
\$\begingroup\$

I'm working on creating an inventory system for a game. The inventory system will use cells and 2D images to represent items, like Minecraft, Diablo, or WoW. I've hit a bit of a snag when trying to let the player place items in the bag (click and drag style).

So far, I've successfully created the inventory grid, which is really smoke and mirrors:

public class InventoryMenu {
boolean objectSelected = false;
Item selectedItem;

public final int COLUMNS = 5;
public final int ROWS = 7;

ArrayList<Item> inv = new ArrayList<Item>((ROWS + 1) * COLUMNS);
Sprite slot;

public void render(Graphics g) {

    for (int i = 0; i < 40; i++) {
        int col = i % COLUMNS;
        int row = ROWS - i / COLUMNS;


        slot.draw(g, (Camera.width - slot.getWidth() * COLUMNS) + slot.getWidth()* col, row * slot.getHeight());

        if (inv.get(i) != null) {
            inv.get(i).render(g);
        }
    }
    if (selectedItem != null) {
        selectedItem.render(g);
    }
}

Basically, I have an arraylist that can hold items, and it just draws the "slot" image 40 times and if there's an item in that "slot" it draws the item image too. Cool? Cool. The problem comes if I want to allow the player to select an item in their inventory and move it to a different slot. I have no problem letting them pick it up (I use a pretty primitive brute force, but with any reasonably sized inventory, it works):

private Item grabItem(Point2D mouse) {
    for (Item i : inv) {
        if (i != null) {
            if (i.getPhysicsShape().contains(mouse)) {
                Item pick = i;
                selectedItem = pick;
                objectSelected = true;
                i = null;
                return pick;
            }
        }
    }
    return null;
}

That bit of code lets a player pick up an item, but placing it fails - it rarely gets the right slot, except if its the bottom row (0-4):

setDown(){
    int slotLoc = calcSlot(InputHandler.mouseCoords);
    placeItem(slotLoc);
}

private void placeItem(int loc) {
    if(loc < 0 || loc > ROWS * (COLUMNS + 1))
        return;

    int col = loc % COLUMNS;
    int row = ROWS - loc / COLUMNS;
    selectedItem.pickUp((Camera.width - slot.getWidth() * COLUMNS) + slot.getWidth() * col, row * slot.getHeight());

    inv.set(loc, selectedItem);
    selectedItem = null;
    objectSelected = false;
}

private int calcSlot(Point2D mouse){
    int colPos = (int) (COLUMNS - (Camera.width - mouse.getX()) / slot.getWidth());
    int rowPos = (int) (ROWS+1 - (mouse.getY()) / slot.getHeight());


    if (colPos > COLUMNS || colPos < 0 || rowPos < 0 || rowPos > ROWS + 1) {
        dropItem();
        return -1;
    } else {
        return colPos + 4*rowPos;
    }

}

I'm fairly confident that the problem is in calcSlot, but I can't seem to find where. Any help would be greatly appreciated, I'm sure it's something silly.

Images!!

So, I can pick up an item with no problem, and it automatically places it in the last slot. So far, everything is gold.

Successfully placed in slot 39

I can then click that image and lift it out of the grid, and it follows my mouse (mouse is hidden by PrntScrn, but its at the top left corner of the image:

Dragging

When I try to place the item by clicking in the middle of slot 33, however, it derps and places it, inexplicably, in slot 27.

Derp

\$\endgroup\$
4
  • \$\begingroup\$ Just write the logic of moving an item from slot to slot on paper and it will become crystal clear what you should do. Think of it as moving value (item) from field A to field B using field C (temp item slot). \$\endgroup\$ Commented Mar 23, 2013 at 5:20
  • \$\begingroup\$ Thanks, but that's not my problem. Picking up the item (making it follow the mouse and then replacing it in the inventory) works just fine, its the placing it in the right slot on the grid (visual problem). \$\endgroup\$ Commented Mar 23, 2013 at 5:22
  • \$\begingroup\$ Can you describe it in more detail? Maybe you have an image that illustrates the problem? \$\endgroup\$ Commented Mar 23, 2013 at 5:24
  • \$\begingroup\$ Added pictures to the post. \$\endgroup\$ Commented Mar 23, 2013 at 5:32

3 Answers 3

3
\$\begingroup\$

I'll just give you the basic logic, not in Java, but I hope you can understand it.

Find the bottom left corner of the inventory (where the slot 0 is) and save that point in BLpoint. Then use variable dropPoint = (mouse.x - BLpoint.x ; BLpoint.y - mouse.y).

If dropPoint.x or .y is less than zero, you've missed the inventory slots.

The slot coordinates X = dropPoint.x / slotWidth, Y = dropPoint.y / slotHeight.

For items larger than 1×1 this might require some alteration. I would suggest you make your slot numbers start at top left corner of the inventory, it's going to be more simple for you to code.

nice metal dude btw

\$\endgroup\$
4
  • \$\begingroup\$ This makes a lot of sense, though I feel like it's almost exactly what I'm doing, just neater. I'm gonna play around with this, and see if it works better. Also, thanks! I like my metal dude. \$\endgroup\$ Commented Mar 23, 2013 at 5:52
  • \$\begingroup\$ Actually, this only solves half my problem. See, the inventory is an ArrayList, not a 2D array, so I can't just put the item in [x][y], I have to turn x and y into a slot ID between 0-39. I had that as x + 4*y, but that doesn't seem to be playing well. Any ideas? \$\endgroup\$ Commented Mar 23, 2013 at 5:57
  • 1
    \$\begingroup\$ Final comment! Your solution is in fact the same as what I'm doing (but it is waaay neater) - my problem was in placing the item. The formula I ended up with is slot = 5*rowPos + colPos and now it works. Thanks all the same, you made me examine my code more closely. \$\endgroup\$ Commented Mar 23, 2013 at 6:07
  • 1
    \$\begingroup\$ Sometimes (actually more often than most programmers are willing to admit) it is better to put aside existing code and think again how you would solve a problem, like in this case. \$\endgroup\$ Commented Mar 23, 2013 at 6:08
0
\$\begingroup\$
private int calcSlot(Point2D mouse){
    int colPos = (int) (COLUMNS - (Camera.width - mouse.getX()) / slot.getWidth());
    int rowPos = (int) (ROWS - ((mouse.getY())- slot.getHeight()) / slot.getHeight());


    if (colPos > COLUMNS || colPos < 0 || rowPos < 0 || rowPos > ROWS + 1) {
        dropItem();
        return -1;
    } else {
        return COLUMNS*rowPos + colPos;
    }

}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ You should add comments and some descriptive text to this answer. Answers that are just code are not very good. \$\endgroup\$
    – House
    Commented Mar 23, 2013 at 7:42
0
\$\begingroup\$

have you tried to use an array of Rectangles then use a method like this to draw for example 35 inventory slots going left to right until finished.

 public Rectangles[] invSlots;

 public int INVENTORY_CELL_SIZE_X = 50;
 public int INVENTORY_CELL_SIZE_Y = 50;
 public int AMOUNT_OF_INVENTORY_CELLS = 35;

public void createSlots() {
invSlots = new Rectangle[AMOUNT_OF_INVENTORY_CELLS];
 for(int id = 0;id < invSlots.length;id++) {
    for(int x = 0;x<INVENTORY_CELL_SIZE_X;x+=INVENTORY_CELL_SIZE_X) {
        for(int y = 0;y<INVENTORY_CELL_SIZE_Y;y+=INVENTORY_CELL_SIZE_Y) {
       //use all incremented integers above to create rectangles transform;
          invSlots[id] = 
         new Rectangle(x, y,INVENTORY_CELL_SIZE_X, INVENTORY_CELL_SIZE_Y);
        } 
    }
 }

}

You can then draw one of these cells like so;

    g.drawImage(image or rect_here,  
invSlots[incrementedInteger].x, invSlots[incrementedInteger].y, 
invSlots[incrementedInteger].width, invSlots[incrementedInteger].height);

heres how to check what cell the player's mouse is inside of.

Make sure you call it from within a loop.

public void checkForMouseEntryOrWhatever() {
    for(int id = 0;id<invSlots.length;id++) {

        //mouse start
         if(mouseX >= invSlots[id].x 
            && mouseY >= invSlots[id].y 
            && mouseX <= invSlots[id].x+invSlots[id].width
            && mouseY <= invSlots[id].y+invSlots[id].height) 
         {
                //DO WHATEVER WHEN THE PLAYER ENTERS THE INVENTORY CELL.
         }
         //Mouse end
    }
}

this method was made to be universal no matter the rectangles size.

it also has a basic id system because of the array, and is organized because of the 'left-to-right' drawing technique.

creating a Item dragging system shouldnt be very difficult after this if your using mouseDragged() method, simply make the item (that the player clicked-to-drag) follow the players mouse until released and then place that item in the slot that it was released in.

try this if statement for example.

it only works inside of a loop (for loop or while loop should do depending on engine)

 if(releasedX >= slotX && releasedY >= slotY && releasedX <= slotX + 
 slotWidth && slotY <= slotY+slotHeight) {
     drawItem(item, slotX, slotY, itemWidth, itemHeight);

 }
\$\endgroup\$
1
  • \$\begingroup\$ late reply...... \$\endgroup\$
    – Cody Orr
    Commented Dec 7, 2017 at 4:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .