RPG Inventory Pickup + Drop System. Help

I’m working on a inventory system for my RPG.
I’m halfway there but need help. Currently when I touch the item added to inventory it leaves a black square, I want it to disappear and a double tap option to drop. Also once a chest is open I want it to show a empty chest, currently it keeps showing the emerald.

displayMode(FULLSCREEN)

function setup()
    
    Chest:init()
    rectMode(CENTER)
    dir,i=1,1
    delay,xs,ys=0,0,0
    dx,dy=WIDTH/2,HEIGHT/2
    createButtons()
    
    cx,cy=0,0
    sx,sy=0,0
    dx,dy=0,0

    fill(255)
    stroke(255)
    strokeWidth(1)
    colBody:init()
end

function draw()
    background(40, 40, 50)
    checkButtons()   
    noFill()
    sprite(asset.builtin.Blocks.Glass_Frame,900,100,200,200)
    c1.x=c1.x+dx
    c1.y=c1.y+dy
    sprite(asset.builtin.Planet_Cute.Character_Princess_Girl,c1.x,c1.y)
    chest()
end

function touched(t)
    Chest:touched(t)
    if t.state==BEGAN then
        cx,cy=t.x,t.y      
    end
    if t.state==MOVING then
        if insideCircle(t.x,t.y) then
            dx=(t.x-cx)/10
            dy=(t.y-cy)/10
        else
            cx,cy=0,0
            dx,dy=0,0
        end
    end
    if t.state==ENDED then
        cc,cy=0,0
        dx,dy=0,0
    end
    if t.state==BEGAN or t.state==MOVING then
        for a,b in pairs(bTab) do
            b:touched(t)
        end
    elseif t.state==ENDED then
        xs=0
        ys=0
    end    
end
function collide(c)  -- this gets called when a collision occurs
    Chest:collide(c)
 end
function insideCircle(x,y)
    -- check if touch is inside of circle or ellipse
    a,b=100,100 -- radius of circle or a,b of ellipse
    if (x-cx)^2/a^2+(y-cy)^2/b^2 <= 1 then 
        return true
                    end
                        return false
end

Chest = class()
   inventorypos=vec2

function Chest:init()
    chestClosed=readImage("Planet Cute:Chest Closed")
    chestOpen=readImage("Planet Cute:Chest Open")

    citems={emerald =(asset.builtin.Planet_Cute.Gem_Blue),emerald2 =(asset.builtin.Planet_Cute.Gem_Blue)}
    inventorypos=vec2(950,80)
end

function chest()
    if open then
        sprite(chestOpen,c2.x,c2.y) 
        sprite(citems.emerald,c2.x,c2.y+30)
        r=true
    if ElapsedTime-et>3 then
        open=false
            end
    else
        sprite(chestClosed,c2.x,c2.y)
    end
        if r==true then
           sprite(citems.emerald2,inventorypos.x,inventorypos.y,30,30) 
        else
    end
end

function Chest:touched(t)

        if t.state==BEGAN and t.x>inventorypos.x-50 and t.x<inventorypos.x+50 and t.y>inventorypos.y-50 and t.y<inventorypos.y+50 then  
        citems.emerald2=0
        print("super power actived")
    end
end

function Chest:collide(c)  -- this gets called when a collision occurs
     if c1.x>c2.x-101 and c1.x<c2.x+101 and c1.y>c2.y-101 and c1.y<c2.y+101 then  
        open=true    -- open the chest
        et=ElapsedTime
        end
            end

colBody = class()

function colBody:init()
    
    physics.gravity(0,0)
    c1 = physics.body(CIRCLE,45)    -- sprite collision circle
    c1.type=DYNAMIC
    c1.x=WIDTH/2
    c1.y=300
    c1.sleepingAllowed=false
    
    c2 = physics.body(CIRCLE,50)    -- sprite collision circle
    c2.type=STATIC
    c2.x=WIDTH/2
    c2.y=600
    c2.sleepingAllowed=false
end

button=class()

