Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : CMM2 tile-based game code example
Author | Message | ||||
capsikin Guru Joined: 30/06/2020 Location: AustraliaPosts: 341 |
I've made some example code for a simple tile-based game. It has lots of comments and is intended to be easily readable, and extendable into a good game along the lines of Pengo or Mr Wiz (a Mr Do clone with more restrictive tile-based movement), or maybe something like Mr Do or Dig Dug, with some adjustments to the movement routines. It could use more support for animation and making different sounds than it has so far though. Animations could each have an array of sprite numbers. Sounds could each have arrays of frequencies and volumes. Also there should be a way of having multiple active objects of the same type, probably involving "SPRITE COPY". For example in Pengo there can be 4 (I think) Sno-Bees active at the same time. You can use, modify and and copy this with no licence restrictions from me, so people can use it in their own games. Zip file with game code and 2 sprites: tunnelchase-1.zip Game code follows '''''''''''''''''''''''''''''' option explicit '''''''''''''''''''''''''''''''' ' Video mode and frame counter ' '''''''''''''''''''''''''''''''' ' Increase frames at every screen blanking interval, so the main program knows when to redraw ' the sprites. Main program then resets frames counter to zero. dim frames frames=0 sub countframes frames=frames+1 end sub mode 2,12,0,countframes '''''''''''' ' Tile map ' '''''''''''' dim xtiles dim ytiles xtiles=15 ytiles=15 dim tiles(xtiles,ytiles) '''''''''''''' ' Tile types ' '''''''''''''' dim tile.empty, tile.earth, tile.player, tile.jewel, tile.monster, tile.wall, tile.playersmile dim tile.max tile.empty=1 tile.earth=2 tile.player=3 tile.jewel=4 tile.monster=5 tile.wall=6 tile.playersmile=7 tile.max=7 '''''''''''''''''''''''''''''''''''''' ' Set a colour for each tile, in ' ' case we don't have a custom sprite ' '''''''''''''''''''''''''''''''''''''' dim tile.colour(tile.max) tile.colour(tile.empty)=RGB(black) tile.colour(tile.earth)=RGB(blue) tile.colour(tile.player)=RGB(255,255,0) ' magenta tile.colour(tile.jewel)=RGB(128,0,192) ' violet tile.colour(tile.monster)=RGB(yellow) tile.colour(tile.wall)=RGB(0,192,192) ' cyan, partial brightness. '''''''''''''''''''''''''''''' ' Initialise sprite graphics ' '''''''''''''''''''''''''''''' dim spritesize dim tile.sprite(tile.max) spritesize=16 ' Load custom sprites tile.sprite(tile.player)=1 sprite load "fuzz1.spr",tile.sprite(tile.player) tile.sprite(tile.playersmile)=2 sprite load "fuzz2.spr",tile.sprite(tile.playersmile) ' Set generic coloured sprites for other objects dim n,spritenumber for n=1 to tile.max if tile.sprite(n)=0 then spritenumber=10+n tile.sprite(n)=spritenumber rbox 0,0,spritesize,spritesize,4,tile.colour(n),tile.colour(n) sprite read spritenumber,0,0,spritesize,spritesize end if next n cls ''''''''''''''''' ' Tile routines ' ''''''''''''''''' sub tile.setanddraw t,tx,ty tiles(tx,ty)=t sprite write tile.sprite(t),tx*spritesize,ty*spritesize end sub sub tile.draw t,tx,ty sprite write tile.sprite(t),tx*spritesize,ty*spritesize end sub sub tile.undraw t,tx,ty box tx*spritesize,ty*spritesize,spritesize,spritesize,,rgb(black),rgb(black) end sub '''''''''''''''''''''''''' ' Mobs - movable objects ' '''''''''''''''''''''''''' dim mob.player,mob.jewel,mob.monster dim mob.max mob.player=1 mob.jewel=2 mob.monster=3 mob.max=3 ' Pixel-precision locations of mobs for drawing sprites dim mob.px(mob.max) dim mob.py(mob.max) ' Pixel-precision velocities for smooth movement. In pixels per update. dim mob.vpx(mob.max) dim mob.vpy(mob.max) ' Number of steps the mob has left to move dim mob.movesteps(mob.max) ' Number of steps per move for future moves dim mob.stepspermove(mob.max) mob.stepspermove(mob.player)=8 ' Jewel takes less time to move mob.stepspermove(mob.jewel)=4 ' Monster takes more time to move mob.stepspermove(mob.monster)=16 ' Tile-precision locations of mobs for game logic dim mob.tx(mob.max) dim mob.ty(mob.max) ' Whether the mob is stored on the "tiles" map and clears spaces it moves on dim mob.onmap(mob.max) ' Which tile is stored on the map for the mob (if it is stored) dim mob.tile(mob.max) ' Mobs are drawn on page 1, background tiles are drawn on page 0 dim mob.sprite(mob.max) sub mob.initanddraw m,t,tx,ty,onmap mob.tx(m)=tx mob.ty(m)=ty mob.px(m)=tx*spritesize mob.py(m)=ty*spritesize mob.tile(m)=t mob.sprite(m)=tile.sprite(t) mob.movesteps(m)=0 mob.onmap(m)=onmap page write 1 sprite show mob.sprite(m),mob.px(m),mob.py(m),0 if onmap then ' Erase any background tile underneath page write 0 tile.undraw tile.empty,tx,ty end if tiles(tx,ty)=t end sub sub mob.startmove m,dtx,dty,steps ' Set px and py so it doesn't start from part way through a previous move mob.px(m)=mob.tx(m)*spritesize mob.py(m)=mob.ty(m)*spritesize local newtx,newty newtx=mob.tx(m)+dtx newty=mob.ty(m)+dty mob.vpx(m)=dtx*spritesize\steps mob.vpy(m)=dty*spritesize\steps mob.movesteps(m)=steps mob.checkcollisions m,newtx,newty if mob.onmap(m) then tiles(mob.tx(m),mob.ty(m))=tile.empty tiles(newtx,newty)=mob.tile(m) end if mob.tx(m)=newtx mob.ty(m)=newty end sub sub mob.move m mob.px(m)=mob.px(m)+mob.vpx(m) mob.py(m)=mob.py(m)+mob.vpy(m) mob.movesteps(m)=mob.movesteps(m)-1 if mob.onmap(m) then ' At the end of moving, erase any background tile underneath page write 0 if mob.movesteps(m)=0 then tile.undraw tile.empty, mob.tx(m),mob.ty(m) end if end if page write 1 sprite next mob.sprite(m),mob.px(m),mob.py(m) end sub sub mob.changesprite m,spr if mob.sprite(m) <> spr then sprite swap mob.sprite(m),spr mob.sprite(m)=spr end if end sub ' Check for collisions as mob m moves to location tx,ty sub mob.checkcollisions m,tx,ty local t ' Add any collisions we care about to the checks below ' First check for collisions on "tiles" map t=tiles(tx,ty) if m=mob.monster then if t=tile.player then collide.monster.player end if end if ' Next check for collisions with things that aren't stored on the map if m=mob.player then if mob.at(mob.jewel,tx,ty) then collide.player.jewel end if end if end sub ''''''''''''''''''''''''''''''' ' Game logic helper functions ' ''''''''''''''''''''''''''''''' sub mob.trymove m,dx,dy local t, moveok t=tiles(mob.tx(m)+dx,mob.ty(m)+dy) moveok=(t <> tile.wall) if moveok then mob.startmove m,dx,dy,mob.stepspermove(m) end if end sub sub mob.trymovelazy m,dx,dy local t, moveok t=tiles(mob.tx(m)+dx,mob.ty(m)+dy) if t=tile.wall then moveok=0 else if t=tile.earth then if rnd(1) < 0.01 then moveok=1 else moveok=0 end if else moveok=1 end if if moveok then mob.startmove m,dx,dy,mob.stepspermove(m) end if end sub ' Check if a specific mob is at specific tile coordinates function mob.at(m,tx,ty) mob.at = (tx = mob.tx(m)) and (ty=mob.ty(m)) end function ''''''''''''''''''''''''''' ' Game logic for each mob ' ''''''''''''''''''''''''''' ' Flags for when the player catches the jewel or is caught by the ' monster could be used in future. dim monstercaughtplayer,playercaughtjewel monstercaughtplayer=0 playercaughtjewel=0 dim asc.left, asc.right, asc.up, asc.down asc.left=130 asc.right=131 asc.up=128 asc.down=129 sub player.decide local m = mob.player if keydown(1)=asc.up then mob.trymove m,0,-1 else if keydown(1)=asc.down then mob.trymove m,0,1 else if keydown(1)=asc.left then mob.trymove m,-1,0 else if keydown(1)=asc.right then mob.trymove m,1,0 end if end sub sub jewel.decide local m = mob.jewel local r = rnd(1) if r < 0.2 then mob.trymovelazy m,0,-1 else if r < 0.4 then mob.trymovelazy m,0,1 else if r < 0.6 then mob.trymovelazy m,-1,0 else if r < 0.8 then mob.trymovelazy m,1,0 end if end sub sub monster.decide local m = mob.monster local r = rnd(1) if r < 0.5 then if mob.tx(mob.player) < mob.tx(mob.monster) then mob.trymovelazy m,-1,0 else mob.trymovelazy m,1,0 end if else if mob.ty(mob.player) < mob.ty(mob.monster) then mob.trymovelazy m,0,-1 else mob.trymovelazy m,0,1 end if end if end sub sub mob.decide m if m=mob.player then player.decide else if m=mob.player then player.decide else if m=mob.jewel then jewel.decide else if m=mob.monster then monster.decide end if end sub '''''''''''''''''''''''' ' Collision game logic ' '''''''''''''''''''''''' sub collide.player.jewel playercaughtjewel=1 sounds.startgoodsound mob.changesprite mob.player, tile.sprite(tile.playersmile) end sub sub collide.monster.player monstercaughtplayer=1 sounds.startbadsound end sub '''''''''''''''''''''' ' Main sound effects ' '''''''''''''''''''''' dim goodsound,badsound,walksound goodsound=0 badsound=0 sub sounds.startgoodsound goodsound=25 end sub sub sounds.startbadsound badsound=5 end sub sub sounds.startwalksound walksound=1 end sub sub sounds.next ' Play sound if player caught jewel if goodsound then ' Volume reduces as goodsound reduces play sound 2,B,Q,2000,goodsound goodsound=goodsound-1 else 'Silence sound 2 play sound 2,B,O,100 end if ' Play sound if monster caught player if badsound then ' Frequency reduces as goodsound reduces play sound 3,B,Q,300*badsound badsound=badsound-1 else ' Silence sound 3 play sound 3,B,O,100 end if ' Player walking sound if walksound then play sound 1,B,Q,1500,10 walksound=0 else ' Silence sound 1 play sound 1,B,O,100 end if end sub '''''''''''''''''' ' Initialise map ' '''''''''''''''''' dim x,y ' Fill map with earth tiles for x=1 to xtiles for y=1 to ytiles tile.setanddraw tile.earth,x,y next y next x ' Put walls at top and bottom for x=1 to xtiles tile.setanddraw tile.wall,x,1 tile.setanddraw tile.wall,x,ytiles next x ' Put walls at left and right edges for y=1 to ytiles tile.setanddraw tile.wall,1,y tile.setanddraw tile.wall,xtiles,y next y ''''''''''''''''''' ' Initialise mobs ' ''''''''''''''''''' mob.initanddraw mob.player,tile.player,3,3,1 mob.initanddraw mob.monster,tile.monster,10,10,1 ' Jewel has "onmap" set to 0, to it doesn't clear a trail as it moves mob.initanddraw mob.jewel,tile.jewel,13,13,0 '''''''''''''''''' ' Main game loop ' '''''''''''''''''' ' mob index dim mi do ' Run the "decide" sub for all mobs that aren't partway through a move. for mi=1 to mob.max if not mob.movesteps(mi) then mob.decide mi end if next mi ' Prepare to play sound at the start of player move if mob.movesteps(mob.player)=mob.stepspermove(mob.player) then sounds.startwalksound ' Play any sounds that have been prepared sounds.next ' Process any moving mobs for mi=1 to mob.max if mob.movesteps(mi) then mob.move mi end if next mi ' Wait before next game loop do loop until frames>=2 frames=0 ' Draw any moved sprites page write 1 sprite move loop until 0 edited to add: weird, the first two spaces of indentation only seem to show as one in the forum post. It should be correct in the attachment. Edited 2020-09-22 12:00 by capsikin |
||||
Print this page |