In-game Scripting (Alpha 0.1) [Besiege v0.08]

spaar

Active Member
#1
Ever wanted to do some in-game programming in Besiege ? Well, now you can (somewhat, we'll get to that).
After this was suggested multiple times in the Suggestions forum, often with the added suggestion that a mod might be better than adding this to the game officially, I set out to create this mod.

Important note: Due to the fact that I have a limited amount of time to spend on creating mods and also need to work on the mod loader and since there is now an alternative availabe, this mod is for now discontinued. If you want a mod that does something very similiar, though probably in a superior way, take a look a Lachcim's Scripting Mod.

Please note that this is only a very early prototype. I wanted to get this out here for people to play with and to see if there is interest in something like this. However, there are currently some essential features missing and what is there is quite possibly somewhat buggy. It will probably impact performance quite a bit as well. Use at your own risk.

I plan on making this open-source relatively soon, if anybody would be interested in the code now, just say so and I will be more than happy to hurry up with that a little bit ;)

Features
Currently, you can create one single script. In there, you can do two things: First, access any method that exists in the game, including any Unity method. This can be quite complex, but is very flexible. Second, create variables, dynamically change their values and use them as value for the slider of blocks (for example the speed of wheels).
Here is a quick video demonstration:

How to use
You can bring up the Scripting window by pressing Ctrl+S. In there you can write your scripts. All scripts are written in Lua, so you can google that for syntax help or if you want to learn how to do some basic programming for this. Lua is interpreted in the game using NLua, which means you can use "import ('namespace')" to import any .Net namespace as well, for example "import ('UnityEngine')". After doing this, you can access any classes and functions that are defined in that namespace from your scripts. The only requirement for your scripts is that they have two functions called "simStart" and "frame". Therefore the basic structure looks like this:
Code:
simStart = function ()

end

frame = function ()

end
simStart will be called everytime the simulation is started, so you can reset variables here and do similiar set-up stuff. frame is called once for every frame, so this is the place to do continuous updating of your variables.
You can only use global variables whose name starts with a 'v' as values in the properties window. These also have to be declared/used outside of any functions once so that the mod will pick them up. After any modifications you make, click the "Parse/Reset" button for the mod to parse the script. Any errors will be displayed in the console, which you can bring up by pressing Ctrl+K.
The last thing to pay attention to is that you need to press the 'R' key once before opening any properties dialog and then again after you have opened one for the first time. You only need to do this once until you restart or possibly until you switch to a different level (not tested).
You will likely encounter all sorts of different issues and bugs, see if somebody already posted them here and if not, feel free to add them. Keep in mind this is only a very early alpha and nowhere near complete.

Example Script
This is the example script used in the video above with some comments to help in understanding it.
Code:
import ('UnityEngine') -- Import the .Net namespace UnityEngine, which contains all classes exposed by Unity. We need this for the input handling later.

vSpeed = 0.0 -- Define vSpeed so the mod can register it

simStart = function () -- This will get called everytime the simulation starts
  vSpeed = 0.0 -- Reset the speed
end

frame = function () -- This will get called every frame while the simulation runs
  if (Input.GetKey(KeyCode.I)) then -- Use Unity's Input class to check if 'I' is pressed
    vSpeed = vSpeed + 0.05 -- if so, increase the speed
  end
  if (Input.GetKey(KeyCode.K)) then -- Now check if 'K' is pressed
    vSpeed = vSpeed - 0.05 -- if so, decrease the speed
  end
end
Installation
The mod requires my mod loader to work, installation instructions are included in the download, in the README.txt file.

Thanks for reading, I hope you have some fun with this, even in its currently very limited form

Attached Files
Besiege Scripting Alpha 0.1.zip
 

ITR

l̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ֍̫̜̥̭͖̱̟̟͉͙̜̰ͅl̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ
Staff member
#4
stellHex said:
Ooooh! Are there any useful references we should know about for UnityEngine?
I wrote a little about them in this blogpost too: (under the fourth spoiler)
http://forum.spiderlinggames.co.uk/b...ur-own-classes