function button:init(x,y,d,xs,ys,n)
    self.x=x    -- x position   
    self.y=y    -- y position
    self.dir=d  -- person direction
    
    self.xs=xs*4  -- person speed x
    self.ys=ys*4 -- person speed y
    self.name=n -- button name
end
  
function button:draw()
    fill(255,0,0)
    rect(self.x,self.y,50,50)
    fill(255)
    text(self.name,self.x,self.y)
end

function button:touched(t)
    if t.x>self.x-25 and t.x<self.x+25 and t.y>self.y-25 and t.y<self.y+25 then
        dir=self.dir
        i=dir
        dx=self.xs
        dy=self.ys
    end
end

function createButtons()
    x,y=WIDTH/2,100
    bTab={}
    table.insert(bTab,button(x-50,y+50,17,-1,1,"u-l"))
    table.insert(bTab,button(x,y+50,9,0,1,"up"))
    table.insert(bTab,button(x+50,y+50,1,1,1,"u-r"))
    table.insert(bTab,button(x-50,y,33,-1,0,"left"))
    table.insert(bTab,button(x+50,y,25,1,0,"right"))
    table.insert(bTab,button(x-50,y-50,57,-1,-1,"d-l"))
    table.insert(bTab,button(x,y-50,49,0,-1,"down"))
    table.insert(bTab,button(x+50,y-50,41,1,-1,"d-r"))
end

function checkButtons()
    for a,b in pairs(bTab) do
        b:draw()
    end
end

See post below for transfer to other thread.

