Documente Academic
Documente Profesional
Documente Cultură
NaaLaa 5
By Marcus.
The biggest difference between NaaLaa 4 and NaaLaa 5 is that the new version comes with a bunch of
standard libraries and editors. These libraries and editors can be used when creating many types of
games. They simply take care of all the boring stuff.
The language itself hasn't evolved that much. There are some new commands for drawing transformed
(rotated and scaled) images. And there's a new data type called object. Also, you can now use some of
the the virtual machine instructions directly in your code, when speed is really, really crucial. And
speaking of speed, the virtual machine has of course become a little faster.
Documentation
Introduction
The compiler
Primitive data types
Arrays
Type Conversion
Selection
Loops
Procedures
Functions
Hidden and visible variables
Constants
Reference parameters
Objects
Maths
Strings
Window and general
Text output and input
Files
Fonts
Images
Image transformations
Zones
Standard libraries
Introduction
Speed
Math
BezierCurve
Keycodes
Tilemap
Raycaster
Mode7
SimpleWidget
AWRCollision
SimpleParticle
Password
Editors
Tilemap Editor
Raycaster Editor
Introduction
[ Go back ]
In your My Documents folder there should now be a new folder named NaaLaa 5 Examples. Once
you've started NED5, this is where you should look for example programs. In this folder you'll also find
audiere.dll. This dll is required for the examples, and for all the programs you create, to run. So
remember to always have a fresh copy of this file in the same folder as your executables. You may
distribute it freely - please have a look at http://audiere.sourceforge.net.
Freeware
NaaLaa is freeware. You may use it however you want, and you may do whatever you want with the
things you create. The creator of NaaLaa can, of course, not be held responsible for any damage caused
directly or indirectly by any of the included components.
Technical details
The compiler and the editor was written in Borland C++ Compiler 5.5 (the free command line tools)
using Crimson Editor.
NaaLaa produces standalone executable files, but it's still an interpreted language. The compiler creates
assembler-like code from your programs. This code is included with an interpreter in the final
executable file.
Neither DirectX or OpenGL is used for graphics rendering. The Creator doesn't believe in such things.
Instead homemade software routines are used for both 2D and 3D graphics. The number of images you
can use therefor only depends on the available RAM memory. There are many advantages with this
technique (yeah yeah, there might be one or perhaps two drawbacks too ...). You can modify images on
the fly without having to wait for them to be uploaded to some silly texture memory. You needn't worry
about different color formats and the bad artefacts they may cause, as NaaLaa uses 32 bits per pixel until
the very end blit from the backbuffer to the window. A NaaLaa program gives the exact same graphical
output on every machine it runs on. For speed reasons only 7 bits, instead of 8, are used for the alpha
component of images.
[ Go back ]
Compiler
[ Go back ]
From the NaaLaa Editor you compile a program by pressing F7, execute a compiled program with F6 or
compile and execute with F5. If you're using the command prompt or another editor the usage for the
compiler is:
The filename should be written without its extension (it's assumed to be ".txt"). If successful, two files
are created filename.sbe and filename.exe. Usually the sbe file can be deleted (see Program Units). If the
L parameter is added filename.lib will be generated instead of the exe file (see Libraries).
To compile the program into a Java Applet, press F9 from the editor or use:
jnaalaa works like naalaa, but besides from an executable and an sbe-file, filename.java is created. Read
more about it in the Java applet chapter. If you compile a program into a Java library, with the L option,
filename.libj will be created.
[ Go back ]
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/compiler.html1/6/2012 2:35:34 AM
NaaLaa - Program units
Program units
[ Go back ]
The whole program unit approach was developed before the system with libraries. It is possible that
program units wont be supported in the next version of NaaLaa, so don't get too attached to them -
they're silly and awkward anyway.
When you compile a program, two files are created: filename.exe (the executable file) and filename.sbe
(a program unit file). Usually the sbe can be deleted, as it is also included in the executable file. But it is
possible to stop the execution of a program and start executing another sbe. In that case the sbe of the
external program is needed (at least for a while).
Java Notice!
Of course, you can't run external NaaLaa program units from an applet. All your source code need to be
in one program.
Examples
Look for ex_run and ex_library_import in the NaaLaa 5 Examples folder.
Stop execution of the current program and run an external (or included) program unit, sbe_filename.
args$[]
The string array args can be used for passing parameters between program units, as it remains untouched
With this compiler directive you can include external program units in your current program. This
makes the resulting executable file independent of all sbe files. It is very important that every program
unit is only included once in the entire program (usually in the unit that is to be launched first). You can
even use a pure launcher for the entire program that gathers all the program units and creates a final
executable. Ex:
rem A game.
include "main.sbe"
include "hiscore.sbe"
include "the_end.sbe"
run "main.sbe"
[ Go back ]
Libraries
[ Go back ]
A library is a precompiled set of sub routines. You create a library by adding the L parameter to the
compiler (ex: naalaa my_program L) or by pressing F8 in the NaaLaa Editor. This generates a file
with the ending ".lib". To create a Java library you can add the L parameter to jnaalaa (ex: jnaalaa
my_program L) or select Create Java library in NED's Program menu. This generates a file with the
ending ".libj".
Libraries may contain global variables and constants. You can even add code outside of the sub routines.
All such library code is executed at the very beginning of the program that imports the library (no matter
where you place the import command presented below). Constants declared in a library are visible to
other programs.
Examples
Look for ex_library and ex_library_import in the NaaLaa 5 Examples folder.
Sub routines
procedure import filename$
This compiler directive imports library lib_filename. All sub routines and constants present in the library
can then be accessed from the program. Ex:
import "MyLib.lib"
If you're making a Java applet and have created a Java version of a library that you wish to import, the
compiler will automatically look for the Java version (replace the "lib" extension with "libj").
If the compiler can't find a library that you're trying to import, it will look in its own library folder
(usually C:\Program Files (x86)\NaaLaa Creator\NaaLaa 5\bin\libs\). This means that you don't need to
copy the standard libraries to the same folder as your own program.
[ Go back ]
Java applets
[ Go back ]
A Java applet is rather different from a NaaLaa program. Therefor some rules need to be obeyed before
you can create an applet from your program.
Is it Java?
If you need to know in your program if it's a Java applet or not, you can call the function javac.
function javac()
Stop running!
Your program code runs in its own thread in Java. This thread can not automatically be stopped safely
from outside, for example if the user leaves your page. In any infinite loop or a loop that can only be
exited by user action you should therefor call the function running. If this function returns false, the user
or the browser wants your program to terminate. You should then do whatever you need and call end.
This will cause the thread that your program is running in to stop. Ex:
The procedures wait keydown and wait mousebutton will automaticly release program control if your
applet needs to shut down.
function running()
Returns true if the applet is okay (or if it's not an applet at all) or false if your program ought to be
terminated.
Unreachable statements
The Java compiler, not the NaaLaa compiler that generates Java code, has an annoying habbit of
generating errors whenever it finds an "unreachable" statement. For example:
procedure Dummy()
wln "I'm a silly procedure"
return
wln "Nobody sees me here but Java!"
endproc
, works fine in NaaLaa. But the Java compiler simply won't accept it. So, be very careful with what you
write.
The creator refuses to make NaaLaa detect unreachable statements, as their existance is extremely useful
in many cases, for example when you're debuging a program and need to inactivate certain parts of your
code.
Compiling
Before you can create a Java applet from your NaaLaa program, you need to install the Java
Development Kit from Oracle and mess around a bit with Windows. Follow these steps:
Now, compiling is easy. Simply press F9 from the editor or select Compile to Java applet from the
Program menu. To start with, this will create a java file with the same name and in the same folder as
your program. If this went well, the Java compiler will attempt to compile the previously created java
file.
If you get an error message saying: "Error: Could not execute javac", you have either forgotten to install
the JDK or not set the path variable correctly. A reboot might help, maybe.
The output of the Java compiler (javac) will be written to the normal output window. If the only thing
you see is "Success", you should uncork a bottle of wine and give yourself a pat on the shoulder. You
now have a class file with the same name and in the same folder as your program.
If you get one or several error messages it's usually about "unreachable statements". The only thing you
can do is to look at the error message, perhaps open the java file, and try to figure out what part of your
code it was that caused the error. If you open the java file you'll probably recognize most of your
NaaLaa code.
On the Web
If you've managed to successfully create a class file you're probably ready to add it to a web page. The
simplest html document to run a program named my_program would look like this:
<HTML>
<HEAD>
</HEAD>
<BODY>
<APPLET CODE="my_program.class" WIDTH=640 HEIGHT=480></APPLET>
</BODY>
</HTML>
my_program.class and all your data files (fonts, images etc) should be in the same folder as the html
document. But before you can test the html page, you also need to copy some NaaLaa class files to your
folder. You can find the files under NaaLaa 5 Examples/Classes or in the bin/classes folder of your
NaaLaa installation. All these files are needed:
NaaLaaApplet.class
NaaLaaApplet$BMFont.class
NaaLaaApplet$NaaLaaEndException.class
NaaLaaApplet$NaaLaaFile.class
NaaLaaApplet$NaaLaaSound.class
NaaLaaApplet$Surface.class
NaaLaaApplet$Zone.class
If nothing happens when you look at your html page in a web browser, or if something strange happens,
you probably need to check the Java Notice! sections of this document. The most common things are:
● A Java error is reported: You've forgotten to add all the class files listed above to your web page
folder.
● No text output: You've forgotten to load a font, as there's no default font in an applet generated
with NaaLaa. Look at the Java Notice! section of the Fonts chapter.
● No transparency in images: Java doesn't support alpha channels for bmp images - you need to
convert all images with transparency to png. Look at the Java Notice! section of the Images
chapter.
[ Go back ]
Fonts
[ Go back ]
All fonts created in a program are converted to a bitmap format. This format is also used when saving
and loading fonts.
Java Notice!
You can not create or save fonts in a Java applet created with NaaLaa. If you need text output and input
in an applet, you have to create a font, save it with save font font_id, txt_filename$, img_filename$ (the
single file version won't work) and load it in the applet with load font font_id, txt_filename$,
img_filename$. You'll also need to convert the bmp file (img_filename) into a png or gif, as Java does
not support transparent bmp files.
Examples
Look in the NaaLaa 5 Examples folder for examples.
Sub routines
procedure create font font_id, name$, s[, b[, i[, u[, smooth]]]]
procedure save font font_id, filename$
procedure load font font_id, filename$
procedure save font font_id, txt_filename$, img_filename$
procedure load font font_id, txt_filename$, img_filename$
procedure set font font_id
procedure free font font_id
function font(font_id)
function fheight(font_id)
function fwidth(font_id, txt$)
procedure create font font_id, name$, s[, b[, i[, u[, smooth]]]]
Create font font_id of size s from name name. The font will be bold, italic or underlined if b, i or u is set
Save font font_id into two files, the data file txt_filename and the image file (bmp) img_filename. If you
want to edit the font image in some imaging software, you should know that each character in the bitmap
has 4 pixels of extra space in all directions (for outlines, shadows etc).
Load font font_id from two files, the ascii txt_filename and the image img_filename. Note that you can
use the single file version of save font to save both the data and the loaded image into one file.
Free font font_id. All fonts are automatically freed when the program exits.
function font(font_id)
function fheight(font_id)
Return the pixel width of txt if it was to be written with font font_id.
[ Go back ]
Images
[ Go back ]
For safety and compability reasons, NaaLaa uses only software routines for all drawing operations.
Java Notice!
This is probably the biggest conflict between NaaLaa and Java. Currently, NaaLaa only supports bmp
images (this will hopefully change soon). Java can load them too but does not support transparency.
Therefor, unless you use colorkeys or the long version of load image, you better use the png image
format in your applets. In the examples you'll often see something like:
if javac()
img$ = ".png"
else
img$ = ".bmp"
endif
...
load image 0, "data/ball" + img$
load image 1, "data/cloud" + img$
This causes the program to load ball.png and cloud.png if it's run as an applet and ball.bmp and cloud.
bmp if it's a Windows executable. You can also use jpg and gif images in applets!
Hopefully someone will soon write a NaaLaa library that loads gif and jpg files ...
Examples
ex_images
ex_raster
Sub routines
procedure load image image_id, filename$
procedure load image image_id, filename$, alpha_filename$
procedure save image image_id, filename$
Load filename to image image_id. The only supported file formats are bmp and ppm (in applets you can
use gif, jpg and png).
Load filename to image image_id and use the red color components of alpha_filename as alpha channel
for the image.
In GIMP, you can extract the alpha channel of an image with Color/Components/Decompose and save it
as a black and white image. To flatten the colors of the original image correctly, so that it can be saved
without an alpha channel, first use Layer/Transparency/Threshold-Alpha with threshold set to 0, then
use Image/Flatten Image. By using indexed color mode, you can greatly decrease the sizes of your
images this way (very good for java applets).
Java notice!
You can not save images from an applet created with NaaLaa.
Create image image_id and set its width and height to w and h.
Free image image_id. All images are automaticly freed when program exits.
function image(image_id)
Make color r, g, b (RGB) transparent when drawing image image_id. An image can only have one color
key.
Java Notice!
Java does not support color keys, atleast it can't be done in a way that would be faster than using a real
alpha channel. When you call this function in an applet, every pixel in the image with the specified
color will have its alpha value set to zero. But if the image is changed later on, new pixels with the
specified color will not automaticly be made transparent!
Set destination image for all drawing operations to image_id. By default drawing is done to the primary
image (the window's back buffer). You should therefor always pass primary as image_id when you're
done drawing to another image.
Draw part of image image_id, defined by the position src_x, src_y and the width and height src_w,
src_h, to x, y.
Create a grid of c columns and r rows for image image_id. The above version of draw image can then be
used to draw a certain cel of the image. Cels are indexed row by row starting with 0.
Draw pixel at x, y.
Set pixel at x, y to current drawing color (see set color and set colori)
Draw rectangle of width w and height h with upper left corner at x, y. If fill is submitted and set to true,
the rectangle is filled.
Set color to r, g, b (RGB) or r, g, b, a (RGBA) if an alpha (transparency) value is submitted. This color
will affect all drawing operation, including text output.
Java Notice!
Colorized drawing of images is really slow in Java. So try to avoid it as much as possible. Also be
aware of that text output (wln/write) draws as many images as there are characters in the text. That
makes colorized text output really slow. If you need a green font, simply create a green font and use it
instead of set color. You can also use images to represent static text.
function pixel[](x, y)
Set current drawing color to c. c is an integer containing one byte per color channel (in the RGBA
format AARRGGBB). See pixeli for more information.
Get color as an integer (in the RGBA format AARRGGBB) at position x, y. If an image, image_id, is
submitted, the pixel will be read from that image.
Java Notice!
Additive draw mode is not available in applets. The images will be drawn normally even after calling
set additive true.
procedure hscroll dx
procedure vscroll dy
Set clipping rectangle for current image to position x, y and width and height w, h. Graphics wont be
drawn outside of this rectangle.
function cels(image_id)
function cols(image_id)
function rows(image_id)
function width(image_id)
function height(image_id)
Draw a horizontal line from x_start, y to x_end, y. This line uses image image_id as a texture. The
texture coordinates at x_start, y are u_start, v_start, and the texture coordinates at x_end, y are u_end,
v_end. The texture coordinates are measured from the top left corner of image image_id, and they
should be in the range 0..1 (where 1, 1 is the bottom right of the image).
This procedure does not handle transparency (alpha channel) of the source image, nor is it affected by
the additive draw mode. Also, the color set with set color works as a "fog" on the texture. That is, if you
use set color 255, 255, 255, 0, the texture will look as it does in the image image_id. But if you use set
color 255, 255, 255, 255, the texture will be replaced by a solid white color.
Draw a vertical line from x, y_start to x, y_end. This line uses image image_id as a texture. The texture
coordinates at x, y_start are u_start, v_start, and the texture coordinates at x, y_end are u_end, v_end.
The texture coordinates are measured from the top left corner of image image_id, and they should be in
the range 0..1 (where 1, 1 is the bottom right of the image).
For information about how set color affects this procedure, have a look at draw hraster.
[ Go back ]
ex_images
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_images.html1/6/2012 2:35:35 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_images.txt
rem ==================================================================
rem ex_images
rem ==================================================================
rem Use png images and load font if it's a java applet.
if javac()
if javac() then load font 0, "courier.txt", "courier.png"
img_ext$ = ".png"
else
img_ext$ = ".bmp"
endif
rem Don't forget to download the GNU Image Manipulation Program (GIMP)
rem from http://www.gimp.org ! It's free and it's gooood!
rem ------------------------------------------------------------------
rem Use:
rem
rem load image id, filename$
rem
rem to load an image. The id can be any integer value, and there's no
rem limitation (other than the available RAM) to the amount of images
rem you can load.
rem The only supported image format is 8, 24 and 32 bit BMP. For
rem the 8 bit format, the images may use RLE compression. You can also
rem use the PPM image format (not binary), but it's really just a
rem waste of space (yes, I admit, a handy waste of space).
rem ------------------------------------------------------------------
rem ------------------------------------------------------------------
rem Load same image again, but add a color key for transparency.
rem ------------------------------------------------------------------
rem With:
rem
rem create image id, width, height
rem
rem you can create an image of size width*height.
rem ------------------------------------------------------------------
rem All drawing is normally done to the primary image (the window's
rem back buffer). But by calling:
rem
rem set image id
rem
rem , you can draw to any existing image.
set image 4
for i = 0 to 999
set color rnd(256), rnd(256), rnd(256)
draw line rnd(128), rnd(64), rnd(128), rnd(64)
next
rem When you're done drawing to any image, you should set the
rem destination image back to primary.
set image primary
rem ------------------------------------------------------------------
glow = 0
glowSpeed = 4
do
set color 128, 128, 192
cls
set caret 0, 0
set color 255, 255, 255
write "Normal, colorized and additive drawing "
rem width(id)
rem
rem and
rem
rem height(id)
rem
rem returns the width and height of an image.
for i = 0 to 7
draw image 3, 16 + i*48, 304, i
next
redraw
wait 10
ex_raster
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_raster.html1/6/2012 2:35:36 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_raster.txt
rem ==================================================================
rem ex_raster
rem
rem I'm afraid I don't fully have the courage or time to explain
rem exactly what I'm doing here, but it's still a nice effect, right?
rem ==================================================================
hstep# = 1.0/float(w)
u# = 0.0
for i = 0 to w - 1
draw vraster 0, x + i, y + int(sin(float(i)*4.0 + a)*16.0), y + h - int(sin(float(i)*4.0 + a)*16.0),
u, 0.0, u, 1.0
u = u + vstep
next
Variables can be of three different types: integer, floating point and string. You create a variable by
assigning a value to it or by simply naming it (which also initializes its value). All variables must begin
with a letter or an underscore. Floating point variables must end with # and strings with $ the first time
they're used. Ex:
an_integer = 5
a_float# = 2.5
a_string$ = "Hello"
another_integer
another_float#
another_string$
another_integer, another_float and another_string will get the values 0, 0.0 and "".
Normal mathemathic rules and precendence aply to integers and floating points. Strings may only use +
and - and paranthesis. Ex:
Examples
ex_datatypes
[ Go back ]
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/datatypes.html1/6/2012 2:35:36 AM
NaaLaa - Primitive data types - Example
ex_datatypes
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_datatypes.html1/6/2012 2:35:36 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_datatypes.txt
rem ==================================================================
rem ex_datatypes
rem ==================================================================
rem Variables contain values that can change during program execution.
rem
rem There are three different types of variables: integer, floating
rem point (decimal) and string (text). A variable is declared to be of
rem floating point type by adding a # character to the end of its name
rem And a variable is declared to be of string type by adding a $ to
rem the end of its name.
rem
rem Variable names are case sensitive. They must begin with a letter
rem but may then also contain numbers and underscores.
rem
rem Variables may be created at any place in your code. But later on
rem hidden, visible and local variables will be introduced.
rem
rem You create a variable by simply adding its name somewhere or by
rem assigning a value of proper type to it:
rem int_variable = <integer expression>
rem float_variable# = <floating point expression>
rem string_variable$ = <string expression>
rem
rem Integer and floating point expressions use the standard math
rem rules. But string expressions may only use +, - and parenthesis.
anInteger = (anInteger*10 + 15*3)/2
aFloat# = (aFloat#*10.0 + 15.0*3.0)/2.0
Arrays
[ Go back ]
Arrays can be of any size, dimension and type. You create an array by assigning values to it or by
naming it:
an_integer_array[] = [1, 2, 3, 4, 5]
a_float_array[3]
a_float_array[0] = 1.0
a_float_array[1] = 2.5
a_float_array[2] = 5.0
a_2d_string_array$[][] = [["an", "array"], ["of", "strings"]]
another_integer_array[] = an_integer_array
an_empty_3d_float_array[][][]
Arrays may change size, but not number of dimensions, during program execution:
an_integer_array[5]
an_integer_array[] = [1, 2, 4, 5, 6, 7, 8]
another_integer_array[] = an_integer_array
an_integer_array[]
Examples
ex_arrays
Sub routines
function sizeof(array)
function sizeof(array)
an_array[4]
s = sizeof(array)
, sets s to 4.
an_array$[4][3][5]
s = sizeof(array, 1)
, sets s to 3.
[ Go back ]
ex_arrays
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_arrays.html1/6/2012 2:35:37 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_arrays.txt
rem ==================================================================
rem ex_arrays.txt
rem ==================================================================
rem Use:
rem
rem sizeof(array)
rem
rem to get the size of the array and loop through the elements.
wln "Integer array 1:"
for i = 0 to sizeof(intArray) - 1
wln " ", intArray[i]
next
wln
rem Init and set a 2D array with 3*2 elements. As the example shows,
rem the dimensions needn't be constants.
xSize = 3
ySize = 2
intArray2D[xSize][ySize]
intArray2D[0][0] = 1
intArray2D[0][1] = 2
intArray2D[1][0] = 3
intArray2D[1][1] = 4
intArray2D[2][0] = 5
intArray2D[2][1] = 6
rem Use:
rem
rem sizeof(array, dimension)
rem
rem to get the size of a specific array dimension.
wln "2D array 1:"
for i = 0 to sizeof(intArray2D, 0) - 1
write " "
for j = 0 to sizeof(intArray2D, 1) - 1
write intArray2D[i][j], " "
next
wln
next
wln
rem Init a new 2D array with 2*2 elements. The old array is replaced
rem by the new one.
intArray2D[][] = [[1, 2], [3, 4]]
wln "2D array 2:"
for i = 0 to sizeof(intArray2D, 0) - 1
write " "
for j = 0 to sizeof(intArray2D, 1) - 1
write intArray2D[i][j], " "
next
wln
next
wln
set color 0, 0, 0
cls
set color 255, 255, 255
set caret 0, 0
rem Init and show floating point array with four elements.
floatArray#[] = [1.0, 2.1, 3.2]
wln "Float array:"
for i = 0 to sizeof(floatArray) - 1
wln " ", floatArray#[i]
next
wln
Type conversion
[ Go back ]
a = 5.0
b# = 5 + "4"
c$ = 57 - 32.0
would generate an error. You convert a float or string expression to an integer with int(expr), to float
with float#(expr) and to string with str$(expr). Ex:
a = int(5.0)
b# = float#(5) + float#("4")
c$ = str$(57 - int(32.0))
Examples
ex_type_conversion
Sub routines
function int(float_expr#)
function int(string_expr$)
function float#(int_expr)
function float#(string_expr$)
function str$(int_expr)
function str$(float_expr#)
function int(float_expr#)
function int(string_expr$)
function float#(int_expr)
function float#(string_expr$)
function str$(int_expr)
function str$(float_expr#)
[ Go back ]
ex_type_conversion
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_type_conversion.html1/6/2012 2:35:38 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_type_conversion.txt
rem ==================================================================
rem ex_type_conversion
rem ==================================================================
anInteger = int(5.0)
aFloat# = float#("1.32")
aString$ = str$(543)
if 1 >= int(2.0) then wln "Awesome"
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_type_conversion.txt1/6/2012 2:35:38 AM
NaaLaa - Selection
Selection
[ Go back ]
Logic expressions
If and then
If and endif
If, else and endif
If, elseif, else and endif
Logic expressions
With the different versions of the selection statement (the if statement, that is), you can use logic
expressions to control the program flow.
During evaluation the operators have the following priorities (highest first):
*
/, %
+, -
=, <>, <, >, <=, >=
and, or
, where % is the modulus operator. But, of course, parenthesis can be used to force precendence.
If and then
if logic expr then statement
If and endif
if logic expr
statement
...
endif
If the logic expression evaluates to true, all the statements between the if and endif lines are performed.
If the logic expression evaluates to true, the statements between the if and else lines are performed, else
the statements between else and endif are performed.
endif
If the first expression evaluates to true, the statements between if and elseif are performed. Else the
second expression is evaluated to se if the lines between elseif and another elseif, else or endif are to be
performed.
Examples
ex_selection
[ Go back ]
ex_selection
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_selection.html1/6/2012 2:35:38 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_selection.txt
rem ==================================================================
rem ex_selection
rem ==================================================================
if 1 = 1
wln "1 = 1 is true."
endif
rem <statement>
rem ...
rem else
rem <statement>
rem ...
rem endif
rem
rem Same as above, but the statements between the "else" and "endif"
rem lines are executed if the logic expression evaluates to false.
if 1 = 2
wln "1 = 2 is true."
else
wln "1 = 2 is false."
endif
if 1 = 0
wln "1 = 0 is true."
elseif 1 = 1 and 3*5 = 6
wln "1 = 1 and 3*5 = 6 is true."
elseif 1 = 2 or 3*5 = 15
wln "1 = 2 or 3*5 = 15 is true."
else
wln "Everything was false."
endif
wln
wln "Press any key to exit ..."
wait keydown
Loops
[ Go back ]
Often you will want to repeat a number of statements a certain amount of times, until a condition is met
or, even, forever. You should have a look at the Selection chapter for some information about logic
expressions before you continue.
If the logic expression evaluates to true, the statements between while and wend are performed. Every
time wend is reached the logic expression is evaluated again.
Do and until
do
statement>
...
until logic expr
The statements between do and until are always performed atleast once. As long as the logic expression
evaluates to false, the statements are performed again.
...
next
This assigns the first expression to the integer variable var. As long as var is less than or equal to the
second expression, the statements between for and next are performed. var is increased by 1 every time
next is reached.
This assigns the first expression to the integer variable var. As long as var is greater than or equal to the
second expression, the statements between for and next are performed. var is decreased by 1 every time
next is reached.
Do and loop
do
statement
...
loop
The statements between do and loop are performed until break is called or someone shuts down the
program.
Break
You can leave any of the loops above by calling break.
Examples
ex_loops
[ Go back ]
ex_loops
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_loops.html1/6/2012 2:35:39 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_loops.txt
rem ==================================================================
rem ex_loops
rem ==================================================================
wln "while:"
a=0
while a < 3
wln " a is ", a, ", which is less than 3"
a=a+1
wend
wln
rem do
rem <statement>
rem ...
rem until <logic expression>
rem
rem The statements between the "do" and "until" lines are always
rem executed atleast once. As long as the logic expression evaluates
rem to false, the statements are executed again.
wln "do/until:"
a=0
do
wln " a is ", a, " and not 3"
a=a+1
until a = 3
wln
wln "for/to/next:"
for a = 0 to 3
wln " a is ", a
next
wln
wln "for/downto/next:"
for a = 3 downto 0
wln " a is ", a
next
wln
rem do
rem <statement>
rem ...
rem loop
rem
rem The statements between the "do" and "loop" lines are executed
rem until "break" is called or someone shuts down the program. "break"
rem also works on all the other iteration types:
rem
rem for i = 0 to 10
rem if i = 5 then break
rem next
rem wln "Break put me here when i was 5"
a=0
wln "do/loop and break"
do
wln " I loop until someone gives me a break"
a=a+1
if a = 4 then break
loop
wln
Procedures
[ Go back ]
A procedure is a sub program that you can create anywhere in the code with:
All variables created inside a procedure are visible only in that procedure, and they're released when the
procedure exits. Variables inside the procedure may have the same names as variables in other
procedures or in the main program. The optional parameters, that can be passed to the procedure when
calling it, act just like local variables. Ex:
Ex:
Examples
ex_procedures
[ Go back ]
ex_procedures
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_procedures.html1/6/2012 2:35:40 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_procedures.txt
rem ==================================================================
rem ex_procedures
rem ==================================================================
wln
wln "Press any key to exit ..."
wait keydown
rem ==================================================================
rem Write hello.
rem ==================================================================
procedure WriteHello()
wln "Hello"
endproc
rem ==================================================================
rem Write the value of 'a' or 'b'.
rem ==================================================================
procedure WriteOneOfTwo(a#, b#)
rem The rnd(max) function returns a random value between 0 and
rem 'max' - 1.
if rnd(2) = 0
wln a#
else
wln b#
endif
endproc
rem ==================================================================
rem Write one of the strings in 'a$[]'
rem ==================================================================
procedure WriteOneOfMany(a$[])
if sizeof(a) > 0
wln a$[rnd(sizeof(a))]
else
wln "The array is empty!"
endif
endproc
rem ==================================================================
rem Write countdown from a to 0 using recursion.
rem ==================================================================
procedure CountDown(a)
rem return can be used to exit the procedure.
if a < 0 then return
wln a
Functions
[ Go back ]
Functions are very much like procedures. The difference is that they're treated as expressions and
therefor must return values. Unless the function is of integer type, its type must be added after its name,
the same way as for variables.
The return statement exits the function and returns the expression. return, but without an expression, can
also be used to exit a procedure. Ex:
function Double#(a#)
return a#*2.0
endfunc
function ArrayOfTwo[](a, b)
return [a, b]
endfunc
A function call is always an expression, and its parameters must be within paranthesis. Ex:
doubled# = Double(2.0)
array[] = ArrayOfTwo(3, 72)
Examples
ex_functions
[ Go back ]
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/functions.html1/6/2012 2:35:40 AM
NaaLaa - Functions - Example
ex_functions
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_functions.html1/6/2012 2:35:40 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_functions.txt
rem ==================================================================
rem ex_functions
rem ==================================================================
rem Functions are very much like procedures. The difference is that
rem functions are treated as expressions - they must return a value.
rem
rem Unless the function is of integer type, its type must be added
rem after its name, the same way as for variables.
rem
rem function <function name>[<type>]([<parameter 1>[, <parameter 2> ...]])
rem <statement>
rem return <expression>
rem ...
rem endfunc
rem
rem A function call must always be part of an expression, and the
rem parameters must be within parenthesis.
intArray[] = [5, 3, 4, 2, 1]
rem ==================================================================
rem Return the biggest value.
rem ==================================================================
function Max(a, b)
if a > b
return a
else
return b
endif
endfunc
rem ==================================================================
rem Return the longest string.
rem ==================================================================
function Longest$(a$, b$)
if len(a$) > len(b$)
return a$
else
return b$
endif
endfunc
rem ==================================================================
rem Return a#^b.
rem ==================================================================
function Pow#(a#, b)
res# = 1.0
for i = 0 to b - 1
res# = res#*a#
next
return res#
endfunc
rem ==================================================================
rem Write integer array.
rem ==================================================================
procedure WriteIntArray(a[])
write "["
for i = 0 to sizeof(a) - 1
write a[i]
if i < sizeof(a) - 1 then write ", "
next
wln "]"
endproc
rem ==================================================================
rem Sort and return array.
rem ==================================================================
function SortIntArray[](a[])
if sizeof(a) > 1
last = sizeof(a) - 2
do
hadChange = false
for i = 0 to last
if a[i] > a[i + 1]
b = a[i + 1]
a[i + 1] = a[i]
a[i] = b
hadChange = true
endif
next
last = last - 1
until not hadChange
endif
return a
endfunc
Normally, the variables in the main program are not visible inside a subprogram. But you can make all
upcomming variables visible to all subprograms by using the visible statement:
visible:
i_am_visible
i_am_also_visible# = 4.0
i_am_very_visible$[] = ["hello", "there"]
hidden:
...
Examples
ex_hidden_visible
[ Go back ]
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/hiddenvisible.html1/6/2012 2:35:41 AM
NaaLaa - Hidden Visible - Example
ex_hidden_visible
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_hidden_visible.html1/6/2012 2:35:41 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_hidden_visible.txt
rem ==================================================================
rem ex_hidden_visble
rem ==================================================================
rem All variables created after 'hidden:' are hidden from procedures
rem and functions.
hidden:
myHiddenVariable = 5
proc CantChangeIt
wln "myHiddenVariable = ", myHiddenVariable
procedure CantChangeIt()
myHiddenVariable = 8
endproc
proc CanChangeIt
wln "myVisibleVariable = ", myVisibleVariable
procedure CanChangeIt()
myVisibleVariable = 57
endproc
wln
Constants
[ Go back ]
A constant works like a variable, but its value can only be set once. Constants are visible in sub
programs, and if constants are declared in a library they're also visible in programs that import the
library. An advice is to use constants for naming images, sound effects, array posts etc, as it makes the
code much easier to read. To declare one or more constants, use the constant statement:
constant:
an_integer_constant 5
pi# 3.14
program_name$ "My Program"
hidden:
...
You can, but needn't, use the = character when declaring constants. When you're done with your
constants, you need to call hidden or visible to make all upcoming variables normal.
[ Go back ]
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/constants.html1/6/2012 2:35:41 AM
NaaLaa - Reference parameters
Reference parameters
[ Go back ]
All parameters are normally sent by their values to sub programs. For large arrays this could get pretty
slow, as the entire arrays needs to be copied into the local parameters at every call. Another problem is
that you might need a sub program that returns two variables of different types – in that case you can't
return the values as an array.
When you have a parameter that is declared to be of a reference type, the variable from the caller isn't
copied to the local parameter. Instead the parameter becomes a pointer to the actual variable that was
sent to the sub program. If you change such a parameter inside the sub program, the value of the variable
outside the sub program is also changed.
You set a parameter to be of a reference type by adding & in front of the parameter name. Ex:
Java notice!
Reference parameters don't work very well in a Java applet (which is very funny concidering that
references is what Java is about ...).
Integers, floats and strings can not be passed by reference in an applet. The Creator has tried to make it
possible, but he simply can't make it work under all circumstances. Therefor, the compiler will generate
an error if you try to use this feature when compiling to a Java applet.
You may, however, pass arrays by reference. But the support is limited! You may change the elements
of such an array inside the subroutine but not the array itself. That is, if an_array is a one dimensional
integer array passed by reference to a subroutine you can do this:
for i = 0 to sizeof(an_array) - 1
an_array[i] = an_array[i]*2
next
, and the elements of the original array will be changed. But you can not do any of the following:
an_array[]
an_array[5]
an_array[] = [1, 2, 3, 4]
, as all these operations modify the array rather than its elements.
Examples
Obviously, concidering the Java notice, there's no example applet, but you can still find an example of
reference parameters in your NaaLaa 5 Examples folder.
[ Go back ]
Objects
[ Go back ]
The creator added the object type to NaaLaa just before the release. He didn't have the time to actually
test them or use them. So if you encounter any bugs or problems, don't hesitate to send an e-mail to
marcus@naalaa.com!
Java notice!
You can not use objects in Java applets created by NaaLaa yet. But an update, 5.1, of NaaLaa will be
released soon, and then it will work. So don't be afraid to use objects.
Introduction
Objects are variables that can contain other variables. They work much like arrays, but the fields
(elements) of an object needn't be of the same type. You declare an object with a questionmark, and you
create and set a field with the . character followed by a field name. Ex:
wait keydown
Output:
5
3.140
Hello
there
Object fields are type sensitive. If you've added a string field named a_string$ you need to use the $
character every time you refer to the field. The fields may, however, change type during program
execution. Ex:
rem Create and object and add an integer field with the value 5.
obj?.x = 5
wln obj.x
obj.x# = 3.14
wln obj.x#
obj.x$ = "Aha"
wln obj.x$
Output:
5
3.140
Aha
All of this is caused by the fact that object fields are dynamically created, deleted and modified at
runtime. The compiler can't know what type a field has, and therefor you need to use # and $ all the way.
Object arrays
You can declare arrays (with any number of dimensions) of objects. But an object can not contain arrays
(or other objects). Ex:
rem Create an object array and add some fields to its objects.
an_obj_array?[2]
an_obj_array[0].x = 5
an_obj_array[0].y# = 3.0
an_obj_array[1].x = 10
an_obj_array[1].y# = 6.0
wln an_obj_array[0].x
wln an_obj_array[0].y#
wln an_obj_array[1].x
wln an_obj_array[1].y#
Output:
5
3.000
10
6.000
Example 1
wait keydown
Output:
an_object.txt$ = Hello
another_object.txt$ = This will have effect.
Example 2
wait keydown
Output:
my_obj.x = 10
my_obj.y = 4
Example 3
wait keydown
Output:
two_objects[0].x = 0
two_objects[1].x = 5
[ Go back ]
Maths
[ Go back ]
NaaLaa has a basic set of mathematical functions, all presented below. If you're interested in vector
algebra and other things, you should have a look at the Math library.
Examples
ex_math
Sub routines
function min(a, b), function min#(a#, b#)
function max(a, b), function max#(a#, b#)
function abs(a), function abs#(a#)
function sqr#(a#)
function sin#(a#), function cos#(a#), function tan#(a#)
function asin#(a#), function acos#(a#), function atan#(a#)
procedure degrees, procedure radians
function degrees()
function min(a, b)
function min#(a#, b#)
function max(a, b)
function max#(a#, b#)
function abs(a)
function abs#(a#)
function sqr#(a#)
function sin#(a#)
function cos#(a#)
function tan#(a#)
function asin#(a#)
function acos#(a#)
function atan#(a#)
procedure degrees
procedure radians
Switch between degrees (standard) and radians for all trigonometric functions.
function degrees()
[ Go back ]
Math (Math.lib)
By Marcus.
[ Go back ]
Introduction
This library contains some mathematical stuff that the Creator often uses himself. Many of the functions
deal with vectors. A vector is always represented by a floating point array with two elements.
Constants
Sub routines
function DecToBin$(dec)
function BinToDec(bin$)
function DecToHex$(dec)
function HexToDec(hex$)
function Distance#(x1, y1, x2, y2)
function DistanceF#(x1#, y1#, x2#, y2#)
function InvDistance#(x1, y1, x2, y2)
function InvDistanceF#(x1#, y1#, x2#, y2#)
function AngleTo#(src_x, src_y, dst_x, dst_y)
function AngleToF#(src_x#, src_y#, dst_x#, dst_y#)
procedure V_Add(&u#[], &v#[]), function V_AddGet#[](&u#[], &v#[])
procedure V_Sub(&u#[], &v#[]), function V_SubGet#[](&u#[], &v#[])
procedure V_Scale(&u#[], s#), function V_ScaleGet#[](&u#[], s#)
procedure V_Normalize(&u#[]), function V_NormalizeGet#[](&u#[])
procedure V_Rotate(&u#[], a#), function V_RotateGet#[](&u#[], a#)
procedure V_Project(&u#[], &v#[]), function V_ProjectGet#[](&u#[], &v#[])
function DecToBin$(dec)
Back to top
function BinToDec(bin$)
Back to top
function DecToHex$(dec)
Back to top
function HexToDec(hex$)
Back to top
Return distance between the integer points x1, y1 and x2, y2.
Back to top
Return distance between the float points x1, y1 and x2, y2.
Back to top
Return the inverted distance (1/d) between the two integer points x1, y1 and x2, y2.
Back to top
Return the inverted distance (1/d) between the two float points x1, y1 and x2, y2.
Back to top
Return the angle (0..360) from the integer point src_x, src_y to dst_x, dst_y.
Back to top
Return the angle (0..360) from the float point src_x, src_y to dst_x, dst_y.
Back to top
Back to top
Back to top
Back to top
procedure V_Normalize(&u#[])
function V_NormalizeGet#[](&u#[])
Back to top
Back to top
Back to top
Back to top
function V_Size#(&u#[])
Back to top
Back to top
Back to top
function V_Angle#(&u#[])
Back to top
Back to top
Back to top
Back to top
[ Go back ]
ex_math
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_math.html1/6/2012 2:35:43 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_math.txt
rem ==================================================================
rem ex_math
rem ==================================================================
rem abs(value)
rem
rem and
rem
rem abs#(value#)
rem
rem returns the absolute value of an integer or float expression.
wln "abs(-4) = ", abs(-4)
wln "abs#(-3.0) = ", abs#(-3.0)
wln
rem min(x, y)
rem
rem and
rem
rem min#(x#, y#)
rem
rem returns the lowerst of the two integer or float expressions, while
rem
rem max(x, y)
rem
rem and
rem
rem max#(x#, y#)
rem
rem returns the highest of the two expressions.
wln "min(6, 3) = ", min(6, 3)
wln "min#(3.0, 6.0) = ", min#(3.0, 6.0)
wln "max(6, 3) = ", max(6, 3)
wln "max#(3.0, 6.0) = ", max#(3.0, 6.0)
wln
rem sqr#(x#)
rem
rem returns the square root of a float expression.
rem cos#(x#)
rem sin#(x#)
rem tan#(x#)
rem acos#(x#)
rem asin#(x#)
rem
rem and
rem
rem atan#(x#)
rem
rem are the standard trigonometric functions. By default degrees are
rem used, but you can switch to radians with:
rem
rem radians
rem
rem and back to degrees with:
rem
rem degrees
rem
wln "cos#(90.0) = ", cos#(90.0)
wln "sin#(90.0) = ", sin#(90.0)
wln "tan#(45.0) = ", tan#(45.0)
wln "acos#(0.0) = ", acos#(0.0)
wln "asin#(1.0) = ", asin#(1.0)
wln "atan#(1.0) = ", atan#(1.0)
wln
Strings
[ Go back ]
Besides from the regular + and - operators, there is a bunch of functions that you can use to manipulate
strings.
Examples
ex_strings
Sub routines
function len(txt$)
function lower$(txt$)
function upper$(txt$)
function left$(txt$, n)
function right$(txt$, n)
function mid$(txt$, pos)
function mid$(txt$, pos, n)
function instr(txt$, sub$)
function instr(txt$, sub$, pos)
function len(txt$)
function lower$(txt$)
function upper$(txt$)
function left$(txt$, n)
function right$(txt$, n)
Return the position of the first occurrence of sub in txt. -1 is returned if txt doesn't contain sub.
[ Go back ]
ex_strings
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_strings.html1/6/2012 2:35:43 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_strings.txt
rem ==================================================================
rem ex_strings.txt
rem ==================================================================
wln
wln "Press any key to exit ..."
wait keydown
end
Here you'll find some things that just didn't fit anywhere else.
Examples
ex_window
ex_redraw
Sub routines
procedure set window x, y, w, h[, full_screen[, scale_factor]]
procedure set redraw value
procedure redraw
procedure wait ms
procedure wait keydown
procedure wait mousebutton
function fullscreen()
function active()
function time()
function rnd(n)
procedure randomize seed
args$[]
Place window at x, y and set its width and height to w and h. If full_screen is set to true and the
dimensions are of a valid format, the screen mode will change to match the window. If scale_factor is
set to a value greater than 1, the window and all the graphics will be scaled by that value. Mouse input
coordinates are automatically scaled. For, example, if you'd like a 320x240 fullscreen window you'd
write:
Java notice!
The full screen mode doesn't work for Java applets created with NaaLaa. And for the scaling to work,
you will need to set the applet's window size to w*scale_factor, h*scale_factor in your html file.
By default every operation that draws something to the primary image (the back buffer) will cause the
entire image to be copied to the window. By setting value to false the primary image will only be copied
when redraw is called.
procedure redraw
procedure wait ms
Sleep for ms milliseconds. Note that the window can only take care of its messages during a sleep
period. If the keydown, mousex, mousey or mousebutton functions are used within a loop, the loop must
contain a wait call. 0 is a valid value for ms.
function fullscreen()
function active()
function time()
function rnd(n)
Send a new seed value to be used next time rnd is called. A normal thing is to use:
randomize time()
in the beginning of your program. But you can of course also force a certain random number sequence
by passing an integer constant.
args$[]
If any arguments have been passed to your program when it starts, this array contains these arguments.
The first argument (args[0]) is always the path to and filename of your program.
Note that the args array can also be used to pass arguments between program units.
[ Go back ]
ex_window
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_window.html1/6/2012 2:35:44 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_window.txt
rem ==================================================================
rem ex_window
rem ==================================================================
rem ==================================================================
rem Java Notice!
rem
rem The size of an applet created with NaaLaa is completely determined
rem by the WIDTH and HEIGHT parameters passed in by the html file. If
rem you change the window size, it'll only affect the size of the
rem primary image (the back buffer). If you wish to use the 2XMode
rem you'll need to set the WIDTH and HEIGHT to the double size of the
rem window.
rem ==================================================================
wait keydown
ex_redraw
Click in the window when the applet has loaded.
Actually ... the fast stars aren't that fast in this Java applet. Try the executable instead :)
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_redraw.html1/6/2012 2:35:44 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_redraw.txt
rem ==================================================================
rem ex_redraw
rem ==================================================================
rem Normally all drawing is done to the primary image. And every time
rem something has been drawn, the primary image is copied to the
rem window. You see the result at once, and this has been suitable so
rem far when dealing with nothing but text input and output.
rem But let's say you want to do something really, really cool,
rem like ... drawing 1,000 or 10,000 pixel shaped stars. Then the
rem primary image would be copied to the window 1,000 or 10,000 times.
rem On my very old computer drawing 1,000 stars takes about 1.5
rem seconds.
set color 0, 0, 0
cls
t = time()
proc DrawStars 1000
set color 255, 255, 255
wln "Done drawing in only ", time() - t, " milliseconds."
wait 1000
wln
wln "That was pretty slow for 1,000 stars, don't you think?"
wait 1000
wln
wln "Press any key to continue ..."
wait keydown
rem The solution is of course not to update the window after every
rem drawing operation. You can do this by calling:
rem
rem set redraw off
rem
rem After this call, you must copy the primary image to the window
rem yourself with:
rem
rem redraw
rem
rem You can turn on automatic redraw again by calling
rem
rem set redraw on
rem
set caret 0, 0
set color 255, 255, 255
wln "Here you have 10,000 a lot faster stars."
wln "Feel free to make the window lose its focus while still being visible."
wln
wln "Press Esc to exit ..."
rem ==================================================================
rem Draw some stars.
rem ==================================================================
procedure DrawStars(starCount)
for i = 0 to starCount - 1
rem Set color to white but with random transparency.
set color 255, 255, 255, rnd(255)
rem Draw a pixel at random position.
draw pixel rnd(640), rnd(480)
next
endproc
Even if NaaLaa is meant for games, there may be circumstances where you need to output or input some
values.
Examples
ex_output
ex_input
Sub routines
procedure write [expr[, expr ...]]
procedure wln [expr[, expr ...]]
function rln([max_chars])
function rln#([max_chars])
function rln$([max_chars]
procedure set caret x, y
procedure set justification left/right/center
procedure center [expr[, expr ...]]
procedure set decimals decimal_digits
procedure set decimals integer_digits, decimal_digits
function inkey()
function chr$(ascii_value)
function asc(a$)
Write a number of arbitrary expressions to current image and add a line break.
function rln([max_chars])
Return an integer value from user (keyboard). If max_chars is submitted, the user can enter a maximum
of max_chars characters.
function rln#([max_chars])
Return a floting point value from user (keyboard). If max_chars is submitted, the user can enter a
maximum of max_chars characters.
function rln$([max_chars]
Return a text string from user (keyboard). If max_chars is submitted, the user can enter a maximum of
max_chars characters.
Write a number of arbitrary expressions centered and add a line break. Setting justification to center and
using wln gives the same result.
Set minimum number of integer digits for text output to integer_digits and the number of decimal digits
to decimal_digits.
function inkey()
function chr$(ascii_value)
function asc(a$)
[ Go back ]
ex_output
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_output.html1/6/2012 2:35:45 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_output.txt
rem ==================================================================
rem ex_output
rem ==================================================================
wln
center "Press any key to exit ..."
wait keydown
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_output.txt1/6/2012 2:35:45 AM
NaaLaa - Input - Example
ex_input
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_input.html1/6/2012 2:35:45 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_input.txt
rem ==================================================================
rem ex_input
rem ==================================================================
wln
wln "So, ", name$, " ..."
wln "You are ", age, " years old and 5/2 is ", div#, "!"
wln
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_input.txt1/6/2012 2:35:46 AM
NaaLaa - Files
Files
[ Go back ]
NaaLaa supports both text and binary files. But the Creator admits, that he added the binary file support
the day before the release of version 5, so it hasn't been tested that much ...
Java notice!
In Java applets created with NaaLaa you can not read or write binary files. Also, you can only write to
files (on the server on which your applet is running) if you include the 'naalaa_fwrite.php' file with your
applet (put it next to the class files). You can find the 'naalaa_fwrite.php' file in the Classes folder
among the example programs.
Examples
Look in the NaaLaa 5 Examples folder for examples.
Sub routines
procedure create file file_id, filename$[, binary]
procedure write file file_id[, expr [, expr ...]]
procedure wln file file_id[, expr [, expr ...]]
procedure set autoquote value
procedure write8 file_id, data
procedure write16 file_id, data
procedure write32 file_id, data
procedure writef file_id, data#
procedure writes file_id, data$
procedure open file file_id, filename$[, binary]
function read(file_id)
function read#(file_id)
function read$(file_id)
function read8(file_id)
function read16(file_id)
function read32(file_id)
function readf#(file_id)
function reads$(file_id)
function file(file_id)
function eof(file_id)
function exists(filename$)
function openfile$(extension$)
function savefile$(extension$)
procedure free file file_id
function datafolder$(directory$)
Create file file_id with the name filename for writing. If a file with the same name already exists, it is
replaced by the new file. If binary is set to false (default), the file will become a text file, else it will
become a binary file.
Write a number of arbitrary expressions to file file_id. This only works on text files.
Write a number of arbitrary expressions to file file_id and add a line break. This only works on text files.
By default, quotes are automatically added to strings containing whitespace when they're written to a
file. You can change this by passing on or off to this procedure.
Write an 8 bit (byte) value, data, to file file_id. This only works on binary files.
Write a 16 bit (short) value, data, to file file_id. This only works on binary files.
Write a 32 bit (long) value, data, to file file_id. This only works on binary files.
Write a float value, data, to file file_id. This only works on binary files.
Write a string, data, to file file_id. In the file, the string is a character (byte) sequence terminated by null
(a byte with the value 0). This only works on binary files.
Open file file_id with the name filename for reading. If binary is set to false (default), the file will be
treated as a text file, else it is assumed to be a binary file.
function read(file_id)
Read and return an integer value from file file_id. This only works on text files.
function read#(file_id)
Read and return a float value from file file_id. This only works on text files.
function read$(file_id)
Read and return a string from file file_id. This only works on text files.
function read8(file_id)
Read and return an 8 bit (byte) value from file file_id. This only works on binary files.
function read16(file_id)
Read and return a 16 bit (short) value from file file_id. This only works on binary files.
function read32(file_id)
Read and return a 32 bit (long) value from file file_id. This only works on binary files.
function readf#(file_id)
Read and return a float value from file file_id. This only works on binary files.
function reads$(file_id)
Read and return a string from file file_id. This only works on binary files.
function file(file_id)
function eof(file_id)
function exists(filename$)
function openfile$(extension$)
Show a standard windows dialog for opening a file. The selected filename is returned. If extension is not
an empty string, only files with the specified extension (ex. "txt") will be visible.
Java notice!
function savefile$(extension$)
Show a standard windows dialog for saving a file. The selected filename is returned. If extension is not
an empty string, only files with the specified extension (ex. "bmp") will be visible.
Java notice!
Close file file_id. All files are automatically closed when the program exits.
function datafolder$(directory$)
Return path to the application data folder of all users. If directory is not an empty string, a folder with
that name will be created (if not present) and added to the return value.
If you want to save "hidden" data, like a game save file, on a user's computer, it is strongly
recommended that you use this function to get a valid path. Ex:
[ Go back ]
Image transformations
[ Go back ]
This is not the place to explain the details of image transformations. If you haven't used such things
before, you should try to think of it as if every transformation changes the coordinate system in which an
image is drawn. Usually, the coordinate system has its origo at the top left corner of the window. When
the x coordinate increases you move right, and when the y coordinate increases you move towards the
bottom. The transformation commands change the origo and these directions. A'ight, man?
Java Notice!
This form of image drawing does not work in Java applets created with NaaLaa yet.
Examples
Look at the ex_image_transformations example in the NaaLaa 5 Examples folder.
Sub routines
draw image image_id
translate x#, y#
scale sx#, sy#
rotate a#
clear transformation
push transformation
pop transformation
rotate a#
clear transformation
Clear the transformation. After calling this, origo will be at the top left corner of the window, right will
be right and down will be down.
push transformation
Push the current transformation matrix to the stack. For every push you make, you must later call pop
transformation, or you'll get a memory leak.
pop transformation
[ Go back ]
Zones
[ Go back ]
Examples
ex_zones
Sub routines
procedure create zone zone_id, x, y, w, h
procedure free zone zone_id
function zone(x, y)
function zone(zone_id)
function zone()
function zonex(zone_id), function zoney(zone_id), function zonew(zone_id), function zoneh(zone_id)
Create zone zone_id at x, y and set its width and height to w, h. The id shouldn't be set to 0.
Free zone zone_id. All zones are automaticly freed when program exits.
function zone(x, y)
Return id of any zone at position x, y. If the coordinates are not inside any zone, 0 is returned.
function zone(zone_id)
Return status of zone zone_id. If 0 is return, the cursor is not inside the zone, or the zone does not exist.
If 1 is returned, the cursor is inside the zone, but no mouse button is pressed. 2 means that the cursor is
inside the zone and the mouse button is pressed.
function zone()
Return the id of the latest zone that was clicked on (mouse down and up while cursor was inside the
zone). Each click is only reported once. 0 is returned if no zone click has been generated since last time
the function was called.
function zonex(zone_id)
function zoney(zone_id)
function zonew(zone_id)
function zoneh(zone_id)
These functions return the x position, y position, width and height of zone zone_id.
[ Go back ]
ex_zones
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_zones.html1/6/2012 2:35:47 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_zones.txt
rem ==================================================================
rem ex_zones
rem ==================================================================
rem Zones can among all (or perhaps only) be used to simulate buttons.
rem You set up a zone with:
rem
rem create zone id, x, y, width, height
rem
rem id can be any integer but should not be set to 0.
do
x = mousex()
y = mousey()
set color 0, 0, 0
cls
wln
wln "Those squares are actually buttons."
wln "Try to hover over them with the mouse and click on them."
wln
rem zone()
rem
rem returns the last zone that had a real click (mouse up and down).
rem Each click is only reported once.
depressed = zone()
if depressed
set color 255, 255, 255
cls
set color 0, 0, 0
set caret 320, 200
center "Button ", depressed, " pressed!"
center
center "Click to continue ..."
redraw
do; wait 0; until mousebutton(0)
endif
redraw
wait 10
until keydown(27) or not running()
rem All zones are deleted when the program exits, but some times you
rem may want to free them yourself with:
rem
rem free zone id
rem
free zone 1
free zone 2
NaaLaa uses the open source Audiere for music and sound playback. Therefor audiere.dll must be
included with your programs. Please visit http://audiere.sourceforge.net for more information about what
music and sound formats are supported!
Java Notice!
NaaLaa applets use the simplest form of audio output for both music and sound effects. The creator
believes that only the au-, wav-, aif- and midi-formats are supported. The creator himself prefers the aif
format. Any piece of music (xm, it, mp3 etc) can easily be converted to wav using lots of free
programs. And a good program for converting wav to aif is the River Past Audio Converter.
Examples
ex_music_and_sound
Sub routines
procedure load music music_id, filename$
procedure set music volume music_id, vol
procedure play music music_id[, looped]
procedure stop music music_id
procedure free music music_id
function music(music_id)
procedure load sound(sound_id, filename$)
procedure play sound(sound_id[, vol[, pan]])
procedure free sound(sound_id)
function sound(sound_id)
Java Notice!
This currently has no effect in applets. Lower the volume of the music file instead.
Start playing music music_id and loop it if looped is set to true (default).
Free music music_id. All music is automaticly freed when program exits.
function music(music_id)
Play sound sound_id at volume vol (0..100, default 100) and with the panning pan (-100..100, left to
right, default 0).
Java Notice!
Free sound sound_id. All sounds are automaticly freed when program exits.
function sound(sound_id)
[ Go back ]
ex_music_and_sound
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_music_and_sound.html1/6/2012 2:35:47 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_music_and_sound.txt
rem ==================================================================
rem ex_music_and_sound
rem ==================================================================
rem ==================================================================
rem Java Notice!
rem
rem Currently NaaLaa applets use the simplest form of audio output for
rem both music and sound effects. The creator believes that only the
rem au-, wav-, aif- and midi-format is supported.
rem ==================================================================
rem NaaLaa uses the open source Audiere for music and sound. Therefor
rem audiere.dll needs to be included with your programs.
rem Please visit http://audiere.sourceforge.net/ for more
rem information about this wonderful high level audio api!
rem Use:
rem
rem load music id, filename$
rem
rem to load "a piece of music". id can be any integer value. You can
rem look at the Audiere webpage (adress above) for information about
rem the supported formats.
rem
rem , where volume should be a value between 0 and 100.
rem set music volume 0, 75
stars[100][3]
for i = 0 to sizeof(stars, 0) - 1
stars[i][0] = rnd(640)
stars[i][1] = rnd(480)
stars[i][2] = rnd(3) + 2
next
scrollx = 0
rem Call:
rem
rem play music id
rem
rem or
rem
rem play music, looped
rem
rem to start playing a piece of music. Set looped to true (default) if
rem the music is to be looped.
play music 0, true
do
rem Although there's not much at all to do or draw in this example,
rem we'll use a very simple technique to maintain a constant frame
rem rate. This requires that we store the time at the beginning of
rem our main loop with:
rem
rem time()
rem
rem The time function returns the current time in milliseconds.
startTime = time()
redraw
stop music 0
free music 0
free sound 0
rem ==================================================================
rem This procedure can be used to maintain a MAXIMUM frame rate. Use
rem time() in the beginning of your game loop to store a start time.
rem Then call HoldFrame at the end of the loop. fps is the number of
rem frames per second that you wishes to uphold. 50 or 60 will do
rem good.
rem ==================================================================
procedure HoldFrame(startTime, fps)
hold = 1000/fps
endTime = time()
deltaTime = endTime - startTime
if deltaTime < hold
wait hold - deltaTime
else
wait 0
endif
endproc
Mouse input
[ Go back ]
Examples
ex_mouse_input
Sub routines
procedure set mouse value
function mousex()
function mousey()
function mousebutton(id[, unflag])
Turn on or off the visibility of the mouse pointer by setting value to on or off.
function mousex()
function mousey()
Same as above, but if unflag (fault by default) is set to true the button status is unflagged (set to false)
until the button has been released and pressed down again.
[ Go back ]
ex_mouse_input
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_mouse_input.html1/6/2012 2:35:48 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/examples/ex_mouse_input.txt
rem ==================================================================
rem ex_mouse_input
rem ==================================================================
redraw
wait 10
until keydown(27) or not running()
Joystick input
[ Go back ]
Java Notice!
Examples
Look for ex_joystick_input in the NaaLaa 5 Examples folder.
Sub routines
function joyx()
function joyy()
function joybutton(id)
function joyx()
function joyy()
function joybutton(id)
Return true if joystick button id is pressed. If id is 0 or greater than 32 any pressed button will cause true
to be returned.
[ Go back ]
VM instructions
[ Go back ]
The creator doesn't recommend anyone but himself to use the stuff presented below. If you try, you'll
most certainly obtain permanent brain damages - or atleast a minor headache.
When you compile a NaaLaa program, all your code is converted into simple instructions that the
NaaLaa virtual machine (VM) can interpret. When the Creator was working on the Raycasting library,
he realized that the compiler wasn't always that smart. Yes, he thought that he, the almighty one, could
make a better job himself (which is funny, as he was the one who wrote the compiler in the first place).
He therefore made some of the VM instructions available for himself and all other NaaLaa
programmers.
Java Notice!
No, you can't use NaaLaa VM instructions when creating a Java applet :)
There's a command named MOV, that moves a value from one place to another. So let's say you wanted
to swap the values of two variables, an_int and another_int. You'd probably write:
tmp = an_int
an_int = another_int
another_int = tmp
But this generates a whole bunch of instructions. With the MOV instruction you could use a register as a
temporary variable and write:
MOV @0 an_int
The stack
Besides from the registers, there's also a stack that can be used as temporary storage. You can push
values from variables, registers and constants to this stack, and you can pop values from the stack to
variables and registers. You do so with the PSH and POP commands.
Arrays
Many commands let you operate on array elements. However, you can not use the arrays directly. First
you need to load an array into a register. What you actually load is a pointer to the first element of the
array. You load an array to a register with the normal MOV command. You can then use a command
named STP to move forward one or more elements in the array. To set or access the variable that a
pointer points at you use square brackets around the register identifier. Ex:
Jumping to labels
There are no loops or selection statements when you work with VM instructions. Instead you do
unconditional and conditional jumps to labels. With the CMP command, you can compare a value
(variable, register ...) with another value. This command sets a piece of information somewhere that you
can use to do a conditional jump. There are many types of jump commands. JLE, for example, does a
jump to the specified label only if the first value passed to the CMP command was less than or equal to
the second value. You create a label with the @ character followed by a name and a colon. In this
example we go through a loop 1000 times:
MOV# @0 1.0
@my_float_loop:
ADD# @0 0.5
CMP# @0 1000.0
JLE# my_float_loop
Examples
Look at ex_vm_instructions in the NaaLaa 5 Examples folder.
Instructions
MOV dst src
STP src
ADD dst src
SUB dst src
MUL dst src
DIV dst src
MOD dst src
PSH src
POP dst
CMP dst, src
JMP label
JE label
JNE label
JG label
JGE label
JL label
JLE label
ITF reg
FTI reg
PSH src
POP dst
JMP label
Jump to label.
JE label
JNE label
JG label
JGE label
Jump to label if dst was greater than or equal to src in last CMP.
JL label
JLE label
Jump to label if dst was less than or equal to src in last CMP.
ITF reg
FTI reg
[ Go back ]
3D rendering
[ Go back ]
In version 4 of NaaLaa you could work with software rendered 3D graphics via an OpenGL like
command set. You can still do so in this version. BUT the Creator is very aware of the fact that he's the
only one who can really use it, because the engine only fully supports models etc. created with (really
old) homemade software that the Creator has no intention of releasing. The Creator hasn't decided if he
should develop/fix the engine yet, and therefore he leaves out all information about it in this document.
If you're really interested, you can download NaaLaa 4 and look at its documentation.
It is possible that version 6 of NaaLaa will support OpenGL instead. Until then, the Creator suggests that
you stick to the Raycaster and Mode7 libraries if you want to make simple 3D games. These libraries
work for Java applets aswell.
[ Go back ]
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/doc/cge.html1/6/2012 2:35:49 AM
NaaLaa - Standard libraries
Standard libraries
[ Go back ]
The standard libraries are located in the C:\Program Files (x86)\NaaLaa Creator\NaaLaa 5\bin\libs\
folder. The compiler can always reach the libraries located there. This mean you don't need to copy the
standard libraries to the folder of your own program.
[ Go back ]
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/intro.html1/6/2012 2:35:49 AM
NaaLaa - Speed Library
[ Go back ]
Introduction
This library contains a couple of sub routines for maintaing a constant speed or fps (frames per second)
in games. If the speed is not controlled somehow, the performance of a game will depend on the player's
computer.
Sub routines
procedure SPD_HoldFrame(fps)
function SPD_GetSpeedCorrection#()
function SPD_GetFPS#()
procedure SPD_HoldFrame(fps)
You can put this function in all loops that require a constant speed. fps is the number of frames you like
to display per second (60 is a good value). Ex:
import "Speed.lib"
...
rem Game loop.
do
rem Deal with logic and drawing.
...
redraw
proc SPD_HoldFrame 60
loop
Back to top
function SPD_GetSpeedCorrection#()
Call this function at the top of your game loop to get a speed factor. Multiply every movement and
animation with this value to maintain a constant speed. This only works for floating point variables. If
you want an "object" with an x coordinate, x_obj#, to move 100 pixels per second, you'd write
something like:
x_obj# = 0.0
do
spd# = SPD_GetSpeedCorrection()
x_obj = x_obj + spd*100.0
...
redraw
wait 1
loop
Note that this function doesn't work well for Java applets, as the standard Java timer has a very low
resolution!
Back to top
function SPD_GetFPS()
If you're using SPD_GetSpeedCorrection you can use SPD_GetFPS to get the current fps value.
Back to top
[ Go back ]
BezierCurve (BezierCurve.lib)
By Marcus.
[ Go back ]
Introduction
This library evaluates points and derivatives on quadratic and cubic two dimensional Bezier curves.
Examples
ex_beziercurve
Sub routines
function QB_Evaluate#[](&cp#[][], param#)
function QB_EvaluateX#(&cp#[][], param#)
function QB_EvaluateY#(&cp#[][], param#)
function QB_EvaluateDeriv#[](&cp#[][], param#, normalize)
function QB_EvaluateDX#(&cp#[][], param#, normalize)
function QB_EvaluateDY#(&cp#[][], param#, normalize)
function CB_Evaluate#[](&cp#[][], param#)
function CB_EvaluateX#(&cp#[][], param#)
function CB_EvaluateY#(&cp#[][], param#)
function CB_EvaluateDeriv#[](&cp#[][], param#, normalize)
function CB_EvaluateDX#(&cp#[][], param#, normalize)
function CB_EvaluateDY#(&cp#[][], param#, normalize)
Return point [x, y] at parameter param on the quadratic curve defined by the control points in cp as [[x1,
y1], [x2, y2], [x3, y3]].
Back to top
Return x coordinate of point at parameter param on the quadratic curve defined by the control points in
cp as [[x1, y1], [x2, y2], [x3, y3]].
Back to top
Return y coordinate of point at parameter param on the quadratic curve defined by the control points in
cp as [[x1, y1], [x2, y2], [x3, y3]].
Back to top
Return derivative (curve direction) [dx, dy] at parameter param on the quadratic curve defined by the
control points in cp as [[x1, y1], [x2, y2], [x3, y3]]. If normalized is set to true, the returned vector will
be normalized.
Back to top
Return x component of derivative (curve direction) at parameter param on the quadratic curve defined
by the control points in cp as [[x1, y1], [x2, y2], [x3, y3]]. If normalized is set to true, the returned
component will be from a normalized vector.
Back to top
Return y component of derivative (curve direction) at parameter param on the quadratic curve defined
by the control points in cp as [[x1, y1], [x2, y2], [x3, y3]]. If normalized is set to true, the returned
component will be from a normalized vector.
Back to top
Return point [x, y] at parameter param on the cubic curve defined by the control points in cp as [[x1,
y1], [x2, y2], [x3, y3], [x4, y4]].
Back to top
Return x coordinate of point at parameter param on the cubic curve defined by the control points in cp
as [[x1, y1], [x2, y2], [x3, y3], [x4, y4]].
Back to top
Return y coordinate of point at parameter param on the cubic curve defined by the control points in cp
as [[x1, y1], [x2, y2], [x3, y3], [x4, y4]].
Back to top
Return derivative (curve direction) [dx, dy] at parameter param on the cubic curve defined by the
control points in cp as [[x1, y1], [x2, y2], [x3, y3], [x4, y4]]. If normalized is set to true, the returned
vector will be normalized.
Back to top
Return x component of derivative (curve direction) at parameter param on the cubic curve defined by
the control points in cp as [[x1, y1], [x2, y2], [x3, y3], [x4, y4]]. If normalized is set to true, the returned
component will be from a normalized vector.
Back to top
Return y component of derivative (curve direction) at parameter param on the cubic curve defined by
the control points in cp as [[x1, y1], [x2, y2], [x3, y3], [x4, y4]]. If normalized is set to true, the returned
component will be from a normalized vector.
Back to top
[ Go back ]
ex_beziercurve
Click in the window when the applet has loaded.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/beziercurve.html1/6/2012 2:35:50 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_beziercurve.txt
rem ==================================================================
rem BezierCurve Library - Example.
rem
rem By Marcus.
rem ==================================================================
set color 0, 0, 0
cls
set color 255, 255, 255
redraw
wait keydown
rem Let an a line move along a cubic curve and show the derivative.
set color 0, 0, 0
cls
do
set color 0, 0, 0, 16
cls
set color 255, 255, 255
mp = mp + 0.005
redraw
wait 10
until keydown(27) or not running()
[ Go back ]
Introduction
This library declares some constants that you can use to check the status of some keys on the keyboard.
No, no, it's not a complete list of the "virtual keys". The truth is, that the Creator wrote a small program:
do
ky = inkey()
if ky then wln ky
wait 10
loop
, and just copied the values he got while hammering the keyboard. Maybe they'll work in Java applets,
maybe they wont.
Constants
Constant Value
VK_CTRL 17
VK_LEFT 37
VK_RIGHT 39
VK_UP 38
VK_DOWN 40
VK_ESC 27
VK_SPACE 32
VK_ENTER 13
VK_SHIFT 16
VK_ALT 12
VK_BACK 8
VK_TAB 9
VK_ENTER 13
VK_PAUSE 19
VK_CAPS_LOCK 20
VK_PAGE_UP 33
VK_PAGE_DOWN 34
VK_END 35
VK_HOME 36
VK_INSERT 45
VK_DELETE 127
VK_F1 112
VK_F2 113
VK_F3 114
VK_F4 115
VK_F5 116
VK_F6 117
VK_F7 118
VK_F8 119
VK_F9 120
VK_F10 121
VK_F11 122
VK_F12 123
VK_NUMLOCK 144
[ Go back ]
[ Go back ]
Introduction
Using the tilemap library and the TM_Editor program, you can create most types of classic 2D games.
Details
A tile based map is a discrete 2D grid with a fixed number of columns and rows. Each cel in this grid is
refered to as a tile. All tiles have the same width and height. The width and height of the tiles depends on
the cel size of the image that the map uses for visualization. Three coordinate systems are used in the
description of the library. Map coordinates are used when refering to a certain column and row, a tile, in
the map. World coordinates are used when refering to a position in the world that the map represents.
The width of the world is the number of columns of the map*the width of a cel in the map image, and the
world height is the number of rows of the map*the height of a cel in the map image. Screen coordinates
are used when refering to a position on the screen. The library contains sub routines to make conversions
between the different coordinate systems.
A map has three different layers, edited in the TM_Editor. Each layer contains a piece of information
about a tile in the map. The image layer tells what cel is to be used from the map image for a certain tile.
The game flag layer stores a single integer value for every map tile. You can use this layer for anything
you want. The loader flag layer also holds an integer value for every map tile, but you only have access
to these values right after loading a map. They're returned to you in the form of an array. This layer can
be used to initialize player or enemy positions or anything you want.
Examples
ex_tilemap_1
ex_tilemap_2
ex_tilemap_3
Sub routines
procedure TM_SetView(x, y, w, h)
function TM_LoadMap(filename$)
function TM_GetLoaderFlags[][]()
procedure TM_SetCamera(x, y)
procedure TM_Render()
procedure TM_SetBorder(l, r, t, b)
function TM_Move[](img, img_x, img_y, dx, dy)
function TM_MoveF#[](img, img_x#, img_y#, dx#, dy#)
function TM_MoveRect#[](x, y, w, h, dx, dy)
function TM_MoveRectF#[](x#, y#, w#, h#, dx#, dy#)
function TM_GetCollisionInfo[]()function TM_CollisionLeft()
function TM_CollisionLeft()
function TM_CollisionRight()
function TM_CollisionDown()
function TM_CollisionUp()
function TM_ToTile[](x, y)
function TM_ToWorld[](x, y)
function TM_ToWorldX(x)
function TM_ToWorldY(y)
function TM_ToScreen[](x, y)
function TM_ToScreenX(x)
function TM_ToScreenY(y)
function TM_ToTileF[](x#, y#)
function TM_ToWorldF#[](x#, y#)
function TM_ToWorldXF#(x#)
function TM_ToWorldYF#(y#)
function TM_ToScreenF#[](x#, y#)
function TM_ToScreenXF#(x#)
function TM_ToScreenYF#(y#)
function TM_MapWidth()
function TM_MapHeight()
function TM_GetCel(x, y)
function TM_GetCelAt(x, y)
procedure TM_SetCel(x, y, cel)
procedure TM_SetFlag(x, y, flag)
function TM_GetFlagAt(x, y)
function TM_GetFlag(x, y)
function TM_Obstacle(cel)
function TM_CameraX()
function TM_CameraY()
function TM_Visible(img, x, y)
procedure TM_InitMap(w, h)
procedure TM_SetImage(img)
procedure TM_SetObstacle(cell, value)
function TM_GetImage()
procedure TM_SetView(x, y, w, h)
Set rendering view to screen position x, y and width and height w, h. Unless you want a smaller view
than the actuall window you should call:
Back to top
function TM_LoadMap(filename$)
Load a map, filename$ created with TM_Editor. The function returns true on success.
Back to top
function TM_GetLoaderFlags[][]()
Call this function after TM_LoadMap to get an array with all loader flags set in TM_Editor. Example:
if TM_LoadMap("my_map.txt")
flags[][] = TM_GetLoaderFlags()
for i = 0 to sizeof(flags, 0) - 1
wln "Flag = ", flags[i][TM_FLAG], " x = ", flags[i][TM_X], " y =
", flags[i][TM_Y]
next
endif
You can use the loader flags for anything you want. Personally I use them to set the player's starting
position and to init enemies.
Back to top
procedure TM_SetCamera(x, y)
Set the camera/rendering top-left position. If you want the map to be rendered with the player centered,
you'd write something like:
Back to top
procedure TM_Render()
Render view to the current image (usually the primary image). The view will be rendered at the position
and with the size set with TM_SetView, and it will show the map from the position set with
TM_SetCamera.
Back to top
The function TM_Move/TM_MoveRect moves an image/rectangle over the map and handles collisions.
TM_SetBorder sets the behaviour for the map edges. For example, if leftSide is set to true the left border
of the map will be treated as a wall, blocking any movement.
Back to top
Move an image, img, at the position img_x, img_y over the map, with the speed dx, dy. The function
returns the new position as an integer array. Example:
If no collision has occured, pos[TM_X] will be playerX + playerDX and pos[TM_Y] will be playerY +
playerDY.
Back to top
This function works like TM_Move but with a floating point position/speed.
Back to top
This function works like TM_Move but instead of using the information of an image, it uses an arbitrary
width and height, w and h.
Back to top
This function works like TM_MoveRect but with floating point values.
Back to top
If you need further actions on collisions than position correction, you can use this function to determine
in what directions collisions occured during the last call to TM_Move/TM_MoveF. Example:
Back to top
function TM_CollisionLeft()
Back to top
function TM_CollisionRight()
Back to top
function TM_CollisionDown()
Back to top
function TM_CollisionUp()
Back to top
function TM_ToTile[](x, y)
Convert world position x, y to map coordinates. Access the coordinates in the array with TM_X and
TM_Y.
Back to top
function TM_ToWorld[](x, y)
Convert screen coordinates to world coordinates. Access the coordinates in the array with TM_X and
TM_Y.
Back to top
function TM_ToWorldX(x)
Back to top
function TM_ToWorldY(y)
Back to top
function TM_ToScreen[](x, y)
Convert world coordinates into screen coordinates. Access the coordinates in the array with TM_X and
TM_Y.
Back to top
function TM_ToScreenX(x)
Back to top
function TM_ToScreenY(y)
Back to top
Convert floating point world position x#, y# to map coordinates. Access the coordinates in the array with
TM_X and TM_Y.
Back to top
Convert floating point screen coordinates to world coordinates. Access the coordinates in the array with
Back to top
function TM_ToWorldXF#(x#)
Back to top
function TM_ToWorldYF#(y#)
Back to top
Back to top
function TM_ToScreenXF#(x#)
Back to top
function TM_ToScreenYF#(y#)
Back to top
function TM_MapWidth()
Back to top
function TM_MapHeight()
Back to top
function TM_GetCel(x, y)
Back to top
function TM_GetCelAt(x, y)
Return the image cel used at world coordinates x, y. If no cel has been set, the function returns -1.
Back to top
Set image cel at map coordinates x, y to cel. If cel is set to -1, the cel will become empty.
Back to top
function TM_GetFlag(x, y)
Back to top
function TM_GetFlagAt(x, y)
Back to top
Back to top
function TM_Obstacle(cel)
Return true if the cel cel in the map image is an obstacle that prevents movement via the TM_Move
functions.
Back to top
function TM_CameraX()
Back to top
function TM_CameraY()
Back to top
function TM_Visible(img, x, y)
Back to top
procedure TM_InitMap(w, h)
Clear map and set its new width and height to w*h
Back to top
procedure TM_SetImage(img)
Set map image to img. Be sure to have set the image's grid with set image grid before calling this
procedure.
Back to top
After having set the map image with TM_SetImage, you can use this function to set the collision
behavior for a cel, cel in the image. If value is true, the image cel will become and obstacle that prevents
movement via the TM_Move functions.
Back to top
function TM_GetImage()
Back to top
[ Go back ]
ex_tilemap_1
Click in the window when the applet has loaded. Use the arrow keys to move around and press (or hold)
space to shoot.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/tm_1.html1/6/2012 2:35:51 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_tilemap_1.txt
rem ==================================================================
rem Tilemap - Example 1
rem
rem A shoot'em up thing.
rem
rem By Marcus.
rem ==================================================================
constant:
rem Images.
PLAYER_IMAGE 0
PLAYER_BULLET_IMAGE 1
ENEMY_1_IMAGE 2
ENEMY_2_IMAGE 3
ENEMY_BULLET_IMAGE 4
EXPLOSION_IMAGE 5
LIVES_IMAGE 6
rem Sounds.
ENEMY_HIT_SOUND 0
ENEMY_EXPLODE_SOUND 1
ENEMY_SHOOT_SOUND 2
PLAYER_EXPLODE_SOUND 3
PLAYER_SHOOT_SOUND 4
MAX_STARS 60
visible:
rem Player data.
vPlayerX
vPlayerY
vPlayerDX
vPlayerDY
vPlayerShield
vFireButtonReleased
vFireTimer
vLives
vScore
vGameOver
vEnemyBullets[MAX_BULLETS][6]
hidden:
do
rem Start with three lives.
vLives = 3
vScore = 0
vGameOver = false
set color 0, 0, 0
cls
set caret width(primary)/2, height(primary)/2
rem Update.
proc UpdatePlayer
proc UpdateEnemies
proc UpdateBullets
proc UpdateExplosions
rem Draw.
set color 0, 0, 0
cls
proc TM_Render
proc DoStars
proc DrawPlayer
proc DrawEnemies
proc DrawBullets
proc DrawExplosions
rem Lives.
set color 255, 255, 255
draw image LIVES_IMAGE, 2, 5
set caret 21, 9
write "X ", vLives
rem Score.
set caret width(primary)/2, 2
set color 255, 255, 255
center "SCORE"
center
rem ==================================================================
rem Load level.
rem ==================================================================
function LoadLevel(level)
rem Quit if level could not be loaded.
if not TM_LoadMap("tm_data/seu_" + str$(level) + ".txt") then return false
vEnemies[i][ENM_TYPE] = 0
next
vFrameCounter = 0
randomize time()
return true
endfunc
rem ==================================================================
rem Update player.
rem ==================================================================
procedure UpdatePlayer()
rem Update shield.
vPlayerShield = max(vPlayerShield - 1, 0)
vPlayerDX = 2
else
vPlayerDX = 0
endif
rem Move.
vPlayerX = max(min(vPlayerX + vPlayerDX, width(primary) - width(PLAYER_IMAGE)), 0)
vPlayerY = max(min(vPlayerY + vPlayerDY, height(primary) - height(PLAYER_IMAGE)), 0)
rem Shoot.
if keydown(VK_SPACE)
vFireTimer = max(vFireTimer - 1, 0)
rem Only shoot if spacebar has previously been released or a
rem certain time has passed.
if vFireButtonReleased or vFireTimer = 0
proc AddPlayerBullet
vFireTimer = 15
play sound PLAYER_SHOOT_SOUND
endif
vFireButtonReleased = false
else
vFireButtonReleased = true
vFireTimer = 0
endif
endproc
rem ==================================================================
rem Player hit.
rem ==================================================================
procedure PlayerHit()
proc AddExplosion vPlayerX + width(PLAYER_IMAGE)/2, vPlayerY + height
(PLAYER_IMAGE)/2
vPlayerX = (width(primary) - width(PLAYER_IMAGE))/2
vPlayerY = height(primary) - height(PLAYER_IMAGE)
vPlayerShield = 200
if vLives = 0
vGameOver = true
else
vLives = vLives - 1
endif
play sound PLAYER_EXPLODE_SOUND
endproc
rem ==================================================================
rem Draw player.
rem ==================================================================
procedure DrawPlayer()
if vGameOver then return
if vPlayerShield%8 < 4
set color 255, 255, 255
if vPlayerDX < 0
draw image PLAYER_IMAGE, vPlayerX, vPlayerY, 1
elseif vPlayerDX > 0
draw image PLAYER_IMAGE, vPlayerX, vPlayerY, 2
else
draw image PLAYER_IMAGE, vPlayerX, vPlayerY, 0
endif
endif
endproc
rem ==================================================================
rem Update enemies.
rem ==================================================================
procedure UpdateEnemies()
vEnemyWaveTimer = vEnemyWaveTimer - 1
rem New attack wave?
if vEnemyWaveTimer <= 0
vEnemyWaveTimer = 50 + rnd(150)
if rnd(2)
type = ENEMY_1_IMAGE
else
type = ENEMY_2_IMAGE
endif
x = rnd(width(primary) - width(type))
enemies = 1 + rnd(3)
for e = 0 to enemies
index = -1
for i = 0 to MAX_ENEMIES - 1
if vEnemies[i][ENM_TYPE] = 0
index = i
break
endif
next
if index >= 0
vEnemies[i][ENM_TYPE] = type
vEnemies[i][ENM_X] = x
vEnemies[i][ENM_Y] = -(e + 1)*(height(type) + 8)
vEnemies[i][ENM_SHIELD_TIMER] = 0
if type = ENEMY_1_IMAGE
vEnemies[i][ENM_DY] = 2
vEnemies[i][ENM_SHIELD] = 2
else
vEnemies[i][ENM_DY] = 1
vEnemies[i][ENM_SHIELD] = 3
endif
else
break
endif
next
endif
if vPlayerShield = 0
if ImageCol(PLAYER_IMAGE, vPlayerX, vPlayerY, vEnemies[i]
[ENM_TYPE], vEnemies[i][ENM_X], vEnemies[i][ENM_Y])
proc PlayerHit
endif
endif
rem ==================================================================
rem Draw enemies.
rem ==================================================================
procedure DrawEnemies()
set color 255, 255, 255
for i = 0 to MAX_ENEMIES - 1
if vEnemies[i][ENM_TYPE] > 0
if vEnemies[i][ENM_SHIELD_TIMER] > 0
draw image vEnemies[i][ENM_TYPE], vEnemies[i][ENM_X], vEnemies[i]
[ENM_Y], 1
else
draw image vEnemies[i][ENM_TYPE], vEnemies[i][ENM_X], vEnemies[i]
[ENM_Y], 0
endif
endif
next
endproc
rem ==================================================================
rem Add player bullet.
rem ==================================================================
procedure AddPlayerBullet()
index = -1
for i = 0 to MAX_BULLETS - 1
if vPlayerBullets[i][BUL_TYPE] = 0
index = i
break
endif
next
if index >= 0
vPlayerBullets[index][BUL_TYPE] = PLAYER_BULLET_IMAGE
vPlayerBullets[index][BUL_X] = vPlayerX + (width(PLAYER_IMAGE) - width
(PLAYER_BULLET_IMAGE))/2
vPlayerBullets[index][BUL_Y] = vPlayerY - 4
vPlayerBullets[index][BUL_DX] = 0
vPlayerBullets[index][BUL_DY] = -6
vPlayerBullets[index][BUL_FRAME] = 0
endif
endproc
rem ==================================================================
rem Add enemy bullet.
rem ==================================================================
procedure AddEnemyBullet(type, x, y)
index = -1
for i = 0 to MAX_BULLETS - 1
if vEnemyBullets[i][BUL_TYPE] = 0
index = i
break
endif
next
if index >= 0
dx# = float(vPlayerX - x)
dy# = float(vPlayerY - y)
k# = 1.0/sqr(dx*dx + dy*dy)
dx = dx*k
dy = dy*k
vEnemyBullets[index][BUL_TYPE] = ENEMY_BULLET_IMAGE
vEnemyBullets[index][BUL_X] = x + (width(type) - width(ENEMY_BULLET_IMAGE))/2
vEnemyBullets[index][BUL_Y] = y + (height(type) - height(ENEMY_BULLET_IMAGE))/2
vEnemyBullets[index][BUL_DX] = int(dx*3.0)
vEnemyBullets[index][BUL_DY] = int(dy*3.0)
vEnemyBullets[index][BUL_FRAME] = 0
endif
endproc
rem ==================================================================
rem Update bullets.
rem ==================================================================
procedure UpdateBullets()
rem Update bullets.
wp = width(primary)
hp = height(primary)
for i = 0 to MAX_BULLETS - 1
if vPlayerBullets[i][BUL_TYPE] > 0
rem Move.
vPlayerBullets[i][BUL_X] = vPlayerBullets[i][BUL_X] + vPlayerBullets[i][BUL_DX]
vPlayerBullets[i][BUL_Y] = vPlayerBullets[i][BUL_Y] + vPlayerBullets[i][BUL_DY]
rem Remove?
if vPlayerBullets[i][BUL_Y] < -16
vPlayerBullets[i][BUL_TYPE] = 0
else
rem Animation.
if vFrameCounter = 0 then vPlayerBullets[i][BUL_FRAME] = 1 - vPlayerBullets[i]
[BUL_FRAME]
if vEnemyBullets[i][BUL_TYPE] > 0
rem Move.
vEnemyBullets[i][BUL_X] = vEnemyBullets[i][BUL_X] + vEnemyBullets[i][BUL_DX]
vEnemyBullets[i][BUL_Y] = vEnemyBullets[i][BUL_Y] + vEnemyBullets[i][BUL_DY]
rem Remove?
if vEnemyBullets[i][BUL_Y] < -16 or vEnemyBullets[i][BUL_Y] > hp or vEnemyBullets
[i][BUL_X] < -16 or vEnemyBullets[i][BUL_X] > wp
vEnemyBullets[i][BUL_TYPE] = 0
else
rem Animation.
if vFrameCounter = 0 then vEnemyBullets[i][BUL_FRAME] = 1 - vEnemyBullets[i]
[BUL_FRAME]
rem ==================================================================
rem Draw bullets.
rem ==================================================================
procedure DrawBullets()
rem Draw bullets.
set color 255, 255, 255
for i = 0 to MAX_BULLETS - 1
if vPlayerBullets[i][BUL_TYPE] > 0
draw image vPlayerBullets[i][BUL_TYPE], vPlayerBullets[i][BUL_X], vPlayerBullets[i]
[BUL_Y], vPlayerBullets[i][BUL_FRAME]
endif
if vEnemyBullets[i][BUL_TYPE] > 0
draw image vEnemyBullets[i][BUL_TYPE], vEnemyBullets[i][BUL_X], vEnemyBullets
[i][BUL_Y], vEnemyBullets[i][BUL_FRAME]
endif
next
endproc
rem ==================================================================
rem Add explosion at x, y.
rem ==================================================================
procedure AddExplosion(x, y)
rem Find unused index.
index = -1
for i = 0 to MAX_EXPLOSIONS - 1
if vExplosions[i][EXP_FRAME] = -1
index = i
break
endif
next
rem ==================================================================
rem Update explosions.
rem ==================================================================
procedure UpdateExplosions()
if vFrameCounter = 0
for i = 0 to MAX_EXPLOSIONS - 1
if vExplosions[i][EXP_FRAME] >= 0
vExplosions[i][EXP_FRAME] = vExplosions[i][EXP_FRAME] + 1
if vExplosions[i][EXP_FRAME] >= 8 then vExplosions[i][EXP_FRAME] = -1
endif
next
endif
endproc
rem ==================================================================
rem Draw explosions.
rem ==================================================================
procedure DrawExplosions()
procedure DoStars()
rem Update and draw stars.
for i = 0 to MAX_STARS - 1
vStars[i][1] = vStars[i][1] + vStars[i][2]
if vStars[i][1] >= 240.0 then vStars[i][1] = vStars[i][1] - 240.0
x = int(vStars[i][0])
y = int(vStars[i][1])
rem ==================================================================
rem Return true if two images overlap.
rem ==================================================================
function ImageCol(img0, x0, y0, img1, x1, y1)
if x0 + width(img0) < x1 then return false
if y0 + height(img0) < y1 then return false
if x1 + width(img1) < x0 then return false
if y1 + height(img1) < y0 then return false
return true
endfunc
ex_tilemap_2
Click in the window when the applet has loaded. Use arrow keys to control Mr. Bluepants.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/tm_2.html1/6/2012 2:35:52 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_tilemap_2.txt
rem ==================================================================
rem Tilemap - Example 2
rem
rem A very original platform game.
rem
rem By Marcus.
rem ==================================================================
constant:
rem Images.
BG_IMAGE 0
PLAYER_IMAGE 1
WALKER_IMAGE 2
BAT_IMAGE 3
BRICK_IMAGE 4
SCORE_IMAGE 5
LOGO_IMAGE 6
rem Sound.
JUMP_SOUND 0
HIT_SOUND 1
CRACK_SOUND 2
COIN_SOUND 3
STOMP_SOUND 4
LIFE_LOST_SOUND 5
COMPLETE_SOUND 6
rem Music.
GAME_MUSIC 0
ENM_DX 5
ENM_DY 6
ENM_EXTRA 7
visible:
rem Player.
vLevel
vLives
vJewels
vScore
vPlayerX
vPlayerY
vPlayerDY
vPlayerCanJump
vPlayerGravityTimer
vPlayerBaseFrame
vPlayerFrame
vLifeLost
vLevelComplete
vLevelEndTimer
rem Enemies.
vEnemies[][]
vEnemyGravityTimer
vEnemyFrame
rem Animation.
vAnimTimer
vWalkAnimSeq[] = [0, 1, 2, 1, 3]
hidden:
rem Load.
proc LoadStuff
do
proc Title
do
if not LoadLevel(vLevel) then break
do
rem If it's an applet, we need to shut down manually.
if not running() then end
rem Update.
vAnimTimer = (vAnimTimer + 1)%4
proc UpdatePlayer
proc UpdateEnemies
proc DrawEnemies
redraw
proc SPD_HoldFrame 50
until vLevelEndTimer = 0
vLevel = vLevel + 1
endif
loop
loop
rem ==================================================================
rem Load all resources.
rem ==================================================================
procedure LoadStuff()
rem Font.
if javac()
load font 0, "tm_data/courier14.txt", "tm_data/courier14.png"
else
load font 0, "tm_data/courier14.txt", "tm_data/courier14.bmp"
endif
rem Message.
set color 48, 48, 128
cls
set color 255, 255, 255
set caret 160, 110
center "Loading ..."
redraw
rem Images.
load image PLAYER_IMAGE, "tm_data/pf_player.bmp"
set image grid PLAYER_IMAGE, 4, 3
set image colorkey PLAYER_IMAGE, 255, 0, 255
load image BRICK_IMAGE, "tm_data/pf_brick.bmp"
set image colorkey BRICK_IMAGE, 255, 0, 255
load image WALKER_IMAGE, "tm_data/pf_walker.bmp"
set image grid WALKER_IMAGE, 4, 2
set image colorkey WALKER_IMAGE, 255, 0, 255
load image BAT_IMAGE, "tm_data/pf_bat.bmp"
set image grid BAT_IMAGE, 4, 1
set image colorkey BAT_IMAGE, 255, 0, 255
load image SCORE_IMAGE, "tm_data/pf_score.bmp"
set image grid SCORE_IMAGE, 1, 3
set image colorkey SCORE_IMAGE, 255, 0, 255
load image LOGO_IMAGE, "tm_data/pf_logo.bmp"
set image colorkey LOGO_IMAGE, 255, 0, 255
rem Music.
if javac()
load music GAME_MUSIC, "tm_data/pf_music.wav"
else
load music GAME_MUSIC, "tm_data/pf_music.it"
endif
endproc
rem ==================================================================
rem Title screen.
rem ==================================================================
procedure Title()
flashTimer = 0
do
if not running() then end
rem ==================================================================
rem Load level.
rem ==================================================================
function LoadLevel(id)
rem Load map.
if not TM_LoadMap("tm_data/pf_level_" + str$(id) + ".txt") then return false
vEnemies[e][ENM_DY] = 0
rem Bat?
elseif flags[i][TM_FLAG] = 3
vEnemies[e][ENM_TYPE] = BAT
vEnemies[e][ENM_IMAGE] = BAT_IMAGE
vEnemies[e][ENM_CEL] = 1
vEnemies[e][ENM_EXTRA] = 90*(e%4)
vEnemies[e][ENM_X] = flags[i][TM_X]*16 + int(cos(float(ENM_EXTRA))*32.0)
vEnemies[e][ENM_Y] = flags[i][TM_Y]*16 + int(sin(float(ENM_EXTRA))*32.0)
vEnemies[e][ENM_DX] = flags[i][TM_X]*16
vEnemies[e][ENM_DY] = flags[i][TM_Y]*16
endif
e=e+1
endif
next
vEnemyFrame = 0
vEnemyGravityTimer = 0
return true
endfunc
rem ==================================================================
rem Update player.
rem ==================================================================
procedure UpdatePlayer()
rem Waiting for life lost effect to finish?
if vLifeLost or vLevelComplete
vLevelEndTimer = vLevelEndTimer - 1
return
endif
rem Jump.
if keydown(VK_UP)
vJumpButtonReleased = false
if vPlayerCanJump
vPlayerDY = -6
vPlayerGravityTimer = 3
play sound JUMP_SOUND
endif
else
vJumpButtonReleased = true
if vPlayerDY < -2 then vPlayerDY = -2
endif
rem If player has landed and the jump button has been released,
rem set flag to true.
if info[TM_DOWN] and vJumpButtonReleased
vPlayerCanJump = true
else
vPlayerCanJump = false
endif
rem If player has hit something with the head, things might
rem happen.
if info[TM_UP]
rem To avoid getting stuck for a while in the ceiling.
if vPlayerDY < 0 then vPlayerDY = 0
proc SP_AddParticle BRICK_IMAGE, 0, false, x + 12, y + 12, 2.0, -2.0, 1.0, 2.0, 1.0,
1.0, 0.05, 0
else
proc TM_SetCel pos[TM_X], pos[TM_Y], -1
proc TM_SetCel pos[TM_X] - 1, pos[TM_Y], -1
endif
proc SP_AddParticle SCORE_IMAGE, 2, false, vPlayerX + width(PLAYER_IMAGE)/2,
vPlayerY, 0.0, -2.0, 0.0, 0.0, 1.0, 1.0, 0.025, 0
vScore = vScore + 1000
rem ==================================================================
rem Lose a life.
rem ==================================================================
procedure LoseLife()
vLifeLost = true
vLevelEndTimer = 100
proc SP_AddParticle PLAYER_IMAGE, 8, false, vPlayerX + width(PLAYER_IMAGE)/2,
vPlayerY + height(PLAYER_IMAGE)/2, 0.0, -4.0, 0.0, 6.0, 1.0, 1.0, 0.025, 0
stop music GAME_MUSIC
play sound LIFE_LOST_SOUND
endproc
rem ==================================================================
rem Update enemies.
rem ==================================================================
procedure UpdateEnemies()
vEnemyGravityTimer = (vEnemyGravityTimer + 1)%4
if vAnimTimer = 0 then vEnemyFrame = (vEnemyFrame + 1)%4
s = sizeof(vEnemies, 0) - 1
for i = 0 to s
type = vEnemies[i][ENM_TYPE]
if type
rem Walker?
if type = WALKER
rem Only update if enemy is visible.
if TM_Visible(WALKER_IMAGE, vEnemies[i][ENM_X], vEnemies[i][ENM_Y])
if vEnemyGravityTimer = 0 then vEnemies[i][ENM_DY] = min(vEnemies[i]
[ENM_DY] + 1, 6)
if vAnimTimer%2 = 0
dx = vEnemies[i][ENM_DX]
else
dx = 0
endif
pos[] = TM_Move(WALKER_IMAGE, vEnemies[i][ENM_X], vEnemies[i]
[ENM_Y], dx, vEnemies[i][ENM_DY])
vEnemies[i][ENM_X] = pos[TM_X]
vEnemies[i][ENM_Y] = pos[TM_Y]
x = vEnemies[i][ENM_X]
y = vEnemies[i][ENM_Y]
rem Turn around?
if TM_CollisionLeft() or TM_CollisionRight() or not TM_Obstacle
(TM_GetCelAt(x + 8 + 8*dx, y + 24))
vEnemies[i][ENM_DX] = -dx
endif
if vEnemies[i][ENM_DX] < 0
vEnemies[i][ENM_CEL] = vWalkAnimSeq[vEnemyFrame + 1]
else
vEnemies[i][ENM_CEL] = vWalkAnimSeq[vEnemyFrame + 1] + 4
endif
rem Collision with player?
if not vLifeLost
if TM_ImageCol(PLAYER_IMAGE, vPlayerX, vPlayerY,
WALKER_IMAGE, x, y)
rem Stomp?
if vPlayerDY > 0 and vPlayerY + height(PLAYER_IMAGE) < y +
height(vEnemies[i][ENM_IMAGE])/2
vEnemies[i][ENM_TYPE] = 0
proc SP_AddParticle WALKER_IMAGE, 0, false, x + width
(WALKER_IMAGE)/2 , y + height(WALKER_IMAGE)/2, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.01, 0
vPlayerDY = -4
vPlayerY = y - height(PLAYER_IMAGE) + vPlayerDY
play sound STOMP_SOUND
proc SP_AddParticle SCORE_IMAGE, 1, false, x + width
(WALKER_IMAGE)/2, y, 0.0, -2.0, 0.0, 0.0, 1.0, 1.0, 0.025, 0
vScore = vScore + 200
else
proc LoseLife
endif
endif
endif
endif
rem Bat?
elseif type = BAT
if TM_Visible(BAT_IMAGE, vEnemies[i][ENM_X], vEnemies[i][ENM_Y])
vEnemies[i][ENM_EXTRA] = (vEnemies[i][ENM_EXTRA] + 1)%360
vEnemies[i][ENM_X] = vEnemies[i][ENM_DX] + int(cos(float(vEnemies[i]
[ENM_EXTRA]))*32.0)
vEnemies[i][ENM_Y] = vEnemies[i][ENM_DY] + int(sin(float(vEnemies[i]
[ENM_EXTRA]))*32.0)
vEnemies[i][ENM_CEL] = vWalkAnimSeq[vEnemyFrame + 1]
x = vEnemies[i][ENM_X]
y = vEnemies[i][ENM_Y]
rem Collision with player?
if not vLifeLost
if TM_ImageCol(PLAYER_IMAGE, vPlayerX, vPlayerY,
WALKER_IMAGE, x, y)
rem Stomp?
if vPlayerDY > 0 and vPlayerY + height(PLAYER_IMAGE) < y +
height(vEnemies[i][ENM_IMAGE])/2
vEnemies[i][ENM_TYPE] = 0
proc SP_AddParticle BAT_IMAGE, 0, false, x + width
(BAT_IMAGE)/2 , y + height(BAT_IMAGE)/2, 0.0, 2.0, 0.0, 2.0, 1.0, 1.0, 0.025, 0
vPlayerDY = -4
vPlayerY = y - height(PLAYER_IMAGE) + vPlayerDY
play sound STOMP_SOUND
proc SP_AddParticle SCORE_IMAGE, 1, false, x + width
(BAT_IMAGE)/2, y, 0.0, -2.0, 0.0, 0.0, 1.0, 1.0, 0.025, 0
vScore = vScore + 200
else
proc LoseLife
endif
endif
endif
endif
endif
endif
next
endproc
rem ==================================================================
rem Draw enemies.
rem ==================================================================
procedure DrawEnemies()
s = sizeof(vEnemies, 0) - 1
for i = 0 to s
if vEnemies[i][ENM_TYPE] > 0
draw image vEnemies[i][ENM_IMAGE], TM_ToScreenX(vEnemies[i][ENM_X]),
TM_ToScreenY(vEnemies[i][ENM_Y]), vEnemies[i][ENM_CEL]
endif
next
endproc
ex_tilemap_3
Click in the window when the applet has loaded. Use arrow keys to control the space marine guy. Put
bombs on the ground using space bar to blow up enemies. You can also open a door with space bar if
you've got a key. Find the exit on each level.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/tm_3.html1/6/2012 2:35:53 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_tilemap_3.txt
rem ==================================================================
rem Tilemap - Example 3.
rem
rem Alien Bomber.
rem
rem By Marcus.
rem ==================================================================
constant:
rem Images.
PLAYER_IMAGE 0
BOMB_IMAGE 1
EXPLOSION_IMAGE 2
H_DOOR_IMAGE 3
V_DOOR_IMAGE 4
GREEN_ENEMY_IMAGE 5
RED_ENEMY_IMAGE 6
SMALL_RED_ENEMY_IMAGE 7
TITLE_IMAGE 8
PLAYER_DIE_IMAGE 9
HEART_IMAGE 10
KEY_IMAGE 11
rem Sound.
JEWEL_SOUND 0
KEY_SOUND 1
PLAYER_HIT_SOUND 2
EXPLOSION_SOUND 3
ENEMY_HIT_SOUND 4
DROP_BOMB_SOUND 5
DOOR_SOUND 6
rem Music.
GAME_MUSIC 0
DOWN 0
UP 3
RIGHT 6
LEFT 9
rem Bomb.
MAX_BOMBS 3
BOMB_TIMER 0
BOMB_X 1
BOMB_Y 2
rem Explosion.
MAX_EXP 8
EXP_STATE 0
EXP_DISTANCE 1
EXP_TIMER 2
EXP_X 3
EXP_Y 4
EXP_LEFT_STOP 5
EXP_RIGHT_STOP 6
EXP_UP_STOP 7
EXP_DOWN_STOP 8
rem Enemy.
ENM_TYPE 0
ENM_X 1
ENM_Y 2
ENM_DIRECTION 3
ENM_MOVE 4
ENM_TIMER 5
ENM_INVUNERABLE 6
visible:
rem Player.
vPlayerX
vPlayerY
vPlayerDirection
vPlayerFrame
vPlayerStamina
vPlayerTimer
vLevel
vLives
vScore
vKeys
vLevelCompleted
vWalkAnim[] = [0, 1, 0, 2]
vAnimTimer
rem Bombs.
vBombs[MAX_BOMBS][3]
vBombTimer
rem Explosions.
vExplosions[MAX_EXP][9]
vBombRange = 4
rem Enemies.
vEnemies[][]
vEnemyFrame
vEnemyAnim[] = [0, 1, 0, 1, 2, 3, 2, 3, 0, 1, 0, 1, 4, 5, 4, 5]
hidden:
proc Load
do
proc Title
vLevel = 1
vLives = 3
vScore = 0
vKeys = 0
do
if not LoadLevel(vLevel) then break
vPlayerStamina = 3
vPlayerTimer = 0
vKeys = 0
vLevelCompleted = false
vAnimTimer = 0
do
rem Shut down if applet is gone.
if not running()
stop music 0
end
endif
rem Cheat.
if keydown("+", true) then vLevelCompleted = true
rem Updates.
proc UpdatePlayer
proc UpdateEnemies
proc UpdateBombs
proc UpdateExplosions
rem Draw.
set color 0, 16, 32
cls
set color 255, 255, 255
proc TM_Render
proc DrawEnemies
proc DrawBombs
proc DrawPlayer
proc SP_DoParticlesAt -TM_CameraX(), -TM_CameraY()
rem Status.
set color 0, 0, 0
draw rect 0, 224, 320, 16, true
rem Hearts.
set color 255, 255, 255
for i = 0 to vPlayerStamina - 1
draw image HEART_IMAGE, 2 + i*18, 224
next
rem Keys.
for i = 0 to vKeys - 1
draw image KEY_IMAGE, 310 - i*12, 224
next
redraw
proc SPD_HoldFrame 60
until keydown(27) or (vPlayerStamina = 0 and vPlayerTimer = 0) or vLevelCompleted
stop music 0
rem ==================================================================
rem Load game resources.
rem ==================================================================
procedure Load()
if javac()
load font 0, "tm_data/silkworm.txt", "tm_data/silkworm.png"
else
load font 0, "tm_data/silkworm.txt", "tm_data/silkworm.bmp"
endif
rem Images.
load image PLAYER_IMAGE, "tm_data/ab_player.bmp"
set image grid PLAYER_IMAGE, 3, 4
set image colorkey PLAYER_IMAGE, 255, 0, 255
rem Sound.
load sound JEWEL_SOUND, "tm_data/ab_jewel.wav"
load sound KEY_SOUND, "tm_data/ab_key.wav"
load sound PLAYER_HIT_SOUND, "tm_data/ab_player_hit.wav"
load sound EXPLOSION_SOUND, "tm_data/ab_explosion.wav"
load sound ENEMY_HIT_SOUND, "tm_data/ab_enemy_hit.wav"
load sound DROP_BOMB_SOUND, "tm_data/ab_drop_bomb.wav"
load sound DOOR_SOUND, "tm_data/ab_door.wav"
rem Music.
if javac()
load music GAME_MUSIC, "tm_data/ab_music.wav"
else
load music GAME_MUSIC, "tm_data/ab_music.it"
endif
endproc
rem ==================================================================
rem Show title screen with instructions.
rem ==================================================================
procedure Title()
timer = 0
do
if not running() or keydown(27, true) then end
if timer < 75
set color 128, 128, 128
center
center "CLICK TO START ..."
endif
redraw
proc SPD_HoldFrame 60
until mousebutton(0, true)
endproc
rem ==================================================================
rem Load level.
rem ==================================================================
function LoadLevel(id)
if not TM_LoadMap("tm_data/ab_level_" + str$(id) + ".txt") then return false
flags[][] = TM_GetLoaderFlags()
enemyCount = 0
for i = 0 to sizeof(flags, 0) - 1
rem Player's starting position.
if flags[i][TM_FLAG] = 1
vPlayerX = flags[i][TM_X]*16
vPlayerY = flags[i][TM_Y]*16
rem Green enemy.
elseif flags[i][TM_FLAG] = 2
enemyCount = enemyCount + 1
rem Red enemy (transforms into two enemies when blown up).
elseif flags[i][TM_FLAG] = 3
enemyCount = enemyCount + 2
endif
next
proc SP_Init 50
return true
endfunc
rem ==================================================================
rem Update player.
rem ==================================================================
procedure UpdatePlayer()
rem A count down used when player blinks after being hit.
vPlayerTimer = max(vPlayerTimer - 1, 0)
if keydown(VK_SPACE, true)
rem Check for doors.
openedDoor = false
if vKeys > 0
if vPlayerDirection = UP
cel = TM_GetCelAt(vPlayerX + 8, vPlayerY - 8)
if cel = 32
openedDoor = true
pos[] = TM_ToTile(vPlayerX + 8, vPlayerY - 8)
proc TM_SetCel pos[TM_X], pos[TM_Y], 11
proc TM_SetCel pos[TM_X] + 1, pos[TM_Y], 0
proc SP_AddParticle H_DOOR_IMAGE, -1, false, pos[TM_X]*16 + 16, pos
[TM_Y]*16 + 8, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.1, 0
elseif cel = 33
openedDoor = true
pos[] = TM_ToTile(vPlayerX + 8, vPlayerY - 8)
proc TM_SetCel pos[TM_X] - 1, pos[TM_Y], 11
proc TM_SetCel pos[TM_X], pos[TM_Y], 0
proc SP_AddParticle H_DOOR_IMAGE, -1, false, pos[TM_X]*16, pos[TM_Y]
*16 + 8, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.1, 0
endif
elseif vPlayerDirection = DOWN
cel = TM_GetCelAt(vPlayerX + 8, vPlayerY + 30)
if cel = 32
openedDoor = true
pos[] = TM_ToTile(vPlayerX + 8, vPlayerY + 30)
proc TM_SetCel pos[TM_X], pos[TM_Y], 11
proc TM_SetCel pos[TM_X] + 1, pos[TM_Y], 0
proc SP_AddParticle H_DOOR_IMAGE, -1, false, pos[TM_X]*16 + 16, pos
[TM_Y]*16 + 8, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.1, 0
elseif cel = 33
openedDoor = true
pos[] = TM_ToTile(vPlayerX + 8, vPlayerY + 30)
proc TM_SetCel pos[TM_X] - 1, pos[TM_Y], 11
proc TM_SetCel pos[TM_X], pos[TM_Y], 0
proc SP_AddParticle H_DOOR_IMAGE, -1, false, pos[TM_X]*16, pos[TM_Y]
*16 + 8, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.1, 0
endif
elseif vPlayerDirection = LEFT
cel = TM_GetCelAt(vPlayerX - 8, vPlayerY + 11)
if cel = 34
openedDoor = true
pos[] = TM_ToTile(vPlayerX - 8, vPlayerY + 11)
vPlayerX = pos[TM_X] - 1
vPlayerY = pos[TM_Y] - 7
rem Exit.
elseif cel = 42
vLevelCompleted = true
endif
endproc
rem ==================================================================
rem Player has been hit.
rem ==================================================================
procedure PlayerHit()
if vPlayerTimer = 0 and vPlayerStamina > 0
vPlayerTimer = 200
vPlayerStamina = vPlayerStamina - 1
rem Stop music and add nasty animation if player's lost a life.
if vPlayerStamina = 0
proc SP_AddParticle PLAYER_DIE_IMAGE, -1, false, vPlayerX + width
(PLAYER_IMAGE)/2, vPlayerY + height(PLAYER_IMAGE)/2, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.025, 0
stop music 0
vPlayerTimer = 100
endif
play sound PLAYER_HIT_SOUND
endif
endproc
rem ==================================================================
rem Draw player.
rem ==================================================================
procedure DrawPlayer()
if vPlayerStamina > 0
rem Blinking.
if vPlayerTimer%10 < 5
draw image PLAYER_IMAGE, TM_ToScreenX(vPlayerX), TM_ToScreenY(vPlayerY),
vPlayerDirection + vWalkAnim[vPlayerFrame]
endif
endif
endproc
rem ==================================================================
rem Drop bomb at x, y.
rem ==================================================================
procedure AddBomb(x, y)
index = -1
for i = 0 to MAX_BOMBS - 1
if vBombs[i][BOMB_TIMER] = 0
index = i
break
endif
next
if index >= 0
vBombs[index][BOMB_TIMER] = 200
vBombs[index][BOMB_X] = x
vBombs[index][BOMB_Y] = y
play sound DROP_BOMB_SOUND
endif
endproc
rem ==================================================================
rem Update bombs.
rem ==================================================================
procedure UpdateBombs()
vBombTimer = (vBombTimer + 1)%20
for i = 0 to MAX_BOMBS - 1
if vBombs[i][BOMB_TIMER] > 0
vBombs[i][BOMB_TIMER] = vBombs[i][BOMB_TIMER] - 1
rem If bomb's done blinking, add an explosion.
if vBombs[i][BOMB_TIMER] = 0 then proc AddExplosion vBombs[i][BOMB_X],
vBombs[i][BOMB_Y]
endif
next
endproc
rem ==================================================================
rem Draw bombs.
rem ==================================================================
procedure DrawBombs()
set color 255, 255, 255
if vBombTimer < 10
frame = 1
else
frame = 0
endif
for i = 0 to MAX_BOMBS - 1
t = vBombs[i][BOMB_TIMER]
if t > 0
if (t < 150 and vBombTimer = 0) or (t < 75 and vBombTimer%5 = 0)
draw image BOMB_IMAGE, TM_ToScreenX(vBombs[i][BOMB_X]),
TM_ToScreenY(vBombs[i][BOMB_Y]), 2 + frame
else
draw image BOMB_IMAGE, TM_ToScreenX(vBombs[i][BOMB_X]),
TM_ToScreenY(vBombs[i][BOMB_Y]), 0 + frame
endif
endif
next
endproc
rem ==================================================================
rem Add an explosion at x, y.
rem ==================================================================
procedure AddExplosion(x, y)
index = -1
for i = 0 to MAX_EXP - 1
if vExplosions[i][EXP_STATE] = 0
index = i
break
endif
next
if index >= 0
vExplosions[index][EXP_STATE] = vBombRange
vExplosions[index][EXP_DISTANCE] = 0
vExplosions[index][EXP_TIMER] = 0
vExplosions[index][EXP_X] = x
vExplosions[index][EXP_Y] = y
vExplosions[i][EXP_LEFT_STOP] = false
vExplosions[i][EXP_RIGHT_STOP] = false
vExplosions[i][EXP_UP_STOP] = false
vExplosions[i][EXP_DOWN_STOP] = false
play sound EXPLOSION_SOUND
endif
endproc
rem ==================================================================
rem Update explosions.
rem ==================================================================
procedure UpdateExplosions()
for i = 0 to MAX_EXP - 1
if vExplosions[i][EXP_STATE] > 0
if vExplosions[i][EXP_TIMER] = 0
vExplosions[i][EXP_TIMER] = 5
if vExplosions[i][EXP_DISTANCE] = 0
rem ==================================================================
rem Explode at x, y.
rem ==================================================================
function ExplodeAt(x, y)
rem Check for enemies.
s = sizeof(vEnemies, 0) - 1
for i = 0 to s
if vEnemies[i][ENM_TYPE] and vEnemies[i][ENM_INVUNERABLE] = 0
if ImageCol(vEnemies[i][ENM_TYPE], vEnemies[i][ENM_X], vEnemies[i][ENM_Y],
EXPLOSION_IMAGE, x, y)
rem Multiplier?
if vEnemies[i][ENM_TYPE] = RED_ENEMY_IMAGE
ex = vEnemies[i][ENM_X]
ey = vEnemies[i][ENM_Y]
vEnemies[i][ENM_TYPE] = SMALL_RED_ENEMY_IMAGE
vEnemies[i][ENM_INVUNERABLE] = 50
vEnemies[i][ENM_TIMER] = 0
vEnemies[i][ENM_MOVE] = 16
vEnemies[i + 1][ENM_TYPE] = SMALL_RED_ENEMY_IMAGE
vEnemies[i + 1][ENM_INVUNERABLE] = 50
vEnemies[i + 1][ENM_TIMER] = 0
vEnemies[i + 1][ENM_MOVE] = 16
rem Place two small new enemies vertically or horizontally.
if rnd(2) = 0
vEnemies[i][ENM_X] = ex + 4
vEnemies[i][ENM_Y] = ey
vEnemies[i][ENM_DIRECTION] = 2
i=i+1
vEnemies[i][ENM_X] = ex + 4
vEnemies[i][ENM_Y] = ey + 8
vEnemies[i][ENM_DIRECTION] = 3
else
vEnemies[i][ENM_X] = ex
vEnemies[i][ENM_Y] = ey + 4
vEnemies[i][ENM_DIRECTION] = 0
i=i+1
vEnemies[i][ENM_X] = ex + 8
vEnemies[i][ENM_Y] = ey + 4
vEnemies[i][ENM_DIRECTION] = 1
endif
else
vEnemies[i][ENM_TYPE] = 0
endif
vScore = vScore + 50
play sound ENEMY_HIT_SOUND
endif
endif
next
if cel = 15
proc TM_SetCel x/16, y/16, 0
vScore = vScore + 10
rem Something hidden in rock?
flag = TM_GetFlag(x/16, y/16)
rem Jewel?
if flag = 1
proc TM_SetCel x/16, y/16, 45 + rnd(3)
elseif flag = 2
proc TM_SetCel x/16, y/16, 31
elseif flag = 3
proc TM_SetCel x/16, y/16, 44
endif
endif
return obstacle
endfunc
rem ==================================================================
rem Update enemies.
rem ==================================================================
procedure UpdateEnemies()
s = sizeof(vEnemies, 0) - 1
if vAnimTimer = 0 then vEnemyFrame = (vEnemyFrame + 1)%sizeof(vEnemyAnim)
for i = 0 to s
if vEnemies[i][ENM_TYPE]
if ImageCol(PLAYER_IMAGE, vPlayerX, vPlayerY, vEnemies[i][ENM_TYPE],
vEnemies[i][ENM_X], vEnemies[i][ENM_Y])
proc PlayerHit
endif
vEnemies[i][ENM_INVUNERABLE] = max(vEnemies[i][ENM_INVUNERABLE] - 1,
0)
if vEnemies[i][ENM_TIMER] > 0
vEnemies[i][ENM_TIMER] = vEnemies[i][ENM_TIMER] - 1
rem Time for new move?
if vEnemies[i][ENM_TIMER] = 0
vEnemies[i][ENM_MOVE] = 16
dx = vPlayerX - vEnemies[i][ENM_X]
dy = vPlayerY - vEnemies[i][ENM_Y]
rem Follow player when close enough.
if dx*dx + dy*dy < 4096
if abs(dx) > abs(dy)
if dx < 0; vEnemies[i][ENM_DIRECTION] = 0
else; vEnemies[i][ENM_DIRECTION] = 1
endif
else
if dy < 0; vEnemies[i][ENM_DIRECTION] = 2
else; vEnemies[i][ENM_DIRECTION] = 3
endif
endif
rem Move by random.
else
vEnemies[i][ENM_DIRECTION] = rnd(4)
endif
endif
else
rem Move.
d = vEnemies[i][ENM_DIRECTION]
dx = 0
dy = 0
if d = 0; dx = -1
elseif d = 1; dx = 1
elseif d = 2; dy = -1
else; dy = 1
endif
pos[] = TM_MoveRect(vEnemies[i][ENM_X], vEnemies[i][ENM_Y], 16, 16, dx,
dy)
vEnemies[i][ENM_X] = pos[TM_X]
vEnemies[i][ENM_Y] = pos[TM_Y]
vEnemies[i][ENM_MOVE] = vEnemies[i][ENM_MOVE] - 1
if vEnemies[i][ENM_MOVE] <= 0 then vEnemies[i][ENM_TIMER] = 25*rnd(3)
endif
endif
next
endproc
rem ==================================================================
rem Draw enemies.
rem ==================================================================
procedure DrawEnemies()
s = sizeof(vEnemies, 0) - 1
for i = 0 to s
if vEnemies[i][ENM_TYPE]
draw image vEnemies[i][ENM_TYPE], TM_ToScreenX(vEnemies[i][ENM_X]),
TM_ToScreenY(vEnemies[i][ENM_Y]) - 4, vEnemyAnim[vEnemyFrame]
endif
next
endproc
rem ==================================================================
rem Return true if two images overlap.
rem ==================================================================
function ImageCol(img0, x0, y0, img1, x1, y1)
if x0 + width(img0) < x1 then return false
if y0 + height(img0) < y1 then return false
if x1 + width(img1) < x0 then return false
if y1 + height(img1) < y0 then return false
return true
endfunc
[ Go back ]
Introduction
With the raycasting library and the RC_Editor program you can create 3D games in the style of
Wolfenstein and Blake Stone. If you want more control, it is possible to create games without using the
editor, but there are no examples of how to do that (if you're really interested you can look at the source
code of RC_Editor). If you are using the RC_Editor you don't need to care much about most of the sub
routines presented below, because RC_LoadMap takes care of much of the setup for you. I strongly
suggest that you start with looking at the example programs and their source codes.
Details
A NaaLaa raycasting "world" should be seen as a grid of cubes. Every cube side is of the size 1.0. This
world is represented by a 2D map/array with a couple of "layers":
● Wall
The image that is displayed on the four sides (in the x,z plane) of a cube.
● Floor
The image that is displayed on a cube's floor.
● Ceiling
The image that is displayed in a cube's ceiling.
● Flag
An integer value that can be used for anything.
● Item
Same as the flag, but an item can be connected to a visual object, such as a tree or a box of
ammunition.
● Darkness
For modification of the fog effect.
Examples
ex_raycasting1
ex_raycasting2
ex_raycasting3
ex_raycasting4
Sub routines
procedure RC_InitView(fov#, render_width, render_height)
function RC_LoadMap[][](filename$)
procedure RC_Render(x_view#, z_view#, view_angle#)
procedure RC_Update(speed#)
function RC_Move#[](min_distance#, x_pos#, z_pos#, dx#, dz#)
function RC_GetCollisionInfo[]()
function RC_FacingPos[](x#, z#, angle#)
function RC_GetImage(image_index)
function RC_GetWall(x, z)
function RC_GetWallImage(x, z)
procedure RC_SetWall(x, z, img_id)
function RC_GetFloor(x, z)
function RC_GetFloorImage(x, z)
procedure RC_SetFloor(x, z, img_id)
function RC_GetCeiling(x, z)
function RC_GetCeilingImage(x, z)
procedure RC_SetCeiling(x, z, img_id)
function RC_GetDoor(x, z)
function RC_GetDoorImage(x, z)
procedure RC_OpenDoor(x, z)
procedure RC_SetDoorSpeed(speed#)
procedure RC_SetDoor(x, z, type, img_id, along_z)
function RC_GetFlag(x, z)
function RC_GetFlagPos[](flag)
procedure RC_SetFlag(x, z, flag)
function RC_GetItem(x, z)
procedure RC_SetItem(x, z, item, obstacle)
procedure RC_RemoveItem(x, z)
procedure RC_AddObject(obj_id, img_id, x#, z#, y#, size#, map_x, map_z)
procedure RC_ModifyObject(obj_id, img_id, x#, z#, y#)
procedure RC_SetObjectImage(obj_id, img_id)
procedure RC_SetObjectPos(obj_id, x#, z#, y#)
procedure RC_RemoveObject(obj_id)
function RC_HasObject(obj_id)
function RC_GetMapWidth()
function RC_GetMapHeight()
procedure RC_SetFog(r, g, b, z_min#, z_max#)
procedure RC_EnableDarkness()
procedure RC_DisableDarkness()
procedure RC_SetDarkness(x, z, value#)
function RC_GetDarkness#(x, z)
function RC_ObstacleAt(x, z)
function RC_Visible(x_pos#, z_pos#, dst_x#, dst_z#)
procedure RC_InitMap(x_size, z_size)
You need to call this procedure before any other raycaster sub routine. It sets the field of view to fov#
(degrees) and the rendering width and height to render_width*render_height. render_width and
render_height should match the size of the image that the view is to be rendered to (usually the primary
image), else you may experience some graphical artefacts.
Back to top
function RC_LoadMap[][](filename$)
Load a map created with RC_Editor. The function returns an integer array containing the player's
starting position and angle, and all the loader flags that has been set in the editor. If the array is empty,
the map could not be loaded. You find the player's starting position and angle at index 0 of the array.
The rest of the array contains the loader flags. Ex:
import "Raycasting.lib"
flags[][] = RC_LoadMap("my_map.txt")
if sizeof(flags) = 0 then end
rem Do something with the rest of the flags, like setting up enemies.
for i = 1 to sizeof(flags, 0) - 1
wln "x = ", flags[i][RC_X], ", z = ", flags[i][RC_Z], ", flag = ",
flags[i][RC_FLAG]
next
Back to top
Render view from the position x_view#, z_view# looking in the direction view_angle# (degrees).
Back to top
procedure RC_Update(speed#)
If you're using doors, you need to call this function once every frame in your game loop. It takes care of
the door animations. Unless you're using some sort of variable frame rate, you should set speed# to 1.0.
Back to top
When you need to move an object, such as the player, you should use this function. x_pos#, z_pos# is
the current position of the object that you wish to move and dx, dz is the movement. The function returns
a float array with the new position. If the object hasn't collided with something, the resulting array will
be [x_pos# + dx#, z_pos# + dz#]. min_distance# is the minimum distance that the object is allowed to
have relative to a wall (or an obstacle item).
Back to top
function RC_GetCollisionInfo[]()
This function returns some information about what happened in the last call to RC_Move. The returned
integer array has four fields, one for each direction, telling you in what directions a collision occured.
Use the constants RC_NORTH, RC_SOUTH, RC_WEST and RC_EAST to get information, true/false,
about any direction. Ex:
Back to top
Return the map position that the point x#, z# is facing in the direction angle# (degrees). You can use
this, together with some other functions, presented bellow, to determine if the player is standing in front
of a door, switch or any other static object in your game. You can access the elements of the returned
array with the constants RC_X and RC_Z.
Note, that if you want to know the map position of an object located at x#, z#, all you need to do is to
convert the position into an integer position: int(x#), int(z#). You can use this to determine if the player
is standing in lava or if a new gun is to be picked up.
Back to top
function RC_GetImage(image_index)
This function only makes sense if you're using the RC_Editor. In the editor you load images into indexes
(1..), and this function returns the id of the image at index image_index.
Back to top
function RC_GetWall(x, z)
Return the wall at x, y . The returned value only makes sense if you're using the RC_Editor. It's the index
of an image loaded in the editor. You can use RC_GetImage to convert the index into an image id.
Back to top
function RC_GetWallImage(x, z)
Back to top
Set the image of the wall at x, z to img_id. If you want to use an image from a map created with the
RC_Editor, you can convert its image index into an image id with RC_GetImage.
Back to top
function RC_GetFloor(x, z)
Return the floor at x, z . The returned value only makes sense if you're using the RC_Editor. It's the
index of an image loaded in the editor. You can use RC_GetImage to convert the index into an image id.
Back to top
function RC_GetFloorImage(x, z)
Back to top
Set the image of the floor at x, z to img_id. If you want to use an image from a map created with the
RC_Editor, you can convert its image index into an image id with RC_GetImage.
Back to top
function RC_GetCeiling(x, z)
Return the ceiling at x, z . The returned value only makes sense if you're using the RC_Editor. It's the
index of an image loaded in the editor. You can use RC_GetImage to convert the index into an image id.
Back to top
function RC_GetCeilingImage(x, z)
Back to top
Set the image of the ceiling at x, z to img_id. If you want to use an image from a map created with the
RC_Editor, you can convert its image index into an image id with RC_GetImage.
Back to top
function RC_GetDoor(x, z)
Return the door at x, z . The returned value only makes sense if you're using the RC_Editor. It's the index
of an image loaded in the editor. You can use RC_GetImage to convert the index into an image id.
Back to top
function RC_GetDoorImage(x, z)
Back to top
procedure RC_OpenDoor(x, z)
Back to top
procedure RC_SetDoorSpeed(speed#)
Set the step size (0.0 .. 1.0) for the the animation when a doors opens to speed#. speed# is multiplied
with the speed passed to RC_Update.
Back to top
Set door at x, z . If along_z is true, the door will move along the z axis, else it'll use the x axis. type is the
value that'll be returned by RC_GetDoor and img_id is the id of the image that the door should use.
Back to top
function RC_GetFlag(x, z)
Back to top
function RC_GetFlagPos[](flag)
Return the position of a certain flag. The function returns an empty array if it couldn't find the flag.
Back to top
Back to top
function RC_GetItem(x, z)
Back to top
Set item at x, z to item. If obstacle is set to true, the item will become an obstacle that the player can't
move through. This procedure only makes sense if you're NOT using the RC_Editor. If you don't use the
RC_Editor, you can use this in combination with RC_AddObject to add visual pickups and obstacles.
Note: If you're using RC_Editor, all items that you've added in the editor will have visual objects
connected to them when you call RC_LoadMap.
Back to top
procedure RC_RemoveItem(x, z)
Remove item at x, z . If there's a visual object associated with this item, it will also be removed.
Back to top
Use this to add a visual object to the world. This can be used for enemies, bullets and other things. An
object is just an image with a position and size. obj_id (a positive, non zero, integer) is the id of the
object to add. Once added, you can modify the object using this id. #x, z# and y# is the position of the
object. If you set y# to 0.0, the object will stand on the floor. If you set it to 1.0 - 'it's height', it will
"hang" from the ceiling. size# is the size of the longest side of the object. If you want to connect the
object with an item, you should set map_x, map_z to the position of that item, else set them to -1, -1.
Back to top
Modify the object obj_id, that has already been added with RC_AddObject. img_id is the id of the image
that the object should use and x#, z# and y# is the position.
Back to top
Back to top
Back to top
procedure RC_RemoveObject(obj_id)
Back to top
function RC_HasObject(obj_id)
Back to top
function RC_GetMapWidth()
Back to top
function RC_GetMapHeight()
Back to top
Set the fog color to r, g and b (RGB). z_min# is the distance from the view at which the fog effect
should start, and z_max# is the distance at which walls and objects are no longer visible. z_max# is also
used as a the far clip plane. So even if you're not out for the fog effect, you should still call this
procedure to set the clip plane (with z_min# = z_max#).
Back to top
procedure RC_EnableDarkness()
Normally only the fog settings (RC_SetFog) determine the appearance of something at a certain distance
from the view point. But by calling this procedure, you can set an intensity for each cell in the map. The
darkness value of a cell, set with RC_SetDarkness, then affects the fog effect. By default, darkness is not
enabled, because it requires some extra calculations.
Back to top
procedure RC_DisableDarkness()
Disable darkness.
Back to top
Set the darkness at x, z to value# (0.0 .. 1.0). A value of 0.0 makes a cell appear completely in the fog
color, while 1.0 (default) has no effect on the appearence at all. All objects that move through the cell
will also be affected by the darkness.
Back to top
function RC_GetDarkness#(x, z)
Back to top
function RC_ObstacleAt(x, z)
Back to top
Return true if the point dst_x#, dst_z# is visible from x_pos#, z_pos#. You can, for example, use this to
determine if an enemy "sees" the player.
Back to top
Init the map to be of the size x_size*z_size. This also clears all objecs, items and flags.
Back to top
[ Go back ]
ex_raycasting1
Click in the window when the applet has loaded. Use the arrow keys to move around.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/raycasting1.html1/6/2012 2:35:55 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_raycasting1.txt
rem ==================================================================
rem Raycaster Library - Example 1.
rem
rem By Marcus.
rem ==================================================================
rem Set field of view to 65 degrees and the render width and height
rem to the size of the primary image.
proc RC_InitView 65.0, width(primary), height(primary)
rem Load map. "Loader flags" are explained in another example. But
rem there should be at least one element - the position and direction
rem of the player. If the array is empty, the map could not be loaded.
flags[][] = RC_LoadMap("rc_data/map0.txt")
if sizeof(flags) = 0 then end
ex_raycasting2
Click in the window when the applet has loaded. Use the arrow keys to move around and open doors
with the space bar. Pick up golden crosses to make the screen flash (what an amazing award!).
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/raycasting2.html1/6/2012 2:35:55 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_raycasting2.txt
rem ==================================================================
rem Raycaster Library - Example 2.
rem
rem In this second raycasting example, we let the player open doors
rem and pick up golden crosses.
rem
rem By Marcus.
rem ==================================================================
rem Set field of view to 65 degrees and the render width and height
rem to the size of the primary image.
proc RC_InitView 65.0, width(primary), height(primary)
rem Load map. "Loader flags" are explained in another example. But
rem there should be at least one element - the position and direction
rem of the player. If the array is empty, the map could not be loaded.
flags[][] = RC_LoadMap("rc_data/map2.txt")
if sizeof(flags) = 0 then end
rem A counter for animations, and the current frame for the golden
rem cross.
frameCounter = 0
crossFrame = 0
flashValue = 0
rem When the player picks up a cross, the screen should flash.
rem The intensity of the flash should always move towards zero.
flashValue = max(flashValue - 4, 0)
rem Render.
proc RC_Render playerX, playerZ, playerAngle
redraw
ex_raycasting3
Click in the window when the applet has loaded. Use the arrow keys to move around and open doors
with the space bar. Pick up golden crosses to make the screen flash (what an amazing award!).
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/raycasting3.html1/6/2012 2:35:56 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_raycasting3.txt
rem ==================================================================
rem Raycaster Library - Example 3.
rem
rem In the third raycasting example, we add some enemies and bullets.
rem Shoot with ctrl and strafe by holding down shift. The game ends
rem when the player's stamina is 0 or all golden crosses have been
rem collected.
rem
rem By Marcus.
rem ==================================================================
constant:
rem Images.
CROSS_ANIM_IMAGE 0
SPINNER_ANIM_IMAGE 1
SPINNER_IMAGE 2
FLYBOT_ANIM_IMAGE 3
FLYBOT_IMAGE 4
PLAYER_BULLET_IMAGE 5
ENEMY_BULLET_IMAGE 6
EXPLOSION_IMAGE_0 7
EXPLOSION_IMAGE_1 8
EXPLOSION_IMAGE_2 9
EXPLOSION_IMAGE_3 10
EXPLOSION_IMAGE_4 11
EXPLOSION_IMAGE_5 12
EXPLOSION_IMAGE_6 13
EXPLOSION_IMAGE_7 14
EXPLOSION_IMAGE_8 15
EXPLOSION_IMAGE_9 16
ENM_X 0
ENM_Z 1
ENM_Y 2
ENM_DX 3
ENM_DZ 4
ENM_EXTRA 5
visible:
rem Player.
vPlayerAngle#
vPlayerX#
vPlayerZ#
vPlayerStamina
vPlayerBulletTimer
rem Enemies.
vEnemies[][]
vEnemiesF#[][]
vSpinnerFrame
vFlybotFrameCounter
vFlybotFrame
rem Bullets.
vBullets[MAX_BULLETS][1]
vBulletsF#[MAX_BULLETS][6]
rem Explosions
vExplosions[MAX_EXPLOSIONS]
vExplosionFrameCounter
hidden:
proc Load
vPlayerStamina = 100
proc UpdateStuff
proc UpdateExplosions
proc UpdatePlayer
proc UpdateBullets
proc UpdateEnemies
redraw
proc SPD_HoldFrame 60
until vPlayerStamina = 0 or vCrossCount = vCrossesPicked or keydown(VK_ESC) or not running()
rem ==================================================================
rem Load graphics, music and sound.
rem ==================================================================
procedure Load()
rem Load a font.
if javac()
load font 0, "rc_data/meiryo24.txt", "rc_data/meiryo24.png"
else
load font 0, "rc_data/meiryo24.txt", "rc_data/meiryo24.bmp"
endif
rem The spinner enemy (and the flybot) uses the same sort of
rem animation as the golden cross: we blit the animation from an
rem image with 12 cels to an image that is used by all spinner
rem objects.
load image SPINNER_ANIM_IMAGE, "rc_data/robowack_spinner.bmp"
set image grid SPINNER_ANIM_IMAGE, 1, 12
rem This is the image that the spinner objects will use.
create image SPINNER_IMAGE, width(SPINNER_ANIM_IMAGE), height
(SPINNER_ANIM_IMAGE)
rem ==================================================================
rem Load level. This function is prepared for more levels than the one
rem in this example.
rem ==================================================================
function LoadLevel(level)
rem Load map.
flags[][] = RC_LoadMap("rc_data/map3_" + str$(level) + ".txt")
if sizeof(flags) = 0 then return false
vEnemiesF[sizeof(flags, 0) - 1][6]
count = 0
for i = 1 to sizeof(flags, 0) - 1
rem Set type, x and z of enemy.
vEnemies[count][ENM_TYPE] = flags[i][RC_FLAG]
vEnemiesF[count][ENM_X] = float(flags[i][RC_X]) + 0.5
vEnemiesF[count][ENM_Z] = float(flags[i][RC_Z]) + 0.5
next
rem Player.
vPlayerX# = float(flags[0][RC_X]) + 0.5
vPlayerZ# = float(flags[0][RC_Z]) + 0.5
vPlayerAngle# = float(flags[0][RC_ANGLE])
return true
endfunc
rem ==================================================================
rem In this procedure, we update all the small things that don't quite
rem deserve their own sub routines.
rem ==================================================================
procedure UpdateStuff()
rem Update cross anim.
if vCrossFrameCounter = 0
vCrossFrame = (vCrossFrame + 1)%12
dst = RC_GetImage(8)
set image dst
set color 255, 255, 255
draw image CROSS_ANIM_IMAGE, 0, 0, vCrossFrame
set image primary
endif
vCrossFrameCounter = (vCrossFrameCounter + 1)%5
endproc
rem ==================================================================
rem Update player.
rem ==================================================================
procedure UpdatePlayer()
rem Strafe or rotate?
if keydown(VK_SHIFT)
if keydown(VK_LEFT)
pos#[] = RC_Move(0.3, vPlayerX, vPlayerZ, cos(vPlayerAngle - 90.0)*0.02, sin
(vPlayerAngle - 90.0)*0.02)
vPlayerX = pos[RC_X]
vPlayerZ = pos[RC_Z]
elseif keydown(VK_RIGHT)
pos#[] = RC_Move(0.3, vPlayerX, vPlayerZ, cos(vPlayerAngle + 90.0)*0.02, sin
(vPlayerAngle + 90.0)*0.02)
vPlayerX = pos[RC_X]
vPlayerZ = pos[RC_Z]
endif
else
if keydown(VK_LEFT) then vPlayerAngle = vPlayerAngle - 2.0
if keydown(VK_RIGHT) then vPlayerAngle = vPlayerAngle + 2.0
endif
rem Move.
if keydown(VK_UP)
pos#[] = RC_Move(0.3, vPlayerX, vPlayerZ, cos(vPlayerAngle)*0.04, sin(vPlayerAngle)
*0.04)
vPlayerX = pos[RC_X]
vPlayerZ = pos[RC_Z]
endif
if keydown(VK_DOWN)
pos#[] = RC_Move(0.3, vPlayerX, vPlayerZ, -cos(vPlayerAngle)*0.04, -sin(vPlayerAngle)
*0.04)
vPlayerX = pos[RC_X]
vPlayerZ = pos[RC_Z]
endif
rem Open doors.
if keydown(VK_SPACE, true)
facingPos[] = RC_FacingPos(vPlayerX, vPlayerZ, vPlayerAngle)
if RC_GetDoor(facingPos[RC_X], facingPos[RC_Z])
proc RC_OpenDoor facingPos[RC_X], facingPos[RC_Z]
endif
endif
rem Shoot.
if keydown(VK_CTRL) and vPlayerBulletTimer = 0
dx# = cos(vPlayerAngle)
dz# = sin(vPlayerAngle)
proc AddBullet 1, vPlayerX + dx*0.25, vPlayerZ + dz*0.25, 0.4, dx*0.2, dz*0.2
vPlayerBulletTimer = 25
endif
vPlayerBulletTimer = max(vPlayerBulletTimer - 1, 0)
rem ==================================================================
rem Decrease the player's stamina.
rem ==================================================================
procedure PlayerHit(damage)
rem Use the alpha of the screen flash to determine if the player
rem should be hit.
if vFlashAlpha < 32
vPlayerStamina = max(vPlayerStamina - damage, 0)
rem Flash screen in red.
vFlashAlpha = 128
vFlashR = 255
vFlashG = 0
vFlashB = 0
endif
endproc
rem ==================================================================
rem Add a bullet. type should be 1 for player bullets and 2 for enemy
rem bullets.
rem ==================================================================
procedure AddBullet(type, x#, z#, y#, dx#, dz#)
rem Find empty bullet index.
index = -1
for i = 0 to MAX_BULLETS - 1
if vBullets[i][BULLET_TYPE] = 0
index = i
break
endif
next
if index >= 0
rem Set values.
y = y - 0.05
vBullets[index][BULLET_TYPE] = type
vBulletsF[index][BULLET_X] = x
vBulletsF[index][BULLET_Z] = z
vBulletsF[index][BULLET_Y] = y
vBulletsF[index][BULLET_DX] = dx
vBulletsF[index][BULLET_DZ] = dz
rem Add objects.
if type = 1
proc RC_AddObject index + 1000, PLAYER_BULLET_IMAGE, x, z, y, 0.1, 0, 0
elseif type = 2
proc RC_AddObject index + 1000, ENEMY_BULLET_IMAGE, x, z, y, 0.1, 0, 0
endif
endif
endproc
rem ==================================================================
rem Update bullets.
rem ==================================================================
procedure UpdateBullets()
for i = 0 to MAX_BULLETS - 1
type = vBullets[i][BULLET_TYPE]
if type > 0
rem Move bullet.
vBulletsF[i][BULLET_X] = vBulletsF[i][BULLET_X] + vBulletsF[i][BULLET_DX]
vBulletsF[i][BULLET_Z] = vBulletsF[i][BULLET_Z] + vBulletsF[i][BULLET_DZ]
rem Remove bullet if it has hit an obstacle.
x = int(vBulletsF[i][BULLET_X])
z = int(vBulletsF[i][BULLET_Z])
if RC_ObstacleAt(x, z)
rem Blow up tin?
if RC_GetItem(x, z) = 1
proc RC_RemoveItem x, z
proc AddExplosion float(x) + 0.5, float(z) + 0.5, 0.0
endif
vBullets[i][BULLET_TYPE] = 0
rem ==================================================================
rem Bullet collision. This function returns true if a bullet of the
rem specified type is close enough to the position x, z. If so, the
rem bullet is also removed.
rem ==================================================================
function BulletCollision(type, x#, z#, size#)
size = size*size
index = -1
for i = 0 to MAX_BULLETS - 1
if vBullets[i][BULLET_TYPE] = type
dx# = x - vBulletsF[i][BULLET_X]
dz# = z - vBulletsF[i][BULLET_Z]
if dx*dx + dz*dz < size
index = i
break
endif
endif
next
if index >= 0
vBullets[index][BULLET_TYPE] = 0
proc RC_RemoveObject index + 1000
return true
endif
return false
endproc
rem ==================================================================
rem Add an explosion at x, z, y.
rem ==================================================================
procedure AddExplosion(x#, z#, y#)
rem Find empty explosion index.
index = -1
for i = 0 to MAX_EXPLOSIONS - 1
if vExplosions[i] = 0
index = i
break
endif
next
if index >= 0
rem Start with the first explosion image.
vExplosions[i] = EXPLOSION_IMAGE_0
proc RC_AddObject index + 2000, vExplosions[i], x, z, y, 0.75, 0, 0
endif
endproc
rem ==================================================================
rem Update explosions.
rem ==================================================================
procedure UpdateExplosions()
vExplosionFrameCounter = (vExplosionFrameCounter + 1)%3
if vExplosionFrameCounter = 0
for i = 0 to MAX_EXPLOSIONS - 1
if vExplosions[i]
rem Time for a new frame.
vExplosions[i] = vExplosions[i] + 1
rem If we've passed the last image, the animation has
rem finished and the object should be removed.
if vExplosions[i] > EXPLOSION_IMAGE_9
vExplosions[i] = 0
proc RC_RemoveObject i + 2000
else
proc RC_SetObjectImage i + 2000, vExplosions[i]
endif
endif
next
endif
endproc
rem ==================================================================
rem Update enemies.
rem ==================================================================
procedure UpdateEnemies()
set color 255, 255, 255
rem Update all enemies. Every enemy type has its own update
rem sub routine.
s = sizeof(vEnemies, 0) - 1
for i = 0 to s
type = vEnemies[i][ENM_TYPE]
if type = 1
proc UpdateXSpinner i
elseif type = 2
proc UpdateZSpinner i
elseif type = 3
proc UpdateFlybot i
endif
next
endproc
rem ==================================================================
rem Update spinner.
rem ==================================================================
procedure UpdateXSpinner(index)
rem Move.
pos#[] = RC_Move(0.3, vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z], vEnemiesF
[index][ENM_DX], vEnemiesF[index][ENM_DZ])
vEnemiesF[index][ENM_X] = pos[RC_X]
vEnemiesF[index][ENM_Z] = pos[RC_Z]
rem Get some information about the collision.
collisionInfo[] = RC_GetCollisionInfo()
rem If the enemy has hit a west or an east wall, it should change
rem direction.
if collisionInfo[RC_WEST] or collisionInfo[RC_EAST]
vEnemiesF[index][ENM_DX] = -vEnemiesF[index][ENM_DX]
endif
rem Update object.
proc RC_ModifyObject index + 1, SPINNER_IMAGE, vEnemiesF[index][ENM_X], vEnemiesF
[index][ENM_Z], vEnemiesF[index][ENM_Y]
rem ==================================================================
rem Update spinner.
rem ==================================================================
procedure UpdateZSpinner(index)
pos#[] = RC_Move(0.3, vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z], vEnemiesF
[index][ENM_DX], vEnemiesF[index][ENM_DZ])
vEnemiesF[index][ENM_X] = pos[RC_X]
vEnemiesF[index][ENM_Z] = pos[RC_Z]
collisionInfo[] = RC_GetCollisionInfo()
if collisionInfo[RC_NORTH] or collisionInfo[RC_SOUTH]
vEnemiesF[index][ENM_DZ] = -vEnemiesF[index][ENM_DZ]
endif
proc RC_ModifyObject index + 1, SPINNER_IMAGE, vEnemiesF[index][ENM_X], vEnemiesF
[index][ENM_Z], vEnemiesF[index][ENM_Y]
rem ==================================================================
rem Update flybot.
rem ==================================================================
procedure UpdateFlybot(index)
rem Only move if player is close and visible to this flybot.
rem Shoot.
vEnemies[index][ENM_TIMER] = (vEnemies[index][ENM_TIMER] + 1)%60
if vEnemies[index][ENM_TIMER] = 0
proc AddBullet 2, vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z], 0.6,
dx*0.08, dz*0.08
endif
rem Move.
rem Let the speed be modified by the ENM_EXTRA field. This
rem way we can make the enemy bounce backwards when it hits
rem the player or gets hit by a bullet.
dx = dx*0.05*vEnemiesF[index][ENM_EXTRA]
dz = dz*0.05*vEnemiesF[index][ENM_EXTRA]
pos#[] = RC_Move(0.25, vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z], dx,
dz
vEnemiesF[index][ENM_X] = pos[RC_X]
vEnemiesF[index][ENM_Z] = pos[RC_Z]
ex_raycasting4
Click in the window when the applet has loaded. Use the arrow keys to move around and open doors
with the space bar. Pick up golden crosses to make the screen flash (what an amazing award!).
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/raycasting4.html1/6/2012 2:35:57 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_raycasting4.txt
rem ==================================================================
rem Raycaster Library - Example 4.
rem
rem In the third raycasting example, we add some enemies and bullets.
rem Shoot with ctrl and strafe by holding down shift. The game ends
rem when the player's stamina is 0 or all golden crosses have been
rem collected.
rem
rem By Marcus.
rem ==================================================================
constant:
rem Images.
CROSS_ANIM_IMAGE 0
SPINNER_ANIM_IMAGE 1
SPINNER_IMAGE 2
FLYBOT_ANIM_IMAGE 3
FLYBOT_IMAGE 4
SHOOTBOT_ANIM_IMAGE 5
SHOOTBOT_IMAGE 6
PLAYER_BULLET_IMAGE 7
ENEMY_BULLET_IMAGE 8
EXPLOSION_IMAGE_0 9
EXPLOSION_IMAGE_1 10
EXPLOSION_IMAGE_2 11
EXPLOSION_IMAGE_3 12
EXPLOSION_IMAGE_4 13
EXPLOSION_IMAGE_5 14
EXPLOSION_IMAGE_6 15
EXPLOSION_IMAGE_7 16
EXPLOSION_IMAGE_8 17
EXPLOSION_IMAGE_9 18
CROSS_ICON_IMAGE 19
AIM_IMAGE 20
MAP_IMAGE 21
LOGO_IMAGE 22
LOGO_BG_IMAGE 23
HELP_IMAGE 24
TRANSITION_IMAGE 25
rem Music.
TITLE_MUSIC 0
GAME_MUSIC 1
visible:
rem Level names.
vLevelNames$[] = ["Area 1 - Getting Started", "Area 2 - More Robots", "Area 3 - Nasty Cannons",
"Area 4 - Lights Out"]
rem Player.
vLevel
vPlayerAngle#
vPlayerX#
vPlayerZ#
vPlayerStamina
vPlayerBulletTimer
rem Enemies.
vEnemies[][]
vEnemiesF#[][]
rem Bullets.
vBullets[MAX_BULLETS][1]
vBulletsF#[MAX_BULLETS][6]
rem Explosions
vExplosions[MAX_EXPLOSIONS]
vExplosionFrameCounter
vCrossFrameCounter = 0
vCrossFrame = 0
hidden:
proc Load
do
proc Title
do
if not LoadLevel(vLevel) then proc QuitGame
play music GAME_MUSIC
levelNameAlpha = 255
proc UpdateStuff
proc UpdateExplosions
proc UpdatePlayer
proc UpdateBullets
proc UpdateEnemies
if vFlashAlpha > 0
set color vFlashR, vFlashG, vFlashB, vFlashAlpha
cls
endif
x = width(primary) - width(MAP_IMAGE) - 5
y = height(primary) - height(MAP_IMAGE) -5
set color 255, 255, 255, 128
draw image MAP_IMAGE, x, y
set color 255, 255, 0, 255
draw rect x + int(vPlayerX*5.0) - 1, y + int(vPlayerZ*5.0) - 1, 3, 3, true
if levelNameAlpha > 0
levelNameAlpha = max(levelNameAlpha - 2, 0)
set caret width(primary)/2, 160
set color 255, 0, 0, levelNameAlpha
center vLevelNames[vLevel - 1]
endif
redraw
if vCrossCount = vCrossesPicked
proc FadeOut 0, 0, 0, 10
vLevel = vLevel + 1
else
proc FadeOut 255, 0, 0, 10
proc FadeOut 0, 0, 0, 10
break
endif
loop
loop
rem ==================================================================
rem Load graphics, music and sound.
rem ==================================================================
procedure Load()
rem Load a font.
if javac()
load font 0, "rc_data/meiryo24.txt", "rc_data/meiryo24.png"
else
load font 0, "rc_data/meiryo24.txt", "rc_data/meiryo24.bmp"
endif
set color 0, 0, 0
cls
set color 255, 255, 255
set caret width(primary)/2, 160
center "Loading ..."
redraw
rem The spinner enemy (and the flybot) uses the same sort of
rem animation as the golden cross: we blit the animation from an
if javac()
load image CROSS_ICON_IMAGE, "rc_data/cross_icon.png"
else
endif
rem Music.
if javac()
load music GAME_MUSIC, "rc_data/bgmusic.wav"
load music TITLE_MUSIC, "rc_data/title.wav"
else
load music GAME_MUSIC, "rc_data/bgmusic.mp3"
load music TITLE_MUSIC, "rc_data/title.mp3"
endif
rem ==================================================================
rem Load level. This function is prepared for more levels than the one
rem in this example.
rem ==================================================================
function LoadLevel(level)
rem Load map.
flags[][] = RC_LoadMap("rc_data/map4_" + str$(level) + ".txt")
if sizeof(flags) = 0 then return false
rem Player.
vPlayerX# = float(flags[0][RC_X]) + 0.5
vPlayerZ# = float(flags[0][RC_Z]) + 0.5
vPlayerAngle# = float(flags[0][RC_ANGLE]) + 0.5
vPlayerStamina = min(vPlayerStamina + 50, 100)
vFlashAlpha = 0
set color 0, 0, 0
cls
set caret width(primary)/2, 160
set color 255, 0, 0
center vLevelNames[vLevel - 1]
redraw
wait 1000
return true
endfunc
rem ==================================================================
rem In this procedure, we update all the small things that don't quite
rem deserve their own sub routines.
rem ==================================================================
procedure UpdateStuff()
rem Update cross anim.
if vCrossFrameCounter = 0
vCrossFrame = (vCrossFrame + 1)%12
dst = RC_GetImage(8)
set image dst
set color 255, 255, 255
draw image CROSS_ANIM_IMAGE, 0, 0, vCrossFrame
rem ==================================================================
rem Update player.
rem ==================================================================
procedure UpdatePlayer()
rem Strafe or rotate?
if keydown("Z")
if keydown(VK_LEFT)
pos#[] = RC_Move(0.3, vPlayerX, vPlayerZ, cos(vPlayerAngle - 90.0)*0.04, sin
(vPlayerAngle - 90.0)*0.04)
vPlayerX = pos[RC_X]
vPlayerZ = pos[RC_Z]
elseif keydown(VK_RIGHT)
pos#[] = RC_Move(0.3, vPlayerX, vPlayerZ, cos(vPlayerAngle + 90.0)*0.04, sin
(vPlayerAngle + 90.0)*0.04)
vPlayerX = pos[RC_X]
vPlayerZ = pos[RC_Z]
endif
else
if keydown(VK_LEFT) then vPlayerAngle = vPlayerAngle - 2.0
if keydown(VK_RIGHT) then vPlayerAngle = vPlayerAngle + 2.0
endif
rem Move.
if keydown(VK_UP)
pos#[] = RC_Move(0.3, vPlayerX, vPlayerZ, cos(vPlayerAngle)*0.04, sin(vPlayerAngle)
*0.04)
vPlayerX = pos[RC_X]
vPlayerZ = pos[RC_Z]
endif
if keydown(VK_DOWN)
pos#[] = RC_Move(0.3, vPlayerX, vPlayerZ, -cos(vPlayerAngle)*0.04, -sin(vPlayerAngle)
*0.04)
vPlayerX = pos[RC_X]
vPlayerZ = pos[RC_Z]
endif
rem Open doors.
if keydown(VK_SPACE, true)
facingPos[] = RC_FacingPos(vPlayerX, vPlayerZ, vPlayerAngle)
if RC_GetDoor(facingPos[RC_X], facingPos[RC_Z])
rem ==================================================================
rem Decrease the player's stamina.
rem ==================================================================
procedure PlayerHit(damage)
rem Use the alpha of the screen flash to determine if the player
rem should be hit.
if vFlashAlpha < 32
vPlayerStamina = max(vPlayerStamina - damage, 0)
rem Flash screen in red.
vFlashAlpha = 128
vFlashR = 255
vFlashG = 0
vFlashB = 0
play sound PLAYER_HIT_SOUND
endif
endproc
rem ==================================================================
rem Add a bullet. type should be 1 for player bullets and 2 for enemy
rem bullets.
rem ==================================================================
procedure AddBullet(type, x#, z#, y#, dx#, dz#)
rem Find empty bullet index.
index = -1
for i = 0 to MAX_BULLETS - 1
if vBullets[i][BULLET_TYPE] = 0
index = i
break
endif
next
if index >= 0
rem Set values.
y = y - 0.05
vBullets[index][BULLET_TYPE] = type
vBulletsF[index][BULLET_X] = x
vBulletsF[index][BULLET_Z] = z
vBulletsF[index][BULLET_Y] = y
vBulletsF[index][BULLET_DX] = dx
vBulletsF[index][BULLET_DZ] = dz
rem Add objects.
if type = 1
play sound PLAYER_BULLET_SOUND
proc RC_AddObject index + 1000, PLAYER_BULLET_IMAGE, x, z, y, 0.1, 0, 0
elseif type = 2
play sound ENEMY_BULLET_SOUND
proc RC_AddObject index + 1000, ENEMY_BULLET_IMAGE, x, z, y, 0.1, 0, 0
endif
endif
endproc
rem ==================================================================
rem Update bullets.
rem ==================================================================
procedure UpdateBullets()
for i = 0 to MAX_BULLETS - 1
type = vBullets[i][BULLET_TYPE]
if type > 0
rem Move bullet.
vBulletsF[i][BULLET_X] = vBulletsF[i][BULLET_X] + vBulletsF[i][BULLET_DX]
vBulletsF[i][BULLET_Z] = vBulletsF[i][BULLET_Z] + vBulletsF[i][BULLET_DZ]
rem Remove bullet if it has hit an obstacle.
x = int(vBulletsF[i][BULLET_X])
z = int(vBulletsF[i][BULLET_Z])
if RC_ObstacleAt(x, z)
rem Blow up tin?
if RC_GetItem(x, z) = 1
proc RC_RemoveItem x, z
proc AddExplosion float(x) + 0.5, float(z) + 0.5, 0.0
play sound TIN_EXPLODE_SOUND
endif
vBullets[i][BULLET_TYPE] = 0
proc RC_RemoveObject i + 1000
else
rem Update object.
if type = 1
proc RC_ModifyObject i + 1000, PLAYER_BULLET_IMAGE, vBulletsF[i]
[BULLET_X], vBulletsF[i][BULLET_Z], vBulletsF[i][BULLET_Y]
elseif type = 2
proc RC_ModifyObject i + 1000, ENEMY_BULLET_IMAGE, vBulletsF[i]
[BULLET_X], vBulletsF[i][BULLET_Z], vBulletsF[i][BULLET_Y]
endif
endif
endif
next
endproc
rem ==================================================================
rem Bullet collision. This function returns true if a bullet of the
rem specified type is close enough to the position x, z. If so, the
rem bullet is also removed.
rem ==================================================================
function BulletCollision(type, x#, z#, size#)
size = size*size
index = -1
for i = 0 to MAX_BULLETS - 1
if vBullets[i][BULLET_TYPE] = type
dx# = x - vBulletsF[i][BULLET_X]
dz# = z - vBulletsF[i][BULLET_Z]
if dx*dx + dz*dz < size
index = i
break
endif
endif
next
if index >= 0
vBullets[index][BULLET_TYPE] = 0
proc RC_RemoveObject index + 1000
return true
endif
return false
endproc
rem ==================================================================
rem Add an explosion at x, z, y.
rem ==================================================================
procedure AddExplosion(x#, z#, y#)
rem Find empty explosion index.
index = -1
for i = 0 to MAX_EXPLOSIONS - 1
if vExplosions[i] = 0
index = i
break
endif
next
if index >= 0
rem Start with the first explosion image.
vExplosions[i] = EXPLOSION_IMAGE_0
proc RC_AddObject index + 2000, vExplosions[i], x, z, y, 0.75, 0, 0
endif
endproc
rem ==================================================================
rem Update explosions.
rem ==================================================================
procedure UpdateExplosions()
vExplosionFrameCounter = (vExplosionFrameCounter + 1)%3
if vExplosionFrameCounter = 0
for i = 0 to MAX_EXPLOSIONS - 1
if vExplosions[i]
rem ==================================================================
rem Update enemies.
rem ==================================================================
procedure UpdateEnemies()
set color 255, 255, 255
endif
rem Update all enemies. Every enemy type has its own update
rem sub routine.
s = sizeof(vEnemies, 0) - 1
for i = 0 to s
type = vEnemies[i][ENM_TYPE]
if type = 1
proc UpdateXSpinner i
elseif type = 2
proc UpdateZSpinner i
elseif type = 3
proc UpdateFlybot i
elseif type = 4
proc UpdateShootbot i
endif
next
endproc
rem ==================================================================
rem Update spinner.
rem ==================================================================
procedure UpdateXSpinner(index)
rem Move.
pos#[] = RC_Move(0.3, vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z], vEnemiesF
[index][ENM_DX], vEnemiesF[index][ENM_DZ])
vEnemiesF[index][ENM_X] = pos[RC_X]
vEnemiesF[index][ENM_Z] = pos[RC_Z]
rem Get some information about the collision.
collisionInfo[] = RC_GetCollisionInfo()
rem If the enemy has hit a west or an east wall, it should change
rem direction.
if collisionInfo[RC_WEST] or collisionInfo[RC_EAST]
vEnemiesF[index][ENM_DX] = -vEnemiesF[index][ENM_DX]
endif
rem Update object.
proc RC_ModifyObject index + 1, SPINNER_IMAGE, vEnemiesF[index][ENM_X], vEnemiesF
[index][ENM_Z], vEnemiesF[index][ENM_Y]
rem ==================================================================
rem Update spinner.
rem ==================================================================
procedure UpdateZSpinner(index)
pos#[] = RC_Move(0.3, vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z], vEnemiesF
[index][ENM_DX], vEnemiesF[index][ENM_DZ])
vEnemiesF[index][ENM_X] = pos[RC_X]
vEnemiesF[index][ENM_Z] = pos[RC_Z]
collisionInfo[] = RC_GetCollisionInfo()
if collisionInfo[RC_NORTH] or collisionInfo[RC_SOUTH]
vEnemiesF[index][ENM_DZ] = -vEnemiesF[index][ENM_DZ]
endif
proc RC_ModifyObject index + 1, SPINNER_IMAGE, vEnemiesF[index][ENM_X], vEnemiesF
[index][ENM_Z], vEnemiesF[index][ENM_Y]
rem ==================================================================
rem Update flybot.
rem ==================================================================
procedure UpdateFlybot(index)
rem Only move if player is close and visible to this flybot.
dx# = vPlayerX - vEnemiesF[index][ENM_X]
dz# = vPlayerZ - vEnemiesF[index][ENM_Z]
d# = dx*dx + dz*dz
if d < 64.0
vis = RC_Visible(vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z], vPlayerX,
vPlayerZ)
if vEnemies[index][ENM_STATE] = off
vEnemies[index][ENM_STATE] = vis
else
d = sqr(d)
k# = 1.0/d
dx = dx*k
dz = dz*k
rem Shoot.
if vis
vEnemies[index][ENM_TIMER] = (vEnemies[index][ENM_TIMER] + 1)%60
if vEnemies[index][ENM_TIMER] = 0
proc AddBullet 2, vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z],
0.6, dx*0.08, dz*0.08
endif
endif
rem Move.
rem Let the speed be modified by the ENM_EXTRA field. This
rem way we can make the enemy bounce backwards when it hits
rem the player or gets hit by a bullet.
dx = dx*0.05*vEnemiesF[index][ENM_EXTRA]
dz = dz*0.05*vEnemiesF[index][ENM_EXTRA]
pos#[] = RC_Move(0.25, vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z], dx,
dz
vEnemiesF[index][ENM_X] = pos[RC_X]
vEnemiesF[index][ENM_Z] = pos[RC_Z]
procedure UpdateShootbot(index)
rem Only move if player is close and visible to this flybot.
dx# = vPlayerX - vEnemiesF[index][ENM_X]
dz# = vPlayerZ - vEnemiesF[index][ENM_Z]
d# = dx*dx + dz*dz
if d < 64.0
if RC_Visible(vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z], vPlayerX, vPlayerZ)
d = sqr(d)
k# = 1.0/d
dx = dx*k
dz = dz*k
rem Shoot.
vEnemies[index][ENM_TIMER] = (vEnemies[index][ENM_TIMER] + 1)%80
if vEnemies[index][ENM_TIMER] = 0
proc AddBullet 2, vEnemiesF[index][ENM_X], vEnemiesF[index][ENM_Z], 0.38,
dx*0.08, dz*0.08
endif
else
play sound ENEMY_HIT_SOUND
endif
endif
endproc
procedure Title()
a# = 0.0
option = 0
showInstructions = false
fade = 255
play music TITLE_MUSIC
do
if not running() then proc QuitGame
if showInstructions
if keydown(VK_ESC, true) or keydown(VK_SPACE, true) or keydown(VK_ENTER,
true)
showInstructions = false
endif
else
rem Move up and down in menu.
if keydown(VK_DOWN, true) and option < 2 then option = option + 1
if keydown(VK_UP, true) and option > 0 then option = option - 1
if keydown(VK_ENTER, true) or keydown(VK_SPACE, true)
if option = 0
break
elseif option = 1
showInstructions = true
else
proc QuitGame
endif
endif
endif
set color 0, 0, 0
cls
rem Draw a cool cloud behind the logo using the hraster command.
set color 255, 255, 255, 0
w = width(LOGO_BG_IMAGE)
h = height(LOGO_BG_IMAGE)
x = (512 - w)/2
y = (384 - h)/2 - 72
vstep# = 1.0/float(h)
v# = 0.0
a = a + 2.0
for i = 0 to h - 1
draw hraster LOGO_BG_IMAGE, y + i, x + int(sin(float(i)*4.0 + a)*16.0), x + w - int
(sin(float(i)*4.0 + a)*16.0), 0.0, v, 1.0, v
v = v + vstep
next
if showInstructions
set caret 256, 172
set color 255, 255, 0
center "INSTRUCTIONS"
center
set color 255, 255, 255
center "Find all Golden Crosses to finish a level."
center "Use arrow keys to walk and turn."
center "Hold down 'Z' to strafe."
center "Open doors with space and shoot with 'X'."
else
rem Draw menu.
set caret 256, 172
set color 32, 96, 128
center "A NaaLaa 5 Example Game"
set caret 256, 216
if option = 0; set color 255, 255, 0; else; set color 255, 255, 255; endif
center "Start Game"
if option = 1; set color 255, 255, 0; else; set color 255, 255, 255; endif
center "Instructions"
if option = 2; set color 255, 255, 0; else; set color 255, 255, 255; endif
center "Quit"
rem Show some good links.
set caret 256, 300
set color 32, 96, 128
center "http://forum.retrogamecoding.org"
center "http://www.naalaa.com"
endif
redraw
proc SPD_HoldFrame 60
loop
proc FadeOut 0, 0, 0, 10
stop music TITLE_MUSIC
vLevel = 1
vPlayerStamina = 100
endproc
rem ==================================================================
rem Fade out.
rem ==================================================================
procedure FadeOut(r, g, b, speed)
set image TRANSITION_IMAGE
set color 255, 255, 255
draw image primary, 0, 0
set image primary
alpha = 0
do
alpha = min(alpha + speed, 255)
set color 255, 255, 255
draw image TRANSITION_IMAGE, 0, 0
set color r, g, b, alpha
draw rect 0, 0, width(primary), height(primary), true
redraw
proc SPD_HoldFrame 60
until alpha = 255
endproc
rem ==================================================================
rem Terminate game. Show a message if it's a java applet.
rem ==================================================================
procedure QuitGame()
stop music TITLE_MUSIC
stop music GAME_MUSIC
set mouse on
set color 0, 0, 0
cls
set color 32, 96, 128
set caret width(primary)/2, 160
center "Thanks for playing!"
redraw
wait 1000
end
endproc
[ Go back ]
Introduction
There was a graphics mode on SNES (Super Nintendo) called Mode 7. With it, it was possible to create
a simple 3D view and many other things. The most famous games using it are probably Super Mario
Kart and F-Zero. With the NaaLaa library you can create games like those two but not much more - the
library is quite limited.
Details
The Mode 7 library is actually an extended subset of the Raycaster library. It's basicly a "floor renderer".
You can use the RC_Editor program to create your game maps, but the wall and ceiling layers are
ignored. The library does not provide any collision handling, but some of the examples below show you
some rather simple techniques.
Examples
ex_mode7_1
ex_mode7_2
ex_mode7_3
ex_mode7_bonus
Sub routines
procedure M7_Init(w, h, z_max#)
function M7_LoadMap[][](filename$)
procedure M7_Render(view_x#, view_z#, view_y#, view_angle#, horizon, fov#)
procedure M7_AddObject(obj_id, img_id, x#, z#, y#, size#, cel, item_x, item_z)
procedure M7_ModifyObject(obj_id, img_id, x#, z#, y#, size#, cel)
procedure M7_RemoveObject(obj_id)
function M7_HasObject(obj_id)
procedure M7_SetFloor(x, z, img_id)
function M7_GetFloor(x, z)
function M7_GetFloorImage(x, z)
procedure M7_SetFlag(x, z, flag)
function M7_GetFlag(x, z)
function M7_GetFlagPos[](flag)
procedure M7_SetItem(x, z, item)
function M7_GetItem(x, z)
procedure M7_RemoveItem(x, z)
function M7_GetImage(img_index)
function M7_GetMapWidth()
function M7_GetMapHeight()
procedure M7_InitMap(w, h)
procedure M7_SetFog(r, g, b, z_min#, z_max#)
You need to call this procedure before calling any other sub routine of the library. w and h should be set
to the width and height of the image that the view is to be rendered to (usually the primary image).
z_max# is the far clip plane.
Back to top
function M7_LoadMap[][](filename$)
Load a map created with RC_Editor. The function returns an integer array containing the player's
starting position and angle, and all the loader flags that has been set in the editor. If the array is empty,
the map could not be loaded. You find the player's starting position and angle at index 0 of the array.
The rest of the array contains the loader flags. Example:
#import "Mode7.lib"
flags[][] = M7_LoadMap("my_map.txt")
if sizeof(flags) = 0 then end
rem Set player position and angle.
playerX = float(flags[0][M7_X]) + 0.5
playerZ = float(flags[0][M7_Z]) + 0.5
playerAngle = float(flags[0][M7_ANGLE])
rem Do something with the rest of the flags, like setting up enemies.
for i = 1 to sizeof(flags, 0) - 1
wln "x = ", flags[i][M7_X], ", z = ", flags[i][M7_Z], ", flag = ",
flags[i][M7_FLAG]
next
Back to top
Render view from the position view_x#, view_z#, view_y# looking in the direction view_angle#
(degrees). y_view# is measured from the ground and up. horizon is an offset allowing you to do a fake
tilt of the view by moving the horizon line. It's measured in pixels. Setting it to -32 will move the
horizon 32 pixels up from the vertical center of the screen. fov# is the field of view (degrees).
Back to top
Add an object with the id obj_id to the world. The object will use the image with the id img_id. If the
image has a grid s you can use cel to select an individual cel (else set it to 1). x#, z#, y# is the position of
the object. size is the size of the object's longest side (vertical or horizontal). If the object is to be
connected with the item layer, you should set item_x, item_z to the position of the item. If the item is
removed, the object will also be removed, and if the object is removed the item will also be removed. If
you do not wish to make such a connection, set item_x and item_z to -1.
Back to top
Back to top
procedure M7_RemoveObject(obj_id)
Remove object obj_id. If the object is connected to an item, that item will also be removed.
Back to top
function M7_HasObject(obj_id)
Back to top
Back to top
function M7_GetFloor(x, z)
This function only makes sense if you're using the RC_Editor. Return the index of the floor image at x,
z.
Back to top
function M7_GetFloorImage(x, z)
Back to top
Back to top
function M7_GetFlag(x, z)
Return flag at x, z.
Back to top
function M7_GetFlagPos[](flag)
Back to top
Set item at x, z to item. This only sets an integer, like a flag. But you can create a connection between an
item and a visual object by using this procedure and M7_AddObject. This is automatically done for
items added in the RC_Editor.
Back to top
function M7_GetItem(x, z)
Return item at x, z.
Back to top
procedure M7_RemoveItem(x, z)
Back to top
function M7_GetImage(img_index)
This function only makes sense if you're using the RC_Editor. Return the id of the image at index
img_index.
Back to top
function M7_GetMapWidth()
Back to top
function M7_GetMapHeight()
Back to top
procedure M7_InitMap(w, h)
Init map to size w*h. This also clears all objects and flags.
Back to top
Set the fog color to r, g, b (RGB). The fog will start at the distance z_min# and end (be fully opaque) at
z_max#. The far clip plane will also be set to z_max#.
Back to top
[ Go back ]
ex_mode7_1
Click in the window when the applet has loaded. Use the arrow keys to move around.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/mode7_1.html1/6/2012 2:35:59 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_mode7_1.txt
rem ==================================================================
rem Mode 7 - Example 1.
rem
rem In this example, we load a map created with the RC_Editor and let
rem the player move around.
rem
rem By Marcus.
rem ==================================================================
ex_mode7_2
Click in the window when the applet has loaded. Use the arrow keys to move around.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/mode7_2.html1/6/2012 2:35:59 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_mode7_2.txt
rem ==================================================================
rem Mode 7 - Example 2.
rem
rem In this example we add a visual object for the player, improve the
rem controls and add a camera.
rem
rem By Marcus.
rem ==================================================================
constant:
rem Constants for images.
SIGN_POST_IMAGE 0
COIN_IMAGE 1
CRAFT_IMAGE 2
rem Objects.
PLAYER_OBJ 1
visible:
rem Player.
vPlayerX#
vPlayerZ#
vPlayerY#
vPlayerAngle#
vPlayerDX#
vPlayerDZ#
vPlayerSpeed#
rem Camera.
vCamX#
vCamZ#
vCamY#
vCamAngle#
vCamHorizon#
rem Animation.
vAnimTimer
vPostFrame
vCoinFrame
hidden:
rem ==================================================================
rem Update animations.
rem ==================================================================
procedure UpdateAnims()
rem Every time animTimer is 0 we update the animations.
vAnimTimer = (vAnimTimer + 1)%4
rem ==================================================================
rem Update player.
rem ==================================================================
procedure UpdatePlayer()
rem Rotate with left and right arrow keys.
if keydown(VK_LEFT) then vPlayerAngle = vPlayerAngle - 4.0
if keydown(VK_RIGHT) then vPlayerAngle = vPlayerAngle + 4.0
if vPlayerAngle >= 360.0 then vPlayerAngle = vPlayerAngle - 360.0
if vPlayerAngle < 0.0 then vPlayerAngle = vPlayerAngle + 360.0
rem Move.
vPlayerX = vPlayerX + vPlayerDX*vPlayerSpeed*0.025
vPlayerZ = vPlayerZ + vPlayerDZ*vPlayerSpeed*0.025
rem Calculate view angle of craft and select the proper image
rem cel.
dx# = vPlayerX - vCamX
dz# = vPlayerZ - vCamZ
k# = 1.0/sqr(dx*dx + dz*dz)
dx = dx*k
dz = dz*k
if dz < 0.0
a# = 360.0 - acos(dx)
else
a# = acos(dx)
endif
a = a - vPlayerAngle + 7.5
if a >= 360.0 then a = a - 360.0
if a < 0.0 then a = a + 360.0
rem ==================================================================
rem Update camera.
rem ==================================================================
procedure UpdateCamera()
rem Move towards wanted position.
vCamX = 0.96*vCamX + 0.04*(vPlayerX - cos(vPlayerAngle)*0.4)
vCamZ = 0.96*vCamZ + 0.04*(vPlayerZ - sin(vPlayerAngle)*0.4)
ex_mode7_3
Click in the window when the applet has loaded. Use the arrow keys to move around. You can pick up
the green things for no reason.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/mode7_3.html1/6/2012 2:36:00 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_mode7_3.txt
rem ==================================================================
rem Mode 7 - Example 3.
rem
rem There's no collision detection/handling support in the mode 7
rem library. So in this example we import the AWR Collision library,
rem that deals with collisions in a world of rectangles. We also
rem allow the player to pick up the green coin thingies.
rem
rem By Marcus.
rem ==================================================================
constant:
rem Constants for images.
SIGN_POST_IMAGE 0
COIN_IMAGE 1
CRAFT_IMAGE 2
SKY_IMAGE 3
rem Objects.
PLAYER_OBJ 1
visible:
rem Player.
vPlayerX#
vPlayerZ#
vPlayerY#
vPlayerAngle#
vPlayerDX#
vPlayerDZ#
vPlayerSpeed#
rem Camera.
vCamX#
vCamZ#
vCamY#
vCamAngle#
vCamHorizon#
rem Animation.
vAnimTimer
vPostFrame
vCoinFrame
hidden:
vPlayerAngle = float(flags[0][M7_ANGLE])
vPlayerDX = cos(vPlayerAngle)
vPlayerDZ = sin(vPlayerAngle)
vPlayerSpeed = 0.0
rem Collision rectangles. Look at the awr library for more information
rem about how it works. I got the coordinates below by looking at the
rem map in the RC_Editor.
vRects[7][4]
vRects[0][0] = 0.0
vRects[0][1] = 0.0
vRects[0][2] = 16.0
vRects[0][3] = 1.5
vRects[1][0] = 0.0
vRects[1][1] = 0.0
vRects[1][2] = 1.5
vRects[1][3] = 16.0
vRects[2][0] = 0.0
vRects[2][1] = 14.5
vRects[2][2] = 16.0
vRects[2][3] = 1.5
vRects[3][0] = 14.5
vRects[3][1] = 0.0
vRects[3][2] = 1.5
vRects[3][3] = 16.0
vRects[4][0] = 8.5
vRects[4][1] = 0.0
vRects[4][2] = 7.5
vRects[4][3] = 3.5
vRects[5][0] = 0.0
vRects[5][1] = 5.5
vRects[5][2] = 3.5
vRects[5][3] = 3.0
vRects[6][0] = 3.5
vRects[6][1] = 12.5
vRects[6][2] = 3.0
vRects[6][3] = 3.5
rem ==================================================================
rem Update animations.
rem ==================================================================
procedure UpdateAnims()
rem Every time animTimer is 0 we update the animations.
vAnimTimer = (vAnimTimer + 1)%4
rem ==================================================================
rem Update player.
rem ==================================================================
procedure UpdatePlayer()
rem Rotate with left and right arrow keys.
if keydown(VK_LEFT) then vPlayerAngle = vPlayerAngle - 4.0
if keydown(VK_RIGHT) then vPlayerAngle = vPlayerAngle + 4.0
if vPlayerAngle >= 360.0 then vPlayerAngle = vPlayerAngle - 360.0
if vPlayerAngle < 0.0 then vPlayerAngle = vPlayerAngle + 360.0
rem Calculate view angle of craft and select the proper image
rem cel.
dx# = vPlayerX - vCamX
dz# = vPlayerZ - vCamZ
k# = 1.0/sqr(dx*dx + dz*dz)
dx = dx*k
dz = dz*k
if dz < 0.0
a# = 360.0 - acos(dx)
else
a# = acos(dx)
endif
a = a - vPlayerAngle + 7.5
if a >= 360.0 then a = a - 360.0
if a < 0.0 then a = a + 360.0
rem ==================================================================
rem Update camera.
rem ==================================================================
procedure UpdateCamera()
rem Move towards wanted position.
vCamX = 0.96*vCamX + 0.04*(vPlayerX - cos(vPlayerAngle)*0.4)
vCamZ = 0.96*vCamZ + 0.04*(vPlayerZ - sin(vPlayerAngle)*0.4)
dx = dx*k
dz = dz*k
if dz < 0.0
vCamAngle# = 360.0 - acos(dx)
else
vCamAngle# = acos(dx)
endif
ex_mode7_bonus
Now, where have we seen this before?..
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/mode7_bonus.html1/6/2012 2:36:00 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_mode7_bonus.txt
rem ==================================================================
rem Mode 7 - Bonus example.
rem
rem By Marcus.
rem ==================================================================
z# = 0.5
do
z = z + 0.008
set color 0, 0, 0
cls
proc M7_Render 0.5, z, 0.4, 270.0, -128, 70.0
redraw
proc SPD_HoldFrame 60
until z > 5.5 or keydown(27) or not running()
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_mode7_bonus.txt1/6/2012 2:36:00 AM
NaaLaa - Simple Widget Library
[ Go back ]
Introduction
The Simple Widget library can be used to create programs with a simple GUI. I wrote it because I
needed an easy way to create the game editors of NaaLaa 5. So don't expect to be able to create a word
processor or something like that with it.
import "SimpleWidget.lib"
do
event[] = SW_GetEvent()
if event[SW_EVENT] = SW_WINDOW_CLOSED_EVENT then end
loop
The first thing we do is to include the library. Next we init the library with a theme, create a window and
add a widget (a text label) to it. When we're setup we enter a loop where we call SW_GetEvent to get an
array of information about anything that has happened (button presses, mouse movements etc).
SW_GetEvent takes over the control of your program until the user does something interesting. When
you've got information about an event, you can take some action or just ignore it and wait for another
event. In the above example, we wait for the user to close down the window that we've added and then
shut down.
Examples
ex_simplewidget_1 - Hello world
ex_simplewidget_2 - Buttons and modal windows
ex_simplewidget_3 - Checkboxes and radio buttons
ex_simplewidget_4 - Menus
Sub routines
function SW_Init(theme$)
procedure SW_CreateWindow(win_id, title$, x, y, w, h, config$)
procedure SW_ChangeWindowTitle(win_id, title$)
procedure SW_ChangeWindowSize(win_id, w, h)
function SW_HasWindow(win_id)
procedure SW_DeleteWindow(win_id)
procedure SW_MoveToFront(win_id)
function SW_GetEvent[]()
procedure SW_CreateLabel(win_id, widget_id, txt$, x, y, centered)
procedure SW_CreateImage(win_id, widget_id, image_id, x, y)
procedure SW_CreateButton(win_id, widget_id, label$, x, y, w)
procedure SW_CreateImageButton(win_id, widget_id, img, cel, x, y)
procedure SW_CreateCheckbox(win_id, widget_id, x, y, checked)
procedure SW_SetChecked(win_id, widget_id, value)
function SW_Checked(win_id, widget_id)
procedure SW_CreateRadioButton(win_id, group_id, widget_id, x, y, selected) procedure SW_SetGroup
(win_id, widget_id, group_id)
procedure SW_SelectWidget(win_id, widget_id)
function SW_SelectedWidget(win_id, group_id)
procedure SW_CreateTextArea(win_id, widget_id, txt$, x, y, w, h)
procedure SW_CreateInput(win_id, widget_id, x, y, w, type)
procedure SW_DeleteWidget(win_id, widget_id)
procedure SW_SetLabel(win_id, widget_id, txt$)
function SW_GetLabel$(win_id, widget_id)
procedure SW_EnableWindowEvent(win_id, event)
procedure SW_DisableWindowEvent(win_id, event)
procedure SW_CreateMenu(win_id, menu$)
procedure SW_CreateDefaultMenu(menu$)
procedure SW_Redraw()
procedure SW_SetBGColor(r, g, b)
procedure SW_EnableTimer(delay)
function SW_Init(theme$)
Init library with the specified theme. A theme consists of three files: an image with the graphics for
windows and widgets, and a text file and an image for the font to be used. As an example, the "dark"
theme consists of the files dark.bmp (graphics image), dark_font.txt (font description file) and dark_font.
bmp (font image). There are only two standard themes, "dark" and "plain". They're located in "My
Documents\NaaLaa Examples\themes". If your program is located in "My Documents\NaaLaa
Examples, you'd write:
import "SimpleWidget.lib"
proc SW_Init "themes/dark"
, to init the library with the "dark" theme. If you have your program in another folder, you need to copy
the theme files to a folder that it can reach.
Back to top
Create a new window. win_id is a unique identifier for your window and should be set to a positive, non
zero, value. The id will be returned with SW_GetEvent to tell you in what window a certain event took
place. You'll also use it to get information about the window and its widgets. title is the name that will
be displayed on the window's top bar. x, y is the position of the window and w and h its width and
height. You can use config$ to change some properties of the window:
Flag Description
noclose Window should not have a close button.
nomin Window should not have a minimize button.
modal Window should be modal (keep focus until closed).
mouse Enable mouse events (see ...).
key Enable keyboard event (see ...).
Back to top
Back to top
procedure SW_ChangeWindowSize(win_id, w, h)
Back to top
function SW_HasWindow(win_id)
Back to top
procedure SW_DeleteWindow(win_id)
Delete a window.
Back to top
procedure SW_MoveToFront(win_id)
Back to top
function SW_GetEvent[]()
Leave control to the library and wait for an event to occur. The fields of the array that is returned can be
accessed with the following constants:
Most of these values will (probably) make better sense when the widgets are presented below.
Back to top
Create a label with the id widget_id in window win_id. The label will contain a single line of text, txt$,
and be placed at the window coordinates x, y. If centered is set to true, the text will be centered around
the x coordinate.
Back to top
Create an image with the id widget_id in window win_id. image_id is the id of the image (that you've
created or loaded). The image will be placed at the window coordinates x, y.
Back to top
Create a text button with the id widget_id in window win_id. label$ is the label that will be used, and the
button will bli placed at the window coordinates x, y. If w is anything larger than 0, it will be used as
width for the button, else the width is automatically adjusted.
When a button has been clicked on, you will get an SW_BUTTON_EVENT event (value 2).
Back to top
Create an image button with the id widget_id in window win_id. img is the id of the image to use, and
cel is the image cel to use. The button will be placed at the window coordinates x, y
When an image button has been clicked on, you will get an SW_BUTTON_EVENT event (value 2).
Back to top
Create a checkbox with the id widget_id in window win_id. The checkbox will be placed at the window
coordinates x, y. If checked is set to true the checkbox will be checked.
When the user clicks on a checkbox you will get either the SW_CHECKED_EVENT or
SW_UNCHECKED_EVENT event (values 10 and 11).
Back to top
Back to top
Back to top
Create a radio button with id widget_id in window win_id. The radio button will belong to the group
group_id (any positive, non zero value). Only one radio button in a group can be selected at a time. The
radio button will be placed at the window coordinates x, y. If selected is set to true, the radio button will
become the selected one in the group.
When a radio button has been selected by the user you will get an SW_RADIO_BUTTON_EVENT. The
Back to top
With this procedure you can make a set of normal buttons work as radio buttons. widget_id will belong
to the group group_id (any positive, non zero value).
When a button that belongs to a group has been selected by the user you will receieve an
SW_RADIO_BUTTON_EVENT instead of an SW_BUTTON_EVENT. The group is in the SW_GROUP
field of the event.
Back to top
Make widget_id in window win_id become the selected widget in the group it belongs to.
Back to top
Back to top
A text area works like a label but may have several lines of word wrapped text. This procedure creates
the text area widget_id at x, y in window win_id. The text will fit to the rectangle defined by the position
and the width and height, w and h.
Back to top
Create an input field, where the user can enter something with the keyboard, with id widget_id at x, y in
window win_id. The width of the input field will be w pixels. type should be SW_INTEGER,
SW_FLOAT or SW_STRING, for integer, floating point or string input.
When the user has finished entering something in a field, you will get an SW_INPUT_EVENT. You can
use the function SW_GetLabel (see below) to retrieve the input. As SW_GetLabel always returns a
string, you may need to convert the result to an integer or float with int or float#.
Back to top
Back to top
Change the label of widget widget_id in window win_id to txt$. This works on normal labels, text areas,
buttons and input fields.
Back to top
Back to top
There are two extra events that can be enabled for a window, win_id. If you set event to
SW_KEYBOARD_EVENT you will get an SW_KEYBOARD_EVENT every time a keyboard key has
been pressed. You can get the key value with SW_KEY. Ex:
...
proc SW_EnableWindowEvent 1, SW_KEYBOARD_EVENT
...
event[] = SW_GetEvent()
if event[SW_WINDOW] = 1 and event[SW_EVENT] = SW_KEYBOARD_EVENT
if event[SW_KEY] = 27 then end
endif
...
By enabling SW_MOUSE_EVENTS for a window, you will get the following events:
You can use SW_MOUSE_X and SW_MOUSE_Y to get the mouse cursor position relative to the top left
corner of the window. Ex:
...
proc SW_EnableWindowEvent 1, SW_MOUSE_EVENTS
...
event[] = SW_GetEvent()
if event[SW_WINDOW] = 1
if event[SW_EVENT] = SW_MOUSE_DOWN_EVENT
start_x = event[SW_MOUSE_X]
start_y = event[SW_MOUSE_Y]
elseif event[SW_EVENT] = SW_MOUSE_DRAG_EVENT
...
elseif event[SW_EVENT] = SW_MOUSE_UP_EVENT
...
endif
endif
Back to top
Back to top
Every window can have its own menu (located the the top of the program window). A menu consists of
one or more titles, and each title has a list of items that the user can select between using the mouse.
There's no support for "sub items".
To create a menu for window 1 with two titles, "File" and "Edit", and a couple of items on each you can
write:
...
proc SW_CreateMenu 1, "@File/New/Open/Save/Exit@Edit/Cut/Copy/Paste/"
Use the @ character for a new title. Use the / character to add an item. For some reason you also need to
add a / character at the end of the entire string.
Every time the user has selected a menu item, you will get an SW_MENU_EVENT. You can then get the
index, starting at 1, of the menu title through SW_MENU_TITLE and the item index, starting at 1 for
each title, with SW_MENU_ITEM.
...
event[] = SW_GetEvent()
if event[SW_WINDOW] = 1
if event[SW_EVENT] = SW_MENU_EVENT
rem File?
if event[SW_MENU_TITLE] = 1
rem New?
if event[SW_MENU_ITEM] = 1
...
elseif event[SW_MENU_ITEM] = 2
...
endif
rem Edit?
elseif event[SW_MENU_TITLE] = 2
rem Cut?
if event[SW_MENU_ITEM] = 1
...
rem Copy?
elseif event[SW_MENU_ITEM] = 2
...
endif
endif
endif
endif
Back to top
procedure SW_CreateDefaultMenu(menu$)
You can also create a default menu that will be used for every window without a menu. It works the
same way as window menus, but the SW_WINDOW of the event will be 0.
Back to top
procedure SW_Redraw()
Most user actions, such as button presses, cause SimpleWidget to redraw. But you can also force a
redraw by calling SW_Redraw. You may, for example, have an image in a window that has changed and
therefor needs to be redrawn.
Back to top
procedure SW_SetBGColor(r, g, b)
You can use this procedure to change the background color of your program to r, g, b (RGB).
Back to top
procedure SW_EnableTimer(delay)
If you need some sort of animation in your program, you can enable the timer event. Every time delay
milliseconds has passed, you will get an SW_TIMER_EVENT. You can get the actual time that has
passed through SW_TIME. The timer is not very accurate, and it may be interrupted by user actions.
Back to top
[ Go back ]
AWRCollision (AWRCollision.lib)
By Marcus.
[ Go back ]
Introduction
This library basicly lets you move a rectangle around in a world of rectangles, with collision detection.
It's small but can be quite useful sometimes.
Examples
ex_awr_1
ex_awr_2
Sub routines
function AWR_MoveRect[](&r[], dx, dy, &rects[][])
r is a rectangle [x, y, w, h] (top left corner and width and height) moving with the speed dx, dy. rects is
an array of rectangles [][x, y, w, h] that prevents r from moving. The function returns an array [left,
right, up, down] that tells the caller if there's been a collision in a certain direction. The position of r is
automatically adjusted during collision.
Back to top
This function works just like AWR_MoveRect but uses float values instead.
Back to top
[ Go back ]
ex_awr_1
Click in the window when the applet has loaded. Use the arrow keys to move around.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/awr_1.html1/6/2012 2:36:02 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_awr_1.txt
rem ==================================================================
rem "A World of Rects" Collision Library Example
rem
rem In this example I only draw rectangles for obstacles and player,
rem but you can of course represent these things with images instead.
rem Control player with cursor keys or A, D, W and S.
rem
rem By Marcus
rem ==================================================================
import "AWRCollision.lib"
do
rem Check if player wants to move.
dx = 0
dy = 0
if keydown("A") or keydown(37) then dx = -2
if keydown("D") or keydown(39) then dx = 2
if keydown("W") or keydown(38) then dy = -2
if keydown("S") or keydown(40) then dy = 2
rem Set players position to the x and y values from the rect.
plyX = r[0]
plyY = r[1]
redraw
wait 10
until keydown(27) or not running()
ex_awr_2
Click in the window when the applet has loaded. Use the arrow keys to walk and jump.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/awr_2.html1/6/2012 2:36:02 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_awr_2.txt
rem ==================================================================
rem AWR Platformer
rem
rem A simple platform "game" that uses the AWRCollision library.
rem
rem By Marcus
rem ==================================================================
rem The player image contains 4 cels (sub images), indexed from 0..3.
rem In cel 0 and one the character is turned right, and in cel 2 and 3
rem it's turned left. The variable playerBaseCel will always be 0 or 2
rem depending on the players current direction. When player is moving
rem left or right the variable playerFrame will flip between 0 and 1,
rem which is all the animation we've got. The image cel drawn will
rem The background image contains some objects that the player should
rem be able to collide with. We now set up an array of rectangles for
rem these objects. Each sub array is a rectangle with the format
rem [x, y, width, height]. The coordinates were simply read from the
rem background image in GIMP.
obstacles[][] = [[0, 0, 16, 480], [624, 0, 16, 480], [16, 432, 608, 48], [448, 320, 96, 112], [48, 320, 112,
32], [208, 208, 96, 64], [384, 176, 176, 32]]
rem Move player among our obstacles. We get some information about
rem the collisions in res.
res[] = AWR_MoveRect(playerRect, xSpeed, playerYSpeed, obstacles)
rem Set players position to the x and y values from the possibly
rem modified rect.
playerX = playerRect[0]
playerY = playerRect[1]
rem If res[2] is true, the player has hit its head into something
rem while jumping, so we set the vertical speed to 0.
if res[2] then playerYSpeed = 0
proc SPD_HoldFrame 60
rem ==================================================================
rem Hold frame to maintain fps.
rem ==================================================================
procedure HoldFrame(startTime, fps)
hold = 1000/fps
endTime = time()
deltaTime = endTime - startTime
if deltaTime < hold
wait hold - deltaTime
else
wait 0
endif
endproc
[ Go back ]
Introduction
This library can be used for many things, not just what you would generally concider as "particle
effects". You can use it for everything from score points flying up into the air to temporary image
animations such as explosions.
Examples
ex_simpleparticle
Sub routines
procedure SP_Init(maxParticles)
procedure SP_AddParticle(img_id, cel, add_mode, x, y, src_dx#, src_dy#, dst_dx#, dst_dy#, src_alpha#,
dst_alpha#, speed#, pause)
procedure SP_UpdateParticles()
procedure SP_DrawParticles()
procedure SP_DoParticles()
procedure SP_DrawParticlesAt(x, y)
procedure SP_DoParticlesAt(x, y)
procedure SP_AddPoof(img_id, cel, x, y, particle_count, distance#, force#, speed#, add_mode, fade_out)
procedure SP_AddRandomPoof(img_id, cel, x, y, particle_count, max_distance#, max_force#,
max_speed#, add_mode, fade_outut)
procedure SP_SetPoofEndVector(dx#, dy#)
procedure SP_Init(maxParticles)
Init/clear and set the maximum number of visible particles at a time to maxParticles. You've got to call
this procedure before trying to add, update or draw any particles.
Back to top
Add a single particle at position x, y using image img_id. If you set cel to zero or any positive value, the
particle will use that cel of the image (based on set image grid). If you set cel to -1, all the cels of the
image will be used in an animation. A value of -2 will cause a random cel to be used (same as rnd(cels
(img_id))). If add_mode is set to true, the particle will be drawn using the additive draw mode. src_dx
and src_dy is the start direction of the particle. dst_dx and dst_dy is the end direction, that the particle
will have when it's done and removed. src_alpha and dst_alpha is the start and end alpha value
(transparency) of the particle, and their values should be in the ranage 0..1. Usually a particle has 1.0 as
src_alpha and 0.0 as dst_alpha. Every particle is controlled by a parameter that goes from 0..1. When
the parameter reaches/passes 1.0, the particle is removed. speed is the step size for this parameter. If you
set step to 0.01, the particle will be updated/drawn 100 times. You can set pause to a value greater than
zero if you want to put the particle on hold for pause number of updates (calls to SP_Update or
SP_DoParticles). During this time period, the particle will not be updated or drawn.
Back to top
procedure SP_UpdateParticles()
Back to top
procedure SP_DrawParticles()
Back to top
procedure SP_DoParticles()
Back to top
Draw all particles translated t_x, t_y pixels. For example, if you want to use SimpleParticle with the
Tilemap library, you can use this procedure to transform from world coordinates to screen coordinates:
Back to top
procedure SP_DoParticlesAt(x, y)
Does the same thing as SP_DrawParticlesAt but also updates all particles.
Back to top
(When I say poof effect, I mean a whole bunch of particles moving away in different directions from a
common center point.)
Add a poof effect at x, y using image img_id. The cel parameter works just like it does in
SP_AddParticle. particle_count number of particles will spread out evenly from x, y. If distance is not
zero, all particles will start distance pixels away from the center. Initially the particles' moving vectors
will be of the size force. Unless you call SP_SetPoofEndVector, the particles will stop moving as they're
about to be removed. If you set add_mode to true, additive draw mode will be used for all particles in
the poof effect. If you set fade_out to true, all particles will fade out. The speed parameter works as it
does for SP_AddParticle.
Back to top
This procedure works almost exactly like SP_AddPoof. The difference is that the effect looks much
more random.
Back to top
If you want the particles of a poof effect to look as if they're affected by some force, like gravity or
wind, you can use this procedure to set their common end movement vector to dx, dy.
Back to top
[ Go back ]
ex_simpleparticle
Click in the window for random poof effects. Press space bar to continue, then click and hold down the
left mouse button to see different effects.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/simpleparticle.html1/6/2012 2:36:03 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_simpleparticle.txt
rem ==================================================================
rem Simple Particle Library - Example.
rem
rem By Marcus
rem ==================================================================
randomize time()
redraw
proc SPD_HoldFrame 60
until keydown(" ", true)
if mousebutton(0)
rem Change and activate effect?
if hasEffect = false
if hasEffect
rem Throw away particles in any direction with gravity.
if effect = 0
for i = 0 to 2
a# = float(rnd(360))
proc SP_AddParticle 1, -2, false, mousex(), mousey(), cos(a)*3.0, sin(a)*3.0, 0.0,
4.0, 1.0, 0.0, 0.025, 0
next
rem Same as above, but with inverse gravity.
elseif effect = 1
for i = 0 to 2
a# = float(rnd(360))
proc SP_AddParticle 1, -2, false, mousex(), mousey(), cos(a)*3.0, sin(a)*3.0, -cos(a)
*2.0, -4.0, 1.0, 0.0, 0.02, 0
next
rem Throw away particles that inverts their direction.
elseif effect = 2
for i = 0 to 2
a# = float(rnd(360))
proc SP_AddParticle 1, -2, false, mousex(), mousey(), cos(a)*3.0, sin(a)*3.0, -cos(a)
*7.0, -sin(a)*7.0, 1.0, 0.0, 0.025, 0
next
rem Same as above, but with other speeds.
elseif effect = 3
for i = 0 to 2
a# = float(rnd(360))
proc SP_AddParticle 1, -2, false, mousex(), mousey(), cos(a)*7.0, sin(a)*7.0, -cos(a)
*3.0, -sin(a)*3.0, 1.0, 0.0, 0.025, 0
next
rem Spiral thing.
elseif effect = 4
for i = 0 to 2
spiralAngle = spiralAngle + 8.0
proc SP_AddParticle 1, -2, false, mousex(), mousey(), cos(spiralAngle)*4.0, sin
(spiralAngle)*4.0, cos(spiralAngle - 90.0)*4.0, sin(spiralAngle - 90.0)*4.0, 1.0, 0.0, 0.025, 0
next
endif
endif
redraw
proc SPD_HoldFrame 60
until keydown(" ", true) or keydown(27, true)
[ Go back ]
Introduction
This library generates passwords for integer data of limited ranges. It's a classic way of storing a game
progress and well suited for Java applets, that aren't allowed to create and write to files.
import "Password.lib"
fields[] = PWD_GetFields(pwd)
for i = 0 to sizeof(fields) - 1
wln fields[i]
next
wait keydown
Output:
HNYJXDYSKM
16
10
29
900
10
123
The first procedure we call is PWD_SetFormat. This tells the library what format the passwords should
use. Each character represents an integer value. x is a value in the range 0..31 and X is a value in the
range 0..1023. In the example we want to store three 0..31 and three 0..1023 values. PWD_GetPassword
converts an array of integers into a password. The order of the elements in the array must be the same as
in the string we sent to PWD_SetFormat. This means that the first element should be in the range
0..1023, while the second and third elements should be in the range 0..31. The function PWD_GetFields
converts a password back into an array of integers.
Examples
ex_password
Sub routines
procedure PWD_SetFormat(fmt$)
function PWD_GetPassword$(fields[])
function PWD_GetFields[](pwd$)
procedure PWD_SetFormat(fmt$)
Set the format of the passwords. fmt$ should be a sequence of the two characters x and X. x represents an
integer value in the range 0..31 and X an integer in the range 0..1023. If fmt$ is set to "XXxx", the
password will represent two 0..1023 integers followed by two 0..31 integers.
Back to top
function PWD_GetPassword$(fields[])
Return a password based on the format set with PWD_SetFormat. fields should contain as many integer
values as there were characters in the string sent to PWD_SetFormat. If any value is out of range it will
be cropped. The generated password uses only alpha and numerical characters (some characters and
numbers, that can cause confusion, are not used). Every 0..31 element adds one character to the
password, and every 0..1023 element adds two characters. The extra character at the end is a checksum
to prevent password modification.
Back to top
function PWD_GetFields[](pwd$)
Convert the password pwd$ back into integer values and return them as an array. If the password is
incorrect, according to its checksum, an empty array is returned.
Back to top
[ Go back ]
ex_password
View source code.
Go back.
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/password.html1/6/2012 2:36:04 AM
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_password.txt
rem ==================================================================
rem Password Library example.
rem ==================================================================
rem Set format of password. level, lives and gunType will use values
rem in the range 0..31. Kills will use a 0..1024 value, and score will
rem be stored as two 0..1024 values.
proc PWD_SetFormat "xxxXXX"
wait keydown
file:///E|/Programming/basic/NaaLaa%205%20Dec%2028%202011/doc/lib/examples/ex_password.txt1/6/2012 2:36:04 AM
NaaLaa - Tilemap Editor
Tilemap Editor
[ Go back ]
With the Tilemap Editor you can create maps that you can load and use with the Tilemap library. If there's something you
don't understand when reading this documentation of the program, it might help to have a look at the library.
The program has got three windows named Edit window, Tiles window and Map window. They're explained in detail
below. In the Edit window you load and save maps and set up the image that your map's different tiles are stored in. In the
Tiles window you select what image tile to draw with in the map window. In the last window, the Map window, you draw
and edit your map.
The best way to learn how to use this program is probably to look at the maps of the Tilemap library's example programs!
To load a map, you click on the Load map button, and to save a map you use the Save map button.
To make a new map from scratch, you begin with loading the image containing your tiles. This image should be a grid of
tiles of a constant size. Here you see an example of such an image:
The tiles in this image are 16x16 pixels large (actually, in the image you see above, they're 32x32 pixels, but that's just
because it looked too damn small in its original size). This means that the image's width and height must both be multiples
of 16.
When you have loaded an image, you enter the tile size on the right of the Tile size label. If your image should have a color
key (a color that is to be transparent), you enter its RGB value on the right of the Colorkey label and make sure that the
checkbox on the left is marked. As you make these steps, things will probably happen in the Tiles window.
Now, in the two fields on the right of the Map size label, you can enter the desired dimensions of your map. The size is
measured in number of horizontal and vertical tiles. For example, if your game map should cover the entire game window
and you're using a resolution of 640x480 pixels. and your tiles are 32x32 pixels large, you should set the map size to 20x15
(640/32 = 20, and 480/32 = 15). As you make these steps, things will probably happen in the Map window. But, of course,
your map can be much larger than the game window! Note, that you can increase the map size without losing any data. But
if you decrease the size of a map, the parts that are removed are gone forever!
In the Tiles window you can click on the tile that you wish to draw with in the Map window. Here you can also decide if a
certain tile is meant to be an obstacle in the game or not. An obstacle is a tile that objects (player, enemies ...) can't move
through (if you're using the TM_Move function).
From start, all tiles have black borders. But if you double click on a tile, its border will become white. And the white
border indicates that the tile is an obstacle. If you click on the tile again, the border will turn back to black.
If your game character all of a sudden can walk through walls or seams to be blocked by thin air, you've probably
accidentally double clicked on a tile in the Tiles window.
This is the window where you draw your maps. You draw by pressing down the left mouse button while the mouse cursor
is over the gray grid, which has the size of your map.
On the bottom left, there are three radio buttons with the labels Images, Game flags and Loader flags. They represent the
three layers that every map consists of.
If you mark the Erase checkbox, you can erase image tiles, game flags or loader flags the same way as you otherwise draw
them.
If your map is larger than the window, you can use the four arrow buttons at the bottom right to scroll in any direction. If
you mark the Screen checkbox, you can scroll an entire window at a time.
When the Images radio button is selected you can draw on the map with the tile selected in the Tiles window. As you may
have already figured out, this is the visible layer of the map, the one that the player will see when playing your game.
Game flags, described in the documentation of the Tilemap library, are integer values that you can access from your code.
On the map they're represented by yellow values. Each tile can have one value set. As an example, from the image above,
you can use game flags to tell that a certain brick is to transform into a jewel once cracked. You can change the game flag
value using the arrow buttons or the text field on the right of the Game flags label. You add a game flag by clicking on a
tile in the grid.
You edit loader flags the same way as you do with game flags. They're represented by green values on the map. In your
program code, you can get a hold of the loader flags, after loading a map, by calling TM_GetLoaderFlags. You can use
different loader flags to indicate the player's and enemies' starting positions etc.
[ Go back ]
Raycaster Editor
[ Go back ]
With the Raycaster Editor you create maps that you can load and use with the Raycaster and Mode7
libraries. If there's something you don't understand when reading this documentation of the program, it
might be of help to have a look at the libraries and their examples.
The program has got six windows named Edit window, General window, Images window, Items window,
Map window and Preview window. They're explained in detail below. In the Edit window you load, clear
and save maps and select between different edit modes. In the General window you change the map size
and set fog properties. In the Images window you load and set up images that can be used for walls,
ceilings, floors and items. The Item windows allows you to set up visual objects that can be added to
your game map. In the map window you create the actual map from walls, ceilings, objects and flags.
The preview window allows you to move through the map you're currently editing.
The best way to learn how to use this program is probably to look at the maps of the Raycaster library's
example programs! Still, the first thing you do when creating a map is to visit the General window and
make some settings ...
A raycasting map is basicly a 2D grid, where each cel represents a cube with some properties, or layers.
In the General window you can set the size of your map, the number of cubes in each direction, by
editing the Map width and height fields. You will not lose any data by increasing the map size, but you
may lose information when decrease the size.
In the General window you can also set the fog range and color. When a wall, floor, ceiling or object
passes a certain distance, z min, it will visually start getting blended with the fog color (RGB). At the
distance defined by z max everything is covered by the fog color. In other words, z max defines the far
clip plane during rendering.
In the Images window you can load images that can be used for walls, floors, ceilings and items/objects.
Each map can have 63 images, indexed as 1..63. You load an image by entering an index next to the
Index label and pressing the Load button. If you want to remove an image, you can use the Clear button.
If you want an image to use a colorkey for transparency, you mark the checkbox next to the Colorkey
label. Then enter the color (RGB) that you want to make transparent below.
If you've read the documentation of the library, you know that there's something called objects. An
object is basically an image in 3D space that is always facing the player. You use objects for everything
from collectable bonuses to lamps and enemies.
Every map has an item layer that you can modify in the editor. That is, every cel in the grid can have an
item set. Items are visually represented by objects, that are automatically added when the map is loaded
in your program. You can use items for non-moving objects, such as barrels, lamps and bonuses.
To create an item type, select an index (1..63) next to the Index label. Then, below, select the image you
want to use - the value on the right of the Image label is the index of an image set in the Images window.
Change the size (0..1) of your object by using the field next to the Size label. If you set the size to 1, the
object will visually be as tall/wide as a wall. On the right of the Align label, you can use the radio
buttons to decide whether the visual object should stick to the ceiling, floor or be vertically centered. If
you mark the checkbox on the left of the Obstacle label, the item will become an obstacle that the player
(or anything using the RC_Move function) can not move through.
With the Load and Save buttons you can load and save maps. The Clear map button clears all layers of
the map but leaves the images you've loaded and the items you've set up. Clear all clears all layers,
images and items.
There's a centered list of labels for everything that you can edit in the Map window. You can use the
radio buttons on the left side of the list to decide what you want to edit in the Map window. With the
checkboxes on the right side you can decide what layers should be visible in the Map window.
If you want to erase something in the currently selected layer you can mark the Erase checkbox at the
bottom left of the window.
Walls
Each cel in the map grid can have a wall image set. This image is used for the four sides (in the x, z
plane) of the cube that the cel represents. When you edit walls in the Map window, you're always using
the image that's active in the Images window.
Floor/Ceiling
Each cel can also have a floor image and a ceiling image. They're only visible if the cel has no walls.
Items
Each cel can have an item. When editing the item layer in the Map window, you're always using the item
that's active in the Items window.
Doors
A door is a horizontal or vertical wall centered in a cel. Doors can be opened from your program code.
You use the currently selected image in the Images window when editing doors (any image can be used
as a door). In the Map window a door is represented by an image and a vertical or horizontal line. Once
you've added a door to a cel, you can click again in the cel to swap between a horizontal and vertical
door.
Game flags
A game flag is an integer value (>0) that can be set for any cel. You can access these flags in your
program and do whatever you want with them. When you edit game flags in the Map window, you use
the flag that is set in the field next to the Flag label at the bottom right of the Edit window.
Loader flags
Loader flags are edited just like game flags. These flags are returned, together with their map
coordinates, to your program when calling RC_LoadMap. You can use them to initialize enemies and
other things.
Player
Each map has a starting position for the player. It's the first element of the array returned by
RC_LoadMap. You don't need to use it in your program, but it is used when you walk through your map
in the Preview window. The player position is represented by an arrow in the Map window. You can
click in the cel that holds the arrow several times to change its direction - the starting direction of the
player.
You change (set or erase) the layer content of a cel in the map grid with your left mouse button. Loader
flags are represented by yellow values and game flags by green values. You can change the visibility of
the different layers in the Edit window.
If you want to move around in the map you're editing you can use the Preview window. Press the
Generate button to create a new preview (you need to do that everytime you've changed something in
the map). Use the round thing with arrows to walk and turn around - it's sort of a virtual analogue
joystick. Just Fiddle around until you get the hang of it. If you wish to open a door, just stand in front of
it and click on it.
[ Go back ]