Spawning Entities Through Tables

In my game, I want to spawn as many entities as I ask, but I don’t exactly know how to spawn multiple entities in the scene without having to write big chunk a of code and wasting a lot of time. I have made a simple table function that inserts an entity into the scene, but I don’t know how to tell the table to spawn more than one entity at a time. Could somebody please shed some light on this??

Here’s my code:

-- Inserting Tables

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

    bobs = {}
end

function createSubjects(n)
    for i=0, #bobs do
        bob = scene:entity()
        bob.model = craft.model(asset.builtin.Primitives.Sphere)
        bob.position = vec3(0, -1, 4)
        bob.scale = vec3(1, 1, 1) / 8
        bob.material = craft.material(asset.builtin.Materials.Standard)
    end
    table.insert(bobs, n)
end

function touched(touch)
    if touch.state == BEGAN then
        createSubjects(5) — The number represents how many entities I want to spawn
    end
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()	
end

Thanks in advance :slight_smile:

Will this do.

viewer.mode=FULLSCREEN

function setup()
    tab={}
    fill(255)
    scene = craft.scene()
    scene.sun.rotation=quat.eulerAngles(20,45,-30)
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 200, 0, 1000)
    createObjects()

end

function createObjects()
    for z=1,150 do
        local a=scene:entity()
        a.position=vec3(math.random(-15,15),math.random(-15,15),math.random(-15,15))
        a.model = craft.model.icosphere(1,2)
        a.material = craft.material(asset.builtin.Materials.Specular)
        a.material.diffuse=color(255,0,0)
        table.insert(tab,a)
    end    
end

function draw()
    update(DeltaTime)
    scene:draw()    
    text("Drag your finger on the screen to rotate the spheres",WIDTH/2,HEIGHT-100)
    for a,b in pairs(tab) do
        b.x=b.x+math.random(-2,2)*.2
        b.y=b.y+math.random(-2,2)*.2
    end
end

function update(dt)
    scene:update(dt)
end

@dave1707, thank you for that code. I did, however, run into one problem. Say that I wanted to generate 3 spheres into the scene. I go into the scene and double tap as I’m supposed to, but instead of spawning 3 spheres, it only spawns 2. I found out you have to double tap one more time for the third sphere to spawn into the scene. I know it has something to do with the index count of the “for loop”, but I don’t know how to fix it. Is there anyway to fix this problem??

Thanks :slight_smile:

@Creator27 Here’s the above code modified to add objects each double tap. It starts out adding 1 object. It adds 1 to the nbr each double tap.

viewer.mode=FULLSCREEN

function setup()
    tab={}
    fill(255)
    scene = craft.scene()
    scene.sun.rotation=quat.eulerAngles(20,45,-30)
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 200, 0, 1000)
    nbr=1
end

function createObjects(n)
    for z=1,n do
        local a=scene:entity()
        a.position=vec3(math.random(-15,15),math.random(-15,15),math.random(-15,15))
        a.model = craft.model.icosphere(2,2)
        a.material = craft.material(asset.builtin.Materials.Specular)
        a.material.diffuse=color(255,0,0)
        table.insert(tab,a)
    end    
end

function draw()
    update(DeltaTime)
    scene:draw()    
    text("Double tap to add objects",WIDTH/2,HEIGHT-100)
    for a,b in pairs(tab) do
        b.x=b.x+math.random(-2,2)*.2
        b.y=b.y+math.random(-2,2)*.2
    end
end

function update(dt)
    scene:update(dt)
end

function touched(t)
    if t.state==BEGAN and t.tapCount==2 then
        createObjects(nbr)
        nbr=nbr+1
    end
end

@dave1707, thank you for that code. There was one other problem that I did encounter. Every time I want to destroy one of the spheres by hitting an object, it sometimes doesn’t remove any of the spheres. Is there anyway to fix this problem??

Here’s my code:

-- Bean

