' We include FreeBASIC's built-in library and allow ' the usage of its additional constants and functions ' with Using FB. #include "fbgfx.bi" Using FB ' We set some needed constants. const fpslimit = 60 const FALSE = 0 const TRUE = 1 const PI = 3.141593 const numofCPUobjects = 20 const numofprojectiles = 50 const numofstars = 1000 const numofplanets = 4 ' Screen size related constants. const screenwidth = 640 const screenheight = 480 const screenmidx = screenwidth/2 const screenmidy = screenheight/2 ' A subroutine used to initiate projectiles (when the player or ' enemy object shoots it). DECLARE SUB InitiateProjectile (px AS SINGLE, py AS SINGLE, pangle AS SINGLE, ptyp AS INTEGER) ' A subroutine that draws and manages active (initiated) projectiles. DECLARE SUB DrawProjectiles () DECLARE SUB DrawStars () DECLARE SUB DrawPlanets () DECLARE SUB DrawMoveShips () ' Custom data types for our misc. objects in the program (projectiles, ' cpu controlled objects, etc.). TYPE ObjType X AS SINGLE ' Used to flag object's x position. Y AS SINGLE ' Used to flag object's y position. AngleDeg AS INTEGER ' Used to flag object's angle in degrees. AngleRad AS SINGLE ' Used to flag object's angle in radians. Speed AS SINGLE ' Used to flag object's speed. RotationSpeed AS SINGLE ' Used to flag object's rotation speed Active AS INTEGER ' Used to flag object's status ActiveTime AS INTEGER ' Use to expire object's activity (once we activate it). Typ AS INTEGER ' Used to flag type of the object (if we want to ' have more kinds of the same object -> different ' ships, projectiles, etc.). ASMode AS INTEGER ' Used to flag the artificial smart type of a ship. ASSubMode AS INTEGER ' Used to flag the artificial smart sub mode of a ship (attacking, running, etc.) Reload AS INTEGER END TYPE ' We declare the needed variables. DIM SHARED workpage AS INTEGER ' The following 3 variables are used for ' frames per second control. DIM SHARED st AS DOUBLE DIM SHARED frameintvl As Double = 1.0/fpslimit DIM SHARED sleepintvl As Integer DIM SHARED angledeg AS INTEGER ' Main object's angle in degrees DIM SHARED anglerad AS SINGLE ' Main object's angle in radians DIM SHARED mainx AS SINGLE ' Main object's x pos DIM SHARED mainy AS SINGLE ' Main object's y pos DIM SHARED mainspeed AS SINGLE ' Main object's speed DIM SHARED main_rotationspeed AS SINGLE ' Main object's rotation speed DIM SHARED main_reload AS INTEGER ' Use to flag how many loops need to ' pass before the player can shoot ' another projectile (emulates ' weapon reload feature). DIM SHARED resultangledeg AS INTEGER ' Angle between the cpu cont. object and main object in degrees DIM SHARED resultanglerad AS SINGLE ' Angle between the cpu cont. object and main object in radians DIM SHARED ASmode AS INTEGER ' artificial smarts control (on/off) DIM SHARED CPUobject(numofCPUobjects) AS ObjType ' Our CPU controlled objects DIM SHARED Projectile(numofprojectiles) AS ObjType ' Our projectiles DIM SHARED Star(numofstars) AS ObjType ' Our stars DIM SHARED Planet(numofplanets) AS ObjType ' Our planets ' camera variables flag the camera position, while MapXMax and ' MapYMax the size of the playfield (in pixels). DIM SHARED AS INTEGER cameraX, cameraY DIM SHARED AS INTEGER MapXMax, MapYMax DIM SHARED AS INTEGER targetX, targetY DIM SHARED AS INTEGER ASdirection ' We set our screen to 640 width, 480 height, 32 color bit-depth, ' 2 work pages and full screen. SCREENRES screenwidth, screenheight, 32, 2, GFX_FULLSCREEN ' We set the initial values for the main object's ' and CPU controlled object's positions/angles/speeds. mainx = 1000 mainy = 1000 mainspeed = 4 main_rotationspeed = 3 angledeg = 0 ASMode = TRUE MapXMax = 2000 MapYMax = 2000 ' Get the random seed from the seconds past midnight (the ' best way to get random numbers). RANDOMIZE TIMER ' We loop through our cpu controlled object and initiate ' their variables. FOR initCPUobj AS INTEGER = 1 TO numofCPUobjects CPUobject(initCPUobj).X = INT(RND * 600) + 720 ' Randomize cpu object's position from 20 to 620 CPUobject(initCPUobj).Y = INT(RND * 440) + 820 ' Randomize cpu object's position from 20 to 460 CPUobject(initCPUobj).AngleDeg = INT(RND * 360) + 1 ' Randomize cpu object's angle from 1 to 360 CPUobject(initCPUobj).AngleRad = (CPUobject(initCPUobj).AngleDeg*PI)/180 CPUobject(initCPUobj).RotationSpeed = INT(RND * 2) + 2 ' Randomize cpu object's rotation speed from 2 to 3 CPUobject(initCPUobj).Speed = INT(RND * 3) + 1 ' Randomize cpu object's rotation speed from 1 to 3 CPUobject(initCPUobj).Active = TRUE ' All object active (alive) by default. CPUobject(initCPUobj).ASMode = 2 ' Make one half of computer controlled objects use AIMode 1. IF initCPUobj < 11 THEN CPUobject(initCPUobj).ASMode = 1 CPUobject(initCPUobj).ASSubMode = 1 NEXT initCPUobj ' Initiate stars (randomize their position in the playfield ' and their type). FOR initstar AS INTEGER = 1 TO numofstars Star(initstar).X = INT(RND * 2000) + 1 Star(initstar).Y = INT(RND * 2000) + 1 Star(initstar).Typ = INT(RND * 6) + 1 NEXT initstar ' Initiate planets. FOR initplanet AS INTEGER = 1 TO numofplanets Planet(initplanet).X = INT(RND * 1800) + 100 Planet(initplanet).Y = INT(RND * 1800) + 100 Planet(initplanet).Typ = INT(RND * 3) + 1 NEXT initplanet ' Your average do loop. DO st = Timer ' Record the current time into st variable ' (used to limit FPS; not related to the ' topic of the example program). screenlock ' Lock our screen (nothing will be ' displayed until we unlock the screen). screenset workpage, workpage xor 1 ' Swap work pages. ' The control keys for the main (player's) object. IF MULTIKEY(SC_LEFT) THEN angledeg = angledeg - main_rotationspeed IF MULTIKEY(SC_RIGHT) THEN angledeg = angledeg + main_rotationspeed ' The following lines keep the angle between ' 0 and 360. IF angledeg<0 THEN angledeg=angledeg+360 IF angledeg>359 THEN angledeg=angledeg-360 anglerad = (angledeg*PI)/180 ' Convert the angle from degrees to radians IF MULTIKEY(SC_UP) THEN mainx = mainx + sin(anglerad)*mainspeed mainy = mainy - cos(anglerad)*mainspeed IF mainx < 3 OR mainx > MapXMax - 3 THEN mainx = mainx - sin(anglerad)*mainspeed IF mainy < 3 OR mainy > MapYMax - 3 THEN mainy = mainy + cos(anglerad)*mainspeed END IF ' Update camera. cameraX = mainx - screenmidx cameraY = mainy - screenmidy ' Keep the camera within the playfield. IF cameraX < 0 THEN cameraX = 0 IF cameraY < 0 THEN cameraY = 0 ' cameraX = 1000 - 320 = 680 ' cameraX = 680 - 320 = 320 ' MapXMax - screenwidth = 1000 - 640 = 360 IF cameraX > MapXMax - screenwidth THEN cameraX = MapXMax - screenwidth IF cameraY > MapYMax - screenheight THEN cameraY = MapYMax - screenheight ' It the player pressed space and the weapon is ' ready for shooting (main_reload = 0), initiate ' a new projectile. IF MULTIKEY(SC_SPACE) AND main_reload = 0 THEN main_reload = 10 ' The next line initiates a new projectile from the ' top of the main object's direction line, with the ' current main object angle, and using projectile ' type 1. InitiateProjectile mainx+sin(anglerad)*20,mainy-cos(anglerad)*20, anglerad, 1 END IF IF MULTIKEY(SC_M) AND main_reload = 0 THEN main_reload = 20 InitiateProjectile mainx+sin(anglerad)*20,mainy-cos(anglerad)*20, anglerad, 2 END IF ' Use to reset the weapon for new shooting (the ' player cannot shoot until main_reload reaches 0, and it ' is reduced by 1 in every loop). IF main_reload > 0 THEN main_reload = main_reload - 1 ' For turning AS on/off. IF MULTIKEY(SC_1) THEN ASMode = TRUE IF MULTIKEY(SC_2) THEN ASMode = FALSE CLS ' Clear the screen DrawStars DrawPlanets DrawMoveShips ' We draw an help Cartesian coordinate system. LINE (50, 80)-(110,80), RGB(255,255,255) LINE (80, 50)-(80,110), RGB(255,255,255) Draw String (77,40), "0", RGB(0, 176, 214) Draw String (69,114), "180", RGB(0, 176, 214) Draw String (114,76), "90", RGB(0, 176, 214) Draw String (23,76), "270", RGB(0, 176, 214) Draw String (12,200), "1 - AI On", RGB(0, 176, 214) Draw String (12,210), "2 - AI Off", RGB(0, 176, 214) ' We display some useful textual information. Draw String (320,10), "Main object's angle:"+STR$(angledeg), RGB(2,117, 190) Draw String (320,30), "CameraX:"+STR$(cameraX), RGB(2,117, 190) Draw String (320,40), "CameraY:"+STR$(cameraY), RGB(2,117, 190) Draw String (320,50), "mainX:"+STR$(mainx), RGB(2,117, 190) Draw String (320,60), "mainY:"+STR$(mainy), RGB(2,117, 190) ' Draw the player's object on the screen. ' Direction line and a circle. 'LINE (mainx-cameraX, mainy-cameraY)-(mainx-cameraX+sin(anglerad)*20,mainy-cameraY-cos(anglerad)*20), RGB(200, 0, 0) 'CIRCLE (mainx-cameraX, mainy-cameraY), 3, RGB(200, 0, 0) ' Triangle representing the player drawn with polar method. LINE (mainx-cameraX+sin(anglerad)*10,mainy-cameraY-cos(anglerad)*10)-(mainx-cameraX+sin(anglerad+PI*3/4)*10,mainy-cameraY-cos(anglerad+PI*3/4)*10), RGB(250,0, 0) LINE (mainx-cameraX+sin(anglerad+PI*3/4)*10,mainy-cameraY-cos(anglerad+PI*3/4)*10)-(mainx-cameraX+sin(anglerad+PI)*3,mainy-cameraY-cos(anglerad+PI)*3), RGB(250,0, 0) LINE (mainx-cameraX+sin(anglerad+PI)*3,mainy-cameraY-cos(anglerad+PI)*3)-(mainx-cameraX+sin(anglerad+PI*5/4)*10,mainy-cameraY-cos(anglerad+PI*5/4)*10), RGB(250,0, 0) LINE (mainx-cameraX+sin(anglerad+PI*5/4)*10,mainy-cameraY-cos(anglerad+PI*5/4)*10)-(mainx-cameraX+sin(anglerad)*10,mainy-cameraY-cos(anglerad)*10), RGB(250,0, 0) ' Draw the map border on the scren. LINE (MapXMax-1-camerax, MapYMax-1-cameray)-(0-camerax,MapYMax-1-cameray), RGB(255,255,255) LINE (MapXMax-1-camerax, 0-cameray)-(MapXMax-1-camerax,MapYMax-1-cameray), RGB(255,255,255) LINE (0-camerax, 0-cameray)-(MapXMax-1-camerax,0-cameray), RGB(255,255,255) LINE (0-camerax, MapYMax-1-cameray)-(0-camerax,0-cameray), RGB(255,255,255) DrawProjectiles ' Projectile layer. workpage xor = 1 ' Swap work pages. screenunlock ' Unlock the page to display what has been drawn. ' Keep the FPS value within fpslimit (set above). sleepintvl = Cint((st + frameintvl - Timer)*1000.0) If sleepintvl>1 Then Sleep sleepintvl else sleep 1 end if LOOP UNTIL MULTIKEY(SC_ESCAPE) ' Do loop until ESC is pressed. SUB InitiateProjectile (px AS SINGLE, py AS SINGLE, pangle AS SINGLE, ptyp AS INTEGER) ' We loop through our projectiles looking for a free one (never used ' before or expired -> ActiveTime = 0). FOR initproj AS INTEGER = 1 TO numofprojectiles ' When a free projectile is found we set its position, type, ' life time (ActiveTime = 30 -> 30 loops) and angle. After this ' the subroutine is exited so that a next free projectile wouldn't ' be initiated too. IF Projectile(initproj).ActiveTime = 0 THEN Projectile(initproj).X = px Projectile(initproj).Y = py Projectile(initproj).AngleRad = pangle Projectile(initproj).Typ = ptyp ' According to given projectile's type we can ' set other projectile's characteristics. ' In this program we'll only set projectile's ' speed according to its type. ' Projectile type 1 will and should only be used ' with the main player since we added a condition ' that the projectile's speed will be increased ' by the main object's speed if it is moving. IF Projectile(initproj).Typ = 1 THEN Projectile(initproj).Speed = 5 IF MULTIKEY(SC_UP) THEN Projectile(initproj).Speed = Projectile(initproj).Speed + mainspeed END IF IF Projectile(initproj).Typ = 2 THEN Projectile(initproj).Speed = 4 Projectile(initproj).RotationSpeed = 4 IF MULTIKEY(SC_UP) THEN Projectile(initproj).Speed = Projectile(initproj).Speed + mainspeed END IF IF Projectile(initproj).Typ = 5 THEN Projectile(initproj).Speed = 3 Projectile(initproj).ActiveTime = 80 EXIT SUB END IF NEXT initproj END SUB SUB DrawProjectiles () FOR countproj AS INTEGER = 1 TO numofprojectiles ' We loop through our projectiles and if an active one is ' found, we move and draw it. IF Projectile(countproj).ActiveTime > 0 THEN ' The next line is used to expire the projectile so it wouldn't ' be active infinitely. We can do this on different ways, like ' by deactivating an object once it passes the edge of screen. ' Still, this is a very handy way of setting the "life time" of an object. Projectile(countproj).ActiveTime = Projectile(countproj).ActiveTime - 1 ' Projectiles are moved just like the main and computer controlled ' objects. Projectile(countproj).X = Projectile(countproj).X + sin(Projectile(countproj).AngleRad)*Projectile(countproj).Speed Projectile(countproj).Y = Projectile(countproj).Y - cos(Projectile(countproj).AngleRad)*Projectile(countproj).Speed ' According to projectile type, we draw it. SELECT CASE Projectile(countproj).Typ CASE 1 LINE (Projectile(countproj).X-cameraX, Projectile(countproj).Y-cameraY)-(Projectile(countproj).X-cameraX+sin(Projectile(countproj).Anglerad)*3,Projectile(countproj).Y-cameraY-cos(Projectile(countproj).AngleRad)*3), RGB(192, 192, 0) CASE 2 LINE (Projectile(countproj).X-cameraX, Projectile(countproj).Y-cameraY)-(Projectile(countproj).X-cameraX+sin(Projectile(countproj).Anglerad)*3,Projectile(countproj).Y-cameraY-cos(Projectile(countproj).AngleRad)*3), RGB(200, 200, 200) LINE (Projectile(countproj).X+sin(Projectile(countproj).Anglerad)*2-cameraX, Projectile(countproj).Y-cos(Projectile(countproj).AngleRad)*2-cameraY)-(Projectile(countproj).X-cameraX+sin(Projectile(countproj).Anglerad)*3,Projectile(countproj).Y-cameraY-cos(Projectile(countproj).AngleRad)*3), RGB(222, 0, 0) CASE 5 LINE (Projectile(countproj).X-cameraX, Projectile(countproj).Y-cameraY)-(Projectile(countproj).X-cameraX+sin(Projectile(countproj).Anglerad)*3,Projectile(countproj).Y-cameraY-cos(Projectile(countproj).AngleRad)*3), RGB(222, 10, 0) END SELECT ' The next FOR loop checks for collision with all the ' active computer controlled objects, and if collision is ' preset (pixel distance check), we deactivate (kill) that ' computer controlled object. FOR colcheckobj AS INTEGER = 1 TO numofCPUobjects ' If the current projectiles is less that 4 pixels horizontally ' and vertically to an computer controlled object, if the projectile ' type is less than 5 (a projectile shot by the player) diactivate ' that object and the projectile. IF (Projectile(countproj).Typ < 5 AND CPUObject(colcheckobj).Active = TRUE AND ABS(CPUObject(colcheckobj).X-Projectile(countproj).X) < 5 AND ABS(CPUObject(colcheckobj).Y-Projectile(countproj).Y) < 5) THEN ' Initiate some explosions (once you implement an explosion layer) ' Add score to player ' Etc. CPUObject(colcheckobj).Active = FALSE Projectile(countproj).ActiveTime = 0 END IF ' If the current projectile is typ 2 (homing missile) ' instruct it to follow the closest computer controlled ' object. Same artificial smart code as with computer ' controlled objects. IF (Projectile(countproj).Typ = 2 AND CPUObject(colcheckobj).Active = TRUE AND ABS(CPUObject(colcheckobj).X-Projectile(countproj).X) < 100 AND ABS(CPUObject(colcheckobj).Y-Projectile(countproj).Y) < 100) THEN ' Missile always moving TOWARD the target and ' target always the closest computer controlled ' object. ASdirection = 1 targetY = CPUObject(colcheckobj).Y targetX = CPUObject(colcheckobj).X resultanglerad = ATAN2((-1)*(targetY-Projectile(countproj).Y),(targetX-Projectile(countproj).X)) resultanglerad = PI/2 - resultanglerad IF resultanglerad < 0 THEN resultanglerad = resultanglerad + 2*PI resultangledeg = (resultanglerad*180)/PI Projectile(countproj).AngleDeg = (Projectile(countproj).AngleRad*180)/PI IF Projectile(countproj).AngleDeg > resultangledeg THEN IF (360-Projectile(countproj).AngleDeg+resultangledeg) >= (Projectile(countproj).AngleDeg-resultangledeg) THEN Projectile(countproj).AngleDeg = Projectile(countproj).AngleDeg - Projectile(countproj).RotationSpeed*ASdirection IF (360-Projectile(countproj).AngleDeg+resultangledeg) < (Projectile(countproj).AngleDeg-resultangledeg) THEN Projectile(countproj).AngleDeg = Projectile(countproj).AngleDeg + Projectile(countproj).RotationSpeed*ASdirection END IF IF Projectile(countproj).AngleDeg < resultangledeg THEN IF (360-resultangledeg+Projectile(countproj).AngleDeg) >= (resultangledeg-Projectile(countproj).AngleDeg) THEN Projectile(countproj).AngleDeg = Projectile(countproj).AngleDeg + Projectile(countproj).RotationSpeed*ASdirection IF (360-resultangledeg+Projectile(countproj).AngleDeg) < (resultangledeg-Projectile(countproj).AngleDeg) THEN Projectile(countproj).AngleDeg = Projectile(countproj).AngleDeg - Projectile(countproj).RotationSpeed*ASdirection END IF IF Projectile(countproj).AngleDeg<0 THEN Projectile(countproj).AngleDeg=Projectile(countproj).AngleDeg+360 IF Projectile(countproj).AngleDeg>359 THEN Projectile(countproj).AngleDeg=Projectile(countproj).AngleDeg-360 Projectile(countproj).AngleRad = (Projectile(countproj).AngleDeg*PI)/180 EXIT FOR END IF ' If the current projectiles is less that 4 pixels horizontally ' and vertically from the player, if the projectile ' type is more than 4 (not player's projectile) reduce ' player's energy and diactivate the projectile. IF (Projectile(countproj).Typ > 4 AND ABS(mainx-Projectile(countproj).X) < 5 AND ABS(mainy-Projectile(countproj).Y) < 5) THEN ' Initiate some explosions (once you implement an explosion layer) ' Reduce player's energy ' "Kill" him if energy < 0 ' Etc. Projectile(countproj).ActiveTime = 0 END IF NEXT colcheckobj END IF NEXT countproj END SUB SUB DrawStars () ' Loop through stars and draw them according to their type. ' Type 5 and type 6 are larger stars, and thus require more ' drawing primitives to be drawn. FOR countstar AS INTEGER = 1 TO numofstars SELECT CASE Star(countstar).Typ CASE 1 PSET (Star(countstar).X-cameraX, Star(countstar).Y-cameraY), RGB(255,255,255) CASE 2 PSET (Star(countstar).X-cameraX, Star(countstar).Y-cameraY), RGB(205,205,205) CASE 3 PSET (Star(countstar).X-cameraX, Star(countstar).Y-cameraY), RGB(100,100,100) CASE 4 PSET (Star(countstar).X-cameraX, Star(countstar).Y-cameraY), RGB(150,150,150) CASE 5 LINE (Star(countstar).X-1-cameraX, Star(countstar).Y-cameraY)-(Star(countstar).X+1-cameraX, Star(countstar).Y-cameraY), RGB(90,90,90) LINE (Star(countstar).X-cameraX, Star(countstar).Y-1-cameraY)-(Star(countstar).X-cameraX, Star(countstar).Y+1-cameraY), RGB(90,90,90) PSET (Star(countstar).X-cameraX, Star(countstar).Y-cameraY), RGB(250,250,250) CASE 6 LINE (Star(countstar).X-1-cameraX, Star(countstar).Y-cameraY)-(Star(countstar).X+1-cameraX, Star(countstar).Y-cameraY), RGB(50,50,50) LINE (Star(countstar).X-cameraX, Star(countstar).Y-1-cameraY)-(Star(countstar).X-cameraX, Star(countstar).Y+1-cameraY), RGB(50,50,50) PSET (Star(countstar).X-cameraX, Star(countstar).Y-cameraY), RGB(170,170,170) END SELECT NEXT countstar END SUB SUB DrawPlanets () ' Loop through planets and draw them according to their type. FOR countplanet AS INTEGER = 1 TO numofplanets SELECT CASE Planet(countplanet).Typ CASE 1 CIRCLE (Planet(countplanet).X-cameraX, Planet(countplanet).Y-cameraY), 20, RGB(168,24,24),,,,F CIRCLE (Planet(countplanet).X-cameraX, Planet(countplanet).Y-cameraY), 20, RGB(148,4,4) CASE 2 CIRCLE (Planet(countplanet).X-cameraX, Planet(countplanet).Y-cameraY), 40, RGB(255,255,128),,,,F CIRCLE (Planet(countplanet).X-cameraX, Planet(countplanet).Y-cameraY), 40, RGB(205,205,88) CASE 3 CIRCLE (Planet(countplanet).X-cameraX, Planet(countplanet).Y-cameraY), 25, RGB(0,192,0),,,,F CIRCLE (Planet(countplanet).X-cameraX, Planet(countplanet).Y-cameraY), 25, RGB(0,152,0) END SELECT NEXT countplanet END SUB SUB DrawMoveShips () FOR countCPUobj AS INTEGER = 1 TO numofCPUobjects ' Loop through all the objects ' If ASMode is true apply the artificial smart code ' on the current CPU controlled object IF ASMode = TRUE THEN ' By default the target is player's object. targetX = mainx targetY = mainy ' By default computer controlled object rotates TOWARD ' the target. ASdirection = 1 ' If the computer controlled object's ASMode = 1 and ' the player's object is not near him travel to point A (120, 120) ' or point B (1700,400) according to ASSubMode. IF CPUobject(countCPUobj).ASMode = 1 THEN IF ABS(CPUobject(countCPUobj).X-mainx)>80 OR ABS(CPUobject(countCPUobj).Y-mainy)>80 THEN IF CPUobject(countCPUobj).ASSubMode = 1 THEN targetX = 120 targetY = 120 END IF IF CPUobject(countCPUobj).ASSubMode = 2 THEN targetX = 1700 targetY = 400 END IF ' Change AS sub mode if reached one or the other point. IF ABS(CPUobject(countCPUobj).X-targetX)<20 AND ABS(CPUobject(countCPUobj).Y-targetY)<20 THEN IF CPUobject(countCPUobj).ASSubMode = 1 THEN CPUobject(countCPUobj).ASSubMode = 2 ELSE CPUobject(countCPUobj).ASSubMode = 1 END IF END IF END IF END IF ' If the computer controlled object's ASMode = 2 ' swap between attack (ASdirection = 1) and ' run modes (ASdirection = - 1). IF CPUobject(countCPUobj).ASMode = 2 THEN IF CPUobject(countCPUobj).ASSubMode = 1 THEN ' Attack mode. Swap to run mode if ' less than 50 pixels away in both directions ' from the target. ASDirection = 1 IF ABS(CPUobject(countCPUobj).X-targetX)<50 AND ABS(CPUobject(countCPUobj).Y-targetY)<50 THEN CPUobject(countCPUobj).ASSubMode = 2 END IF IF CPUobject(countCPUobj).ASSubMode = 2 THEN ' Run mode. Swap to attack mode if ' more than 200 pixels away in any direction ' from the target. ASDirection = -1 IF ABS(CPUobject(countCPUobj).X-targetX)>200 OR ABS(CPUobject(countCPUobj).Y-targetY)<200 THEN CPUobject(countCPUobj).ASSubMode = 1 END IF END IF ' The following lines calculate the angle of direction ' from the current computer controlled object toward the target. resultanglerad = ATAN2((-1)*(targetY-CPUobject(countCPUobj).Y),(targetX-CPUobject(countCPUobj).X)) resultanglerad = PI/2 - resultanglerad IF resultanglerad < 0 THEN resultanglerad = resultanglerad + 2*PI ' The following line converts the result angle between the ' two objects from radians to degrees. resultangledeg = (resultanglerad*180)/PI ' If the CPU controled object's angle is larger than the ' result angle (angle between the CPU object and the target object)... IF CPUobject(countCPUobj).AngleDeg > resultangledeg THEN ' If the difference between the current angle of the ' CPU controlled object and the result angle going ' counter-clockwise is less than this difference ' clockwise, rotate the CPU object counter-clockwise IF (360-CPUobject(countCPUobj).AngleDeg+resultangledeg) >= (CPUobject(countCPUobj).AngleDeg-resultangledeg) THEN CPUobject(countCPUobj).AngleDeg = CPUobject(countCPUobj).AngleDeg - CPUobject(countCPUobj).RotationSpeed*ASdirection ' If the difference between the current angle of the ' CPU controlled object and the result angle going ' clockwise is less that this difference counter-clockwise, ' rotate the CPU object clockwise IF (360-CPUobject(countCPUobj).AngleDeg+resultangledeg) < (CPUobject(countCPUobj).AngleDeg-resultangledeg) THEN CPUobject(countCPUobj).AngleDeg = CPUobject(countCPUobj).AngleDeg + CPUobject(countCPUobj).RotationSpeed*ASdirection END IF ' Same as above but for situation when CPU object's angle is ' less that the result angle. IF CPUobject(countCPUobj).AngleDeg < resultangledeg THEN IF (360-resultangledeg+CPUobject(countCPUobj).AngleDeg) >= (resultangledeg-CPUobject(countCPUobj).AngleDeg) THEN CPUobject(countCPUobj).AngleDeg = CPUobject(countCPUobj).AngleDeg + CPUobject(countCPUobj).RotationSpeed*ASdirection IF (360-resultangledeg+CPUobject(countCPUobj).AngleDeg) < (resultangledeg-CPUobject(countCPUobj).AngleDeg) THEN CPUobject(countCPUobj).AngleDeg = CPUobject(countCPUobj).AngleDeg - CPUobject(countCPUobj).RotationSpeed*ASdirection END IF ' The following lines keep the current CPU object's angle within ' 0 to 360 degrees area. IF CPUobject(countCPUobj).AngleDeg<0 THEN CPUobject(countCPUobj).AngleDeg=CPUobject(countCPUobj).AngleDeg+360 IF CPUobject(countCPUobj).AngleDeg>359 THEN CPUobject(countCPUobj).AngleDeg=CPUobject(countCPUobj).AngleDeg-360 ' Convert the CPU object's angle from degrees to radians. CPUobject(countCPUobj).AngleRad = (CPUobject(countCPUobj).AngleDeg*PI)/180 ' Move the current CPU object according to angle and speed ' (note how SIN and COS functions are used). ' Since positive y axis goes down in FB, we need to reduce ' the y position of the object by the COS function and not add ' it as in normal Cartesian coordinate system. CPUobject(countCPUobj).X = CPUobject(countCPUobj).X + sin(CPUobject(countCPUobj).AngleRad)*CPUobject(countCPUobj).Speed CPUobject(countCPUobj).Y = CPUobject(countCPUobj).Y - cos(CPUobject(countCPUobj).AngleRad)*CPUobject(countCPUobj).Speed IF CPUobject(countCPUobj).X < 3 OR CPUobject(countCPUobj).X > MapXMax - 3 THEN CPUobject(countCPUobj).X = CPUobject(countCPUobj).X - sin(CPUobject(countCPUobj).AngleRad)*CPUobject(countCPUobj).Speed IF CPUobject(countCPUobj).Y < 3 OR CPUobject(countCPUobj).Y > MapYMax - 3 THEN CPUobject(countCPUobj).Y = CPUobject(countCPUobj).Y + cos(CPUobject(countCPUobj).AngleRad)*CPUobject(countCPUobj).Speed END IF IF CPUobject(countCPUobj).Active = TRUE THEN ' If the current computer controlled object's weapon is ' reloaded and the player is less than 120 pixels vertically ' or horizontally away, shoot a projectile. IF CPUobject(countCPUobj).Reload = 0 AND ABS(CPUobject(countCPUobj).X-targetX)<120 AND ABS(CPUobject(countCPUobj).Y-targetY)<120 THEN CPUobject(countCPUobj).Reload = 35 InitiateProjectile CPUobject(countCPUobj).X+sin(CPUobject(countCPUobj).AngleRad)*20,CPUobject(countCPUobj).Y-cos(CPUobject(countCPUobj).AngleRad)*20, CPUobject(countCPUobj).AngleRad, 5 END IF ' Time out the weapon (reload it). IF CPUobject(countCPUobj).Reload > 0 THEN CPUobject(countCPUobj).Reload = CPUobject(countCPUobj).Reload - 1 ' Draw the computer controlled object. ' Direction line and a circle. 'LINE (CPUobject(countCPUobj).X-cameraX, CPUobject(countCPUobj).Y-cameraY)-(CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad)*20,CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad)*20), RGB(2,117, 250) 'CIRCLE (CPUobject(countCPUobj).X-cameraX, CPUobject(countCPUobj).Y-cameraY), 3, RGB(2,117, 250) ' Triangle drawn with polar method. LINE (CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad)*10,CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad)*10)-(CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad+PI*3/4)*10,CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad+PI*3/4)*10), RGB(2,117, 250) LINE (CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad+PI*3/4)*10,CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad+PI*3/4)*10)-(CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad+PI*5/4)*10,CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad+PI*5/4)*10), RGB(2,117, 250) LINE (CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad+PI*5/4)*10,CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad+PI*5/4)*10)-(CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad)*10,CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad)*10), RGB(2,117, 250) ' Triangle drawn with Cartesian method. 'LINE (CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad)*10+cos(CPUobject(countCPUobj).AngleRad)*0, CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad)*10+sin(CPUobject(countCPUobj).AngleRad)*0)-(CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad)*-10+cos(CPUobject(countCPUobj).AngleRad)*-10,CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad)*-10+sin(CPUobject(countCPUobj).AngleRad)*-10), RGB(2,117, 250) 'LINE (CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad)*-10+cos(CPUobject(countCPUobj).AngleRad)*-10, CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad)*-10+sin(CPUobject(countCPUobj).AngleRad)*-10)-(CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad)*-10+cos(CPUobject(countCPUobj).AngleRad)*10,CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad)*-10+sin(CPUobject(countCPUobj).AngleRad)*10), RGB(2,117, 250) 'LINE (CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad)*-10+cos(CPUobject(countCPUobj).AngleRad)*10, CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad)*-10+sin(CPUobject(countCPUobj).AngleRad)*10)-(CPUobject(countCPUobj).X-cameraX+sin(CPUobject(countCPUobj).AngleRad)*10+cos(CPUobject(countCPUobj).AngleRad)*0,CPUobject(countCPUobj).Y-cameraY-cos(CPUobject(countCPUobj).AngleRad)*10+sin(CPUobject(countCPUobj).AngleRad)*0), RGB(2,117, 250) END IF NEXT countCPUobj END SUB