|
|
| (25 intermediate revisions by 8 users not shown) |
| Line 3: |
Line 3: |
| === Setup === | | === Setup === |
|
| |
|
| Lua unit animation is implemented partially in the engine, and partially in a Lua gadget which is shipped with Spring in springcontent.sdz. By default, this gadget is not loaded, so a bit of setup is required to enable Lua unit scripts. | | Lua unit animation is implemented partially in the engine, and partially in a Lua gadget which is shipped with Spring in [[springcontent.sdz]]. By default, gadget is not loaded, so a bit of setup is required to enable Lua unit scripts. (In some games, gadget is alredy activated, for example in Zero:k) |
|
| |
|
| To enable Lua unit scripts, create a file ''LuaRules/Gadgets/unit_script.lua'', and paste the following into it: | | To enable Lua unit scripts, create a file ''LuaRules/Gadgets/unit_script.lua'', and paste the following into it: |
| Line 15: |
Line 15: |
| --UNITSCRIPT_DIR = "scripts/" | | --UNITSCRIPT_DIR = "scripts/" |
| | | |
| return VFS.Include("LuaGadgets/Gadgets/unit_script.lua", nil, VFS.ZIP_ONLY) | | return include("LuaGadgets/Gadgets/unit_script.lua") |
| </small> | | </small> |
| |} | | |} |
| | |
| | Also, do check whether your [http://github.com/spring/spring/blob/master/installer/builddata/springcontent/LuaGadgets/system.lua ''LuaRules/system.lua''] is up to date, if you copied this verbatim into your game. (Must be from a later date than 5 september 2009) |
|
| |
|
| Now this is done, you can start putting *.lua files in your ''scripts/'' folder. | | Now this is done, you can start putting *.lua files in your ''scripts/'' folder. |
| Line 25: |
Line 27: |
| Lua has the major advantage over BOS/COB that you do not need to compile it, which can reduce the time to develop scripts quite a bit. | | Lua has the major advantage over BOS/COB that you do not need to compile it, which can reduce the time to develop scripts quite a bit. |
|
| |
|
| To save further time, do not restart Spring for each small change. Simply run Spring in an window so you can easily switch between your editor and Spring, and use ''/luarules reload'' to reload all Lua unit scripts. | | To save further time, do not restart Spring for each small change. Simply run Spring in an window so you can easily switch between your editor and Spring, and use ''/cheat'' and ''/luarules reload'' to reload all Lua unit scripts. |
| | |
| | |
| == Call-outs ==
| |
| | |
| The new callouts are defined in the Spring.UnitScript table.
| |
| | |
| Types for arguments are only shown where they're ambiguous. For a number of (common) arguments, the types are:
| |
| | |
| * unitID: number
| |
| * piece: number
| |
| * axis: number (1 = x axis, 2 = y axis, 3 = z axis)
| |
| * destination: number (world coors or radians)
| |
| * speed: number (world coors or radians per second)
| |
| * accel/decel: number (radians per second per frame)
| |
| * heading/pitch: number (radians)
| |
| | |
| === Animation ===
| |
| | |
| '''Spring.UnitScript.SetPieceVisibility''' ( unitID, piece, boolean visible ) -> nil<br>
| |
| '''Spring.UnitScript.Show''' ( unitID, piece ) -> nil<br>
| |
| '''Spring.UnitScript.Hide''' ( unitID, piece ) -> nil
| |
| | |
| These may be used to show/hide pieces of the unit's model.
| |
| | |
| | |
| '''Spring.UnitScript.Move''' ( unitID, piece, axis, destination[, speed] ) -> nil
| |
| | |
| Move piece along axis to the destination position. If speed is given, the piece isn't moved immediately, but will move there at the desired speed. The X axis is mirrored compared to BOS/COB scripts, to match the direction of the X axis in Spring world space.
| |
| | |
| | |
| '''Spring.UnitScript.Turn''' ( unitID, piece, axis, destination[, speed] ) -> nil
| |
| | |
| Turn piece around axis to the destination angle. If speed is given, the piece isn't rotated immediately, but will turn at the desired angular velocity. Angles are in radians.
| |
| | |
| | |
| '''Spring.UnitScript.Spin''' ( unitID, piece, axis, speed[, accel] ) -> nil
| |
| | |
| Makes piece spin around axis at the desired angular velocity. If accel is given, the piece does not start at this velocity at once, but will accelerate to it. Both negative and positive angular velocities are supported. Accel should always be positive, even if speed is negative.
| |
| | |
| | |
| '''Spring.UnitScript.StopSpin''' ( unitID, piece, axis[, decel] ) -> nil
| |
| | |
| Stops a piece from spinning around the given axis. If decel is given, the piece does not stop at once, but will decelerate to it. Decel should always be positive. This function is similar to Spin(unitID, piece, axis, 0, decel), however, StopSpin also frees up the animation record.
| |
| | |
| | |
| '''Spring.UnitScript.IsMoving''' ( unitID, piece, axis ) -> boolean<br> | |
| '''Spring.UnitScript.IsTurning''' ( unitID, piece, axis ) -> boolean<br>
| |
| '''Spring.UnitScript.IsSpinning''' ( unitID, piece, axis ) -> boolean
| |
| | |
| Returns true iff the piece is moving along the axis, or turning/spinning around the axis.
| |
| | |
| | |
| '''Spring.UnitScript.WaitForMove''' ( unitID, piece, axis ) -> nil<br>
| |
| '''Spring.UnitScript.WaitForTurn''' ( unitID, piece, axis ) -> nil
| |
| | |
| Waits until the piece has stopped moving along / turning around the axis. If the piece is not animating, this functions return at once. You can not wait for a spin, because a spin does never finish.
| |
| | |
| | |
| '''Spring.UnitScript.Sleep''' ( unitID, number milliseconds ) -> nil
| |
| | |
| Waits a number of milliseconds before returning.
| |
| | |
| | |
| '''Spring.UnitScript.StartThread''' ( unitID, function fun, ... ) -> nil
| |
| | |
| Starts a new (animation) thread, which will execute the function 'fun'. All arguments after the function are passed as-is as arguments to 'fun'. A thread is just a Lua thread, ie. a coroutine, so please refer to the Lua documentation about coroutines for exact semantics.
| |
| === Effects ===
| |
| | |
| '''Spring.UnitScript.EmitSfx''' ( unitID, piece, number id ) -> nil
| |
| | |
| Emits a particle from the given piece. The id may be one of:
| |
| TODO
| |
| | |
| | |
| '''Spring.UnitScript.Explode''' ( unitID, piece, number flags ) -> nil
| |
| | |
| Explodes a piece, optionally creating a particle which flies off. Typically used inside Killed. Explode does not hide the piece by itself; if using it outside Killed you may want to Hide the piece immediately after. The flags may be a combination of:
| |
| TODO
| |
| | |
| === Other ===
| |
| | |
| '''Spring.UnitScript.AttachUnit''' ( unitID, piece, passengerID ) -> nil<br> | |
| '''Spring.UnitScript.DetachUnit''' ( unitID, passengerID ) -> nil
| |
| | |
| Attaches or detaches another unit (a passenger, as this is designed for transports) to this unit. For AttachUnit, piece specifies the attachment point.
| |
| | |
| | |
| '''Spring.UnitScript.GetUnitValue''' ( ... ) -> number | number, number<br>
| |
| '''Spring.UnitScript.SetUnitValue''' ( ... ) -> nil
| |
| | |
| This may be used instead of COB's get and set codes. It is recommended however, to use dedicated Lua functions (e.g. Spring.GetUnitHealth(unitID) instead of GetUnitValue(unitID, 4)): these functions should be considered a relic of the past.
| |
| | |
| Note that these are identical to Spring.GetUnitCOBValue and Spring.SetUnitCOBValue (see also [[Lua_SyncedCtrl#Lua_to_COB]] for the signature of those functions.)
| |
| | |
| | |
| '''Spring.UnitScript.SetSignalMask''' ( unitID, number mask ) -> nil<br>
| |
| '''Spring.UnitScript.Signal''' ( unitID, number signal ) -> nil
| |
| | |
| These two support functions offer a powerful way to kill running threads. SetSignalMask assigns a mask to the currently running thread (any new threads started by this one will inherit the signal mask). Signal immediately stops all threads of this unit for which the bitwise and of mask and signal is not zero.
| |
| | |
| | |
| '''Spring.UnitScript.GetLongestReloadTime''' ( unitID ) -> number reloadTime
| |
| | |
| Returns max(reload time) of all the unit's weapons in milliseconds. This utility function exists to aid in porting BOS scripts, which have a SetMaxReloadTime call-in that is called immediately after Create.
| |
| | |
| | |
| == Call-ins ==
| |
| | |
| Call-ins are calls from the engine, into the unit script. In other words, these functions are called, if they are defined, when a particular “event†happens.
| |
| | |
| For Lua unit scripts, a new callin mechanism has been implemented, which is faster than the regular callin mechanism which is used for widgets and gadgets.
| |
| | |
| === Generic ===
| |
| | |
| '''Create''' ( unitID ) -> nil
| |
| | |
| This is called just after the unit script has been created.
| |
| | |
| | |
| '''StartMoving''' ( unitID ) -> nil<br>
| |
| '''StopMoving''' ( unitID ) -> nil
| |
| | |
| These are called whenever the unit starts or stops moving. Typical use for them is to trigger wheels to start spinning, animate treads, or start/stop a walking animation.
| |
| | |
| | |
| '''Killed''' ( unitID, recentDamage, maxHealth ) -> number corpseType
| |
| | |
| This is called when the unit is killed. The severity of the kill may be calculated as severity=recentDamage/maxHealth. Typically, this function would play a death animation for the unit, and finally return a corpse type.
| |
| | |
| | |
| '''SetDirection''' ( heading ) -> nil
| |
| '''SetSpeed''' ( speed ) -> nil
| |
| | |
| Called only for wind generators and metal extractors.
| |
| | |
| For wind generators, both of these are called each time the wind changes. SetDirection receives the new wind direction and SetSpeed receives the new wind speed.
| |
| | |
| For metal extractors, only SetSpeed is called. It receives the amount of metal which will be extracted every second, and is called every time this amount changes. (Nearby overlapping metal extractor is destroyed, for example.)
| |
| | |
| | |
| '''Go''' ( unitID ) -> nil
| |
| | |
| Called only for metal extractors. Called just after SetSpeed, but only if the extractor is activated.
| |
| | |
| | |
| '''setSFXoccupy''' ( number curTerrainType ) -> nil
| |
| | |
| I don't see any use for this. I'll probably remove this from Spring at some point. Called when terrain type changes. Terrain type is calculated with the following rules (in this order):
| |
| | |
| * If unit is being transported -> curTerrainType = 0
| |
| * If ground height < -5 and unit is always upright -> curTerrainType = 2
| |
| * If ground height < -5 and unit is not always upright -> curTerrainType = 1
| |
| * If ground height < 0 and unit is always upright -> curTerrainType = 1
| |
| * Otherwise -> curTerrainType = 4
| |
| | |
| Where is curTerrainType = 3 ? :-)
| |
| | |
| | |
| '''MoveRate0''' ( unitID ) -> nil
| |
| '''MoveRate1''' ( unitID ) -> nil
| |
| '''MoveRate2''' ( unitID ) -> nil
| |
| '''MoveRate3''' ( unitID ) -> nil
| |
| | |
| Another pointless set of call-ins. I'll probably remove this from Spring at some point. Called only for certain types of aircraft (those which use ''CTAAirMoveType''.) The move rate is determined by the following rules (in this order):
| |
| | |
| * If the aircraft is landing or taking off -> curRate = 1
| |
| * Otherwise -> curRate = floor(curSpeed / maxSpeed * 3), clamped to be in the range [0, 2]
| |
| | |
| It follows from this that MoveRate3 is not even called, ever.
| |
| | |
| | |
| '''QueryLandingPad''' ( unitID ) -> { number piece1, number piece2, ... }
| |
| | |
| Called one time for units with landing pads. Should return a table with pieces which should be used as landing pads. The number of pieces returned also determines the number of pads, so for Lua unit scripts there is no QueryLandingPadCount.
| |
| | |
| | |
| '''Activate''' ( unitID ) -> nil<br>
| |
| '''Deactivate''' ( unitID ) -> nil
| |
| | |
| Exact situation these are called depends a lot on the unit type. Factories are activated when they open their yard and deactivated when they close it. Aircraft are activated when they take off and deactivated when the land. Any unit that can be turned on or off is activated when it's turned on and deactivated when it's turned off. On ''SetUnitValue(COB.ACTIVATION, ...)'' one of these call-ins may be called too.
| |
| | |
| | |
| === Weapons ===
| |
| | |
| '''QueryWeapon1''' ( unitID ) -> number piece<br>
| |
| '''AimFromWeapon1''' ( unitID ) -> number piece<br>
| |
| '''AimWeapon1''' ( unitID, heading, pitch ) -> boolean
| |
| | |
| Weapon support. The suffix "1" should be replaced with the actual weapon number.
| |
| The return value of QueryWeapon and AimFromWeapon determines the pieces which will be used for aiming: typically e.g. the barrel for QueryWeapon and the turret for AimFromWeapon. AimWeapon is then called to allow the script to turn the weapons in the target direction, which is passed as the heading and pitch argument (in radians). Only if AimWeapon returns true, the weapon is actually fired.
| |
| | |
| TODO: better explanation (?), note about AimWeapon being called very often etc.
| |
| | |
| | |
| '''FireWeapon1''' ( unitID ) -> nil<br>
| |
| '''Shot1''' ( unitID ) -> nil<br>
| |
| '''EndBurst1''' ( unitID ) -> nil
| |
| | |
| If after aiming the unit actually fires it's weapon, FireWeapon is called once at the beginning of the salvo. Shot is called just before each projectile is fired. RockUnit (see below) is called just after all projectiles for that frame have been fired. At the end of the salvo, EndBurst is called.
| |
| | |
| Of these call-ins, FireWeapon is the more generic one and Shot and EndBurst are more specialized. FireWeapon is usually used to play a recoil animation or emit some smoke near the weapon's barrel using EmitSfx.
| |
| | |
| | |
| '''BlockShot1''' ( unitID, targetUnitID, boolean userTarget ) -> boolean
| |
| | |
| Allows you to block a weapon from shooting. TargetUnitID may be nil: in this case the unit has a ground-attack order.
| |
| | |
| | |
| '''TargetWeight1''' ( unitID, targetUnitID ) -> number
| |
| | |
| Allows you to tweak the priority of the target for this particular weapon. The target priority is multiplied by the return value of this function. Lower priority targets are targetted first, so return a value smaller than 1 to prioritize a target, or return a value larger than 1 to avoid a target.
| |
| | |
| The exact behavior of specific values shouldn't be relied upon.
| |
| | |
| | |
| '''RockUnit''' ( unitID, x, z ) -> nil
| |
| | |
| A bit like the weapon-specific FireWeapon function, although this is called after any weapon fires. As argument it gets a two dimensional vector in the direction the unit just fired. This may be used to “rock†the unit as a whole a bit as part of the firing animation. Note though that this vector is in world space, so for a truely realistic rock direction it needs to be rotated according to the unit's current heading.
| |
| | |
| | |
| '''HitByWeapon''' ( unitID, x, z ) -> nil
| |
| '''HitByWeaponId''' ( unitID, x, z, weaponDefID, damage ) -> nil | number newDamage
| |
| | |
| These are called if a unit has been hit by a weapon. (x, z) is the direction from which the projectile came in world space (the reverse direction of the impulse, to be exact.)
| |
| | |
| In addition, HitByWeaponId also gets the weaponDefID of the weapon which is dealing the damage, and the amount of damage. If HitByWeaponId returns a number, this number will replace the damage value calculated by the engine.
| |
| | |
| Note: these call-ins run just before the LuaRules UnitPreDamaged callin (see also [[LuaCallinReturn]]). If HitByWeaponId overrides the damage, UnitPreDamaged will see the new damage value, and may override again the damage value.
| |
| | |
| | |
| === Builders and factories ===
| |
| | |
| '''StartBuilding''' ( unitID, heading, pitch ) -> nil<br>
| |
| '''StartBuilding''' ( unitID ) -> nil<br>
| |
| '''StopBuilding''' ( unitID ) -> nil
| |
| | |
| These notify the script when a builder or factory starts or stops building.
| |
| | |
| The first variant (with heading and pitch arguments) is called for builders. For factories, the second variant is used. In this case the heading and pitch are not necessary, because the factory script specifies the build location itself using QueryBuildInfo.
| |
| | |
| | |
| '''QueryBuildInfo''' ( unitID ) -> number piece
| |
| | |
| For factories only. Should return the piece to which the unit which is going to be build will be attached while it's being build.
| |
| | |
| | |
| '''QueryNanopiece''' ( unitID ) -> number piece
| |
| | |
| Called each time a nano particle is to be created. Should return the piece at which the particle will be spawned. This may be used to iterate through a few pieces, to simulate the factory/builder having multiple nanolathes.
| |
| | |
| | |
| === Transports ===
| |
| | |
| There are some different code paths inside Spring related to transports, each (unfortunately) also associated with a different set of unit script call-ins.
| |
| | |
| This table shows for the three different transportUnloadMethods for both air transports and ground transports which callins are used and roughly when and how often they are called. Refer to the documentation below for a description of the call-ins.
| |
| | |
| The entire behavior around transports should be considered subject to change; it is obvious it is far from a perfect design currently.
| |
| | |
| | |
| {|border="1" style="border-spacing:0px;"
| |
| |+
| |
| !
| |
| !Load
| |
| !UnloadLand (0)
| |
| !UnloadDrop (1)
| |
| !UnloadLandFlood (2)
| |
| |-
| |
| |
| |
| |
| |
| |default unload
| |
| |fly over and drop unit
| |
| |land, then release all units at once
| |
| |-
| |
| |air
| |
| |BeginTransport (each)<br>QueryTransport (each)
| |
| |EndTransport (last)
| |
| |EndTransport (each)
| |
| |StartUnload (first)<br>TransportDrop (each)<br>EndTransport (last)
| |
| |-
| |
| |ground
| |
| |TransportPickup (each)
| |
| |TransportDrop (each)
| |
| |TransportDrop (each)
| |
| |TransportDrop (each)<br>EndTransport (last)
| |
| |}
| |
| | |
| | |
| ==== Air transports ====
| |
| | |
| '''BeginTransport''' ( unitID, passengerID ) -> nil<br>
| |
| '''QueryTransport''' ( unitID, passengerID ) -> number piece
| |
| | |
| For an air transport, if any one unit is picked up, these two are called in succession and the passenger is attached to the piece returned by the second one.
| |
| | |
| | |
| '''StartUnload''' ( unitID ) -> nil
| |
| | |
| Only called in UnloadLandFlood behavior. Signals the start of an unload cycle.
| |
| | |
| | |
| '''TransportDrop''' ( unitID, passengerID, x, y, z ) -> nil
| |
| | |
| Only called in UnloadLandFlood behavior. Called when a passenger will be unloaded. Contrary to ground transports, Spring will detach the passenger after the call.
| |
| | |
| | |
| '''EndTransport''' ( unitID ) -> nil
| |
| | |
| In UnloadLand and UnloadLandFlood behaviors, these are called one time after all units are unloaded. (The transport is empty.) For the UnloadDrop behavior, this is called for every unit that is unloaded.
| |
| | |
| | |
| ==== Ground transports ====
| |
| | |
| '''TransportPickup''' ( unitID, passengerID ) -> nil
| |
| | |
| Called when a passenger should be loaded into the transport. This should eventually call AttachUnit to actually attach the unit. Assuming the transport is in range of the next passenger, this will be called again for the next passenger 16 frames later, ''unless'' the script enters the BUSY state: then Spring will not move on to the next passenger until the script leaves the BUSY state.
| |
|
| |
|
| | To be able to use commands above, unzip your game into directory named "myGame.sdd", then you can directly change lua scripts (animations etc.) and reload. |
|
| |
|
| '''TransportDrop''' ( unitID, passengerID, x, y, z ) -> nil
| | Additionally, for Lua unit scripts operating on Assimp models (primarily .dae and .blend), it is possible to do most of your animating in Blender using the [https://github.com/Anarchid/blender2lus blender2lus] export addon. |
|
| |
|
| Called when a passenger should be unloaded. This should eventually call DetachUnit to actually detach the unit, ''unless'' the used unload method is UnloadLandFlood, in which case Spring will actually detach the unit after the call.
| | === Workflow for animating S3o models in Blender === |
|
| |
|
| | Anarchids Blendertools can be used to animate (within limits) S3O models. Here are the steps: |
|
| |
|
| '''EndTransport''' ( unitID ) -> nil
| | 1. Export your model into Blender. |
|
| |
|
| Only called in UnloadLandFlood behavior, after the last unit has been unloaded.
| | 2. Restore the Hierarchy in Blender. |
|
| |
|
| | https://blender.stackexchange.com/questions/26108/how-do-i-parent-objects |
| | (Ctrl + P) is your friend . |
|
| |
|
| ==== Passenger ====
| | 3. If all Pivots are set correctly, create the Animations, one by one. |
|
| |
|
| '''Falling''' ( unitID ) -> nil
| | 4. Export the Animations with Anarchids Skript Export tool. |
|
| |
|
| For a unit dropped from an UnloadDrop transport, this is called every frame to inform the script the unit is still falling. It may be used to show a parachute for example.
| | 5. Open the resulting Animationskript for postprocesing. |
|
| |
|
| | 6. Find Move commands like {['c']='move',['p']=LowerJaw, ['a']=x_axis, ['t']=-0.000000, ['s']=0.012682}, and purge them. Replace them with todos- you will have to insert them manually later, with correct axis and values. |
|
| |
|
| '''Landed''' ( unitID ) -> nil | | 7.In the turn commands - exchange the ['a']=z_axis with ['a']=y_axisz and the old ['a']=y_axis with ['a']=z_axis. |
| | Here is a Regex, to make the text-search easier. |
|
| |
|
| This is called one time after the unit reached the ground. May be used to hide a parachute for example.
| | {\['c']='turn',\['p']=([^\s]+), \['a']=z_axis, \['t']=\* |
|
| |
|
| | {\['c']='turn',\['p']=([^\s]+), \['a']=y_axis, \['t']=\* |
|
| |
|
| === Internal ===
| | 8. Invert (change the sign) of the y_axis values. |
|
| |
|
| These call-ins are NOT available to Lua unit scripts. They are called by the engine however, but always 'intercepted' by the framework gadget. For completeness (or if you are poking at modifying the gadget), they are listed here anyway.
| | 9. Start the game and call the Animation you want to debug in a Loop. |
|
| |
|
| | 10. Congratulations you now have smoothly animated S3o Models. |
|
| |
|
| '''MoveFinished''' ( unitID, piece, axis ) -> nil<br>
| | == Further reading == |
| '''TurnFinished''' ( unitID, piece, axis ) -> nil
| | * [[Animation:LuaExamples]] |
| | * [http://tvo.github.com/spring/2010/04/19/lus-stumpy.html Stumpy tutorial] |
| | * [http://tvo.github.com/spring/2010/04/26/lus-stumpy-2.html Polishing the stumpy] |
| | * [[Animation-LuaCallins]] |
| | * [[Animation-LuaCallouts]] |
| | * [[Animation-CobLuaDifferences | comparing Lua and COB unit scripts]] |
| | * [[SpringTutorialGame]] contains simple examples unit scripts |
| | * [[SpringRtsTutorialAnimDef]] examples animation scripts |
|
| |
|
| Called when a move or turn finished. The framework gadget uses this to resume the coroutines which are waiting for the particular move or turn to be finished.
| | == TODO == |
|
| |
|
| | * Conversion tool |
| | * Performance measurements |
| | * Link to article in piro's magazine |
| | * Coordinate system (axis, direction of rotation, picture) |
|
| |
|
| '''Destroy''' ( unitID ) -> nil
| |
|
| |
|
| Called right before the unit's script is destroyed. This may happen if the unit is being destroyed, but also if the unit's script is being replaced by another script. The framework gadget uses this to stop all threads and remove the unit from some internal data structures.
| |
|
| |
|
|
| |
|
| [[Category:Animation]] | | [[Category:Animation]] |
Getting started
Setup
Lua unit animation is implemented partially in the engine, and partially in a Lua gadget which is shipped with Spring in springcontent.sdz. By default, gadget is not loaded, so a bit of setup is required to enable Lua unit scripts. (In some games, gadget is alredy activated, for example in Zero:k)
To enable Lua unit scripts, create a file LuaRules/Gadgets/unit_script.lua, and paste the following into it:
|
-- Enables Lua unit scripts by including the gadget from springcontent.sdz
-- Uncomment to override the directory which is scanned for *.lua unit scripts.
--UNITSCRIPT_DIR = "scripts/"
return include("LuaGadgets/Gadgets/unit_script.lua")
|
Also, do check whether your LuaRules/system.lua is up to date, if you copied this verbatim into your game. (Must be from a later date than 5 september 2009)
Now this is done, you can start putting *.lua files in your scripts/ folder.
Workflow
Lua has the major advantage over BOS/COB that you do not need to compile it, which can reduce the time to develop scripts quite a bit.
To save further time, do not restart Spring for each small change. Simply run Spring in an window so you can easily switch between your editor and Spring, and use /cheat and /luarules reload to reload all Lua unit scripts.
To be able to use commands above, unzip your game into directory named "myGame.sdd", then you can directly change lua scripts (animations etc.) and reload.
Additionally, for Lua unit scripts operating on Assimp models (primarily .dae and .blend), it is possible to do most of your animating in Blender using the blender2lus export addon.
Workflow for animating S3o models in Blender
Anarchids Blendertools can be used to animate (within limits) S3O models. Here are the steps:
1. Export your model into Blender.
2. Restore the Hierarchy in Blender.
https://blender.stackexchange.com/questions/26108/how-do-i-parent-objects
(Ctrl + P) is your friend .
3. If all Pivots are set correctly, create the Animations, one by one.
4. Export the Animations with Anarchids Skript Export tool.
5. Open the resulting Animationskript for postprocesing.
6. Find Move commands like {['c']='move',['p']=LowerJaw, ['a']=x_axis, ['t']=-0.000000, ['s']=0.012682}, and purge them. Replace them with todos- you will have to insert them manually later, with correct axis and values.
7.In the turn commands - exchange the ['a']=z_axis with ['a']=y_axisz and the old ['a']=y_axis with ['a']=z_axis.
Here is a Regex, to make the text-search easier.
{\['c']='turn',\['p']=([^\s]+), \['a']=z_axis, \['t']=\*
{\['c']='turn',\['p']=([^\s]+), \['a']=y_axis, \['t']=\*
8. Invert (change the sign) of the y_axis values.
9. Start the game and call the Animation you want to debug in a Loop.
10. Congratulations you now have smoothly animated S3o Models.
Further reading
TODO
- Conversion tool
- Performance measurements
- Link to article in piro's magazine
- Coordinate system (axis, direction of rotation, picture)