hypothete [Lexaloffle Blog Feed]https://www.lexaloffle.com/bbs/?uid=15034 Sparkle Team <p> <table><tr><td> <a href="/bbs/?pid=97929#p"> <img src="/bbs/thumbs/pico8_sparkleteam-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=97929#p"> Sparkle Team</a><br><br> by <a href="/bbs/?uid=15034"> hypothete</a> <br><br><br> <a href="/bbs/?pid=97929#p"> [Click to Play]</a> </td></tr></table> </p> <p>This is a half-completed demake of the Sega Genesis title <em>Shining Force</em>. I played the game for the first time early this year, and I found myself fascinated with the turn-based battle system. My biggest annoyance with <em>Shining Force</em> was that characters take a movement turn on the map, then combat takes place in a battle screen for only one turn. As enjoyable as it is to see higher quality graphics of the characters and terrain on the battle screen, there's a lot of time wasted moving between the two views in larger battles. I decided to write a similar battle system, but have all combat take place on the map instead.</p> <p>Here's how combat works: Characters on the map are sorted by their speed to determine turn order, then each character gets a movement and action turn. Playable characters have HP and MP bars that appear at the bottom of the screen during their turn. Depending on their class, a character may have ranged or melee attacks, as well as one or more magic spells. There are also potions hidden on the map, which characters can pick up by standing on them, and can drink as an action. There isn't a win condition implemented, but I found it fun to try and get my party to the castle in the center of the map while testing the mechanics.</p> <p>Writing this cart was a great way to get comfortable with coroutines, and hopefully the code will prove helpful for other people writing turn-based battle systems. Let me know what you think!</p> https://www.lexaloffle.com/bbs/?tid=44797 https://www.lexaloffle.com/bbs/?tid=44797 Tue, 28 Sep 2021 15:58:49 UTC GMagic: a vector art drawing program <p><a href="https://www.lexaloffle.com/bbs/files/15034/computergraphics.png" target=_view_image><img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/15034/computergraphics.png" width=160 height=160 alt="" /></a> <a href="https://www.lexaloffle.com/bbs/files/15034/breakfast.png" target=_view_image><img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/15034/breakfast.png" width=160 height=160 alt="" /></a> <a href="https://www.lexaloffle.com/bbs/files/15034/wrecks.png" target=_view_image><img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/15034/wrecks.png" width=160 height=160 alt="" /></a> <a href="https://www.lexaloffle.com/bbs/files/15034/pig.png" target=_view_image><img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/15034/pig.png" width=160 height=160 alt="" /></a></p> <p>Hi all,</p> <p>I'm writing a short graphical text adventure for the PICO-8, and a few weeks ago I determined that I needed a vector graphics editor capable of outputting PICO-8 code. I've created a web app called <a href="https://hypothete.github.io/gmagic/">GMagic</a> that lets you make vector drawings on a canvas, then export Lua functions for drawing them. I also provide the functions for drawing polygons and polylines:</p> <p>ptstr() (needed for the functions):<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:100%; max-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>function ptstr(s) local data={} local wip='' for i=1,#s do r=sub(s,i,i) if(r==',') then add(data,wip+0) wip='' else wip=wip..r end end add(data,wip+0) return data 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> <p>Polygon:<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:100%; max-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>function poly(r,c,p) local t=ptstr(r) --based off alienryderflex.com/polygon_fill --t=table x1,y1,x2,y2... --c=colors (hex) --p=pattern local pc=#t/2 local px={} local py={} local my=127--miny local xy=0 --maxy --split out xy lookups for i=1,#t-1,2 do add(px,t[i]) add(py,t[i+1]) if(t[i+1]&lt;my) my=t[i+1] if(t[i+1]&gt;xy) xy=t[i+1] if(i&lt;#t-2) then if(p) fillp(p) line(t[i],t[i+1],t[i+2],t[i+3],c) fillp() --yield() end end --scan down the screen for y=my,xy do local nx={} --build a list of nodes local n=0 local j=pc for i=1,pc do if((py[i]&lt;y and py[j]&gt;=y) or(py[j]&lt;y and py[i]&gt;=y)) then add(nx,(px[i]+(y-py[i])/(py[j]-py[i])*(px[j]-px[i]))) end j=i end --bubblesort nodes local k=1 while(k&lt;#nx) do if(nx[k]&gt;nx[k+1]) then nx[k],nx[k+1]=nx[k+1],nx[k] if(k&gt;1) then k-=1 end else k+=1 end end --fill the pixels for l=1,#nx-1,2 do local d=nx[l] local e=nx[l+1] if(d&gt;=127) break if(e&gt;0) then if(d&lt;0) d=0 if(e&gt;127) e=127 if(p) fillp(p) line(d,y,e,y,c) fillp() end end end --yield() 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><br /> Polyline:<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:100%; max-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>function pline(r,c,p) local t=ptstr(r) for i=1,#t-2,2 do if(p) fillp(p) line( t[i], t[i+1], t[i+2], t[i+3], c ) fillp() end --yield() 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> <p>If you want to read more about GMagic or check out some sample screenshots, you can view the Github repository <a href="https://github.com/hypothete/gmagic/tree/master">here</a>. If you end up using GMagic for a cart, I'd love to hear about it!</p> <p>EDIT 6/24: I can't believe I forgot to include ptstr()! I've added it above, and to <a href="https://github.com/hypothete/gmagic/blob/master/PICO-8.lua">the Lua sample</a> in the repo.</p> https://www.lexaloffle.com/bbs/?tid=33129 https://www.lexaloffle.com/bbs/?tid=33129 Sat, 02 Feb 2019 18:26:27 UTC World of Pico: a GPIO experiment <p><a href="https://www.lexaloffle.com/bbs/files/15034/screenshot.png" target=_view_image><img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/15034/screenshot.png" width=160 height=156 alt="" /></a></p> <p>Hi all, I wanted to share with you an experiment I've been working on called <a href="https://hypothete.com/projects/2019/world-of-pico/">World of Pico</a>. It uses the GPIO pins to transfer map data from a JavaScript context to the cart, allowing for essentially unlimited maps for exploration when the cart is hosted on a webpage. The demo has 3 maps, but I can see this technique being used in combination with a map server, and eventually allowing for interactivity between the client and server.</p> <p>The method of data transfer is very similar to how <a href="https://www.lexaloffle.com/bbs/?tid=3909">P8T by seleb</a> works. Different values on pin 0 of the GPIO tell the JS app or the cart whose turn it is to read and update the following pin values. If you want to explore the source code or read more about the transfer technique, please check out the <a href="https://github.com/hypothete/world-of-pico">GitHub repo</a>.</p> <p>Thanks for taking a look!</p> https://www.lexaloffle.com/bbs/?tid=32802 https://www.lexaloffle.com/bbs/?tid=32802 Sun, 06 Jan 2019 00:29:46 UTC Fill pattern dithering <p> <table><tr><td> <a href="/bbs/?pid=46131#p"> <img src="/bbs/thumbs/pico46130.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=46131#p"> Fill pattern dither</a><br><br> by <a href="/bbs/?uid=15034"> hypothete</a> <br><br><br> <a href="/bbs/?pid=46131#p"> [Click to Play]</a> </td></tr></table> </p> <p>This is a demo using the fill patterns introduced in 0.1.11 as a way of dithering between two or more colors. Use the buttons to adjust spread of the gradient, the number of sample circles drawn per frame, and the radius of the circles.</p> <p>The way it works is I have a gradient table, a fill pattern table, and a spread value. I'm going to draw 500 circles randomly each screen refresh, and each circle is going to use two colors and a fill pattern as its fill. The circle's colors are determined by the nearest and next nearest colors on the gradient based on some measurement, in this case the proportion of the spread to the shortest distance from a circle to one of three bouncing points.</p> <p>I set up a table of fill patterns that I generated from a 4x4 ordered dithering matrix. There's a good description of ordered dithering <a href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT">here</a>. Here's the matrix I used:</p> <div> <div class=scrollable_with_touch style="width:100%; max-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> 1 9 3 11 13 5 15 7 4 12 2 10 16 8 14 6 </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>To make a table of fill pattern values, I iterated over the 4x4 matrix 16 times, and if each cell was higher than the count i, I flipped a corresponding bit in a 16-bit binary number. This gives us 16 binary numbers to pass to the fillpattern method:</p> <div> <div class=scrollable_with_touch style="width:100%; max-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> pat={ 0b1111111111111111, 0b0111111111111111, 0b0111111111011111, 0b0101111111011111, 0b0101111101011111, 0b0101101101011111, 0b0101101101011110, 0b0101101001011110, 0b0101101001011010, 0b0001101001011010, 0b0001101001001010, 0b0000101001001010, 0b0000101000001010, 0b0000001000001010, 0b0000001000001000 } </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>The fill pattern for each circle is then determined by the circle's position between one color and the next along the gradient. So if the circle lands between two colors, it will use pat[7] or pat[8], but if it's centered on a color it uses pat[1].</p> https://www.lexaloffle.com/bbs/?tid=30231 https://www.lexaloffle.com/bbs/?tid=30231 Sat, 11 Nov 2017 02:11:38 UTC Voronoi diagram generator <p> <table><tr><td> <a href="/bbs/?pid=28059#p"> <img src="/bbs/thumbs/pico28058.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=28059#p"> Voronoi diagram generator</a><br><br> by <a href="/bbs/?uid=15034"> hypothete</a> <br><br><br> <a href="/bbs/?pid=28059#p"> [Click to Play]</a> </td></tr></table> <br /> Simple Voronoi diagram generator. I was trying to see if I could get a speed boost from writing pixel values directly to the video RAM, but regardless the fill walking through all the pixels is still very slow. Any ideas on how I could speed things up? </p> <div> <div class=scrollable_with_touch style="width:100%; max-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> --voronoi diagram --by hypothete points={} function makepoints() for i=1,16 do e=rnd(128) f=rnd(128) add(points,{ x=e, y=f, c=rnd(255) }) end end function jitter() for i=1,#points do p=points[i] p.x+=rnd(2)-1 p.y+=rnd(2)-1 end end function near(pts,b) nt=nil --nearest pt nd=4096--dist to nt for i=1,#pts do a=pts[i] nl=(b.x-a.x)^2 + (b.y-a.y)^2 --dist leaving off sqrt if(nl&lt;nd)then nd=nl nt=a end end return nt end function drawvoro() for i=0,63 do for j=0,127 do k=i+64*j --x+y*w = 1d position z={x=i*2,y=j} np=near(points,z) if(np) then memset(0x6000+k,np.c,0x1) end end end end function _init() makepoints() drawvoro() end function _update() if(btnp(5)) then jitter() drawvoro() end end </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> https://www.lexaloffle.com/bbs/?tid=27612 https://www.lexaloffle.com/bbs/?tid=27612 Mon, 05 Sep 2016 19:57:24 UTC Bracewell Probe Simulator <p> <table><tr><td> <a href="/bbs/?pid=28019#p"> <img src="/bbs/thumbs/pico28017.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=28019#p"> Bracewell Probe Simulator</a><br><br> by <a href="/bbs/?uid=15034"> hypothete</a> <br><br><br> <a href="/bbs/?pid=28019#p"> [Click to Play]</a> </td></tr></table> This is a simple simulation of Bracewell probes, AI-guided spacecraft that explore star clusters, looking for life and intelligence. Most of what I experimented with in this cartridge was depth-based sorting for drawing and hacky 3D projection techniques.</p> https://www.lexaloffle.com/bbs/?tid=27603 https://www.lexaloffle.com/bbs/?tid=27603 Sun, 04 Sep 2016 13:27:51 UTC Wizard of the Golden Hat <p> <table><tr><td> <a href="/bbs/?pid=27581#p"> <img src="/bbs/thumbs/pico27579.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=27581#p"> Wizard of the Golden Hat 0.0.1</a><br><br> by <a href="/bbs/?uid=15034"> hypothete</a> <br><br><br> <a href="/bbs/?pid=27581#p"> [Click to Play]</a> </td></tr></table> </p> <p>Hi all, this is my unfinished Ludum Dare 36 submission (<a href="http://ludumdare.com/compo/ludum-dare-36/?uid=20847">http://ludumdare.com/compo/ludum-dare-36/?uid=20847</a>). I started building the game with the day/night system and text menus; by the time I was 40 hours in I realized that I hadn't found the game mechanic and decided to call it quits. Still learned a ton, though.</p> <p>Quick shout out to geckojsc for the lua coroutine dialog system tutorial: <a href="https://www.lexaloffle.com/bbs/?tid=3833">https://www.lexaloffle.com/bbs/?tid=3833</a> I used a lot of the work here with a few tweaks to build the textboxes and in-game menu. One issue I'd like to address in the future is a more terse way of setting up actors and conditional scripts. I feel like when Pico-8 cartridges reach a length of ~1000 chars or so, things start to get really messy in terms of source code organization. Additionally, there were a few functions that I had trouble &quot;hoisting&quot; and I couldn't figure out why. If anyone has pointers on how to simplify the data structures I'm using or specifically better use of tables, please let me know. Thanks for taking a look!</p> https://www.lexaloffle.com/bbs/?tid=27553 https://www.lexaloffle.com/bbs/?tid=27553 Sun, 28 Aug 2016 17:56:35 UTC