function setup()
    -- Create a new craft scene
    scene = craft.scene()
    scene.sky.material.sky = color(0, 240, 255)
    scene.sky.material.horizon = color(0, 131, 255)
    scene.sky.material.ground = color(0, 131, 255)
    parameter.watch("bean.rotation.x")
    parameter.watch("bob[bc].name")
    viewer.mode = FULLSCREEN
    bobActive = false
    pm = false
    hit = false
    swingshot = false
    spawned = false
    cr = 0
    tr = 0
    tp = vec2(0, 0)
    br = 0
    br2 = 0
    bc = 0
    hc = 0
    nbr = 4
    bobs = {}
    moveDir = vec3(0, 0, 0)
    weapons = {sword = craft.model(asset.builtin.CastleKit.sword_obj);
               gun = craft.model(asset.documents.Dropbox.machinegun_obj);
               blaster = craft.model(asset.documents.Dropbox.blasterB_obj)}
    forward = scene.camera.forward * moveDir.z
    right = scene.camera.right * moveDir.x
    up = vec3(0,1,0) * moveDir.y
    
    finalDir = forward + right + up

    -- Create a new entity
    bean = scene:entity()
    b = bean:add(craft.rigidbody, DYNAMIC)
    b.sleepingAllowed = false
    b.angularDamping = 0.4
    bean.model = craft.model(asset.builtin.Primitives.Capsule)
    bean:add(craft.shape.model, bean.model)
    bean.position = vec3(0, -1, 0)
    bean.scale = vec3(2, 2, 2) / 8
    bean.material = craft.material(asset.builtin.Materials.Standard)
    
    lob = scene:entity()
    lb = lob:add(craft.rigidbody, STATIC)
    lb.sleepingAllowed = false
    lob.model = craft.model(asset.builtin.Primitives.Sphere)
    lob:add(craft.shape.model, lob.model)
    lob.position = vec3(bean.x + 1, bean.y, bean.z)
    lob.scale = vec3(1, 1, 1) / 8
    lob.material = craft.material(asset.builtin.Materials.Standard)
    
    createGround(vec3(0, -3.12, 0))
    scene.camera.position = vec3(-5, 2.5, -5)
    scene.camera.eulerAngles = vec3(25, 45, 0)
    cameraSettings = scene.camera:get(craft.camera)
    cameraSettings.ortho = true
    cameraSettings.orthoSize = 2.5
end

function createGround(p)
    ground = scene:entity()
    g = ground:add(craft.rigidbody, STATIC)
    g.restitution = 1
    ground.model = craft.model.cube(vec3(4, 4, 4))
    ground:add(craft.shape.box, vec3(4, 4, 4))
    ground.position = p
    ground.material = craft.material(asset.builtin.Materials.Standard)
    ground.material.map = readImage(asset.builtin.Blocks.Sand)
end

function createSubject(p)
    bob[bc] = scene:entity()
    bob[bc].name = "Bob No."..bc
    bob[bc].model = craft.model(asset.builtin.Primitives.Sphere)
    bob[bc].position = p
    bob[bc].scale = vec3(1, 1, 1) / 8
    bob[bc].material = craft.material(asset.builtin.Materials.Standard)
    bc = bc + 1
end

function createSubjects(n)
    for i=1, n do
        llob = scene:entity()
        l = llob:add(craft.rigidbody, DYNAMIC)
        llob:add(craft.shape.sphere, 1, 3)
        l.sleepingAllowed = false
        l.restitution = 0.2
        llob.name = "Bob No."..bc
        llob.model = craft.model(asset.builtin.Primitives.Sphere)
        llob.position = vec3(bean.x - 1, -1, 0)
        llob.scale = vec3(1, 1, 1) / 8
        llob.material = craft.material(asset.builtin.Materials.Standard)
    end
    table.insert(bobs, 1)
    for a,b in pairs(bobs) do
        llob.x = math.random(-3, 3) * .2
        llob.y = 0
        llob.z = math.random(-1, -1) * .2
    end