EDIT: nevermind, I think that's the methods, not the other stuff.
Well, anyways, there is some stuff about stuff unity can do on the blog too.
 
#7
spaar i love you ill marry you ill cook for you <3

Any idea how to implement sensors? For example having a reference block and monitoring it's rotation along both x and y axises? A gyroscope, really.
 

ITR

l̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ֍̫̜̥̭͖̱̟̟͉͙̜̰ͅl̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ
Staff member
#8
=Ø= said:
spaar i love you ill marry you ill cook for you <3

Any idea how to implement sensors? For example having a reference block and monitoring it's rotation along both x and y axises? A gyroscope, really.
That should be transform.rotation.[x,y,z], it should give a float between 0 and 360
 

spaar

Active Member
#9
=Ø= said:
spaar i love you ill marry you ill cook for you <3

Any idea how to implement sensors? For example having a reference block and monitoring it's rotation along both x and y axises? A gyroscope, really.
What ITR wrote is correct, but to use that you need to first get a reference to a GameObject. The easiest way to do that is probably via their names, using GameObject.Find("name"). The names follow a certain system: the starting cube is always called bgeL0, the first block you build is called bsg0, the second bsg1 and so on. However, blocks that you loaded with a saved machine, are called bgeL1, bgeL2 etc (I hope this is correct, been a while since I had to use those names)
 

ITR

l̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ֍̫̜̥̭͖̱̟̟͉͙̜̰ͅl̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ
Staff member
#10
Also, deleted blocks keep their names for themselves
 

spaar

Active Member
#11
Right. Actually, I just had the idea of including an easier API for getting a reference to a block in a future version of this mod. Something like clicking on one and then have the mod handle figuring out the name.
 
#12
Damn, I know nothing about lua or the unity engine. However pls take a look at this semi-pseudo code (this is having the starting cube for the actual sensor):

Code:
import ('UnityEngine')
import ('System.Collections')

simStart = function ()

end

frame = function ()

gyro = GameObject.Find ('bgeL0')
coord = transform.rotation [gyro]
print ('coord')
 
end
So I suppose System.Collections should be imported for the GameObject.Find to work.
Then, how exactly do I reference the transform.rotation to the actual object? Besides, this function returns quaternions as far as I've checked and transform.rotate should be used instead, somehow.
And finally "print" doesn't really print in the console, so whatever comes out can't be monitored.
 

spaar

Active Member
#13
Try this:
Code:
import ('UnityEngine')

simStart = function ()

end

frame = function ()
  cube = GameObject.Find("bgeL0")
  rot = cube.transform.eulerAngles
  Debug.Log(rot)
end
So, to get the transform of the actual object, you just do object.transform. Also, you are right, transformation is a quaternion but eulerAngles returns the rotation as three angles, from 0°-360°. And to print to the actual console, just use the Unity Debug class.
 

ITR

l̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ֍̫̜̥̭͖̱̟̟͉͙̜̰ͅl̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ
Staff member
#14
Well, you can see which method I used for the post-place mod, though it's kinda sometimes not working.
 
#18
Finally realized that the reference I needed was GameObject and that I didn't have to look thru the 1025 dropdown items in the Unity documentation.

OK, so anyway, I executed this extremely simple script, to a "Object reference not set to an instance of an object" error:
Code:
import ('UnityEngine')

simStart = function ()
  Debug.Log(GameObject.Find('bgeL0').tag)
end

frame = function ()

end
What am I doing wrong?
 

spaar

Active Member
#19
stellHex said:
What am I doing wrong?
Honestly, I don't know. That snippet works just fine for me and prints "Untagged" to the console. The only object reference there should be what GameObject.Find returns but bgeL0 should always be there AFAIK, except maybe in the menu... but there simStart would never be called.
Could you maybe post the entire error message? You should be able to copy it from the console with Ctrl+C.
 
Top