![]() |
![]() |
#1 |
Historian
Join Date: Jan 2004
Location: Surrey
Posts: 313
|
![]()
One of the TEN features is the implementation of Lua scripts, they require some programing knowledge, but definitelly will open the door to new frontiers.
Along this topic, I would like go sharing small tutorials here and there. I think that showing how to do things, can help people to use Lua in their levels, and eventually for them to do also their own scripts. If you’ve got any doubt, suggestion or feedback, you are free to ask here too. We know Lua may looks a bit intimidating so I hope this topic can help to feel more confortable with this new workflow. Extra documentation: Official Lua for TEN documentation Basics of Lua Programming (Update) Tomb Engine Lua Puzzle Setups TRLE levels adapted for TEN Index: NEWS: 12 - 08 -2022: The Basics of Lua programming has been updated, you can check more in this post. 07 - 08 -2022: Lua for TEN documentation and tutorial Basics of Lua programming, have been published, check more information in this post.
__________________
Living and Left :) Last edited by adngel; 21-08-22 at 13:58. |
![]() |
![]() |
![]() |
#2 |
Historian
Join Date: Jan 2004
Location: Surrey
Posts: 313
|
![]() Adding new levels to my game The first we are going to do, is modify our gameflow script to can include our new level. (Or the many levels that we want). What are these Lua files? In the TombIDE program, you can find your lua files pressing the third button on the left panel: ![]() In your Scripts folder, you will find these files, they are part of the Ten system. (You need them, you can edit them, but not delete them). ![]()
Apart of these ones, then there are some extra Lua files dedicated to each level, for example, you have there Title.lua and TestLevel.lua. So what do I need to add in these scripts to have a new level? To add a new level, you must do three things.
Creating the Level block in Gameflow The script may look complex at first sight, but if you take a more general look, you can see that there are some 3 areas in this script. ![]()
So you can add your next level block at the end of the list. The level block has this minimal structure: Code:
Level1 = Level.new() Level1.nameKey = "L0_Title" Level1.scriptFile = "Scripts\\l_LaraGym.lua" Level1.ambientTrack = "108" Level1.levelFile = "Data\\LaraGym.ten" Level1.loadScreenFile = "Screens\\rome.jpg" Flow.AddLevel (level1) Please not the word in blue, this must be unique for each level, I think an easy way to do that is just calling Level1 the first level, Level2 the second, etc.. Filling the level block: - nameKey Is the name of your level, you must add it to your strings file and put it here. - scriptFile Here is where you will put you Lua level file, we will cover it later. - ambientTrack This is the ambient music that has your level at the begginng, you can find the songs in the folder Engine/Audio - levelFile This is the file of your level, located in the Engine/Data folder. - loadScreenFile This is the image that will appear while your level is loading, you can find and add pictures at the folder Engine/Screens ![]() Adding an string name The strings goes in you String.lua file, so open it and go at the end of the file. Before the bracket close, that's the place to inject your new strings. You can just copy the structure of the previous string and paste it below. Example: ![]() Pay attention to the commas, only the last string don’t need comma at the end, but the rest yes need a comma after the bracket like: },
Adding a new Lua script In TombIDE, you can add a new file pressing the left button of the mouse, on the File Explorer, there you can find the create new file. ![]() In the new window, just put the name of your new file, and choose the lua format. Then press Create. ![]() When you create a new file, this file will be empty, to have a minimal workable level code, you need to add the next lines: Code:
---- FILE: \Levels\l_laraGym.lua LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnControlPhase = function() end LevelFuncs.OnEnd = function() end Put this code in the file you've just created and save it. Finally you can update the scriptFile value in you level block with the address to your lua file. (In my case: "Scripts\\l_LaraGym.lua") Completed Once you've done, you should be able to find your level in the game menu and play it, (although first you must have compiled the Tomb Editor level!) If it fails, the first check should be the log document. (you will find it in Engine\Logs\ ), look for a line that says [error], usually at the end of the document, these logs tends to provide useful information, like the line where your script has failed. (It can be for the lack of a comma, for a misspelled word, etc...) Extra features That provided code, was quite minimal, there are more elements that you can add to your level block, like horizon, sky layer, fog, weather, etc... You can find all the features in the documentation. (You can download from this git hub: https://github.com/Stranger1992/Tomb-Engine-Demo-Levels ) For example: Code:
Level0 = Level.new() Level0.nameKey = "l0_Title" Level0.scriptFile = "Scripts\\Levels\\l_LaraGym.lua" Level0.ambientTrack = "108" Level0.levelFile = "Data\\LaraMoves.ten" Level0.loadScreenFile = "Screens\\rome.jpg" Level0.horizon = true Level0.weather = 2 Level0.weatherStrength = 1 Level0.layer1 = Flow.SkyLayer.new(Color.new(72, 80, 96), 5) Level0.fog = Flow.Fog.new(Color.new(32, 56, 64), 5, 20) Flow.AddLevel(Level0)
__________________
Living and Left :) Last edited by adngel; 12-08-22 at 09:26. |
![]() |
![]() |
![]() |
#3 |
Explorer
Join Date: Nov 2019
Location: Polska
Posts: 869
|
![]()
In addition to that, in that repo, you will find my Lua basics tutorial which will teach you Lua from basics. I encourage you to read it.
Both my tutorial and Squidshire's documentation will be regularly updated so check often! I am aware that my Lua tutorial has information that does not reflect some stuff (for example volume triggers) I will update accordingly this week to reflect those changes ![]() Stay tuned for more and happy learning. I am extremely curious of what you will guys create with Lua ![]()
__________________
Chronicles Lara: "Whatever" |
![]() |
![]() |
![]() |
#4 |
Historian
Join Date: Jan 2004
Location: Surrey
Posts: 313
|
![]()
I've put the link to the repo in the first message.
To can see the documentation, you have to download it (press the green button named "code" and select Download ZIP). One inside the folder, you can find the TRLE projects for Lua and a folder named Lua tutorial / docs. Open the file index.html (in any internet browser) and there you can find several information about using Lua for TEN.
__________________
Living and Left :) Last edited by adngel; 07-08-22 at 23:28. |
![]() |
![]() |
![]() |
#5 |
Historian
Join Date: Jan 2004
Location: Surrey
Posts: 313
|
![]() Making functions for showing text Today I want to explain how to create functions and how to link them with the level of Tomb Editor, for that, we will use simple functions that only will print a line of text. Learning about Functions: Once you’ve got your level, you also will have a lua file dedicated to that level, that document is where we write the functions. ![]() As we remember, our level code starts like this: Code:
LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnControlPhase = function() end LevelFuncs.OnEnd = function() end
These are the default level functions, but you can create more. I’ll add two here: Code:
LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnControlPhase = function() end LevelFuncs.OnEnd = function() end m_Util = require("Util") m_Util.ShortenTENCalls() LevelFuncs.PrintTextVolume = function() local text = "Function Text Volume Activated" local string = DisplayString(text, 100, 100, Color.new(250,250,250)) ShowString(string, 5) end function PrintTextFunc () local text = "Function Text Function Activated" local string = DisplayString(text, 100, 200, Color.new(250,250,250)) ShowString(string, 5) end Code:
LevelFuncs.FunctionName = function() . . . end Code:
function FunctionName () . . . end About the content, you can see is mostly similar in both cases.
In order to can use the TEN specifict functions, (like DisplayString and ShowString), is necessary we call also a module, that what these two lines are doing: m_Util = require("Util") m_Util.ShortenTENCalls() But, we will talk about modules another day. For now, copy these functions in your level and save the file. Linking the level lua file to the Tomb Editor: Open your level in Tomb Editor. The first step we must do to can call your Levelfuncs in the level, is link the level lua file with your level Tomb Editor project. So we have to open the Level Settings (in the Tools Tab of the top). ![]() Once in the level settings, go to the Misc area, and fill the Lua slot with your level lua file. Then save your project to avoid this step in the future. ![]() Creating a Trigger Volume: After linking the file, Tomb Editor has access to the functions you write in the Lua file. But to activates the level, you need a trigger volume. To create a trigger volume, select a group of tiles, and press the key V. (You can press Ok in the window for now). ![]() That pink cube, is a new version of trigger, you can move, rotate and scale. If you select it and press the key O, you will open the edition window. ![]() In this window we create the eventriggers that will link to our code functions.
![]() If everything has gone well, we will be able to see our text line every time we step in the volume. ![]() Calling a functions from another code: That was the way to activate the Levelfunc function, but how do we call the traditional function? As we told, it has to be done from Lua, for example, we are going to add the call in the function Start() so our traditional function print its text at the beggining of the level. Code:
LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() PrintTextFunc () LevelFuncs.PrintTextVolume () end LevelFuncs.OnControlPhase = function() end LevelFuncs.OnEnd = function() end m_Util = require("Util") m_Util.ShortenTENCalls() LevelFuncs.PrintTextVolume = function() local text = "Function Text Volume Activated" local string = DisplayString(text, 100, 100, Color.new(250,250,250)) ShowString(string, 5) end function PrintTextFunc () local text = "Function Text Function Activated" local string = DisplayString(text, 100, 200, Color.new(250,250,250)) ShowString(string, 5) end You can see that I also put the function LevelFuncs.PrintTextVolume in there, that's to show you can call LevelFuncs also from Lua too. Save the file, and run your level, (you don’t need to recompile your level to see your the Lua changes). If everything is ok, we should be able to see both lines at the beggining of the level. ![]() Calling a functions with arguments: To end this day lesson, I’ll show about sending arguments to the function. Sometimes we may want to use the same function, but with a little small change, (a different timer, a different object, a different password, etc...) to do that, we use arguments. We are going to read some arguments and print them on the screen. In the Tomb Editor, we’ve already seen that there is a box to type arguments for our functions, we are going to put something there, it can be a number, or a word. I’ll type chocolate. ![]() Although we must do some changes in our code to can read that. Take a look in the next version of the code. Code:
LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() PrintTextFunc ("Vainilla") end LevelFuncs.OnControlPhase = function() end LevelFuncs.OnEnd = function() end m_Util = require("Util") m_Util.ShortenTENCalls() LevelFuncs.PrintTextVolume = function( triggerer, arg ) local text = "Function Text Volume Activated likes " .. arg local string = DisplayString(text, 100, 100, Color.new(250,250,250)) ShowString(string, 5) end function PrintTextFunc ( arg ) local text = "Function Text Function Activated likes " .. arg local string = DisplayString(text, 100, 200, Color.new(250,250,250)) ShowString(string, 5) end
Although we are not using the triggerer in this function, we have to put it becaues the order is important, the arguments in LevelFuncs functions, are the second input value. That’s why we have to put triggerer first. Once we’ve got the argument variable in the parameters (inside the bracket), we can use it inside that function, for example, the text I’m sending, is a combination of the written line "Function Text Function Activated likes " and whatever is in the argument arg. (Check that I useed the double points .. to combine both words). But we don’t always need the volumes to set arguments, we can sent arguments directly to our traditional functions too, we just need to put the value, in the brackets when we call the function. In this same code, look at the call in OnStart function, We keep calling our traditional function but we are sending the word "vainilla", (We put the " to make the program knows that is a text, not a variable). The traditional functions do not have triggerers, so we don’t need to put it on the parameter, that’s why I put directly arg, and used it in a similar way I did on LevelFuncs. Now, if we save the code and run the level, we should be able to see ours texts using the words we send. ![]() ![]() Using arguments with the functions is also a very useful feature which definitely we will use in our codes. /---------------------------------------/ I hope you find this lesson useful, please if you’ve got any doubt or issue, feel free to ask.
__________________
Living and Left :) Last edited by adngel; 08-08-22 at 13:51. |
![]() |
![]() |
![]() |
#6 |
Explorer
Join Date: Nov 2019
Location: Polska
Posts: 869
|
![]()
Hi!
Lua Tutorial has been updated! Here is the changelog: 1.1 - Improve grammar and elaborate some stuff (Thanks Sezz). - Reflected Volume triggers section. 1.2 - Added a new section called: Small example scripts which provides some basic example stuff. You can download the lua tutorial using Adngel's google drive (if you want to see the tutorial online), view it in github repo: https://github.com/Stranger1992/Tomb...a-Basics-Guide, or download from dropbox: https://www.dropbox.com/sh/7rsxm45u4...Qc8f426da?dl=0 (to have a local copy for yourself)
__________________
Chronicles Lara: "Whatever" Last edited by Kubsy; 21-08-22 at 13:42. |
![]() |
![]() |
![]() |
#7 |
Historian
Join Date: Jan 2004
Location: Surrey
Posts: 313
|
![]()
My third pack about the modules is having more changes so it will take a few more delay.
But I wanted to shared these code that covers a couples of things I was asked: - How to rotate a static object - How to send several arguments with the volume trigger. A level lua code. Code:
----------------------- -- Level Global vars ----------------------- DeltaTime = 0.0 ----------------------- -- Main Functions ----------------------- LevelFuncs.OnStart = function() InitializeModules () end LevelFuncs.OnControlPhase = function(dt) DeltaTime = dt end LevelFuncs.OnEnd = function() end LevelFuncs.OnLoad = function() InitializeModules () end LevelFuncs.OnSave = function() end function InitializeModules () --Utils m_Util = require("Util") m_Util.ShortenTENCalls() end ----------------------- -- Level Functions ----------------------- --Rotating Object LevelFuncs.RotateMyObjectUpdate = function (Trigerer, Argument) local ParameterValues = SplitString (Argument) local objectName = ParameterValues[1] local rotSpeed = ParameterValues[2] * DeltaTime myObject = GetStaticByName(objectName) local newRotation = Rot1_myObject:GetRotation().y + rotSpeed myObject:SetRotation(Rotation.new(0, newRotation, 0)) end function SplitString (inputstr, sep) if sep == nil then --If there is not a separator, then use spaces as separator. sep = "%s" end local t={} for str in string.gmatch(inputstr, "([^"..sep.."]+)") do table.insert(t, str) end return t end Argument: RotatingStatue 30 Two words separated by an space, so later, every word will be a different value. You'll see, jumping back to our code, the function RotateMyObjectUpdate also takes the usual triggerer and args, but then, we use the function SplitString to separate the words. And later, put all those words in a new table. What are these table? think on them like arrays, a chain of data that you can access later calling them with its right bracket. So If the string is "RotatingStatue 30" After passing through the function, our ParameterValues table will have ParameterValues [1] = "RotatingStatue" ParameterValues [2] = "30" We can use them, but I like to translate that data into other variables with better name. objectName and rotSpeed. In that way, I could bring multiples values from the VolumeTrigger onto my function. About the object rotation, I hope the rest get easier to understand. Because I'm rotating for several frames, I'm calling this function in onUpdate or WhenInside the volume trigger. Then it reads the current rotation of the object, and adds a speed. (the number of degrees that should move in a 1 second). P.S. Don't ignore the DeltaTime, it's important. (A story for another day), just check this is defined at beggining of the code, and updated in the OnControlPhase function.
__________________
Living and Left :) Last edited by adngel; 24-08-22 at 19:25. |
![]() |
![]() |
![]() |
#8 |
Explorer
Join Date: Nov 2019
Location: Polska
Posts: 869
|
![]()
Creating an ammo counter in Lua
(Based on tutorial from l.m. at trlevel.de https://www.trlevel.de/lexicon/index...-ammo-counter/ picture and code credits go to him) Hi guys ![]() ![]() you need: - a basic understanding of how variables works - a basic understanding of how decision-making works (if else statement work) - a basic understanding of logical operators (and, or, not but this code uses not only) - TEN 1.0.3 due to new lua commands introduced in this version. If you don't know what are variables and/or decision-making then I recommend reading this tutorial: https://github.com/Stranger1992/Tomb...a-Basics-Guide note: Unfortunately this is not possible with node editors, due to the fact that they are designed for room-based events and this tutorial uses OnControlPhase() which is necessary if you want the counter to appear throughout the game. ok let's dive in. The script to make the ammo counter is as follows: Code:
LevelFuncs.OnControlPhase = function() ShowAmmoCounter() end function ShowAmmoCounter() local holdWeapon = Lara:GetHandStatus() local ammoMessage = DisplayString("Ammo: " .. Lara:GetAmmoCount(), 100, 300, Color(0,255,128), false) if (Lara:GetAmmoCount() == -1) then unlimited = true else unlimited = false end if not unlimited then if holdWeapon == 4 then ammoMessage:SetKey('Ammo: ' .. Lara:GetAmmoCount()) ShowString(ammoMessage) else HideString(ammoMessage) end end end Code:
LevelFuncs.OnControlPhase = function() ShowAmmoCounter() end the ShowAmmoCounter() is to call the function. Fyi: of course you could copy paste the entire code to the OnControlPhase function however I wouldn't recommend this because you will probably have lots of things being checked every game frame and so it's easier to split those pieces of codes into subprograms (functions) ![]() Code:
local holdWeapon = Lara:GetHandStatus() local ammoMessage = DisplayString("Ammo: " .. Lara:GetAmmoCount(), 100, 300, Color(0,255,128)) The second variables stores the the message itself into a ammoMessage variable where: - The operator ".." is used to concatenate (join) the strings together - 100 = x (horizontal) position of the text - 300 = y (vertical) position of the text - Color(0,255,128) = creates a colour of the text with the r = 0, g = 255, b = 128. Note: A disadvantage using raw values (100, 300) is that the text may not be shown or misaligned depending on the player's resolution. you should therefore try to use a command PercentToScreen(x,y) which takes in a percentage (say 50 for x and 50 for y) and returns a pixel coordinate of the screen which will align nicely depending on the resolution. More on this and an example here: https://lwmte.github.io/1%20modules/...ercentToScreen Code:
if (Lara:GetAmmoCount() == -1) then unlimited = true else unlimited = false end Code:
if not unlimited then if holdWeapon == 4 then ShowString(ammoMessage) else HideString(ammoMessage) end end end In this case for every weapon except pistols (unless you write a code to make shotgun have unlimited ammo for example) this if statement will be true (note the not which is a logical operator). So because the ammo for pistols is unlimited, then the if statement is skipped entirely and string will not be shown/hidden. holdWeapon == 4 this checks if Lara's hand status is 4. According to the API document (2) the status is as follows: Code:
1=Busy(climbing,etc), 2=WeaponDraw, 3=WeaponUndraw, 4=WeaponInHand. if Lara is holding the weapon, then the variable ammoMessage will be print onto the screen. If not then the message will be hidden so that it is not shown constantly. Note: you can of course make your code more readable, for example instead of having holdWeapon == 4 you could add a new variable with a string in it and then check for equality. For example Code:
local isHoldingWeapon = 4 holdWeapon == isHoldingWeapon This is the end of the tutorial, now you will be able to draw a message onto the screen to show the current ammo count for each weapon ![]() references: 1) https://lwmte.github.io/2%20classes/...t:GetAmmoCount 2) https://lwmte.github.io/2%20classes/...:GetHandStatus https://www.trlevel.de/lexicon/index...-ammo-counter/
__________________
Chronicles Lara: "Whatever" Last edited by Kubsy; 08-03-23 at 16:07. Reason: editing on the fly |
![]() |
![]() |
![]() |
#9 |
Explorer
Join Date: Nov 2019
Location: Polska
Posts: 869
|
![]()
Turning on Soft Collision for static objects and vice versa
(Based on l.m.'s tutorial from trlevel.de https://www.trlevel.de/lexicon/index...tatics-setzen/ code credit goes to him) https://streamable.com/8vlk49 Tomb Engine has a default hard collision on for all statics. However, there may be cases where you just want to have some statics have soft collision. Well there are 2 ways to achieve this: - Setting soft collision using static slots - Setting soft collision using static's lua name set in Tomb Editor I shall go through the 2 methods. you will need: - basic understanding of array (in Lua they are called tables) - basic understanding of loops (especially nested loop, more on that later) - basic understanding of pairs() function. - Static:SetSolid() command (https://lwmte.github.io/2%20classes/...tatic:SetSolid) again if you don't know anything about the arrays, loops etc then I recommend you to read the tutorial: https://github.com/Stranger1992/Tomb...a-Basics-Guide Setting soft collision using static slots the whole code is as follows: Code:
LevelFuncs.OnStart = function() SetStaticsSoftCollision() end function SetStaticsSoftCollision() local staticSlots = { 0,2,4,5,6,7,11,12 } for _, staticSlot in pairs(staticSlots) do local statics = GetStaticsBySlot(staticSlot) for _, static in pairs(statics) do static:SetSolid(false) end end end Code:
LevelFuncs.OnStart = function() SetStaticsSoftCollision() end Code:
local staticSlots = { 0,2,4,5,6,7,11,12 } Code:
for _, staticSlot in pairs(staticSlots) do local statics = GetStaticsBySlot(staticSlot) for _, static in pairs(statics) do static:SetSolid(false) end end end the outer loop Code:
for _, staticSlot in pairs(staticSlots) do local statics = GetStaticsBySlot(staticSlot) in the pairs() brackets you are passing staticSlots table variable for the loop to iterate through, the staticSlot is used to access the numbers in the table. You don't need to worry about index variable as it just accesses the index of the number in the table so you don't need to worry about it (index of digit 0 is 1, digit 2 is 2 and so forth). note: if the index is never used/referenced then instead of index you can use an underscore _ hence from: Code:
for index, staticSlot in pairs(staticSlots) do local statics = GetStaticsBySlot(staticSlot) Code:
for _, staticSlot in pairs(staticSlots) do local statics = GetStaticsBySlot(staticSlot) Code:
for _, static in pairs(statics) do static:SetSolid(false) pairs(statics) loops through the table statics when we assigned them to GetStaticBySlot. we then reference each with static and setting them to soft collision static:SetSolid(false) Setting soft collision using static's lua name The previous method is great because we can make every static in the slot to have soft collision. However, now you may ask: "But what if I DON'T want every static in the same slot to have soft collision? I want some of them to have hard collision." Well this is also doable: Code:
LevelFuncs.OnStart = function() SetStaticsSoftCollision() end function SetStaticsSoftCollision() local SoftCollisionStatics = { "static_mesh_433", "static_mesh_399", "static_mesh_398" } for _, value in pairs(SoftCollisionStatics) do local static = GetStaticByName(value) static:SetSolid(false) end end note: the strings must be comma separated as you see in the above example (to change object's lua name: right-click on the object -> rename object -> type the lua name you want the object to have for example: "static_mesh_5" to "wooden pedestal") Thanks for reading the tutorial ![]() references: - https://lwmte.github.io/2%20classes/...tatic:SetSolid - https://www.trlevel.de/lexicon/index...tatics-setzen/
__________________
Chronicles Lara: "Whatever" Last edited by Kubsy; 27-11-22 at 13:11. |
![]() |
![]() |
![]() |
#10 |
Explorer
Join Date: Nov 2019
Location: Polska
Posts: 869
|
![]()
Infinite Boulder
In this tutorial, I will show you how to make an infinite boulder which will be activated infinitely. Code:
spawner = GetMoveableByName("Boulder_spawner") boulder = Moveable(TEN.Objects.ObjID.ROLLINGBALL, "boulder", spawner:GetPosition()) LevelFuncs.OnStart = function() boulder:MakeInvisible() end LevelFuncs.BoulderSpawn = function() boulder:Enable() end LevelFuncs.resetBoulder = function() boulder:SetPosition(spawner:GetPosition()) end Code:
spawner = GetMoveableByName("Boulder_spawner") boulder = Moveable(TEN.Objects.ObjID.ROLLINGBALL, "boulder", spawner:GetPosition()) - spawner variable which gets the moveable by its lua name set in Tomb Editor. In this case it's "Boulder_spawner" and a nulllmesh (doesn't matter which slot) - Boulder variable which creates a new boulder via the Moveable() function. To learn more about this function, read here: https://lwmte.github.io/2%20classes/....html#Moveable ---- Code:
LevelFuncs.OnStart = function() boulder:MakeInvisible() end LevelFuncs.BoulderSpawn = function() boulder:Enable() end LevelFuncs.resetBoulder = function() boulder:SetPosition(spawner:GetPosition()) end Boulderspawn function will simply trigger the boulder. ResetBoulder will reset to its initial position using the nullmesh. --- Setup in TE To set this up you need: - nullmesh from any slot - 2 volumes in my test level this looks like this: ![]() the nullmesh at the top acts as a boulder "spawner", the volume to the right makes the boulder trigger (activated by lara), the volume at the bottom resets the boulder position (activated by Other objects - we do not want Lara to reset the position of boulder.). ![]() ![]() Let's see how this looks in game! clicky Notes: - You don't have to use the moveable() function to create the boulder, you can just place it in TE, however there are scenarios that moveable() can be very useful and used in an interesting way. One of the example is making an infinite random enemy spawner: https://github.com/Stranger1992/Tomb...Lua-Scripts#12 That is the end of the tutorial, let me know if you have any suggestions ![]()
__________________
Chronicles Lara: "Whatever" |
![]() |
![]() |
![]() |
Thread Tools | |
|
|