end

function weaponGen()
    weapon = scene:entity()
    weapon.model = craft.model()
end

function coinGen(p)
    coin = scene:entity()
    coin.model = craft.model(asset.documents.Dropbox.coinGold_obj)
    coin.position = p
    coin.eulerAngles = vec3(0, 0, 0)
    coin.scale = vec3(1, 1, 1) / 8
end

function BD(n)
    if llob[n] ~= nil then
        llob[n]:remove(craft.model)
        print("Bob No."..n.." destroyed!")
    else
        print("No such Bob exists!")
    end
end

function BP(n, a)
    if llob[bc].name == "Bob No."..n then
        llob[n].model = a
    end
end

function update(dt)
    -- Update the scene (physics, transforms etc)
    scene:update(dt)
    bean.eulerAngles = vec3(0, 0, 0)
end

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

    -- Draw the scene
    scene:draw()	
    calc()
    
    scene.debug:line(vec3(bean.x, bean.y, bean.z), vec3(lob.x, lob.y, lob.z), color(255))
    ray = scene.physics:raycast(vec3(bean.x, bean.y, bean.z), vec3(lob.x, lob.y, lob.z), 100)
    
    if ray ~= nil then
        text(ray.entity.z, 500, 500)
    end
end

function touched(touch)
    if touch.state == BEGAN or touch.state == MOVING then
        b.friction = 0.4
    end
    
    if touch.x < WIDTH/2 then
        if touch.state == MOVING and touch.deltaY > 0 then
            b:applyForce(vec3(0, 0, 7)) 
            pm = true
        end 
        if touch.state == MOVING and touch.deltaY < 0 then
            b:applyForce(vec3(0, 0, -7))
            pm = true
        end
        if touch.state == MOVING and touch.deltaX > 0 then
            b:applyForce(vec3(-7, 0, 0))
            if br <= 25 then
                br = br + 5  
            end
            pm = true
        end
        if touch.state == MOVING and touch.deltaX < 0 then
            b:applyForce(vec3(7, 0, 0))
            if br >= -25 then
                br = br - 5
            end
            pm = true
        end
    end
    
    if touch.x > WIDTH/2 then
        if touch.state == MOVING and touch.deltaX > 0 then
            cr = cr + 2
            pm = true
        end
        if touch.state == MOVING and touch.deltaX < 0 then
            cr = cr - 2
            pm = true
        end
    end
    
    if touch.x > WIDTH/2 then
        if touch.tapCount == 2 then
            if touch.state == BEGAN then
                sound(SOUND_JUMP, 3209)
                b.linearVelocity = vec3(0, 3, 0)
                b.linearDamping = 0.4
            end
        end
    end
    
    if touch.tapCount == 2 then
        if touch.state == BEGAN then
            bc = bc + 2
            createSubjects(3)
            if bc == 1 then
                print("There is "..bc.." Bob in the game!")
            else
                print("There are "..bc.." Bobs in the game!")
            end
        end 
    end
    
    if touch.state == ENDED then
        pm = false
        b.angularVelocity = vec3(0, 0, 0)
        if swingshot == true then
            b.linearVelocity = vec3(lob.x - math.ceil((lob.x - 100)/12), lob.y - math.ceil((lob.y - 100)/12), lob.z - math.ceil((lob.z - 150)/12))
            b.linearDamping = 0.4
            b.friction = 2
        end
    end
end

function calc()
    x = math.abs(bean.x - lob.x)
    y = math.abs(bean.y - lob.y)
    z = math.abs(bean.z - lob.z)
    if x<.2 and y<.2 and z<.2 then
        hit = false
        if hit == false then
            print("HIT!")
            sound(SOUND_HIT, 21739)
            b:applyForce(vec3(3, 0, 3))
            b.linearVelocity = vec3(0, 5, 0)
            b.linearDamping = 0.4
            for a,b in pairs(bobs) do
                llob:destroy()
                spawned = false
            end
            bc = bc - 1
            if bc == 1 then
                lob:remove(craft.model)
            end
            if bc > 0 then
                print("One in "..bc)
                if bc == 1 then
                    print("There is now "..bc.." Bob in the game!")
                else
                    print("There are now "..bc.." Bobs in the game!")
                end
            end
        end
        hit = true
    end
