Codea 2.2 Beta

@SkyTheCoder @JakAttak interesting. They are not supposed to get out of the examples collection. I wonder if they just appear to be going back there as part of the transition, but aren’t really.

@Andrew_Stacey generally it means no drawing, setContext would be affected too. I believe we have always disabled setContext during the validation phase.

Every rendering, sound, and data function is disabled during this phase. That is, all rendering commands, show/hide keyboard, recording, restart, close, print, parameters, read/save data, open url, alert, and some others.

@Simeon It may just be that I’ve never used setContext before setup. I ran into the shader issue because there are a couple of things where I have all objects sharing the same mesh (and same shader) for efficiency so I set up the mesh when the tab is run. Now, it seems, I’ll have to put that into the initialisation for when the objects are created.

I wonder what the most efficient way to do that would be. One way would be to have a flag which is tested when each object is created and which is false initially but set to true after the first object. Another would be to have an initialisation function which destroys itself after it is run.

INITIALISE = true
local function doinit()
    -- do lots of complicated stuff
    INITIALISE = false
end

function Class:init()
    if INITIALISE then
        doinit()
    end
end

versus

local function doinit()
    -- do lots of complicated stuff
    doinit = function() end
end

function Class:init()
    doinit()
end

Actually, I guess the most efficient would be to rewrite the class initialisation function.

function Class:init()
    -- do lots of complicated stuff that only needs to be done once
    self:_init()
    Class.init = Class._init
end

function Class:_init()
    -- do the stuff that needs to be done every time
end

@Andrew_Stacey I see, so in the past you had a global mesh with shader and then had classes which all used it.

You could try a singleton pattern, that’s a fairly readable method:

--# Singleton

Singleton = class()

local _instance

function Singleton:init()
    -- Do complex initialisation
    self.value = 2 + 2
end

function Singleton.shared()
    if not _instance then
        _instance = Singleton()
    end
    
    return _instance
end


--# Main

function setup()

    print( Singleton.shared().value )
    
end

