Codea 3.6.1 (353)

@John - think you’re right about the print statements in white. Another funny with the scroll bar in the parameter window, image attached.

@John - output.clear() fired up an error as can not see global ‘output’

@Simeon @John - question a bit out of the box for you:

What information is sent to TLL with error reports?

After mentioning accessing the Codea version from within Codea. I wondered if it would be advantageous if you could supply a package containing the version number, the iOS/iPadOS and the iPad gen info. That way you could pick up on it without having to ask the questions.

Also it could be neat to have an entry on the menu bar list of the Editor to allow users to access the info without having to search for it.

Codea4?A long-awaited new feature!!!

I found two new debug parameter types.

Curve types are sometimes drawn out of the region in parameter.curve().

Test code:

---[=[
    
function setup()
    parameter.color('BackgroundColor', color(64, 64, 64))
    parameter.curve('curve', curve(123))
    parameter.gradient('gradient', gradient(123))
    parameter.vec2("Rotation", vec2(180,0))
    
    scene.main = scene.default3d()
    -- scene.main = scene.canvas()
    
    e = scene.main:entity()
    e.rotation = quat.eulerAngles(45, 0, 45)
    -- e.mesh = mesh.box(vec3(1,1,1),vec3(8,8,8))
    -- e.mesh = mesh.sphere(1.3,32,16,0,360,0,180)
    e.mesh = mesh.roundedBox(0.25,vec3(1,1,1),2,vec3(8,8,8))
    e.mesh = mesh.icoSphere(1,2)
    e.mesh = mesh.cone(1.3,1.9,32,8,4,0,180)
    e.mesh = mesh.cylinder(1.3,1.9,32,8,4,0,350)
    e.mesh = mesh.capsule(1.3,1.9,32,8,4,0,350)
    e.mesh = mesh.disk(1.3,0,32,4,0,360)
    e.mesh = mesh.torus(0.925,1,16,32,8,4,10,360)

    e.mesh = mesh.teapot(8)
    e.mesh = mesh.torusKnot(2,3,8,96)
    -- print(mesh.texture())
    -- e.mesh.texture = mesh.texture(asset.builtin.Blocks.Brick_Red)
    
    myLight = light.spot
    
    green = material.unlit()
    green.baseColor = color(228, 21, 9)
    green.roughness = 1
    
    e.mesh.material = green
    
    -- Destroy after 1 second when touched
    e.touched = function(entity, touch)
        if touch.began then entity:destroy(1) end
        print(4)
        -- scene.editorMode()
    end
    
    -- Play hurt sound when destroyed
    e.destroyed = function()
        sound.play(SOUND_HURT)
    end
    
end

function draw()
    e.rotation = quat.eulerAngles(time.elapsed*100, 45, 45)
    
    matrix.perspective() 
    local v = mat4.orbit(vec3(0, 0, 0), 1, Rotation:unpack())    
    matrix.view(v)
end
--]=]

@Bri_G I am sorry for I made a mistake to cover your bug report item in the google doc, pls rewrite it, thanks.

@binaryblues @Simeon Nice demo. Lot of stuff to look at. For some reason, when I touch the screen the entity:destroy causes Codea to crash. I commented out the e.destroyed code, but it still crashed.

@dave1707 Thank you for your careful examination! I found the same crash. After I tried comment almost every possible line, I got the line who cause crash! It is this line in draw():

    e.rotation = quat.eulerAngles(time.elapsed*100, 45, 45)

@binaryblues I added some code to stop the crash. I added “dest=true” and “if not dest”. When the screen is touched, you destroy e but in draw its still trying to do the e.rotation which doesn’t exist anymore.

    -- Play hurt sound when destroyed
    e.destroyed = function()
        dest=true
        sound.play(SOUND_HURT)
    end
    
end

function draw()
    if not dest then
        e.rotation = quat.eulerAngles(time.elapsed*100, 45, 45)
    end
    

@dave1707 You are right! The crash is my code logic error.

@binaryblues - thanks for the heads-up, couldn’t remember wording but think I covered it again.

@Bri_G error reports usually just give us the time/date it crashed and a symbolcated report if we’re lucky (where it crashed)

I’ll look into what extra debug info we can provide

@binaryblues The new parameter types are still a work in progress (the imgui widgets are a bit dodgy). They can be used with shaders too (I’ll need to make an example project)

@binaryblues @dave1707 When you say crash do you mean it crashes the app or it just throws out errors? You can also use entity.valid to check if an entity is still alive

@john It crashes Codea. Takes you completely out and asks if you want to send a crash report. I’ll try the entity.valid to see how that works.

PS. The entity.valid worked. Can’t wait to get the full documentation that shows all the commands in 4.x .

@John @dave1707 When I say crash, I mean the whole Codea app suddenly quit and went back to the iPad interface. The crash seemed to be a logical problem for my test code: Destroy an object, and then continue referencing it in draw(). It is normally up to the user to avoid this code logic(use a if statement).

The entity.valid took effect.

I will continue to explore new features, very interesting! It seems that our testing schedule occasionally gets ahead of development

@dave1707 You may try to clone the Codea4 help document on GitHub. I’m working on the format and how to submit it so that we can sync up the missing documents as quickly as possible. And there’s a lot of interesting stuff hidden in this document.

In the Physics3D example, I found it support shadow, the default shadow. Sometimes the shadows disappear and are replaced by streaks of light and dark, with varying widths.

Test code:

-- Physics3D
-- From Codea4 

local Grabber = class('Grabber')

function Grabber:created()
    self.spring = 100
    self.damper = 10
    self.world = self.scene.world3d
    self.cam = self.entity:get(camera)
    self.rig = self.entity:get(camera.rigs.orbit)
end

function Grabber:touched(touch)        
    local origin, dir = self.cam:screenToRay(touch.x, touch.y)
    
    if touch.began then        
        local hit = self.world:raycast(origin, dir, 100)        
        if hit and hit.body.type == DYNAMIC then
            self.body = hit.body            
            self.anchor = self.body:localPoint(hit.point)
            self.dist = hit.fraction * 100
            self.rig.pan.enabled = false
            self.rig.pinch.enabled = false
            return true
        end
    elseif touch.moving then
        self.target = origin + dir * self.dist
    elseif touch.ended then
        self.anchor = nil
        self.target = nil
        self.body = nil
        self.rig.pan.enabled = true
        self.rig.pinch.enabled = true        
    end
end

function Grabber:draw()
    if self.anchor and self.target then
        matrix.push().reset()
        style.push().noFill().stroke(255).strokeWidth(5)
        local wp = self.body:worldPoint(self.anchor)
        gizmos.line(wp, self.target)
        style.pop()
        matrix.pop()
    end
end

function Grabber:fixedUpdate(dt)
    if self.anchor and self.target then
        local wp = self.body:worldPoint(self.anchor)
        local v = self.target - wp
        --
        self.body:applyForce(v * self.spring - self.body:velocityAtWorldPoint(wp) * self.damper, wp)
    end
end

function scene:sphere(dynamic, radius, x, y, z)    
    local sphere = self:entity("sphere")
    sphere.position = vec3(x or 0, y or 0, z or 0)
    sphere:add(physics3d.body, dynamic and DYNAMIC or STATIC) --:sphere(0.5)
    sphere:add(physics3d.sphere, radius).rollingFriction = 0.1
    sphere.mesh = mesh.sphere(radius)    
    sphere.meshMaterial = checkers
    return sphere
end

function scene:capsule(dynamic, radius, height, x, y, z)    
    local sphere = self:entity("sphere")
    sphere.position = vec3(x or 0, y or 0, z or 0)
    sphere.scale = vec3(1,1,1)
    sphere:add(physics3d.body, dynamic and DYNAMIC or STATIC):capsule(radius, height)
    sphere.mesh = mesh.capsule(radius, height / 2)    
    sphere.meshMaterial = checkers
    return sphere
end

function scene:box(dynamic, sx, sy, sz, x, y, z)    
    local box = self:entity("box")
    box.position = vec3(x or 0, y or 0, z or 0)    
    box:add(physics3d.body, dynamic and DYNAMIC or STATIC)
    box:add(physics3d.box, sx, sy, sz)
    box.mesh = mesh.box(sx, sy, sz)    
    box.meshMaterial = checkers
    return box
end

function entity:box(sx, sy, sz, x, y, z, rx, ry, rz)    
    local box = self:child()
    box.position = vec3(x or 0, y or 0, z or 0)    
    box.rotation = quat.eulerAngles(rx or 0, ry or 0, rz or 0)
    box:add(physics3d.box, sx, sy, sz)
    box.mesh = mesh.box(sx, sy, sz)    
    box.meshMaterial = checkers
    return box
end

function entity:capsule(radius, height, x, y, z, rx, ry, rz)    
    local box = self:child()
    box.position = vec3(x or 0, y or 0, z or 0)    
    box.rotation = quat.eulerAngles(rx or 0, ry or 0, rz or 0)
    box:add(physics3d.capsule, radius, height)
    box.mesh = mesh.capsule(radius, height / 2)    
    box.meshMaterial = checkers
    return box
end

function scene:convex(dynamic, msh, x, y, z, s)    
    local teapot = scn:entity()
    teapot.position = vec3(x, y, z)
    teapot.mesh = msh
    teapot.meshMaterial = checkers    
    teapot:add(physics3d.body, dynamic and DYNAMIC or STATIC):mesh(teapot.mesh, true)
    s = s or 1.0
    teapot.scale = vec3(s,s,s)    
    return teapot
end

function scene:torus(dynamic, radius1, radius2, x, y, z)
    local torus = scn:entity()
    torus.position = vec3(x, y, z)    
    torus:add(physics3d.body, dynamic and DYNAMIC or STATIC)
    
    torus:capsule(radius2 - radius1, 1, 0, 0, 0)
    
    return torus
end

function setup()
    scn = scene.default3d()
    local orbit = scn.camera:add(camera.rigs.orbit)
    orbit.angles.x = 4.5
    orbit.angles.y = 45
    orbit.distance = 50
    
    grabber = scn.camera:add(Grabber)    
    cam = scn.camera:get(camera)    
    scn.sun:get(light).intensity = 1.8
    
    parameter.boolean("PhysicsDebugDraw", false, function(b)
        scn.physics3d.debugDraw = b
    end)
    
    parameter.number("TimeScale", 0, 1, 1, function(t)
        time.scale = t
    end)
    
    checkers = material.lit()
    checkers.baseColorMap = image.read(asset.documents.checker_png)
    checkers.roughness = 0.5
    
    compound = scn:entity()
    compound.position = vec3(3, 5, 0)    
    compound:add(physics3d.body, DYNAMIC)
    compound:box(1, 0.1, 1, 0, -.9, 0, 0, 0, 20)
    compound:box(1, 0.1, 1, 0, .9, 0, 0, 0)    
    compound:box(0.1, 1, 1, -.9, 0, 0, 0, 0)
    compound:box(0.1, 1, 1, .9, 0, 0, 0, 0)    
    
    sphere = scn:sphere(true, 0.5, -2.5, 5, 0)
    box = scn:box(true, .125, .5, .125, 0, 5, 0)
    
    
    capsuleA = scn:capsule(true, 0.25, 1, 0, 2, 0)
    capsuleB = scn:capsule(true, 0.25, 1, capsuleA:transformPoint(vec3(0, 1.5, 0)):unpack())    
    capsuleC = scn:capsule(true, 0.25, 1, capsuleB:transformPoint(vec3(0, 1.5, 0)):unpack())        
    local mx, my, mz = capsuleC:transformPoint(vec3(0, 1.0, 0)):unpack()
    monkey = scn:convex(true, mesh.read(asset.builtin.Primitives.Monkey_obj), mx, my, mz, 0.75)
    --monkey:get(physics3d.body).mass = 0.25
    local h1 = capsuleA:get(physics3d.body):hinge(capsuleB:get(physics3d.body), 0, 0.75, 0, 1, 0, 0)
    local h2 = capsuleA:get(physics3d.body):hinge(0, -0.75, 0, 0, 1, 0)    
    local h3 = capsuleB:get(physics3d.body):hinge(capsuleC:get(physics3d.body), 0, 0.75, 0, 1, 0, 0)    
    local h4 = capsuleC:get(physics3d.body):hinge(monkey:get(physics3d.body), 0, 0.75, 0, 1, 0, 0)        
    
    h1.useMotor = true        
    h1.maxTorque = 1
    h1.useLimit = true
    h1.lowerLimit = -125
    h1.upperLimit = 125
    
    h3.useMotor = true        
    h3.maxTorque = 0.5
    h3.useLimit = true
    h3.lowerLimit = -125
    h3.upperLimit = 125
    
    h4.useMotor = true        
    h4.maxTorque = 0.25
    h4.useLimit = true
    h4.lowerLimit = -125
    h4.upperLimit = 125
    
    -- torus = scn:torus(true, 1, 1.5, 0, 5, 0)
    ground = scn:box(false, 10, .1, 10)
end

function update()
end

function draw()
    scn:draw()    
end

function touched(touch)
    return scn:touched(touch)
end

https://youtu.be/3U0YQs4kNnY

scene.save() and scene.read() will crash both.
When I run the example code bellow, it will crash with the line:

    scene.save(asset.documents .. "/myTestSceneEye.scene", scene.main)

but the file myTestSceneEye.scene can be generated successfully.

Then when I try to read the scene file, it will crash.

Test code1:

-- 2D Physics in Scenes
--
-- Adding a body to a scene entity will automatically enable 
-- physics for it. You can use callbacks to tap into various
-- physics features, including hit tests (for touches) and
-- collisions (to react to physical events)

---[=[
viewer.fullscreen()

-- Create and attach an eyeball to something
function eye(x, y, parent)
    local eye = scn:entity()
    eye.parent = parent
    eye.x = x
    eye.y = y
    local c = eye:add(physics2d.body, DYNAMIC):circle(0.25)
    c.sensor = true
    
    -- Draw an eye shape on top of this rigidbody
    function eye:draw()
        matrix.reset().translate(self.position)
        style.push().sortOrder(-3) -- use sortOrder to draw in-front
        style.fill(255)
        ellipse(0, 0, 0.6)
        style.fill(0)
        ellipse(0, 0, 0.45)
        style.fill(255)
        matrix.push().scale(math.sin(time.elapsed * 30) * 0.15 + 1.0)
        ellipse(-.1, .1, .3)
        ellipse(.1, .1, .08)
        ellipse(.1, -.1, .1)
        matrix.pop()
        style.pop()
    end
    
    local p = eye.worldPosition
    local j = eye.body2d:distance(parent.body2d, p.x, p.y, p.x, p.y + 0.1)
    j.minLength = 0
    j.maxLength = 0.125
end

-- Create and attach a leg to something
function leg(name, x, y, parent)
    local leg = scn:entity(name)
    leg.parent = parent
    
    function leg:draw()
        style.push().sortOrder(-1).rectMode(CENTER)
        style.stroke(255).strokeWidth(0.05).fill(24, 50, 239)
        rect(0, 0, 0.6, 0.8, 0.3)        
        style.pop()
    end
    
    leg.x = x
    leg.y = y
    leg:add(physics2d.body, DYNAMIC):box(0.3, 0.4)
    local p = leg.worldPosition
    local j = leg.body2d:hinge(parent.body2d, p.x, p.y + 0.2)
    j.useMotor = true
    j.motorSpeed = 5
    j.maxTorque = 20
end

function setup()
    -- Create a default 2d scene
    scn = scene.default2d()
    scn.physics2d.debugDraw = true
    
    -- cam = scn.camera:get(camera)
    -- cam = camera.ortho(50, -100, 100)
    scn.camera:add(physics2d.grabber)
    
    
    function scn.camera:touched(touch)
    end
    
    floor = scn:entity("floor")
    floor:add(physics2d.body, KINEMATIC):box(8, 0.5)
    
    -- Enable hit test on entity to enable collision checking when receiving touch events
    floor.hitTest = true
    
    -- Simple touch script for dragging around an object
    --[[
    function floor:touched(touch)        
        local delta = touch.delta        
        local px, py = cam:screenToWorld(0, 0)        
        local dx, dy = cam:screenToWorld(delta.x, delta.y)        
        self.x = self.x + (dx - px)
        self.y = self.y + (dy - py)
        return true -- capture touch here
    end--]]
    
    -- New entity
    ball = scn:entity('ball')
    -- Add a physics body and attach a circle collider to it
    ball:add(physics2d.body, DYNAMIC):circle(1.0)
    ball.body2d.fixedRotation = true
    ball.y = 8
    -- Custom entity property
    ball.ouch = 0
    
    function ball:draw()
        style.push().sortOrder(-2) -- draw in front of physics objects
        style.stroke(255).strokeWidth(0.05).fill(221, 85, 142)
        ellipse(0, 0, 2.0)
        
        -- Draw a different expression if recently hit something
        if math.abs(time.elapsed - self.ouch) < 0.5 then 
            -- :O
            style.noStroke().fill(0)
            ellipse(0, -0.2, 0.2)
        else
            -- :)
            style.noFill().stroke(0).strokeWidth(0.1)
            line(-0.1, -0.1, 0.1, -0.1)
        end
        
        style.pop()
    end
    
    -- Respond to collision events
    function ball:collisionBegan2d(hit)        
        -- Play a sound and record when the hit happened
        sound.play(SOUND_HURT)
        self.ouch = time.elapsed
    end
    
    -- Attach all the body parts
    eye(0, 0.5, ball)    
    eye(-0.5, 0, ball)        
    eye(0.5, 0, ball)
    leg("leftLeg", -0.8, -0.8, ball)
    leg("rightLeg", 0.8, -0.8, ball)
    
    -- Create a concave 2D polygon (which is automatically decomposed into convex shapes)
    local points = 
    {
        vec2(-1, 1), 
        vec2(-0.8, 1),
        vec2(-0.5, 0.0),
        vec2(0.5, 0.0),
        vec2(0.8, 1),
        vec2(1, 1),
        vec2(1, -1), 
        vec2(-1, -1),
    }
    poly = scn:entity()
    poly.rz = 80
    poly:add(physics2d.body, DYNAMIC):polygon(points)
    poly.y = 3
    
    scene.main = scn
    scene.save(asset.documents .. "/myTestSceneEye.scene", scene.main)
end

function draw()
    
end

-- #######
-- Grabber
-- #######
-- Add's a touch-based grabber to interact with physics objects
-- Simply add to your scene camera: 
--     scn.camera:add(physics2d.grabber)

local grabber = class('grabber')

function grabber:created()
    self.world = self.scene.world2d
    -- Need the camera for translating touches to world space
    self.cam = self.entity:get(camera)
    -- self.cam.ortho(50, -100, 100)
end

function grabber:touched(touch)
    -- Convert touches from screen to world space using the camera
    local wx, wy = self.cam:screenToWorld(touch.x, touch.y)
    local point = vec2(wx, wy)
    
    if touch.began then
        -- Check for a hit when touches began
        local hit = self.world:queryBox(point, 0, 0)
        -- Ensure the found body is dynamic
        if hit and hit.body.type == DYNAMIC then
            -- Keep track of it and the local point that was grabbed
            self.body = hit.body
            self.anchor = self.body:localPoint(point)
            return true
        end
    elseif touch.moving then
        self.target = point
    elseif touch.ended then
        self.anchor = nil
        self.target = nil
        self.body = nil
    end
end

-- Visualise the grabber force / anchor point
function grabber:draw()
    -- self.cam:apply()
    if self.anchor and self.target then
        matrix.push().reset()
        style.push().noFill().stroke(255).strokeWidth(0.1).sortOrder(-10)
        local wp = self.body:worldPoint(self.anchor)
        line(wp, self.target)
        style.noStroke().fill(255)
        ellipse(wp, 0.2)
        ellipse(self.target, 0.2)
        style.pop()
        matrix.pop()
    end
end

function grabber:fixedUpdate(dt)
    if self.anchor and self.target then
        local wp = self.body:worldPoint(self.anchor)
        local v = self.target - wp
        self.body:applyForce(v * 100 - self.body:velocityAtWorldPoint(wp) * 10.0, wp)
    end
end

physics2d.grabber = grabber

--]=]

Test code2:

-- MyC4

-- Use this function to perform your initial setup
function setup()
    -- scn = scene.default3d()
    -- local sceneKey = asset.documents.."/Test.scene"
    -- sceneKey = asset.documents .. "/myTestSceneEntity.scene"
    sceneKey = asset.documents .. "/myTestSceneEye.scene"
    scn = scene.read(sceneKey)
    
    --[[
    local orbit = scn.camera:add(camera.rigs.orbit)
    orbit.angles.x = 4.5
    orbit.angles.y = 45
    orbit.distance = 50
    
    -- grabber = scn.camera:add(Grabber)    
    cam = scn.camera:get(camera)    
    scn.sun:get(light).intensity = 1.8
    --]]
end

function draw()
    scn:draw()    
end

function touched(touch)
    return scn:touched(touch)
end

@binaryblues What 4.x docs were you referring to on GitHub. This is the one I’ve been looking at. Is there one with more info in it.

https://johntm.github.io/Codea4-Docs/

@dave1707 Looks like another link, but you need to dig into its directory structure to find a lot of interesting test code. After accessing this link, we can assist the developer to update the document and submit it

https://github.com/JohnTM/Codea4-Docs

When I run my project with the new runtime, I get this issue. Is there anything I’m doing wrong/do tabs have to be imported in some way?

If I’m not mistaken, you had a similar issue @skar. Were you able to solve that?

@Elias - might help if you post a little bit of the relevant code.