Snow_ [Lexaloffle Blog Feed]https://www.lexaloffle.com/bbs/?uid=31769 Ultra Simple Platformer Code Under 100 Lines with Mario Style Jumping <p> <table><tr><td> <a href="/bbs/?pid=88071#p"> <img src="/bbs/thumbs/pico8_ultra_simple_platformer-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=88071#p"> ultra_simple_platformer</a><br><br> by <a href="/bbs/?uid=31769"> Snow_</a> <br><br><br> <a href="/bbs/?pid=88071#p"> [Click to Play]</a> </td></tr></table> </p> <p>Demo:</p> <img style="margin-bottom:16px" border=0 src="/media/31769/simpleplatformer.p8_0.gif" alt="" /> <p>Same base engine used in <a href="https://www.lexaloffle.com/bbs/?tid=41585">Bullet Ball</a>:</p> <img style="margin-bottom:16px" border=0 src="/media/31769/20_Bullet Ball Gameplay.gif" alt="" /> <p>This platformer base code is what my game <a href="https://www.lexaloffle.com/bbs/?tid=41585">Bullet Ball</a> is built on. It is inspired by Super Mario Bros for the NES. This demo contains code for Super Mario style variable jumping, AABB collision (1 way platforms or full collision), and a very simple animation function.</p> <p>Like many newbies, I struggled with platforming when I was learning to program and always found that my code was bloated with many unnecessary variables. I still see many newbies struggling with this. I'm also seeing many demos with verbose code and needless multiple variables.</p> <p>Programming is difficult and optimizing even more so, but as a rule of thumb, you always want to have efficient, optimized code that's clear to read and understand. By efficiency, you want to use as little computer power as you can. Even though with today's ultra blazing fast processors, it seems not necessary, it's a good practice, because it also helps you simplify. It takes years to get there, but you learn.</p> <p>The magical element in my code is the use of lookup tables for the use of movement and position for collision detection. Super Mario Bros used lookup tables as using mathematical equations (especially multiplication and division) would bog down the program on the NES. The NES ran at 1.79MHz with very limited ram. NES programmers had to optimize hardcore to get their games to run the way they wanted them too. SMB is a true marvel. In my own movement code, I only increment, decrement and use modulus (same as division, but the result is the remainder) for friction.</p> <p>So, a quick look at the lookup tables and an explanation for them. Following that in the hidden tag is commented code. It is aimed at newbies with little experience coding. The code in the demo above is condensed down to 87 lines (sans the 2 dividing dashed lines) and can be condensed a bit more if you take out the block for 1-way platforms. </p> <p>This is the speed look up table. This is used for both horizontal running and vertical jump movement. </p> <div> <div class=scrollable_with_touch style="width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>speed={-4,-2,-1,-1,0,1,1,2,4}</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>By using a counter variable that can increment or decrement, I can then add the result to my x or y position and voila.</p> <p>For example, if you wanted the player to just run right at top speed:</p> <div> <div class=scrollable_with_touch style="width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>hv=9 --hv is horizontal velocity x+=speed[hv]</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>So by simply changing the hv variable, I can make the player not only move left or right, but also immitate acceleration and drag. Notice how the sets of numbers count up on both sides of 0. Look at the movement function in the code below to see how this all works.</p> <p>For gravity, using the speed table is super handy. If vv (vertical velocity) is less than 5, my player will move up (jumping), but go past 5 and the player starts to fall. So in my movement code, I have:</p> <div> <div class=scrollable_with_touch style="width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>if(vv&lt;9) vv+=1</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>This line runs no matter what. When holding down my jump button, vv is set to 1 and will be reset at 1 every tick until either my jump boost (see code below) runs out or I let go before it runs out, so that the player will move up. When I let go or my jump boost has hit max, then the line above is free to count up vv. This causes an arc movement and then the player falls down and will continue to move down unless stopped by a platform. Gravity.</p> <p>My 2nd look up table is simply a table of multiples of 8:</p> <div> <div class=scrollable_with_touch style="width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>for i=-1,16 do tile[i]=i*8 end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>This table helps in detecting local collision around the player. Refer to the code below to see how it works.</p> <p>Feel free to use the code as a base for your projects. Be careful if you tinker with the values within the speed table. Collision can be easily thrown off and you might end up inside or going through blocks. I'm not easily available, but I'll answer any questions best I can, when I can. I'm also of the &quot;there are no stupid questions&quot; policy. Ask anything.</p> <p>You can also look at the code in <a href="https://www.lexaloffle.com/bbs/?tid=41585">Bullet Ball</a> to see more platformer functions and to see how my code works with the entire map space. At the moment BB's code is uncommented, but I am putting together a post-mortem post that will contain commented code.</p> <p>FULL COMMENTED CODE:<br /> <div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"></p> <div> <div class=scrollable_with_touch style="width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>--&gt;8 --player variables x=60 y=88 xdir=false --movement variables hv=5 --horizontal velocity vv=5 --vertical velocity friction=0 surface=2 --works as a counter with friction.. the higher the number, lower the friction boost=0 --variable jump height counter speed={-4,-2,-1,-1,0,1,1,2,4} --this is the speed look up table. it can be used for left/right and vertical movement. --map variables tile={} for i=-1,16 do tile[i]=i*8 --look up table with multiples of 8 (8*-1 to 8*16). this is used in the collision function for horizontal and vertical coordinates. end --animation variables anim=false set=2 --the first sprite of the current set of frames to animate. start=0 --this works as a counter with duration. duration=3 --length of current set of frames frame=1 --starting frame --test timer variables timer=0 timerlimit=20 --&gt;8 function _update() --timer=(timer+1)%timerlimit --if timer==0 then input() move() animate() --end end function input() if btn(0) then --if pressing &quot;left&quot;, face left, count down horizontal velocity xdir=true if(hv&gt;1) hv-=1 elseif btn(1) then --&quot;right&quot;, face right, count up horizontal velocity xdir=false if(hv&lt;9) hv+=1 else friction=(friction+1)%surface --when friction%surface is 0, then if moving horizontally, count up or down until hv is 5 if friction == 0 then if(hv&lt;5) hv+=1 if(hv&gt;5) hv-=1 end end if btn(5) then if boost &lt; 6 then --variable height jump boost+=1 vv=1 --so long as boost is less than 6, keep vertical velocity at 1. speed[1]=-4, so the player will continue moving up 4 pixels end else boost=6 --if let go in mid air, set to 6 to prevent double jumping. resets to 0 when on ground end end function move() --here is where the speed look up table is used for both horizontal and vertical speeds x+=speed[hv] y+=speed[vv] if(vv&lt;9) vv+=1 --unless vv is set by another function, it will otherwise count up till 9. here is where the jump arc happens and then constant gravity. collision() end function collision() anim=false --at the beginning, anim is false - this way, unless player is touching ground, player will display jump sprite. surface=4 --setting at 4 at the beginning allows for more natural movement in air. on ground is set to 2. if(x&gt;=120) x=120 --set right side screen boundary if(x&lt;=0) x=0 --set left side screen boundary local n1=flr(x/8) --n1 and n2 get the coordinates of the tile that the top left pixel of the player is currently inhabiting. local n2=flr(y/8) for i=n1-1,n1+1 do --now we check all the tiles around the player. in this code, this is extended 2 tiles below the player. for j=n2-1,n2+2 do if fget(mget(i,j),0) then --uncomment this block if you want one way platform collision------ --[[if x &lt; p[i]+7 and x+7 &gt; p[i] and y &lt;= p[j-1] and y+8 &gt;= p[j-1] and vv&gt;5 then -- if y &lt; p[j] and y+8 &gt;= p[j] then -- if (not btn(5)) boost = 0 -- y=p[j-1] -- vv=5 -- end end]] ------------------------------------------------------------------- --this block of code allows for full aabb collision---------------- --top of tile if x &lt; tile[i]+7 and x+7 &gt; tile[i] and y &lt; tile[j] and y+9 &gt;= tile[j] and vv&gt;5 then --note that the 'tile' look up table is used here. if (not btn(5)) boost = 0 y=tile[j-1] --set player position on ground vv=5 --stop vertical movement anim=true --now on ground, anim is true surface=2 --add more friction to movement now that on ground end --bottom of tile if x &lt; tile[i]+7 and x+7 &gt; tile[i] and y-1 &lt;= tile[j]+7 and y+7 &gt; tile[j]+7 then if(vv&lt;9) vv+=1 --incrementing vv here doubles time for movement to go from up to down. boost=6 --set to 6 to cancel jump y=tile[j+1] end --right side of tile if x-1 &lt;= tile[i]+7 and x+7 &gt; tile[i]+7 and y &lt; tile[j]+7 and y+7 &gt; tile[j] then hv=5 x=tile[i+1] end --left side of tile if x &lt; tile[i] and x+8 &gt;= tile[i] and y &lt; tile[j]+7 and y+7 &gt; tile[j] then hv=5 x=tile[i-1] end -------------------------------------------------------------------- end end end end --&gt;8 function animate() if anim then if(hv~=5) then start=(start+1)%duration --when anim is set to true and hv is not 5, then run the 'running' animation frame=start+set end if(hv==5) frame=0 --if hv is 5, then set frame to 'stand' frame else frame=4 --otherwise set to jump frame end end function _draw() cls() map(0,0,0,0,16,16) spr(1+frame,x,y,1,1,xdir) end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p></div></div></div></p> https://www.lexaloffle.com/bbs/?tid=41729 https://www.lexaloffle.com/bbs/?tid=41729 Mon, 08 Mar 2021 21:01:28 UTC Bullet Ball <p><center> <table><tr><td> <a href="/bbs/?pid=87690#p"> <img src="/bbs/thumbs/pico8_bullet_ball-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=87690#p"> Bullet Ball 1.02</a><br><br> by <a href="/bbs/?uid=31769"> Snow_</a> <br><br><br> <a href="/bbs/?pid=87690#p"> [Click to Play]</a> </td></tr></table> </center></p> <p><center><img style="margin-bottom:16px" border=0 src="/media/31769/bullet ball gameplay.gif" alt="" />&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/24_20_Bullet Ball Gameplay.gif" alt="" /></center></p> <p>Once upon a time, cute and fluffy street thugs decided to settle a score they had with a friendly round of street ball. Their skirmishes grew intense and it wasn&rsquo;t long before weapons got involved. Their game of street ball evolved into Bullet Ball. Since then, they&rsquo;ve forgotten why they were even fighting and continue their battle today.</p> <p>The object of the game is to get the ball into the opposing team&rsquo;s hoop. You will have an arsenal of 8 weapons and power ups to aid you or your team to victory. </p> <p>You can run, jump, aim (in 8 directions), shoot and toss weapons or toss ball.</p> <h3>Default controls:</h3> <h3>Player 1:</h3> <p><strong>UP</strong>......(aim)<br /> <strong>DOWN</strong>....(aim)<br /> <strong>LEFT</strong>....(aim/move)<br /> <strong>RIGHT</strong>...(aim/move)<br /> <strong>Z/N/C</strong>...(fire/toss)<br /> <strong>X/M/V</strong>...(jump)</p> <h3>Player 2:</h3> <p><strong>E</strong>.......(aim)<br /> <strong>D</strong>.......(aim)<br /> <strong>S</strong>.......(aim/move)<br /> <strong>F</strong>.......(aim/move)<br /> <strong>TAB/L SHIFT</strong>......(fire/toss)<br /> <strong>Q/A</strong>.....(jump)</p> <p>Player 3 to Player 4: Configure your controllers how you wish.</p> <p><strong>WARNING: 4 PLAYER HAS NOT BEEN TESTED WITH CONTROLLERS YET!</strong></p> <p><strong>Ctrl+R</strong> will instantly reset the game.<br /> <strong>WARNING:</strong> if you reset your game and you made a custom map with the map editor, it will default back to the skeleton map. You will have to rebuild it. If you want to leave your current round, but keep your custom map, press <strong>ENTER</strong> and select <strong>&quot;exit round&quot;</strong>. This will reset the game, but map selection will still have your map as the first one.</p> <h3>Starting a Game</h3> <p>Select 2 or 4 player. Set score limit if you wish. Default is 10 points to win. The game will begin with the characters in their default spawn positions on the second map, unless a custom map was made and saved. Then the game will start on the first map. The first map is blank and reserved for the map editor. The game has 11 default maps as shown:</p> <p><center><img style="margin-bottom:16px" border=0 src="/media/31769/bullet ball maps.png" alt="" /></center></p> <p><center><img style="margin-bottom:16px" border=0 src="/media/31769/59_level 3.png" alt="" />&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/60_level 1.png" alt="" /></center></p> <p>Scroll <strong>LEFT</strong> or <strong>RIGHT</strong> to pick a level and press <strong>X</strong>. You can now select your character by pressing <strong>UP</strong> or <strong>DOWN</strong> and pressing <strong>X</strong>. Once both (or all 4 if in 4 player) players have chosen their character, the game will start. You can choose one of the following 4 badass characters: Fluffy the bunny, Muffin the mouse, Stubbs the dog, and Patchy the cat.</p> <p><center><img style="margin-bottom:16px" border=0 src="/media/31769/53_Fluffy.png" alt="" />&emsp;&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/54_Muffin.png" alt="" />&emsp;&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/55_Stubbs.png" alt="" />&emsp;&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/56_Patchy.png" alt="" /></center></p> <h3>Gameplay</h3> <p>Get the ball in the opposing team&rsquo;s hoop. The first to score 10 points wins the round.</p> <p>You can only hold one item: the ball or a weapon. Once a weapon is discarded, either by touching the ball, using up ammo, or tossing it (knife and star), another weapon will immediately spawn in a random position on the map.</p> <h3>Powerups</h3> <p>Powerups will also randomly spawn on the map after some time. Regular powerups restore 1 heart of health. Each character has a <strong>special powerup</strong> that will grant them full health and invincibility for 5 seconds. If the player touches a powerup that does not match the character, the powerup will act like a regular powerup and only restore 1 health.</p> <p><center><img style="margin-bottom:16px" border=0 src="/media/31769/45_Fluffy.png" alt="" />&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/49_carrot.png" alt="" />&emsp;&emsp;&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/46_Muffin.png" alt="" />&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/50_cheese.png" alt="" />&emsp;&emsp;&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/47_Stubbs.png" alt="" />&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/drumstick.png" alt="" />&emsp;&emsp;&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/48_Patchy.png" alt="" />&emsp;<img style="margin-bottom:16px" border=0 src="/media/31769/52_fish.png" alt="" /></center></p> <p>You have 3 hearts of health. If you lose all 3, you die and respawn. When you respawn, you are invincible for 1 second.</p> <h3>Special Strategies</h3> <p><center><img style="margin-bottom:16px" border=0 src="/media/31769/Bullet Ball Strategies.png" alt="" /></center></p> <h3>Using The Map Editor</h3> <p><center><img style="margin-bottom:16px" border=0 src="/media/31769/bullet ball map editor short big.gif" alt="" /></center><br /> Press <strong>Z</strong> to bring up your editor panel and press <strong>Z</strong> again to hide it.<br /> Press <strong>X</strong> to make your selections.</p> <p>Use <strong>arrow keys</strong> and <strong>X</strong> to design your map. You can erase a tile, simply by moving the cursor onto it and pressing <strong>X</strong>.</p> <p>You can mix and match your tiles. You have a lot of freedom in the editor so be creative and have fun. Just remember, that if you want to share maps (via image post here), make sure they are symmetrical, so that both sides have equal chance.</p> <p><strong>NOTE:</strong> Leave at least <strong>2 open vertical spaces</strong> at the <strong>first column of tiles (left of screen)</strong> and <strong>last (right of screen)</strong>. The game code picks these spaces as spawn areas. If you make a column of blocks from the floor up to the block that holds the hoop, with no spaces, the players will end up spawning inside the blocks. This may cause a crash or other unintended effects.</p> <p><strong>FILL</strong> will set all the visible tiles to whatever tile you have selected.<br /> <strong>SAVE</strong> will activate the map and add it to the beginning of the map list.<br /> <strong>EXIT</strong> will go back to the main menu. If you saved your map and start a new game, your custom map will be the first choice.</p> https://www.lexaloffle.com/bbs/?tid=41585 https://www.lexaloffle.com/bbs/?tid=41585 Mon, 15 Feb 2021 22:23:32 UTC