Quick Tip: Notes in Code

Going along with my last post, just a quick tip: sometimes it makes sense to use comments to show how a loop will progress. For me, at least, this is another way to get a grasp on how values are changing and ensure that calculations account for the situations you may need.

In this case, following the logic flow, I realized that the initial value for v2 was where things were breaking down. I was also able to capture the final segment without using an additional for-loop which makes things a bit cleaner. I’m actually going to evaluate some of my other triangle logic to see if I can do the same thing using the vx -= vertices.Length method to take care of the last parent loop.

Troubleshooting via UI in Unity – Deuta

As a visual learner, I’ve found that sometimes seeing something working is a better debugging tool for me than seeing an array of int values. With the array, I can still usually see where a pattern breaks down or unexpected values might be (at least when the use merits it), but it’s more difficult for me to wrap my brain around what needs to be changed.

I’ve continued work on Deuta, my project for parametric primitives in Unity. One of the things I’ve spent some time in is custom editor/inspector UIs for shape generation. I highlighted the vertex-index (vertidx) in a previous post, but I have a great example of how it helps me.

In the above video, I’m working on a parametric torus option. I have the vertices down how I want them, but as I was writing code for the tris, I clearly missed a step. I looked at the int[] of triangles I got. I could see where there was an issue. But being able to visualize it helped me understand precisely what I needed to change and how. I know how the triangles need to be ordered, but this also allowed me to see at what index it breaks down, if there’s a pattern to it or it’s just a single issue, and to see how numeric patterns played out.

I’m sure I’ll be posting more Deuta stuff over the next several weeks. I’ll likely show off some more of my troubleshooting/visual debugging steps as I work on some more complex shapes.

Unity Custom Attributes and Custom Editors

Shapes Editor 01
Custom editor/inspector view for Shapes.cs

While working on Programmatic Meshes, it became clear that I needed some custom gizmos to help me visualize things as I moved along. It really became a necessity as I was working on sphere generation because I was having some issues where certain sizes and segment counts were creating bad geometry. This was almost certainly due to ordering of the int[] array for triangles associated to the mesh. Since everything is generated by code, that means that once all vertices are created, the code needs to also sort/order those vertices the same every time to ensure that the facet tris are created correctly.

Sphere Vertices Indices
Sphere Vertices Indices

This was my first venture into gizmos aside from some very basic line drawings. I wanted the indices of each Vector3 in the mesh so that I could ensure they were getting properly ordered each time and would meet the requirements for tri calculation. So the above was born – and damn did it ever help me see where things were occasionally not working (sadly, I don’t have a screenshot of the bad sphere, but let’s just say that it was… not an ideal geometric shape).

After getting through that, I wanted to also change the inspector so that I could enable/disable vertex visualization. As shapes become more complex, the numbering is great, but I wanted a better visualization of the vertices in the scene view. As the screenshot above illustrates, unless you rotate the view around a bit, it’s easy to get lost with where vertices actually are in relation to one another.

Sphere Vertices Visualization
Sphere Vertices Visualization

In the above GIF, you can see how movement helps determine what indices you’re viewing, but the ROYGBIV and SIZE options for visualization also help. In the ROYGBIV mode, the closest vertices are red and the furthest are violet, and everything in between follows the ROYGBIV order. With the size option, the closest vertices are the largest and the furthest away are the smallest, and they are scaled to suit in between. In either case, they’ve updated in real time. I’m not yet sure how this performs on very high density meshes, and I’m sure some optimization will be necessary, but it’s good enough for my needs for now.

I wanted the collapsible Viewables area in the inspector for this, as well as for mesh data (Vertices[], Normals[], and Triangles[]). I also wanted to be able to select the Shape (each of which is a class inheriting from Primitive()), and which Generate() method should be used (each shape has different generate methods).

For this to work, I created a few custom classes, which I added to my external DLL:

SelectableList<T> is a custom List<> type collection that has an interactive indexer property called .Selected that references the index of the selected item in the list. This has turned out to be handy for selecting items in lists from dropdowns in the inspector.

MethodCaller<T> is a custom collection that contains a reference to a class (in this case, each shape class gets a method caller), and a SelectableList<MethodInfo> of the generation methods in that class.

And lastly, MethodDictionary<T> is a custom collection class that collects MethodCaller<T> objects. Its constructor takes a filter for classes (to remove the base class and secondary base classes where inheritance takes place on multiple levels), and a filter for methods based on the name of the methods to acquire.

The creation of the MethodDictionary also builds out the dictionary based on the filters provided, so there isn’t a lot of work needed to implement it. This is definitely a plus.

In the Unity code, I also created three custom attributes:

[Segmented] is tagged to generate methods that use the segment count value. This allows that slider to be enabled/disabled on constructor selection.

[DefaultGenerator] is tagged to generate methods that the default Generate() method passes to.

[GeneratorInfo] is tagged to all generate methods and provides inline help text in the inspector, typically what segment count actually accounts for if it’s used, and what the measure/size value indicates (e.g.: circle/diameter, quad/size, hexagon/apothem*2).

Using reflection, I do something like this in the ShapeEditor.cs script:

if (shape.shapeMethods.Callers.Selected. Methods.Selected. GetCustomAttributes().SingleOrDefault(s => s.GetType() == typeof(SegmentedAttribute)) != null)

It’s not terribly pretty, but it’s fairly quick – quick enough for inspector draws – and allows the inspector panel to change on the fly as selections are made.

It’s worth noting, if you haven’t worked with custom attributes before, that the attribute doesn’t need to have fields despite all examples I came across online containing them. Without fields, it’s basically a check to see if it exists or not – a boolean of sorts applied to a reflected method to change how the inspector is drawn. Some examples:

[AttributeUsage(AttributeTargets.Method)]
public class SegmentedAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method)]
public class DefaultGeneratorAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method)]
public class GeneratorInfoAttribute : Attribute
{
    public readonly string info;

    public GeneratorInfoAttribute(string info)
    {
        this.info = info;
    }
}

And usage on a class method:

[Segmented]
[DefaultGenerator]
[GeneratorInfo("Generates a circle based on the 'starburst' pattern.\n\nSize is the diameter of the circle.\n\nSegments is the number of segments _per quadrant_.")]
public Mesh GenerateStarburst() { /* code */ }

I will probably write some additional posts about this, maybe with more code, as this project continues. And I’m sure I’ll have a Part 2 of Programmatic Meshes in the next week or two.

Programmatic Meshes, pt. I

I’m not sure how many parts this will end up being, but I’ve been spending a good amount of time lately on programmatically generating both 2D and 3D meshes. Currently, I’m working on a library to expand the Unity primitives system to create meshes based on parameters. So far, I’ve built Quads (standard/two triangle, starburst array from center), Circles (starburst), Hexagons (starburst, compact), and Triangles (equilateral, right). I’m now working on basic spheres from sets of circles.

Single Circle
Single Circle
Sphere from circles
Sphere from circles

One thing that these shapes do, so long as the shape object is kept, is track vertices across changes. I’d like to do some basic deformation options down the road, but for now this works well because for the sphere, I create just a single circle, copy its vertex[] rotate it and copy over and over until it’s complete.

The above image, “Sphere from circles” is actually just multiple circle objects rotated properly. My current speedbump is sorting the vertices for the sphere itself. The vertex at (0, 0, 0) is removed, and the vertices where x=0 are only parsed from the first circle rotation. All vertices are then ordered descending by y, so from the top down. Now I need to also sort the x/z values in clockwise order so that the vertex[] basically stores the vertices as horizontal slices from top to bottom, then clockwise for each slice (or counter-clockwise). This is necessary so that the triangles can also be generated programmatically without intervention.

My current attempt was something like this:

this.vertices = vertList.OrderByDescending(o => o.y).ThenBy(o => Mathf.Atan2(o.x, o.z)).ToArray();

But that doesn’t properly sort the x/z components. I’m sure there’s an easy formula that I’m missing, so… I’ll have to keep working through it.

Creating Sprites Programmatically in Unity

So, I’ve been working on a game idea (yeah, I know, I haven’t actually completed any games thus far… my bad!), and have created some place-holder graphics for testing a few game mechanics. In other words, the visuals are not a permanent sort of thing. However, one of the mechanics will require some programmatically generated sprites to come into being as directed by a UI window the player will be presented with.

The basic setup is like this: The main game visuals are using Unity’s Tileset feature. The grid has (currently) three overlaid tilemaps: ground, ground shadows, ground clutter; the clutter being grass and flowers and other non-interactable bits for visual effect. Each tilemap moves up one in the z-sort order and all but the ground layer are using alpha transparency.

The programmatic sprites will be one z-sort layer above those (and below the player/NPCs) and is displayed at a target transform called CircleTarget. The initial code looked like this:

if (tex == null)
{
     tex = new Texture2D(256, 256);
     tex.alphaIsTransparency = true;

     Color c = Color.red;
     
     for (int x = 120; x <= 130; x++)
          for (int y = 120; y <= 130; y++)
               tex.SetPixel(x, y, c);

      s = Sprite.Create(tex, new Rect(0, 0, 256, 256), new Vector2(0.5f, 0.5f), 32f);

      CircleTarget.GetComponent<SpriteRenderer>().sprite = s;
}

This was intended just to put a small red square down where the CircleTarget lives, but instead I was just presented with this:

Ah, you need to apply changes – but also need to set things up for transparency. So, let’s try this:

if (tex == null)
{
      tex = new Texture2D(256, 256);
      tex.alphaIsTransparency = true;

      Color c = Color.red;
      Color a = new Color(1f, 1f, 1f, 0f);

      for (int x = 0; x < tex.width; x++)
            for (int y = 0; y < tex.height; y++)
                 tex.SetPixel(x, y, a);

       tex.Apply();

       for (int x = 120; x <= 130; x++)
           for (int y = 120; y <= 130; y++)
               tex.SetPixel(x, y, c);

       tex.Apply();

       s = Sprite.Create(tex, new Rect(0, 0, 256, 256), new Vector2(0.5f, 0.5f), 32f);

       CircleTarget.GetComponent<SpriteRenderer>().sprite = s;
}

Ah, much better, however the red pixels are surrounded by a buffer of whiteish/alphaish pixels. Of course, if you have existing sprites that you’re importing into Unity that use alpha and you want pixels to look precise, we need to change how they’re filtered. For programmatic sprites, you need to do the same thing.

tex = new Texture2D(256, 256);
tex.alphaIsTransparency = true;
tex.filterMode = FilterMode.Point;  // Add this line

...

And now we have a properly transparent background red square placed at our target location.

I’m a big fan of programmatic generation of meshes, sprites, and really everything. It makes the overall footprint of the game smaller and often consumes no more memory or processing power than what you’d have anyway – not always, but often. In this case, the programmatic option is actually significantly better than having a bunch of predesigned objects as sizes can be calculated on the fly and the variations that I plan for won’t require any palette-swapping, or even any palettes at all since it’ll just be stored in code. Generation of pixel art on the fly really opens up how this game mechanic can be used. I’m sure there will be more posts on it down the road – keep an eye out.

Pixel Art Tutorials – Small House

So I’m playing around with pixel art – which was the reason I started messing around with palettes. I am not an artist, but I want to gain some pixel art skills. I figured I’d share my trials and tribulations on this journey because… why not?

I’ll be using some simple tutorials from some great artists, including: Slynyrd (who also has a great blog), Pedro Medeiros, and Rémy Devaux.

I plan to try limiting myself to an eight or fewer color palette (though that may not always be possible). When the tutorial isn’t behind a paywall (is otherwise freely available), I’ll share both the tutorial and my result. Bear with me as the first attempts will likely not be so great.

First tutorial is from Slynyrd’s 3/4 Top Down House.

And my first attempt…

Small House, animated pixel art
Small House, animated pixel art

Not great, but not awful. At least it’s obvious what it’s supposed to be, which is more than I can say for many of my attempts at art.

Palettes

I’ve started working on some color palettes for a few projects. Because we aren’t limited to 8-bit visuals these days, I’ve taken an atypical tack. Rather than having a palette for a specific biome or environment, I’m working on creating a variety of 8-color palettes that can be combined as needed in any various environment. The benefit here is that the total colors in a scene are still being limited, and the palettes can be used to ensure a visual “feel”, but more total colors can be utilized in a pixel art format.

Sulfur Pools
Seafoam
Hot & Cold
Greyscale
Flames
Cool Blue

I have ideas for about a dozen more and plan to utilize each of them in various ways. I also have CSS stylesheets made for them. I’ll upload those at some point and add links for anyone who might be interested.

HyperDisk Kickstarter

For anyone who has backed campaigns on Kickstarter, you probably know that they’re sometimes a crapshoot. Back in 2019, I backed two portable SSD projects: HyperDisk and WarpDrive. Both were expected to deliver in early 2020, but a combination of a suddenly volatile SSD market and the COVID pandemic caused them both to sort of evaporate – vaporware, if you will. Many started hammering both as scams, demanding refunds – a fairly reasonable response given that many campaigns go that route.

WarpDrive may very well have been a scam. The creators haven’t posted an update since January 2020. HyperDisk has had updates and, much to my surprise, I actually received mine today. So, of course, I set to benchmark it against their purported 1000MB/s claims.

HyperDisk CrystalMark
HyperDisk CrystalMark

It does actually meet those speeds using the supplied USB-C to USB-C cable to the Thunderbolt 3 port on my laptop. Internally, the enclosure is a 3.1 Gen 2 interface with an M.2 NVMe SSD. The cost during the campaign was US$139, and for a comparable (what appears to be a 2242 form-factor stick) SSD with an enclosure, it came out to be pretty much a wash in February 2021 prices, though for the time it was a pretty decent deal. I haven’t opened it up to look, but I’m presuming a 2242 based on the size. I’m also not sure the branding on the stick itself.

HyperDisk CrystalInfo
HyperDisk CrystalInfo

The part number, HYPCNV001T doesn’t bring up anything in Google.

We’ll see how it holds up over time, but for now I’m not terribly displeased. I’ve come to expect Kickstarter campaigns to deliver long after their estimates. I’ve backed 128 projects to date, though many have been just a $1 backing as a show of support (if a lot of folk gave even a dollar to many “good” projects, more would end up with the necessary funding – worth thinking on). Of the ones with a deliverable product that I’ve backed at a tier to get said product, ~80% of them have gone beyond their time tables, and of those, half or so by quite a ways… often a year or more.