In this tutorial we will make a newcomponent, which will be moving an entity to way points and movement start will be activated by trigger zone
Let's start with making WayPoint component:
In the Ultra Editor click plus button in Project tab:
Now open Visual Studio Code.
Open WayPoint.json
- "properties" is a list of component's fields avaible for edit in the Editor
- "name" - actual name of property that will be used in code later
- "label" - just a name to display in the Editor
- "value" - initial value that property will have after map load by default. Can be changed in the Editor for specific entity.
- "options" - allows to choose int value in Combo Box in the Editor. First option - 0 value
- Default value here also defines type of this property.
- New component made via editor have all possible types.
Replace WayPoint.json content with:
{ "component": { "properties": [ { "name": "nextPoint", "label": "Next point", "value": null }, { "name": "doStayOnPoint", "label": "Do stay on point", "value": false } ] } }
- nextPoint - another WayPoint, where platform will move to once reach this one
- doStayOnPoint - wait for command before moving to next WayPoint
Take a note that the Editor sees only json which could be same for LUA and C++ projects which allows to work on same map even if people have different engine versions (Pro/Standard) or make a level before programming components.
Replace WayPoint.lua content with:
WayPoint = {} -- name should always match class name for correct component work WayPoint.name = "WayPoint" WayPoint.nextPoint = nil -- wait for command before moving to next WayPoint WayPoint.doStayOnPoint = false -- Start is called when Load() of all components was called already function WayPoint:Start() end -- will be called on map load function WayPoint:Load(properties, binstream, scene, flags, extra) -- internally entity saves in the Editor as String unique id -- can be empty if this way point is final if type(properties.nextPoint) == "string" then for _, entity in ipairs(scene.entities) do if properties.nextPoint == entity:GetUuid() then self.nextPoint = entity break end end -- self.nextPoint = scene:GetEntity(properties.nextPoint) if type(properties.doStayOnPoint) == "boolean" then self.doStayOnPoint = properties.doStayOnPoint end end return true end -- Can be used to save current component state on map save function WayPoint:Save(properties, binstream, scene, flags, extra) if self.nextPoint ~= nil then properties.nextPoint = self.nextPoint:GetUuid() properties.doStayOnPoint = self.doStayOnPoint; end return true end -- Can be used to get copy of this component function WayPoint:Copy() local t = {} local k local v for k, v in pairs(self) do t[k] = v end return t end -- needed for correct work, when loaded from a map RegisterComponent("WayPoint", WayPoint) return WayPoint
Let's create our floating object component and call it WayMover
WayMover.json:
{ "component": { "properties": [ { "name": "moveSpeed", "label": "Move Speed", "value": 4.0 }, { "name": "nextPoint", "label": "Next point", "value": null }, { "name": "doDeleteAfterMovement", "label": "Del after move", "value": false } ], "inputs": [ { "name": "DoMove" } ], "outputs": [ { "name": "EndMove" } ] } }
- moveSpeed - how fast entity will move to way point
- doDeleteAfterMovement - auto remove entity when it's reach final waypoint. Can be used for door, that goes into walls or floor
- inputs - it's commands for components, that usually triggered by another components via flowgrough
- outputs - commands that component sends to other components inputs via FireOutputs("EndMove"); in the component code
WayMover.lua:
WayMover = {} -- name should always match class name for correct component work WayMover.name = "WayMover" WayMover.moveSpeed = 4.0 WayMover.isMoving = false WayMover.nextPoint = nil WayMover.scene = nil function WayMover:Copy() local t = {} local k local v for k, v in pairs(self) do t[k] = v end return t end -- will be called on map load function WayMover:Load(properties, binstream, scene, flags, extra) if type(properties.moveSpeed) == "number" then self.moveSpeed = properties.moveSpeed end if type(properties.isMoving) == "boolean" then self.isMoving = properties.isMoving end if type(properties.doDeleteAfterMovement) == "boolean" then self.doDeleteAfterMovement = properties.doDeleteAfterMovement end if type(properties.nextPoint) == "string" then for _, entity in ipairs(scene.entities) do if properties.nextPoint == entity:GetUuid() then self.nextPoint = entity break end end -- self.nextPoint = scene:GetEntity(properties.nextPoint) -- need scene for removing entity on doDeleteAfterMovement condition self.scene = scene return true end end -- Can be used to save current component state on map save function WayMover:Save(properties, binstream, scene, flags, extra) if self.nextPoint ~= nil then properties.nextPoint = self.nextPoint:GetUuid() properties.doStayOnPoint = self.doStayOnPoint; end properties.moveSpeed = self.moveSpeed; properties.isMoving = self.isMoving; properties.doDeleteAfterMovement = self.doDeleteAfterMovement; return true end function WayMover:DoMove() self.isMoving = true end function WayMover:MoveEnd() local doStay = false if (self.nextPoint ~= nil) then doStay = self.nextPoint:GetComponent("WayPoint").doStayOnPoint self.nextPoint = self.nextPoint:GetComponent("WayPoint").nextPoint end if (doStay or self.nextPoint == nil) then self.isMoving = false; self:FireOutputs("EndMove") -- deleting entity if need to, after reaching final way point if (not doStay and self.nextPoint == nil and self.doDeleteAfterMovement and self.scene ~= nil) then --commented out this code for now until bind for RemoveEntity will added --self.scene:RemoveEntity(self.entity) end end end function WayMover:Update() if (not self.isMoving) then return; end local wayPoint = self.nextPoint if (self.entity == nil or wayPoint == nil) then return end --60 HZ game loop, change to own value if different to keep same final speed local speed = self.moveSpeed / 60.0 local targetPosition = wayPoint:GetPosition(true) --moving to point with same speed directly to point no matter which axis local pos = self.entity:GetPosition(true); local distanceX = Abs(targetPosition.x - pos.x); local distanceY = Abs(targetPosition.y - pos.y); local distanceZ = Abs(targetPosition.z - pos.z); local biggestDelta = distanceZ; if (distanceX > distanceY and distanceX > distanceZ) then biggestDelta = distanceX; elseif (distanceY > distanceX and distanceY > distanceZ) then biggestDelta = distanceY; end local moveX = MoveTowards(pos.x, targetPosition.x, speed * (distanceX / biggestDelta)); local moveY = MoveTowards(pos.y, targetPosition.y, speed * (distanceY / biggestDelta)); local moveZ = MoveTowards(pos.z, targetPosition.z, speed * (distanceZ / biggestDelta)); self.entity:SetPosition(moveX, moveY, moveZ) if (self.entity:GetPosition(true) == targetPosition) then self:MoveEnd() end end -- needed for correct work, when loaded from a map RegisterComponent("WayMover", WayMover) return WayMover
Now we can use just made component in practice.
One of things that can be made is door or secret wall activated by player actions and this door will move a little bit inward and then to the side inside of wall. After that invisible now door will be removed.
- Create a walls with a empty place between them.
- Create couple of Empty/pivots and attach WayPoints to them.
- First WayPoint place a same place where door will be, but offset a bit deep into.
- In Scene tab grab and drag 2nd WayPoint to Nex Point field of 1st WayPoint.
- Place 2nd WayPoint insde of the wall.
- Create a door between walls. Attach WayMover component to it.
- Grab and drag 1st WayPoint to door's WayMover Next Point field.
- Enable "Del after Move" in WayMover component
- Create a box before door, make its collision type a trigger:
- Add Collision Trigger component to it.
- Open Flowgraph (2nd button at left side of the Editor).
- Drag and Drop trigger and door to it from Scene tab.
In different order, but same result in video format:
Result should looks something like that in game:
In fast debug mode it might crash at this moment for unkown reason. Use Full Debug or Run mode.
Project files: LuaExample2.zip
Repository: https://github.com/Dreikblack/LuaTutorialProject/tree/2-making-and-using-components
- 1
- 1
0 Comments
Recommended Comments
There are no comments to display.