Navigation

Home
About
Documentation
Screenshots
Status
Download
 
Taxipilot at
  Sourceforge




Support This Project

Configuration of levels

A level is... well, I don't think I have to explain this. Let's have a walk through a sample config-file.

<!DOCTYPE level_data >
<document author="Thomas Friedrichsmeier" caption="Plain Level 1">

The "author"- and "caption"-attributes should be self-explanatory by now. Only thing is, that here you have to specify "caption" instead of "title" for historical reasons. The "caption" is also shown in TaxiPilot's window-caption when the level is on.

	<completion deliveries="5" extra_life="no" />

This specifies, that you will have to complete 5 deliveries successfully (get a tip for the delivery) in order to compelete this level. Upon completion of this level you will not be awarded an extra life.

	<image background="level_background.jpg" foreground="level_foreground.png" />

Every level may have a unique background, specified like any other filename (this is not an animation!). Choose .png or any other file-format, QT supports, e.g. .jpg should be a reasonable choice most of the time. The background image is not solid/harmful, you can fly right over it. Make sure it doesn't look too much like the real level.

The level foreground is first of all a simple image with transparancies. You can fly over the transparency, you can crash into everything else (+ land on the designated platforms, see below). For right now, the foreground-image has to have a solid frame. Currently there is not other mechanism of keeping the taxi inside the visible area.

You may want to have a look at the background- and foreground-images provided in the missions shipped with TaxiPilot. It's really not that complicated. The only restrictions on the size of foreground- and background-images is that they should have the same size and should not be too large for a user with, say 800x600-screen-resolution to display (take into account the space the game-displays take up).

Starting with version 0.4.2 you may however also create oversized levels. The syntax is as follows:

	<oversize visible_width="640" visible_height="480" initial_offset_x="0" initial_offset_y="0" margin="80" />

This specifies that the portion of the level that will be visible to the player is 640x480 pixels (your level should of course be bigger than that, if you use this option), you will initially see the top-left corner of the level, and finally "margin"-means the distance the taxi may have to any side of the visible area, before the level is scrolled.

	<platforms>
		<data y="265" passengers="yes" has_fuel="no" x1="94" passenger_base_x="190" x2="194" />
		<data y="265" passengers="yes" has_fuel="no" x1="236" passenger_base_x="240" x2="356" />
		<data y="355" passengers="yes" has_fuel="no" x1="116" passenger_base_x="120" x2="195" />
		<data y="355" passengers="yes" has_fuel="no" x1="234" passenger_base_x="240" x2="337" />
		<data y="389" passengers="yes" has_fuel="no" x1="420" passenger_base_x="425" x2="585" label="Residential area" />
		<data y="71" passengers="no" has_fuel="yes" fuel_price="0.1000" fuel_step="3" x1="440" x2="540" />
	</platforms>

