Ok so half of it's sloppy, the other half is modular, and somewhere in between is stuff I could've put in a better spot (and probably will for some of it, like bullet movement)
but hey, it's got player controls, detects when the enemy bullets hit you, and is modular enough to where you could add your own types of bullets WITHOUT LOOKING AT THE REST OF THE CODE!!! In other words, it's an engine, and it works... (except player bullets, I gotta add that in about now...)
Here's the code, and a screenie for kicks (though everything in it is for debugging uses, I honestly can do artistic stuff, but not focused on that)
`this is a basic shooter, intended to be modular
`and use C++ style code
`my personal goal is to make this as dynamically editable as
`can be, using ini files and similar more than code.
`for loading enemies, players, even types of gameplay
`INITIALIZATION
sync on
sync rate 32
set image colorkey 255,255,255
`white is the new black... or nonexistant anyway
`Load images
load image "Player.bmp", 1
`VARIABLE DECLARATION
global gameState as integer
global stateGame as integer
global stateMenu as integer
global level as integer
global enemyFlyCount as integer
`Entity variables
global player as integer
`global playerx as integer
`global playery as integer COMMENTED OUT SEE BELOW
`playerHealth and XY will be fly(1)'s value... since fly(1) = player. (fly(player), in the AI control)
global playerSpeed as integer
`gonna add system time as a global for AI usage
global system_time as string
`calling entities flies now, heh, 'cause they're ships
`also the fly(500) index will be the entity, and the integer will
`be its health, for clean efficient code
`THE REASON UDT'S ARE NOT USED IS BECAUSE THEY CAN'T BE PASSED INTO A FUNCTION
`flyshotTimer has been added so that there is now a "did I shoot?" cooldown timer...
`otherwise it adds a very large amount of shots to one screen...
global dim fly(500) as integer
global dim flyx(500) as integer
global dim flyy(500) as integer
global dim flyactive(500) as integer
global dim flyimg(500) as integer
global dim flywidth(500) as integer
global dim flyheight(500) as integer
global dim flyAI(500) as integer
global dim flyShotTimer(500) as integer
`flyAI is really the flyAI type, which determines how the ship behaves
````BULLETS`````````````` NOTE: Either use bullet() or bulletActive() to determine
`whether or not it's an enemy bullet or player bullet. If player, collide with enemy
`and visa-versa. ! 1=enemy 2=player or something. BulletDMG is how much damage it does when it hits...
global dim bullet(500) as integer
global dim bulletx(500) as integer
global dim bullety(500) as integer
global dim bulletactive(500) as integer
global dim bulletimg(500) as integer
global dim bulletwidth(500) as integer
global dim bulletheight(500) as integer
global dim bulletAI(500) as integer
global dim bulletDmg(500) as integer
global bulletcount as integer
`bulletcounter is invaluable, it cycles through so that you don't
`overload the buffer.
`PLAYER AI TYPES TO BE ENUMERATED
global aiTypePlayer as integer
global aiTypeBasic as integer
`BULLET AI TYPES TO BE ENUMERATED
global bulletOfPlayer as integer
global bulletOfEnemy as integer
`Bullet AI specific types next...
global bulletAiTypeBasic as integer
`VARIABLE ASSIGNING
`initialize flies and bullets...
gosub initialize_flies
player = 1
playerSpeed = 9
`enumerate AI types
aiTypePlayer = 0
aiTypeBasic = 1
`enumerate bulletAI types
bulletAItypeBasic=0
``````EXTRA bulletAItypeBasic=1
`initialize bullettype
bulletOfEnemy = 1
bulletOfPlayer=2
`initilize bulletcounter, await increment before any new bullets are added
bulletcount=0
`Enumeration of state of game
stateGame = 1
stateMenu = 2
`The basic starting level lest a save file is used
level = 1
`PreMain Assigning
gosub initialize_flies
`CHANGE THIS DURING TESTING ALONE
gameState = stateMenu
`MAIN```````````````````````````````
do
system_time = get time$()
cls
`for debug...
print system_time
if gameState = stateMenu then menuFunction()
if gameState = stateGame then doMainGame()
SYNC
loop
`````````END MAIN```````````````
`FUNCTION DEFINITION
`addBullet adds one active bullet, player/enemy and what type.
`bx and by are x and y coordinates of the start. type determines height and width...
function AddBullet( playerorenemy, BulletAItype, bx, by)
`increment the count...
bulletcount = bulletcount + 1
`add bullet using bullet() as identifier
bullet(bulletcount) = playerorenemy
`make active the new bullet
bulletActive(bulletcount) = 1
`infuse the AI!!!
bulletAI(bulletcount) = BulletAItype
`coordinates of start of bullets
bulletx(bulletcount) = bx
bullety(bulletcount) = by
doAssignDmg(bulletcount)
`do this check early to prevent overflow error like in map editor clicking code...
if bulletcount > 491 then bulletcount = 0
endfunction
function checkbulletsBounding(bulletnumber)
`IF BULLET IS OUT OF 800 by 600 SCREEN, IT IS DEACTIVATED!
if bulletX(countBull) < -25 OR bulletX(countBull) > 600 OR bulletY(countBull) < -25 OR bulletY(countBull) > 830 then bulletActive(countBull) = 0
endfunction
`a function that loads the bullet with the correct Damage amount based on AI
function doAssignDmg(bulletnumber)
if bulletAI(bulletnumber) = bulletAiTypeBasic then bulletDmg(bulletnumber) = 50
endfunction
`THE MENU
function menuFunction()
print "Press spacebar to begin!"
if spacekey()
doLoadLevel(level)
gameState = stateGame
endif
endfunction
`THE GAME STATE
function doMainGame()
`check for bullets colliding...
for countBull = 0 to 500
if bulletActive(countBull)
`clear out all the bullets not in screen... or near enough anyway
checkBulletsBounding(countBull)
displayBullet(countBull)
if bullet(countBull) = bulletOfEnemy
`print "into the loop1" pass debug
doEnemyBulletAI(countBull)
if checkBulletPlayerCollide(countBull)
`debug print string..
print "testing for collision"
`do (initiate) an animation too, to be added...
fly(player) = fly(player) - BulletDmg(countBull)
bulletActive(countBull) = 0
endif
endif
if bullet(countBull) = bulletOfPlayer
doPlayerBulletAI(countBull)
checkBulletEnemyCollide(countBull)
endif
`Move the thing
`show it!
displayBullet(countBull)
endif
next countBull
`developer's note: it seems this function is independent of what level is
`currently loaded. This might be a problem, or it might be OK, will find out
`when I load a few levels after I get the switch-level code in here.
`update every fly()'s movement
AIfunction()
`render the understuff first...
doBackground()
`gotta render to the screen
displayFly()
`debug section
`display player's health, to see if collide
` print STR$(fly(player))
if checkForLoss()
cls
Print "You Lose! Press Any key to restart"
sync
wait 1500
wait key
gameState = stateMenu
gosub initialize_flies
endif
endfunction
`bullet movement, to be modular like player/fly AI
function doPlayerBulletAI(bullNumber)
`both player and enemy an use the same AI types, but they must be defined in each section... (I know, sloppy code...)
if bulletAI(bullNumber) = BulletAITypeBasic
bulletY(bullNumber) = bulletY(bullNumber) - 30
endif
endfunction
`enemy bullet AI movement
function doEnemyBulletAI(bullNumber)
if bulletAI(bullNumber) = BulletAITypeBasic
bulletY(bullNumber) = bulletY(bullNumber) + 2
endif
`any if should add if bulletAI(bullnumber) = new type, encapsulate what it does and add an endif statement to add new AI Type
endfunction
`test to see if the player lost
function checkforLoss()
temp=0
if fly(player) <= 0
temp=1
endif
endfunction temp
`test to see if the bullet hits the player
function checkBulletPlayerCollide(bulletNumber)
`debug string...
`print "intotheloop"
`passed, this does get tested... flaw was in parameters...
`return 0 if not colliding, anything else if is.
temp = 0
if bulletX(bulletNumber) <= flyx(player)+flywidth(player) AND bulletX(bulletNumber) >= flyX(player) AND bulletY(bulletNumber) <= flyy(player) + flyheight(player) AND bulletY(bulletnumber) >= flyy(player)
print "there is a collision, I detect"
temp = 1
endif
endfunction temp
`STILL HAVE TO ADD PLAYER BULLETS COLLIDING WITH THE ENEMIES!
`test to see if the bullet is hitting an enemy
function checkBulletEnemyCollide(bulletnumber)
endfunction
`The artificial Intelligence function is responsible for ALL entities, even the player
`the goal is to modularize all types of AI for every ship... so you can plug in a ship
`say it's a "fighter" and it'll automatically act like a fighter through a config variable
`this is why the player is no different it is "an entity set to act like the player"
function AIfunction()
for count = 1 to 500
if flyActive(count) > 0
doFlyMoveAI( count, flyAI(count) )
doFlyShooting( count)
`see if anything is below the bottom, make it deactivated
checkBelow()
endif
next count
endfunction
function displayBullet(bulletnum)
`for debug...
`print "there is an active bullet"
`displaying a circle for testing purposes...
if BulletActive(bulletnum) then circle BulletX(bulletnum), BulletY(bulletnum),20
endfunction
function doFlyShooting(flynumber)
temps$ = Right$(system_time, 1)
print temps$
if flyAI(flynumber) = AiTypeBasic
if flyshottimer(flynumber) = 0
if VAL( temps$ ) = 0
AddBullet( bulletOfEnemy, bulletAiTypeBasic, flyx(flynumber) + flywidth(flynumber)/2, flyy(flynumber) - flyheight(flynumber) )
`very basic, but allows a single shot per enemy at the 0 mark of every 10 sec
flyShotTimer(flynumber)=1
endif
endif
endif
endfunction
`Within the AI, this function obtains the player's movement controls
function playerMovement()
if keystate( 17 ) then flyy(player) = flyy(player) - PlayerSpeed
if keystate( 30 ) then flyx(player) = flyx(player) - playerSpeed
if keystate( 31 ) then flyy(player) = flyy(player) + PlayerSpeed
if keystate( 32 ) then flyx(player) = flyx(player) + playerSpeed
keepPlayerInside()
endfunction
function keepPlayerInside()
if flyx(player) > 744 then flyx(player) = 744
if flyx(player) < 0 then flyx(player) = 0
if flyy(player) > 544 then flyy(player) = 544
if flyy(player) < 0 then flyy(player) = 0
endfunction
`RENDER THE FLIES to the screen!
function displayFly()
for c = 1 to 500
` if flyactive(c) > 0 then
paste image flyimg(c), flyx(c), flyy(c)
next c
endfunction
`HANDLE THE MOVEMENT OF EVERY FLY, AI STYLE
function doFlyMoveAI(flynum, aiStyle)
`flynum is the index of the fly, aiStyle determines how it should move
`admittedly playerMovement isn't following along in the same style as the other
`entities, because at some point I'll need to grab the input, so I left it as is
if aiStyle = aiTypePlayer then playerMovement()
`aiTypeBasic just moves the entity forward, and will shoot if I add shooting
`to this, or another AI command, like BulletAI, unsure how as of yet
if aiStyle = aiTypeBasic
flyy(flynum) = flyy(flynum) + 6
endif
`Lastly, make sure all AI ships are on-screen X-coordinate wise
doAIBoundingCheck(flynum)
endfunction
`this function displays the background, it is separate so you can load
`any sort ot thing, from an image to a map, for any occastion
`I suggest using a switch, and doing stuff like if BOSS then use BG_BOSS_1 or something
`there will need to be information based on level, and if you're at the boss or not
function doBackground()
endfunction
function doLoadLevel(lvl)
lname as string
lname = "level" + STR$(lvl) + ".txt"
`for good measure, gonna deactivate all entities except player
DeActivateFlies()
enemyFlyCount = 1
open to read 1, lname
`my parser is extremely basic, will use tokens in the near future hopefully
`though it does allow comments so long as the start of a string isn't a keyword!
while file end(1)=0
read string 1, instring$
if left$(instring$, 5) = "group" then doParseGroup()
`endif
endwhile
close file 1
endfunction
`this function will deactivate anything that's well below the assumed 800
`by 600 area. This saves time for collision and other functions, even display
function checkBelow()
for count = 2 to 500
if flyy(count) > 1050 then flyactive(count) = 0
next count
endfunction
function doParseGroup()
`t = temp... for naming conventions
`image type (1 = player's for tests)
read string 1, instring$
timg = VAL(instring$)
`number of ships
read string 1, instring$
tflyarray = VAL(instring$)
`starting X values
read string 1, instring$
txStart = VAL(instring$)
`starting Y values
read string 1, instring$
tyStart = VAL(instring$)
`spacing between them in pixels (speed is handled by AI type)
read string 1, instring$
tspacing = VAL(instring$)
`style of AI
read string 1, instring$
tAItype = VAL(instring$)
`gotta make sure to activate and update everyone EXCEPT player
for temp = 1 to tFlyArray
enemyFlyCount = enemyFlyCount + 1
flyActive(enemyFlyCount) = 1
flyx(enemyFlyCount) = txStart
flyy(enemyFlyCount) = tyStart + tspacing * temp * (-1)
`negative to encourage ships to come after, not before indicated spot
flyAI(enemyFlyCount) = tAItype
next temp
endfunction
`keep those bugs on the screen! AI itself might shove them off otherwise
function doAIBoundingCheck(flynumbr)
`it is now apparent I will need to add flywidth and height sooner than I
`expected in order to have clean code most of the way through... this for now
`assumes 64 by 64 pixel images, which I can't always do
if flyx(flynumbr) < 0 then flyx(flynumbr) = 0
if flyx(flynumbr) > 744 then flyx(flynumbr) = 744
endfunction
`the INITIALIZATION SUBROUTINE...
initialize_flies:
for c = 1 to 500
`starting health = 200 for now
fly(c) = 200
flyx(c) = -860
`initializing all object above the window in center
`assuming 800 by 600
flyy(c) = -900
`initializing all objects as inactive, might change later
`also might not even be used
flyactive(c) = 0
`just noticed, if you paste images that are above the screen, then they
`just paste to the upper left hand corner, so I need this variable to tell
`if they're active or not for the displayFly() function
`flyimg is which image the Fly's should use, 1 is player by default
flyimg(c)=1
`cooldown
flyshottimer(c) = 0
`BULLET SECTION for initializing all as nonactivated and with default values
bullet(c) = 0
bulletx(c) = 390
bullety(c) = 0
bulletactive(c) = 0
` bulletimg(c) = 1 Note: might add code for 1, 2, 3, 4, 5 and translate it to
`the image numbers like 50,51,52, or whatever area I decide the bullet images will go inside...
bulletwidth(c) = 25
bulletheight(c) = 25
`bulletAI(c) = 0
bulletDmg(c) = 10
next c
flyx(player) = screen width()/2
flyy(player) = screen height() - image height(1)
flyactive(player) = 1
flywidth(player) = image width(1)
flyheight(player) = image height(1)
return
`end initialize subroutine, the only subroutine...
function DeActivateFlies()
for count = 2 to 500
flyactive(count) = 0
next count
endfunction
Right now, the background is lacking, and my only "End Of Level" detect is your death, but I will add your win, endOfLevel now Goto Boss, and backgrounds later. (might rewrite the engine to handle multiple level's b/g's and boss b/g's) as well.
My purpose in releasing this to the community is that WE DO NOT HAVE FULL GAMES, at least not as complete as my still-not-half-done engine here, and if they are, it's some odd outdated game for 3/4.0 in the snippets.
When I finally finish the engine, and will demo it in program announcements with better gfx, everyone here will have FULL SOURCE for an ENTIRE GAME! and to top it off, I won't charge anything. I don't like commercializing to be honest, even though this started from my commercial project, lol.
Anyway, yes, I need to add sound, and a menu system (which I did add, but I edited the wrong source file today, so... here it is in debug mode but working otherwise).
TO RUN! CREATE A FILE NAMED "level1.ini" and place it in the exe's folder, along with a Player.bmp image that's 64 by 64 pixels (you can edit the source however you like). It's made for 800 by 600 res in windowed mode, but full works.
Also, level1.ini should have something in it, here's mine for tests
keyword(s): group
that keyword has its next lines as image, ship count, x, y, spacing, and AIType in that order
....player AI is 0 and basic is 1, to start
group
1
5
50
-100
88
1
group
1
8
340
-99
125
1
note: I plan on learning tokens soon enough... but right now focused on finishing this.
So, there's the DBP full src, ready to demo itself. I have homework due in 9 hours otherwise I'd get those player bullets in right now, but sleep is calling me...
Will update in the near future with more features as time progresses. Have fun!
Signed
------