end

Thanks :slight_smile:

@Creator27 Here’s an example showing how to destroy an entity and remove it from a table. When the spheres hit the rectangle, I destroy them and remove them from the table.

viewer.mode=STANDARD

function setup()
    assert(OrbitViewer, "Please include Cameras as a dependency")
    fill(255)
    scene = craft.scene()
    skyMaterial=scene.sky.material
    skyMaterial.sky=color(0, 62, 255, 255)
    skyMaterial.horizon=color(255, 152, 0)  
    scene.sun.rotation=quat.eulerAngles(20,45,-30)
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 200)
    v.rx,v.ry=20,20
    tab={}
    createRect()
    createSphere()  
end

function draw()
    update(DeltaTime)
    scene:draw()    
    checkCollision()
    text("Drag your finger on the screen to rotate the cube",WIDTH/2,HEIGHT-100)
end

function update(dt)
    scene:update(dt)
end

function createRect() 
    c1=scene:entity()
    w=c1:add(craft.rigidbody,STATIC)
    w.restitution=.8
    c1.position=vec3(0,-10,0)
    c1.model = craft.model.cube(vec3(20,2,20))
    c1:add(craft.shape.model,c1.model)
    c1.material = craft.material(asset.builtin.Materials.Standard)
    c1.material.map = readImage(asset.builtin.Surfaces.Basic_Bricks_AO)
end

function checkCollision(c)
    for z=#tab,1,-1 do  -- parse table in reverse order to avoid remove problems
        if tab[z].x>=-10 and tab[z].x<=10 and tab[z].y<-8.5 then
            tab[z]:destroy()    -- destroy sphere
            print("removed  x="..tab[z].x.."  z="..tab[z].z)
            table.remove(tab,z) -- remove sphere from table
        end        
    end
end

function createSphere()
    for z=1,10 do
        local sphere1=scene:entity()
        s1=sphere1:add(craft.rigidbody,DYNAMIC)
        sphere1.position=vec3(math.random(-10,10),
            math.random(20,40),math.random(-10,10))
        sphere1.model = craft.model.icosphere(.5,5)
        sphere1:add(craft.shape.sphere,.5)
        sphere1.material = craft.material(asset.builtin.Materials.Specular)
        sphere1.material.diffuse=color(255,0,0)
        table.insert(tab,sphere1)
    end
end

@dave1707, thank you for that code. It really helped out a lot!

@dave1707, just one more question. If I want to destroy one of the spheres when I collide with a particular sphere, all it does is destroy them all at once. Is there anyway to fix this???

Thanks :slight_smile:

@Creator27 You should have all your spheres in the table and just destroy the ones that collide.

@dave1707, the thing is, I don’t exactly know how to do that. Like I know what you mean, but I don’t know what to write.

@Creator27 In the example I have above, I show how to put the spheres in a table (createSphere). I also show how to destroy them and remove them from the table (checkCollision). If your checking if two spheres in the table collide, you have to go through the table for each sphere and for each sphere go thru the table again. That’s a for loop inside a for loop.

@dave1707, it’s all good actually. I figured out what to do and it works like a charm. Apologies if I’m sometimes a bit hard to work with.

@dave1707, when I want to make an object’s position be the player’s through a duplicated destroy table, it will stop following the player if he/she moves at a certain speed. Is there anyway I can fix this??

Here’s the code I’m trying to fix:

function checkWeaponCollision()
    for b=#weaponry,1,-1 do
        x = math.abs(bean.x - weaponry[b].x)
        y = math.abs(bean.y - weaponry[b].y)
        z = math.abs(bean.z - weaponry[b].z)
        if x<=.2125 and z<=.2125 then
            weaponry[b].position = vec3(bean.x, bean.y, bean.z)
        end
    end
end

Thanks :slight_smile:

@Creator - don’t see the rest of your code but, daft question, what happens if you use:


weaponry[b]?position = vec3(x,y,z)

@Bri_G, that doesn’t really work. It just does the exact same things as before.

All good. Figured out how to fix it, and now it works fine! :slight_smile:

@dave1707, there is actually one more thing that I need help with. How can I use a raycast to destroy a sphere?

Here’s the code I’ve written:

-- In function setup()
raycasts = {}

-- In function draw()
for i=#raycasts,1,-1 do
    weaponRay = scene.physics:raycast(vec3(bean.x, bean.y, bean.z), vec3(weaponry[b].x, -10, CurrentTouch.x), 100) 
end

function checkWeaponCollisionWithBobs()
    if equipped == true then
        for i=#bobs,1,-1 do
            for b=#raycasts,1,-1 do
                x2 = math.abs(raycasts[b].x - bobs[i].x)
                y2 = math.abs(raycasts[b].y - bobs[i].y)
                z2 = math.abs(raycasts[b].z - bobs[i].z)   
                if x2<=2 and y2<=2 and z2<=2 then
                    sound(SOUND_HIT, 20445)
                    bobs[i]:destroy()
                    table.remove(bobs,i)
                end
            end
        end
    end    
end

Thanks :slight_smile:

@Creator27 Here’s a 3D raycast example. Move the sliders to move the raycast line. When the raycast line intersects a sphere, it will turn green. You can add whatever code you want at that point. The raycast only finds the first intersect since there’s not a raycastAll for 3D. You can rotate the screen to get a better view of the intersects.

viewer.mode=STANDARD

function setup()
    tab={}
    parameter.integer("x",-400,400,0)
    parameter.integer("y",-400,400,0)
    parameter.integer("z",-400,400,0)
    assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")        
    scene = craft.scene()
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 200, 0, 1000)
    createSphere(vec3(0,0,0),1)
    for z=1,500 do
        createSphere(vec3(math.random(-60,60),math.random(-60,60),math.random(-60,60)),2)
    end
end

function draw()
    update(DeltaTime)
    scene:draw()
    for a,b in pairs(tab) do
        b.material.diffuse=color(255,0,0)
    end        
    rtab=scene.physics:raycast(vec3(0,0,0),vec3(x,y,z),200)
    if rtab~=nil then
        rx=rtab.point.x
        ry=rtab.point.y
        rz=rtab.point.z        
        for a,b in pairs(tab) do
            if math.abs(b.position.x-rx)<2 and math.abs(b.position.y-ry)<2 and math.abs(b.position.z-rz)<2 then
                b.material.diffuse=color(0,255,0)
            end
        end
    end
    scene.debug:line(vec3(0,0,0),vec3(x,y,z)*20,color(255))  
end

function update(dt)
    scene:update(dt)
end

function createSphere(p,size)
    local sphere1=scene:entity()
    local s1=sphere1:add(craft.rigidbody,STATIC)
    sphere1.position=vec3(p.x,p.y,p.z)
    sphere1:add(craft.shape.sphere,size)
    sphere1.model = craft.model.icosphere(size,2)
    sphere1.material = craft.material(asset.builtin.Materials.Specular)
    sphere1.material.diffuse=color(255,0,0)
    table.insert(tab,sphere1)
end

@dave1707, thank you for that. After a bit of tinkering, it works like a charm!

@dave1707, thank you for that code. Another thing, do you know how I can make the raycast rotate around as another object?? For example, if I have a gun that rotates around the centre of the player, is there anyway that I can get the raycast to do the same thing???

Thanks :slight_smile: