Eiyeron [Lexaloffle Blog Feed]https://www.lexaloffle.com/bbs/?uid=1281 Long Line Theory <h2>Caution</h2> <p>This runs poorly in the Web version of 0.1.0f (runs too slow for the streaming to work well). This cart is better experienced in desktop versions.</p> <h2>Long Line Theory</h2> <p> <table><tr><td> <a href="/bbs/?pid=146941#p"> <img src="/bbs/thumbs/pico64_eyn_llt-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=146941#p"> eyn_llt</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=146941#p"> [Click to Play]</a> </td></tr></table> </p> <p>This cart is a quick port of <a href="http://www.pouet.net/topic.php?which=8357&amp;amp;page=13">Long Line Theory</a>, a bytebeat track that was and still is impressing me as of today. When I have access to directly audio rendering, this is usually my audio Hello World, especially with the <a href="https://gist.github.com/Eiyeron/7986703">C version</a> I made to port the JS snippet to desktop.</p> <p>This bytebeat is actually quite heavy, I had to resort to some tricks like a dirty resampling from 8kHz (its original sampling rate) to Picotron's 44.1kHz. It gave me enough spare cycles so I could whip that ugly visualizer. Can't have both your cake and eat it, I guess!</p> <p>Again, many thanks to <a href="https://www.lexaloffle.com/bbs/?uid=24137"> @luchak</a> for the <a href="https://www.lexaloffle.com/bbs/?pid=146405">PCM streaming proof-of-concept cart</a> and mu6k for that awesome piece of code.</p> https://www.lexaloffle.com/bbs/?tid=141818 https://www.lexaloffle.com/bbs/?tid=141818 Fri, 19 Apr 2024 10:47:09 UTC Tiny Animation Editor <h2>Caution</h2> <p>This posts acts also as a kind of documentation for the tool, its usage and the integration of the data. It's not final and might probably change in the future, to improve the writing style, fix mistakes or add more explanations. Please do report any feedback you desire so I can improve the documentation.</p> <h2>Anim Editor</h2> <p>Hello! From starting a project, I ended up going on a tangent for weeks and had been making a frame-based animation editor for the last few weeks with an intent of making my own internal mini animation library to make sprite animations as easy as drawing -or at least, for me-. </p> <p> <table><tr><td> <a href="/bbs/?pid=144671#p"> <img src="/bbs/thumbs/pico64_eyn_anim_editor-5.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=144671#p"> Tiny Animation Editor 0.0</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=144671#p"> [Click to Play]</a> </td></tr></table> </p> <h2>Using the tool</h2> <p>The animation editor is trying to follow the philosophy of Picotron's builtin editors. While it can't enjoy the same integration than the tools provided with the OS (like not having its own file open intent), it'll still aiming to feel at home when next to the other tool. Thus it's working at its best when opened while a cart is mounted/loaded to work on the cart's files.</p> <p>The editor is split in three parts : the view, the timeline and the sidebar, each of which is going to have its own section. There's also going to be one for using the data generated by the animation editor.</p> <h3>The sidebar</h3> <p>The sidebar has buttons to open or save an animation, save as another file, replace the currently loaded GFX file, a button to create animations and undo/redo actions. You can right click the open button to open up a recent file list instead of Picotron's open dialog for a faster access.</p> <p>Note that saving and opening are disabled in the BBS because there's no persistence nor demo files. This is planned for when I'll the energy to.</p> <p>Then is presented to you the animation list. Once you created one or more animations, they'll be listed there. Click on one of them to select it and double click an animation to rename it. The X button allows you to delete animations. Don't worry, deleting an animation is undoable.</p> <p>Following down is the sprite selector. It should work like the GFX editor except that you have an extra button to reload the GFX if you edited it externally. You can click &amp; drag a sprite from the grid to drop it on the view to add it on the current frame in the current animation.</p> <p>Note that the reload button is going to go away as soon as I'll replicate the map editor's automatic GFX reload mechanism. Another planned &quot;when in the mood for&quot; feature.</p> <h3>The timeline</h3> <p>Once you create and selected an animation, you'll see there its frames in the bottom bar and two buttons crossing over its border. The first button will create more frames at the end of the animation and the other one will play the animation. You can press space to toggle playback too but that doesn't seem to work on the BBS as my browsers tend to scroll the page down instead.</p> <p>Click on a frame to select it. Drag it to move it in the timeline. More options are hidden a right-click on a frame, like copy &amp; paste or duplicate the frame. The small circle on the top right corner will delete the frame. Again, it's one undo away from you.</p> <p>Note that most actions are disabled during playback, for your convenience (and to avoid a plethora of bugs). The grid will disappear and you'll be pretty much limited to change the playback speed (left editable for your convenience) and pausing the playback.</p> <h3>The scene view</h3> <p>Finally, the rest of the owl: the scene view. The scene view will display the current animation's current frame by overlaying the sprites from first to last inserted. Drag a sprite from the sprite selector to the view to add it to the frame. Once dropped, you can continue interacting with them by dragging them to reposition them or right-click for more options, like applying the currently selected sprite on the selected sprite. You can drag the view by click and dragging the middle mouse button to pan in the scene.</p> <p>Note that the two blue and green lines are the main axises of the animations and the point where they meet will be the origin of the animation. You might want to use that point as a reference when integrating your animations, the latter being the main topic of the next section. Nice segue, eh?</p> <h2>Using the animation data</h2> <p>Now that you made your animations, you might want to use them in your game or project, right? This is the section that will explain the inner details to help you getting to it.</p> <p>Like any POD file, an <code>.anim</code> file is just a serialized Lua table. You can introspect the <code>.anim</code> files by opening them with <code>podtree</code>, that's always a good trick to keep around in case you want to figure something or edit them.</p> <h3>Animation structure</h3> <p>An animation file (<code>.anim</code>), once loaded with <code>fetch</code> or <code>unpod</code>, contains two main elements at its root: a reference to the GFX file used during the creation of the file and a table named <code>anims</code>.</p> <p><code>anims</code> contains your animations, indexed by the name you put in the editor. So <code>my_anim</code> will be accessible by getting <code>my_loaded_file.anims[&quot;my_anim&quot;]</code> or <code>my_loaded_file.anims.my_anim</code>; the former syntax allows for spaces in the name.</p> <p>The GFX reference is used by the editor to determine which GFX file to load when loading the <code>.anim</code>, but you can also use it to identify yourself what to load, for situations like having a specific GFX file for a specific animations or anything, really, it's up to you.</p> <h3>Animations</h3> <p>An animation contains a list of frames, a <code>tick</code> member and a <code>loop</code> flag.</p> <ul> <li><code>ticks</code>: The system currently being based on rendering frames (or game logic ticks) as a measure of time, that member indicates how many ticks should be spent between two frames - so, in other words, a bit like the speed of the animation. Think of SFX' <code>speed</code></li> <li><code>loop</code>: This value is currently not used in the editor but you can use it in your code to determine if your animation should stop or not</li> </ul> <p>Each frame contains a list of sprites, which each stores an ID mapped to the loaded GFX file's sprite list(so like <code>spr</code> does too) and a position offset (relative to center of the scene in the editor). Those sprites should be rendered from first to last in the array to reflect what you'll see in the editor</p> <h3>Sample code</h3> <p>This is not fully tested, I just ripped off my project and tried to remove what was speicfic to it, but the general idea is there.</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>local player_anims = fetch &quot;anim/player.anim&quot; player = { ... anims = player_anims.anims } function player:set_anim(anim) self.curanim = anim local a=self.anims[self.curanim] self.animticks = a.ticks self.curframe = 1 end function player:update_animation() self.animtick-=1 if self.animtick&lt;=0 then self.curframe+=1 local a=self.anims[self.curanim] self.animtick=a.ticks--reset timer if self.curframe&gt;#a.frames then if a.loop then self.curframe=1--loop else -- Here I had something else in my code to transition into another animation if needed. -- Another element I'll probably add in the editor when I'll feel the need for. self.curframe = #a.frames end end end end function player:draw_animation() local a=self.anims[self.curanim] local frame=a.frames[self.curframe] -- Here, the animation's origin will be placed on (cx,cy), so the center of the player object. -- That's one way to of doing it, you could also use the middle point on the bottom, a corner, etc. local cx, cy = self.x-(self.w/2), self.y-(self.h/2) local flp_x = self.flipx and -1 or 1 for sprite in all(frame) do spr(sprite.gfx_index, cx + (sprite.x * flp_x), cy + sprite.y, self.flipx, false) 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> <h2>About the tool's future</h2> <p>I'm probably going to plug more features as I'll need them in the future, like having a timeline for hitboxes or triggers. I'll probably go back to this tool only when I'll really feel the need for it.</p> <p>Also, I'd like to be honest and say in advance I don't really plan on making the most versatile tool ever, but I'd like to make it a tool one could remix to their own needs. I made this small tool when building for another project in mind (or two, maybe???) and I'd not want it to take most of my time. I hope you'll understand.</p> <p>That said, I'll also add the task of trying to improve the source code to make it more open for customization in the &quot;maybe later&quot; task list.</p> <h2>Resources used</h2> <ul> <li>Zep's GUI lib and wrangler utility (forked the latter into a custom version). I also borrowed his save icon I recolorized. I hope you don't mind. :&deg;</li> <li><a href="https://opengameart.org/users/surt">Surt</a>'s <a href="https://opengameart.org/content/kenney-16x16">take on Kenney's Platformer Kit</a>. Licence: CC0</li> </ul> https://www.lexaloffle.com/bbs/?tid=141150 https://www.lexaloffle.com/bbs/?tid=141150 Tue, 02 Apr 2024 21:37:24 UTC [0.1.0d] Overlapping string in text editors and CRLF <p>Hello <a href="https://www.lexaloffle.com/bbs/?uid=1"> @zep</a>. I had to dig into the bug where text in text editors would overlap for some reasonand I noticed something: on Windows, the following snippet causes the issue 100% when pasted from notepad:</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>adasd the game</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Of course, I don't think copy-pasting it from here would work. As a matter of fact, there should be two blank lines and there's only one, so there's something altering the text, be it the BBS, the browser or something else.</p> <p>So, I hacked in <code>gui_ed.lua:insert_multiline_string</code> a way to read the string and its hexdump in the console log in the following snippet. It's ugly but it's functional.</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>local res = &quot;&quot; --str = str:gsub(&quot;\r&quot;, &quot;&quot;) -- I'll get to that for i=1, str:len() do local c = str:sub(i,i) local co = ord(c) local cs = c if co &lt; 32 then cs = (&quot;&lt;%02x&gt;&quot;):format(co) end res ..= (&quot;[%s][%02x]&quot;):format(cs, co) end printh(res)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>I spotted the presence <code>[&lt;0d&gt;][0d][&lt;0a&gt;][0a]</code> in console log, the classical CRLF. In that function, you're splitting by <code>\n</code> and I got a certain suspicion that happens when you mix reading text and Windows. Listing the pasted line's last characters got me on track: <code>\r</code>, a.k.a. <a href="https://en.wikipedia.org/wiki/Carriage_return">the carriage return</a>. That characters stays at the end of the line after the editor's code tries to split the clipboard content by the newlines. And because that character actually does a carriage return like the standard, the text following the character gets moved back to the start of the line and presto, it's overlapping text time!</p> <p>So, I don't know if you already have resolved that bug or if you have something in your planning, but in case not (and if people feel hacky enough to mod their editor until an official fix appears), one could build a workaround by removing any occurence of <code>\r</code> in the pasted code or strip them from the split lines.</p> <p>For the first method, the line I commented out in the snippet would do the trick. For the second method, one could add such snippet right after the split</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>for i, line in ipairs(lines) do local l = line:len() if line:sub(l, l) == &quot;\r&quot; then lines[i] = line:sub(1, l-1) 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> <p>I hope you'll find a more elegant solution than my monkeypatching and I hope that those pesky CRLFs were the only source for this specific bug. Have a nice day!</p> https://www.lexaloffle.com/bbs/?tid=141273 https://www.lexaloffle.com/bbs/?tid=141273 Sat, 30 Mar 2024 12:36:15 UTC [0.1.0d] Regression on cart saving as folders <p>Hello zep. I was wondering about a specific behavior of Picotron and I couldn't figure if it was a regression or a choice.</p> <p>Prior to 0.1.0c, if a cart folder with its name ending with <code>.p64</code> was loaded, saving it would preserve the format, the cart would stay a folder. Now, whatever I try to do, as soon as I save a folder cart from Picotron, it gets turned into a .p64 file, which is a bit more inconvenient as I'm currently using an external editor.</p> <p>Even <code>cp -o &lt;src&gt; &lt;dest&gt;</code> doesn't save a folder anymore if &lt;dest&gt; is suffixed with <code>.p64</code>. Copying to a normally named folder seems to work and I just realized that as I was writing this blog post. Still my question stands.</p> <p>Are project folders or files ending in <code>.p64</code> will always taken as files and going to be converted as such? Was the switch intentional? Should I rename all the folders in my project folder so far?</p> <p>Good luck squashing all those bugs! Have a nice day!</p> https://www.lexaloffle.com/bbs/?tid=141090 https://www.lexaloffle.com/bbs/?tid=141090 Mon, 25 Mar 2024 20:58:04 UTC Wrestling with wrangle <p>Hello, the release thread is a bit busy and I'd like to make it a bit more visible as it's both about a possible bug and a feature the community could use for editor or more, it's a bit more interesting than just a crash, I'd say. I think I found a possible issue with <code>wrangle</code> and <code>filenav</code>.</p> <p>Basically, wrangle that works with the current opened file pwf() and by when creating the wrangle object you have to pass getter/setter to store/load data from the file. Right?</p> <p>Inspired by the GUI code here and there, I found out that the argument <code>intention</code> was mostly the thing that makes filenav acts as an open/close dialog, or supposedly. Thus, I ended up with code looking like that</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> sidebar:attach_button{ x=0, y=0, label=&quot;Open&quot;, tap = function() local segs = split(pwf(),&quot;/&quot;,false) local path = string.sub(pwf(), 1, -#segs[#segs] - 2) -- same folder as current file create_process(&quot;/system/apps/filenav.p64&quot;, {path=path, intention=&quot;open_file&quot;, window_attribs={workspace = &quot;current&quot;, autoclose=true}}) end } sidebar:attach_button{ x=32, y=0, label=&quot;Save as&quot;, tap = function() local segs = split(pwf(),&quot;/&quot;,false) local path = string.sub(pwf(), 1, -#segs[#segs] - 2) -- same folder as current file create_process(&quot;/system/apps/filenav.p64&quot;, {path=path, intention=&quot;save_file_as&quot;, window_attribs={workspace = &quot;current&quot;, autoclose=true}}) 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>And somehow, it works! Or almost.</p> <p>I believe there's a slight issue with the <code>open_file</code> intention: it doesn't properly override the doubleclick event, as seen in 1/apps/filenav.p64/open.lua<code>, <a href="https://www.lexaloffle.com/bbs/?uid=1"> @zep</a> wrote that he didn't any find another intention that didn't needed the same exception than</code>save_file_as`; the default operation did the same expected result anyway by leaving the default editor to open the file thanks to that hardcoded* extension/editor association mapping.</p> <p>Thus we end up with the situation where we can't just open a file from a non-system editor by doubleclicking with a custom file or file format. I found a workaround: if you type the file to open in the filename toolbar, it'll properly handle the event, pass the open_file event back to wrangle and your file will properly load!</p> <p>So, here's my questions:</p> <ul> <li>Picotron's boundaries about what's user-accesible code or not is a bit blurry, should we allowed to use wrangle?</li> <li>Should <code>filenav</code>'s <code>open_file</code> intention get the same exception than <code>save_file_as</code> if it was called from an external program?</li> <li>Was the end result intented or is it a bug? Having two contradictory results from the dialog seems like a bit unexpected.</li> </ul> <p>Anyway, have a nice day!</p> <p>Addendum : I also noticed another potential issue: the opening workflow works only when one types the filename in the text entry. Selecting an icon and then pressing Open won't work and won't change the current file, failing the opening process.</p> https://www.lexaloffle.com/bbs/?tid=140890 https://www.lexaloffle.com/bbs/?tid=140890 Mon, 18 Mar 2024 23:02:22 UTC Random Picotron discoveries <p>Some Discord servers have been quite busy lately and we've been discovering (less trivial) things here and there than the officially documented things and I thought it was good to have them available in the BBS instead of losing them in a Discord server's chat log. I'll try to update this post as more discoveries are uncovered.</p> <p>Don't hesitate to write more discoveries in the thread.</p> <h2>Notice</h2> <p>At the moment I'm writing this post, we're running 0.1.0b, stuff might change in the future, nothing is set in stone for now.</p> <h2>POD is data, data is POD</h2> <p>Most of the file one will find on their systems are just POD files with an extension. The extension allows the OS to determine which app to launch but the internal data seems to work the same for all formats: they're PODs.</p> <p><code>podtree (your_file)</code> will pop a tool window containing a tree interface with the guts of your file. So you can determine how those file are formatted.</p> <p>For instance the default <code>drive.loc</code> file, once opened, will show that it has only one property: location. So creating a table looking like that <code>my_table = {location=&quot;/path/to/a/program.p64&quot;}</code> and then saving it with <code>store(my_shortcut.loc, my_table)</code> will efectively crete a new shortcut.</p> <p>In the same idea, GFX files are just arrays of small tables containing an userdata and some editor properties, map files are in the same vein than GFX files.</p> <p>Remember that there is a spec documentation available to explain in detail what a POD is or how to manipulate them: <a href="https://www.lexaloffle.com/dl/docs/picotron_pod.html">here</a>.</p> <h3>.loc files</h3> <p>Loc files are conceptually similar to Windows' <code>.lnk</code> files. They have a property (<code>location</code>) pointing to a file or cart, but they can also store arguments in a table (<code>argv</code>) that will be passed to the launched program. Here a snippet to create a sample <code>.loc</code> launching a program with arguments</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>store(&quot;/desktop/my.loc&quot;, {location=&quot;/dev/a_program.p64&quot;, argv={&quot;some&quot;, &quot;arguments&quot;, &quot;as&quot;, &quot;an&quot;, &quot;the&quot;, &quot;game&quot;}})</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Those arguments will be accessible from the launched program through <code>env().argv</code>. Thus, you could make yourself shortcuts to quickly open a tool with a specific file or options or launch a program with a specific mode depending on the flags you launch, you're free to do it the way you want.</p> <p>I'm working on a tool prototype and here's for instance the current code I'm using to parse the arguments. I'm doing extra logic to handle <code>--gfx</code> or <code>--anim</code> options for absolutely no reason, though. You're free to edit the sample as you wish.</p> <p><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>local default_anim_path = &quot;/desktop/untitled.anim&quot; --local default_gfx_path = &quot;/ram/cart/gfx/0.gfx&quot; local default_gfx_path = &quot;/dev/platformer.p64/gfx/0.gfx&quot; -- My current project function get_or(tbl, key, fallback) return tbl[key] or fallback end function extract_args(argv) local anim, gfx = default_anim_path, default_gfx_path if not argv then return anim, gfx end local index = 1 while index &lt; #argv do if index == &quot;--gfx&quot; then local gfx_arg = get_or(argv, index + 1) if gfx_arg ~= nil then gfx = gfx_arg index += 2 else index += 1 end elseif index == &quot;--anim&quot; then local gfx_arg = get_or(argv, index + 1) if gfx_arg ~= nil then gfx = gfx_arg index += 2 else index += 1 end else -- Guessing from extension local arg = argv[index] local parts = arg:split(&quot;.&quot;) local ext = parts[#parts] if ext == &quot;gfx&quot; then gfx = arg elseif ext == &quot;anim&quot; then anim = arg end index += 1 end end return anim, gfx 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> <h2>The Tool Tray</h2> <p>The tool tray (also known as <code>desktop2</code> in some internal places) is the blue region that shows up when you drag the menu bar down. By default it's pretty bare, only a clock and a pair of eyes will welcome you, but it contains a few tricks under its sleeve (or should I dare to say tray?)</p> <h3>Widgets</h3> <p>(Widgets isn't an official term, they just remind me of Windows Vista's widgets)</p> <p>First, adding more programs in the tray can be done by doing something like what does <code>/system/startup.lua</code></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>create_process(&quot;/path/to/file.lua&quot;, {window_attribs = {workspace = &quot;tooltray&quot;, x=widget_x, y=widget_y, width=widget_width, height=widget_height}})</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>More research should be done around those tools, but so far, here's what was found out: Widgets can only draw by default in their region provided in the <code>window_attribs</code> and the drawing coordinates are offset to align (0,0) to the region's top left (basically, <code>clip</code> + <code>camera</code>). As shown by <code>eyes.lua</code>, widgets also can listen to input events. Widgets works like any other process, so they'll be listed by <code>ps</code> and can be killed.</p> <p><strong>Caution</strong> Launching a program as a wallpaper (with the window_attribute <code>wallpaper</code> set to true) doesn't seem to work and it'll blink every other frame, so if you're sensitive to blinking lights, you definitely shouldn't do thqt.</p> <h3>Putting files in the tray</h3> <p>As hinted by some of the OS' code, the tray can act as a second desktop where you can place files in them! Just drag'n'drop from the normal desktop to the tray and you'll can see it can store the file! Actually when you moved the file to the tray, it was moved to <code>/appdata/system/desktop2</code>. So, you could store random shortcuts there, log files, etc. in that tray and show them at will on any other workspace.</p> <h2>Copy data from Pico-8 to Picotron</h2> <p>As Pico-8 and Picotron use the clipboard, you can pass along some data. For instance, copying a sprite from Pico-8's sprite editor to Picotron works. Of course, in Pico-8 you'll be limited to the original 16 colors, so it cannot act as a full replacement for Picotron's drawing tool.</p> <p>In a pinch, it could help you importing spritesheets to Picotron until other methods are implemented.</p> <h3>POD embedding in code editor</h3> <p>As shown in notebook.p64, Picotron can somewhat support embedded graphics userdata in text file and display them inline with the rest of the file. The way of using that is to pod an userdata into base64 format and concatenating to your file with a comment header like that</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>--[[pod_type=&quot;image&quot;]]unpod(&quot;b64:the base64 representation of your image&quot;)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>And it'll show up as a picture in both in <code>notebook.p64</code> and the code editor too! I haven't got to make work with <code>print</code> yet so maybe they're more fit for comments?</p> <h2>The desktop envrionment</h2> <h3>Theming your wallpaper</h3> <p>A small tip: the wallpapers provided with the OS are grabbing the theme properties to adapt to the system's theme. For instance <code>&quot;desktop0&quot;</code> and <code>&quot;desktop1&quot;</code> are two of the three colors set for the desktop section of the theme. If you want to write a wallpaper adapting itself automatically to the system, you might want to grab those colors on a regular basis with <code>theme(&quot;desktop0&quot;)</code> and <code>theme(&quot;desktop1&quot;)</code> as they'll automatically update when needed. You're not limited to those colors either, but I think that sticking to those colors will help with readability as the selected colors will most often be different from the ones used in other GUI elements.</p> <h3>More desktop workspaces?</h3> <p><strong>Caution</strong> This is really not tested yet, this seems to work but here be dragons.</p> <p>Somehow, a certain combination of window attibutes will allow you to spawn additional desktop workspaces. Surprisingly, most of the behvaior of the desktop is not really a program so the wallpaper will do the job. Here's a minimal snippet to clone your default desktop with comments</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>-- Those two lines are directly copied from startup.lua, they'll fetch your wallpaper program local sdat = fetch&quot;/appdata/system/settings.pod&quot; local wallpaper = (sdat and sdat.wallpaper) or &quot;/system/wallpapers/pattern.p64&quot; -- create_process(wallpaper, { window_attribs = { workspace = &quot;new&quot;, -- I don't know yet desktop_path = &quot;/desktop&quot;, -- I suppose that's the folder shown on the desktop wallpaper=true}, -- RUn the program in background, for wallpaper programs style=&quot;desktop&quot;}) -- Somehow this does the trick and will also make the icons show on the workspace but I don't know why it's not in startup.lua</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>That should do the trick. Of course, you don't have to stick to your configured wallpaper, you could perfectly use another. Note that the theme settings are global so you can't really have different UI themes between workspaces yet.</p> <h3>More colors in your icons</h3> <p>So, you've been probably thinking that three color and an alpha channel aren't enough for your icons? Maybe you want your program to stand out on your desktop? Don't fret any more, I have the solution!</p> <p>Pictron saves metadata for virtually almost every file it can open, icons are part of them. When you've been editing the icon through the icon editor tool, you have been editing those files' metadta, right? What if I told you this icon is just a simple sprite like any other sprite you can create, draw and store? Catch my drift? Here's a magic trick:</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>source = fetch &quot;/ram/cart/gfx/0.gfx&quot; meta = fetch_metadata &quot;/untitled.p64&quot; meta.icon = source[0].bmp store_metadata(&quot;/untitled.p64&quot;, meta)</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 will effectively loads the first sprite of your currently loaded cart and set its as the icon of <code>/untitled.p64</code>. There are a few caveats before you get drunk with power:</p> <ul> <li>Sadly (or not), this won't work if the icon you want to set is not 16*16 pixels. (Note, right now the OS checks only the width so you can go as tall as you wish but it's most likely a bug)</li> <li>For desktop theming, <code>filenav</code> (and thus the desktop too) remaps the colors <code>1, 6, 7, 13</code> to the desktop's theme colors set for the icons and you can't really circumvent that (unless you want to mod your OS). So if you want to get artistic, you might want to skip those colors. Note that those colors are effectively the colors you've been applying to the icon when using the icon editor.</li> </ul> <h2>Unsorted general tips or info</h2> <ul> <li>Don't forget to dig in the OS' Lua files, they're currently a good source of info not yet documented, like <code>blit</code>, which allows copying a 2D region of an userdata to another. A few of the info mentionned were dug from snooping in them, so have look!</li> <li>Picotron's <code>/system</code> folder is written as read-only but what it means for now is that any user change will be lost as the folder will be recreated at every launch.</li> <li>In a similar vein, the OS contains some goodies like fonts you can apply on your program by launching a snippet like that one: <code>poke(0x4000, get(fetch(&quot;/system/fonts/lil_mono.font&quot;)))</code>. Pico-8's font can be found there, have a look!</li> <li><code>poke(0x5f36, 0x80)</code> as seen in <code>filenav.p64</code> enables text wrapping using the <code>clip()</code> rect.</li> <li><code>/ram/system</code> contains a few neat stuff like <code>processes.pod</code> which lists all the executing process.</li> <li>When you launch a cart, it might not close when you exit it and its icon will stick in the menu bar. To effectively close them, you can right-click or middle-click on their icon and hit close. Or use <code>ps</code> and <code>kill</code>. Or use a process manager tool. Or reboot Picotron, etc.</li> <li>The audio editor can be quite unituitive, you might want to look at the <a href="https://www.lexaloffle.com/dl/docs/picotron_synth.html">doc</a> in case you missed a feature or another. I mean, I spent some time playing with the tool until I noticed that I could sawp wavetables to get white noise by clicking on an osc.'s waveform window.</li> <li>It seems like calling <code>poke(0x547d,0xff)</code> in a windowed program will make any transparent color marked with <code>palt</code> or other mechanisms turn transparent, so you can see what's behind your window. Thanks <a href="https://www.lexaloffle.com/bbs/?uid=54999"> @taxicomics</a> for the report.</li> </ul> https://www.lexaloffle.com/bbs/?tid=140758 https://www.lexaloffle.com/bbs/?tid=140758 Sun, 17 Mar 2024 00:22:13 UTC Raycasting base code <p> <table><tr><td> <a href="/bbs/?pid=92849#p"> <img src="/bbs/thumbs/pico8_eyn_raybase-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=92849#p"> eyn_raybase</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=92849#p"> [Click to Play]</a> </td></tr></table> </p> <p>So, I fell into the raycasting hole. I'll keep around a small cart with a few routines so I can quickly do more stuff with that technique.</p> <p>I'm not making a generic routine to display the walls because there are a lot of features one might want to use in their own caster (wall uvs, animations, etc etc), so instead, I made a few scenes to show how to augment a simple caster to do a few more things (like alternating textures on NS/EW sides or having a depth buffer to properly render world sprites)</p> <p>In the future I might explore ray collision, there is potential to get fun stuff with that. A lead I'm following is using custom collision shapes per tile so hitting a tile will trigger the shape. An example of a possible shape would be a circular column smaller than a tile would be simple to do with a ray-circle hit detection and atan2 to compute the UV.</p> <p>Addendum: the cart is in WIP because this cart'll never sum up to a finished project and because there is room for improvement. For instance I'm not totally satisfied with rspr.</p> <p>Version 0: initial release</p> <p>Version 1: quickly added a sspr map renderer. Costs less CPU than tline for a mostly similar look minus visual jumps in some angles. The renderer might need more work to avoid having the walls and their texture jump as much (experimenting with flooring/ceiling the coordinates might be a lead).</p> <p>Topic update : moved to GFX samples as it might be a better place than WIP.</p> https://www.lexaloffle.com/bbs/?tid=43135 https://www.lexaloffle.com/bbs/?tid=43135 Mon, 31 May 2021 18:21:50 UTC 3D Maze <p> <table><tr><td> <a href="/bbs/?pid=0#p"> <img src="/bbs/thumbs/pico8_eyn_3dmaze-4.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=0#p"> 3D Maze</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=0#p"> [Click to Play]</a> </td></tr></table> </p> <p>The legendary screensaver from Windows 95, recreated in Pico-8. You can now feel like it's 97 all over again, but in 128x128 pixels.</p> <p>Something is off, I can't put my finger on it. Maybe if I <em>let it run</em> for a while?..</p> <p>A content note (spoiler) : <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;">Contains mild horror stuff (eyes, bloddy mouth). No screamer though.</div></div></div></p> https://www.lexaloffle.com/bbs/?tid=43109 https://www.lexaloffle.com/bbs/?tid=43109 Sat, 29 May 2021 09:05:51 UTC Sample Sandbox <p>A cart a bit different than the usual coming from me. I recently discovered about the hidden PCM channel and I just had to play with.</p> <p>So I'm experimenting with both sample playback and PSG (Programmable Sound Generators) to both learn and see if we can make the most of the PCM channel and -why not- in the distant future, have a 5-channel tracker?</p> <p>So here, we've got one cart that shows smooth playback of various samples and at the end a sawtooth PSG.</p> <p> <table><tr><td> <a href="/bbs/?pid=91665#p"> <img src="/bbs/thumbs/pico8_eyn_smplsndbx-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=91665#p"> eyn_smplsndbx</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=91665#p"> [Click to Play]</a> </td></tr></table> </p> <p>To generate the samples, I use two steps:</p> <ul> <li>A pass through SoX to convert a sample into unsigned 8bit 5512Hz raw file (<code>-e unsigned-integer -r 5512 -b 8</code>).</li> <li>A quick use of a Python script to convert the sample into a pastable string (I suggest you to convert it into chars once inside Pico-8). I'm sorry I can't post the snippet here yet, it somehow breaks the BBS' upload process.</li> </ul> <p>I commented in the cart a basic low-pass filter inside the sawtooth PSG. It seems pretty costly to generate it on the fly. Maybe it'd be wise to precompute filtered waveforms like <a href="https://www.littlesounddj.com/">LSDj</a> does.</p> <p>A few notes on my findings</p> <ul> <li>The playback is way better on Desktop than on a browser. I'm sorry in advance for the noise or the volume.</li> <li>I got the best playback results with a packet size of 512 bytes.</li> <li>Just playing samples from a string doesn't cost a lot. It'd be even lighter if you would blit the string in the RAM to just memcpy away.</li> <li>It <em>seems</em> that a tick of length 8 in a SFX vaguely matches 366 PCM samples. Vaguely because I still have desync issues after a while. I wish I can find the proper packet size balance so we could not have to deal with desyncs.</li> </ul> <p>Update : moved to SFX. I probably won't touch the cart anymore.</p> https://www.lexaloffle.com/bbs/?tid=42809 https://www.lexaloffle.com/bbs/?tid=42809 Fri, 07 May 2021 22:36:55 UTC Sprint'a'Gift <p> <table><tr><td> <a href="/bbs/?pid=85186#p"> <img src="/bbs/thumbs/pico8_eyn_sprintagift-2.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=85186#p"> Sprint'a'Gift</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=85186#p"> [Click to Play]</a> </td></tr></table> </p> <p>Play it also on Itch : <a href="https://eiyeron.itch.io/sprintagift">https://eiyeron.itch.io/sprintagift</a></p> <p>Sprint'a'Gift is a submission to a certain 2020 holidays calendar you can find <a href="https://www.lexaloffle.com/bbs/?tid=40701">here</a>.</p> <p>Santa's in a hurry and forgot to jump on his magical sleigh! Now he's trying to run as fast as he can on the rooftops for an express delivery. Can you help him?</p> <p>Controls:</p> <ul> <li>(X) Jump (hold for higher jumps)</li> </ul> <p>Thanks to:</p> <ul> <li>Gruber for the music</li> <li><a href="https://somepx.itch.io/">Somepx</a> for the title font</li> <li>Adam Saltsman for Canabalt, which is the main inspiration for this game.</li> </ul> https://www.lexaloffle.com/bbs/?tid=40717 https://www.lexaloffle.com/bbs/?tid=40717 Wed, 09 Dec 2020 07:41:41 UTC Fillp-based Fade Generator <p> <table><tr><td> <a href="/bbs/?pid=81392#p"> <img src="/bbs/thumbs/pico8_eyn_fade_gen-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=81392#p"> Fillp Fade generator</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=81392#p"> [Click to Play]</a> </td></tr></table> </p> <p>I'm making a small tool to quickly generate fill pattern for making fades. As I'm working on a game using those, I hastily threw together this small program to quickly visualize and tweak a fade based on the base pattern and to export it.</p> <p>Each case in the grid represents a pixel in the fill pattern. The generator is creating a fill pattern gradient from 0x0000 to 0xFFFF while each pixel can turn off in a different frame. The pixel's value will indicate to the generator how many frames the bit must be kept at 0, with zero meaning that it'll stay down for 1 frame, one for two 2 frames and so on. Up to 17 frames worth of fill pattern can be created this way.</p> <p>The default setting is the fade with the classic dithering 2x2 Bayer pattern, the one that inspired me to do this tool.</p> <h2>Controls</h2> <p>[Up/Down/Left/Right] : Move the cursor around the grid<br /> [X+Up/Down/Left/Right] : Change the frame at which the bit selected by the cursor is kept at 0.<br /> [O] : Test the pattern<br /> [X+O] : Copy pattern to the clipboard (+ctrl-c on web)</p> <h2>Changelog</h2> <h3>Revision 1</h3> <ul> <li>Now generating less frames if the found maximum value is less then 15</li> <li>Using up/down when changing the frame value in the grid will increase/decrease by 4</li> </ul> https://www.lexaloffle.com/bbs/?tid=39446 https://www.lexaloffle.com/bbs/?tid=39446 Mon, 31 Aug 2020 11:43:55 UTC Quasi tunnel <p> <table><tr><td> <a href="/bbs/?pid=80961#p"> <img src="/bbs/thumbs/pico8_quasi_tunnel-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=80961#p"> quasi_tunnel</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=80961#p"> [Click to Play]</a> </td></tr></table> </p> <p>I almost succeeded in making a tline-based tunnel effect in a tweetcart.</p> <p>Two limitations : poor angle/side management and no perspective scaling.</p> <p>Close enough.</p> <h3>Post-mortem explanation</h3> <p>Most sites explaining the effect are based on screen-space LUTs. pset-ing 128*128 times being very slow,<br /> I got the idea to use tline to draw on the whole screen by considering that function as the converter between normal and polar coordinates.</p> <p>To get the &quot;normal coordinates&quot; version, try replacing the for calls to w with <code>w(x,0,x,127,p,o,0,v)</code></p> <p>I accidentally made the tunnel circular instead of square, can't help explaining this part, sorry.</p> https://www.lexaloffle.com/bbs/?tid=39284 https://www.lexaloffle.com/bbs/?tid=39284 Wed, 19 Aug 2020 19:01:22 UTC Vortex <p> <table><tr><td> <a href="/bbs/?pid=74558#p"> <img src="/bbs/thumbs/vox_tc_vortex-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=74558#p"> tc_vortex</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=74558#p"> [Click to Play]</a> </td></tr></table> </p> <p>I got the voxel itch again after so long. This is a tweetcart version of an effect I'll very probably use in the future. The code is slightly altered from what I posted on Twitter because when running a cart without a scene, the camera is not properly reset.</p> <p>I also added the zoom transition that'll be used, you can see it working by pressing up/down.</p> <p>Here's the code</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>q=0 function _draw() camera() if(btn(3))q-=.5 if(btn(2))q+=.5 q=mid(20,q) clv() for z=48,63 do a=t()/6-z/12 r=63-z+q s=16*(1-q/20) o,p=s*cos(a),s*sin(a) col=z%2+33 set_draw_slice(z-q) rectfill(0,0,127,127,col) circfill(o+64,p+64,r*6,0) end set_draw_slice(0) 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=37286 https://www.lexaloffle.com/bbs/?tid=37286 Wed, 08 Apr 2020 10:15:19 UTC A new rotoscaler! <p>I can't believe it's been almost 5 years I posted <a href="https://www.lexaloffle.com/bbs/?tid=1843">that old rotoscale effect here</a>. It's been roughly 5 years that I discovered and loved Pico8, it's a console that stuck on me and that I love to program little bits and bobs on it.</p> <p>I also can't believe how far the community have gone with that small computer. Just look back and see how much projects evolved on it and how thriving it is after so long. Y'all are so productive and creative you make the BBS and the community awesome!</p> <p>So yeah, after a few years, I had to touch up that old cart. It was really poorly optimized. Inspired by a few awesome devs, I used a few new tricks based on peek/poke and <em>damn</em>, it goes way faster than I expected. I jumped on the occasion to add translation and a small effect, just because why the hell not.</p> <p>See ya!</p> <p> <table><tr><td> <a href="/bbs/?pid=73789#p"> <img src="/bbs/thumbs/pico8_new_roto-2.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=73789#p"> new_roto</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=73789#p"> [Click to Play]</a> </td></tr></table> </p> <p>Update 2020-05-05 (or 2020-05-05 for people reading days before months)<br /> Finally got to make it fit under the 0.2 CPU timing limitations (Post binary operations re-re-balance). Big frame time gain of ~50%.</p> <ul> <li>Increased the spritesheet to 32x32 to only keep a bitmask instead of calling FLR.</li> <li>Precomputed a 128x128 pixel map to make up for the bigger pattern (and to make a neat shifting pattern)</li> <li>Precomputed the wave effect to avoid doing the calculation too many times</li> <li>Extra color shenanigans because why not?</li> <li>Slowed down the scrolling and zooming. Bumping up the wave shift to amplify its visibility.</li> </ul> https://www.lexaloffle.com/bbs/?tid=37031 https://www.lexaloffle.com/bbs/?tid=37031 Mon, 09 Mar 2020 20:12:48 UTC Spiral Effect Breakdown <p>Hello there, after a positng a sketch variation I did on Twitter earlier today, I was asked how one would do such a similar result.</p> <p>So instead of a badly written Twitter thread, let me post you a badly written BBS post with a badly written (but well commented) breakdown on how I did it.</p> <p>The spiral is a cylinder sliced in a few circles I offset on X and Y based on a formula. This formula varies with time and on which circle it'll yield the offset to (here, the index).</p> <p>So, I progressively iterated from nothing to the spiral. Here's how I broke it down:</p> <p>First I generate circles made by vertices I'd store aside. Drawing circles this way will allow me to the other steps. Each circle is drawn by drawing a segment between two consecutive vertices in the circle and by linking the same vertex between two consecutives circles. Here, it looks like a colored spider web.</p> <img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/1281/PICO-8_000.png" alt="" /> <p>Then, I made the circles' center move based on the time. But it still doesn't look like a spiral. We can do better.</p> <img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/1281/PICO-8_0.gif" alt="" /> <p>So I make each circle's offset move indenpendtanly. I draw the circle in a <code>for i=1,n</code><br /> loop, so I can use i to have a different result per circle. Here I just add an offset to the sin formula to make each center different from the others.</p> <img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/1281/PICO-8_1.gif" alt="" /> <p>By doing the same on the y axis, I'd have a diagonal if I would use the exact same formula. The complement formula to draw a circle based on T with sine is cosine, so for the y offset I used the same formula but with sin turned into cos. Now each center moves into a circle.</p> <img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/1281/PICO-8_2.gif" alt="" /> <p>I can perfectly tweak both formulas differently. For instance here, I removed the x offset and made the y offset in a way so circles will cross some of their neigbors. It'll be useful to give a better sense of depth in the next step<img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/1281/PICO-8_3.gif" alt="" /></p> <p>And, as a last step, I replaced the line drawing by drawing quads with the trifill routine generously made by ElectricGryphon so we have a solid tunnel instead of a wireframe one!</p> <img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/1281/circles_0.gif" alt="" /> <p>And that's the core basics on how I made the Nuclear Throne inspired vortex sketch a while ago! I'll be leaving the commented code on the bottom of this post, feel free to have a look on how I did it, but here's a fair warning: I clearly didn't optimize the code, there is still a lot that could be done to avoid useless calculations, but it should be clear enough to allow quickly anyone to hack it, it works and in 30 FPS. Have a nice day and happy 32 colors day!<br /> <table><tr><td> <a href="/bbs/?pid=67245#p"> <img src="/bbs/thumbs/pico8_colored_spiral-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=67245#p"> colored_spiral</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=67245#p"> [Click to Play]</a> </td></tr></table> </p> https://www.lexaloffle.com/bbs/?tid=35263 https://www.lexaloffle.com/bbs/?tid=35263 Wed, 04 Sep 2019 18:50:08 UTC fishes <p> <table><tr><td> <a href="/bbs/?pid=64332#p"> <img src="/bbs/thumbs/vox_fishes-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=64332#p"> fishes</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=64332#p"> [Click to Play]</a> </td></tr></table> </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>r=rnd function _draw() srand(1) clv() for i=0,32 do ot = r(16)-8 tf = flr((t()+ot)*16) op = r() c = 96+r(7) sh = r(4)+12 z = r(63) yb= r(127) for x=0,48 do h = sin(x/48)*5+6 X = (x + tf)%128 y = sin(X/96 + op) * sh + yb line3d(X, y, z, X, y + h, z, c) end 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> <h1>Alternative version</h1> <p> <table><tr><td> <a href="/bbs/?pid=64332#p"> <img src="/bbs/thumbs/vox_fishes_alt-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=64332#p"> fishes_alt</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=64332#p"> [Click to Play]</a> </td></tr></table> </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>r=rnd function _draw() srand(1) clv() for i=0,32 do ot = r(16)-8 tf = flr((t()+ot)*16) op = r() sh = r(4)+12 z = r(63) Y= r(127) for x=0,48 do X = (x + tf)%128 y = sin(X/96 + op) * sh + Y line3d(X, y, z, X, y + sin(x/48)*5+6, z, 96+7-(z/9)) end 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=34184 https://www.lexaloffle.com/bbs/?tid=34184 Sat, 11 May 2019 20:33:56 UTC Sphere Cube <p> <table><tr><td> <a href="/bbs/?pid=60688#p"> <img src="/bbs/thumbs/vox_sphere_cube-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=60688#p"> sphere_cube</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=60688#p"> [Click to Play]</a> </td></tr></table> </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>c=cos s=sin l=sphere v=8 M=2 m=-M function _draw() clv() for X=m,M do for Y=m,M do for Z=m,M do T=t() a=T/8 W=c(a) w=s(a) V=v*(1/T+1)+W+w x,y,z=X*W-Y*w,X*w+Y*W,Z x,y,z=z*w+x*W,y,z*W-x*w x,y,z=x*V+64,y*V+64,z*V+32 l(x,y,z,5,224-16*flr(y/16-2)) l(x,y,z,4,13+X+Y+Z) end end 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=32833 https://www.lexaloffle.com/bbs/?tid=32833 Tue, 08 Jan 2019 19:47:56 UTC Issues with pseudo-modules <p>Hello, I'm trying to port over some libraries to kickstart prototyping on voxatron (such as 30log or cpml) and I got a weird issue with functions not finding an upvalue.</p> <p>Let's say we have a B.lua file and a A.lua file<br /> B.lua contains this:</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>B = {} B_mt = {} local function new() return setmetatable({}, B_mt) end function B.new() return new() end function B.draw() print(&quot;Called&quot;,0,0,7) end B_mt.__index = B function B_mt.__call() return B.new() end B = setmetatable({}, B_mt)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>It's basically a global class-ish definition with a constructor, an alias to the constructor via __index and the private constructor which is called internally.</p> <p>Let's say we have an A.lua script which does:</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>local b = B() function _update() end function _draw() b.draw() 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>It simply gets a B instance and calls its draw function yet it doesn't work on Voxatron 0.3.5. I don't know what are the private/public global/local stuff available on this platform but this kind of pattern doesn't work well. I get this kind of error.</p> <img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/bbs/files/1281/a.png" alt="" /> <p>In vanilla lua, it works pretty well, I can use <em>dofile</em> or <em>require</em> sequentially those files and call _draw() without error.</p> <p>So I don't know if it's an error or a quirk designed by Voxatron limitations, but I'd like to know if it's intended and what are the extends of using local/global variables between scripts in Voxatron.</p> <p>Thanks and have a nice day.</p> <p>Edit : I'm calling those pseudo-modules because as we don't have Lua's module system, there are a few patterns that allows for psuedo modules to happen. They're just loaded during the cart initialization and in a sequential manner.</p> <p>Edit 2 : For further indication, this is cpml's way of making classes.</p> https://www.lexaloffle.com/bbs/?tid=32775 https://www.lexaloffle.com/bbs/?tid=32775 Thu, 03 Jan 2019 16:28:20 UTC Sphere (Vox) <p> <table><tr><td> <a href="/bbs/?pid=60455#p"> <img src="/bbs/thumbs/vox_sphere_vox-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=60455#p"> sphere_vox</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=60455#p"> [Click to Play]</a> </td></tr></table> </p> <p>I had to recreate my Sphere on Voxatron. I wandted to see how it'd look. I don't have a fillp routine yet, but I feel already happy with how it looks.</p> <p>I didn't redo the white HUD tidbits for a specific reason : I haven't got to determine the good processes to make good HUD. The &quot;Core status&quot; part looks not as good as I expected.</p> https://www.lexaloffle.com/bbs/?tid=32747 https://www.lexaloffle.com/bbs/?tid=32747 Mon, 31 Dec 2018 10:31:50 UTC Scripting notes <p>Hey there. I'll be writing down a few things I'm discovering while taking a bite off the brand new Voxatron update. Scripting API was a long-awaited feature and I'm definitely excited to give a new spin to Vox.</p> <h3>Disclaimer</h3> <p>I'm writing this post while playing with the alpha 0.3.5b. Stuff I'll be writing can and may change over versions.</p> <h3>Script organization</h3> <p>As a script is a component like others, you can perfectly use them in an actor as well as an animation or an emitter. <strong>update</strong> and <strong>draw</strong> are called when an actor is updated or drawn.</p> <p>A script has a basic encapsulation system. Local &quot;top&quot;[^1] variables are indeed locals to the script and globals are shared over scripts. Yeah, you read that perfectly. You can perfectly have &quot;library&quot; script pieces that are just there to hold your functions akin to a Pico8 code tab as long as the desired functions or variables are global.</p> <p>Note that if the script has <strong>_draw</strong> and <strong>_update</strong>, they take precedence over Voxatron's routines, even if they're not placed in a room. I'm linking a cart that stores two script pieces, a few circle drawing routines and a script having _update and _draw. Feel free to download it to see how it goes. As you can see, the room is totally blank and isn't actually rendered at all.</p> <p> <table><tr><td> <a href="/bbs/?pid=60452#p"> <img src="/bbs/thumbs/vox_doyumogeka-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=60452#p"> &quot;Library&quot; script test</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=60452#p"> [Click to Play]</a> </td></tr></table> </p> <p>I don't know if there are &quot;rules&quot; for loading or executing or ordering the scripts pieces yet, but it looks quite promising. You can have behavior code for an actor, an advanced particle emitter to add tidbits to a creature or even take over voxatron's rules temporarily to implement some logic over it (for instance a battle engine to intrrupt your RPG players with some slimes? :D )</p> <h3>Colors</h3> <p>Colors are actually spaced over the [0-255] range sparsely. I'm linking a demo so you see them. Press up or down to change the bottom layer to see which colors are transparent. The 0-15 colors are the good old Pico-8 palette where the 16 and 32 color row looks like complementary colors. There are two nice gray gradients at 80-85 and 86-91.</p> <p>The (interesting) transparent colors are at 160-168, 192-200 and 224-255.<br /> <table><tr><td> <a href="/bbs/?pid=60452#p"> <img src="/bbs/thumbs/vox_sinihojoni-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=60452#p"> Color palette demo</a><br><br> by <a href="/bbs/?uid=1281"> Eiyeron</a> <br><br><br> <a href="/bbs/?pid=60452#p"> [Click to Play]</a> </td></tr></table> </p> <h3>Properly making global/local functions</h3> <p>In 0.3.5 there is a scoping issue as seen <a href="https://www.lexaloffle.com/bbs/?tid=32775">there</a> that raises when trying to use a local function through a function set to a variable. </p> <p>For instance trying to make a globally accessible <em>class</em> named <strong>B</strong> where one of the class (or object)' members in a script like this:</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>B = {} local function new() return {draw = B.draw} end function B.new() return new() end function B.draw() print(&quot;Called&quot;,0,0,7) 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>will not properly find the local function <strong>new</strong> for unknown yet reasons. I suggest to create the global variable as-is and wrap the rest of the code in a do ... end block. It'll properly set the upvalues scoping and will fix the issue.</p> <h3>Making libraries</h3> <p>As there are a few quirks around how Voxatron loads code, there might be the need to make a few conventions to make easily shareable code.</p> <ul> <li>As mentioned in the previous point, there is a current scoping issue, so the best route would be wrapping as much code in a do/end scope, if not the whole script object.</li> <li>Currently, when exporting objects or folders, the resulting cart uses as label the BBS label of the currently loaded cartridge (the object seen in the Metadata tab). That could be a fancy way to give an identity to your library</li> <li>An idea for organization is having a README script only to contain your licence. You can do comment blocks by wrapping your comment in <code>--[[ &lt;your code&gt; ]]</code>.</li> <li>You can directly export folders. That can be quite useful to export multiples scripts easily.</li> </ul> <h3>Random API bits</h3> <ul> <li><strong>set_draw_slice</strong> also takes an additional boolean argument to determine if you want to draw the Pico8's slice on a XY plane (flat) or XZ plane (vertically in front of the player). If it's <strong>true</strong>, it'll use XZ and will draw the top 64 rows of Pico8's buffer, else (<strong>false</strong> or <strong>nil</strong>) it'll draw on a layer like before.</li> <li>From what I tested, <strong>stat</strong> seems to work here and there. Looks like the CPU and memory usage functions seem to work. I have yet to test the rest</li> </ul> <h3>Footnotes</h3> <p>[^1]: I can't find a better way or word to explain, but any kind of variable that's not already in a scope like a do/end, a function, a condition, a while loop or a repeat.</p> https://www.lexaloffle.com/bbs/?tid=32744 https://www.lexaloffle.com/bbs/?tid=32744 Mon, 31 Dec 2018 10:10:22 UTC