3DML is a simple markup language similar to HTML, the language used to build pages on the Web. 3DML creates, or "describes", Internet-ready, three-dimensional environments called spots. Much of the syntax will be familiar to you, if you already know basic HTML.
3DML is unique because it allows you to build a 3D space on the Web without doing any 3D modeling. And you can integrate many kinds of media right into a spot, including sound, animation, 2D graphics, and text. Building a spot for the Web is actually very similar to building in the real world using familiar pieces such as simple wooden blocks or even two-by-fours from the local lumberyard. In 3DML, there are sets of predefined blocks that you can put together to build a house, or a waterfall, or anything you desire. These sets of blocks are aptly named blocksets. In the Basic block set, there are blocks which are the shape ramps, columns, signs and more. The Village block set has blocks shaped like trees, houses, and sidewalks. Each of these blocks is represented by a character on your keyboard.
Like an HTML file, a 3DML file has 2 major sections: the head and the body.
The head is the section where you set attributes for the entire spot, such as the map dimensions, ambient light and sound, the sky texture, etc.
The body is the section where you can customize your blocks, and where you create your actual map. The map is the heart of a 3DML file, where you use different kinds of blocks (represented by ASCII characters) to build a 3D space. Each block typically occupies a space of 256 x 256 x 256 (pixels). Blocks are arranged into a grid pattern to create each horizontal level of a spot. Levels are stacked on top of each other to create multi-story spots.
This tutorial will take you step-by-step through the process of creating a spot. After you have completed your first spot, you may wish to use more advanced 3DML features. Check the 3DML Tag Guide for a complete list of 3DML tags. The Block Reference Guide has a complete list of the blocks in each blockset, with their default symbols and part names. The RoverScript Reference Guide describes the advanced topic of scripting your spots. Finally, the Blockset Builder Guide details the construction of your own blocksets.
Before you begin the tutorial, there are two things you will need to do:
1. Download and install the Flatland Rover software, and
2. Download and install the tutorial files.
If you haven't downloaded Flatland Rover yet, you can download it from http://www.flatland.com/download.
There are also a few files you will need in order to follow along with the tutorial. You can get the tutorial files at http://download.flatland.com/builders/tutorial.exe. This file will unzip to a folder called Flatland Tutorial on your desktop. Save your 3DML files that you create during the tutorial in this folder.
Open a new file in your text editor. You'll want to use software that displays all ASCII characters in the same amount of space. This is also called monospacing, meaning that an "i" takes up just as much space on the screen as a "M". Monospacing is very important for creating spots, because your maps will appear as easily readable grids. The Windows accessory program Notepad works well. Do not use a fancier word processor, such as Microsoft Word, which does not display characters with monospacing; your maps will not appear as easily readable grids.
Everything in a 3DML file must be bounded by the
Go ahead and type the following lines of code to get started:
<spot version="3.3">
<head>
</head>
<body>
</body>
</spot>
When you have finished typing this, save your 3DML file with .3dml as the file extension (i.e., firstspot.3dml).
The
Add the following line of code just after your
<debug warnings="yes" />
The
<title name="title text" />
Put the following code between the
<title name="First Spot" />
<blockset href="url" />
The
Everything in a spot is made out of blocks. The <blockset> tag tells the browser what set of blocks to use to display the spot. Currently, Flatland hosts five blocksets: the basic set (contaning mostly simple block-like shapes), the basic 2 set (more simple shapes), the island set, the interior set (containing tables, chairs, etc.), and the village set (containing houses, sidewalks, trees, etc.). You can find details about the blocks in each block set on the Blocksets page.
Put the following code between the <head> tags in your 3DML file:
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
<map style="single|double"
dimensions="(columns,rows,levels)" />
The
We are going to make a spot that is 9 blocks wide, 9 blocks long, and 1 block high. Put the following code between the <head> tags in your 3DML file.
<map style="single" dimensions="(9,9,1)" />
<sky texture="image-file-path-or-URL"
color="(red,green,blue)"
brightness="brightness%" />
The
If you prefer, you can set a color for the sky rather than a texture. The color is expressed by red, green, and blue values between 0 to 255. For example, pure red would be expressed as color="(255,0,0)", pure blue is color="(0,0,255)", and pure green would be color="(0,255,0)". All other colors can be expressed as combinations of red, green, and blue.
You can also set the brightness of the sky in the
Remember, if your image file isn't in the same folder as your 3DML file,
then you also need to specify the path to your image:
Put the following code between the
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="image-file-path-or-URL"
color="(red,green,blue)" />
The
You can specify either a texture or a color with which to fill the
ground plane. If you leave the
Put the following line of code between the
<ground texture="images/dirt.gif" />
<ambient_light brightness="brightness%"
color="(red,green,blue)" />
The
Brightness defaults to 100%, if not otherwise specified. Color defaults to white, or (255,255,255). Lighting will be covered in more detail in the Lighting section of the tutorial. For now, leave your ambient light at the default levels.
Put the following code between the
<ambient_light brightness="100%" />
<ambient_sound file="wave-file-path-or-URL" VOLUME="volume%"
playback="looped|random" delay="minimum..maximum" />
The
We'll talk about other ways to use sound later in the Sound section of the tutorial.
Put the following code between the
<ambient_sound file="sounds/waves.wav" volume="65%"
playback="looped" />
After you've heard how this works, you may want to remove the
There are three other tags that can go in the head section of the 3DML
file:
The complete code for this tutorial should look like this:
<spot version="3.3">
<head>
<debug warnings="yes" />
<title name="First Spot" />
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
<map style="single" dimensions="(9,9,1)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="100%" />
<ambient_sound file="sounds/waves.wav" volume="65%" playback="looped" />
</head>
<body>
</body>
</spot>
The body of a 3DML file is where you finally get to make the map itself.
There are five main activities that are handled in the
The map is made up of individual levels that act just like stories of a building. Each level in a spot must have the same number of rows and columns. If you need to add extra rows or columns to a spot you have already been working on, you will need to add those rows or columns to every level in the spot.
Each level in a spot is bounded by the
For this first map we will use just two kinds of blocks. You can find a complete list of blocks in the Block Reference Guides.
The full block is a solid cube, filling up the entire 256 x 256 x 256 block space.
Nothing but virtual thin air. The empty block is just a place holder that keeps your maps looking like easy-to-read grids.
Put the following code between the
<level number="1">
###...###
#.......#
#.......#
#.......#
#.......#
#.......#
#.......#
#.......#
#########
</level>
You must always specify at least one entrance for your spot. The
entrance doesn't look like anything, it is just the place in the spot where
your visitors will first land. The
The location is specified as an (x,y,z) coordinate, measured in blocks (with 1,1,1 being in the top left (or northwest) corner of the bottom level.)
The name attribute allows you to name each entrance, so that you can refer to them later. They act sort of like targets in HTML. Every spot must have one entrance named "default".
The angle attribute defines what direction your visitors will be facing when they enter the spot. The angle parameter has 2 values, turn and tilt, specified in whole number degrees. The first value specifies what direction (north, south, east, west, or somewhere in between) your visitors will face. Possible values range from 0 to 359. The second value specifies whether they will be looking up or down, with possible values of -90 to 90. The default value is "0,0" which will leave your visitors facing north, and parallel to the horizon. A value of "90,0" will set your visitors facing directly east, "180,45" will leave them facing south, and 45 degrees up into the "air", etc.
Put the following code after the
<entrance location="(5,8,1)" name="default" angle="0,0" />
Congratulations!
You now have a fully functioning spot! Save the file as "firstspot.3dml" in the Flatland Tutorial folder, and open it in your Web browser or the Flatland Rover stand-alone browser (simply drag the file firstspot.3dml onto your browser window). You will find yourself in a room with 4 walls and no ceiling. You should see your sky texture overhead, and the ground texture underfoot. You will also see the sky texture in the open space in the wall in front of you. Go to the edge and look over.
<spot version="3.3">
<head>
<debug warnings="yes" />
<title name="First Spot" />
<blockset
href="http://blocksets.flatland.com/flatsets/basic.bset" />
<map style="single" dimensions="(9,9,1)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="100%" />
<ambient_sound file="sounds/waves.wav" volume="65%"
playback="looped"/>
</head>
<body>
<level number="1">
###...###
#.......#
#.......#
#.......#
#.......#
#.......#
#.......#
#.......#
#########
</level>
<entrance location="(5,8,1)" name="default" angle="0,0" />
</body>
</spot>
So lets make this simple room we've created a little taller and give it a ceiling.
The ceiling block is 32 pixels thick and fills the top of the block space. Ceiling Blocks also happen to make great floors for the level above them!
Levels in a spot don't actually have to be numbered. Numbering is an easy way to keep track of what level of a spot you are working on, but it also means that if you add any new levels to anywhere other than the top of a spot, you have to go through and change all of your level numbers. The browser will read the spot just fine whether or not you include the number attribute, so this option is entirely up to you. In this tutorial, we'll go ahead and number them.
Add the following code to your 3DML file, after the level that you've already made.
<level number="2">
###---###
#-------#
#-------#
#-------#
#-------#
#-------#
#-------#
#-------#
#########
</level>
Now we have changed the dimensions of our spot, so we will have to
change the
<map dimension="(9,9,2)" />
Let's also change the title of this spot to Tall Spot. But don't throw
away your firstspot.3dml file. We will use it again later in the tutorial.
Change the
<title name="Tall Spot" />
Now save your spot as "tallspot.3dml" and open it in your browser. You should have a tall room with a ceiling and an opening in front of you.
<spot version="3.3">
<head>
<debug warnings="yes" />
<title name="Tall Spot" />
<blockset
href="http://blocksets.flatland.com/flatsets/basic.bset"/>
<map style="single" dimensions="(9,9,2)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="100%" />
<ambient_sound file="sounds/waves.wav" volume="65%"
playback="looped"/>
</head>
<body>
<level number="1">
###...###
#.......#
#.......#
#.......#
#.......#
#.......#
#.......#
#.......#
#########
</level>
<level number="2">
###---###
#-------#
#-------#
#-------#
#-------#
#-------#
#-------#
#-------#
#########
</level>
<entrance location="(5,8,1)" name="default" angle="0,0" />
</body>
</spot>
Visitors to your spots can't fly through them. Spots have gravity, so if you want your visitors to be able climb to the upper levels of your spot, then you will have to provide a path for them to do so.
The half block is just the bottom half of a full block.
The nramp block is a ramp that rises to the height of a full Block, going up towards the north.
The nbottomramp block is a ramp that rises to the height of a half block, going up towards the north.
The ntopramp block is a ramp that rises from the height of a half block to the height of a full block, going up towards the north.
Change level 1 of your Tall Spot to look like this:
<level number="1">
###...###
#.......#
##......#
##......#
#K......#
#h......#
#k......#
#.......#
#########
</level>
Change level 2 of your Tall spot to look like this:
<level number="2">
###---###
#-------#
#N------#
#.------#
#-------#
#-------#
#-------#
#-------#
#########
</level>
Save your Tall Spot and open it in your browser. You should now be able to climb the ramps up to the roof!
<spot version="3.3">
<head>
<debug warnings="yes" />
<title name="Tall Spot" />
<blockset
href="http://blocksets.flatland.com/flatsets/basic.bset"/>
<map style="single" dimensions="(9,9,2)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="100%" />
<ambient_sound file="sounds/waves.wav" volume="65%"
playback="looped"/>
</head>
<body>
<level number="1">
###...###
#.......#
##......#
##......#
#K......#
#h......#
#k......#
#.......#
#########
</level>
<level number="2">
###---###
#-------#
#N------#
#.------#
#-------#
#-------#
#-------#
#-------#
#########
</level>
<entrance location="(5,8,1)" name="default" angle="0,0" />
</body>
</spot>
All of the 3DML blocks are assigned particular textures, and sometimes
sounds or other attributes. With the
Each kind of Block that is used in a 3DML file has a number of "parts"
that make up its shape. You can change the texture of each of these parts
with the
Lets take a look at a sample
<create symbol="a" block="full">
<part name="n,s,e,w" texture="images/brick.gif" />
</create>
This tag tells the browser that we are going to make a new block, which will be referred to in the map as the ASCII character "a", and which will be shaped like a full block. Then we tell the browser to change the texture on the 4 sides of the cube to be the file "brick.gif", located in the "images" folder. Note that the "top" and "bottom" parts of the block haven't been changed, and will appear with the default texture.
Rover supports GIF files, including animated or transparent GIFs, and JPEG files.
There are some syntax details you'll need to keep in mind:
If you want to change all of the parts of a block to be a single
texture, you can use "*" to refer to all parts at once:
In the block attribute, you can refer to the block type either by its name "full", or by its default ASCII symbol "#". You can also reuse the ASCII characters that are assigned as defaults. For example, if you aren't going to use any unaltered full blocks in your spot, then you can assign the "#" character to one of your changed blocks:
<create symbol="#" block="full">
<part name="*" texture="images/brick.gif" />
</create>
Now everytime you use the "#" character in your map, you will get full blocks that are textured with brick.gif, rather than the default texture.
All blocks have default textures that are included in the blockset. If you want to use one of these textures on a different part or different block, you can do so by preceeding the texture name with a "@".
<create symbol="#" block="#">
<part name="top" texture="@clouds.gif" />
</create>
This would put the texture clouds.gif, which usually appears as the default sky texture, on the top of the full block.
By default, textures will be "stretched" to fill the part in question
when you change a texture. If your texture is 64 x 64 pixels, and the part
you are placing it on is 256 x 256, then the texture will be stretched to
the appropriate size to fit the part. In this case, you would be making the
texture four times its original size, which would probably cause the
texture to pixelate (or lose resolution.) You also have a couple of other
options if you use the style attribute in the
On some blocks, textures may not always appear exactly as you expected. This happens on curved blocks, like spheres, domes, and the curvein and curveout blocks. To make a long story short, the way Rover usually projects textures onto blocks just doesn't work well for these curved blocks. For these blocks, it works best for the texture to be projected from just one side, and you can specify which side with the projection attribute. Possible values are "top|bottom|north|south|east|west". Projection is only necessary with textures that are "tiled" or "scaled" onto curved blocks. "Stretched" textures do not need the projection attribute.
Occasionally you may want to change the orientation of a texture on a part. For instance, you may want it to display upside-down. You can achieve this by adding an angle attribute to the <create> tag. Possible values for the angle attribute range from 0-359. The texture will be rotated in a clockwise direction. Angle="180" would turn the texture 180 degrees clockwise, in effect turning it upside down.
You can also use the
<part name="name" color="(red,green,blue)" />
You can also set a part to be translucent:
<part name="top" texture="painting.gif" translucency="50%" />
The translucency feature will only show up to users who have 3D acceleration hardware installed. Users who don't will see all opaque textures.
Faces specifies whether a texture is displayed on one, both, or none of the sides of a polygon. The default value is faces="1" which means that textures are applied to just one side of a polygon. So with a full block in its default state, you can see the textures from the outside of the block. But if you were to step inside the block itself, you would not see anything, because the textures are not displayed on the "inside" sides of the polygons. But if you specify faces="2", then the textures will be displayed on both sides of each polygon. This is particularly useful if you use a translucent or transparent texture on one part of a block. For instance, if you use a translucent texture on the south side of a full block, and you use faces="2" for all the other parts, then you will be able to see the inside of the block when you look through the south side.
The faces attribute can also be used to make polygons invisible, by using faces="0". This will prevent textures from being displayed on both sides of the polygon, making it invisible. You still won't be able to walk through it though.
The faces attribute goes in the <part> tag.
The solid attribute determines whether or not your visitors will collide with that particular part of a block. If solid="no", then they will be able to walk right through that part. The default value is solid="yes".
So the syntax for the entire <part> tag is as follows:
<part name="name" texture="folder/image.gif"
color="(r,g,b)" style="tiled|stretched|scaled"
projection="top|bottom|north|south|east|west"
faces="0|1|2" solid="yes|no" translucency="number%"
angle="0-359" />
When a visitor first comes to view your spot over the Internet, it may
take a few seconds (or even minutes depending the size of your texture
files and the speed of the visitor's Internet connection) to download the
custom textures that you have assigned to your blocks. The shape of your
spot will be displayed much more quickly however. If Rover is ready to
display a block, but the texture has not finished downloading from the
Internet, then a placeholder texture will be displayed until the custom
texture arrives. Every blockset has a placeholder texture associated with
it that will be used by default, but you can also assign a different
texture to act as the placeholder. The
<placeholder texture="image-file-path -or- URL" />
You can also use different colors as placeholders on specific blocks by
using the color attribute in the
Textures will be downloaded in the order in which they appear in the
3DML file, so it is a good
idea to put the
Or you can use the
<load texture="folder/image.gif" />
Put the following code in your Tall Spot 3DML file, just after the <body> tag:
<create symbol="#" block="full">
<part name="n,s,e,w" texture="images/pinkmarble.gif" />
</create>
<create symbol="-" block="ceiling">
<part name="bottom" texture="@edgetop.gif" />
</create>
Save your file and open it in your browser. The walls of your spot should now appear to be pink marble, and the ceiling should be a sort of metal screen-like texture. If you go up onto the roof, however, you will see that the top of the ceiling blocks haven't changed.
<spot version="3.3">
<head>
<debug warnings="yes" />
<title name="Tall Spot" />
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset"/>
<map style="single" dimensions="(9,9,2)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="100%" />
<ambient_sound file="sounds/waves.wav" volume="65%" playback="looped"/>
</head>
<body>
<create symbol="#" block="full">
<part name="n,s,e,w" texture="images/pinkmarble.gif"/>
</create>
<create symbol="-" block="ceiling">
<part name="bottom" texture="@edgetop.gif" />
</create>
<level number="1">
###...###
#.......#
##......#
##......#
#K......#
#h......#
#k......#
#.......#
#########
</level>
<level number="2">
###---###
#-------#
#N------#
#.------#
#-------#
#-------#
#-------#
#-------#
#########
</level>
<entrance location="(5,8,1)" name="default" angle="0,0" />
</body>
</spot>
In addition to changing textures, the
Orientation is accomplished by specifying two different values. First, you specify what direction you want the top of the block to face (up,down,north,south,east, or west). Then you specify an angle of rotation around that axis.
Lets look at a new block called the curvein block, and turn it around to see how orientation works.
The curvein block looks like a full block that has been "scooped out" to be concave on the top and south sides.
Now if you want to turn the curvein block around so that the scooped out side faces the top and north, you would use the following tag:
<create symbol="A" block="curvein">
<param orient="up,180" />
</create>
Now every time the browser encounters an "A" in the map, it will take a curvein block, leave its top pointing "up", and turn it 180 degrees clockwise, (around the Y axis) making the curved side of the block face up and north.
Now, if you were standing to the south of a curvein block, and you wanted to tip it over to the right, so its top faced east, you would use this code:
<create symbol="A" block="curvein">
<param orient="east,0" />
</create>
So Rover will make the top of the block face "east", and will rotate it "0" degrees around that axis.
Now imagine that you want the "scooped out" part to face down and east. You'll need to point the top of the block towards the "east", and then rotate "270" degrees. That is a 270 degree clockwise rotation, if you were looking at the original top of the block, which is now pointing east.
Rotation is limited to values of 0, 90, 180, or 270. Rotation is always clockwise around what was originally the y axis. Imagine that you are standing on the top of the block, and you remain there as the block is tilted to the "east". You are now standing on the east side of the block, looking at what used to be the top of the block. The rotation will take place in a clockwise direction from where you are standing. Having a physical block to play with on your desk may be of some help. Here are some examples to help you visualize all this topsy-turvy-ness.
Without any rotation, blocks are designed to look "right" to a visitor who is facing north. This is just a general rule that hopefully will make building a littleeasier. For instance, the curvein and curveout blocks both have their curves on the south side, so that you can see them when you are facing north. The front door of the house blocks (in the Village Blockset) all face south, so that they look correct to a visitor who is facing north.
In the Basic Blockset, we have gone ahead and provided north, south, east and west orientations of the ramp blocks, just to make life a little easier. So to get a ramp that goes up to the south, you can just use the sramp block, rather than having to use an orient attribute on an nramp block.
First, lets just put a few different curvein blocks in your spot just to see how they work.
Add the following code just after the
<create symbol="A" block="curvein">
</create>
<create symbol="B" block="curvein">
<param orient="up,90" />
</create>
<create symbol="C" block="curvein">
<param orient="down,0" />
</create>
<create symbol="D" block="curvein">
<param orient="west,90" />
</create>
And change level 1 of tallspot.3dml to look like this:
<level number="1">
###..D###
#.......#
##...C..#
##......#
#K...B..#
#h......#
#k...A..#
#.......#
#########
</level>
Save the file and open it in your browser. Take a look at how each orientation attribute changed the different curvein blocks.
Go back to the four <create> tags for blocks A, B, C, and D, and change them to look like this:
<create symbol="A" block="curvein">
<param orient="east,0" />
</create>
<create symbol="B" block="curvein">
<param orient="west,0" />
</create>
<create symbol="C" block="curvein">
<param orient="north,90" />
</create>
<create symbol="D" block="curvein">
<param orient="north,270" />
</create>
Change level 1 of tallspot.3dml to look like this:
<level number="1">
###...###
#A.....B#
##......#
##......#
#K......#
#h......#
#k......#
#D.....C#
#########
</level>
Save the file and open it in your browser. The room should now have nice curved corners.
<spot version="3.3">
<head>
<debug warnings="yes" />
<title name="Tall Spot" />
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset"/>
<map style="single" dimensions="(9,9,2)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="100%" />
<ambient_sound file="sounds/waves.wav" volume="65%" playback="looped"/>
</head>
<body>
<create symbol="A" block="curvein">
<param orient="east,0" />
</create>
<create symbol="B" block="curvein">
<param orient="west,0" />
</create>
<create symbol="C" block="curvein">
<param orient="north,90" />
</create>
<create symbol="D" block="curvein">
<param orient="270,90" />
</create>
<create symbol="#" block="full">
<part name="n,s,e,w" texture="images/pinkmarble.gif" />
</create>
<create symbol="-" block="ceiling">
<part name="bottom" texture="@edgetop.gif" />
</create>
<level number="1">
###...###
#A.....B#
##......#
##......#
#K......#
#h......#
#k......#
#D.....C#
#########
</level>
<level number="2">
###---###
#-------#
#N------#
#.------#
#-------#
#-------#
#-------#
#-------#
#########
</level>
<entrance location="(5,8,1)" name="default" angle="0,0" />
</body>
</spot>
The ability to make hyperlinks between information sources is arguably the most important feature of the Internet. Spots are no different in this respect than HTML Web pages. Links are accomplished in 3DML by naming entrances and exits in your file, and pointing them at each other, or at outside spots or Web pages.
Links can occur anywhere in a spot. You can place an exit on any block, including an empty block. Traditionally, however, exits are used in conjuction with the portal block. When a visitor to your spot rolls their mouse over an exit, the destination title or URL will appear just below the cursor, to let them know where the link will take them.
The portal block is used to indicate a hyperlink. It looks something
like a doorway, only a little twistier. You can place an image over the
doorway to give your visitors some clue as to where the link leads. By
default, a portal block is linked to http://www.flatland.com. You can link
the portal to any URL by using an
When you are making your own spots, you'll want to use the
<exit location="(column,row,level)"
href="file_name#entrance_name"
trigger="click on,step on" text="text"
target="destination name" />
Like the
The
Entrances and exits can also be attached to specific blocks by including them in the <create> tag. The tag syntax is the same, except that you don't need a location parameter. Remember, when you
attach an exit directly to a block, then every instance of that block in your map will link to the same URL. When you attach an entrance to a block, and then use that block more than once in a map, then you will effectively have more than one entrance with the same name. Lets say you have an entrance named "doorway" attached to a block that appears three times in your map. When a visitor travels through a link to the "doorway" entrance, Rover will chose one of the 3 doorway entrances to use at random.
Entrances can only be placed on empty spaces or on certain kinds of blocks. If an entrance is placed on a location that is occupied by a block with a solid shape, then Rover will remove the model for that block, and it won't appear in your spot. This includes the portal Block. If you want a portal to act as an entrance as well as an exit, you should place the entrance on the location just in front of the portal block. The blocks in the Basic Blockset that are allowed as entrances are these: floor, ceiling, ground, halfceiling, halffloor, all light blocks, and sound. Check the Blockset Guides to be sure whether or not a particular block can act as an entrance.
We are going to make a link between firstspot.3dml and tallspot.3dml, and a link between two different locations within tallspot.3dml.
First, lets put in a portal. Change Level 1 of firstspot.3dml to look like this:
<level number="1">
###.@.###
#.......#
#.......#
#.......#
#.......#
#.......#
#.......#
#.......#
#########
</level>
Then, add this exit tag just before the
<exit location="(5,1,1)" href="tallspot.3dml#default"
trigger="click on, step on" text="tallspot"/>
This has established a one-way link from the portal in firstspot.3dml,
located at (5,1,1), to the default entrance in tallspot.3dml. A visitor can
travel from firstspot.3dml to tallspot.3dml, but not back again, because
there is no
In order to make this a two-way link, add this tag before the
<exit location="(5,1,1)" href="firstspot.3dml#default"
trigger="click on, step on" text="firstspot" />
And put a portal in that location to mark the link:
<level number="1">
###.@.###
#A.....B#
##......#
##......#
#K......#
#h......#
#k......#
#D.....C#
#########
</level>
Save both of your files, and open firstspot.3dml in your browser. Go back and forth between the links!
You probably noticed that when you linked back into firstspot.3dml, you
didn't enter in the same location from which you left. This is because
there is only one
In order to create a direct two-way link, add this
<entrance location="(5,2,1)" name="second" angle="180,0" />
And go back to the
<exit location="(5,1,1)" href="firstspot.3dml#second"
trigger="click on, step on" text="firstspot" />
Now you have a direct link between two locations in two different spots. Next, we'll add an internal link between two different locations within tallspot.3dml.
In your tallspot.3dml file, add these tags to the body:
<entrance location="(7,6,1)" name="floor" />
<entrance location="(7,6,3)" name="roof" />
<exit location="(7,7,1)" href="#roof"
trigger="click on, step on" text="Up to the Roof" />
<exit location="(7,7,3)" href="#floor"
trigger="click on, step on" text="Down to the Floor" />
Change Level 1 to the following:
<level number="1">
###.@.###
#A.....B#
##......#
##......#
#K......#
#h......#
#k....@.#
#D.....C#
#########
</level>
And then add a Level 3 that looks like this:
<level number="3">
.........
.........
.........
.........
.........
.........
......@..
.........
.........
</level>
And now you will need to change your
<map dimensions="(9,9,3)" />
Save both of your files and open tallspot.3dml in your browser. Experiment jumping around between all of the links you have created.
<spot version="3.3">
<head>
<debug warnings="yes" />
<title name="Tall Spot" />
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
<map style="single" dimensions="(9,9,3)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="100%" />
<ambient_sound file="sounds/waves.wav" volume="65%" playback="looped" />
</head>
<body>
<create symbol="A" block="curvein">
<param orient="east,0" />
</create>
<create symbol="B" block="curvein">
<param orient="west,0" />
</create>
<create symbol="C" block="curvein">
<param orient="north,90" />
</create>
<create symbol="D" block="curvein">
<param orient="north,270" />
</create>
<create symbol="#" block="full">
<part name="n,s,e,w" texture="images/pinkmarble.gif" />
</create>
<create symbol="-" block="ceiling">
<part name="bottom" texture="@edgetop.gif" />
</create>
<level number="1">
###.@.###
#A.....B#
##......#
##......#
#K......#
#h......#
#k....@.#
#D.....C#
#########
</level>
<level number="2">
###---###
#-------#
#N------#
#.------#
#-------#
#-------#
#-------#
#-------#
#########
</level>
<level number="3">
.........
.........
.........
.........
.........
.........
......@..
.........
.........
</level>
<entrance location="(5,8,1)" name="default" angle="0,0" />
<exit location="(5,1,1)" href="firstspot.3dml#second"
trigger="click on,step on" text="firstspot" />
<entrance location="(7,6,1)" name="floor" />
<entrance location="(7,6,3)" name="roof" />
<exit location="(7,7,1)" href="#roof"
trigger="click on, step on" text="Up to the Roof" />
<exit location="(7,7,3)" href="#floor"
trigger="click on, step on" text="Down to the Floor" />
</body>
</spot>
There are four different ways that sounds can be used in spots: ambient
sounds, the sound block, sounds attached to blocks in the
The sound block has no 3D model. You can't see it at all; you can only hear it.
If you want to have a sound that appears to come from an object, then
you want to use the
The tag for sound has eight attributes: file, volume, playback, delay, flood, radius, rolloff, and name. The syntax is as follows:
<create symbol="x" block="sound">
<sound file="sounds/noise.wav" volume="number%"
playback="looped|random|once|single"
delay="minimum..maximum" flood="yes|no"
radius="number of blocks" rolloff="1.0"
name="sound name" />
</create>
Be sure to include the path when you name the file, if your sounds aren't in the same folder as your 3DML file.
Volume is expressed as a whole number percentage.
Playback determines how a sound will be played. There are 4 different playback options: looped, random, once, and single. Playback="looped" will cause the sound to play continuously. If playback="once", the sound will play only once. If playback="single", then the sound will play once every time the player enters the specified radius. If playback=random", the sound will play at random intervals. If playback="random", you can also specify a range of delay times between playbacks. Delay times are measured in seconds, and are measured from the time that the sound begins, rather than when it ends. For example, if your sound is five seconds long, playback="random", and delay="5..10", then sometimes the sound will play back to back, as the length of the sound file is the same as the minimum delay time, and no more than 5 seconds will ever elapse between when the sound ends and when it begins again. The maximum delay time, 10 seconds, minus the length of the sound itself, 5 seconds, leaves a maximum silence of 5 seconds.
The volume of a sound will drop off gradually as you get farther away from the source. But if flood="yes", then the sound will play at the specified volume throughout the specified radius, rather than dropping off gradually.
Radius is measured in blocks, and has two different roles. On a sound with flood="yes", the radius defines how large an area will be filled with that sound. If volume="100%", flood="yes", and radius="5", then the sound will be heard at full volume right up to the edge of the 5 block border, at which point it will turn off completely. On a sound with playback="once" or playback="single", the radius acts as a trigger. The sound will be played when the user enters the specified radius.
Rolloff determines how quickly the sound volume will taper off as you move away from the sound source. In most cases, the default value (rolloff="1.0") is the most natural setting for this parameter. But if you need more control over how the sound drops off, you can change the rolloff value. If rolloff="2.0", then the sound will drop off twice as fast (meaning it will be audible only half as far away from the source.) If rolloff="0.5", then the sound will drop off half as fast (meaning it will be audible twice as far away.)
The default values for these attributes are as follows: volume="100%", playback="looped" delay="5..10" radius="1" rolloff="1.0".
Note that a block can only have one sound attached to it, unless you give each sound a name attribute.
You can also assign sounds to a specific location in the map by simply
adding a location parameter to the
<sound file="sounds/noise.wav" volume="number%"
playback="looped|random" delay="minimum..maximum"
flood="yes|no" radius="number of blocks"
location="(column,row,level)" />
Having lots of sound sources in a spot can tax the performance of Rover on slower machines. If you attach a sound to your floor block for instance, and that block appears 25 times in your spot, Rover has to keep track of 25 different sound sources. Visitors to your spot will get much better performance out of Rover if you place that sound on one location, or scatter a few sounds sources around the spot. If you set flood="yes", and your radii overlap, the sound will play at a consistent volume throughout the area.
Just like custom textures, sound files will be downloaded in the order
in which they appear in the 3DML file. Because sound files are often quite
large, it is a good idea to list any
In tallspot.3dml, add the following code after the
<create symbol="~" block="sound">
<sound file="sounds/giggle.wav" volume="75%"
radius="5" flood="yes" playback="looped" />
</create>
<create symbol="c" block="ceiling">
<part name="top" texture="images/smiley.gif" />
<part name="bottom" texture="@edgetop.gif" />
<sound file="sounds/guffaw.wav" volume="100%"
playback="random" delay="3..6" />
</create>
Change Level 2 to look like this:
<level number="2">
###---###
#c-----c#
#N------#
#.------#
#-------#
#-------#
#-------#
#c-----c#
#########
</level>
And change Level 3 to look like this:
<level number="3">
.........
.........
.........
.........
....~....
.........
......@..
.........
.........
</level>
Save your file and open it in your browser. Go up to the roof of the spot, move around and listen to the different ways the sounds work. You should be able to hear 3 different sounds: the constant ambient sound (unless you took this tag out), the guffaws that you hear intermittently and are louder if you are close to a smiley, and the giggle that plays at a constant volume throughout the area.
<spot version="3.3">
<head>
<debug warnings="yes" />
<title name="Tall Spot" />
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset"/>
<map style="single" dimensions="(9,9,3)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="100%" />
<ambient_sound file="sounds/waves.wav" volume="65%"
playback="looped" />
</head>
<body>
<create symbol="~" block="sound">
<sound file="sounds/giggle.wav" volume="75%"
radius="5" flood="yes" playback="looped" />
</create>
<create symbol="c" block="ceiling">
<part name="top" texture="images/smiley.gif" />
<part name="bottom" texture="@edgetop.gif" />
<sound file="sounds/guffaw.wav" volume="100%"
playback="random" delay="3..6" />
</create>
<create symbol="A" block="curvein">
<param orient="east,0" />
</create>
<create symbol="B" block="curvein">
<param orient="west,0" />
</create>
<create symbol="C" block="curvein">
<param orient="north,90" />
</create>
<create symbol="D" block="curvein">
<param orient="270,90" />
</create>
<create symbol="#" block="full">
<part name="n,s,e,w" texture="images/pinkmarble.gif" />
</create>
<create symbol="-" block="ceiling">
<part name="bottom" texture="@edgetop.gif" />
</create>
<level number="1">
###.@.###
#A.....B#
##......#
##......#
#K......#
#h......#
#k....@.#
#D.....C#
#########
</level>
<level number="2">
###---###
#c-----c#
#N------#
#.------#
#-------#
#-------#
#-------#
#c-----c#
#########
</level>
<level number="3">
.........
.........
.........
.........
....~....
.........
......@..
.........
.........
</level>
<entrance location="(5,8,1)" name="default" angle="0,0" />
<exit location="(5,1,1)" href="firstspot.3dml#second"
trigger="click on,step on" text="firstspot" />
<entrance location="(7,6,1)" name="floor" />
<entrance location="(7,6,3)" name="roof" />
<exit location="(7,7,1)" href="#roof"
trigger="click on, step on" text="Up to the Roof" />
<exit location="(7,7,3)" href="#floor"
trigger="click on, step on" text="Down to the Floor" />
</body>
</spot>
We have already discussed the
Aside from ambient_light, there are three different categories of light: orb light, point_light, and spot_light. Orb light is light that shines from a specific direction in the sky, illuminating the entire spot. Point_light is light that shines in all directions from a specified location. Spot_light is light that shines in a specified direction from a specified location.
<orb texture="folder/image.gif"
position="(turn,tilt)"
brightness="percentage%"
color="(red,green,blue)" />
The
No matter what texture you use in the sky, light will shine from the location of the texture illuminating the entire spot. Unlike ambient_light, light from the orb will create shadowed areas. Ambient light will illuminate all areas of a spot, regardless of whether or not they are exposed to the sky. But orb light will only illuminate surfaces that face the light source.
Position refers to where the orb will sit in the sky. Position is expressed as a pair of angles called "turn" and "tilt". The turn angle specifies what direction the orb will be in. Possible values are from 0-359, with 0 refering to north, 90 to east, 180 to south, etc. The tilt angle defines how high in the sky the orb will appear. Possible values range from -90 to 90, with 0 being at the ground, or "horizon", 90 being directly overhead, etc.
Brightness defines how bright the orb light will be. And texture defines what image will be displayed. Brightness will be 100% by default, and the default orb texture will be displayed in the sky if no other texture is specified.
Color allows you to define the color of the light, but colored light will only appear to users who have 3D acceleration hardware. Other users will see the normal white light.
You can also turn your orb into a hyperlink by adding an href parameter:
<orb texture="folder/image.gif" position="(turn,tilt)"
brightness="percentage%" color="(red,green,blue)"
href="url" text="text" target="target_frame" />
First, you'll want to lower the ambient_light in your spot so that your
lighting effects will show up. In tallspot.3dml, change the
<ambient_light brightness="30%" />
Then place the following tag in the head section of tallspot.3dml:
<orb position="(45,45)" brightness="60%" />
There are two different styles of point_light: static and pulsate. Static point_lights are good for lighting a general area of a spot. Pulsating point_lights are good for alien abduction scenes. (OK, and a few other more mundane things as well. But alien abductions are the preferred way to use them!)
The static point_light tag looks like this:
<point_light style="static" position="(x,y,z)"
brightness="brightness%" radius="#_of_blocks"
flood="yes|no" color="(red,green,blue)" />
Here, position refers to the placement of the light within the block space. Position="(0,0,0)" would place the light at the bottom southwest corner of the block. Position="(128,256,128)" would place the light in the middle of the top of the block. Lights will be placed in the center of the block (128,128,128) by default if no position is defined.
Brightness defines how bright the light will be at the position of the source.
Radius defines how far from the source the light will be visible. If radius="4" and brightness="90%", then the light will be 90% brightness at the location of the light source, and will fade gradually to whatever the ambient_light level is 4 blocks away.
That is, unless flood is set to "yes". Flood="yes" will cause the light to flood the entire radius at the specified brightness level. In the above example, if flood were turned on, then light would appear at 90% brightness for the entire 4 block radius, and the light would drop sharply to the ambient level at the edge of the 4 block radius. The flood parameter defaults to "no".
Color allows you to define the color of the light, but colored light will only appear to users who have 3D acceleration hardware. Other users will see the normal white light.
Note that every polygon inside of a light's radius will not necessarily be illuminated. Only those polygons that face the light will be lit. A polygon that is within the radius of a light, but is not facing it, will not be affected by the light.
The tag for a pulsating point_light is slightly different:
<point_light style="pulsate" position="(x,y,z)"
brightness="min%..max%" radius="#_of_blocks"
flood="yes|no" color="(red,green,blue)"
speed="cycles_per_second" />
Notice that the brightness parameter describes a range between two values. And there is an added speed attribute. If brightness="20%..80%" and speed="2", then the light level will pulse from 20% to 80% and back again twice every second. You can slow the pulse down by assigning a value less than 1 to the speed parameter. Speed=".25" would create a light that takes four seconds to raise to its brightest level and back again.
Go back to the
<point_light style="pulsate" position="(128,0,128)"
brightness="20%..90%" radius="1" flood="yes"
color="(0,0,255)" speed="1" />
So the entire
<create symbol="c" block="ceiling">
<part name="top" texture="images/smiley.gif" />
<part name="bottom" texture="images/pinkmarble.gif" />
<sound file="sounds/guffaw.wav" volume="100%"
radius="2" playback="random" />
<point_light style="pulsate" position="(128,0,128)"
brightness="20%..90%" radius="2" flood="yes"
color="(0,0,255)" speed="1" />
</create>
This will make a pulsating light under all of your smileys. Remember, your smileys are ceiling blocks with smiley faces on the top of the block space. This point_light is assigned to the bottom of the block space. Your smiley textures will not be lit by it because they face away from it. In order to light the smiley textures themselves, you would want to place a light above the smiley blocks, in level 3 of your map.
There are 3 different kinds of spot_lights: static, search, and revolve. A static spot_light shines a still cone of light. A searching spot_light moves back and forth between 2 specified points. A revolving spot_light rotates in a defined circle.
The tag for a static spot_light looks like this:
<spot_light style="static" position="(x,y,z)"
brightness="brightness%" radius="#_of_blocks"
flood="yes|no" color="(red,green,blue)"
direction="(turn,tilt)" cone="angle" />
Position, brightness, radius, flood, and color all work the same here as they do for point_lights.
Direction describes where the spot_light is focused, and is expressed as a pair of angles. If no direction parameter is present, the light will face exactly north and horizontal to the ground plane by default, or direction="(0,0)". The first angle is called the "turn". The turn angle describes rotation in the horizontal plane. Possible values range from 0 to 359, where 0 is north, 180 is south, etc. The second angle is called the "tilt" and describes how far above or below the horizontal plane the light points. Possible values range from -90 to 90, where 0 is horizontal to the ground, 90 points straight up, and -90 points straight down. With the turn and tilt angles, you can describe any possible direction for your light to point.
Cone describes how wide the spot_light is. Cone is the diameter of the influence of the light, expressed as a degree, (0 to 359). The default value for cone is 45.
So a spot_light with direction="(45,0)" and cone="90" would illuminate the northeastern corner of a scene (assuming that the spot_light is in the center of the scene.) The turn angle is 45 pointing directly northeast, the tilt angle is 0 pointing parallel to the ground plane, and the cone is 90 which spreads the light out over a 90 degree area from the north axis to the east axis.
Direction="(0,-90)" would create a light that points straight down.
The tag for a searching spot_light would look like this:
<spot_light style="search" position="(x,y,z)"
brightness="brightness%" radius="#_of_blocks"
flood="yes|no" color="(red,green,blue)"
direction="(turn1,tilt1)..(turn2,tilt2)"
cone="angle" speed="cycles_per_second" />
In a search style spot_light, you can define two different directions and the search light will move smoothly back and forth between the two directions. The path that the search light takes between the two defined directions is determined by which direction has a higher value for its turn angle. The light will always travel from the lowest turn angle value to the highest. Values for the turn angles can range from -359 to 359. To make a search light that moves between a point directly north to a point directly east, you would designate direction="(0,0)..(90,0)", and the light would travel clockwise from the north horizon to the east horizon. But what if you wanted a light to travel between the same 2 points, but to go the long way around, passing by the south and west horizons on the way? Then you would change the value of the eastern direction to read (-270,0). Direction="(0,0)..(-270,0)" would create a light that travels clockwise from the eastern horizon to the northern horizon and back again, passing through the south and west on the way.
Speed determines how fast the search light will move between the two directions. Speed is expressed as cycles per second. Speed="2" would make a light that moves from direction 1 to direction 2 and back again twice per second.
To create a revolving spot_light use the following code:
<spot_light style="revolve" position="(x,y,z)"
brightness="brightness%" radius="#_of_blocks"
flood="yes|no" color="(red,green,blue)"
direction="(turn1,tilt1)..(turn2,tilt2)"
cone="angle" speed="revolutions_per_second" />
This tag is very similar to the syntax for the search light, but the light will continue in a full circle through the 2 specified directions. If the turn angle of the first direction is smaller than the second one, then the light will rotate in a clockwise direction. If the second turn angle is smaller, then the motion will be counterclockwise.
There are three different ways to describe light in a 3DML file:
The tags that describe point_lights and spot_lights can be placed in the
Alternately, a light can be assigned to a specific location in your map, regardless of what block might be there. To do this, simply put your light tag in the body of your 3DML file (usually near the end with your entrances and exits). You will also need to add a location parameter to the light tag to place the light at a specific location in the map. The location parameter works just the way it did for sounds: location="(column, row, level)"
In tallspot.3dml, add the following tag to the end of the body, just before your entrances and exits:
<spot_light style="search" position="(1,1,128)"
brightness="100%" radius="7" location="(4,4,1)"
direction="(17,3)..(132,3)" cone="30" speed=".5" />
This should give you a spot_light that searches back and forth between the two portals on level 1 of tallspot.3dml
The pointlight block has no 3D model. A visitor won't see any object where the pointlight block sits, but light will emanate from it, lighting the surrounding blocks. By default, the pointlight block is a static point_light at 100% brightness and a radius of 4.
Now change the code for level 2 to look like this:
<level number="2">
###---###
#c-----c#
#N------#
#'------#
#-------#
#-------#
#-------#
#c-----c#
#########
</level>
This should give you a bright light over the ramp area.
Save your file and open it in your browser to see the light. (Don't you wish illumination was always this easy?) You should see pulsing lights in the four corners of the first level of tallspot.3dml (and they will be blue if you have 3D acceleration hardware), a search light that roves between the two portals, and a constant bright light over the ramp area. You will also notice that the orb light is visible even when you are "inside". Lights in 3DML do not cast hard shadows. The orb light shines right through the "roof" and illuminates the walls that face it inside as well.
<spot version="3.3">
<head>
<debug warnings="yes" />
<title name="tall spot" />
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
<map style="single" dimensions="(9,9,3)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="30%" />
<ambient_sound file="sounds/waves.wav" volume="65%"
playback="looped" />
<orb position="(45,45)" brightness="60%" />
</head>
<body>
<create symbol="~" block="sound">
<sound file="sounds/giggle.wav" volume="75%" radius="5"
flood="yes" playback="looped" />
</create>
<create symbol="c" block="ceiling">
<part name="top" texture="images/smiley.gif" />
<part name="bottom" texture="@edgetop.gif" />
<sound file="sounds/guffaw.wav" volume="100%"
playback="random" delay="3..6" />
<point_light style="pulsate" position="(128,0,128)"
brightness="20%..90%" radius="1" flood="yes"
color="(0,0,255)" speed="1" />
</create>
<create symbol="a" block="curvein">
<param orient="east,0" />
</create>
<create symbol="b" block="curvein">
<param orient="west,0" />
</create>
<create symbol="c" block="curvein">
<param orient="north,90" />
</create>
<create symbol="d" block="curvein">
<param orient="270,90" />
</create>
<create symbol="#" block="full">
<part name="n,s,e,w" texture="images/pinkmarble.gif" />
</create>
<create symbol="-" block="ceiling">
<part name="bottom" texture="@edgetop.gif" />
</create>
<level number="1">
###.@.###
#a.....b#
##......#
##......#
#k......#
#h......#
#k....@.#
#d.....c#
#########
</level>
<level number="2">
###---###
#c-----c#
#n------#
#'------#
#-------#
#-------#
#-------#
#c-----c#
#########
</level>
<level number="3">
.........
.........
.........
.........
....~....
.........
......@..
.........
.........
</level>
<spot_light style="search" position="(1,1,128)"
brightness="100%" radius="7" location="(4,4,1)"
direction="(17,3)..(132,3)" cone="30" speed=".5" />
<entrance location="(5,8,1)" name="default" angle="0.0" /%gt;
<exit location="(5,1,1)" href="firstspot.3dml#second"
trigger="click on,step on" text="firstspot" />
<entrance location="(7,6,1)" name="floor" />
<entrance location="(7,6,3)" name="roof" />
<exit location="(7,7,1)" href="#roof"
trigger="click on, step on" text="up to the roof"/>
<exit location="(7,7,3)" href="#floor"
trigger="click on, step on" text="down to the floor" />
</body>
</spot>
Popups are 2D images or text that you can assign to specific locations in your map. They are not visible to the visitor at first, but "pop up" on the screen when the visitor gets within a defined radius of the location that holds the popup, or when she rolls her mouse over a block that holds the popup. Popups are very useful for including extra information that you want a visitor to be able to see, without cluttering up your spot. They are great for providing detailed info about many objects in the spot. They also can be used to provide a simple navigational map of your spot that is visible right at the entrance.
The
Lets start by just looking at a simple <popup> tag:
<popup location="(column,row,level)"
trigger="rollover,proximity|everywhere" radius="blocks"
texture="folder/image.gif" placement="mouse|top-left|top|
top-right|left|center|right|bottom-left|bottom|bottom-right"
brightness="number%" />
Location describes where in the map the popup is anchored. If the popup
is attached to a block in a
Trigger is how the popup gets activated, either by rolling over it with the mouse, or by coming within the specified radius, or both. Or, if trigger="everywhere", then the popup will appear throughout the entire spot.
Radius is how close the user has to be to the location to trigger the popup (when trigger is set to "proximity"). Radius is described as a whole number of blocks. Unlike lights and sounds, the radius for popups only functions on one level, i.e. a popup on level 4 with a radius of 2 will not be visible on levels 3 or 5.
Texture defines the file that will pop up.
Placement describes where on the user's screen the image will appear. When placement="mouse", the popup will appear in the same location as the user's cursor.
Brightness defines how bright the popup will appear.
You can also put text in popups by adding the following attributes to
the
text="message"
textalign="top-left|top|top-right|left|center|right|
bottom-left|bottom|bottom-right"
textcolor="(r,g,b)"
Textalign defines how your text will appear in relationship to the popup texture.
Textcolor is the color of the text.
You can also assign a color to the popup itself, rather than a texture. To do so, you will need these two additional tags:
color="(r,g,b)"
size="(width,height)"
Size defines the size of the rectangle of color on which your text will appear, measured in pixels. If you place text over an image, then the color attribute will be used to define a color for a drop shadow on the text, making it easier to read against the background image. If no color is defined, then the background of the popup will be transparent by default.
Popups can also contain clickable imagemaps. The syntax for creating an imagemap is almost exactly the same as it is in HTML, except that the tag is called imagemap rather than map, and 3DML supports rectangle and circle shapes in the imagemap, but not polygons. To create an imagemap, put the following code somewhere in the body section of your 3DML file:
<imagemap name="imagemap name">
<area shape="rect|circle" coords="(x1,y1,x2,y2)|(x,y,radius)"
href="destination URL" target="destination target"
text="display text" />
...
</imagemap>
When creating a rectangular area of an imagemap, the coordinates x1,y1 refer to the top left corner of the rectangle, and x2,y2 refer to the bottom right corner. When creating a circular area of an imagemap, x,y refers to the center of the circle.
In order to use an imagemap in your popup, add the following parameter to
the
imagemap="imagemap name"
Note: If you are using an imagemap with your popup, and you have trigger set to rollover, then your placement will have to be mouse. Otherwise, the popup will disappear before your visitor can select anything!
So the entire
<popup location="(column,row,level)"
trigger="rollover,proximity|everywhere"
radius="number-of-blocks"
texture="image-file-path-or-URL"
color="(r,g,b)"
placement="mouse|top-left|top|top-right|left|center|
right|bottom-left|bottom|bottom-right"
size="(width,height)"
text="message"
textalign="top-left|top|top-right|left|center|right|
bottom-left|bottom|bottom-right"
textcolor="(r,g,b)"
imagemap="map name"
brightness="brightness%" />
Default values are as follows: trigger="proximity", placement="center", color="transparent", textcolor="(255,255,255)", size="(320,240)", textalign="center", brightness="100%".
Add these
<popup location="(3,3,3)" radius="2" text="What's so funny?"
color="(0,255,0)" size="(100,60)" textcolor="(255,0,0)"
placement="top" />
<popup location="(3,7,3)" radius="2" text="Beats me man!"
color="(0,0,255)" size="(100,60)" textcolor="(255,0,0)"
placement="bottom" />
Save your file and open it in your browser. Move around on the roof and take a look at how the popups work.
<spot version="3.3">
<head>
<debug />
<title name="Tall Spot" />
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
<map style="single" dimensions="(9,9,3)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="30%" />
<ambient_sound file="sounds/waves.wav" volume="65%"
playback="looped" />
<orb position="(45,45)" brightness="60%" />
</head>
<body>
<create symbol="~" block="sound">
<sound file="sounds/giggle.wav" volume="75%" radius="5"
flood="yes" playback="looped" />
</create>
<create symbol="c" block="ceiling">
<part name="top" texture="images/smiley.gif" />
<part name="bottom" texture="@edgetop.gif" />
<sound file="sounds/guffaw.wav" volume="100%"
playback="random" delay="3..6" />
<point_light style="pulsate" position="(128,0,128)"
brightness="20%..90%" radius="1" flood="yes"
color="(0,0,255)" speed="1" />
</create>
<create symbol="A" block="curvein">
<param orient="east,0" />
</create>
<create symbol="B" block="curvein">
<param orient="west,0" />
</create>
<create symbol="C" block="curvein">
<param orient="north,90" />
</create>
<create symbol="D" block="curvein">
<param orient="270,90" />
</create>
<create symbol="#" block="full">
<part name="n,s,e,w" texture="images/pinkmarble.gif" />
</create>
<create symbol="-" block="ceiling">
<part name="bottom" texture="@edgetop.gif" />
</create>
<level number="1">
###.@.###
#A.....B#
##......#
##......#
#K......#
#h......#
#k....@.#
#D.....C#
#########
</level>
<level number="2">
###---###
#c-----c#
#N------#
#'------#
#-------#
#-------#
#-------#
#c-----c#
#########
</level>
<level number="3">
.........
.........
.........
.........
....~....
.........
......@..
.........
.........
</level>
<spot_light style="search" position="(1,1,128)"
brightness="100%" radius="7" location="(4,4,1)"
direction="(17,3)..(132,3)" cone="30" speed=".5" />
<entrance location="(5,8,1)" name="default" angle="0.0" />
<exit location="(5,1,1)" href="firstspot.3dml#second"
trigger="click on,step on" text="firstspot" />
<entrance location="(7,6,1)" name="floor" />
<entrance location="(7,6,3)" name="roof" />
<exit location="(7,7,1)" href="#roof"
trigger="click on,step on" text="Up to the Roof" />
<exit location="(7,7,3)" href="#floor"
trigger="click on,step on" text="Down to the Floor" />
<popup location="(3,3,3)" radius="2" text="What's so funny?"
color="(0,255,0)" size="(100,60)" textcolor="(255,0,0)"
placement="top" />
<popup location="(3,7,3)" radius="2" text="Beats me man!"
color="(0,0,255)" size="(100,60)" textcolor="(255,0,0)"
placement="bottom" />
</body>
</spot>
Sprites are special types of blocks that don't really have a 3D model, but that offer particular behaviors to 2D images in 3D space. There are 4 types of sprites:
The simplest sprite block is simply a single plane on which you can place a texture and which doesn't really have any behavior at all.
The spriterevolve block is a single plane that spins around on its central axis.
The spriteface block is a single plane that always faces the viewer. No matter what direction you approach the spriteface block from, the image that is assigned to it will appear to be facing you.
The spritefacet block will unwrap a gif animation and present each frame to be viewed from a different angle in the spot. For example, if you took photographs of your favorite comfy chair from 8 different vantage points, all in the same horizontal plane, then put those images together in a gif animation, the spritefacet block would unwrap that animation, making it appear as if the chair were in your spot, and you could walk all the way around it.
There are 5 parameters that are associated with sprites. All sprites can take the align, solid, and size parameters. Align specifies at what height in the blockspace the sprite will appear. Sprites will appear at the bottom of the block space by default. They can also be assigned to the top or the center. solid determines whether or not you can walk through the sprite. If solid="no", then a visitor can walk right through the sprite. If solid="yes", then the sprite will be solid. Solid="yes" by default. Size of course determines how large the sprite will be. Size is measured in pixels and cannot exceed "(256,256)". If no size is specified, the sprite will be the same size as the image that is placed on it.
The sprite block can also take an angle parameter, specifying what angle the sprite is facing. The angle is expressed as whole number degrees from 0 to 359. The default value is "0". The spriterevolve block can take a speed parameter, expressed as revolutions per second. The default value is ".5".
Put the following
<create symbol="1" block="sprite">
<part name="*" texture="images/animate.gif" />
<param angle="45" solid="no" />
</create>
<create symbol="2" block="spriterevolve">
<part name="*" texture="images/animate.gif" />
<param speed="1" solid="no" />
</create>
<create symbol="3" block="spriteface">
<part name="*" texture="images/animate.gif" />
<param align="top" />
</create>
<create symbol="4" block="spritefacet">
<part name="*" texture="images/animate.gif" />
<param align="center" />
</create>
And change the map to look like this:
<level number="1">
###.@.###
#.......#
#.1.....#
#.....2.#
#.......#
#.3.....#
#....4..#
#.......#
#########
</level>
Save the file and open it in your browser. Walk around each of the different sprites to see how they behave. Try walking right through them.
<spot version="3.3">
<head>
<debug />
<title name="First Spot" />
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
<map style="single" dimensions="(9,9,1)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="100%" />
<ambient_sound file="sounds/waves.wav" volume="65%"
playback="looped" />
</head>
<body>
<create symbol="1" block="sprite">
<part name="*" texture="images/animate.gif" />
<param angle="45" />
</create>
<create symbol="2" block="spriterevolve">
<part name="*" texture="images/animate.gif" />
<param speed="1" />
</create>
<create symbol="3" block="spriteface">
<part name="*" texture="images/animate.gif" />
<param align="top" />
</create>
<create symbol="4" block="spritefacet">
<part name="*" texture="images/animate.gif" />
<param align="center" />
</create>
<level number="1">
###.@.###
#.......#
#.1.....#
#.....2.#
#.......#
#.3.....#
#....4..#
#.......#
#########
</level>
<entrance location="(5,2,1)" name="second" angle="180,0" />
<entrance location="(5,8,1)" name="default" angle="0,0" />
<exit location="(5,1,1)" href="tallspot.3dml#default"
trigger="click on,step on" text="tallspot" />
</body>
</spot>
Let's take a look at some sample code, then we'll go into the details:
<create symbol="1" block="full">
<part name="*" texture="images/sad.gif" />
<action trigger="roll on" >
<replace source="2" />
</action>
</create>
<create symbol="2" block="full">
<part name="*" texture="images/happy.gif" />
</create>
Here we have created a full block, which has the image "sad.gif" on all its parts, and assigned it the symbol "1". Whenever a user rolls her mouse over this block, the block will be replaced with the "2" block, which is also a full block but which has the image "happy.gif" on all its parts.
Note that there is no other action on the "2" block, so once this action
has been triggered once, there is no more functionality. When the player
rolls off the block, it will still appear to be happy. But we can also add
an
<create symbol="2" block="full">
<part name="*" texture="images/happy.gif" />
<action trigger="roll off" />
<replace source="1" />
</action>
</create>
Now there is another
Let's look at the complete syntax for action and replace:
<action location="(column,row,level)" trigger="roll on|
roll off|click on|step in|step out|proximity|timer|location"
radius="number-of-blocks" delay="min..max" />
<replace source="symbol|(column,row,level)"
target="(column,row,level)" />
</action>
Radius is measured in blocks and is only used when the trigger is "step in", "step out", or "proximity". When trigger="proximity", the action will remain active as long as the user is within the specified radius. Once they leave the radius, then the action will reverse itself.
Delay is measured in seconds and is only used when the trigger is "timer". If only one value is included for delay, then the delay will always be the same number of seconds. If a minimum and maximum delay are specified, then the delay will be a random length in between those 2 values.
If the action is not attached to a block through a
Target (in the
Target (in the
Source specifies the block that will be used to replace whatever block sits at the target.
<action trigger="step in" radius="3" location="(5,5,1)">
<exit href="hell.3dml#yerdead" />
</action>
So any time a user wanders within 3 blocks of the location (5,5,1), they
will be sent to the entrance named "yerdead" in the spot "hell.3dml".
Each action can have only one trigger, but a single
Actions can also work inside of imagemaps. The code is the same as for a
regular imagemap, except that the
<imagemap name="pop1train">
<action shape="rect" coords="0,0,100,100"
trigger="click on">
<replace source="+2" target="(10,6,2)" />
</action>
</imagemap>
The source and target for a
<create symbol="#" block="full">
<action>
<replace source="(-2,+3,0) target="(0,0,+1)" />
</action>
</create>
Lets say that this block is sitting at the location (4,4,4) in your map. This action tells Rover to take the block that is at (2,7,4) [That's -2 columns, +3 rows, +0 levels] and place a copy of it at (4,4,5) [+0 columns, +0 rows, and +1 level].
Still working in your firstspot.3dml file, add the following
<create symbol="#" block="full">
<action trigger="click on">
<replace source="A" />
</action>
</create>
<create symbol="A" block="full">
<part name="*" texture="images/pinkmarble.gif" />
</create>
The "#" blocks that make up the walls of this spot will now replace
themselveswith the "A" block when they are clicked on. Save the file and
open it in your browser. Click on the walls to see them change.
Now lets try a different kind of action. Change the
<create symbol="2" block="spriterevolve">
<part name="*" texture="images/animate.gif" />
<param speed="1" />
<action trigger="timer" delay=".85">
<replace source="5" />
</action>
</create>
And add a new
<create symbol="5" block="sprite">
<part name="*" texture="images/animate.gif" />
<action trigger="timer" delay="2">
<replace source="2" />
</action>
</create>
Save the file and open it in your browser. You'll see that the spriterevolve block will now revolve for a little less than a second, and then replace itself with a regular sprite block that doesn't move for 2 seconds. Then this sprite block will replace itself with the original spriterevolve block again.
And now lets use the target parameter, and do several replaces in one
<level number="2">
.........
.........
.........
.........
.........
.........
.........
.........
.........
</level>
And don't forget to change the dimensions in your
<map style="single" dimensions="(9,9,2)" />
Then add the following
<create symbol="B" block="pyramid">
<part name="*" texture="images/pinkmarble.gif" />
<action trigger="click on">
<replace source="." />
<replace source="P" target="(1,1,2)" />
<replace source="P" target="(1,9,2)" />
<replace source="P" target="(9,1,2)" />
<replace source="P" target="(9,9,2)" />
<replace source="P" target="(3,1,2)" />
<replace source="P" target="(7,1,2)" />
</action>
</create>
<create symbol="P" block="pyramid">
<part name="*" texture="images/pinkmarble.gif" />
</create>
And now add the "B" block to your map. Change Level 1 to look like this:
<level number="1">
###.@.###
#.......#
#.1.....#
#.....2.#
#...B...#
#.3.....#
#....4..#
#.......#
#########
</level>
Save the file and open it in your browser. You'll see a pink pyramid in
the center of the spot. When you click on this pyramid, it will disappear
and 6 other pyramids will appear along the top of the wall. The original
block disappears throught the first
<spot version="3.3">
<head>
<debug />
<title name="First Spot" />
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
<map style="single" dimensions="(9,9,2)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="100%" />
<ambient_sound file="sounds/waves.wav"
volume="65%" playback="looped" />
</head>
<body>
<create symbol="1" block="sprite">
<part name="*" texture="images/animate.gif" />
<param angle="45" />
</create>
<create symbol="2" block="spriterevolve">
<part name="*" texture="images/animate.gif" />
<param speed="1" />
<action trigger="timer" delay=".85">
<replace source="5" />
</action>
</create>
<create symbol="3" block="spriteface">
<part name="*" texture="images/animate.gif" />
<param align="top" />
</create>
<create symbol="4" block="spritefacet">
<part name="*" texture="images/animate.gif" />
<param align="center" />
</create>
<create symbol="5" block="sprite">
<part name="*" texture="images/animate.gif" />
<action trigger="timer" delay="2">
<replace source="2" />
</action>
</create>
<create symbol="#" block="full">
<action trigger="click on">
<replace source="A" />
</action>
</create>
<create symbol="A" block="full">
<part name="*" texture="images/pinkmarble.gif" />
</create>
<create symbol="B" block="pyramid">
<part name="*" texture="images/pinkmarble.gif" />
<action trigger="click on">
<replace source="." />
<replace source="P" target="(1,1,2)" />
<replace source="P" target="(1,9,2)" />
<replace source="P" target="(9,1,2)" />
<replace source="P" target="(9,9,2)" />
<replace source="P" target="(3,1,2)" />
<replace source="P" target="(7,1,2)" />
</action>
</create>
<create symbol="P" block="pyramid">
<part name="*" texture="images/pinkmarble.gif" />
</create>
<level number="1">
###.@.###
#.......#
#.1.....#
#.....2.#
#...B...#
#.3.....#
#....4..#
#.......#
#########
</level>
<level number="2">
.........
.........
.........
.........
.........
.........
.........
.........
.........
</level>
<entrance location="(5,2,1)" name="second" angle="180,0" />
<entrance location="(5,8,1)" name="default" angle="0,0" />
<exit location="(5,1,1)" href="tallspot.3dml#default"
trigger="click on,step on" text="tallspot" />
</body>
</spot>
It is possible to use blocks from more than one blockset in a single
spot. Simply include more than one
Within each blockset, each block has a default symbol. When using more than one blockset, however, you may encounter situations where the same default symbol is used to represent 2 different blocks from 2 different blocksets. In this situation, the default symbols from the primary blockset (the one that appears first in your 3DML file) take precedence. You can still use the default symbol for a block in a secondary blockset if that symbol isn't used in the primary blockset. If you want to refer to a block that comes from a secondary blockset, thenjust preceed the name of the block with the name of the blockset, separated by a colon:
<create symbol="A" block="village:housebase1">
Textures refered to with the @ symbol will come from the primary blockset. Again, to refer to a texture from a secondary blockset, preceed the name of the texture with a colon and the name of the blockset:
<part name="n" texture="@village:bluedoor.gif" />
Lets put a lamp block from the Village blockset into our spot. First,
add this extra
<blockset href="http://blocksets.flatland.com/flatsets/village.bset" />
The Basic and Village blocksets are designed so that the default block
symbols don't overlap, so we can use the lamp block without doing anything
special in the
Add the following code to the beginning of the body section of tallspot.3dml:
<create symbol="v" block="village:lamp">
</create>
And change level 3 of your map to look like this:
<level number="3">
.........
.........
.........
.........
....~....
.........
..v...@..
.........
.........
</level>
Now go back to the create tag that you made way back in the beginning of the tutorial for the full block (#) and change it to read:
<create symbol="#" block="full">
<part name="n,s,e,w" texture="@village:sqcel.gif" />
</create>
Now save your file and open it in your browser. You should see a streetlamp from the village set up on the roof, and the walls on the bottom level should be covered in square bumpy things.
Back at the very beginning of the tutorial, we talked about the
When you use a double-character map, you must also use double-characters
in your
Each block has a single character symbol by default. The default double-character symbol for each block is the same as the default single character, preceeded by a "." So the default symbol for the full block, "#", becomes simply ".#". An nramp block is normally "N", and its double-character default is ".N", etc.
When you make a map with double characters, you can leave a space in between the symbols for each block, so that you can read your map more easily. Here's a very simple single character map, and the same map made again with double characters:
<level number="1">
#####
#.N.#
#...#
#W.E#
#...#
#.S.#
#####
</level>
<level number="1">
.# .# .# .# .#
.# .. .N .. .#
.# .. .. .. .#
.# .W .. .E .#
.# .. .. .. .#
.# .. .S .. .#
.# .# .# .# .#
</level>
Its not necessary for you to convert your tallspot.3dml spot to double characters, but here's what it would look like if you did, with all changed tags in bold.
<spot version="3.3">
<hread>
<debug />
<title name="Tall Spot" />
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
<blockset href="http://blocksets.flatland.com/flatsets/village.bset" />
<map style="double" dimensions="(9,9,3)" />
<sky texture="images/clouds.gif" brightness="90%" />
<ground texture="images/dirt.gif" />
<ambient_light brightness="30%" />
<ambient_sound file="sounds/waves.wav" volume="65%"
playback="looped" />
<orb position="(45,45)" brightness="60%"
href="http://www.flatland.com"
text="Check out Flatland Online!" />
</head>
<body>
<create symbol=".v" block="village:lamp">
</create>
<create symbol=".~" block="sound">
<sound file="sounds/giggle.wav" volume="75%" radius="5"
flood="yes" p