3D dice

This code draws a 3d dice that can be rolled and feedback the number it lands on. Feel free to use the code.


--# Main
-- main

function setup()
    b=Die(0,0,0,200)
end

function draw()
    background(255, 0, 0, 255)
    b:draw()
    fill(0)
    fontSize(50)
    if b.rolling then
        text("rolling...",300,100)
    else
        text("The dice is on face "..b.face,300,100)
    end
end

function touched(touch)
    if touch.state==BEGAN then
        b:roll()
    end
end





--# Die
Die = class()

function Die:init(x,y,z,s)
    local one=image(s,s)
    local two=image(s,s)
    local three=image(s,s)
    local four=image(s,s)
    local five=image(s,s)
    local six=image(s,s)
    local spotsize=s/4.5
    fill(0)
    noStroke()
    
    setContext(one)
    ellipse(s/2,s/2,spotsize)
    
    setContext(two)
    ellipse(s/3,s/3,spotsize)
    ellipse(s/3*2,s/3*2,spotsize)
    
    setContext(three)
    ellipse(s/4,s/4,spotsize)
    ellipse(s/4*2,s/4*2,spotsize)
    ellipse(s/4*3,s/4*3,spotsize)
    
    setContext(four)
    ellipse(s/3,s/3,spotsize)
    ellipse(s/3*2,s/3,spotsize)
    ellipse(s/3*2,s/3*2,spotsize)
    ellipse(s/3,s/3*2,spotsize)
    
    setContext(five)
    ellipse(s/4,s/4,spotsize)
    ellipse(s/4*2,s/4*2,spotsize)
    ellipse(s/4*3,s/4*3,spotsize)
    ellipse(s/4,s/4*3,spotsize)
    ellipse(s/4*3,s/4,spotsize)
    
    setContext(six)
    ellipse(s/4,s/3,spotsize)
    ellipse(s/4*2,s/3,spotsize)
    ellipse(s/4*3,s/3,spotsize)
    ellipse(s/4,s/3*2,spotsize)
    ellipse(s/4*2,s/3*2,spotsize)
    ellipse(s/4*3,s/3*2,spotsize)
    
    local img=image(s*6,s)
    local spotpos={1,2,6,5,3,4}
    setContext(img)
    stroke(0)
    strokeWidth(10)
    rectMode(CORNER)
    spriteMode(CORNER)
    for i=1,6 do
        fill(255)
        rect((i-1)*s-5,0-5,s+10,s+10)
        fill(0) 
        fontSize(30)
        font("AmericanTypewriter-Bold")
        if spotpos[i]==1 then
            sprite(one,(i-1)*s,0)
        elseif spotpos[i]==2 then
            sprite(two,(i-1)*s,0)
        elseif spotpos[i]==3 then
            sprite(three,(i-1)*s,0)
        elseif spotpos[i]==4 then
            sprite(four,(i-1)*s,0)
        elseif spotpos[i]==5 then
            sprite(five,(i-1)*s,0)
        elseif spotpos[i]==6 then
            sprite(six,(i-1)*s,0)
        end
    end
    setContext()
    self.x = x
    self.y = y
    self.z = z
    self.width = s/4 -- width
    self.height = s/4 -- height
    self.depth = s/4 -- depth
    self.texture = img
    self.texR = {0,0,1/6,1, 1/6,0,2/6,1, 2/6,0,3/6,1, 3/6,0,4/6,1, 4/6,0,5/6,1, 5/6,0,6/6,1}
    self.mesh = self:createDie()
    
    self.angle={x=0,y=0,z=0}
    
    self.rolling=false
    self.face=6
    self.faceangle=
    {vec2(2,4),vec2(1,3),vec2(2,1),vec2(4,1),vec2(3,2),vec2(0,0)}
end

function Die:createDie()
    local w,h,d = self.width,self.height,self.depth
    -- right = +
    -- up = +
    -- front = +
    --table of the verticies of a cube
    --x ,y, z
    local v = 
    {
    vec3(-0.5*w +self.x,-0.5*h +self.y,0.5*d +self.z), -- left  bottom front --+
    vec3(0.5*w +self.x,-0.5*h +self.y,0.5*d +self.z), --  right bottom front +-+
    vec3(0.5*w +self.x,0.5*h +self.y,0.5*d +self.z), --   right top    front +++
    vec3(-0.5*w +self.x,0.5*h +self.y,0.5*d +self.z), --  left  top    front -++
    
    vec3(-0.5*w +self.x,-0.5*h +self.y,-0.5*d +self.z), --left  bottom back  ---
    vec3(0.5*w +self.x,-0.5*h +self.y,-0.5*d +self.z), -- right bottom back  +--
    vec3(0.5*w +self.x,0.5*h +self.y,-0.5*d +self.z), --  right top    back  ++-
    vec3(-0.5*w +self.x,0.5*h +self.y,-0.5*d +self.z), -- left  top    back  -+-
    }
    
    local cubeverts =
    {
    -- front face
      v[1], v[2], v[3], v[1], v[3], v[4],
    
    -- right face
      v[2], v[6], v[7], v[2], v[7], v[3],
    
    -- back face
      v[6], v[5], v[8], v[6], v[8], v[7],
    
    -- left face
      v[5], v[1], v[4], v[5], v[4], v[8],
    
    -- top face
      v[4], v[3], v[7], v[4], v[7], v[8],
    
    -- bottom face
      v[5], v[6], v[2], v[5], v[2], v[1],   
    }
    local cubetexCoords = {}
    for f=1,6 do
        local p=(f-1)*4
        local BL=vec2(self.texR[1+p],self.texR[2+p]) --bottom left
        local BR=vec2(self.texR[3+p],self.texR[2+p]) --bottom right  
        local TR=vec2(self.texR[3+p],self.texR[4+p]) --top right
        local TL=vec2(self.texR[1+p],self.texR[4+p]) --top left
                
        table.insert(cubetexCoords,BL)
        table.insert(cubetexCoords,BR)
        table.insert(cubetexCoords,TR)
        table.insert(cubetexCoords,BL)
        table.insert(cubetexCoords,TR)
        table.insert(cubetexCoords,TL)
    end

    local ms = mesh()
    ms.vertices = cubeverts    
    ms.texture = self.texture
    ms.texCoords = cubetexCoords
    ms:setColors(255,255,255,255)
    
    return ms
end

function Die:draw()
    
    pushMatrix()
    perspective(45,WIDTH/HEIGHT)
    camera(0,0,-300,0,0,0,0,1,0)
    rotate(self.angle.x,0,1,0)
    rotate(self.angle.y,1,0,0)
    self.mesh:draw()
    popMatrix()
    ortho()
    viewMatrix(matrix())
end

function Die:roll()
    if not self.rolling then
        local Xroll=0
        while Xroll==0 do Xroll=math.random(-1,1) end
        local Yroll=0
        while Yroll==0 do Yroll=math.random(-1,1) end
        self.newface=math.random(1,6)
        self.rolling=true
local rotateX=self.faceangle[self.newface].x*90-self.angle.x+Xroll*360
local rotateY=self.faceangle[self.newface].y*90-self.angle.y+Yroll*360
        tween(1.5,self.angle,
        {x=self.angle.x+rotateX,
        y=self.angle.y+rotateY},
        tween.easing.quadInOut,
        function()
            self.rolling=false 
            self.face=self.newface
        end)
    end
end








This script can only make a dice on center of screen. How can I make a few dices and place it at other location?

To change a dice’s position, a quick solution is to use translate:

pushMatrix()
translate(-WIDTH/2+yourX,-HEIGHT/2+yourY) -- replace yourX and yourY with the dice position you want to use
d:draw() -- draw the dice
popMatrix()

@olzenkhaw Replace the functions with what I have below.

EDIT: Changed code a little.

supportedOrientations(LANDSCAPE_ANY)

function setup()
    b=Die(0,0,0,100)
    c=Die(0,0,0,100)
end

function draw()
    background(255, 0, 0, 255)
    translate(25,0)
    b:draw()
    translate(-50,0)
    c:draw()
    fill(0)
    fontSize(50)
    if b.rolling then
        text("rolling...",300,100)
    else
        text("The dice is on face "..b.face,300,200)
        text("The dice is on face "..c.face,300,100)
    end
end

function touched(touch)
    if touch.state==BEGAN then
        b:roll()
        c:roll()
    end
end

Thank you. However, the 2 dices when see in 2D are different because of the camera view. How can I show the 2 dices exactly 100% same in 2D?

@olzenkhaw One way to do it would be to show the dice spinning in 3D, but just as they stop, draw the face of the dice in 2D.

@olzenkhaw If you’re after simple 2D dice, then here’s a small program to get you started. You can modify this to what you want. Tap the screen to roll the dice.

function setup()
    rectMode(CENTER)
    d1=dice(200,400)
    d2=dice(300,400)
end

function draw()
    background(40, 40, 50)
    d1:draw()
    d2:draw()
end

function touched(t)
    if t.state==BEGAN then
        d1:touched(t)
        d2:touched(t)
    end
end

dice=class()

function dice:init(x,y)
    self.x=x
    self.y=y
    self.cnt1=0
    self.cnt2=0
    self.p=math.random(6)
    self.rolls=false
end

function dice:draw()
    fill(255)
    rect(self.x,self.y,80)  
    fill(0)
    if self.p==1 or self.p==3 or self.p==5 then
        ellipse(self.x,self.y,20)
    end
    if self.p==2 or self.p==3 then
        ellipse(self.x-20,self.y-20,20)
        ellipse(self.x+20,self.y+20,20)
    end
    if self.p==4 or self.p==5 or self.p==6 then
        ellipse(self.x-20,self.y-20,20)
        ellipse(self.x+20,self.y+20,20)
        ellipse(self.x-20,self.y+20,20)
        ellipse(self.x+20,self.y-20,20)
    end
    if self.p==6 then
        ellipse(self.x-20,self.y,20)
        ellipse(self.x+20,self.y,20)
    end
    if self.rolls then
        if self.cnt1>math.random(10,20) then
            self.rolls=false
        end 
        self.cnt2=self.cnt2+1
        if self.cnt2>math.random(5,10) then
            self.cnt2=0
            self.cnt1=self.cnt1+1
            self.p=math.random(6)
        end
    end
end

function dice:touched(t)
    if t.state==BEGAN then
        self.cnt1=0
        self.cnt2=0
        self.rolls=true
    end
end

Nice!