Jump to content

More amazing things you can do with Lua in Leadwerks 5

Josh

1,382 views

Our implementation of Lua in Leadwerks 5 is shaping up to be a dream come true. Below are some of the great improvements that are being made.

Access STL Containers in Lua

You can access STL containers directly from Lua:

for n = 1, #entity.kids do
	entity.kids[n]:Move(1,0,0)
end
while #entity.kids > 0 do
	entity.kids[1]:SetParent(nil)
end

In fact, verbose commands like CountChildren() and GetChild() are no longer needed at all. On the C++ side you can use this:

for (int n=0; n<entity->kids.size(); n++) {
	entity->kids[n]->Move(1,0,0);
}
while (entity->kids.size()) {
	entity->kids[0]->SetParent(nullptr);
}

Note that in C++ arrays start with 0 and in Lua they start with 1.

This also allows us to return STL contains from functions or accept them as arguments. No more ForEachEntity... callbacks are needed:

local aabb = AABB(-10,10,0,5,-10,10)
local entities = world:GetEntitiesInAABB(aabb)
for n=1,#entities do
	entities[n]:AddForce(0,10,0)
end

Super Pro User-defined Values

There will be no more self.entity or entity.script conventions in Leadwerks 5. Functions and user-defined values will be attached directly to the entity itself. The example below shows user-defined values that persist even when the entity goes out of scope of the Lua virtual machine:

--Create child
local a = CreateBox(world,1,1,1)

--Set a user-defined value
a.health = 100

--Create parent
local b = CreateBox(world,1,1,1)

--Set parent
a:SetParent(b,true)

--Let child go out of scope (parent keeps it from being deleted in C++)
a = nil

--Collect garbage
collectgarbage()

--Get the child
local c = b.kids[1]

--Check the value
print(c.health) --prints '100'

In Leadwerks 4 an entity script might look like this:

function Script:Update()
	self.entity:Turn(self.speed,0,0)
end

In Leadwerks 5 it is simpler because self is the actual entity:

function Entity:Update()
	self:Turn(self.speed,0,0)
end

In Leadwerks 4 you have to check to see if an entity has a script attached and us that to store all user-defined values:

if world:Pick(v1,v2,pickinfo) then
	if pickinfo.entity.script~=nil then
		if type(pickinfo.entity.script.TakeDamage)=="function" then
			pickinfo.entity.script:TakeDamage(10)
		end
	end
end

Leadwerks 5 is a lot simpler. You just check if the functions exists on the entity and then call it:

if world:Pick(v1,v2,pickinfo) then
	if type(pickinfo.entity.TakeDamage)=="function" then
		pickinfo.entity:TakeDamage(10)
	end
end

You can even assign custom properties to entities without worrying whether they have a script attached:

function Entity:Collision( collidedentity, position, normal, speed )
	collidedentity.lasthitobject = self --No script? No problem!
end

In fact all a script does is attach some functions and values to an entity and then it is gone. There is no fundamental difference between a scripted and non-scripted entity.

Casting Objects

Casting objects in Leadwerks 4 uses syntax that is a little awkward. I actually had to look up the tolua.cast function just now because I couldn't remember the order of the arguments:

local a = Model:Box()
local b = Model:Box()
a:SetParent(b)
local entity = b:GetChild(0)
local model = tolua.cast(entity,"Model")

Casting is simpler and more intuitive in Leadwerks 5:

local a = CreateBox()
local b = CreateBox()
a:SetParent(b)
local entity = b:kids[1]
local model = Model(entity)

If the entity is not a model then the casting function will just return nil.

A big thanks goes out to the developers of sol2, an awesome modern Lua binding library with support for C++11 smart pointers.

  • Like 2


6 Comments


Recommended Comments

Incidentally, this would be better for really large numbers (thousands) of children because it removes objects from the end of the vector.

while #entity.kids > 0 do
	entity.kids[#entity.kids]:SetParent(nil)
end

I am also looking into creating a new version of std::vector where the [] operator is read-only, since changing the entity kids elements could cause serious problems.

Share this comment


Link to comment

That looks amazing! There is so much overhead disappearing this way. Looking forward to using it.

So you would get something like this?

--le4
Script.playerEntity = nil --entity
local playerScript = nil

function Script:Start()
	--Get the script of the  referenced player entity and call its hello function
	playerScript = self.playerEntity.script
	playerScript:Hello()
end

--le5?
Script.playerEntity = nil --entity

function Script:Start()
	self.playerEntity:Hello()
end

 

Share this comment


Link to comment

I actually find it a little disorienting after being so used to the le4 way of doing things but I love the simplicity.

Share this comment


Link to comment

I think you are right about that. Our brains are all wired up to using these standard layouts after so long. Still, I see it as a positive evolution of the code.

Share this comment


Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Blog Entries

    • By Josh in Josh's Dev Blog 6
      A new build is available on the beta branch on Steam.
      Updated to Visual Studio 2019. Updated to latest version of OpenVR and Steamworks SDK. Fixed object tracking with seated VR mode. Note that the way seated VR works now is a little different, you need to use the VR orientation instead of just positioning the camera (see below). Added VR:SetRotation() so you can rotate the world around in VR. The VRPlayer script has rotation added to the left controller. Press the touchpad to turn left and right. Any arbitrary rotation will work, including roll and pitch. Here are the offset commands:
      static void VR::SetOffset(const Vec3& position); static void VR::SetOffset(const float x, const float y, const float z); static void VR::SetOffset(const float x, const float y, const float z, const float pitch, const float yaw, const float roll); static void VR::SetOffset(const Vec3& position, const Vec3& rotation); static void VR::SetOffset(const Vec3& position, const Quat& rotation); static Vec3 VR::GetOffset(); static Vec3 VR::GetRotation(); static Quat VR::GetQuaternion();  
    • By tipforeveryone in tipforeveryone's Blog 15
      I spent a whole week for learning UE4 with cpp, yep, UE4 is a great engine for sure, but I found out that my mind could not understand the way UE4 works easily. It is too complex and made me tired. Then I returned to my Leadwerks project and felt so familiar. Soooo... sweet, everything is simple as it is
      It felt like I have had a long trip to UE city then return to my hometown. I miss Leadwerks indeed.
      Last year, I thought I could only use Leadwerks with LUA and never touch its CPP side. But I tried my best, learned Cpp for 8 months. Now I am not a cpp pro but I am confident in using this language. At least I can rewrite my whole project in CPP instead. this 3-years project helped me to understand my potential and interest in gamedev.
      I wish Josh be successful in progress of making Turbo, a new hope for much better Leadwerks.
      To all people who are using Leadwerks and help me these years, love you.
      ...
      Peace!
    • By Marcousik in Marcousik's Creations Blog 1
      I updated the moto I was working on and now the physics let having fun with this.
       
×
×
  • Create New...