Contents
Programming Tutorials
This is the imeight programming language. One that resembles those 80s
languages when programming was still fun to learn. Do you want to experience, too?
This emulated imaginary machine has these screen modes:
- Program Listing: for writing and editing your program text.
- Runner Screen: for issuing interactive commands and reading output of your program as it runs.
- Design Util: see Game Programming Tutorial.
You can use the usual Copy and Paste function in your browser to transfer
example codes from the tutorial to the Program Listing panel.
For a test run, press > RUNNER (F9) then see RUN command appear in the
Runner Screen, press Enter.
Return to the Program Listing by entering the LIST command.
NEW command will also erase the program text.
Press Esc button for long to kill a running program.
Reference Sheet Index
Fun Projects
Contents
PRINT "HELLO WORLD"
REMARK: The PRINT instruction is for learning and debugging purposes only.
REMARK: See "HELLO WORLD" printed as a result.
An Infix Operator: + Between Numbers
PRINT 6+4
REMARK: See 10 printed on the Runner Screen.
REMARK: + is an infix operator and works like in maths.
REMARK: There are more operators to be covered later.
A Function: SIN
PRINT SIN(1.571)
REMARK: 1.571 is approximately 90 degrees in radians.
REMARK: So this will print a number close to 1, sine of 90 degrees.
REMARK: You must not leave white space between SIN and the parenthesis.
Full Syntax
INPUT "HOW MUCH?", A
REMARK: Again an instruction for learning purposes only.
REMARK: Displays the question "HOW MUCH?". User may enter the value.
Default Prompt
INPUT A
REMARK: A shorter version of the INPUT instruction.
REMARK: Also asks the user but the question is generated by the runner.
INPUT A
PRINT A
INPUT B
PRINT B
Now we wrote a program of multiple lines.
The topmost line will run first. Program waits for input.
Then the 2nd line runs so the value of the variable A is printed.
See that whatever is entered is printed.
It's because INPUT instruction has assigned the entered value
to the variable A, which kept that value when printed.
Third and fourth line does the same with another variable, B.
INPUT B happens after printing A, as if you would read a story.
Assignment: Old Value, New Value
INPUT A
PRINT A
INPUT A
PRINT A
In the previous example A kept its value. Now here is an example how it can drop the value.
Read the story.
1st line prompts the user and assigns the entered value to A. Variable A will keep it for the next line.
To prove it, we do a PRINT A in the 2nd line.
In the 3rd line INPUT will assign again. Which means, the old value is replaced by the new.
See what gets printed in the 4th line: the new value of A, regardless of its previous value.
Write a program with a lot of PRINT instructions to make beautiful ASCII art.
Wanna see my submission?
PRINT " , _____ , "
PRINT " /,!\ (_ _/_______ /TZ)"
PRINT " ` V/\__ _ / / / / / _ \ _ __/\/"
PRINT " _(LL||TTT ) / / / / / (/ / ( TTT||JJ)_"
PRINT " \, \) (_/\____/\___/ (/ _/"
PRINT " \__ /_"
PRINT " _______ / /_______________/ /"
PRINT " (_ / , \/ _ ) ,_/ _ / __/ /"
PRINT " / __/ __/ (/ / / / (/ /_ /_/"
PRINT " /___/\___/\___/_/ \__,_\__(_)"
The key take-away from this project task was that the lines appear on the
Runner Screen the same order as in the Program Listing, which we call the normal
program flow. Another take-away is that the writer of this paper has substandard
drawing skills.
I have a
forum topic for you in case you want to tell the world how you
accomplished this task. Time to contact fellow imeight programmers!
In the INPUT examples we could see that there are variables named A and B, which help us store numbers.
But you can name them relatively freely. Let's see the exact rules for naming variables:
- A variable name must start with a letter A through Z. It may have a longer name.
INPUT NUM
- From the second position on, the name may contain dots (.), digits 0 to 9 or more letters, in any order.
INPUT NUMBER2STORE
INPUT INCOME2020
- There is no length limit for the name.
INPUT THERE.IS.NO.DEFINED.LENGTH.LIMIT.FOR.THE.VARIABLE.NAMES
- The name optionally ends in one $ or one % sign.
Convention is that the name ends in $ if it is supposed to have a text value rather than number.
The % sign suggests integer number value.
INPUT N%
INPUT TEXT$
These rules not only apply to variable names, but also function names and array names, which are covered later.
LET SUM = 6+4
PRINT SUM
The first line will assign a calculated value, 10, to the variable SUM.
Second line shows that the variable keeps the value.
This way you can give a name to your calculation results, making your intent clear and the code maintainable.
Implicit LET Instruction
SUM = 6+4
PRINT SUM
You can omit the instruction LET and it will still be interpreted as an assignment.
Note: Line 1 is not an equation. The left side must specify the thing to assign to (variable A this time.)
It is an error to swap the two sides of the assignment, putting numbers or operators to the left side.
If your variable name starts with an instruction (e.g. PRINTED, LETTER$) then the LET keyword is necessary.
Motivation
SUM = 1+1+1+1+1+1+1+1+1+1
LITTLEBIGGER = SUM+1
MUCHBIGGER = SUM+10
PRINT SUM
PRINT LITTLEBIGGER
PRINT MUCHBIGGER
Let's pretend that calculating SUM takes a lot of time and effort.
This is how you reuse a calculation. The SUM variable keeps its value and is used for calculating two more values.
So variables are not only there for code readability, they can make your code more efficient, too.
Referencing The Old Value In LET
INPUT A
A = A+1
PRINT A
2nd line says, add 1 to the old value of A, and let the incremented value be the new value of A.
So the 3rd line will print the successor of whatever the user enters.
You can make your code self documented by inserting REM instrucions. They make the runner ignore the rest of the line.
REM * USER WILL ENTER A NUMBER *
INPUT A
REM * COMPUTER WILL INCREMENT THE NUMBER *
A = A+1
REM * AND NOW DISPLAY THE RESULT *
PRINT A
You can use this instruction to temporarily skip a line or two while developing your program:
PRINT "HELLO"
REM PRINT "GOODBYE"
REM * I HAVE COMMENTED OUT THE SECOND LINE *
REM * RUNS LIKE IT WAS DELETED BUT *
REM * MAYBE I WILL WANT TO UNCOMMENT LATER *
You can normally put several instructions on a line, separated by colon:
PRINT "HELLO":PRINT "WORLD":REM BOTH WILL PRINT
But the colon does not break the REM instruction:
PRINT "THIS PRINTS":REM HERE IS A REMARK:PRINT "PART OF REM, NOT PRINTING"
The REMARK lines in the examples before are also REM instructions.
The space after the REM or any instruction is optional, so the text starting with ARK had been ignored by the runner.
But you should keep your code readable, which means spaces are good for you.
A$ = "THIS TEXT BETWEEN QUOTES IS A LITERAL, A SIMPLE EXPRESSION."
A = 30:REM THE NUMBER IS ALSO A LITERAL, WHICH IS AN EXPRESSION
SUM = A+1:REM A CALCULATION WITH AN OPERATOR IS AN EXPRESSION
PRINT A+1:REM EXPRESSION MAY APPEAR ON = RIGHT SIDE OR PRINT ARGUMENT
PRINT A$:REM VARIABLE NAME IS EXPRESSION IF ON = RIGHT SIDE OR IS PRINT ARG
INPUT A$, C$:REM OR ARGUMENT TO INSTRUCTIONS OTHER THAN PRINT
Y = SIN(1 + 0.571):REM FUNCTIONS WITH OPERATORS BUILD EXPRESSIONS, TOO
Z = SIN(4.712)+2:REM COMBINE THEM FREELY LIKE IN MATHS
String Expressions
(A) The String Literal
A$ = "HELLO WORLD"
PRINT "HELLO WORLD"
PRINT A$
REM * THE QUOTED "HELLO WORLD" IS CALLED LITERAL *
REM * BECAUSE IT ASSIGNS, PRINTS "HELLO WORLD" LITERALLY *
REM * WHEREAS A$ IS NOT A LITERAL BECAUSE *
REM * IT PRINTS "HELLO WORLD" RATHER THAN "A$" LITERALLY *
(B) Concatenation
PRINT "HELLO" + "WORLD"
REM * PLUS BETWEEN STRING LITERALS MEANS CONCATENATION *
REM * PRINTS "WORLD" IMMEDIATELY FOLLOWING "HELLO" *
GREETING$ = "HELLO"
AUDIENCE$ = "WORLD"
PRINT GREETING$ + " " + AUDIENCE$
REM * CONCATENATION OF STRING VARIABLES AND LITERALS ALSO WORKS *
(C) String Functions
PRINT LEN("HOW LONG AM I"):REM
PRINTS 13 (10 LETTERS + 3 SPACES)
PRINT "1" + "2":REM
DOES NOT PRINT 3 BUT A CONCATENATED STRING "12"
PRINT VAL("1") + VAL("2"):REM
PRINTS 3
PRINT ASC("A"):REM
PRINTS THE ASCII CODE 65
PRINT CHR$(65):REM
PRINTS "A" BEACUSE ITS ASCII CODE IS 65
PRINT LEFT$("HELLO", 3):REM
PRINTS "HEL" - 3 CHARACTERS FROM THE LEFT
PRINT RIGHT$("HELLO", 3):REM
PRINTS "LLO" - 3 CHARACTERS FROM THE RIGHT
PRINT MID$("HELLO", 2, 3):REM
PRINTS "ELL" - 3 CHARACTERS FROM THE 2ND POS
REM
* THE COMMA IS AN OPERATOR HERE THAT MAKES A PARAMETER LIST *
REM
* IT'S ON THE LOWEST PRECEDENCE LEVEL AMONG ALL THE OPERATORS *
Numeric Expressions
Examples below are for your reference, not error free programs to run.
(A) Literals
MOL = 6.022E+23:REM E MEANS "TIMES 10 TO THE POWER"
A = 10:REM DECIMAL 10, REALLY TEN
B = %10:REM BINARY 10, MEANING TWO
C = $10:REM HEXADECIMAL 10, MEANING SIXTEEN
D = !10:REM FOUR-BASE 10, MEANING FOUR
E = 1.2:REM 1 AND 2 TENTHS
F = .2:REM 2 TENTHS
G = .2E-2:REM 0.002
(B) Operators
C = A+B:REM ADD
C = A-B:REM SUBTRACT
C = A*B:REM MULTIPLY
C = A/B:REM DIVIDE
C = A MOD B:REM REMAINDER OF AN INTEGER DIVISION
C = A^B:REM POWER
C = A AND B:REM BITWISE LOGICAL AND; SPACE IS NECESSARY AFTER A
C = A XOR B:REM BITWISE LOGICAL EXCLUSIVE OR; SPACE IS NECESSARY AFTER A
C = A OR B:REM BITWISE LOGICAL OR; SPACE IS NECESSARY AFTER A
(C) Functions
REM * SOME INTERESTING THINGS THAT TECHNICALLY ARE FUNCTIONS *
Y = -X:REM UNARY MINUS, MEANING (-1)*X
Y = A*(B+C):REM THE () IS A FUNCTION WITHOUT A NAME: RETURNS WHAT IS INSIDE
REM * BASIC MATHS *
Y = SGN(X):REM -1 FOR A NEGATIVE X, 0 FOR 0, 1 FOR A POSITIVE X
Y = INT(X):REM INTEGER PART OF X, BUT STAYS FLOATING POINT
Y = FRAC(X):REM FRACTIONAL PART OF X
Y = ABS(X):REM ABSOLUTE VALUE: -X IF X<0, OTHERWISE X
Y = SQR(X):REM SQUARE ROOT
REM * TRANSCENDENT *
Y = LOG(X):REM NATURAL LOGARITHM
Y = EXP(X):REM NATURAL EXPONENTIAL FUNCTION
REM * TRIGONOMETRY *
Y = COS(X):REM COSINE
Y = SIN(X):REM SINE
Y = TAN(X):REM TANGENT
Y = ATN(X):REM ARC TANGENT
REM * COMPUTING *
Y = NOT(X):REM BITWISE LOGICAL NEGATION
Y = RND(X):REM NON-NEGATIVE RANDOM NUMBER THAT IS LESS THAN X
Y = PEEK(X):REM THE BYTE STORED AT ADDRESS X; SPOILER: USE POKE INSTRUCTION
Y$ = STR$(X):REM A DECIMAL REPRESENTATION OF THE NUMBER X
B = INI(X):REM TEST WHETHER X IS INITIALIZED
About Evaluation
PRINT RND(8)-RND(8):REM RND EVALUATED TWICE, CAN RETURN DIFFERENT VALUES
X = RND(8):REM EVALUATED ONCE
PRINT X - X:REM ALWAYS RETURNS ZERO
Make an ASCII art zebra say something that the user enters.
INPUT "WHAT DOES THE ZEBRA SAY?", MSG$
PRINT " ,, ____________"
PRINT " /oo)___/" + LEFT$(MSG$ + " ", 12) + "\"
PRINT " _ __/=/ \____________/"
PRINT " ( TTT||JJ) "
PRINT " || || "
What expressions can you find in my code?
- String literals? Find all 8.
- Is there a number literal, too?
- Can you find a function?
- Maybe infix operators?
- Are the plus signs concatenations or number additions here?
Do you have a better version? Remember the
forum topic where you can share it?
Flow instructions can break the normal flow of the program. GOTO instructs the runner to immediately go to a specified
point in the program, rather than continuing at the next one in reading order. Using the @ instruction you can put a
label to a point in the program and reference that label in a GOTO argument.
Jumping over a part of the program:
PRINT "TITLE"
PRINT "INTRODUCTION"
GOTO RESULTS
REM NOONE CARES ABOUT CALCULATIONS
PRINT "CALCULATIONS"
@RESULTS
PRINT "RESULTS"
Jumping back makes an endless loop:
@LOOP
INPUT A
GOTO LOOP
REM * THIS WILL RUN UNTIL USER HITS ESC BUTTON *
Jumping wildly:
PRINT "THEY SAY GOTO IS A CRIME"
GOTO INTERMEZZO
@CONTINUATION
PRINT "CAN WE CONCLUDE, GOTO IS FUN?"
GOTO FIN
@INTERMEZZO
PRINT "I SAY GOTO IS FINE"
GOTO CONTINUATION
@FIN
Note: there is a built-in label called START, which points to the beginning
of the program. Therefore:
- To restart the program, say GOTO START.
- The name START is reserved.
Logical Operators
INPUT A
REM * EQUAL AND UNEQUAL SIGNS ARE OPERATORS, TOO: *
REM * THEY APPEAR BETWEEN TWO NUMERIC EXPRESSIONS *
REM * AND GIVE 1 AS RESULT IF TRUE, 0 IF FALSE *
IF A=1 THEN PRINT "A IS ONE"
IF A<>2 THEN PRINT "A IS NOT TWO"
IF A<10 THEN PRINT "A IS LESS THAN TEN"
IF A>5 THEN PRINT "A IS GREATER THAN FIVE"
IF A<=8 THEN PRINT "A IS NOT GREATER THAN EIGHT"
IF A>=7 THEN PRINT "A IS NOT LESS THAN SEVEN"
REM * AND IS AN OPERATOR, JUST LIKE OR *
IF A>=4 AND A<=6 THEN PRINT "A IS BETWEEN FOUR AND SIX"
IF A<3 OR A>9 THEN PRINT "A IS NOT BETWEEN THREE AND NINE"
Mixing Logic and Numbers
- True converts to 1, false to 0 if comparison result is used in numeric expression
- When numeric expression is used as a condition, 0 means false, non-0 numbers true
INPUT "PLEASE ENTER 1 HERE.", A
IF 1-A THEN PRINT "BAD"
IF 1-A<>0 THEN PRINT "BAD"
IF 1<>A THEN PRINT "BAD"
REM * IF USER DOES NOT ENTER 1 THEN "BAD" APPEARS THREE TIMES *
REM * IF USER ENTERS 1 THEN PROGRAM ENDS WITHOUT PRINTING *
Pitfalls
Operators AND, OR work bitwise.
As long as the two sides of them are either 0 or 1, they can be used to combine conditions.
Comparison operators like < and > and = will give either 0 or 1 to support such combinations.
However, NOT function is bitwise and may have astonishing result.
INPUT A:INPUT B
IF NOT(A=B) THEN PRINT "A IS NOT B?"
REM * ENTER EQUAL NUMBERS *
REM * A=B GIVES 1 (TRUE). NOT(A=B) GIVES ALL BITS BUT ONE SET, -2 *
REM * IT IS NOT 0, CONDITION IS MET, MESSAGE WILL BE PRINTED *
PRINT 0=0=0:REM 0 (FALSE) BECAUSE 0=0 GIVES 1 (TRUE), 1=0 GIVES 0 (FALSE)
PRINT 0=0=1:REM 1 (TRUE) BECAUSE 0=0 GIVES 1 (TRUE), 1=1 GIVES 1 (TRUE)
Colon After THEN
@TASK
A = RND(10)
B = RND(10)
@ASK
INPUT A + " + " + B, C
IF C = A+B THEN PRINT "CORRECT":GOTO TASK
PRINT "TRY AGAIN":GOTO ASK
If the user input is correct then the program will not only PRINT "CORRECT" but also GOTO TASK.
If the condition is not met then the rest of the line is skipped, even if it contains
several instructions separated with colon.
Have you noticed that you know everything you need to create a text
adventure game? Feel free to change or add more
options – and
then share your work!
BOREDOM=0:MONEY=0:GF=0
PRINT "----------- TEXT ADVENTURE GAME -----------"
PRINT "------ CLICK HERE AND PRINT ALL CAPS ------"
@HOME
PRINT "YOU ARE AT HOME. LIVING ALONE FEELS LONELY"
PRINT "SOMETIMES... BUT YOU CAN JUMP ON YOUR BED"
PRINT "IF YOU LIKE."
BOREDOM=BOREDOM+1
IF BOREDOM>10 THEN GOTO DEATH
IF BOREDOM<>3 THEN GOTO HOMEASK
PRINT "YOU STAND UP ON THE BED TO JUMP... YOU FEEL"
PRINT "SOMETHING PUSHING YOUR FOOT..."
PRINT "HEY! YOU FOUND A COIN BELOW THE BEDSHEET!"
MONEY=1
@HOMEASK
INPUT "STAY OR LEAVE?", MOVE$
IF MOVE$="STAY" THEN GOTO HOME
IF MOVE$="LEAVE" THEN GOTO STREET
GOTO HOMEASK
@DEATH
PRINT "LIFE IS SO BORING THAT YOU DIED. GRAY RATS"
PRINT "WHO JUST HAD BEEN LINGERING THERE"
PRINT "ARE LISTLESSLY EATING YOUR BODY."
PRINT "------------------- END -------------------"
END
@STREET
PRINT "FRESH AIR! THE STREET IS CROWDED AS USUAL."
PRINT "YOU STAND JUST IN FRONT OF YOUR HOME"
IF BOREDOM>3 AND MONEY=0 THEN GOTO SELL
@STREETASK
INPUT "WHERE WOULD YOU GO? CENTER, OUTSKIRTS, HOME?", MOVE$
IF MOVE$="CENTER" THEN GOTO CENTER
IF LEFT$(MOVE$, 3)="OUT" THEN GOTO OUTSKIRTS
IF MOVE$="HOME" THEN GOTO HOME
GOTO STREETASK
@CENTER
PRINT "MALLS AND RESTAURANTS ALL AROUND."
PRINT "YOU FEEL LIKE SHOPPING!"
IF MONEY=0 THEN PRINT "WISH YOU HAD ANY MONEY :(":GOTO CENTERASK
IF GF=1 THEN GOTO FLOWERS
PRINT "YOU BOUGHT A GOLDEN PIGLET. IT'S A PERFECT"
PRINT "PRESENT... YOU JUST NEED SOMEBODY TO GIVE IT."
GOTO BOUGHT
@FLOWERS
PRINT "YOU BOUGHT SOME FLOWERS FOR YOUR GF."
PRINT "IT'S SO NICE TO HAVE HER."
PRINT "------------------- END -------------------"
END
@BOUGHT
MONEY=0
@CENTERASK
INPUT "STAY OR STREET?", MOVE$
IF MOVE$="STAY" THEN GOTO CENTER
IF MOVE$="STREET" THEN GOTO STREET
GOTO CENTERASK
@OUTSKIRTS
IF GF=1 THEN GOTO OUTASK
PRINT "YOU REMEMBER A GIRL YOU USED TO KNOW FROM"
PRINT "SCHOOL. MAYBE IT'S BECAUSE SHE LIVED HERE. OR"
PRINT "MAYBE IT'S BECAUSE YOU ALWAYS THINK OF HER"
PRINT "EVER SINCE."
@OUTASK
PRINT "YOU STAND RIGHT AT THE GIRL'S DOOR."
INPUT "KNOCK OR STREET?", MOVE$
IF MOVE$="KNOCK" THEN GOTO KNOCK
IF MOVE$="STREET" THEN GOTO STREET
GOTO OUTASK
@KNOCK
IF GF=1 THEN GOTO LOVE
PRINT "'HEY, IS THAT REALLY YOU? I REMEMBER"
PRINT "THE SHY GUY FROM SCHOOL. HAHA!'"
PRINT "YOU TALK A LITTLE. SHE ASKS ABOUT YOUR LIFE."
IF MONEY=0 THEN GOTO DECLINE
GF=1
PRINT "SHE TELLS YOU THAT SHE LIKES FLOWERS."
PRINT "SHE FEELS ALONE. SHE LIKES TO JUMP ON HER BED."
PRINT "SHE SHOWS HOW."
@LOVE
PRINT "YOU STAY UNTIL THE MORNING COMES."
@DECLINE
PRINT "SHE ASKS YOU TO LEAVE AS SHE HAS"
PRINT "IMPORTANT THINGS TO DO."
GOTO OUTASK
@SELL
PRINT "A BAD LOOKING MAN IS APPROACHING."
PRINT "HE WANTS TO SELL YOU STOLEN WEAPONS."
PRINT "HE WOULD BUY THINGS OF VALUE, TOO."
PRINT "YOU THINK OF SELLING THE PIGLET."
INPUT "SELL OR LEAVE?", MOVE$
IF MOVE$="SELL" THEN MONEY=1:PRINT "YOU GET A COIN."
GOTO STREET
Precedence
REM ^ LEVEL 1
PRINT 2 * 3^2:REM 18
PRINT (2*3)^2:REM 36
REM / * MOD LEVEL 2
PRINT 1 + 2*3:REM 7
PRINT (1+2)*3:REM 9
REM + - LEVEL 3
PRINT 6 < 10+2:REM 1
PRINT (6<10)+2:REM 3
REM <> >= > <= < LEVEL 4
PRINT 2 = 4<>3:REM 0
PRINT (2=4)<>3:REM 1
REM = LEVEL 5
PRINT 1 AND 3 = 1:REM 0
PRINT (1 AND 3)=1:REM 1
REM AND LEVEL 6
PRINT 1 OR 3 AND 2:REM 3
PRINT (1 OR 3)AND 2:REM 2
REM OR XOR LEVEL 7
PRINT 1, 2 OR 4:REM [1, 6]
REM , LEVEL 8
REM * OTHER OPERATORS ON THE SAME PRECEDENCE LEVELS *
PRINT 18 / 3^2:REM 2
PRINT 6 + 4/2:REM 8
PRINT 6 - 4/2:REM 4
PRINT 6 < 10-2:REM 1
PRINT 9 > 10-2:REM 1
PRINT 8 <= 10-2:REM 1
PRINT 8 >= 10-2:REM 1
PRINT 1 = 4>3:REM 1
PRINT 3 = 3<2:REM 0
PRINT 1 = 4>=4:REM 1
PRINT 0 = 1<=1:REM 0
Associativity
REM * ALL OPERATORS LEFT-ASSOCIATIVE (INCLUDING POWER, UNLIKE IN MATHS) *
PRINT 2^3^2:REM 64
PRINT 2^(3^2):REM 512
PRINT 100/20/5:REM 1
PRINT 100/(20/5):REM 25
PRINT 100-20-5:REM 75
PRINT 100-(20-5):REM 85
PRINT 3>2>1:REM 0 (FALSE) BECAUSE 3>2 GIVES 1 (TRUE), 1>1 GIVES 0 (FALSE)
PRINT 3>(2>1):REM 1 (TRUE) BECAUSE 2>1 GIVES 1 (TRUE), 3>1 GIVES 1 (TRUE)
The Unary Minus Sign
REM * UNARY MINUS HAS LOWER PRECEDENCE THAN POWER *
PRINT -2^2:REM -4
PRINT (-2)^2:REM 4
REM * UNARY MINUS HAS HIGHER PRECEDENCE THAN ADD OR SUBTRACT *
PRINT -2+2:REM 0
PRINT -(2+2):REM -4
PRINT "VERSE 1"
GOSUB CHORUS:REM GO TO SUBPROGRAM AT @CHORUS BUT COME BACK WHEN IT'S DONE
PRINT "VERSE 2"
GOSUB CHORUS:REM NOTE THAT THE SAME SUBPROGRAM CAN RETURN HERE, TOO
GOTO OUTRO
@CHORUS: PRINT "CHORUS"
RETURN:REM SUB IS OVER, GO BACK TO THE POINT AFTER GOSUB (THE RIGHT GOSUB)
@OUTRO: PRINT "OUTRO"
Alternative RETURN syntax has a label argument. In case the program would
run to such a RETURN instruction by accident, not because a GOSUB deliberately
jumped there, it would stop the program with error rather than continuing the
wrong flow.
PRINT "VERSE 1"
GOSUB CHORUS
PRINT "VERSE 2"
GOSUB CHORUS
GOTO OUTRO
@CHORUS: PRINT "CHORUS"
RETURN CHORUS:REM MAKES SURE IT RETURNS TO A GOSUB CHORUS INSTRUCTION
@OUTRO: PRINT "OUTRO"
PRINT "VERSE 1"
GOSUB CHORUS
PRINT "VERSE 2"
GOSUB CHORUS
PRINT "OUTRO"
END:REM PREVENTS RUNNING THE CHORUS AGAIN
@CHORUS: PRINT "CHORUS"
RETURN
PRINT "STEP 1"
STOP
PRINT "STEP 2"
STOP
PRINT "STEP 3"
REM * ENTER INTERACTIVE COMMAND CONT TO CONTINUE *
REM * ENTER INTERACTIVE COMMAND RUN TO START OVER *
REM * ?STATUS TO TELL STOP (1) FROM END (0) OR ERROR (-1) *
Here are all the interactive commands that you can use on the Runner Screen:
- RUN - run the program that is tokenized in the runner
- CONT - continue where the program exited (at a STOP instruction or if user hit Esc)
- LIST - change screen mode to Program Listing
- NEW - clear the program from both the Program Listing and runner
- OLD - restore the program after NEW
- DGNS - see Game Programming Tutorial
- Question mark: enter an expression following
? to see its value.
- By entering a programming instruction, you add a line to the end of the program
Wanna do something 10 times?
FOR I=1 TO 10:PRINT "THIS OLD MAN, HE PLAYED " + I:NEXT
What more can FOR loops do?
FOR I=0 TO 9
A$ = " "
REM * ANOTHER LOOP INSIDE THE LOOP *
REM * THE END OF THE LOOP IS AN EXPRESSION *
REM * THE COUNTER J WILL STEP DOWN *
FOR J=9 TO 9-I STEP -1
A$ = A$ + J
NEXT
PRINT A$
NEXT I
REM * THIS SYNTAX OF NEXT MAKES SURE THAT IT ENDS THE CORRECT LOOP: IF *
REM * THE PROGRAM FLOW ACCIDENTALLY HITS IT WHEN THERE IS NO LOOP FOR I *
REM * THEN INSTEAD OF CONTINUING THE WRONG FLOW, IT IMMEDIATELY STOPS *
FOR I=10 TO 45 STEP 10:PRINT I:NEXT
PRINT "LOOP EXITED WITH " + I
REM I NEVER GETS EXACTLY 45, LAST CYCLE STARTS WITH I=40, EXITS WITH I=50
REM * BREAKING THE LOOP EARLY *
INPUT "SELL YOUR STOCKS AFTER HOW MANY DAYS?", CUT
FOR I=1 TO RND(30)
PRINT "DAY "+I
PRINT "STOCKS HIGH":PRICE=I
IF I=CUT THEN I=30:NEXT:GOTO OUT
PRICE=1:PRINT "STOCKS LOW"
NEXT
@OUT
PRINT "STOCKS SOLD FOR "+PRICE
Evaluations:
- The TO expression is evaluated once when the FOR instruction is reached.
- The loop counter is checked against the evaluated TO value when NEXT is reached.
- Therefore: at the FOR instruction, the loop cannot exit
without entering the loop body. Which exit point (of the several NEXT
instructions) would it take? [Scientists'
Note]
When breaking a loop in an IF condition, make sure:
- that the loop counter is over the TO value – I=30
- to say NEXT so that the loop is cleaned up – NEXT
- to jump over all the other NEXT instructions – GOTO OUT
OK, the essentials are now done. You can jump to Game
Programming Tutorial if you are in a hurry. You'll be able to follow, but
some particular instructions you'll need to look up in this second part. There
are still some details about the language, so read on to learn them all.
Contents
REM * READ ASSIGNS THE NEXT VALUE FROM THE DATA LINE TO ITS ARGUMENT *
FOR I=1 TO 5:READ A:PRINT A:NEXT
DATA 2,3,5,7,11
READ A:READ B:A=9:READ C
PRINT A,B,C
DATA RND(8)
DATA A, A + 1
On READ A, first data line is evaluated, a random number gets generated.
On READ B, second data line evaluates (both elements of it at once.) Now variable A holds
the randomized number, so B gets the same value as A.
Then A=9 assignment happens.
C gets the already evaluated value, which is the random number plus 1 (the new value of A,
9, does not affect C's.)
Restore to the beginning
GOSUB POEM
PRINT "*"
GOSUB POEM
END
@POEM
RESTORE
REM * RESTORE INSTRUCTION MAKES SURE THE POEM STARTS WITH THE FIRST LINE *
REM * NO MATTER HOW MANY TIMES THE PROGRAM RUNS THE SUBPROGRAM *
FOR LINE=1 TO 5:READ L$:PRINT L$:NEXT LINE
RETURN
DATA "THERE WAS AN OLD MAN WITH A BEARD,"
DATA "WHO SAID, 'IT IS JUST AS I FEARED!"
DATA "TWO OWLS AND A HEN,", "FOUR LARKS AND A WREN,"
DATA "HAVE ALL BUILT THEIR NESTS IN MY BEARD!'"
Restore to a label
RESTORE WEEKEND
FOR I=1 TO 14
READ DAY$:PRINT DAY$ + " " + I
IF DAY$ = "SUN" THEN RESTORE
NEXT
END
DATA "MON", "TUE", "WED", "THU", "FRI"
@WEEKEND: DATA "SAT", "SUN"
Define an indexed array. An array is like a number of variables
because it has elements that hold a value each. But unlike variables, you
can refer to the elements using an index. This enables e.g. traversing the array
in a FOR loop, which you cannot do with individually named variables.
REM * BUBBLE SORT *
DIM ARRAY(10)
INPUT ARRAY(0)
FOR I=1 TO 9
READ ARRAY(I)
NEXT
FOR K=8 TO 0 STEP -1
FOR I=0 TO K
IF ARRAY(I)>ARRAY(I + 1) THEN NEXT I:GOTO OUT
SWAP = ARRAY(I)
ARRAY(I) = ARRAY(I + 1)
ARRAY(I + 1) = SWAP
NEXT I
@OUT
PRINT ARRAY(I)
NEXT K
PRINT ARRAY(0)
END
DATA 1, 2, 3, 5, 9, 8, 7, 4, 6
Note: DIM can also erase an already existing array.
Store a byte in the memory by address.
POKE 5000,6
REM 5000 IS THE ADDRESS, 6 IS THE BYTE
PRINT PEEK(5000)
Clear all variables and arrays. Built-in variables restored.
PI = 3.0
PRINT PI
INPUT "PRESS ENTER TO CONTINUE ", A
CLR
PRINT PI
REM BUILT-IN VARIABLE WITH THE INITIAL VALUE 3.141592653589793
Bytes in memory survive a CLR.
POKE 5000,6
CLR
PRINT PEEK(5000):REM 6
Define a function. Code repetition is a source of errors.
Here is a means of avoiding it.
LOG2 = LOG(2)
DEF LOG2(X) = LOG(X)/LOG2
X=10
PRINT LOG2(32)
PRINT X
CLR will erase user-defined functions, too.
DEF TWICE(N) = 2*N
DIM ARRAY(10)
CLR
DIM TWICE(10):REM NOT AN OVERDEFINITION
DEF ARRAY(N) = 2*N:REM NOT AN OVERDEFINITION
With IF instruction, you gave your program two possible continuation paths: one
to go when the condition is true, one if it is false. What if you want three
or more continuation paths, depending on a numeric expression?
INPUT "CHOOSE FROM MENU 1-3", CHOICE
ON CHOICE GOTO M1, M2, M3
@M1: PRINT "YOU CHOSE #1"
END
@M2: PRINT "YOU CHOSE #2"
END
@M3: PRINT "YOU DIDN'T CHOOSE 1 OR 2 BUT SOMETHING ELSE"
END
INPUT "CHOOSE FROM MENU 1-3", CHOICE
ON CHOICE GOSUB M1, M2, M3
GOTO START
@M1: PRINT "YOU CHOSE #1"
RETURN
@M2: PRINT "YOU CHOSE #2"
RETURN
@M3: PRINT "YOU DIDN'T CHOOSE 1 OR 2 BUT SOMETHING ELSE"
RETURN
A trick to save a line of code:
INPUT N
ON N>0 GOTO POSITIVE, NONPOSITIVE:REM IF N>0 IS TRUE, BRANCH 1 IS SELECTED
@POSITIVE:PRINT "POSITIVE":END
@NONPOSITIVE:PRINT "NONPOSITIVE":END
INPUT N
IF N>0 THEN GOTO POSITIVE
GOTO NONPOSITIVE:REM THIS NEEDS TO BE ON A SEPARATE LINE
@POSITIVE:PRINT "POSITIVE":END
@NONPOSITIVE:PRINT "NONPOSITIVE":END
You may use the comma operator in the array index to create a matrix.
DIM MANCALA(6,2)
MANCALA(4,1) = 0
MANCALA(5,1) = MANCALA(4,1)+1
Nullary
D12 = RND(12)+1
PRINT D12
REM * GIVES 12 JUST AS OFTEN AS 7 *
INPUT XX
CLR
D12 = RND(6)+RND(6)+2
REM * RANDOM WITH THE DISTRIBUTION OF ROLLING 2 REGULAR DICE *
PRINT D12
PRINT D12
PRINT D12
REM * EVALUATION HAPPENS ONCE, SAME NUMBER IS PRINTED 3 TIMES *
INPUT XX
CLR
DEF D12()=RND(6)+RND(6)+2
REM * NULLARY FUNCTION *
PRINT D12()
PRINT D12()
PRINT D12()
REM * ROLLS THREE TIMES *
Higher Arities
DEF MAX(A,B)=(A>=B)*A+(A<B)*B
PRINT MAX(-3,MAX(5/2,8/4))
REM
* T. IS SHORT FOR THEN *
REM
* G. IS SHORT FOR GOTO *
REM
* N. IS SHORT FOR NEXT *
REM
* R. STANDS FOR RETURN *
REM
* W. (COVERED LATER) *
'
OH, AND YOU CAN USE APOSTROPHE INSTEAD OF REM INSTRUCTION
INPUT "ENTER REQUESTED INDIAN COUNT", N '
NO NEED FOR A COLON
IF N>10 T.G.HANDLER
S$=""
FOR I=1 TO N
GOSUB INDIAN
S$="S"
N.
END
@HANDLER:
PRINT "TOO MANY INDIANS"
STOP
@INDIAN:
PRINT I+" LITTLE INDIAN"+S$
R.
Do you know the stack data structure? You can use it like this:
PUSH 1:PUSH 2:PUSH 3
PULL C:PULL B:PULL A 'REVERSE ORDER
PRINT A,B,C
REM * SEND OVER SOMETHING TO A SUB VIA STACK *
PUSH "MESSAGE"
GOSUB SHOW
END
@SHOW
PULL RA 'AFTER GOSUB THE RETURN ADDRESS IS ON THE STACK TOP!
PULL M$ 'HERE IS YOUR MESSAGE
PUSH RA 'BEFORE RETURN, YOU NEED TO PUT BACK THE ADDRESS THAT WAS THERE
PRINT M$
RETURN
PUSH and PULL may mess up running of other instructions if they are not used
in pairs. Use them at your own risk.
Motivation
This technique allows recursive calls.
DIM PEG$(3)
PEG$(1)=" A:4321"
PEG$(2)=" B:"
PEG$(3)=" C:"
PRINT PEG$(1) + PEG$(2) + PEG$(3)
STEP=1
N=4:SOURCE=1:VIA=3:TARGET=2:GOSUB MOVE
END
@MOVE
IF N=0 THEN RETURN
PUSH N:PUSH SOURCE:PUSH VIA:PUSH TARGET
N=N-1:S=VIA:VIA=TARGET:TARGET=S:GOSUB MOVE
PULL TARGET:PULL VIA:PULL SOURCE:PULL N
PEG$(TARGET)=PEG$(TARGET)+RIGHT$(PEG$(SOURCE), 1)
PEG$(SOURCE)=LEFT$(PEG$(SOURCE), LEN(PEG$(SOURCE))-1)
M$ = STEP + ". MOVE DISC FROM " + CHR$(64+SOURCE) + " TO "
PRINT M$ + CHR$(64+TARGET) + ":" + PEG$(1) + PEG$(2) + PEG$(3)
STEP = STEP + 1
PUSH N:PUSH SOURCE:PUSH VIA:PUSH TARGET
N=N-1:S=SOURCE:SOURCE=VIA:VIA=S:GOSUB MOVE
PULL TARGET:PULL VIA:PULL SOURCE:PULL N
RETURN
ILLEGAL EXPRESSION
PRINT "A"-1
CLR
PRINT NOSUCH
DATA XX+1, YY+1
XX=0
READ Y:REM TRIES TO EVALUATE THE WHOLE DATA LINE, INCLUDING YY+1
YY=0:REM TOO LATE
DIM A$(8)
A$(1) = ""
PRINT A$(1):REM FINE
PRINT A$(2):REM NO VALUE
REM * MAKE SURE YOU INITIALIZE ALL MEMBERS OF YOUR ARRAY BEFORE USE *
DIM A$(15)
A$(1) = "V"
DIM A$(25)
PRINT A$(1):REM LOST IN RE-DIM
INVALID REFERENCE
CLR
INPUT UNARRAY(0)
SIN(0) = 0
NEXT WITHOUT FOR
FOR I=0 TO 10
IF I=5 THEN I=10:NEXT
REM * WHAT HAPPENS WHEN I=5? IF CONDITION MET, I GETS 10 *
REM * NEXT ABOVE WILL TERMINATE THE LOOP AND CONTINUE HERE *
REM * THE OTHER NEXT WILL ALSO RUN BUT THERE IS NO LOOP ANYMORE *
NEXT
RETURN WITHOUT GOSUB
GOSUB SUB
REM * NOTE: AFTER RETURNING FROM THE SUB, PROGRAM CONTINUES HERE *
@SUB
RETURN
LOOP MISMATCH
FOR I=1 TO 10:NEXT J
CALL MISMATCH
GOSUB SUBX
END
@SUBX
PRINT "SUB X ENTERED"
@SUBY
PRINT "SUB Y ENTERED"
RETURN SUBY
OVERDEFINITION
DIM SIN(10)
DEF FN(PM)=-PM
DIM FN(10)
DIM ARR(10)
DEF ARR(X)=-X
OUT OF DATA
REM * OOPS, OFF BY ONE *
FOR I=0 TO 10:READ X:NEXT
DATA 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
LABEL DOES NOT EXIST
GOTO PI
GOSUB PI
RESTORE PI
NO DATA AT LABEL
RESTORE LABEL
@LABEL:PRINT "NOT A DATA INSTRUCTION"
DATA 1
DIVIDE BY ZERO
A = 1/0
This programming language is inspired by C64 BASIC V2.
Inspiration means that:
- Those who know C64 BASIC V2 will find it easy to learn.
- Program flow and instructions are on the same abstraction level.
But not:
- Easy portability of programs between both.
- Any intent to converge to C64 in the future versions of imeight.
- That they would be comparable in performance.
In other words, imeight is not what C64 was, it is what it should have been.
List of Intentional Differences
Dollar or percent sign at the end of names is a convention
A% = "HELLO"
A$ = 3
REM * BOTH WORK BUT DISCOURAGED *
The full name of the variable identifies
VAR1 = 1:VAR2 = 2:REM TWO DISTINCT VARIABLES HERE
PRINT VAR1,VAR2
Use spaces to separate names from operators
SCORE = 30
SC = 1:E = 2
PRINT SCORE:REM 30
PRINT SC OR E:REM 3
Dimensions in DIM is documentation of intended indexing. It does not limit the
usage of the array as it is _not_ memory allocation. Programmer may use
zero-based or one-based indexing, interpret DIM numbers as maximal index or
number of elements... to taste.
DIM A(2)
A(-1)=0
A(8)=0
A(2,1)=0
REM * ALL OF THE ABOVE IS LEGAL ALTHOUGH THE CODE IS MISLEADING *
More differences that are already mentioned:
OK, that was boring. Fortunately this imaginary little machine has all the
necessary stuff for action game programming, too. You'll need controls,
timing and graphics. Let's go!
Contents
WAIT instruction halts execution of your program until one of the
events occur:
- A button on the keyboard is hit or released. Note that in the emulator, you
need to focus (click) on the Runner Screen to get keystroke events.
- Clock ticks. It constantly ticks every 20 milliseconds. So a WAIT
instruction returns after 20 milliseconds max, depending on what moment
it started to run. E.g. just after another WAIT, it's exactly 20 ms.
GET instruction assigns the key code of the key hit on the keyboard to the
variable in argument. Consecutive GETs will process the key hits in
chronological order.
Key codes:
- If no button has been hit (since all of the events had been processed by GET
instructions) then GET assigns the value 0.
- Letter buttons have key codes 65 through 90, according to ASCII.
- Number buttons have key codes 48 through 57, according to ASCII.
- Numpad is differentiated, encoded 96 to 105.
- 32 is Space bar, 27 means Escape button, 13 is Enter, 9: Tab.
- Shift and Ctrl buttons - 16 and 17, respectively.
- Function keys 112-123 (those may activate functions in your browser, too.)
- When Shift or Ctrl is still pressed while another key is hit, .5 or .25 is
added to its key code, respectively.
- On release, the negated key code is assigned by GET.
SECS=10:AN=10
PRINT "ENTER "+AN+" ANIMALS IN "+SECS+" SECONDS"
T$="":TICKS=0
@LOOP:GET KEY
IF KEY=27 THEN PRINT "GIVEN UP?":END
IF KEY<=0 THEN WAIT:TICKS=TICKS+1
IF KEY>31 AND 128>KEY THEN T$=T$+CHR$(KEY)
IF KEY=13 THEN AN=AN-1:PRINT T$+" ACCEPTED, "+AN+" STILL TO GO!":T$=""
IF AN=0 THEN PRINT "YOU WIN.":END
IF TICKS>50 THEN SECS=SECS-1:PRINT SECS+" SECONDS LEFT...":TICKS=0
IF SECS=0 THEN PRINT "YOU LOSE.":END
GOTO LOOP
Motivation
Busy loops without any WAIT in them run for times highly dependent on the
configuration that runs the program.
REM * PROCESSOR HEATING CODE RUNS FOR 1 S ON MY LAPTOP, HOW ABOUT YOURS? *
FOR I=0 TO 2600000:NEXT
FOR I=0 TO 50:WAIT:NEXT
'CPU IS COOLER AND PROGRAM RUNS FOR 1 SECOND
Clearing Past Events
FOR I=1 TO 500:WAIT:N. '
WAIT 10 SECS: USER MAY HIT KEYS MEANWHILE
PRINT "HIT A BUTTON NOW:"
@GETLOOP:WAIT:GET A '
PROGRAMMER MAY THINK THIS WAIT AND GET BELONG TOGETHER
IF A=0 T.G.GETLOOP
PRINT A
REM
* KEY CODE OF FIRST HIT SINCE PROGRAM START GETS PRINTED *
REM
* NOT NECESSARILY ONE HIT WHILE WAITING AT GETLOOP *
FOR I=1 TO 500:WAIT:N.
@ZAP:GET A:IF A<>0 THEN GOTO ZAP '
CLEAR ALL PAST EVENTS
PRINT "HIT A BUTTON NOW:"
@LOOP:WAIT:GET A '
NOW THIS WILL GET A YOUNG EVENT
IF A=0 T.G.LOOP
PRINT A
FOR I=1 TO 500:WAIT:N.
CLR '
CLEAR ALL PAST EVENTS (AND ALL VARIABLES ETC.)
PRINT "HIT A BUTTON NOW:"
@LOOP:WAIT:GET A
IF A=0 T.G.LOOP
PRINT A
FOR I=1 TO 50:W.:N. 'WAIT >980 BUT <=1000 MILLISECONDS
PRINT TIME() 'MILLISECONDS SINCE EPOCH, 1 JAN 1970
PRINT TIME$(0) 'THE EPOCH IN A HUMAN READABLE FORMAT
PRINT TIME$(TIME()) 'CURRENT DATE AND TIME, UTC
FOR I=0 TO 50:W.:N. 'WAIT (MORE THAN) A SECOND...
PRINT TIME$() 'CURRENT DATE AND TIME, SHORTER WAY
REM * LAST TWO LINES SHOULD DIFFER IN 1 SECOND *
Timing for less than 20 milliseconds:
UNTIL=TIME()+10 '10 MILLISECONDS FROM NOW
@BUSY:IF TIME()<UNTIL T.G.BUSY
Time Zones
PRINT TIME$(TIME()+2*3.6E6) 'IN B TIME ZONE OFFSET
PRINT TIME$(TIME()+TZO) 'IN LOCAL TIME ZONE OFFSET
My First Animation
SPRX(0)=180+160*COS(TIME()/600)
SPRY(0)=96+60*SIN(TIME()/300)
WAIT
GOTO START
Finally we can and see some graphics on the Runner Screen.
SPRX and SPRY are built-in arrays. SPRX(K) for every K would mean the
horizontal coordinate of the sprite K; SPRY(K) is the vertical
coordinate of the same. Coordinates are in pixels, horizontal coordinate
0 is the left edge of the screen, screen is 384 pixels wide. Y coordinates
go from top to bottom, screen is 216 pixels high. The sprite itself is 24 by 24
pixels.
Physical Animations
SCREENWIDTH=384:SCREENHEIGHT=216
'
START IN THE MIDDLE OF THE SCREEN
SPRX(0)=SCREENWIDTH/2-12:SPRY(0)=SCREENHEIGHT/2-12
@HIT '
HIT THE BALL IN A RANDOM DIRECTION
SPEEDX=RND(40)/10-2:SPEEDY=RND(40)/10-2 '
PIXELS PER 20 MILLISECONDS
@LOOP
'
ADVANCE BALL POSITION ACCORDING TO SPEED
SPRX(0)=SPRX(0)+SPEEDX
SPRY(0)=SPRY(0)+SPEEDY
'
BOUNCE ON SCREEN EDGES
IF SPRX(0) <= 0 OR SPRX(0) >= SCREENWIDTH-24 THEN SPEEDX = -SPEEDX
IF SPRY(0) <= 0 OR SPRY(0) >= SCREENHEIGHT-24 THEN SPEEDY = -SPEEDY
WAIT:GET A
ON A>0 GOTO HIT, LOOP 'LOOP IF KEY CODE<=0; GOES TO HIT OTHERWISE
The above algorithm appears in Billiard games, Pong or Breakout.
WT=384:HT=216
DIM SPEEDX(99):DIM SPEEDY(99)
N=0
@SPAWN
N=N+1
SPRX(N)=0:SPRY(N)=0
SPEEDX(N)=RND(30)/10:SPEEDY(N)=0
@LOOP
FOR I=1 TO N
IF SPRY(I) < 0 THEN NEXT:GOTO OUT
SPRX(I)=SPRX(I)+SPEEDX(I)
SPRY(I)=SPRY(I)+SPEEDY(I)
IF SPRX(I) <= 0 OR SPRX(I) >= WT-24 THEN SPEEDX(I) = -SPEEDX(I)
'
STOP A DEAD BALL
IF SPRY(I) >= HT-24 AND ABS(SPEEDY(I)) < .5 THEN SPRY(I)=-24
'
BOUNCE FROM THE GROUND AND LOSE SOME ENERGY
IF SPRY(I) >= HT-24 THEN SPEEDY(I) = -SPEEDY(I)*.9
'
ADD GRAVITY
IF SPRY(I) >= 0 THEN SPEEDY(I)=SPEEDY(I)+.1
NEXT:@OUT
WAIT:GET A
ON A>0 GOTO SPAWN, LOOP
Combine bouncing with gravity for an effect like in Flipper, ballistic
games. A jumping character can as well be animated using gravity like above.
Note that setting a coordinate to -24 makes the sprite invisible.
Issue the command DGNS on the Runner Screen to see the names of all built-in
designs for your sprites. Use them like this:
SPRDGN(0)=DGNMAN():SPRX(0)=0:SPRY(0)=0 'MAN IS A BUILT-IN DESIGN
SPRDGN(1)=DGNWALL():SPRX(1)=0:SPRY(1)=24 'SO IS WALL
How about some art?
Design your own sprites in the Design Util screen mode. You will see 227 slots
for designs in the Memory Map. Just choose slots, colors, and paint using the
mouse. Once done, copy the number from below the Memory Map, and set SPRDGN(K)
to that number in the program.
REM ASSUMING YOU DREW SOMETHING INTO SLOT 2 IN THE DESIGNER
SPRX(5)=0:SPRY(5)=0 'THE UPPER LEFT CORNER
SPRDGN(5)=288 'THE SECOND DESIGN FROM THE MEMORY
Find one bug in the list below. Correct it and have fun.
WT=384:HT=216 'SCREEN WIDTH AND HEIGHT
BORINGNESS=10
REM SPRITES
REM 0 TO 9: ROAD LEFT SIDE
REM 10 TO 19: ROAD RIGHT SIDE
REM 20: CAR UNDER CONTROL
REM 21 AND ON: SPARE LIVES DISPLAYED
REM LAST: CRASHED CAR
@INIT
SPRX(20)=WT/2:SPRY(20)=180:SPRDGN(20)=DGNCAR()
FOR I=0 TO 9
SPRX(I)=WT/4:SPRX(I+10)=WT/4*3
SPRY(I)=I*24-23:SPRY(I+10)=SPRY(I)
SPRDGN(I)=DGNDUST():SPRDGN(I+10)=DGNDUST()
N.
FOR I=1 TO LIFE:SPRX(20+I)=0:SPRY(20+I)=I*26-25:SPRDGN(20+I)=DGNCAR():N.
SPRY(21+LIFE)=0:SPRX(21+LIFE)=-24:SPRDGN(30)=DGNCAR()
ROADWT=WT/4 'CURRENT ROAD WIDTH IN 2-PIXEL UNITS
CARVX=0:CARVY=0 'VELOCITY COMPONENTS
DIRY=2
PRINT "HIT UP ARROW TO ACCELERATE"
PRINT "HIT LEFT OR RIGHT ARROW TO STEER"
@CONTROL
WAIT:GET A
IF A=-38 THEN CARVY=CARVY+1 'UP
IF CARVY<1 T.G.CONTROL 'WAIT FOR THE PLAYER TO START THE GAME
IF A=37 THEN CARVX=-CARVY 'LEFT
IF A=39 THEN CARVX=CARVY 'RIGHT
IF A=-37 OR A=-39 THEN CARVX=0 'RELEASE
SPRX(20)=SPRX(20)+CARVX 'CAR MOVES ACCORDING TO CONTROL
FOR TM=1 TO CARVY
SPRY(21+LIFE)=SPRY(21+LIFE)+1 'LEAVE CRASHED CAR BEHIND
FOR I=0 TO 9
SPRY(I)=SPRY(I)+1:SPRY(I+10)=SPRY(I) 'MOVE ROAD DOWN ON SCREEN
IF SPRY(I)<HT T.G.ROLLEND '24 RASTERS SCROLLED OUT?
OLDTOP=I+1:IF OLDTOP>9 THEN OLDTOP=0 'WHICH SPRITES WERE ON SCREEN TOP?
DIRY=DIRY-1 'Y COORDINATE OF WHERE THE ROAD IS HEADING
IF RND(DIRY)=0 THEN DIRX=RND(WT-2*ROADWT)+ROADWT:DIRY=16 'CHANGE HEADING
SPRY(I)=-23:SPRY(I+10)=-23 'REUSE THE SPRITES SCROLLED OUT
IF ROADWT>40 AND RND(BORINGNESS)=0 THEN ROADWT=ROADWT-2 'LEVEL UP
SPRX(I)=(DIRX-ROADWT-SPRX(OLDTOP))/DIRY+SPRX(OLDTOP) 'LINEAR STEP
SPRX(I+10)=SPRX(I)+2*ROADWT
@ROLLEND
IF SPRY(I)<=SPRY(20)-24 OR SPRY(I)>=SPRY(20)+24 T.G.COLLIDEEND
IF SPRX(20)>=SPRX(I)+24 AND SPRX(20)<=SPRX(I+10)-24 T.G.COLLIDEEND
PRINT "BUMP!"
LIFE=LIFE-1
IF LIFE<0 THEN PRINT "CRASH!":GOTO OVER
GOSUB DIE:CARVY=1
@COLLIDEEND
N.:N.
GOTO CONTROL
@DIE
XMID=(SPRX(I)+SPRX(I+10))/2
DX=XMID/16
DY=(SPRY(20)-SPRY(21+LIFE))/16
FOR J=0 TO 15
SPRX(21+LIFE)=SPRX(21+LIFE)+DX+SIN(J*PI/8)*16
SPRY(21+LIFE)=SPRY(21+LIFE)+DY
WAIT:WAIT
N.
REM CRASHED CAR APPEARS WHERE CAR UNDER CONTROL WAS
SPRX(21+LIFE)=SPRX(20):SPRY(21+LIFE)=SPRY(20)
SPRX(22+LIFE)=-24 'CAR CRASHED EARLIER STILL ON SCREEN?
SPRX(20)=XMID 'THE CONTROLLED CAR KEEPS INDEX 20
R.
@OVER
FOR I=1 TO 200:W.:N.
INPUT BACKGROUND 'YET ANOTHER BUILT-IN VARIABLE
Color |
Dark |
Light |
black/gray |
0 | |
8 | |
red |
1 | |
9 | |
green |
2 | |
10 | |
yellow |
3 | |
11 | |
blue |
4 | |
12 | |
magenta |
5 | |
13 | |
cyan |
6 | |
14 | |
gray/white |
7 | |
15 | |
You can use POKE instructions to redesign the sprite while the program is
running. With love for fellow coordinate geometry lovers.
DEF NEAR(A,B)=(A-B)^2<2 'DO NOT USE = TO COMPARE FLOATS
SPRX(0)=180:SPRY(0)=96 'CENTER
SPRDGN(0)=0
@LOOP
WAIT:WAIT 'RECALCULATE ONCE PER SCREEN REFRESH
X=COS(TIME()/318):Y=SIN(TIME()/318) 'MOVE X,Y IN CIRCLES OVER TIME
FOR R=0 TO 23 'FOR ALL ROWS OF THE DESIGN
FOR C=0 TO 23 STEP 2 'FOR EVERY 2ND COLUMN OF IT
HI=0:LO=0 'HIGH AND LOW NIBBLE OF THE DESIGN BYTE
FOR A=-11 TO 11 STEP 2 'PARAMETER OF THE LINE'S EQUATION
IF NEAR(C, X*A+12) AND NEAR(R, Y*A+12) THEN HI=10*16
IF NEAR(C+1, X*A+12) AND NEAR(R, Y*A+12) THEN LO=10
NEXT
POKE 12*R+INT(C/2),HI OR LO 'PUT PIXELS
NEXT
NEXT
GOTO LOOP
And another animation technique here, using a set of prepared designs,
swapping the design pointer of one sprite rapidly.
FOR I=0 TO 5*288-1:
READ B:POKE I,B:NEXT
SPRY(0)=192
F=0:X=-23
@LOOP
SPRDGN(0)=INT(F)*288
SPRX(0)=X
X=X+1:IF X>384 THEN X=-23
F=F+0.334:IF F>5 THEN F=0
WAIT:WAIT
GOTO LOOP
DATA 0,0,0,0,0,221,208,0,0,0,0,0,0,0,0,0,13,0,221,0,0,0,0,0,0,0,0,0,13,0,0,208,0,0,0,0,0,0,0,0,13,0,13,208,0,0,0,0,0,0,0,0,0,208,208,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,13,221,0,0,0,0,0,0,0,0,0,0,221,0,208,0,0,0,0,0,0,0,0,13,0,208,13,13,0,0,0,0,0,0,0,13,0,208,13,221,208,0,0,0,0,0,0,13,0,208,13,0,0,0,0,0,0,0,0,13,221,0,221,0,0,0,0,0,0,0,0,13,13,0,0,208,0,0,0,0,0,0,0,0,0,221,208,13,208,0,0,0,0,0,0,0,13,13,13,208,13,0,0,0,0,13,221,221,208,208,0,13,208,208,0,0,0,13,0,0,13,0,0,0,13,13,0,0,0,13,13,221,208,0,0,0,13,13,221,0,0,13,13,0,0,0,0,0,0,208,13,0,0,0,208,0,0,0,0,0,0,221,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,221,208,0,0,0,0,0,0,0,0,0,13,0,221,0,0,0,0,0,0,0,0,0,13,0,0,208,0,0,0,0,0,0,0,0,13,0,13,208,13,0,0,0,0,0,0,0,0,208,208,0,221,0,0,0,0,0,0,0,0,13,0,0,13,0,0,0,0,0,0,221,221,221,0,0,208,0,0,0,0,0,0,208,13,0,221,221,208,0,0,0,0,0,0,208,0,208,13,0,0,0,0,0,0,0,0,221,0,208,13,0,0,0,0,0,0,0,0,208,0,208,13,0,0,0,0,0,0,0,0,0,13,0,13,0,0,0,0,0,0,0,0,0,13,0,0,208,0,0,0,0,0,0,0,0,0,221,0,13,0,0,0,0,0,0,13,208,13,13,221,0,208,0,0,0,0,0,208,13,208,208,0,208,13,0,0,0,0,0,208,208,13,0,0,13,13,0,0,0,0,13,13,13,208,0,0,13,13,0,0,0,0,13,208,0,0,0,0,13,13,0,0,0,0,0,0,0,0,0,0,13,13,221,0,0,0,0,0,0,0,0,0,13,0,13,0,0,0,0,0,0,0,0,0,13,221,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0
REM
TOE IS AT X=15, Y=23 IN FRAME #2
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,221,208,0,0,0,0,0,0,0,0,0,13,0,221,0,0,0,0,0,0,0,0,0,13,0,0,208,0,0,0,0,0,0,0,0,13,0,13,208,0,0,0,0,0,0,0,0,0,208,208,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0,221,0,0,0,0,0,0,0,0,0,0,13,0,221,0,0,0,0,0,0,0,0,0,13,208,13,0,0,0,0,0,0,0,0,0,208,208,13,13,0,0,0,0,0,0,0,0,208,208,13,221,208,0,0,0,0,0,0,0,13,0,13,0,0,0,0,0,0,0,0,0,13,0,13,0,0,0,0,0,0,0,0,0,0,208,0,208,0,0,0,0,0,0,0,0,0,221,0,208,0,0,0,0,0,0,0,0,0,208,208,13,0,0,0,0,0,0,0,0,0,13,13,13,0,0,0,0,0,0,0,0,13,208,13,0,208,0,0,0,0,0,0,221,208,13,221,13,0,0,0,0,0,0,0,208,13,208,208,13,0,0,0,0,0,0,0,208,208,0,208,208,0,0,0,0,0,0,0,221,0,13,0,13,0,0,0,0,0,0,0,0,0,13,221,221,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,221,208,0,0,0,0,0,0,0,0,0,13,0,221,0,0,0,0,0,0,0,0,0,13,0,0,208,0,0,0,0,0,0,0,0,13,0,13,208,0,0,0,0,0,0,0,0,0,208,208,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0,221,0,0,0,0,0,0,0,0,0,0,13,208,221,0,0,0,0,0,0,0,0,0,13,208,13,0,0,0,0,0,0,0,0,0,13,208,13,0,0,0,0,0,0,0,0,0,13,208,13,208,0,0,0,0,0,0,0,0,13,221,221,221,0,0,0,0,0,0,0,0,13,0,13,0,0,0,0,0,0,0,0,0,0,208,0,208,0,0,0,0,0,0,0,0,0,208,0,208,0,0,0,0,0,0,0,0,0,221,0,221,0,0,0,0,0,0,0,0,0,13,0,208,208,0,0,0,0,0,0,0,221,208,0,208,208,0,0,0,0,0,0,0,208,208,13,221,0,0,0,0,0,0,0,0,221,0,208,0,0,0,0,0,0,0,0,0,221,13,208,0,0,0,0,0,0,0,0,0,221,0,13,0,0,0,0,0,0,0,0,0,13,221,221,0,0,0,0,0
REM
TOE IS AT X=9, Y=23 IN FRAME #4
REM
TO KEEP FOOT ON THE GROUND, MOVE THE SPRITE 3 PIXELS AHEAD PER FRAME
DATA 0,0,0,0,0,221,208,0,0,0,0,0,0,0,0,0,13,0,221,0,0,0,0,0,0,0,0,0,13,0,0,208,0,0,0,0,0,0,0,0,13,0,13,208,0,0,0,0,0,0,0,0,0,208,208,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,13,221,0,0,0,0,0,0,0,0,0,0,13,208,208,0,0,0,0,0,0,0,0,0,208,208,13,0,0,0,0,0,0,0,0,0,208,208,13,0,0,0,0,0,0,0,0,0,13,208,13,208,0,0,0,0,0,0,0,0,13,221,221,221,0,0,0,0,0,0,0,0,13,0,0,208,0,0,0,0,0,0,0,0,0,221,208,13,208,0,0,0,0,0,0,0,13,13,13,208,13,0,0,0,0,0,0,0,13,13,0,13,0,208,0,0,0,0,0,0,208,208,0,13,0,208,0,0,0,0,0,0,208,208,0,208,13,0,0,0,0,0,0,13,13,0,13,13,208,0,0,0,0,0,0,13,13,0,13,0,208,0,0,0,0,0,0,208,208,0,0,208,13,0,0,0,0,0,13,0,208,0,0,13,208,0,0,0,0,0,0,208,13,0,0,0,0,0,0,0,0,0,0,13,221,0,0,0,0,0,0,0
REM
NORMALLY YOU WOULD USE THE DESIGNER TO PREDESIGN ANIMATION FRAMES
REM
BUT IN THIS TUTORIAL, IT'S EASIER TO COPY INSTRUCTIONS THAN MEMORY
You can put any number of sprites on screen... but it may become cumbersome
to move a lot of them together. A typical example is when you have a
scrolled maze, platform or background in the game. For that purpose, we have
smoothly scrollable grid of tiles.
DIM MAZE(16,16)
FOR RO=0 TO 15:FOR CO=0 TO 15
READ MAZE(RO,CO)
N.:N.
TILEX=0:TILEY=0 '
BUILT-IN VARIABLE - TRANSLATES THE WHOLE GRID OF DESIGNS
OX=0:OY=7
FOR X=0 TO 15:FOR Y=0 TO 8
TILE(Y,X)=-1 '
BUILT-IN ARRAY OF DESIGN POINTERS
IF MAZE(Y+OY,X+OX) THEN TILE(Y,X)=DGNWALL()
N.:N.
@TRIG:WAIT:GET A:IF A<=0 THEN GOTO TRIG
REM
SMOOTH SCROLLING OF TILES
FOR OY=OY-1 TO 0 STEP -1
FOR X=0 TO 15:FOR Y=9 TO 1 STEP -1
TILE(Y,X)=TILE(Y-1,X) '
MOVE EVERY TILE A ROW LOWER
N.:N.
FOR X=0 TO 15 '
GET A NEW ROW FROM THE ARRAY
TILE(Y,X)=-1
IF MAZE(Y+OY,X+OX) THEN TILE(Y,X)=DGNWALL()
N.
TILEY=-23 '
TILES ARE A ROW = 24 RASTERS LOWER THAN BEFORE, MAKE IT 1
FOR SM=0 TO 23 '
SCROLL RASTER BY RASTER UNTIL A ROW GOES OFF SCREEN
WAIT:WAIT
TILEY=TILEY+1
NEXT
NEXT
TILEY=0
FOR I=0 TO 20:WAIT:WAIT:NEXT
END
REM
GENERATED: https://sourceforge.net/p/imeight/wiki/Routines/
DATA 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
DATA 1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1
DATA 1,0,1,0,1,0,1,1,1,0,0,0,0,0,1,1
DATA 1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1
DATA 1,0,1,1,1,1,0,1,1,0,1,0,1,0,1,1
DATA 1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1
DATA 1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1
DATA 1,1,1,0,1,0,1,0,1,0,1,0,1,0,0,1
DATA 1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1
DATA 1,0,0,1,0,1,0,1,0,1,1,1,1,0,0,1
DATA 1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1
DATA 1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1
DATA 1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1
DATA 1,1,0,1,0,1,1,0,1,1,0,0,0,1,0,1
DATA 1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1
DATA 1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1
TILE array is indexed with row and column number. If you fill it with
design pointers similar to those of SPRDGN, a grid of designs will appear on
the graphical screen, altogether offset by the values in variables TILEX and
TILEY. Smooth scrolling means to change the TILEX or TILEY in small steps.
PRINT vs. TEXTLINE$
Each time a PRINT instruction runs, it prints to the text layer. It is convenient if
you need to print one line below the other.
For positioning text to a certain line on the screen though is more convenient by
TEXTLINE$ array. Lines visible are indexed 0 through 26, and an extra line, number 27,
can be made visible by setting TEXTY=-8. TEXTLINE$ elements may be longer than the
visible line, which is 48 characters: extra characters are stored in the array but
won't appear on screen.
Font
Try pressing the MODE link in the Design Util. It changes the purpose of the
selected memory slot. It cycles through the following modes:
- Sprite or tile design mode
- Font design mode, pad 1: alphanumeric characters
- Font design mode, pad 2: remaining characters
- Hexadecimal mode for copy-pasting memory content
Draw characters in font mode, set FONTALNUM variable to the address of the
slot and see the letters and numbers appear in your design.
Font can be embedded in the program text using DATA instructions.
Demo below with smooth scroll:
FOR I=0 TO 287:READ B:POKE I,B:NEXT
FONTALNUM=0 'USER-DEFINED ALPHANUMERIC FONT
TEXTCOLORUC=7 'APPLIES TO UPPERCASE LETTERS
TEXTCOLORLC=15 'APPLIES TO CHARACTERS C$ WHERE ASC(C$) AND $20 <> 0
TEXTX=0
TEXTY=0
TEXTLINE$(13)=" HELL0"
@L:FOR TEXTX=0 TO -7 STEP -1:WAIT:WAIT:NEXT
TEXTLINE$(13)=RIGHT$(TEXTLINE$(13), LEN(TEXTLINE$(13))-1)
IF LEN(TEXTLINE$(13)) > 0 T.G.L
REM REDEFINING THE ZERO IN BINARY
DATA %01111100
DATA %11000110
DATA %11001110
DATA %11010110
DATA %11100110
DATA %11000110
DATA %01111100
DATA %00000000
REM REST OF THE FONT IS A COPY OF THE DEFAULTS
DATA 56,24,24,24,24,24,126,0,252,6,6,124,192,192,254,0,252,6,6,124,6,6,252,0,12,28,60,108,204,254,12,0,254,192,192,252,6,6,252,0,124,192,192,252,198,198,124,0,254,6,12,24,24,48,48,0,124,198,198,124,198,198,124,0,124,198,198,126,6,6,124,0,124,198,198,198,254,198,198,0,252,198,198,252,198,198,252,0,124,198,192,192,192,198,124,0,248,204,198,198,198,198,252,0,254,192,192,252,192,192,254,0,254,192,192,252,192,192,192,0,124,192,192,222,198,198,126,0,198,198,198,254,198,198,198,0,126,24,24,24,24,24,126,0,30,6,6,6,6,198,124,0,198,204,216,252,198,198,198,0,192,192,192,192,192,192,254,0,130,198,238,214,198,198,198,0,134,198,230,214,206,198,194,0,124,198,198,198,198,198,124,0,252,198,198,198,252,192,192,0,124,198,198,194,218,124,24,14,252,198,198,252,216,204,198,0,124,198,192,124,6,198,124,0,126,24,24,24,24,24,24,0,198,198,198,198,198,198,124,0,198,198,198,108,108,56,16,0,198,198,198,214,214,238,68,0,198,198,108,56,108,198,198,0,102,102,102,60,24,24,24,0,126,6,12,24,48,96,126,0
WAIT and GET instructions also deal with mouse and touch events. WAIT
stops waiting when a mouse button is pressed or released, much like in the case
of a keyboard button. Instead of a key code, GET will assign 1 to the variable
when a mouse button is pressed, -1 when released.
When the user touches the touch screen, WAIT stops as well. GET assigns a
code greater than 255 to identify the touch point. When that same touch ends,
the opposite of its code gets assigned.
Use the code that you GET to index TOUCHX and TOUCHY functions for the
coordinates of each touch point. TOUCHX(1) and TOUCHY(1) consequently return
the mouse position.
Both TOUCHX and TOUCHY will return -1 for codes that do not correspond to
any touch when evaluated. This may happen when a drag goes off screen.
When Shift or Control or both keys are pressed while pressing the mouse
button, 0.5 or 0.25 or both will be added to the code assigned by GET,
in accordance with keyboard hits.
SPRX(1) = 180
SPRY(1) = 96
GRABX = -1
@L
WAIT:GET EVCODE
IF EVCODE = 27 THEN END
IF EVCODE = 1 THEN GOSUB PRESS 'MOUSE BUTTON PRESSED
IF EVCODE = -1 THEN GRABX = -1 'MOUSE BUTTON RELEASED
IF GRABX <> -1 THEN GOSUB DRAG
G.L
@PRESS
GRABX = TOUCHX(1) - SPRX(1)
GRABY = TOUCHY(1) - SPRY(1)
IF (GRABX - 12)^2 + (GRABY - 12)^2 > 144 THEN GRABX = -1
R.
@DRAG
IF TOUCHX(1) = -1 THEN GRABX = -1:R. 'OFF SCREEN
SPRX(1) = TOUCHX(1) - GRABX
SPRY(1) = TOUCHY(1) - GRABY
R.
Objects of the higher priority value will cover the other.
Negative priorities are invisible (covered by the background color fill.)
TEXTX=4:TEXTY=0
TEXTCOLORLC=$D
TEXTPRIO=4 'PRIORITY OF THE TEXT LAYER
TILEX=12:TILEY=0
TILE(4,7)=DGNBALL24()
TILEPRIO=3 'PRIORITY OF THE TILE LAYER
SPRDGN("P")=DGNBALL10():SPRDGN("M")=DGNBALL4()
T=0:U=0
FOR V=0 TO 3*PI STEP .003
T=T+.05:U=U+.02:A=COS(V)
TEXTLINE$(13)=" " + INT(V)
SPRX("P")=187+60*COS(U)
SPRY("P")=103+A*60*SIN(U)
SPRPRIO("P")=3+2*SGN(A*SIN(U)) 'PRIORITY OF SPRITE "P"
SPRX("M")=SPRX("P")+15*COS(T)+3
SPRY("M")=SPRY("P")-A*15*SIN(T)+3
SPRPRIO("M")=SPRPRIO("P")-SGN(A*SIN(T)) 'PRIORITY OF SPRITE "M"
WAIT:WAIT
NEXT
Changing the Background Music
INPUT "SELECT SONG 1 OR 2:", SONG
ON SONG GOTO A, B, C
@A:MUSIC$="space_blues.mp3":GOTO START
@B:MUSIC$="beepbox-song.mp3":GOTO START
@C:MUSIC$="":GOTO START 'SILENCE
MUSIC$=""
INPUT "SELECT EFFECT 0-5:", FX
MUSIC$="sfx.wav" 'FACTORY SOUND EFFECT FILE
MUSICTIME=FX*2 'EFFECTS BEGIN AT EVERY 2ND SECOND
FOR I=1 TO 100:W.:N. 'EFFECTS PLAY FOR 2 SECONDS EACH
GOTO START
MUSICTIME |
Effect |
0 |
Jump |
2 |
Shoot |
4 |
Explode |
6 |
Appear |
8 |
Disappear |
10 |
Ding |
Extending the Environment
These 2 songs and 6 effects are provided by the factory environment zip.
After downloading the environment zip, you can add more mp3 or wav files to the zip and
refer to them in the MUSIC$ variable. In this case though, Runner Screen cannot play the song.
You can specify a URL in the MUSIC$ value in case the mp3 file is available on a server.
Be careful: if you specify the file name in uppercase
instead of lower or vice versa then Windows systems will play the song but Linux ones won't.
Okay, with that you get the concepts. Now here are some details that I have
not mentioned so far.
The rest of built-in variables
The tutorials so far covered the following built-in variables:
PI,
TZO,
BACKGROUND,
MUSIC$, MUSICTIME,
TILEX, TILEY,
TILEPRIO, TEXTPRIO,
FONTALNUM, TEXTX, TEXTY, TEXTCOLORUC, TEXTCOLORLC
Here is the rest:
- CURSORY – on which line will the next PRINT/INPUT print
- CURSORX – it's normally 0, only changes during INPUT (when program can't get its value)
- CURSORPERIOD, CURSORON – cursor blink timing [Note]
- READYPROMPT – the text appearing on the Runner Screen when commands are expected [Note]
- FONTSIGNS – pointer to user-defined non-alphanumeric characters' memory slot
- MUSICEND – the full playing time of the current background music, seconds
Palette
Components of color code CC stored in RED(CC), GREEN(CC) and BLUE(CC). Each value ranges from 0 to 255.
The built-in designs are not affected. Only the 16 existing color codes can be redefined, CC's outside the
range of 0 to 15 won't be effective.
'REPLACE LIGHT COLORS WITH GRAYSCALE
FOR I = 0 TO 7
CC = I+8
B = I*255/7
RED(CC) = B
GREEN(CC) = B
BLUE(CC) = B
NEXT
Re-DIM to erase
Quickly erase all sprites, tiles, text:
DIM SPRX()
DIM TILE()
DIM TEXTLINE$():CURSORY=0
That's all. I hope you enjoyed this tutorial. Have fun programming!
Be sure to visit the forum sometimes to
share your experience and wisdom. Find the wiki
for less simplified sample program lists, and more help in programming imeight.