home *** CD-ROM | disk | FTP | other *** search
- ------------------------------------------------------------------------
- -- Astro Smash Coding: Eric Askilsrud (Redlense@u.washington.edu) --
- -- A <10k program written with Amos 1.3, Jun 1992 --
- -- --
- -- Tutorial file on AstroSmash's creation. --
- ------------------------------------------------------------------------
-
- Hey, I like the idea of the Amoner editors' for this 10k program thing.
- This way I can hack out fun little routines w/o having to do painstaking
- waste-of-my-time polishing work!
-
- Anyways, Astro Smash is really the first 10k of a much bigger program
- that I may be writing soon. AstroSmash has a little bit of everything -
- and - as a bonus - it is actually playable! So I decided to write this
- tutorial on it's creation for intermediate AMOS programmers!
-
- -----------------------------------------------------------------------------
-
- First some background - The game uses the 8 hardware sprites, with sprites
- 0 and 4 being the spaceships. The graphics are in a sprite bank that
- was saved along with the program. They were originally drawn with Dpaint in
- 4 color mode - it is very important that you pick up sprites from a 4 color
- screen, otherwise they will be treated like computed sprites until you ERASE
- them!
-
- object
- 1-16 different rotations of the spaceship, w/ object 1 being a space-
- ship pointing upwards, and each succesive object being the spaceship
- rotated 22.5 degrees further clockwise
-
- 17 the bullet
-
- 18 explosion
-
-
- ----------------------------
- Algorithm:
-
- setup
- while playing
- -title screen/wait to start
- while alive
- for player=0 to 1
- -check joystick
- -update sprites
- next
- wend
- -game over sequence
- wend
-
- ---------------------------
-
-
- Looking at the code:
- --------------------
-
- >> Dim XDIR#(1),YDIR#(1),X#(1),Y#(1),LK(1),I(1),AX#(16),AY#(16)
-
- This line reserves all the memory for all the arrays in the game. An array
- is used for every variable that needs a seperate version for each of the two
- spaceships - the index of the array represents the player number (0 & 1).
-
- xdir#() - holds the horizontal component of velocity
- ydir#() - holds the vertical component of velocity
- x#() - holds x coord of ship
- y#() - holds y coord of ship
- lk() - holds the last direction the joystick was pressed
- i() - holds the image number of ship (1-16)
-
- Notice that the '#' after x,y,xdir,ydir means that they are floating point
- variables - that means they contain a decimal point (see manual)
-
- ax#() and ay#() are used to store a table of values, they will be
- explained shortly
-
- >> Flash Off : Hide : Curs Off : Paper 0 : Degree
-
- These commands turn the flashing off, hide the mousepointer, turn the cursor
- off, set the background to black, and set the trigonomic functions to degree
- mode(see below) respectively.
-
- >> For ANGLE=0 To 15
- >> AX#(ANGLE+1)=0.5*Sin(ANGLE*22.5)
- >> AY#(ANGLE+1)=-0.5*Cos(ANGLE*22.5)
- >> Next
-
- These statements fill the table of the aforementioned AX#() and AY#().
- This table is a holds the 'x-acceleration' and 'y-acceleration' for the
- ship for any given spaceship image number (1-16). I've set the acceleration
- to .5 - We can use trigonometry to figure the x and y components of accel.
- For example, if the ship was thrusting 45 degrees clockwise from straight
- up (image#3) ax# would be .5 * sin45 and ay# would be .5 * cos45.
-
- Notice the negative in front of the calculation for AY# - this is because
- 'up' on the computer screen is negative and not positive. Negating the
- accel y-component will enable us to comply.
-
- So, the loop precalculates x,y components of acceleration for each image number.
- Eg. ax#(3) returns accel x-component for image #3
-
- >> Make Mask
-
- Make mask arround images for collision detection
-
- >> While QUIT=0
-
- 'Keep doing every thing between here and WEND until user quits'
-
- >> TYPE=0 : For Z=0 To 1 : XDIR#(Z)=0.0 : YDIR#(Z)=0.0 : Next
- >> X#(1)=10.0 : Y#(1)=10.0 : I(1)=7 : X#(0)=300.0 : Y#(0)=180.0 : I(0)=15
- >> INGAME=0 : Cls
-
- This initializes all the stuff for a game:
-
- TYPE=0 --> TYPE holds Warp/Bounce mode - 0 means that we don't know yet
- XDIR#(), YDIR#() = 0 --> set velocity vectors to zero
- x=10, y=10, etc --> gives spaceships their starting coords
- i(1)=7 i(0)=15 --> gives spaceships their initial images
- INGAME=0 --> this means that nobodys died in current game yet
-
-
- >> Locate ,2 : Centre "Astro Smash"
- >> Locate ,4 : Centre "(Written in Amos 1.3)"
- >> Locate ,8 : Centre "1) Reflective Walls "
- >> Locate ,10 : Centre "2) Warp Space"
- >> Locate ,13 : Centre "Q) Quit"
- >> While TYPE=0 : A$=Inkey$ : If A$="1" Then TYPE=1
- >> If A$="2" Then TYPE=2
- >> If Upper$(A$)="Q" Then End
- >> Wend
-
- This draws the game selection menu and waits for the user to enter a TYPE.
- Keeps getting keys until TYPE other than 0 is given, or, by the selection of
- 'q', the program is ended. Notice the use of upper$, which lets it accept
- capital or lower-case Q's - see manual.
-
- >> Cls : If TYPE=1 Then Box 0,0 To 319,199
-
- Clears the screen and, if in a Bounce game, draw the border
-
- >> While INGAME=0
-
- 'Keep doing every thing between here and WEND until somebodys dead'
-
- >> For P=0 To 1
-
- P represents the player number - so, do each of the following for each player:
-
- >> K=Joy(P)
-
- Read the JoyStick for current P
-
- >> If K>15 Then K=K-16 : XDIR#(P)=XDIR#(P)+AX#(I(P)) : YDIR#(P)=YDIR#(P)+AY#(I(P)) : Gosub CHSPEED
-
- If K>15 that means that that player is pressing FIRE button
- k=k-16 just means 'now we know the players pressed the button, and we'll take
- care of it' - subtracting 16 from k just leaves us with
- joystick direction values w/o the button (see manual)
-
- Since the 'thrust' was pressed, we will add the the component-acceleration
- values from the AX and AY tables explained above (notice the player indexing).
-
- XDIR#(P)=XDIR#(P)+AX#(I(P)) : YDIR#(P)=YDIR#(P)-AY#(I(P))
-
- And lastly, Gosub CHSPEED which limits the spaceship from going too
- fast (see explanation of routine below).
-
- >> If K=8 Then If Chanan(P)=0 Then I(P)=I(P)+1 : Gosub CHLOOP : Amal P*4,"A2,("+Str$(I(P))+",1)" : Amal On P*4
-
- If K=8 that means that the player is pressing right on the joystick,
- which means that the spaceship should be rotated right - meaning image
- number is increased - but what if we are at image 16 (337.5 degrees) and
- we rotate 22.5 degrees further? Since 360 degrees = 0 degrees, we switch
- back to image number 1 - this is exactly what Gosub CHLOOP performs.
- Once we figure out what new Image the sprite should be, we set up an AMAL
- string to Animate it to that image - Why all this Chanan (see manual!!)
- and AMAL stuff? why not just change the sprite? Because that would make the
- ship rotate too fast! So, we say with an amal string, to change the image
- number in 2 vbl's - With the Chanan(P) function check that the image is not
- being animated before incrementing the image!
-
- Amal P*4,"A2,("+Str$(I(P))+",1)"
-
- ^^ this little tricky string addition trick,
- the string is seen as:
-
- "A2,(#,1)" where # represents the image number to
- animate to.
-
- Expirement with this trick of using the str$() function to create amal
- strings!!! This method is much better than writing independent amal strings
- for small speed or distance differences OR by using the Amreg function
- to pass it along!!
-
- >> If K=4 Then If Chanan(P)=0 Then I(P)=I(P)-1 : Gosub CHLOOP : Amal P*4,"A2,("+Str$(I(P))+",1)" : Amal On P*4
-
- This is the same story as the line before, except this time we are dealing with
- joystick left
-
- >> If K=1 and LK(P)<>K Then Gosub BULLET
-
- If the joystick is pressed up AND the last direction the joystick was pressed
- was NOT up (to ensure only ONE bullet is released every time the joystick
- is pressed up) then Gosub BULLET (see below).
-
- >> On TYPE Gosub BOUNCE,WARP
-
- Now depending on the type of game do either 1) bounce off walls 2) warp to
- other side of screen (see below)
-
- >> X#(P)=XDIR#(P)+X#(P) : Y#(P)=YDIR#(P)+Y#(P)
-
- After getting the joystick info, we can now finally update the sprites.
- The new x coord will equal the old one plus the x-comp of velocity(xdir)
- The new y coord will equal the old one plus the y-comp of velocity(ydir)
-
- >> Sprite P*4,X Hard(X#(P)),Y Hard(Y#(P)),I(P)
-
- Put the sprite in its place - Sprite 0 is used for player 0
- Sprite 4 is used for player 1
- Therefore there is a neat little formula that gives sprite number given
- player number: player# * 4 !!! (wow)
-
- Notice the current player index is accessed for x,y and i
-
- >> Gosub CHECKBULLS
-
- Also we should check to make sure their are no bullets standing still on
- the playfield (see below)
-
- >> LK(P)=K
-
- store the current k into 'last k' (lk) for that player
- this is used by the fire bullet routine (see above)
-
- >> If Sprite Col(P*4)<>0 Then Boom : Sprite P*4,X Hard(X#(P)),Y Hard(Y#(P)),18 : INGAME=1 : Amal Off
-
- Check for sprite collisions - sprite number for collision detection is
- calculated from our previously derived formula, sprite# = p*4.
-
- If there is a collision, then make a Boom sound,
- change that sprite image into an explosion! (image 18)
- turn amal off, and let the WHILE loop know that somebody has died (ingame=1)
-
- >> Next
-
- End of 'Player' loop...
-
- >> Wait Vbl
-
- Wait a Vbl to wait for screen to draw
-
- >> Wend
-
- Once we get passed this WEND, that means that somebody has DIED!
-
- >> For Z=0 To 1
- >> If Sprite Col(Z*4)<>0 Then Sprite Z*4,X Hard(X#(Z)),Y Hard(Y#(Z)),18
- >> Next
-
- Check Collision of the two spaceships once more, just incase they collided
- into one another - otherwise only one would turn into an explosion.
- If there is a collision, turn that sprite into an explosion image #18 as
- above
-
- >> Sprite Update : Wait Vbl : Locate ,11 : Centre "Game Over" : Wait 40 : While Joy(1)<16 : Wend
-
- This is more end-of-game stuff - update the sprites to ensure they show an
- explosion, print 'game over', wait for player 1 to press his button
-
- >> For Z=0 To 7 : Sprite Off Z : Next : Sprite Update
-
- Finally, turn all the sprites off, as we are done with them for this game
-
- >> Wend
- >> End
-
- Once we are out of this WEND, that means the person has quit!!
- Which means the next command is End!
-
- --------------------------------
- Routines called by the main loop
- --------------------------------
-
- >> CHLOOP:
- >> If I(P)>16 Then I(P)=1
- >> If I(P)<1 Then I(P)=16
- >> Return
-
- This routine sets image# back to 1 if it gets greater than 16
- and up to 16 if it gets below image number 1 (see above)
-
- >> CHSPEED:
- >> If XDIR#(P)>4.0 Then XDIR#(P)=4.0
- >> If XDIR#(P)<-4.0 Then XDIR#(P)=-4.0
- >> If YDIR#(P)>4.0 Then YDIR#(P)=4.0
- >> If YDIR#(P)<-4.0 Then YDIR#(P)=-4.0
- >> Return
-
- This routine limits how big or small a component of velocity can be.
- You can see that if the absolute value of the component of speed is
- greater than 4 it is set back to 4.
-
- >> BOUNCE:
- >> If X#(P)>304.0 Then X#=304.0 : XDIR#(P)=0.0-XDIR#(P) : Bell 1
- >> If X#(P)<-3.0 Then X#=-3.0 : XDIR#(P)=0.0-XDIR#(P) : Bell 1
- >> If Y#(P)>184.0 Then Y#=184.0 : YDIR#(P)=0.0-YDIR#(P) : Bell 1
- >> If Y#(P)<-2.0 Then Y#=-2.0 : YDIR#(P)=0.0-YDIR#(P) : Bell 1
- >> Return
-
- This routine is used by the Bounce mode of the game - if the x or y
- components of the ships go off the screen, then the velocity-component that
- is perpendicular to that of the boundary it exceeds is reversed.
- If such a collision is detected, the awesome 'Bell 1' sound effect is
- executed for that extra arcade realism.
-
- >> WARP:
- >> If X#(P)>304.0 Then X#(P)=0.0
- >> If X#(P)<0.0 Then X#(P)=304.0
- >> If Y#(P)>184.0 Then Y#(P)=0.0
- >> If Y#(P)<0.0 Then Y#(P)=184.0
- >> Return
-
- This routine is used by the Warp mode of the game - if the x or y
- components exceed the maximum in the region, they are set to the minimum
- and vise versa.
-
- >> BULLET:
- >> Q=0
- >> If P=0 Then For Z=1 To 3 : If Chanmv(Z)=0 Then Q=Z : Next
- >> If P=1 Then For Z=5 To 7 : If Chanmv(Z)=0 Then Q=Z : Next
-
- The Bullet routine is called whenever the joystick is pressed up again -
- First we must cycle thru the bullet Sprites that belong to the current
- player, to see if any are stationary - which means they are not on the
- screen and can be used.
-
- Sprites 1 to 3 are bullets belonging to player0
- sprites 5 to 8 are bullets belonging to player1
-
- q holds the last found currently-available bullet - It is initially set
- to zero, therefore, if no bullets are found it is left 0
-
- >> If Q=0 Then Return
- >> Shoot
-
- So, if no bullets are available, RETURN (do nothing)
- Otherwise, make the neat 'Shoot' sound fx, and do the following:
-
- >> Sprite Q,X Hard(X#(P)+7)+30*AX#(I(P)),Y Hard(Y#(P)+8)+30*AY#(I(P)),17
-
- This command gives the bullet its initial position. The initial position
- is going to be the ships x,y plus a displacement value (x+7,y+8) that gives
- the coordinate of the center of the ship. To the center of the ship's coords
- are added multiple of the vector that points in the direction of the
- ship ---- the components of this vector are the same as that of the accel
- vector, our good buddies AX and AY! To initially get the bullet good and
- far away from the ship, this vector is multiplied by 30 (determined expire-
- mentally).
-
- Image number 17 is assigned, as this is the 'bullet' object
-
-
- >> Amal Q,"M "+Str$(Int(300*AX#(I(P))))+","+Str$(Int(300*AY#(I(P))))+",50" : Amal On Q
-
- This gives the bullet its Movement command. Again, this uses string addition
- to produce the AMAL string. Looks pretty gross, don't it??
-
- What it basically does is: "M 300*ax(i),300*ay(i),50"
- which means Move (in 50 vbl's) : 300 times the x-comp of accel in the x-
- direction, and 300 times the y-comp of accel in the y-direction.
-
- The reason for all those parethesis is:
- 1) We have them around the Str$(),
- 2) We use Int() around the string to Str$() - this is because AMAL does't
- like floats - so we must convert the numbers to Str$() into integers
- 3) player indexing
-
-
- Hopefully it isn't too mind boggeling - Remember, when looking at things
- like this it is very helpful to watch your order of operations - start
- from the inside of the parenthesis and work your way out
-
- EX)
-
- Amal Q,"M "+Str$(Int(300*AX#(I(P))))+","+Str$(Int(300*AY#(I(P))))+",50"
-
- AMAL Q,"M " + Str$(Int(300*ax#(2))) + "," + Str$(Int(300*AY#(2))) + ",50"
-
- AMAL Q,"M " + Str$(Int(300*.38)) + "," + Str$(Int(300 * .92)) + ",50"
-
- AMAL Q,"M " + Str$(114) + "," + str$(276) + ",50"
-
- AMAL Q,"M " + "114" + "," + "276" + ",50"
-
- AMAL Q,"M 114,276,50"
-
- >> Return
-
-
- >> CHECKBULLS:
- >> For Z=1 To 7
- >> If Z<>4 and Chanmv(Z)=0 Then Sprite Off Z
- >> Next
- >> Return
-
- This routine makes sure that there are no bullets standing still on the play-
- feild. Bullets are given a starting location and a certain movement string by
- the BULLET routine above - but there is nothing clearing them once their
- movement pattern runs out. This checks each of the sprites 1-7 except 4
- (sprites 0 and 4 are ships) to see if they are moving with the Chanmv command
- (see manual). If they are not moving, this routine just turns the sprite off.
-
-
- -------------------------------------------------------------------------------
-
- Okay, that's it! Hopefully that's been of some interest to you.
- Why don't you drop me a line and let me know what you think,
- (don't tell me I spel bad or nuthin grammer like)
-
- Thanks,
- -Eric (redlense@milton.u.washington.edu)
-