This section defines, where you can land in this level. Note that you can't land in the void. TaxiPilot first checks, whether you collided yith the level foreground, and only after that, whether this means you're landed. Make sure the landing-areas are really even, otherwise you might get "stuck" on them. The "label"-Attribute allows you to specify, what Spacetaxi will call the platform. If you omit the label-Attribute, the Platforms will be numbered in the order of their definition, starting with 1 (and called "Platform <number>". It's your job to provide the user with information (in the level-image), which platform is which. Also don't forget to provide valid information about where the pilot can land. Therefore I'd recommend to explicitely label all platform in the level image.

You have to measure (2 or 3 pixels error won't harm) the y-coordinates of the surface of the platforms (y), and the x-coordinates of the left (x1) and right (x2) boundaries of the platform. Make sure the platform is large enough to land on it (esp. with a passenger waiting on it). Of course you should be careful with these measures, to make sure the player can land everywhere, they expect to.

You may find the command-line-option "--highlight" useful during development. What it does is draw a (yellow) horizontal line from "x1" to "x2" at height "y". So this allows you to see, whether you really specified the platform-coordinates correctly.

The remaining parameters specify, whether there are passengers waiting on this platform (or demanding to be taken there) ("passengers", default is "no"), if so, where exactly they appear / disappear on (passenger_base_x) (y coordinates are always right on top of the platform).

Furthermore, you can specify, whether you will get fuel on this platform ("has_fuel", default is "no") and what the price of a unit of fuel is. I guess it is generally a good idea to keep passenger- and fuel-platforms separate, but the same platform may also have passengers and fuel.

"fuel_step" specifies, how fast the taxi will be fueled, i. e. how many units of fuel (see mission-configuration) will be fueled up per unit of time (50 msec). "fuel_step" can take integer values from 1 (pretty slow) to 8000 (should amount to instant fueling to max for about any taxi). Personally I'd think values from 2 through 6 to be reasonable, as long as you don't want this "instant"-fueling effect.

	<gravity base_gravity="0.0" horiz_gravity="0.0">
		<data x="640" y="480" gravity="100" potential="2" />
		<data x="0" y="0" gravity="100" potential="2" />
		<data x="640" y="0" gravity="100" potential="2" />
		<data x="0" y="480" gravity="100" potential="2" />
	</gravity>

You have control over gravity far more than physics would allow. The simple parameters "base_gravity" and "horiz_gravity" specify the simple downward / sideward pull, you would expect in any game like this (independend of you current position). Start exprimenting with values around 0.005. Of course you may use negative values in order to reverse direction.

The following tags are "centers of gravity". Those allow you to make the force acting on the taxi depend on its current position on the screen. Obviously you need to specify the location of the center of gravity. Next is a constant of gravity. Reasonable values (double) for this constant may vary dramatically depending on the following parameter. Use negative values to achieve a "pushing away". The parameter "potential" affords you a lot of control.

The allowed values and their effects are:

0: force does not depend on distance (but direction of force depends on direction)

1: force depends on plain distance

2: "physical gravity" - force is reverse of distance squared

4: "dangerous spot" - force is reverse of distance to the fourth power

There is no value "3"! You may have as many centers of gravity as you like, but I'm afraid, having real lots of them could slow down the game on old machines. You may of course omit specifying centers of gravity.

	<teleporters>
		<data x="100" y="100" destination="2" fare="0" factor_x="1" factor_y="1" frames="1" file_pattern="teleporter1.png" />
		<data x="200" y="200" destination="3" fare="0" factor_x="-2.5" factor_y="-2.5" frames="1" file_pattern="teleporter1.png" />
		<data x="400" y="200" destination="1" fare="1.50" factor_x="0" factor_y="0" frames="1" file_pattern="teleporter1.png" />
	</teleporters>

Have a look at level 3 of the current distribution, if you want to know, what teleporters do. They may have unique animations (always continuous, only additional parameter allowed is "anim_oscillating"), and of course they need to be placed on some coordinates. The other parameters are as follows:

"destination": Teleporters are numbered in the order of definition starting with 1. You can only teleport from a TP and only to another TP. This specifies the number of the TP, you will arrive at. If you want a TP to serve as an arrival-point only, set this value to "0".

"fare": Teleporting may cost money. This parameter specifies how much.

"factor_x", "factor_y": These parameters might be very nasty, they change the speed (and direction) when you arrive. Putting these values to 0 will obiviously stop the taxi. Putting them to large values might be very dangerous to the pilot.

Since generally, the active-region of a teleporter is determined by whether the taxi touches the teleporter, if you want to have an invisible teleporter (or one where the active-region does not correspond to the image), you will have to additionally specify the parameters "width" and "height" (in pixels). For an invisible teleporter, you could then specify a transparent 1x1-image. You may not omit the file_pattern-parameter, however. As a matter of fact, specifying a "width" and "height" for your teleporter, may save some resources, since in this case no collision-detection needs to be performed.

You may of course omit the teleporters-section, if you don't want any teleporters.

	<tips min="10.00" max="30.00" />

This simply specifies the range of tips, passengers may start out with...

	<fare base="5.40" step="0.050000" />

... while this parameter is used to control the taxi-pricing. "base" is the base-fare, "step" determines, how fast the fare will increase.

	<initial_position x="50" y="50" />

Finally, this is, where the taxi starts out at in the level.

</document>

Version 0.5.0 finally introduced support for moving objects in the levels. As of this version, there is still a lot to do, but also, a lot of flexibility is implemented already. And here is how that works:

	<objects>
		<object class="background" frames="5" file_pattern="some_object%1.png"
				z="90" anim_frame_period="50" looping="yes" initial_vx="10" initial_vy="10" >
			<path x="100" y="100" time="500" accel="linear" />
			<path x="110" y="100" time="500" accel="abrupt" />
			<path x="130" y="100" time="500" accel="linear" />
			<path x="140" y="100" time="500" accel="linear" />
			<path x="170" y="100" time="1500" accel="linear" visible="no" />
		</object>
		<object class="harmful" frames="10" file_pattern="another_object%1.png" looping="no" z="90" >
			<path x="100" y="100" time="5000" accel="linear" />
			<path x="100" y="300" time="5000" accel="linear" frames="5" file_pattern"animation_override%1.png" />
			<path x="100" y="400" time="5000" accel="linear" />
		</object>
	</objects>

So first of all objects may belong to different classes. Two basic classes are supported: Either the object is "harmful" i.e. you crash when you collide with it, or "background" i.e. it does not do anything to you, and is merely decoration. There is a number of special classes, which will be dealt with in the next section. Then of course, an object has an image or animation as described in the section on animations. The available additional parameters for the animation are: "anim_continuous" (default="false"), repetitions (default="1") and "anim_oscillating" (default=false). For moving objects, the ability to create textual "animations" might be especially interesting.

Of course, the animations may also have sounds, with the additional parameters "continuous" (default="false"), "repetitious" (default="false") and "interruptable" (default="false").

Further, you may specify the z-Position of the object. The higher the value, the closer the object is, i.e. it will cover objects with a lower z, when the two overlap. BTW, the taxi is at z="75", the level at z="50", passengers at z=40". Of course the object can not be behind the level's background, however.

An object may either be "looping" (going from A to B to C to A) or "bouncing" (going from A to B to C to B to A and then back). Note that this also affects the way that the last path-segment is treated. For looping objects, it will be taken as the way back, i.e. the first object above will be invisible for 1.5 seconds and return to the position 100/100 during that time. For bouncing objects, the way is the same in both directions, so here the last path-segment describes the way the object takes starting from the last key-position, until it reaches that same key-position again. So it will spend 5 seconds in the third path-segment and then go back to the second.

You may specify an inital speed for the object. This only has an effect, if the first segment of the path has accel="linear" given. See below.

Next we will have to specify the path of the object: Therefore we define key-frames, with starting-coordinates, time needed to reach next key-point (milliseconds), mode of acceleration, and whether it will be visible on the way (while invisible it is never harmful).

There are three possible modes of acceleration:

accel="abrupt": The object moves from the starting-coordinates of the current path-segment to the starting-coordinates of the next at a constant speed on a straight line. Therefore the speed and direction of the object may change abruptly with respect to the previous path-segment.

accel="linear": The object starts out with the speed and direction it had on the last frame of the previous segment of the path (or with initial_vx and initial_vy). It then uses just that constant acceleration that will make it arrive at the next key-position in the specified time. Most of the time this should give nice smooth movements.

accel="custom": The tough way, but of course the one with the most flexibility. If you specify accel="custom", you may also specify the parameters "vx" and "vy" (starting velocity (in pixels per second)), "ax" and "ay" (starting acceleration in pixels per second squared) and "dax" and "day" (change in acceleartion over time in pixels per second cube). Of course you don't have to specify all these. Any parameter you omit will be assumed to be zero. Therefore, if you omit "ax", "ay", "day", and "dax", you will get a movement with a constant velocity "vx" and "vy". Using this mode, it is entirely your responsibility to make sure that using these parameters, the object will reach the next key-frame in the specified time. If it does not, it will simply be put there, making the object jump. So this is for those who love maths. Even in this mode, if you specify a "bouncing" object, the way back will be exactly the reverse of the way forth.

Finally you can override the animation used in any path-segment.

I admit, this is quite complex already, but as always, you can start out with simple objects and slowly experiment with more difficult ones.

Version 0.5.1 greatly extends the support for moving objects in the levels. You can now also define platforms, teleporters and centers of gravity to be moving objects. In order to do so, first of all you assign an identification label to the platform/teleporter/center of gravity (example for a moving teleporter):

		<data ident="tp1" destination="2" fare="0" factor_x="1" factor_y="1" />

Of course now, you do not need to specify a (static) x- and y-position and also, you don't have to specify the animation parameters ("file_pattern" etc.). After all, the teleporter now is a moving object, that may change it's position and appearance.

Note: You may of course mix "normal" and "moving" teleporters in the teleporters' section.

Next, the teleporter needs to be tied to a moving object. You do this simply by declaring an object to be of class "teleporter" and having the same idenification label you used when defining the teleporter:

		<object class="teleporter" frames="5" file_pattern="some_object%1.png"
				z="90" anim_frame_period="50" looping="yes" ident="tp1" >
			<path x="100" y="100" time="500" accel="linear" />
			...
		</object>

Everything else works the usual way. So, to sum it up, you define the parameters specific to a teleporter in the teleporters' section and those specific to a moving object in the object's section, then you tie both sections together with the "ident"-paramenter.

Note: The one thing that is different is, that x- and y-position-parameters for a (normal) static teleporter are interpreted to be the center of the image, objects' positions always refer to the top-left corner of the image!

For moving platforms and centers of gravity, the procedure is basically the same. What is left to be said is that objects tied to centers of gravity may either be defined with class="harmful center" or class="harmless center". Obviously, the two differ in whether the taxi can crash into them. Also obviously, the x- and y-position-parameters (in the definition of the center of gravity) are not interpreted for moving centers.

Moving platforms still take the "x1", "x2", "passenger_base_x" and "y"-paramenters. For moving platforms, those parameters are interpreted as relative to the top left of the image of the platform. The belonging moving object has to be classified as class="platform".

Finally, it needs to be said, that the "tying up" of platforms/teleporters/centers of gravity with moving objects fails, if the object does not have the same "ident"-parameter, or if it is not classified appopriately. You can only ever tie up one of these functions with a single moving object, and you cannot tie several moving objects to one function.

As always, having a look at the configuration-files provided might help understanding the procedure.

An arcade game of this sort, without doors and switches? Of course not! Version 0.7.0 introduces a framework for creating doors and switches and eventually many other things. Not everything that this framework allows for has been implemented yet, but new features are soon to follow.

Let me start by giving you a general overview of "events" and "states": A "state" is basically a variable which may either be on or off. E.g. you might have a state labled "door_open", which may either be on or off, and of course a door (a moving object) which will act according to this state (how to accomplish this will be described some paragraphs below).

The whole thing would of course be pointless, if the "door_open"-state would never change. Changing states is accomplished by events. Think of events as actions, which may be triggered when something happens. The most imporant way (and the earliest one to have been implemented) is the "hot_area", which can fire events. By no also platforms are be able to trigger events, when you land on them, when a passenger appears on them, teleporters, when you arrive at them... We'll discuss that further below.

So actually, opening a door is not all that easy to do: You need a moving object, that depends on a state, a state, which it depends on, an event, that changes the state and finally something to trigger the event. This framework does however allow for a maximum of flexibility. Let's have a more detailed look:

The syntax for declaring a state is relatively straightforward. All state-declarations are grouped together in a "states"-tag and individual "states" are given a label ("ident") and initial value ("initial"):

	<states>
		<state ident="door_open" initial="off"/>
		<state ident="some_other_state" initial="on"/>
	</states>

Similarily events are grouped in an "events"-tag and of course also need a label. Events, generally, also change some state(s), which is accomplished via a "change"-tag:

	<events>
		<event ident="toggle_door">
			<change state="door_open" to="toggle"/>
		</event>
	</events>

What happens in this example is, that the event, when triggered, changes the state "door_open" to is opposite value, i.e. to "on" when it was "off" and vice versa. Of course you may also specify to="on" (or to="off"), if you want your event to only open (close) the door.

This, however, isn't all there is to events. You may make the execution of your event depend on a condition. E.g. you might have a state "have_key", which is to control, whether your "toggle_door"-event takes any effect. In the following example, if "have_key" is "off", and the event "toggle_door" is triggered, nothing will happen, because the condition is not met:

		<event ident="toggle_door">
			<condition>
				<requires state="have_key" to_be="on"/>
			</condition>
			<change state="door_open" to="toggle"/>
		</event>

The "condition"-syntax is described in more detail, below. There may be only one condition-tag per event, but it may involve several states.

Events may also be associated to (single-shot) sounds:

		<event ident="toggle_door">
			<condition>
				<requires state="door_can_be_opened" to_be="on"/>
			</condition>
			<change state="door_open" to="toggle"/>
			<sound file="unlock_sound.wav"/>
		</event>

Another thing, that can be done in events is to trigger some further events. E.g. you could have two doors, A and B, and you want door B to get shut, whenever door A gets opened, but not necessarily the other way around. You could accomplish this using the following two events:

	<events>
		<event ident="open_door_a">
			<change state="door_a_open" to="on"/>
			<child_event ident="close_door_b"/>
		</event>
		<event ident="close_door_b">
			<change state="door_b_open" to="off"/>
		</event>
	</events>

What's left to say is that each event may have only one condition-tag and any number of "change"- and "child_event"-tags. When the event gets triggered, first the condition (if any) will be checked. If the condition fails, nothing will happen. If the condition is fulfilled, the event will process all "change"-tags in the order they are specified. Only after that all "child_event"s will be triggered in the order they appear in the config. Triggering means, that the "child_events" will each be processed fully one at a time. I.e. if you have an event A with child-events B, C and D, and C has child-event E, first A will be triggered, then B, then C, then E and only then D. (Just mentioning tis to confuse you, probably you won't ever have to worry about that situation).

Note that events perform strict checking for recursions. If an event notices, that it is called again (from some child_event), before it has finished all its actions, it will ignore that call and output an error message. Whenever timers do get implemented, you will however be able to have a recursion with a certain delay between each cycle.

Conditions are not all that complicated, but since they may appear in several places, they deserve a section of their own. A condition is really a sequence of "requires"-tags with all the specified "state"s required to be in the specified state. All "requires"-statements have to be fulfilled at once. They therefore constitute a logical AND.

			<condition>
				<requires state="has_key" to_be="on"/>
				<requires state="can_handle_key" to_be="on"/>
				<requires state="key_broken" to_be="off"/>
			</condition>

Starting with version 0.7.2 there are a number of other ways to trigger events besides "hot_areas". Those other ways will be discussed later, since "hot_areas" probably the most important way. Hot "area"s are rectangular regions on the screen (invisible by themselves) which can trigger events, if the taxi touches ("touch_event", stops to touch ("untouch_event"), enters ("enter_event") or leaves ("leave_event") this region. Note that hot-areas currently don't perform an exact check for these events, i.e. do no real collision-detection, but merely check, whether the bounding-rectangle of the taxi-sprite touches, enters, ... the area. I believe this is a reasonable compromise with performance. One helpful thing when creating levels with hot-areas is the commandline-option --highlight, which not only hightlights the platforms as mentioned above, but also oultines the hot_areas, so you can see, whether they are positioned correctly.

The following example should illustrate the syntax. Note that all hot-areas in a level are grouped in a single "hot_areas"-tag (analogous to events and states).

	<hot_areas>
		<area x1="558" x2="640" y1="0" y2="68" enter_event="unlock"/>
		<area x1="0" x2="78" y1="320" y2="340" touch_event="toggle_left_door" untouch_event="toggle_left_door"/>
		<area x1="0" x2="78" y1="354" y2="375" leave_event="close_all_doors"/>
	<hot_areas>

So far events and states have remained dry theory, with no visible results. The ultimate purpose of "states" is of course that they affect the behavior of objects in the game. Moving Objects are the first kind of objects that can have conditional behavior. You can add special actions to each path-segment, that will be processed at the end of that path-segment. Let's have a look at a concrete example:

		<object frames="1" file_pattern="objects/door.png" class="harmful" z="1" looping ="true">
			<path x="84" y="343" time="500" accel="abrupt"/>
			<path x="0" y="343" time="50" accel="abrupt">
				<stop>
					<condition>
						<requires state="door_open" to_be="off"/>
					</condition>
				</stop>
			</path>
			<path x="0" y="343" time="500" accel="abrupt"/>
			<path x="84" y="343" time="50" accel="abrupt">
				<stop>
					<condition>
						<requires state="door_open" to_be="on"/>
					</condition>
				</stop>
			</path>
		</object>

What this example is meant to accomplish is to have a door that will be in x-position 0 when the state "door_open" is "off", and in position 84 when the state is "on". In the example, the door will start out opened (at x=84) and move to closed from the first to the second-path-segment. Next, it will move all the way of the second path-segment, which actually simply tells the door to remain in place for a brief period of time. At the end of the second path-segment, however a "stop" is to be processed. This "stop" tells the object to simply wait without moving as long as the given condition is fullfilled, i.e. as long as "door_open" is "off".

If "door_open" happens to be "on" when the object finishes the path-segment, it simply moves on to the next segment, like it normally would. If "door_open" is "off" however, it will not continue to move until "door_open" changes to "on". It is important to understand, that the object will only ever stop at the end of a path-segment, never in between.

There are three more tag besides "stop" that version 0.7.2 supports: "freeze", "trigger" and "jump". "freeze" is used in exactly the same way as "stop" and does almost exactly the same thing (stop the object), but also stops any animation the object might have. "trigger" and "jump" will be discussed below.

A few things remain to be said about conditional movements. First, you may have wondered, why I specified four path-segments for really only two positions. The reason is that at the end of a path-segment, the object is generally some way before reaching it's target position. The next key-position will only be reached at the start of the new path-segment. Therefore, if you want very exact control over where the object stops, you should insert "dummy" path-segments, where no movement occurs. Second, you should note, that the "linear"-accel mode does not work as might be expected over a "stop". Rather, the object will come to an abrupt halt if it is to stop, and when released, starts with the speed it would have had, if there had been no "stop"-tag in between. This is because the movement-velocities are calculated beforehand, not during the game. Therefore, you should make sure not to introduce stops at points where the object would normally be moving very fast - that would simply look awkward. "jump"s, discussed below give you a neat way to circumvent this limitation.

The syntax for "jump"s is basically the same as for "stop"s:

			<path x="0" y="343" time="50" accel="abrupt">
				<jump target="5">
					<condition>
						<requires state="go_somewhere" to_be="on"/>
					</condition>
				</stop>
			</path>
			...

What a "jump" does, is that - if the condition is met - the object will continue it's movement at the specified "target". Target is the number of a path-segment for this object (path-segments are counted starting with 1). So in the above example, if the state "go_somewhere" is "on", instead of proceeding to the next path-segment, the object will continue it's movement at the fifth path-segment. Any further actions like "stop"s or other "jump"s that follow the "jump"-tag will be ignored, if the jump-condition is met. If it is not met, the "jump"-tag will simply be ignored.

It might not be easy to understand the "jump"-tag, but it is indeed very powerful, giving you the option of not only stopping an object, but making it move entirely differently. If you are familiar with a programming language that has GOTO-statements, it will probably help, thinking of "jump"s as GOTO-statements.

Two things remain to the said about jumps. First, TaxiPilot will not take them into account when doing path-calculations (when putting meaning to accel="linear" or accel="abrupt"), and instead calculate acceleration-rates as though the path would continue normally. In many situations it will therefore be adviseable to use accel="custom" for best results.

Second, when using "bouncing" objects, there will internally be twice as many path-segments than you specified (for the way back). You are allowed to address those in the "target"-attribute, making your object jump to a position on the way back. E.g. you might have an object going for A to B (path-segment 1) to C (2) to D (3) to E (4), then bouncing back to D (internal segment 5) to C (6) to B (7) to A (8). Now you could insert a jump between after 2 (when the object has arrived at C) with target="7". Then if the jump-condition is met, the object will jump to the path-segment taking it back form C to B, i.e. effectively return back before going to E.

Finally the "trigger"-action can be used to trigger an event, when the object arrives at a certain key-posiiton:

			<path x="0" y="343" time="50" accel="abrupt">
				<trigger event="do_something">
					<condition>
						<requires state="inform" to_be="on"/>
					</condition>
				</stop>
			</path>
			...

Here, after the object finishes the path-segment, the event "do_something" will be triggered. This might be useful for syncing the movement of several objects. As with all other types of actions, the "condition"-tag is mandatory.

As always, having a look at the level-files in the distribution might be more instructive than this document. Go ahead and try. E-mail me, if you experience problems or find bugs!

Version 0.7.2 of TaxiPilot introduced a number of additional ways of firing events.

Platforms may signal four different events: (1) The taxis has landed on the platform (2) the taxis has taken off (3) a passenger appeared on the platform (3) a passenger has left the platform. Using these events is really rather straight-forward:

	<platforms>
		<data y="100" passengers="yes" has_fuel="no" x1="100" passenger_base_x="110" x2="140" label="Special platform"
				land_event="do_something" take_off_event="do_something_else"
				arrive_event="yet_another_event" leave_event="and_another_one" />
		...
	</platforms>

So this platform would fire four different events in the four above-mentioned cases.

Teleporters can trigger event, when (1) the taxi gets teleported away from this teleporter and (2) the taxi gets teleported to this teleporter:

	<teleporters>
		<data x="461" y="273" destination="2" fare="0" factor_x="0" factor_y="0" frames="1" file_pattern="teleporter.png"
				arrive_event="open_door" leave_event="close_door" />
		...
	<teleporters>

Timers essentially behave like events and are defined and used in much the same way. The difference being that when triggered, the timer will not immediately do it's stuff (checking it's condition, then changing states and firing child-events), but rather wait for a specified period of time before doing so. Let's have a look at the definition of a timer:

	<timers>
		<timer ident="timer1" period="500" triggered_while_active="restart" loop_state="some_state" trigger_initially="true" >
			<condition>
				<requires state="door_can_be_opened" to_be="on"/>
			</condition>
			<change state="door_open" to="toggle"/>
			<child_event ident="some_event_or_timer"/>
		</timer>
	</timers>

So first of all, you should note, that a timer takes all the attributes and tags that a normal event does. In fact it internally is an event, and whereever you are allowed to specify an event to be triggered, you could specify a timer in exactly the same way. The additional parameters for a timer are:

"period": The duration of the delay in msecs.

"triggered_while_active": Specifies, what will happen, when the timer is triggered, while it is already actively counting down. Possible values are (1) "ignore" (default), the timer will simply ignore the triggering and continue counting down (2) "restart", the timer will start over with the count-down (3) "stop", the timer will be stopped.

"loop_state": Here you may specify the name of a state, that controls, whether the timer behaves as a single-shot-timer, i.e. stops after it has finished it's countdown and done its actions or whether the timer starts over automatically. The default is to behave as a single-shot-timer, but if you specify a valid state, each time the timer finishes it's countdown, it will check the specified state and restart itself if the state is set to "on".

"trigger_initially": Controls, whether the timer will be triggered initially (when the level is started). Default is false/no.

Besides affecting the movement of moving objects, states may control a few other things:

States can be used to (de)activate teleporters, i.e. to control (1) whether the teleporter will take the taxi anywhere and (2), whether a taxi can be teleported to the teleporter:

	<teleporters>
		<data x="461" y="273" destination="2" fare="0" factor_x="0" factor_y="0" frames="1" file_pattern="teleporter.png"
				arrive_state="state1" leave_state="state2" />
...
	<teleporters>

So, if "state1" is "off", you can not teleport to this teleporter, i.e. all teleporters that have this teleporter a their destination will be blocked. If "state2" is "off", the teleporter itself is blocked, i.e. will not take you anywhere (but depending on "state1" you can still arrive on it).

The attribute "active_state" allows you to specify a state that controls, whether the center-of-gravity is active (i.e. attracting or pushing away the taxi). This way, you can turn on and off centers-of-gravity:

	<gravity>
		<data x="320" y="240" gravity="200" potential="2" active_state="has_gravity"/<
...
	</gravity>


Last modified: Apr 03 2005 17:50 (GMT)

SourceForge Logo