Ok, so my last inventory system was trash (probably why no one answered :# ) so I made a better one.
How come after I get the emerald to add to the inventory I get nil?
I want the code to check for a open slot then if it’s false it adds the game object to inventory.

function setup()
    
    inventory={
    isFull={false,false,false,false},
    slots={vec2(200,100),vec2(350,100),vec2(500,100),vec2(650,100)}}
       
    items = {asset.builtin.Blocks.Glass_Frame,
             asset.builtin.Blocks.Glass_Frame,
             asset.builtin.Blocks.Glass_Frame,
             asset.builtin.Blocks.Glass_Frame
            }
    
    gameobject = {asset.builtin.Planet_Cute.Gem_Blue,
                 }
    objectpos = vec2(500,400)
    
end

function draw()
    background(49)
    for i,v in ipairs(inventory.isFull) do
        if inventory.isFull[i] == false then   
       sprite(items[i],inventory.slots[i].x,inventory.slots[i].y)
            elseif
        inventory.isFull[i] == true then
    while true do
            break
            end
        end
    end
    if a==true then
       invsystem(gameobject[i]) 
    end

    sprite(gameobject[1],objectpos.x,objectpos.y,75,130)
end

function invsystem(i)
        for i,v in ipairs(inventory.slots) do
        if inventory.isFull[i] == false then   
        sprite(gameobject[i],inventory.slots[i].x,inventory.slots[i].y)
            elseif
        inventory.isFull[i] == true then
            print("isFull")
    while true do
            break
            end
        end
    end   
end

function touched (t)
    if t.state==BEGAN and t.x>objectpos.x-60 and t.x<objectpos.x+60 and t.y>objectpos.y-60 and t.y<objectpos.y+60 then 
        print("test")
        a=true
    end
end

I figured out everything else but can someone tell me why a black square is appearing after I touch the inventory emerald(the small one). I really don’t understanding the logic behind that.

@Bri_G It works great, thanks! I think you meant to post this in my other forum.

https://codea.io/talk/discussion/10502/2d-table-tile-map-help#latest

@Jarc - yup, sorry transferred it to :smile:

Scrolling 2D map

You set the image to 0 in the chest touch function

citems.emerald2=0

The sprite command tries to load a zero image which gives you the black square

@West Weird, in another example when I collide with a heart sprite it makes the heart sprite = 0, which makes the sprite disappear. Example pics below.
Why doesn’t that same logic work here.

Here’s the code to make the heart disappear

if c.state==BEGAN and
 c1.x>c4.x-100 and c1.x<c4.x+100 and c1.y>c4.y-100 and c1.y<c4.y+100 then
      value=value+10 
        potion[1]=0
        end    
    end

The other difference is the emerald is in the touch function and the heart is in collide function.

@West nvm it was this line messing me up.

      if r==true then
           sprite(citems[2],inventorypos.x,inventorypos.y,30,30) 

I had to make false but now I have to redo my whole code to get it to work with item dropping :expressionless: Does anyone have code for a game inventory equip and drop?
Or a forum link.

I’m having one problem with my inventory pick up and drop system, if anyone could help that would nice. My problem is the double tap to drop. Whenever I double tap the empty inventory sprite slot position after opening the chest it drops a emerald. I pretty much want to turn off the touch function so whenever the sprite isn’t in the position(inventory slot) but not sure how to.

Turn iPad to landscape

function setup()
    chestClosed=readImage("Planet Cute:Chest Closed")
    chestOpen=readImage("Planet Cute:Chest Open")
    
    tab={readImage(asset.builtin.Planet_Cute.Gem_Blue)}
    tab2={readImage(asset.builtin.Planet_Cute.Gem_Blue)}
    tab3={}
    pos={inv=vec2(850,250),drop=vec2(300,400),chest=vec2(WIDTH/2,HEIGHT/2)}
end

function draw()
    background(40,40,50)
    sprite(asset.builtin.Blocks.Glass_Frame,900,200,200,200)
    fill(255)
    text("tap screen to open chest for 3 seconds",WIDTH/2,HEIGHT/2+200)
    chest(tab[1],tab2[1])    
end

function chest(x,z)
    if open then
        sprite(chestOpen,pos.chest.x,pos.chest.y)
        sprite(x,WIDTH/2,HEIGHT/2+70)
    if ElapsedTime-et>3 then
            for a,b in pairs (tab) do
            table.remove(tab,1)
        table.insert(tab,1,0)
            open=false
                inv=true
                chestOpen=0
                chestClosed=0
        end
            end
    else
        sprite(chestClosed,pos.chest.x,pos.chest.y)
        end
    if inv==true and tab[1]==0 then
            sprite(z,pos.inv.x,pos.inv.y,50)
    elseif
        inv==false and tab[1]==0
    then
        sprite(z,pos.drop.x,pos.drop.y,50)
    end
end

function touched(t)
    if t.state==BEGAN and t.x>pos.chest.x-101 and t.x<pos.chest.x+101 and t.y>pos.chest.y-101 and t.y<pos.chest.y+101 then  
        open=true    -- open the chest
        et=ElapsedTime    -- set time
    end
    
    if t.state==BEGAN and t.x>pos.inv.x-50 and t.x<pos.inv.x+50 and t.y>pos.inv.y-50 and t.y<pos.inv.y+50 and   t.tapCount==1 and inv==true then 
        table.move(tab2,1,1,1,tab3)
        table.insert(tab2,1,0)
        print("super power activated") 
        inv=false
        end   
    
        if t.state==BEGAN and t.x>pos.inv.x-50 and t.x<pos.inv.x+50 and t.y>pos.inv.y-50 and t.y<pos.inv.y+50 and   t.tapCount==2 and inv==false and tab2[1]==0 then
        table.move(tab3,1,1,1,tab2)
        inv=false
        print("item dropped")
        end   
    
         if t.state==BEGAN and t.x>pos.drop.x-50 and t.x<pos.drop.x+50 and t.y>pos.drop.y-50 and t.y<pos.drop.y+50 and tab[1]==0 then
        inv=true
        end     
end

@Jarc I would suggest setting up a couple of classes, one for the items and one for the inventory (made up of slots). You can then track the position of items and slots and manipulate accordingly. Here’s a short example (hopefully this imports ok - there seems to be an issue with the export, where only the firs tab is exported)



--# Main
-- RPG Inventory

-- Use this function to perform your initial setup
function setup()
    mapx,mapy,mapw,maph=300,100,500,500
    
    
inventory={}
    --set up 5 vertical slots
    for ypos=1,5 do 
        table.insert(inventory,Slot(ypos,WIDTH-250,100+ypos*120))
    end
    itemImage={asset.builtin.Planet_Cute.Gem_Green,asset.builtin.Planet_Cute.Key,asset.builtin.Planet_Cute.Gem_Orange}
    items={}

    for i=1,6 do
        --place 3 random items in the map
        table.insert(items,Item(i,mapx+math.random(mapw),mapy+math.random(maph),math.random(#itemImage)))
    end
    
    
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    --draw "map" area
    fill(140, 42, 37)
    rect(mapx,mapy,mapw,maph)
    
    
for _,s in pairs(inventory) do
        s:draw()
    end
for _,i in pairs(items) do
        i:draw()
    end
    
end

function touched(touch)
    for _,i in pairs(items) do
        i:touched(touch)
    end
    
    
end

--# Slot

Slot = class()

function Slot:init(id,x,y)
    self.id=id --variable to track the identity of the slot
    self.x = x
    self.y=y
    self.w=100
    self.h=100
    self.content=0 --holds the id of the item in this slot; 0 means it is empty
end

function Slot:draw()
    stroke(255)
    strokeWidth(3)
    noFill()
    rect(self.x,self.y,self.w,self.h)  --hard coded size of 100 x 100
    --debug text - print the id of any item in the slot in the corner
    fill(255)
    text(self.content,self.x+10,self.y+10)
end

function Slot:touched(touch)
    -- Codea does not automatically call this method
end

--# Item

Item = class()

function Item:init(id,x,y,kind)
    -- you can accept and set parameters here
    self.id=id
    self.x = x
    self.y = y
    self.w=100 --hard coded width and height
    self.h=100
    self.kind=kind --the object type - 1 is an emerald, 2 is a key,3 is an orange gem - match with the itemImage array
    self.location=0 --stores the slot id of the item when picked up; 0 is the default "map" location, -1 would mean the item is used and is ready to be deleted
    --could expand to include items being in specific chests.
    self.selected=false -- flag to see if the object is selected - used to put a highlight reticule around it
end

function Item:draw()
    sprite(itemImage[self.kind],self.x,self.y,self.w,self.h)
    --debug text - print the id of the item
    fill(0)
    text(self.id,self.x,self.y)
    --add a selection reticule
    if self.selected then
        tint(255,150+100*math.sin(ElapsedTime*4))
        sprite(asset.builtin.Blocks.Glass,self.x,self.y,self.w,self.h)
        noTint()
    end
end

function Item:touched(touch)
    
    if touch.x>self.x-self.w/2 and touch.x<self.x+self.w/2 and touch.y>self.y-self.h/2 and touch.y<self.y+self.h/2 then
        self.selected=true
        self.x=touch.x
        self.y=touch.y
    end
    if touch.state==ENDED and self.selected then
        self.selected=false
                    --empty the slot if it was picked up from a slot
            for i,s in pairs(inventory) do
                if s.content==self.id then
                    s.content=0
                end
            end
        
        if self.x<mapx or self.x>mapx+mapw or self.y<mapy or self.y>mapy+maph then
            --let go of item outside map so place in a slot
            local destinationslot=0
            local desinationslotarrayposition=0
            --find the first available empty slot
            for i,s in pairs(inventory) do
                if s.content==0 then
                    destinationslot=s.id
                    desinationslotarrayposition=i
                    break
                end
            end
            --update the slot content and item position and location
            if destinationslot>0 then
                self.location=destinationslot
                self.x=inventory[desinationslotarrayposition].x+inventory[desinationslotarrayposition].w/2
                self.y=inventory[desinationslotarrayposition].y+inventory[desinationslotarrayposition].h/2
                inventory[desinationslotarrayposition].content=self.id
            else
            --if there are no empty slots then put it back in the map
                sound(asset.downloaded.Game_Sounds_One.Wrong)
                self.x=mapx+math.random(mapw)
                self.y=mapy+math.random(maph)
                self.location=0
            end
        end
    end
end