Difference between revisions of "Basics of Scripting"

From X-Moto
Jump to: navigation, search
(How-to make a trainer script?)
(General)
Line 321: Line 321:
 
If some action doens't work but doesn't crash either try using Game.Message("debug") to see if the script is ever even executed. In X-Moto scripts the '''script must be in an ''[http://wiki.xmoto.tuxfamily.org/index.php?title=Scripting_Dictionary#Event event]''''' otherwise the script is never executed.
 
If some action doens't work but doesn't crash either try using Game.Message("debug") to see if the script is ever even executed. In X-Moto scripts the '''script must be in an ''[http://wiki.xmoto.tuxfamily.org/index.php?title=Scripting_Dictionary#Event event]''''' otherwise the script is never executed.
  
If you get an error with '''line number''' then to find the exact line, '''count''' the script's lines '''ignoring all empty lines''', that is how you should be able to find the correct line, since the script parser removes empty lines before executing the script.
+
If you get an error with '''line number''' then to find the exact line, '''count''' the script's lines '''ignoring all empty lines''' and if you have joined lines with ";" you must break them, that is how you should be able to find the correct line, since the Lua script parser removes empty lines before executing the script.
  
 
== Err. SetDynamicBlockTranslation crashes ==
 
== Err. SetDynamicBlockTranslation crashes ==

Revision as of 05:28, 20 July 2009

Introduction

This tutorial explains how to write clean script and how to make some things. Please see the Dictionary for more information about each keywords.

Clean Script

I've seen horrible scripts. So I decided to make a style guideline here.

Indent

Indenting your script makes it much more readable. Compare the following scripts:

function lol()
if wut==1 then
if lolwut==2 then
Game.KillPlayer()
end
end
end

and

function lol()
    if wut==1 then
        if lolwut==2 then
            Game.KillPlayer()
        end
    end
end

Makes it easier to see if you forget an end for example. ;-)

Comments

You should comment your script so that someone who could be interested how this is done could understand the script, but don't comment too much because that makes the script messy.

...
if somevar==2 then -- here we see if the player plaaplaaplaa...
...

Other

You can use ";" to join lines without linechange

This is okay:

zone1={};visited1=0"

But do not connect too many lines.

Please, do not put if and then on separate lines

if somevar!=something
then
...

Instead:

if lol==1 then
...

Using the () in the if is optional:

if(lol==1)then
...

How-To Section

Here we collect how to scripts. like "How-to make an elevator?" or "How-to make a jump button?"

You can't download example levels because this wiki doesn't allow me to upload .lvl files anymore: "This file contains HTML or script code that may be erroneously be interpreted by a web browser.". I know it sucks. It's just xml with some lua.

How-to make an elevator?

What we need:

  • a dynamic block
  • the block id must be "blockele1"
  • a zone, id "zoneele1"

The Script:

zoneele1={}
function zoneele1.OnEnter() -- when we enter the zoneele it starts the elevator.
    h=10 --height (how much up we go)
    speed=2000 -- how long it takes to go there (speed depends on the h)
    wait=200 -- how long to wait before starting the elevator (200=2s)
    Game.SetDynamicBlockTranslation("blockele1",0,h,speed,wait,wait+(speed/2))
end

You can edit the variables to fit your needs.

How-to make a jump key?

This is easy, it can be done purely with script.

function OnLoad()
    Game.SetKeyHook("J","Jump") -- bind the J key to the Jump function below
    return true
end
function Jump()
    Game.AddForceToPlayer(0,10000,0,10,0)
end

With that script the player can cheat and jump even when on air. We want the player only to be allowed to jump when on ground again. So we need a variable to see if the player has jumped already:

hasjumped=true --you can use 1 as well
function OnLoad()
    Game.SetKeyHook("J","Jump") -- bind the J key to the Jump function below
    return true
end
function Jump()
    if hasjumped==false then
        hasjumped=true
        Game.AddForceToPlayer(0,10000,0,10,0)
    end
end
function OnWheel2Touchs(bStatus) --rearwheel
    if bStatus==1 then -- only when touching not when leaving the ground
        hasjumped=false --we touch the ground so we must be jumped.
    end
end

How-to make zoom buttons?

Zooming is somewhat easy, but it recuires some script to do, I have this old piece of script I got from Lothar's level, I've changed it to be more configurable. You can use it as it is, just remember to leave the comments about the creators of the script there :)

--original script by Lothar
--upgraded by Tuhoojabotti 18.12.2008

--settings
zoomlevel = 1 --default zoom
blockzoom = 0 --enable/disable zoom 0=enabled
zoominbutton="I" 
zoomoutbutton="O"
maxzoomout=4 --strokes
maxzoomin=0 --strokes
step=0.05 --amount of zoom per stroke

function OnLoad()
	Game.Message("Press "..zoominbutton.." to zoom in")
	Game.Message("Press "..zoomoutbutton.." to zoom out")
	Game.SetKeyHook(zoominbutton, "ZoomIn")
	Game.SetKeyHook(zoomoutbutton, "ZoomOut")
	return true
end

function ZoomIn()
	if zoomlevel==maxzoomin then
			Game.ClearMessages()
			Game.Message("Can't zoom in any further.")
	else
		if blockzoom==0 then
			Game.CameraZoom(step)
			zoomlevel = zoomlevel-1
		end
	end
end

function ZoomOut()
	if zoomlevel==maxzoomout then
		Game.ClearMessages()
		Game.Message("Can't zoom out any further.")
	else
		if blockzoom==0 then
			Game.CameraZoom(-step)
			zoomlevel = zoomlevel+1
		end
	end
end

How-to make readable signs?

You need:

  • Entities, like: sign1, sign2, sign3, ...
  • Zones, like: signz1, signz2, signz3, ...
  • a variable to hold the sign texts; SignText=""
  • and a keyhook for the Read function

Zones:

SignText="No signs here..."
signz1={}--;signz2={};signz3={};...

function OnLoad()
   Game.Message("Hello, you can read signs with 'R' key.")
   Game.SetKeyHook("R","Read")
   return true
end

function Read() --read teh sign
    Game.Message(SignText)
end

--repeat this for all zones...
function signz1.OnEnter()
    SignText="This is the Sign1 it says: plaaplaaplaplapal..."
end
function signz1.OnLeave() --this is optional
    SignText="No signs here..."
end
--end repeat block

Somewhat easier way is to use Entity.Touch() event, which doesn't have leave support, but then you can dump the zones.
Entities:

SignText="No signs here..."
sign1={}--;sign2={};sign3={};...

function OnLoad()
   Game.Message("Hello, you can read signs with 'R' key.")
   Game.SetKeyHook("R","Read")
   return true
end

function Read() --read teh sign
    Game.Message(SignText)
end

--repeat this for all entities...
function sign1.Touch()
    SignText="This is the Sign1 it says: plaaplaaplaplapal..."
end
--end repeat block

How-to make a explore script?

I found this script from aeRo - Crazy Elevator. This is pretty easy, just need:

  • Zone called 'zone_explore'
  • few variables:
    • canexplore = false
    • isexploring = false
    • explored_x = 0
    • explored_y = 0
    • move_step = 5
    • limit_right = 20
    • limit_left = 0
    • limit_up = 3
    • limit_down = 2
    • explore_zoom=0.15

Here is the script:

--EXPLORE SCRIPT
--original script by aeRo
--wikied + options added by tuhoojabotti 22.06.2009

--BASE
zone_explore 	= {}
--states
canexplore 		= false
isexploring 	= false
--position
explored_x 		= 0
explored_y 		= 0
--OPTIONS
--how much to move on single stroke
move_step   	= 5
--how many times u can move to x direction
limit_right 	= 67
limit_left  	= 0
limit_up    	= 3
limit_down  	= 2
--zoom in explore mode
explore_zoom=0.15

function OnLoad()
	Game.SetKeyHook("E", "explore")
	Game.SetKeyHook("A", "explore_left")
	Game.SetKeyHook("S", "explore_down")
	Game.SetKeyHook("D", "explore_right")
	Game.SetKeyHook("W", "explore_up")	
	return true
end
--EXPLORE ZONE
function zone_explore.OnEnter()
	Game.Message("Press E to explore the level.")
	canexplore = true
end
function zone_explore.OnLeave()
	cancel_explore()
	canexplore = false
end
function explore()
	if canexplore == true and isexploring == false then
		explored_x = 0
		explored_y = 0
		isexploring = true
		Game.CameraZoom(-explore_zoom)
		Game.ClearMessages()
		Game.Message("Press W,A,S,D to explore.")
		Game.Message("E again to cancel.")
	elseif isexploring == true then
		cancel_explore()
	end
end
function cancel_explore()
	if isexploring == true then
		isexploring = false
		Game.ClearMessages()
		Game.CameraMove(-explored_x, -explored_y)
		Game.CameraZoom(explore_zoom)
	end
end
--MOVING EXPLORE
function explore_left()
	if isexploring == true and explored_x ~= limit_left*move_step then
		Game.CameraMove(-move_step, 0)
		explored_x = explored_x - move_step
	end
end
function explore_right()
	if isexploring == true and explored_x ~= limit_right*move_step then
		Game.CameraMove(move_step, 0)
		explored_x = explored_x + move_step
	end
end
function explore_up()
	if isexploring == true and explored_y ~= limit_up*move_step then
		Game.CameraMove(0, move_step)
		explored_y = explored_y + move_step
	end
end
function explore_down()
	if isexploring == true and explored_y ~= -limit_down*move_step then
		Game.CameraMove(0, -move_step)
		explored_y = explored_y - move_step
	end
end

Just paste the script and edit the options. :)

How-to make a trainer script?

Loads of people have been asking about this, it is rather simple. All you need is:

  • a keyhook
  • an entity (like a sprite)

and here it is:

function OnLoad()
    Game.SetKeyHook("1","trainer1") -- create the keyhook on load of the level
    return true -- without this x-moto crashes
end

function trainer1()
    x,y=Game.GetEntityPos("entity1") --get position of the entity
    --throw the player to the position we just got
    Game.SetPlayerPosition(x,y,0) -- the 0 can be set to 1 if you want the player to face right after teleport
end

Debugging

General

Basically debugging means figuring out what makes the script behave unwanted ways or fix crashing. It is a good way to comment lines which you think makes the script crash and then start uncommenting then line by line till you find the crash spot, then try to figure out what is wrong:

  • typo (spelling error)
  • invalid parameter in function call
  • block not existing
  • block not dynamic
  • dynamic block in wrong layer

If some action doens't work but doesn't crash either try using Game.Message("debug") to see if the script is ever even executed. In X-Moto scripts the script must be in an event otherwise the script is never executed.

If you get an error with line number then to find the exact line, count the script's lines ignoring all empty lines and if you have joined lines with ";" you must break them, that is how you should be able to find the correct line, since the Lua script parser removes empty lines before executing the script.

Err. SetDynamicBlockTranslation crashes

Check that blocks all blocks are dynamic and in the main layer. Also look for typos in script. If the level has 2 or more main layers then the block must be in the original main layer.

Err. Zone.OnEnter fails

Is the zone defined at the start of the level like: Zone={}? X-Moto don't know to call the OnEnter function if you haven't defined it.