;_/^^^^^^^^^^^^^\_______________________________________________________________________________________________________
;-[ Information ]------------------------------------------------------------------------------------------------1-2-0--
;^\_____________/^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; Project Z: One (Demo)
; Created by: TheChange
; Date: 16 Jun 2002
; If you wish to play the game, please check out the optimized version; Project Z: One (Opt).
; There are many differences in the optimized version, like the major speed difference.
; If you wish to learn how the game works or wish to check it out anyway, I'd recommend reading this code.
; This is the unoptimized and commented code for Project Z: One.
; Note: This game is resolution dependent (time saving) -> 800x600.
; For more information about this game, please run the optimized version of Project Z: One.
; The first two sections were taken from external files "Keyboard.BB" and "Vector.BB".
; The keyboard file includes all the common used scancodes so you don't have to look them up all the time.
; The vector file includes 4 simple functions to calculate angles and distances.
; Include "Lib\Keyboard.BB"
;_/^^^^^^^^^^^^^^^^^^^^^^\______________________________________________________________________________________________
;-[ Key code definitions ]---------------------------------------------------------------------------------------1-2-0--
;^\______________________/^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;-( Numerical )------------------------------------------;
Const Key1% = 2
Const Key2% = 3
Const Key3% = 4
Const Key4% = 5
Const Key5% = 6
Const Key6% = 7
Const Key7% = 8
Const Key8% = 9
Const Key9% = 10
Const Key0% = 11
Dim KeyNumeric% ( 9 )
KeyNumeric ( 0 ) = Key0
KeyNumeric ( 1 ) = Key1
KeyNumeric ( 2 ) = Key2
KeyNumeric ( 3 ) = Key3
KeyNumeric ( 4 ) = Key4
KeyNumeric ( 5 ) = Key5
KeyNumeric ( 6 ) = Key6
KeyNumeric ( 7 ) = Key7
KeyNumeric ( 8 ) = Key8
KeyNumeric ( 9 ) = Key9
;-( Alphabetic )-----------------------------------------;
Const KeyQ% = 16
Const KeyW% = 17
Const KeyE% = 18
Const KeyR% = 19
Const KeyT% = 20
Const KeyY% = 21
Const KeyU% = 22
Const KeyI% = 23
Const KeyO% = 24
Const KeyP% = 25
Const KeyA% = 30
Const KeyS% = 31
Const KeyD% = 32
Const KeyF% = 33
Const KeyG% = 34
Const KeyH% = 35
Const KeyJ% = 36
Const KeyK% = 37
Const KeyL% = 38
Const KeyZ% = 44
Const KeyX% = 45
Const KeyC% = 46
Const KeyV% = 47
Const KeyB% = 48
Const KeyN% = 49
Const KeyM% = 50
Dim KeyAlpha% ( 26 )
KeyAlpha ( 1 ) = KeyA
KeyAlpha ( 2 ) = KeyB
KeyAlpha ( 3 ) = KeyC
KeyAlpha ( 4 ) = KeyD
KeyAlpha ( 5 ) = KeyE
KeyAlpha ( 6 ) = KeyF
KeyAlpha ( 7 ) = KeyG
KeyAlpha ( 8 ) = KeyH
KeyAlpha ( 9 ) = KeyI
KeyAlpha ( 10 ) = KeyJ
KeyAlpha ( 11 ) = KeyK
KeyAlpha ( 12 ) = KeyL
KeyAlpha ( 13 ) = KeyM
KeyAlpha ( 14 ) = KeyN
KeyAlpha ( 15 ) = KeyO
KeyAlpha ( 16 ) = KeyP
KeyAlpha ( 17 ) = KeyQ
KeyAlpha ( 18 ) = KeyR
KeyAlpha ( 19 ) = KeyS
KeyAlpha ( 20 ) = KeyT
KeyAlpha ( 21 ) = KeyU
KeyAlpha ( 22 ) = KeyV
KeyAlpha ( 23 ) = KeyW
KeyAlpha ( 24 ) = KeyX
KeyAlpha ( 25 ) = KeyY
KeyAlpha ( 26 ) = KeyZ
;-( Numeric keypad )-------------------------------------;
Const KeyPad7% = 71
Const KeyPad8% = 72
Const KeyPad9% = 73
Const KeyPad4% = 75
Const KeyPad5% = 76
Const KeyPad6% = 77
Const KeyPad1% = 79
Const KeyPad2% = 80
Const KeyPad3% = 81
Const KeyPad0% = 82
Dim KeyPadNumeric% ( 9 )
KeyPadNumeric ( 0 ) = KeyPad0
KeyPadNumeric ( 1 ) = KeyPad1
KeyPadNumeric ( 2 ) = KeyPad2
KeyPadNumeric ( 3 ) = KeyPad3
KeyPadNumeric ( 4 ) = KeyPad4
KeyPadNumeric ( 5 ) = KeyPad5
KeyPadNumeric ( 6 ) = KeyPad6
KeyPadNumeric ( 7 ) = KeyPad7
KeyPadNumeric ( 8 ) = KeyPad8
KeyPadNumeric ( 9 ) = KeyPad9
;-( Function keys )--------------------------------------;
Const KeyFunction1% = 59
Const KeyFunction2% = 60
Const KeyFunction3% = 61
Const KeyFunction4% = 62
Const KeyFunction5% = 63
Const KeyFunction6% = 64
Const KeyFunction7% = 65
Const KeyFunction8% = 66
Const KeyFunction9% = 67
Const KeyFunction10% = 68
Const KeyFunction11% = 87
Const KeyFunction12% = 88
Dim KeyFunction% ( 12 )
KeyFunction ( 1 ) = KeyFunction1
KeyFunction ( 2 ) = KeyFunction2
KeyFunction ( 3 ) = KeyFunction3
KeyFunction ( 4 ) = KeyFunction4
KeyFunction ( 5 ) = KeyFunction5
KeyFunction ( 6 ) = KeyFunction6
KeyFunction ( 7 ) = KeyFunction7
KeyFunction ( 8 ) = KeyFunction8
KeyFunction ( 9 ) = KeyFunction9
KeyFunction ( 10 ) = KeyFunction10
KeyFunction ( 11 ) = KeyFunction11
KeyFunction ( 12 ) = KeyFunction12
;-( Shiftstate )-----------------------------------------;
Const KeyLeftShift% = 42
Const KeyRightShift% = 54
Const KeyLeftAlt% = 56
Const KeyRightAlt% = 184
Const KeyLeftCtrl% = 29
Const KeyRightCtrl% = 157
Const KeyCapsLock% = 58
Const KeyNumLock% = 69 ; Disfunctional
Const KeyScrollLock% = 70
Const KeyLeftAlternate% = 56
Const KeyRightAlternate% = 184
Const KeyLeftControl% = 29
Const KeyRightControl% = 157
;-( Control keys )---------------------------------------;
Const KeySpace% = 57
Const KeyEnter% = 28
Const KeyTab% = 15
Const KeyBackSpace% = 14
Const KeyInsert% = 210
Const KeyDelete% = 211
Const KeyHome% = 199
Const KeyEnd% = 207
Const KeyPageUp% = 201
Const KeyPageDown% = 209
Const KeyEscape% = 1
Const KeyPause% = 197 ; Numlock
Const KeyLeftWindows% = 219
Const KeyRightWindows% = 220
Const KeyApps% = 221
Const KeyPower% = 222
Const KeySleep% = 223
Const KeyWake% = 227
;-( Signs )----------------------------------------------;
Const KeyBackQuote% = 41
Const KeyMinus% = 12
Const KeyEquals% = 13
Const KeyLeftBracket% = 26
Const KeyRightBracket% = 27
Const KeyBackSlash% = 43
Const KeySemiColon% = 39
Const KeyQuote% = 40
Const KeyComma% = 51
Const KeyPeriod% = 52
Const KeySlash% = 53
;-( Keypad controls )------------------------------------;
Const KeyPadSlash% = 181
Const KeyPadAsterisk% = 55
Const KeyPadMinus% = 74
Const KeyPadPlus% = 78
Const KeyPadEnter% = 156
Const KeyPadPeriod% = 83
;-( Cursors )--------------------------------------------;
Const KeyCursorUp% = 200
Const KeyCursorDown% = 208
Const KeyCursorLeft% = 203
Const KeyCursorRight% = 205
;_/^^^^^^^^^^^^^^^^^^^^^^\______________________________________________________________________________________________
;-[ Key name definitions ]---------------------------------------------------------------------------------------1-2-0--
;^\______________________/^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dim KeyName$ ( 255 )
;-( Numerical )------------------------------------------;
KeyName ( Key1 ) = "1"
KeyName ( Key2 ) = "2"
KeyName ( Key3 ) = "3"
KeyName ( Key4 ) = "4"
KeyName ( Key5 ) = "5"
KeyName ( Key6 ) = "6"
KeyName ( Key7 ) = "7"
KeyName ( Key8 ) = "8"
KeyName ( Key9 ) = "9"
KeyName ( Key0 ) = "0"
;-( Alphabetic )-----------------------------------------;
KeyName ( KeyQ ) = "Q"
KeyName ( KeyW ) = "W"
KeyName ( KeyE ) = "E"
KeyName ( KeyR ) = "R"
KeyName ( KeyT ) = "T"
KeyName ( KeyY ) = "Y"
KeyName ( KeyU ) = "U"
KeyName ( KeyI ) = "I"
KeyName ( KeyO ) = "O"
KeyName ( KeyP ) = "P"
KeyName ( KeyA ) = "A"
KeyName ( KeyS ) = "S"
KeyName ( KeyD ) = "D"
KeyName ( KeyF ) = "F"
KeyName ( KeyG ) = "G"
KeyName ( KeyH ) = "H"
KeyName ( KeyJ ) = "J"
KeyName ( KeyK ) = "K"
KeyName ( KeyL ) = "L"
KeyName ( KeyZ ) = "Z"
KeyName ( KeyX ) = "X"
KeyName ( KeyC ) = "C"
KeyName ( KeyV ) = "V"
KeyName ( KeyB ) = "B"
KeyName ( KeyN ) = "N"
KeyName ( KeyM ) = "M"
;-( Numeric keypad )-------------------------------------;
KeyName ( KeyPad7 ) = "Pad 7"
KeyName ( KeyPad8 ) = "Pad 8"
KeyName ( KeyPad9 ) = "Pad 9"
KeyName ( KeyPad4 ) = "Pad 4"
KeyName ( KeyPad5 ) = "Pad 5"
KeyName ( KeyPad6 ) = "Pad 6"
KeyName ( KeyPad1 ) = "Pad 1"
KeyName ( KeyPad2 ) = "Pad 2"
KeyName ( KeyPad3 ) = "Pad 3"
KeyName ( KeyPad0 ) = "Pad 0"
;-( Function keys )--------------------------------------;
KeyName ( KeyFunction1 ) = "F1"
KeyName ( KeyFunction2 ) = "F2"
KeyName ( KeyFunction3 ) = "F3"
KeyName ( KeyFunction4 ) = "F4"
KeyName ( KeyFunction5 ) = "F5"
KeyName ( KeyFunction6 ) = "F6"
KeyName ( KeyFunction7 ) = "F7"
KeyName ( KeyFunction8 ) = "F8"
KeyName ( KeyFunction9 ) = "F9"
KeyName ( KeyFunction10 ) = "F10"
KeyName ( KeyFunction11 ) = "F11"
KeyName ( KeyFunction12 ) = "F12"
;-( Shiftstate )-----------------------------------------;
KeyName ( KeyLeftShift ) = "Left Shift"
KeyName ( KeyRightShift ) = "Right Shift"
KeyName ( KeyLeftAlt ) = "Left Alt"
KeyName ( KeyRightAlt ) = "Right Alt"
KeyName ( KeyLeftCtrl ) = "Left Control"
KeyName ( KeyRightCtrl ) = "Right Control"
KeyName ( KeyCapsLock ) = "CapsLock"
KeyName ( KeyNumLock ) = "NumLock"
KeyName ( KeyScrollLock ) = "ScrollLock"
;-( Control keys )---------------------------------------;
KeyName ( KeySpace ) = "SpaceBar"
KeyName ( KeyEnter ) = "Enter"
KeyName ( KeyTab ) = "Tab"
KeyName ( KeyBackSpace ) = "BackSpace"
KeyName ( KeyInsert ) = "Insert"
KeyName ( KeyDelete ) = "Delete"
KeyName ( KeyHome ) = "Home"
KeyName ( KeyEnd ) = "End"
KeyName ( KeyPageUp ) = "PageUp"
KeyName ( KeyPageDown ) = "PageDown"
KeyName ( KeyEscape ) = "Escape"
KeyName ( KeyPause ) = "Pause"
KeyName ( KeyLeftWindows ) = "Left Windows"
KeyName ( KeyRightWindows ) = "Right Windows"
KeyName ( KeyApps ) = "Apps"
KeyName ( KeyPower ) = "Power"
KeyName ( KeySleep ) = "Sleep"
KeyName ( KeyWake ) = "Wake"
;-( Signs )----------------------------------------------;
KeyName ( KeyBackQuote ) = "BackQuote"
KeyName ( KeyMinus ) = "Minus"
KeyName ( KeyEquals ) = "Equals"
KeyName ( KeyLeftBracket ) = "Left Bracket"
KeyName ( KeyRightBracket ) = "Right Bracket"
KeyName ( KeyBackSlash ) = "BackSlash"
KeyName ( KeySemiColon ) = "SemiColon"
KeyName ( KeyQuote ) = "Quote"
KeyName ( KeyComma ) = "Comma"
KeyName ( KeyPeriod ) = "Period"
KeyName ( KeySlash ) = "Slash"
;-( Keypad controls )------------------------------------;
KeyName ( KeyPadSlash ) = "Pad Slash"
KeyName ( KeyPadAsterisk ) = "Pad Asterisk"
KeyName ( KeyPadMinus ) = "Pad Minus"
KeyName ( KeyPadPlus ) = "Pad Plus"
KeyName ( KeyPadEnter ) = "Pad Enter"
KeyName ( KeyPadPeriod ) = "Pad Period"
;-( Cursors )--------------------------------------------;
KeyName ( KeyCursorUp ) = "Cursor Up"
KeyName ( KeyCursorDown ) = "Cursor Down"
KeyName ( KeyCursorLeft ) = "Cursor Left"
KeyName ( KeyCursorRight ) = "Cursor Right"
;_/^^^^^^^^^^^^^^^^^^^^\________________________________________________________________________________________________
;-[ Key initialization ]-----------------------------------------------------------------------------------------1-2-0--
;^\____________________/^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FlushKeys ()
;-->
; Include "Lib\Vector.BB"
; *------------------------------------*
; | |
; | Vector Matrix Conversion - VXII |
; | |
; *------------------------------------*
;-[ Sub ]--------------------------------------------------------------------------------------------------------1-2-0--
Function GetVectorX# ( Distance# , Angle# ) ; Get horizontal size of vector using distance and angle.
Return Sin ( Angle ) * Distance
End Function
Function GetVectorY# ( Distance# , Angle# ) ; Get vertical size of vector using distance and angle.
Return Sin ( Angle - 90 ) * Distance
End Function
;<--
Function GetLength# ( X# , Y# ) ; Get true length of a vector (not used in this game).
Return Sqr ( X * X + Y * Y )
End Function
Function GetAngle% ( X# , Y# ) ; Get true angle of a vector.
Result% = ATan2 ( Y , X ) + 90
If Result < 0 Result = Result + 360
Return Result
End Function
; For more explanation on these functions, see further below.
;-->
Graphics 800 , 600 , 0 , 1 ; Force 800 x 600 - detect colordepth - force fullscreen.
ClsColor 0 , 0 , 0
Color 255 , 255 , 255
Print "Starting up manually..."
Font = LoadFont ( "Blitz" , 20 , True ) ; Default font is font from Blitz(tm).
SetFont Font
PlayerBitmap = CreateImage ( 32 , 32 ) ; What the player looks like.
MidHandle PlayerBitmap
SetBuffer ImageBuffer ( PlayerBitmap )
Color 0 , 63 , 127
Rect 0 , 0 , 32 , 32 , False
Color 0 , 127 , 255
Oval 3 , 3 , 26 , 26 , False
Color 0 , 255 , 255
Oval 6 , 6 , 20 , 20 , False
PlayerX = 400 ; Put player in center of screen.
PlayerY = 300
TargetBitmap = CreateImage ( 15 , 15 ) ; The mouse crosshair to use for aiming.
MidHandle TargetBitmap
SetBuffer ImageBuffer ( TargetBitmap )
Color 255 , 0 , 0
Oval 0 , 0 , 15 , 15 , False
Plot 7 , 7
EnemyBitmap = CreateImage ( 25 , 25 ) ; What the enemy looks like.
MidHandle EnemyBitmap
SetBuffer ImageBuffer ( EnemyBitmap )
Color 95 , 127 , 0
Rect 0 , 0 , 25 , 25 , False
Color 191 , 255 , 0
Oval 2 , 2 , 10 , 10 , False
Oval 2 , 13 , 10 , 10 , False
Oval 13 , 2 , 10 , 10 , False
Oval 13 , 13 , 10 , 10 , False
Type Enemy ; Collection of enemies.
Field X# ; Horizontal coordinate.
Field Y# ; Vertical coordinate.
Field Class ; See Enemy Movement section for descriptions.
End Type
Local Enemy.Enemy ; Variable to use to iterate through the collection.
BulletBitmap = CreateImage ( 3 , 3 ) ; All bullets looks like this.
MidHandle BulletBitmap
SetBuffer ImageBuffer ( BulletBitmap )
Color 255 , 255 , 255
Plot 1 , 1
Color 127 , 127 , 127
Plot 0 , 1
Plot 1 , 0
Plot 2 , 1
Plot 1 , 2
Color 63 , 63 , 63
Plot 0 , 0
Plot 0 , 2
Plot 2 , 0
Plot 2 , 2
Type Bullet ; Collection of bullets.
Field Owner ; 1 for Player , 2 for Enemy.
Field X# ; Coords.
Field Y#
Field Angle# ; Angle or direction in which the bullet is heading.
End Type
Local Bullet.Bullet ; Iteration variable.
; Note: All bullets travel at 5 pixels per frame.
ShrapnelBitmap = CreateImage ( 12 , 12 ) ; Shrapnel can't hurt in this game.
MidHandle ShrapnelBitmap
SetBuffer ImageBuffer ( ShrapnelBitmap )
Color 95 , 127 , 0
Oval 0 , 0 , 12 , 12 , False
Color 191 , 255 , 0
Oval 2 , 2 , 8 , 8 , False
Type Shrapnel ; Collection.
Field X# ; Horz coord.
Field Y# ; Vert coord.
Field Angle# ; Angle/direction/heading.
Field Distance ; Current distance since creation.
Field TotalDistance ; Distance to achieve before dissolving.
End Type
Local Shrapnel.Shrapnel
; Note: All shrapnel travels at 1 pixel per frame.
MaxEnemy = 15 ; Max number of enemies allowed.
; When spawning an enemy and there's already a max number of enemies,
; the first enemy dissolves / explodes into shrapnel.
SpawningTime# = 100 ; Number of frames to wait before spawning an enemy.
; This value decreases slowly during gameplay (the spawning increases).
HighScore = 1000000 ; Default highscore.
SeedRnd MilliSecs ()
SetBuffer BackBuffer ()
Repeat
; Scoring:
; In this game, all of the difficulty settings are based on your score,
; except for the SpawningTime which is independent.
; If your score goes above 1,999,999 you become invincible.
; A lot of details are different in the optimized version.
If Score < 1000
BulletCost = 1 ; Amount of score to use for each bullet.
ShootDelay = 200 ; Cheap bullets, so a huge delay to Recharge.
Level = 0 ; Level indicator is shown as red "¤" signs.
EnemyClass = 1 ; Maximum Enemy Class to spawn.
EnemySpeed = 1 ; Maximum Speed (in pixels) of each enemy.
ElseIf Score < 2000 ; When your score reaches 1000...
BulletCost = 1 ; Still cheap bullets.
ShootDelay = 150 ; A bit less delay.
EnemySpeed = 2 ; Enemies twice as fast.
ElseIf Score < 3000
BulletCost = 1
ShootDelay = 100 ; High shoot delay.
ElseIf Score < 4000
BulletCost = 1
ShootDelay = 80
ElseIf Score < 10000 ; After 4000 points...
BulletCost = 2 ; A bit more expensive bullets.
ShootDelay = 60 ; Medium shoot delay.
Level = 1 ; Advancing to next level (1).
EnemyClass = 2 ; Introducing a new type of enemy.
ElseIf Score < 20000
BulletCost = 3
ShootDelay = 40 ; Recharge Indicator disappears.
Level = 2 ; Advance to next level (2).
EnemySpeed = 3 ; Fast enemies.
ElseIf Score < 30000
BulletCost = 4
ShootDelay = 24
EnemyClass = 3 ; New enemy type.
ElseIf Score < 40000
BulletCost = 5
ShootDelay = 12
ElseIf Score < 50000
BulletCost = 6
ShootDelay = 6 ; Low shoot delay.
Level = 3 ; Next level.
EnemyClass = 4 ; New enemy.
ElseIf Score < 100000
BulletCost = 12
ShootDelay = 4
Level = 4
EnemyClass = 5
ElseIf Score < 200000
BulletCost = 24
ShootDelay = 2
Level = 5
EnemyShooting = True ; Enemies 1 through 3 start shooting at you!
EnemyShots = 1 ; Chance (%) of enemy shooting.
ElseIf Score < 300000
BulletCost = 48
ShootDelay = 1 ; Turbo shoot speed.
Level = 6
EnemyShots = 2 ; Double chance.
ElseIf Score < 500000
BulletCost = 96
ShootDelay = 0 ; Maximum shoot-out.
Level = 7
EnemySpeed = 4
EnemyShots = 3
ElseIf Score < 700000
Level = 8
EnemySpeed = 6
EnemyShots = 4
ElseIf Score < 1000000
Level = 9
EnemySpeed = 8
EnemyShots = 5
ElseIf Score < 2000000
Level = 10 ; Highest level.
EnemySpeed = 10 ; Turbo enemy speed.
EnemyShots = 10 ; Heavy enemy fire.
Else ; GodMode at 2,000,000+ points.
BulletCost = 0 ; Free bullets.
GodMode = True ; No score decrement.
EndIf
If Score > HighScore Then HighScore = Score ; Update highscore.
If ScoreWait > 9 ; Automatically increase score with 1 point per 10 frames.
ScoreWait = 0
Score = Score + 1
Else
ScoreWait = ScoreWait + 1
EndIf
; Player and Enemy Shooting:
; Player can shoot with Left Mouse button when not recharging.
; Shooting is Recharging, ShootDelay is RechargeDelay.
; But when Player's score is too low, Player can't shoot either.
; Enemies of class/type 1 through 3 are able to shoot.
If Shooting ; Recharging.
If ShootingWait >= ShootDelay ; Recharge time is over.
Shooting = False
ShootingWait = 0 ; Reset Recharge timer.
Else
ShootingWait = ShootingWait + 1 ; Recharging...
EndIf
Else ; Not recharging - ready to shoot.
If MouseDown ( 1 )
If Score >= BulletCost ; If Player can afford bullet.
Score = Score - BulletCost ; Buy bullet.
Shooting = True ; Enable Recharging.
Bullet = New Bullet ; Create bullet.
Bullet\Owner = 1 ; Player owns bullet.
Bullet\X = PlayerX ; Bullet starts at player position.
Bullet\Y = PlayerY
Bullet\Angle = GetAngle ( MouseX () - PlayerX , MouseY () - PlayerY )
; Bullet is pointing at where your mouse cursor is, from your Player's point of view.
EndIf
EndIf
EndIf
If EnemyShooting ; If enemies are allowed to shoot...
For Enemy = Each Enemy ; Iterate through the enemy collection.
Select Enemy\Class
Case 1 ; If Enemy\Class = 1...
If Int ( Rnd ( 1 , 100 / EnemyShots ) ) = 1 ; EnemyShots (%) chance of shooting.
Bullet = New Bullet
Bullet\Owner = 2 ; Enemy owns bullet.
Bullet\X = Enemy\X ; Bullet starts at enemy position.
Bullet\Y = Enemy\Y
Bullet\Angle = GetAngle ( PlayerX - Enemy\X , PlayerY - Enemy\Y ) + Rnd ( -15 , 15 )
; Bullet is pointing at Player, from Enemy's point of view,
; with a random diffusion of max 15 degrees.
If Bullet\Angle < 0 Then Bullet\Angle = Bullet\Angle + 360
If Bullet\Angle > 359 Then Bullet\Angle = Bullet\Angle - 360
; If diffusion caused angle to go below 0 or beyond 359 degrees, warp/flip it.
; Diffusion causes Enemy's bullets to be more inaccurate for a more realistic effect.
EndIf
Case 2
If Int ( Rnd ( 1 , 200 / EnemyShots ) ) = 1 ; EnemyShots % devided by 2.
Bullet = New Bullet
Bullet\Owner = 2
Bullet\X = Enemy\X
Bullet\Y = Enemy\Y
Bullet\Angle = GetAngle ( PlayerX - PlayerX , PlayerY - PlayerY ) + Rnd ( -30 , 30 )
; Less accurate (30 degrees diffusion).
If Bullet\Angle < 0 Then Bullet\Angle = Bullet\Angle + 360
If Bullet\Angle > 359 Then Bullet\Angle = Bullet\Angle - 360
EndIf
Case 3
If Int ( Rnd ( 1 , 300 / EnemyShots ) ) = 1 ; Chance / 3.
Bullet = New Bullet
Bullet\Owner = 2
Bullet\X = Enemy\X
Bullet\Y = Enemy\Y
Bullet\Angle = GetAngle ( PlayerX - PlayerX , PlayerY - PlayerY ) + Rnd ( -45 , 45 )
; The Least accurate of the 3 (45 degrees diffusion).
If Bullet\Angle < 0 Then Bullet\Angle = Bullet\Angle + 360
If Bullet\Angle > 359 Then Bullet\Angle = Bullet\Angle - 360
EndIf
; Enemies 4 and 5 don't shoot, ever.
End Select
Next
EndIf
; Spawning Enemies:
; Spawning occurs always, if necessary, the oldest enemy will be removed to make place for a new one.
; This will cause a funny effect but also constant refreshment (increased difficulty).
; Spawning is WaitingToSpawnNextEnemy, SpawningWait is the timer for waiting before spawning.
; Enemies spawn with random position and class.
If SpawningTime > 1 Then SpawningTime = SpawningTime / 1.0001 ; Automatically decrease SpawningTime slowly.
If Spawning ; Waiting to spawn new (SpawningOld).
If SpawningWait > SpawningTime ; Ready to spawn new.
Spawning = False
SpawningWait = 0 ; Reset timer.
Else
SpawningWait = SpawningWait + 1 ; Waiting...
EndIf
Else
Spawning = True ; Enable waiting...
; This part counts the number of enemies currently in the collection (slow).
Count = 0
For Enemy = Each Enemy
Count = Count + 1
Next
; In the optimized version the program keeps track of the number of enemies manually (fast).
; E.g. "Enemies = Enemies + 1" after a "New Enemy" command and
; "Enemies = Enemies - 1" after a "Delete Enemy" command.
If Count >= MaxEnemy ; If there's already a max number of enemies...
Enemy = First Enemy ; Find the first enemy.
For x = 0 To 3 ; Make 4 pieces of shrapnel.
Shrapnel = New Shrapnel
Shrapnel\X = Enemy\X ; Position them at the enemy position.
Shrapnel\Y = Enemy\Y
Shrapnel\Angle = x * 90 + Rnd ( 90 ) ; With 4 different and random angles in 90 degrees range.
Shrapnel\Distance = 0 ; No distance travelled since creation.
Shrapnel\TotalDistance = 9 + Rnd ( 20 ) ; Distance before dissolving is at least 9 pixels
; ; plus a random value of max 20 (after rounding).
Next
Delete Enemy ; And make the enemy dissolve.
EndIf
; This part calculates the position for the enemy. A random location is okay.
; But not if it's too close to the player! E.g. spawning on a player is nasty.
px1 = PlayerX - 99 ; Creating 4 coordinates of a rectangle around the player.
px2 = PlayerX + 99 ; The size of the rectangle is in this case 198 x 198.
py1 = PlayerY - 99
py2 = PlayerY + 99
Repeat
x = Rnd ( 800 ) ; Get random coordinates for Enemy.
y = Rnd ( 600 )
Until Not ( x > px1 ) And ( x < px2 ) And ( y > py1 ) And ( y < py2 )
; Repeat getting random values until the coordinates are outside the player range.
Enemy = New Enemy ; Then spawn the new enemy.
Enemy\X = x ; At the random coordinates.
Enemy\Y = y
Enemy\Class = Rnd ( 1 , EnemyClass ) ; With a random class/type, depending on the maximum allowed.
EndIf
; Player, Enemy, Bullet and Shrapnel Movement:
; Cursor keys influence player position naturally.
; Enemies move according to their type specification.
; All bullets act the same, but move in different directions.
; For shrapnel basically the same as bullets.
If KeyDown ( KeyCursorUp ) Then PlayerY = PlayerY - 2 ; Move player 2 pixels when user wants to.
If KeyDown ( KeyCursorDown ) Then PlayerY = PlayerY + 2
If KeyDown ( KeyCursorLeft ) Then PlayerX = PlayerX - 2
If KeyDown ( KeyCursorRight ) Then PlayerX = PlayerX + 2
If PlayerX < 0 Then PlayerX = 0 ; Adjust player coordinates to prevent player from going off-screen totally.
If PlayerX > 799 Then PlayerX = 799
If PlayerY < 0 Then PlayerY = 0
If PlayerY > 599 Then PlayerY = 599
For Enemy = Each Enemy ; Loop through the enemy collection.
Select Enemy\Class ; Move enemies according to their type/class.
Case 1 ; random , max speed = EnemySpeed * sqrt(2) (read explanation below).
; This one has 1 cubic speed factor (read explanation below).
Enemy\X = Enemy\X + Rnd ( -EnemySpeed , EnemySpeed )
Enemy\Y = Enemy\Y + Rnd ( -EnemySpeed , EnemySpeed )
; Similar to player movement physics, cubic movement instead of circular.
; Only major difference is that it's totally random.
Case 2 ; random , avoid target , max speed = EnemySpeed * sqrt(2)
; This one has 2 cubic speed factors.
Enemy\X = Enemy\X + Rnd ( -EnemySpeed/2 , EnemySpeed/2 )
Enemy\Y = Enemy\Y + Rnd ( -EnemySpeed/2 , EnemySpeed/2 )
; Same as first enemy type but half the speed.
If MouseX () > Enemy\X Then Enemy\X = Enemy\X - EnemySpeed/2
If MouseX () < Enemy\X Then Enemy\X = Enemy\X + EnemySpeed/2
If MouseY () > Enemy\Y Then Enemy\Y = Enemy\Y - EnemySpeed/2
If MouseY () < Enemy\Y Then Enemy\Y = Enemy\Y + EnemySpeed/2
; Adding an intelligent bit, avoiding the mouse cursor.
Case 3 ; random , avoid target , hunt player , max speed = EnemySpeed * sqrt(2)
; This one has 3 cubic speed factors.
Enemy\X = Enemy\X + Rnd ( -EnemySpeed/3 , EnemySpeed/3 )
Enemy\Y = Enemy\Y + Rnd ( -EnemySpeed/3 , EnemySpeed/3 )
; Same as first enemy, but a third of the random speed.
If PlayerX < Enemy\X Then Enemy\X = Enemy\X - EnemySpeed/3
If PlayerX > Enemy\X Then Enemy\X = Enemy\X + EnemySpeed/3
If PlayerY < Enemy\Y Then Enemy\Y = Enemy\Y - EnemySpeed/3
If PlayerY > Enemy\Y Then Enemy\Y = Enemy\Y + EnemySpeed/3
; This piece hunts the player.
If MouseX () > Enemy\X Then Enemy\X = Enemy\X - EnemySpeed/3
If MouseX () < Enemy\X Then Enemy\X = Enemy\X + EnemySpeed/3
If MouseY () > Enemy\Y Then Enemy\Y = Enemy\Y - EnemySpeed/3
If MouseY () < Enemy\Y Then Enemy\Y = Enemy\Y + EnemySpeed/3
; Same as second enemy type, avoiding the mouse cursor.
Case 4 ; random , hunt 8-way player , max speed = EnemySpeed * sqrt(2)
; This one has 2 cubic speed factors.
Enemy\X = Enemy\X + Rnd ( -EnemySpeed/2 , EnemySpeed/2 )
Enemy\Y = Enemy\Y + Rnd ( -EnemySpeed/2 , EnemySpeed/2 )
; Same as first enemy, but half the speed.
If PlayerX < Enemy\X Then Enemy\X = Enemy\X - EnemySpeed/2
If PlayerX > Enemy\X Then Enemy\X = Enemy\X + EnemySpeed/2
If PlayerY < Enemy\Y Then Enemy\Y = Enemy\Y - EnemySpeed/2
If PlayerY > Enemy\Y Then Enemy\Y = Enemy\Y + EnemySpeed/2
; Again, hunting the player.
Case 5 ; random , hunt 360-way player , max speed = EnemySpeed
; This one has 2 circular speed factors.
x = GetVectorX ( EnemySpeed/2 , Rnd ( 360 ) )
y = GetVectorY ( EnemySpeed/2 , Rnd ( 360 ) )
; Get the X and Y disposition coordinates of half the enemy speed in a random direction.
a = GetAngle ( PlayerX - Enemy\X , PlayerY - Enemy\Y )
; Get the absolute angle to the Player position from the Enemy's point of view.
Enemy\X = Enemy\X + GetVectorX ( EnemySpeed/2 , z ) + x
Enemy\Y = Enemy\Y + GetVectorY ( EnemySpeed/2 , z ) + y
; Updates the enemy's position with:
; 1) The disposition coordinates of half the enemy speed in the player's direction.
; 2) The disposition coordinates of half the enemy speed in a random direction.
; Difference between Cubic and Circular motion:
;
; ooooooooO |
; o /o |
; o / o |
; o / o |
; o O o | Cubic movement.
; o o |
; o o |
; o o |
; ooooooooo |
;
; ooooooooO | Cubic motion vector:
; o V /| | Vector V [X|Y]
; o / |Y |
; o / | | X = EnemySpeed
; o O---O | Y = EnemySpeed
; o X o | V = Sqrt( EnemySpeed^2 + EnemySpeed^2 ) = EnemySpeed * Sqrt( 2 )
; o o |
; o o | So the length of V is actually more than is allowed in this case.
; ooooooooo | The circular movement preserves the original values, e.g. cubic movement is 'cheating'.
;
; ooo |
; ooo ooO |
; o /o |
; oo / oo |
; o O o | Circular movement.
; oo oo |
; o o |
; ooo ooo |
; ooo |
;
; ooo | Circular motion vector:
; ooo ooO | Vector V [X|Y]
; o V /|Y |
; oo / |o | V = EnemySpeed
; o O--Oo | X = GetVectorX ( V , Angle )
; oo X oo | Y = GetVectorY ( V , Angle )
; o o |
; ooo ooo | Angle is the angle of the vector between line X and V.
; ooo | The Vector routines use an orientation where an angle of 0 is always straight up.
;
End Select
If Enemy\X < 0 Then Enemy\X = 0 ; Make sure the enemies don't move totally off-screen.
If Enemy\X > 799 Then Enemy\X = 799
If Enemy\Y < 0 Then Enemy\Y = 0
If Enemy\Y > 599 Then Enemy\Y = 599
; In an Asteroids type of game one would change the first line to: "If Enemy\X < 0 Then Enemy\X = Enemy\X + 800"
Next
For Bullet = Each Bullet ; Walk through the bullet collection.
Bullet\X = Bullet\X + GetVectorX ( 5 , Bullet\Angle ) ; Update the bullet's position with a distance/length of 5
Bullet\Y = Bullet\Y + GetVectorY ( 5 , Bullet\Angle ) ; circular pixels and the angle of the bullet itself.
If ( Bullet\X < 0 ) Or ( BulletX > 799 ) Or ( Bullet\Y < 0 ) Or ( Bullet\Y > 599 ) Then Delete Bullet
; In the case of bullets, they are no longer required when going off-screen.
Next
For Shrapnel = Each Shrapnel ; Iterate through all pieces of shrapnel.
Shrapnel\X = Shrapnel\X + GetVectorX ( 1 , Shrapnel\Angle ) ; Shrapnel pieces move 1 pixel per frame, in the
Shrapnel\Y = Shrapnel\Y + GetVectorY ( 1 , Shrapnel\Angle ) ; direction of the angle specified at creation time.
If Shrapnel\Distance >= Shrapnel\TotalDistance ; But if the covered distance is enough, wipe it out.
Delete Shrapnel
Else ; Otherwise keep movin'.
Shrapnel\Distance = Shrapnel\Distance + 1
If ( Shrapnel\X < 0 ) Or ( Shrapnel\X > 799 ) Or ( Shrapnel\Y < 0 ) Or ( Shrapnel\Y > 599 ) Then Delete Shrapnel
; If going off-screen, like bullets, no need in using them anymore.
EndIf
Next
; Collisions:
; Enemy colliding with Player results in Enemy 'exploding' and score going down.
; Enemy colliding with Player bullet results in Enemy 'exploding', bullet dissolving, and score going up.
; Player colliding with Enemy bullet results in bullet dissolving and score going down.
For Enemy = Each Enemy
If ImagesCollide ( EnemyBitmap , Enemy\X , Enemy\Y , 0 , PlayerBitmap , PlayerX , PlayerY , 0 )
; Test for collision between Enemy and Player (pixel-perfect)
For x = 0 To 3 ; If collision detected, make just another quad-shrapnel with the good 'ol values.
Shrapnel = New Shrapnel
Shrapnel\X = Enemy\X
Shrapnel\Y = Enemy\Y
Shrapnel\Angle = x * 90 + Rnd ( 90 )
Shrapnel\Distance = 0
Shrapnel\TotalDistance = 9 + Rnd ( 20 )
Next
Delete Enemy ; Delete Enemy after creating the Shrapnel, because we needed the enemy position for it.
If Not GodMode Then Score = Score - 1000 ; And score goes down by 1000 points (!) but not in GodMode.
EndIf
Next
For Enemy = Each Enemy
For Bullet = Each Bullet
; To see when 'each' bullet collides with 'each' enemy, we have to loop through both collections simultaneously.
If Bullet\Owner = 1 ; Only checking the bullets owner by Player.
If ImagesCollide ( EnemyBitmap , Enemy\X , Enemy\Y , 0 , BulletBitmap , Bullet\X , Bullet\Y , 0 )
; Pixel-perfect collision detection between Enemy and Bullet.
Score = Score + 100 * Enemy\Class + 1000 * EnemyShooting
; If there's a collision, the score increases depending on the Enemy type/class.
; The simplest enemy is 100 points and the most advanced enemy is 500 points.
; If the enemies are shooting, an addition of 1000 points is granted.
; In the optimized version of the game, the size of the addition depends on enemy shot accuracy.
For x = 0 To 3 ; As usual, make the enemy turn into shrapnel.
Shrapnel = New Shrapnel
Shrapnel\X = Enemy\X
Shrapnel\Y = Enemy\Y
Shrapnel\Angle = x * 90 + Rnd ( 90 )
Shrapnel\Distance = 0
Shrapnel\TotalDistance = 9 + Rnd ( 20 )
Next
Delete Bullet ; Don't forget to remove the bullet.
Delete Enemy ; As well as the enemy.
Exit
EndIf
EndIf
Next
Next
For Bullet = Each Bullet
If Bullet\Owner = 2 ; If this bullet is an Enemy bullet...
If ImagesCollide ( PlayerBitmap , PlayerX , PlayerY , 0 , BulletBitmap , Bullet\X , Bullet\Y , 0 )
; Collide between Player and Bullet.
Delete Bullet ; Simply remove the bullet.
If Not GodMode Then Score = Score - 100 ; And decrease the score, but not in GodMode.
EndIf
EndIf
Next
If Score < 0 Then Score = 0 ; Game isn't totally unfriendly, score is always positive.
; Rendering:
; Drawing all bitmaps for shrapnel, enemies, bullets, player and mouse crosshair.
; (In that order respectively, to make sure the right things overlap each other)
; And lots of other neat little thingies that increase the quality of the gaming experience.
For Shrapnel = Each Shrapnel ; Draw each piece of shrapnel at the designated coordinates.
DrawImage ShrapnelBitmap , Shrapnel\X , Shrapnel\Y
Next
For Enemy = Each Enemy ; Same for all enemies.
DrawImage EnemyBitmap , Enemy\X , Enemy\Y
Next
For Bullet = Each Bullet ; And bullets.
DrawImage BulletBitmap , Bullet\X , Bullet\Y
Next
DrawImage PlayerBitmap , PlayerX , PlayerY ; Only one player.
DrawImage TargetBitmap , MouseX () , MouseY () ; Target is directly controlled by the mouse.
Color 0 , 127 , 255 ; Display score and highscore, centered on center coordinates.
Text 200 , 590 , "Score: " + WithComma ( Score ) , True , True ; Uses WithComma() function.
Text 600 , 590 , "High: " + WithComma ( HighScore ) , True , True ; See below.
If Not GodMode ; Show level in number of red "¤", unless in godmode.
Color 255 , 0 , 0
Text 400 , 590 , String ( "¤" , Level ) , True , True
EndIf
Color 63 , 127 , 0 ; Show the enemy spawn speed in a bar.
Rect 300 , 596 , ( 100 - SpawningTime ) * 2 , 2 , False ; Assumes SpawningTime is 100 by default.
Color 47 , 95 , 0
Rect 298 , 594 , 200 + 2 , 6 , False ; Outer frame.
; This shows the Recharging meter.
If ShootDelay > 40 ; Don't show the meter if recharging is fast enough.
If Shooting ; Currently recharging (ShootingOld)
Color 63 , 127 , 0
Rect 10 , 10 , ShootingWait * 780 / ShootDelay , 10 , True ; Percent-like formula.
Color 47 , 95 , 0
Rect 8 , 8 , 780 + 4 , 14 , False ; Outer frame.
Color 95 , 191 , 0
Text 400 , 15 , "RECHARGING" , True , True
EndIf
EndIf
; The optimized version features a Pause function and a Frame limiting method switch.
Flip True ; Hardware frame-limiting, e.g. wait for a vertical blank each frame.
Cls ; Then clear the screen, since we have no background picture or something like that.
Until KeyHit ( KeyEscape ) ; Quit the game when pressing Escape.
Delete Each Shrapnel ; Clean up all collections.
Delete Each Bullet ; Blitz can happily do it for you, normally.
Delete Each Enemy ; But there are lots of cases where even Blitz can't.
FreeImage ShrapnelBitmap ; And remove all images.
FreeImage BulletBitmap ; Sometimes you can work behind Blitz' back to accomplish things that
FreeImage EnemyBitmap ; cannot normally be done with solely native Blitz commands. In these
FreeImage PlayerBitmap ; cases it is imperative to clean up all things yourself.
FreeFont Font ; Don't forget font.
FreeTimer Timer ; Almost forgot the timer.
EndGraphics ; This command is also automatically executed when exiting your Blitz program.
Color 255 , 255 , 255
Print "Shutting down automatically..."
End
Function WithComma$ ( Number$ ) ; This function generates comma's in a number.
; This function is really slow but it's very easy to understand what's going on.
Local Reverse$
Local Comma$
For x = 1 To Len ( Number ) ; Go through each position in the number (backwards).
Reverse = Reverse + Mid ( Number , Len ( Number ) - x + 1 , 1 )
Counter = Counter + 1
If Counter = 3 ; And put a comma where necessary.
Counter = 0
Reverse = Reverse + ","
EndIf
Next
For x = 1 To Len ( Reverse ) ; Reverse the string.
Comma = Comma + Mid ( Reverse , Len ( Reverse ) - x + 1 , 1 )
Next
If Left ( Comma , 1 ) = "," Then Comma = Mid ( Comma , 2 , Len ( Comma ) - 1 ) ; Remove leading comma.
Return Comma ; Return generated result.
End Function
               (
geocities.com/thechange)