```


(Where `Singleton` is named more appropriately for your use, e.g., `MeshManager` or something)

I’m seeing some issues with dependencies. Some methods of objects in dependencies are returning nil, or throwing errors as if the function doesn’t exist. Copy the class back to the current project, and everything is fine. Move it out to the library, and suddenly some (but not all) methods of the class seem to throw errors. Oddly enough, the attributes of the object are fine.

Trying to make a neat example, but the only place it’s popping up is a large project with a total of 46 tabs (which don’t redefine the classes in question or have references to yet more libraries – I checked)

location.available() isn’t reliable. It will often return false even when called after location.enable() and when location readings are working fine.

@Mark hmm, this is what we are actually checking for on the available() call:

abailable = ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized &&
        [CLLocationManager locationServicesEnabled])

We should probably also check for kCLAuthorizationStatusAuthorizedWhenInUse which is new in iOS 8. I will fix this in 2.2.

@Simeon Here’s another fun one. I have code on one iPad running 2.2. (1). This code runs fine. The code includes a large project and two libraries. All good.

However, I copied each project to text and emailed them to the second iPad then restored the libraries and projects using Paste Into Project. This iPad is running 2.1 (24). The code will not run. It’s throwing errors on functions of parent classes. For added fun, the properties of these same classes still hold the correct values.

As an example, the Frame class has Frame.init(x, y, w, h) and a Frame:right() which returns x + w.

The SettingsBox(Frame) class is defined with SettingsBox.init(x, y, w, h) and with the first line of the init being Frame.(self, x, y, w, h)

If I define s = SettingsBox(10, 10, 100, 100) I can still reference s.x and get 10. But if I call s:right() on the iPad running 2.2(1) I get 110, while on the iPad running 2.1(24) I get nil.

Since I did a copy paste to get onto the 2.1(24) iPad, I’ve looked for the obvious things – tab order, or any visible extra/missing characters. So far as what is visible to me, both are identical.

It seems to be some kind of dependency tangle. Project 1 uses library 1 and library 2. Library 1 also uses library 2.

One the first iPad, everyone is happy. On the second iPad, Library 1 throws an error when I run Project 1… making me suspect it’s “compiling” before library 2… but there seems to be no way to change the dependency order.

Does any of that make sense?

@Mark the dependency order is stored in the info.plist within the project (as an array, I think). Perhaps you could try swap the order and see if that resolves the issue?

@Simeon, have you had a chance to look into the runtime physics bug I mentioned? It’s all that’s keeping me from releasing my game.

It seems to happen when the following conditions are met:

  • having the gamecenter addon enabled

  • having the collide function somewhere in your code

  • applied force to a body

  • that body collides with another body

Here is some example code that causes the problem:

function setup()
    ball = physics.body(CIRCLE, WIDTH / 20)
    ball.x, ball.y = WIDTH / 2, HEIGHT / 2

    wall = physics.body(EDGE, vec2(WIDTH, 0), vec2(0, 0))

    ball:applyForce(vec2(100, 100))
end

function draw()
    background(255)

    ellipse(ball.x, ball.y, ball.radius * 2)
end

function collide(c)

end

If you paste that into main and enable the gamecenter addon, the error should come up

Thanks!

EDIT: Logged on the Issue Tracker for you

Going a bit further, I tracked it to this line:

luaL_openlib(L, GAMECENTER_LIB_NAME, gamecenterLibs, 0);

I’m not sure why that line (in conjuction with all the conditions above) causes a problem, but to fix it I replaced it with these:

 lua_register(L, "gamecenter_enabled", gamecenter_enabled);
 lua_register(L, "gamecenter_showLeaderboards", gamecenter_showLeaderboards);
 lua_register(L, "gamecenter_showAchievements", gamecenter_showAchievements);
 lua_register(L, "gamecenter_submitScore", gamecenter_submitScore);
 lua_register(L, "gamecenter_submitAchievement", gamecenter_submitAchievement);

which changes the lua API a bit but not much

Not sure what the problem was, or how great my solution is, but it seems to work so far.

EDIT:

Another issue: the way you were getting the numbers from Lua was not getting them correctly. Replace code like this lua_Number percent = luaL_checknumber(L, 2); with this double percent = atof(lua_tostring(L, 2)); and it should work correctly.

Thanks for the detective work @JakAttak. I suspect something funny is happening to the Lua stack in the physics code. I will debug.

Odd that it wasn’t getting numbers correctly, what was luaL_checknumber doing to the numbers?

@Simeon, most of them came out as 0 or as something enormous like 218361376736.1972393898.

@JakAttak very strange. On both the simulator and device? Is this through looking with the debugger?

@Simeon, yes both on device and simulator. I did a print in lua and an NSLog in C of the value to figure this out, the print returned the correct value, the NSLog returned the wacky one

Sorry, I can’t really check out the beta, since I’m renting out my iPad to people, but if I get a chance before release, I’ll be sure to test it out. Thanks!

@JakAttak can you give me a very simple example e.g., using the existing game center addon or something like that, which prints out a bad value in C?

@Simeon, in the submitAchievements function, percent will print out a bad value in C

@Simeon - apparently, this code used to work in previous versions

S = shader([[ //vertex code]], [[ //fragment code]])
m.shader = S

Now it throws a shader compilation error, seemingly because Codea doesn’t like shader objects that are independent of a mesh.

It can be fixed by rewriting S as a table of strings, and then assigning a shader to the mesh, using those strings - which has been the usual way to embed shaders in code.

S = {v=[[ //vertex code]], f=[[ //fragment code]]}
m.shader = shader(S.v, S.f)

See this thread for actual code examples

http://codea.io/talk/discussion/6034/shader-compile-error

Thank you @Ignatz

It depends where the shader is constructed. If it happens in the global scope, then there will be a shader compile error because there is no GL context setup at that time.

We should defer the actual shader compilation until later, but at the moment the best fix is to construct your shaders in setup() and not out in the global scope.

e.g.,


function setupShaders()

    myShader = shader("void main(){}", "void main(){}")

end

function setup()

    setupShaders()

end

-- If setupShaders is called out here, there will be a compile error
setupShaders()