I am very proud that the Corona scripts are written in my language
What do you mean?
several years ago i showed first time the principle - One tool, one script, one structure
now i see many tools are written this way
its a system where you define tool, it’s interface, callbacks, and macros all in one structure
Hehe… I hv tried many times.
I’m still at THAT level.
Hopefully one day.
can you show it again ?
I have a feeling that on this site it has become completely impossible to find any kind of archive.
Ok. I try to find this topic, and once again show how I design and organize my tools.
If I remember correctly you use single structure and everything else is “inside” this structure - rollout, functions, etc.
I have this code of yours, saved on my PC.
global GeneralSceneOps ( struct GeneralSceneStruct ( fn destroy = try(closeRolloutFloater GeneralSceneOps.dialog) catch(), title = "General Scene Helpers", dialogWidth = 250, dialogHeight = 400, dialog, MatStruct = ( struct MatStruct (material, slot) ), ObjectRollout = rollout ObjectRollout "Objects" ( local owner = if owner != undefined do owner button deleteall_bt "Delete All Objects" align:#left width:(owner.dialogWidth - 30) offset:[-5,0] on deleteall_bt pressed do undo "Delete All" on ( format ">>> %\n" owner delete objects ) ), materials = #(), MaterialRollout = rollout MaterialRollout "Materials" ( local owner = if owner != undefined do owner button collectmats_bt "Collect Editor Materials" align:#left width:(owner.dialogWidth - 30) offset:[-5,0] on collectmats_bt pressed do ( owner.materials = for k=1 to 24 collect (owner.MatStruct (medit.GetTopMtlSlot k) k) format "mats: %\n" owner.materials ) ), rollouts = #(ObjectRollout, MaterialRollout), fn show = ( destroy() dialog = newRolloutFloater title dialogWidth dialogHeight for r in rollouts do addRollout r dialog ), on create do ( destroy() rollouts.owner = this ) ) GeneralSceneOps = GeneralSceneStruct() ok ) GeneralSceneOps.show()
Scope problem with struct - Section Updater Tool
Thanks! that’s a very good example
I categorized all of my scripts like this, But now I have a question. Do you think is it efficient to call a function from structure like this?
Yes. It’s absolutely safe and clear for code reading.
But we all know that ‘accessing’ a struct and struct members take a time and mxs memory allocation. So if you need to call some method frequently or repeatedly it’s better to store a pointer to the method first and you use later in a loop for example.
struct MyStruct ( fn call_method a b = (a*b) ) ( gc() d = MyStruct() t0 = timestamp() h0 = heapfree for k=1 to 100000 do ( d.call_method 100 100 ) format "time:% heap:%\n" (timestamp() - t0) (h0 - heapfree) ) ( gc() d = MyStruct() t0 = timestamp() h0 = heapfree call_method = d.call_method for k=1 to 100000 do ( call_method 100 100 ) format "time:% heap:%\n" (timestamp() - t0) (h0 - heapfree) )
so, looking on the method name (GetBones) it’s ok to call it like MyCompany.MyTools.MySkinTools.GetBones()
because it’s a ‘once-used’ method (it doesn’t really effect performance and memory use)
but a function for example GetLocalVertexNormal which is expected to be used in a loop should be call as:
getLocalVertexNormal = MyCompany.MyTools.PolyMethods.GetLocalVertexNormal <in loop> getLocalVertexNormal ...
in you case the good way to organize own tools could be (how I would do it):
//** base scripts and one file **// global MyLibrary = ( struct MyLibraryStruct ( MathOps = ( struct MathOps ( fn sincos a = [sin a, cos a] ) ), NodeOps = ( struct NodeOps ( fn getName node = if isvalidnode node then node.name else "" ) ) ) ) //** specific tool and another file **// global PolyOptimization ( struct PolyOptimizationStruct ( private my_lib = MyLibrary(), math_ops = my_lib.MathOps(), node_ops = my_lib.NodeOps(), public fn getSceneNodeNames = ( getname = node_ops.getname for node in objects collect (getname node) ) ) global _po = PolyOptimization = PolyOptimizationStruct() ok ) /* _po.getSceneNodeNames() */
i create a global variable “_po” just to help myself with easier debugging. you must not use in the code of course.
use some simple and short name… and don’t care if anyone might overwrite it. any commonly used names should not be used as global names anyway. So you shouldn’t be cake about overwriting someone’s else globals
My methods looks little different.
I first define structures to create something like namespaces in C# at the beginning.
I have only one global MyLibrary.
I create only ONE instance of each structure at the beginning of definition.
So my code look like this:
( global MyLibrary = ( struct _struct ( MathOps,NodeOps,PolyOptimization ) )() MyLibrary.MathOps = ( struct _struct ( fn sincos a = [sin a, cos a] ) )() MyLibrary.NodeOps = ( struct _struct ( fn getName node = if isvalidnode node then node.name else "" ) )() MyLibrary.PolyOptimization = ( struct _struct ( private math_ops = MyLibrary.MathOps, node_ops = MyLibrary.NodeOps, public fn getSceneNodeNames = ( getname = node_ops.getname for node in objects collect (getname node) ) ) )() ok ) MyLibrary.PolyOptimization.getSceneNodeNames()
I’m actually worry about overriding my own functions :), because some times I will develop several tools for one company with different functionality that may have conflict with each other.
that’s exactly why i try to define minimum globals for my tools.
I like this way too. The “namespaces” concept is great, with only one global, and avoiding defining structs inside structs. Very nice. Thanks for sharing.
Another point is I just separated all my tools and functions in two parts: common and specific. common will be updated for all tools which consist of all general functions.
Very instructive topic. Thank you all for sharing your workflows.
I have one small question about DenisT’s script, posted by Miauu.
What is the purpose of defining a local variable like this?
local owner = if owner != undefined do owner
It seems redundant, but probably isn’t, yet I do not understand why.