Craft 2D Canvas/Drawing Example - A system to easily draw 2D images within a 3D space.

Add this component to an empty entity and it will create a plane, and an empty image with the resolution you desire as that plane’s material map. It’s really simple stuff, but it helps out when you want to add text that follows a character, etc. You can probably even make an entire game like this.

Just add the component, and call this in the draw function

yourCanvas:draw(function() -- do your drawing here end)

canvas = class()

function canvas:init(entity,w,h,c)
    self.entity=entity
    entity.model = craft.model.plane(vec2(40,20))
    entity.material = craft.material(asset.builtin.Materials.Basic)
    entity.eulerAngles=vec3(-90,0,-180)
    entity.material.blendMode = NORMAL
    entity.w=w or 500
    entity.h=h or 200
    entity.w2=entity.w/2
    entity.h2=entity.h/2
    entity.bg=c
    entity.image=image(entity.w,entity.h)
    entity.material.map = entity.image

    self.entity.fill=function(entity)
        setContext(entity.image)
        background(entity.bg)
        fill(0, 0)
        stroke(0, 0)
        rectMode(CORNER)
        strokeWidth(8)
        rect(0,0,entity.h)
        setContext()
   end

    self.entity.draw=function(entity,cb)
        entity:fill()
        if cb~=nil then
            setContext(entity.image)
            cb()
            setContext()
        end
    end

    self.entity.obj=function(entity,obj)
        setContext(Canvas.image)
        obj:draw()
        setContext()
    end
end

In order to do the drawing, I usually just reuse some very simple functions.

--quick 2D
function drawRnd(x,y,w,h,c)
    pushStyle()
    w = w or 1
    h = h or 1
    c = c or color(255)
    fill(c)
    stroke(c)
    ellipse(x,y,w,h)
    popStyle()
end
function drawRect(x,y,w,h,c)
    pushStyle()
    w = w or 1
    h = h or 1
    c = c or color(255)
    fill(c)
    stroke(c)
    rect(x,y,w,h)
    popStyle()
end
function drawLine(x,y,w,h,c)
  pushStyle()
    w = w or nil
    h = h or nil
    c = c or color(255, 0, 0)
   -- fill(c)
    stroke(c)
    strokeWidth(1)
    line(x,y,w,h)
    popStyle()
end
function drawSprite(x,y,a)
    pushStyle()
    local x=x or WIDTH/2
    local y=y or HEIGHT/2
    sprite(a,x,y)
    popStyle()
end
function drawTextUI(x,y,words,c,s,fo)
    pushStyle()
    fo = fo or "SourceSansPro-Bold"
    font()
    s = s or 60
    fontSize(s)
    a = a or CENTER
    textAlign(a)
    c = c or color(255)
    fill(c)
    text(words, x, y)
    popStyle()
end

Anyways, have a good one! If you make any changes, please share them! i’d love to improve upon this functionality.

Thanks for your share, but how to use it?

like this:

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    e = scene:entity()
    myCanvas = e:add(canvas,100,200,color(83, 80, 233))
end

function update(dt)
    -- Update the scene (physics, transforms etc)
    scene:update(dt)
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)

    -- Draw the scene
    scene:draw()	
    e:draw(12,23,10,10,color(227, 233, 80),drawRnd)
end

function drawRnd(x,y,w,h,c)
    pushStyle()
    w = w or 1
    h = h or 1
    c = c or color(255)
    fill(c)
    stroke(c)
    ellipse(x,y,w,h)
    popStyle()
end

I have not see the plane. I guess I wrote it wrong. Can you show the whole code? Thanks

You may have to rotate the plane, I have all my default scenes flipped due to personal preferences. Move the camera back as well.

The only other thing I can see is where you call e:draw()

I would do

    e:draw(function()
    --drawing here
    drawRnd(e.w2,e.h2,32,32,color(0,255,0,255)
    end)

e.w2 being the width of the canvas image cut in half. @binaryblues

@arismoko My guess is that it’s the camera settings. When you’re working with Craft 3D graphics, you can’t see anything if you change the camera parameters, so the best thing to do is to use all the camera parameters you’ve tested. I look forward to your complete example

I’ll post a detailed example in a moment! (:

You should see a white circle with a red background!

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    e=scene:entity()

    -- Add the canvas
    e:add(canvas,500,200,color(255, 0, 0))

    -- Move the camera forward and flip it.
    scene.camera.position=vec3(0,0,10)
    scene.camera.eulerAngles=vec3(0,-180,0)
    
    parameter.number("tx",-360,360)
    tx=-90
end

function update(dt)
    scene:update(dt)
    e.eulerAngles=vec3(tx,0,-180)
end

function draw()
    update(DeltaTime)

    -- Draw the scene
    scene:draw()
    -- Draw the canvas and the things with in it
    e:draw(function()
        drawRnd(e.w2,e.h2,32,32,color(255))
    end)
end

@binaryblues bingo that’s exactly what it was after I tested it for a bit :blush: i’ll definitely keep that in mind for any future sharing i do

There is an easy way is to pack your project, send a compression package, will also avoid a lot of problems, the following is a demonstration of my operation.

https://youtu.be/rTW21rUf_QU

If you have dependencies in your project, the package will miss the dependencies, so you can first create a template based on the project, and then use the template, will automatically include the dependencies, which is what @Bri_G taught me, it worked like a charm.

I’m planning on releasing all the utilities I’ve made eventually so this will definitely come in handy, especially the part about packing the dependencies. So i’d take my large project with multiple dependencies and make a template using it, and then if I export that template my dependencies will remain? If i understand correctly, that should be easy. Thanks for the heads up! @binaryblues

@arismoko You need to create a new template based on your current project, which has been include the dependencies in it, then create a new project based on the template you made right now, then the new project will take the dependencies together when you export it

maybe this would really be the isometric solution i’m looking for