Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Raenir Salazar
Nov 5, 2010

College Slice

TheLastManStanding posted:

What's the smoothing iteration? The vertexes that you feed into the triangle library shouldn't change?

My understanding was lloyld's relaxation shifts the sites around sort of like a k-means distribution; so I'm a little confused why checking each pixel for distance works otherwise. If I do 0 iterations of smoothing vs 10 iterations either way I am able to accurately display the result so if its merely moving the "sub" vertices of the voronoi cells then I'm confused how my current method manages to work in the first place.

Adbot
ADBOT LOVES YOU

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

FuzzySlippers posted:

I'm not sure why you need them to be accessible from the inspector. If they need configuration data I wouldn't make it part of the System but a separate scriptable object config. That can be a lazy loaded Singleton so you don't have to link it anywhere.

For debug I have a generic scriptable Singleton that anything can pipe data into and usually my Systems do so based on a debug level.

For which systems should run, priority,etc I usually do that with attributes on the Systems class.

Well, need is a strong term here. I want to be able to confirm subsystem state particularly when debugging like, say, the day/night state is night but none of the stuff to do that actually happened.

A reasonable compromise looks like to use scriptable objects for that state so I don't have to fuss over MonoBehaviour timings but I still get Unity editor exposure.

Raenir Salazar
Nov 5, 2010

College Slice
Currently still working on the scan line thing with my current work before testing out the 2D distance array solution and something I must've not done something right.

My interpretation of the JS code provided above, and it seems to get stuck somewhere.

code:
    void ConvexFillScanline(int x, int y, bool goUp, bool goDown)
    {
        int minEcks = x;
        int maxEcks = x;

        while (minEcks > 0 && ShouldBeThisColour(minEcks - 1, y))
        {
            minEcks--;
        }

        while (maxEcks < Width - 1 && ShouldBeThisColour(maxEcks + 1, y))
        {
            maxEcks++;
        }

        int firstPixel = y * Width + minEcks;
        int lastPixel = y * Width + maxEcks;

        for (int pix = firstPixel; pix <= lastPixel; pix++)
        {
            Pixels[pix] = thisColour;
        }

        if (goUp && y > 0)
        {
            int nextY = y - 1;
            for (x = minEcks; x <= maxEcks; x++)
            {
                if (ShouldBeThisColour(x, nextY))
                {
                    ConvexFillScanline(x, nextY, true, false);
                    // once you've found a point 'up' you can stop looking because it'll all be 
                    // filled by the scanline,
                    // because the shape is convex.
                    break;
                }
            }
        }

        if (goDown && y < Height - 1)
        {
            int NextY = y + 1;
            for (x = minEcks; x <= maxEcks; x++)
            {
                if (ShouldBeThisColour(x, NextY))
                {
                    ConvexFillScanline(x, NextY, false, true);
                }
            }
        }

    }
Distance checking moved to ShouldBeThisColour:

code:
    private bool ShouldBeThisColour(int x, int y)
    {
        Vertex centerVert = verts[currentVSiteID];
        // see if current tile is closer to any other
        // of the adjacent sites, if it is than we 
        // break/continue
        float dstToCenter =
            Vector2.Distance(new Vector2(x, y),
                             new Vector2((float)centerVert.x, (float)centerVert.y));

        foreach (int sideID in adjacentSiteIDs)
        {
            Vertex VertToCheck = verts[sideID];

            float dstToAdjacent =
                Vector2.Distance(new Vector2(x, y),
                                 new Vector2((float)VertToCheck.x, (float)VertToCheck.y));

            if (dstToAdjacent < dstToCenter)
            {
                return false;
            }
        }

        return true;
    }
I had also refactored my Voronoi code into a class so my Voronoi generator has its own context for generating images.

Currently in the process of trying to see what I did wrong.

E: I have found my oops. Now I am solving the next inevitable problem that has reared its head (everything is blank) but never fear.

Raenir Salazar fucked around with this message at 08:21 on Sep 29, 2020

Sab669
Sep 24, 2009

I have sort of a weird question, but basically do you guys have any resources for project management / how to actually plan and build a game?

I'm a programmer for my day job for 8 years + education, I know how to write code and I've dicked around with Unity on-and-off over the last ~5 years but I've never even come close to really making something. I can happily follow along with any of the official tutorials, or YouTube series, but once those end I just feel like "OK but now what". I feel completely lost on priorities or how to "correctly" do anything.

Every year I get more and more burnt out being a 'business' programmer, not caring about any of my projects and just tired of all the things that come with the job. It seems like it would be nice to really have a project I actually enjoy working on, something I'm invested in... but I have no idea where to begin :(

12 rats tied together
Sep 7, 2006

I've done some googling around this but I'm interested in any other opinions here: I have basically a 2d grid that makes up a shared simulation, planned for up to 300ish unique actors per environment. Actors will be triggering pathfinding to get the path from their current location to their desired location and doing so fairly often, moving is basically the default state for every actor.

The 2d grid will be up to like 1000 by 1000, just to give an order of magnitude (its not infinite), but each actor is only ever concerned with everything in about a 20 cell radius from itself.

I do have something that works just for pathfinding in general but it's basically a blocking loop and after a (frankly insane) number of actors the simulation loops start being delayed long enough for the network loops to be impacted. I'll never need that many actors but right now the only simulation systems in place that have a significant effect on the simulation loops are the movement ones, so I can see this problem getting exponentially worse as more systems are implemented.

For an immediate fix I'm going to steal some concepts from jump-point search, but anyone have any thoughts on how to manage 300ish actors all triggering pathfinding basically all the time? I'm considering just storing a path from every cell to every other cell within each cell's allowable movement radius which seems like a pretty intuitive memory vs compute tradeoff.

dreamless
Dec 18, 2013



Sab669 posted:

I'm a programmer for my day job for 8 years + education, I know how to write code and I've dicked around with Unity on-and-off over the last ~5 years but I've never even come close to really making something. I can happily follow along with any of the official tutorials, or YouTube series, but once those end I just feel like "OK but now what". I feel completely lost on priorities or how to "correctly" do anything.

Having gone from a college student to a professional, and then a professional looking enviously at our rivals to reading our rivals' code: there isn't anything magic that they're doing that you're not. Seriously, there's a lot of ugly ugly garbage under the hood and it's invisible to the players. If you've got a game-shaped artifact at the end of the process: congratulations! It's a game! You've done it!

In general though you've got an idea for what kind of game you want to make, I'm assuming? One technique is to build the smallest possible version and get it playable, then expand it from there. This lets you test whether what you thought was fun actually works in practice and also motivates you to keep going.

You don't need a 'press start' -> game -> 'you win!'/'you lose!' loop until close to the end, and it's a pain in the rear end, but I do recommend it if you want your game to feel like a real game sooner.

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
You make games by getting your hands dirty and making games. There's no secret sauce or technique. I'm applying the same processes I learned in industry software to gamedev software (aside from testing, I guess) and they're working fine. It is helpful however to recognize that much of game code is "business logic" and ultimately kind of disposable.

If you want to finish a game, and especially if you want to sell a game, then you need to start doing things like figuring out what your big risks are and making sure to address those first and foremost. There's a big discussion on that in the ask a gamedev thread.

12 rats tied together posted:

I've done some googling around this but I'm interested in any other opinions here: I have basically a 2d grid that makes up a shared simulation, planned for up to 300ish unique actors per environment. Actors will be triggering pathfinding to get the path from their current location to their desired location and doing so fairly often, moving is basically the default state for every actor.

The 2d grid will be up to like 1000 by 1000, just to give an order of magnitude (its not infinite), but each actor is only ever concerned with everything in about a 20 cell radius from itself.

I do have something that works just for pathfinding in general but it's basically a blocking loop and after a (frankly insane) number of actors the simulation loops start being delayed long enough for the network loops to be impacted. I'll never need that many actors but right now the only simulation systems in place that have a significant effect on the simulation loops are the movement ones, so I can see this problem getting exponentially worse as more systems are implemented.

For an immediate fix I'm going to steal some concepts from jump-point search, but anyone have any thoughts on how to manage 300ish actors all triggering pathfinding basically all the time? I'm considering just storing a path from every cell to every other cell within each cell's allowable movement radius which seems like a pretty intuitive memory vs compute tradeoff.

The more information you can store in the environment the better you can make your pathfinding perform. If destinations rarely change, then you can build heatmaps that mark each tile with "I am X distance from this destination", and then to pathfind to a given destination each actor just needs to move to the adjacent tile with the lowest distance. If destinations never change then you can start adding things like navmeshes so that actors just have to path to the closest mesh edge, then follow the mesh to the closest point to their destination.

Conversely, the more the environment changes and the faster you want actors to react to changes in their environment, the less you can take for granted and the more CPU-intensive pathfinding becomes. You see a lot of games make visible tradeoffs around pathfinding; it's not an easy problem to solve.

Raenir Salazar
Nov 5, 2010

College Slice

Raenir Salazar posted:

For a 512 by 512 map this is ~320ms for floodfill was ~685ms before. (225 sites)
For a 1024 by 1024 map this is ~1244ms for floodfill was ~2682ms before. (225 sites)

For a 512 by 512 map this is ~382ms for floodfill was ~1457ms before. (1100 sites)
For a 1024 by 1024 map this is ~1332ms for floodfill was ~3552ms before. (1100 sites)

New bench marks using flood fill scan line (by checking adjacent sites):

For a 512 by 512 map this is ~137ms to 141ms for scan line. (225 sites)
For a 1024 by 1024 map this is ~520ms for scan line. (225 sites)

For a 512 by 512 map this is ~208ms for scan line. (1100 sites)
For a 1024 by 1024 map this is ~601ms for scan line. (1100 sites)

Pretty impressive! Will try out the 2D distance array next.

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

Sab669 posted:

I have sort of a weird question, but basically do you guys have any resources for project management / how to actually plan and build a game?

I'm a programmer for my day job for 8 years + education, I know how to write code and I've dicked around with Unity on-and-off over the last ~5 years but I've never even come close to really making something. I can happily follow along with any of the official tutorials, or YouTube series, but once those end I just feel like "OK but now what". I feel completely lost on priorities or how to "correctly" do anything.

Every year I get more and more burnt out being a 'business' programmer, not caring about any of my projects and just tired of all the things that come with the job. It seems like it would be nice to really have a project I actually enjoy working on, something I'm invested in... but I have no idea where to begin :(

Start small, games are a ton of work and everything is more effort and pain than it seems like it'll be. Take some simple game that you like, re-create it as best you can, and then try to put a spin on it.

Like, make your own flavor of Mario, or whatever you like. Trying to make that clone, then playing with it and iterating, can teach you a lot. You can use that existing game as a template to help if you're kinda lost on what to do next.

FuzzySlippers
Feb 6, 2009

Rocko Bonaparte posted:

Well, need is a strong term here. I want to be able to confirm subsystem state particularly when debugging like, say, the day/night state is night but none of the stuff to do that actually happened.

A reasonable compromise looks like to use scriptable objects for that state so I don't have to fuss over MonoBehaviour timings but I still get Unity editor exposure.

My general mantra is that ScriptableObjects are good but MonoBehaviours are bad. Doesn't mean Monos don't work their way into places, but I try to minimize their importance by putting any none scene data (like you still have to use a mono to stick a child gameobject in a field) on a Scriptable.


Sab669 posted:

I'm a programmer for my day job for 8 years + education, I know how to write code and I've dicked around with Unity on-and-off over the last ~5 years but I've never even come close to really making something. I can happily follow along with any of the official tutorials, or YouTube series, but once those end I just feel like "OK but now what". I feel completely lost on priorities or how to "correctly" do anything.

Do some game jams

Raenir Salazar
Nov 5, 2010

College Slice

Raenir Salazar posted:

New bench marks using flood fill scan line (by checking adjacent sites):

For a 512 by 512 map this is ~137ms to 141ms for scan line. (225 sites)
For a 1024 by 1024 map this is ~520ms for scan line. (225 sites)

For a 512 by 512 map this is ~208ms for scan line. (1100 sites)
For a 1024 by 1024 map this is ~601ms for scan line. (1100 sites)

Pretty impressive! Will try out the 2D distance array next.

Alright, took a couple of tries.

So using a distance lookup table ran into a snag of not really being all that faster because I assume for each vertex it was computing it would computer something like 90% of the previously computed space. So this would presumably quickly converge since it wasn't much worse than the above at first but my assumption it does something like; first face do the whole array (every pixel), second vertex do every pixel/cell in the array until it equalizes where it meets pixels belonging to the first vertex; and so on.

As a result to constrain this I try to approximate a circle large enough for the largest voronoi cell and grabbed the radius and use that radius to determine a maximum distance I should bother/consider checking with the current vertex.

My extremely lazy brute force way to determine this looks like this:

code:
        targetRadius = (Width * Height) / (VCellCount / 2);
        targetRadius = Mathf.Sqrt(targetRadius) + 1;
I took a brief look at how to pack N circles into a Square but that looked a little too difficult so I guestimated something else that seems to work but isn't the most optimal; a more optimal solution might shave off a few more ms.

With this check in place I now get very nice fast results:

For a 512 by 512 map this is ~37ms for scan line. (225 sites)
For a 1024 by 1024 map this is ~203ms for scan line. (225 sites)

For a 512 by 512 map this is ~61ms for scan line. (1100 sites)
For a 1024 by 1024 map this is ~225ms for scan line. (1100 sites)

Basically a 1/3 reduction from above, which was itself also a 1/3 or so reduction from the previous benchmark, this seems good enough for me, now onto the thing.

BoneMonkey
Jul 25, 2008

I am happy for you.

Everyone elses advice is on point, the only thing I have to add is to try and keep your code replaceable. Im a newish programmer, But I do try and think as I'm writing in a new component or feature "how easy is this gonna be to tear out in 2 months as I'm gonna want to do."

I normally rewrite thing 2 or more times. But it seems to have kept my game manageable.

TomR
Apr 1, 2003
I both own and operate a pirate ship.

Internet Janitor posted:

September is upon us, and October is right around the corner, which means it's time to get hyped for Octojam 7:


It's the one and only annual CHIP-8-themed game jam! Scratch that low-level programming itch, and see how much gameplay you can cram into a few kilobytes:

http://octojam.com

This year I wrote a pair of example games that participants can use as a starting point if they wish:

Into The GarlicScape


Super NeatBoy


(ok, that's the end of my shameless plug.)

I made a game for Octojam 7. Check it out https://atomr.itch.io/akir8

TIP
Mar 21, 2006

Your move, creep.



Anyone have any thoughts on how to find smaller streamers/influencers/reviewers?

It's hard to get the time of day from anyone who's huge, but it's hard to find the people who are small enough to talk to me but big enough to actually be any help. All the search functions on sites just seem to funnel me towards the most popular 1% of people.

I feel like people with something like 5,000 to 100,000 subscribers seem like the right level where it could be mutually beneficial.

My game is a freestyle rapping game, so I'm also looking for small on the rise rappers who might enjoy trying it out and streaming them playing it.

Also, if you know of anyone who fits the bill, just suggestions could be helpful too.

Here's the game I'm promoting, Rhyme Storm:
https://store.steampowered.com/app/1250350/Rhyme_Storm/

We're announcing our release date tomorrow (and it's coming out very soon afterwards), and I'm getting nervous about getting enough coverage or attention. We've reached out to about a hundred people so far.

Raenir Salazar
Nov 5, 2010

College Slice
Eye'm a genius!



(Improved colour ranges)

I was having not very good results trying to "pack" in the voronoi tiles to be denser on land / sparser on water; the results while vaguely looking in the right direction weren't giving me enough control and just wasn't really deterministic enough for me to know what inputs gave me what outputs.

After sitting on it for a few days and thinking I have found a solution.

Since Paradox sea tiles don't really relate to the land tiles other than just being adjacent I decided to take the lessons learned here and tried a new tact.

I generated a distributed list of land sites, and a distributed list of sea sites (but a lot less).

With the list of land tile sites, I generated the voronoi as normal. From there I randomly assigned a tile to be water (60% chance).

Water tiles are set to be all white.

Land tiles are set to any random rgb colour except the blue channel is always 0 (as you can see from the results).

With the resulting colours array I then take the initial water sites list and then prune it for any sites that exist over a land pixel.

With the resulting pruned water sites list I make a new voronoi diagram and then I compare the two.

If the colour of a pixel in the land diagram is white, I set it to the corresponding pixel from the sea diagram.

There's a slight problem in the cropping of it, where a relatively small/tiny sliver of a sea tile may protrude a bit.

I think the simplest solution is some sort of flood fill for such edge cases and then simply append it to the closest land or sea tile.

It's not perfect but my next step is to split the water sites into two diagrams, one for "seas" i.e water next to land; and then "oceans" water next to seas; this should result in easier to
fix examples of "slivers" since the water tiles affected are smaller.



Tip posted:

Anyone have any thoughts on how to find smaller streamers/influencers/reviewers?

It's hard to get the time of day from anyone who's huge, but it's hard to find the people who are small enough to talk to me but big enough to actually be any help. All the search functions on sites just seem to funnel me towards the most popular 1% of people.

I feel like people with something like 5,000 to 100,000 subscribers seem like the right level where it could be mutually beneficial.

My game is a freestyle rapping game, so I'm also looking for small on the rise rappers who might enjoy trying it out and streaming them playing it.

Also, if you know of anyone who fits the bill, just suggestions could be helpful too.

Here's the game I'm promoting, Rhyme Storm:
https://store.steampowered.com/app/1250350/Rhyme_Storm/

We're announcing our release date tomorrow (and it's coming out very soon afterwards), and I'm getting nervous about getting enough coverage or attention. We've reached out to about a hundred people so far.

You should try contacting some of the English language VTubers such as the ones who work under HoloLive or IronMouse etc. If you go via their business inquiry contact email (which I'm sure is a thing) I think maybe its possible they're willing to try it out especially if its music/singing related?

e: Mo' Noi' Time

Nailed it.

Height map:



Tile map:



So as it turns out I was using some methods wrong in the library. The "vertice" list in the Voronoi object as it turns out, quite reasonably actually points to the vertices making up the surrounding edges of the voronoi cell, and *not* what I thought was the vertices of the delaney mesh.

As I was getting weird results like this originally



I figured out how to get the base site id for each face and fixed it.

Step 2 now is to try to create sea tiles to separate the land from the ocean although the current results.

Raenir Salazar fucked around with this message at 06:45 on Oct 6, 2020

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
I've consolidated a lot of my more decoupled, global logic into subsystems. I discovered even more ticking time bombs all related to starting and stopping the main menu. That has to do with pausing/unpausing and also disabling/enabling the HUD. I also cache a screenshot right before opening the menu so I can include it with any new save that might be about to be created. So I just had a new bug show up where the cached screen shot got purged when the save menu screen was opened. This is because the actual main menu itself is disabled when showing the save GUI. This fires an event claiming the main menu was closed (which is both kind of true and false). Something listened to that and decided to try to turn on the HUD, which triggered another event that eventually signaled to purge the screen shot. Solution? Main menu management also should be a subsystem. Everything becomes a subsystem! Everything!

TIP
Mar 21, 2006

Your move, creep.



Raenir Salazar posted:

You should try contacting some of the English language VTubers such as the ones who work under HoloLive or IronMouse etc. If you go via their business inquiry contact email (which I'm sure is a thing) I think maybe its possible they're willing to try it out especially if its music/singing related?

Thanks, I've never even heard of VTubers before, I'll have to check that out.

Well, here's my launch trailer! We're going on sale this Monday, October 12.

https://www.youtube.com/watch?v=dRUwAYpkef0

https://store.steampowered.com/app/1250350/Rhyme_Storm/

Oh, and I did manage to come up with a way to look for smaller but active people on Youtube. Basically search for videos of whatever type and then filter them to only show videos uploaded in the last month, then sort them by view count and then scroll down to the lower view counts.

TIP fucked around with this message at 21:57 on Oct 6, 2020

Raenir Salazar
Nov 5, 2010

College Slice

Tip posted:

Thanks, I've never even heard of VTubers before, I'll have to check that out.

Well, here's my launch trailer! We're going on sale this Monday, October 12.

https://www.youtube.com/watch?v=dRUwAYpkef0

https://store.steampowered.com/app/1250350/Rhyme_Storm/

Oh, and I did manage to come up with a way to look for smaller but active people on Youtube. Basically search for videos of whatever type and then filter them to only show videos uploaded in the last month, then sort them by view count and then scroll down to the lower view counts.

Also I think Achievement Hunter might be open to trying it out, since Jeremy Dooley (one of the main cast) is known for writing songs, I think if you give them free keys they'd be happy to try it out for you as a Let's Play.

ALSO, after clicking on your trailer, have you considered making a fork of it to sell/advertise as a "songwriter helper" for game creators? I'm tempted to get it now actually to use it to try to write Disney like insert/rock opera songs for my own RPG project.

xzzy
Mar 5, 2009

Being a complete idiot in the ways of render pipelines: what is the performance considerations of having a material in unity with the standard textures (diffuse, normal, etc), duplicating it, and applying a tint with the unity color picker? Does that result in two copies of my diffuse/normal maps ending up on the video card? Does it depend on the material type (in this case, it's HDRP/lit)? Or does Unity magically optimize it and do the tint on the fly?

If this One Weird Trick worked well I assume I'd be able to find google results on it, but either I'm using the wrong keywords or it's a fool's errand.


I'm curious about the answer before I run off with the plan of generating a dozen material clones with different tints to add some variety to a scene.

dreamless
Dec 18, 2013



xzzy posted:

Being a complete idiot in the ways of render pipelines: what is the performance considerations of having a material in unity with the standard textures (diffuse, normal, etc), duplicating it, and applying a tint with the unity color picker? Does that result in two copies of my diffuse/normal maps ending up on the video card? Does it depend on the material type (in this case, it's HDRP/lit)? Or does Unity magically optimize it and do the tint on the fly?

This isn't my specialty, but it doesn't make a new texture; if you look in the shader code it's essentially doing "pixel color = texture[u,v] * tintcolor" as it draws each pixel. So each material is a little bit of extra storage, but not nearly as much as a full texture. If you're changing the color at runtime you might want to look into material property blocks so you don't have to keep making copies of the material in memory.

Raenir Salazar
Nov 5, 2010

College Slice
Alright, I got a bit of a pickle.

I'd like to create a colours array of unique colours.

Googling suggests the following function to convert an int to a colour.

code:
        int red = ((value >> 0) & 255);
        int green = ((value >> 8) & 255);
        int blue = ((value >> 16) & 255);

        return new Color((float)red / 255,
                        (float)green / 255,
                        (float)blue / 255, 1);
However I have 2 constraints:

1. I'd like the colours to exist on an even spread, so if I only have 100 colours they aren't all shades of red, but exist across the spectrum of red to blue.
2. I'd like to constrain my colours according to a max and min, i.e if I want blue to have a min/max of 0 (i.e no blue channel), so I only have colours composed or red/green, or
otherwise set a lower/upper bound on each channel to avoid too dark or too bright colours.

I figured something like this:

code:
    Color GetNextRGBColour(int index)
    {
        int value = index * Mathf.RoundToInt(maxColours / numColours) - 1;
        int minR = (int)minColourRange.x;
        int minG = (int)minColourRange.y;
        int minB = (int)minColourRange.z;

        int maxR = (int)maxColourRange.x;
        int maxG = (int)maxColourRange.y;
        int maxB = (int)maxColourRange.z;

        int red = ((value >> 0) & maxR) + minR;
        int green = ((value >> 8) & maxG) + minG;
        int blue = ((value >> 16) & maxB) + minB;

        return new Color((float)red / 255,
                        (float)green / 255,
                        (float)blue / 255, 1);
    }
However this doesn't seem to be working as I hoped it would. While I get a spread I also get collisions, up to several collisions where colours repeat themselves.

maxColours being set in an Init function where I take the max - min of each channel and then multiply them together (with sanity checks so the final result isn't 0 if one of the channels is also 0), so for example 255 * 255 * 255 which works find with max/min or 255,0; 255,0; 255,0 for each channel.

But this seems to result in collisions so I'm not really sure how to proceed from here.

KillHour
Oct 28, 2007


Depending on what libraries you have available, I would do it in HSV.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Raenir Salazar posted:

code:
        int value = index * Mathf.RoundToInt(maxColours / numColours) - 1;
You said maxColours is 255*255*255 but you want 256*256*256. Probably not the core problem you have, but, it's one issue.

Have you considered just returning an array of colours rather than doing a per-index generator? 200 colours is a very small amount of memory, and doing it that way will make it much easier to make your function flexible, like you can just populate the array by nesting three loops, one iterating over the set of possible values for red, one for the set of possible values for green, and one for the set of possible values for blue. (You can do the same thing with an index number but it's just much much simpler with nested loops and returning an array of colours.)

Raenir Salazar
Nov 5, 2010

College Slice

KillHour posted:

Depending on what libraries you have available, I would do it in HSV.

Hrm, there doesn't appear to be tutorials for how to convert a given index to a given HSV value like there is for int to RGB. Also it's generally more desirable for me to be able to say "no blue for land tiles" and "no red for sea tiles" or some other valid range, while HSV seems to complicate that quite a bit.

roomforthetuna posted:

You said maxColours is 255*255*255 but you want 256*256*256. Probably not the core problem you have, but, it's one issue.

Have you considered just returning an array of colours rather than doing a per-index generator? 200 colours is a very small amount of memory, and doing it that way will make it much easier to make your function flexible, like you can just populate the array by nesting three loops, one iterating over the set of possible values for red, one for the set of possible values for green, and one for the set of possible values for blue. (You can do the same thing with an index number but it's just much much simpler with nested loops and returning an array of colours.)

I am doing this to generate an array. I want a spread such that the colours are evenly spread apart regardless of the number of colours. Such that if the first colour is 0,0,0 the last is always 255, 255, 255 (or close enough); regardless if I am picking 10, 100 or 1000 colours for my cells.

Basic usage here:
code:
    private void SetUniqueVoronoiColours(int totalPoints)
    {
        for (int i = 0; i < totalPoints; i++)
        {
            // get a colour
            Color m_colour = GetColour(i);

            VCellColours[i] = m_colour;

        }
    }
e: Basically if I was to pick 200 colours I don't want them to be all varying shades of red.

Raenir Salazar fucked around with this message at 03:39 on Oct 10, 2020

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Raenir Salazar posted:

I am doing this to generate an array. I want a spread such that the colours are evenly spread apart regardless of the number of colours. Such that if the first colour is 0,0,0 the last is always 255, 255, 255 (or close enough); regardless if I am picking 10, 100 or 1000 colours for my cells.
That's not a very good model though, if you're iterating through them with a single index. If your number of colours is any multiple of 256, for example, you won't get a variety of blue shades.

Here's an approximation of a decent spread that will always give you a pretty good distribution, but won't necessarily make it to white.
code:
int numColours = (this is your input value);
int numShades = (int)(power(numColours, 1/3)+1);  // Cube root + 1 means numShades*numShades*numShades is more than enough to fill your array.
Color getColor(int index) {
  float red = (index % numShades) / (float)(numShades - 1);
  float green = ((int)(index / numShades) % numShades) / (float)(numShades - 1);
  float blue = ((int)(index / numShades / numShades) % numShades) / (float)(numShades - 1);
  return new Color(red, green, blue);
}

roomforthetuna fucked around with this message at 03:57 on Oct 10, 2020

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
And to clarify why I was saying nested looping is simpler, it means you can drop all the awkward modulus math, something like...

code:
int numShades = (int)(power(numColors, 1/3) + 1);
Color[] colors = Colors[numColors];
int i = 0;
for (int blue = 0; blue < numShades; blue++) {
  for (int red = 0; red < numShades; red++) {
    for (int green = 0; green < numShades; green++) {
      colors[i] = new Color(red/(numShades-1),green/(numShades-1),blue/(numShades-1));
      i++;
      if (i == numColors) return colors;
    }
  }
}

Raenir Salazar
Nov 5, 2010

College Slice

roomforthetuna posted:

That's not a very good model though, if you're iterating through them with a single index. If your number of colours is any multiple of 256, for example, you won't get a variety of blue shades.

Here's an approximation of a decent spread that will always give you a pretty good distribution, but won't necessarily make it to white.
code:
int numColours = (this is your input value);
int numShades = power(numColours, 1/3)+1;  // Cube root + 1 means numShades*numShades*numShades is more than enough to fill your array.
Color getColor(int index) {
  float red = (index % numShades) / (float)(numShades - 1);
  float green = ((int)(index / numShades) % numShades) / (float)(numShades - 1);
  float blue = ((int)(index / numShades / numShades) % numShades) / (float)(numShades - 1);
  return new Color(red, green, blue);
}

Thanks! Yeah it was just an example. As typically I would want to constrain it so that my colours are neither too bright nor too dark, white is reserved to mark tiles as sea tiles and ideally I'd prefer it that the colours are well short of being black or too dark.

I'm giving this a go, can I change numShades so I can set individual channels? I have an interest in being able to nullify the blue channel for land tiles and the red channel for sea tiles, etc?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Raenir Salazar posted:

I'm giving this a go, can I change numShades so I can set individual channels? I have an interest in being able to nullify the blue channel for land tiles and the red channel for sea tiles, etc?
Yeah, you just need to pick numbers such that numShadesRed * numShadesBlue * numShadesGreen >= numColours.
This variant makes the simplicity of the looped version significantly more desirable.

Raenir Salazar
Nov 5, 2010

College Slice

roomforthetuna posted:

Yeah, you just need to pick numbers such that numShadesRed * numShadesBlue * numShadesGreen >= numColours.
This variant makes the simplicity of the looped version significantly more desirable.

Hrm, I have encountered some issues.

Let's suppose I have two Vector3's; minColourRange and maxColourRange as implied above.

How do I set that loop in accordance to it?

If blue's max is set to 0 than the entire nested loop doesn't iterate at all.

If I still iterate by numShades for each loop than that's a lot of calculations that aren't doing anything.

I can't have division by 0 for the computations in the inner loop.

Are the loops meant to be <=?

Also isn't the 1/3 is there's like 255^3; what happens if this isn't certain? For example if the number of blue shades is 0 then wouldn't this be 255^(1/2)?

TheLastManStanding
Jan 14, 2008
Mash Buttons!

Raenir Salazar posted:

code:
    Color GetNextRGBColour(int index)
    {
        int value = index * Mathf.RoundToInt(maxColours / numColours) - 1;
        int minR = (int)minColourRange.x;
        int minG = (int)minColourRange.y;
        int minB = (int)minColourRange.z;

        int maxR = (int)maxColourRange.x;
        int maxG = (int)maxColourRange.y;
        int maxB = (int)maxColourRange.z;

        int red = ((value >> 0) & maxR) + minR;
        int green = ((value >> 8) & maxG) + minG;
        int blue = ((value >> 16) & maxB) + minB;

        return new Color((float)red / 255,
                        (float)green / 255,
                        (float)blue / 255, 1);
    }
I don't think this does what you think it does.
Bitwise AND doesn't clamp a max value; it guarantees the result will be smaller than either value, but it wont return the max (for example: 23 AND 45 is 5.)
Adding your min to that result could produce a value that is larger than your max (and it could overflow).
Why are you generating an int and then splitting it with bit shifting rather than just generating the rgb values.

Raenir Salazar posted:

1. I'd like the colours to exist on an even spread, so if I only have 100 colours they aren't all shades of red, but exist across the spectrum of red to blue.
2. I'd like to constrain my colours according to a max and min, i.e if I want blue to have a min/max of 0 (i.e no blue channel), so I only have colours composed or red/green, or
otherwise set a lower/upper bound on each channel to avoid too dark or too bright colours.

Raenir Salazar posted:

As typically I would want to constrain it so that my colours are neither too bright nor too dark, white is reserved to mark tiles as sea tiles and ideally I'd prefer it that the colours are well short of being black or too dark.
Like Killhour suggested, you should be doing this in HSV. There's a reason why color pickers are almost always HSV, colors in RGB are a nightmare. HSV would let you keep the saturation and brightness in the range you want, while letting you clamp the color to whatever range of colors you need. In RGB it's hard to limit youself to just red as it means that green and blue have to change together to avoid color shifting. That gets even harder if you want something like orange, which has a ridiculous rgb value. You also can't just cut out a channel; removing the blue channel would not only remove purples and cyan, but also bright reds/greens and whites.

Raenir Salazar
Nov 5, 2010

College Slice
Am I misunderstanding something or doesn't HSV have it's own headaches?

Looking at an online colour picker for HSV, red seems to exist at both 0 and 360 (another has it at 400?), so its a little fuzzy to me how best to go about clamping it, especially if a colour I want to eliminate happens to be somewhere in the middle?

Maybe modulo to "start" the hue at -100 to include the purple bit and then "stops" at teal or something?

e: Also the other problem with HSV is, is well, how do I vary the Saturation and brightness? I probably want to be able to generate around 5,000 unique colours I don't think hue alone will do.

e: This stackoverflow article suggests the solution is non trivial: https://stackoverflow.com/questions/470690/how-to-automatically-generate-n-distinct-colors

e2: On second thought the visual distinctiveness while nice to have is probably not necessary. I'll try with HSV and see what it gives me.

Raenir Salazar fucked around with this message at 05:16 on Oct 10, 2020

KillHour
Oct 28, 2007


I haven't tested this, so it will probably throw errors. I also took some liberties with what libraries you have available. You may need to handle HSV colors manually. Some HSV implementations allow you to set a hue greater than 360, which would allow you to go from, say 300 degrees (purple) to 400 degrees (orange). YMMV.

code:
(int min, int max) hueRange, satRange, valRange;
hueRange = (1, 360);
satRange = (0, 255);
valRange = (0, 255);
// This will generate 1000 colors (10*10*10).  To set (approximate) number of colors directly, use cubic root of n for each.
int hueCount = 10; // Number of hues to generate. Must be greater than 1 to avoid a div/0 error.
int satCount = 10; // Number of saturation bands to generate.  Must be greater than 1 to avoid a div/0 error.
int valCount = 10; // Number of value bands to generate.  Must be greater than 1 to avoid a div/0 error.
// I recommend introducing some randomness in the generation so you don't end up with a TOO obviously generated result
float hueJitter = 0.05f;
float satJitter = 0.05f;
float valJitter = 0.05f;
var colors = new List<ColorHSV>();

for (var i = 0; i < hueCount; i++) {
    for (var j = 0; j < satCount; j++) {
        for (var k = 0; k < valCount; k++) {
            var hue = Math.Lerp(hueRange.min, hueRange.max, ((float)i / (hueCount - 1)) + Random.Range(-hueJitter, hueJitter));
            var sat = Math.Lerp(satRange.min, satRange.max, ((float)j / (satCount - 1)) + Random.Range(-satJitter, satJitter));
            var val = Math.Lerp(valRange.min, valRange.max, ((float)k / (valCount - 1)) + Random.Range(-valJitter, valJitter)); //This gives a fully linear distribution, however people don't see brightness linearly.  Recommend using gamma scaling instead.  This is left as an exercise to the reader :)
            colors.add(new ColorHSV(hue, sat, val));
        }
    }
}

KillHour fucked around with this message at 05:25 on Oct 10, 2020

TheLastManStanding
Jan 14, 2008
Mash Buttons!
Use Tuna's loop, but use HSV instead of RGB. The max value of H is whatever, since you'll have to map it back to RGB. To clamp the color just start somewhere, then use mod to roll over.

e: The solution is non-trivial if you take into account color perception; color theory is a whole branch of study unto itself. Outputting a bunch of moderately spaced out colors is easy.

KillHour
Oct 28, 2007


Raenir Salazar posted:

e: Also the other problem with HSV is, is well, how do I vary the Saturation and brightness? I probably want to be able to generate around 5,000 unique colours I don't think hue alone will do.

I'm just going to point out that the H and V in HSV stand for "Saturation" and "Value" respectively.

Raenir Salazar
Nov 5, 2010

College Slice

KillHour posted:

I'm just going to point out that the H and V in HSV stand for "Saturation" and "Value" respectively.

The problem wasn't how to technically adjust those, but how to adjust them in such a way to get desirable results.

Anyways, here's my initial naive attempt:

code:
    private Color[] GetUniqueColours(int totalPoints)
    {
        Color[] colors = new Color[totalPoints];
        float increment = 360.0f / totalPoints;

        for (int i = 0; i < totalPoints; i++)
        {
            float h = (i * increment) / 360;
            float s = 1;
            float v = 1;

            Color fromHSV = Color.HSVToRGB(h, s, v);
            UnityEngine.Debug.Log("HSV: " + h + "," + s + "," + v);
            UnityEngine.Debug.Log("RGB: " + fromHSV.r + "," + fromHSV.g + "," + fromHSV.b);
            colors[i] = new Color(fromHSV.r, fromHSV.g, fromHSV.b, 1);
        }

        return colors;

    }
Initial results from just playing with hue:



One thing I hadn't considered is that about half of my cells get pruned to make way for water tiles (coloured white) so I technically have more colours than I need, I could shuffle the list and probably get decent results.

I'll adjust it according to the suggestions y'all provided above in the thread. But this is a good start.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Raenir Salazar posted:

I can't have division by 0 for the computations in the inner loop.

Are the loops meant to be <=?
This is behaving correctly - if you have zero blue shades then you can't make any colors, because every color has to have *a* blue shade, even if that shade is 0. So the minimum useful value for numShadesBlue is 1, which makes the loop not have multiple passes for different shades of blue.

TheLastManStanding
Jan 14, 2008
Mash Buttons!

Raenir Salazar posted:

code:
            Color fromHSV = Color.HSVToRGB(h, s, v);
            colors[i] = new Color(fromHSV.r, fromHSV.g, fromHSV.b, 1);
You don't need to reconstruct the color from it's components, it's already a color.
code:
Color fromHSV = Color.HSVToRGB(h, s, v);
colors[i] = fromHSV ;

or just 

colors[i] = Color.HSVToRGB(h, s, v);

Raenir Salazar
Nov 5, 2010

College Slice

TheLastManStanding posted:

You don't need to reconstruct the color from it's components, it's already a color.
code:
Color fromHSV = Color.HSVToRGB(h, s, v);
colors[i] = fromHSV ;

or just 

colors[i] = Color.HSVToRGB(h, s, v);

I wasn't sure what it'd set the alpha to.

TIP
Mar 21, 2006

Your move, creep.



Raenir Salazar posted:

Also I think Achievement Hunter might be open to trying it out, since Jeremy Dooley (one of the main cast) is known for writing songs, I think if you give them free keys they'd be happy to try it out for you as a Let's Play.

ALSO, after clicking on your trailer, have you considered making a fork of it to sell/advertise as a "songwriter helper" for game creators? I'm tempted to get it now actually to use it to try to write Disney like insert/rock opera songs for my own RPG project.

Thanks, I'll check them out.

I have considered making some kind of songwriting tool with it, I think that could be a cool project but I'm not totally sure how I'd want to do it or how big of an audience there'd be for it.

I actually am hoping to get a new feature in that would be helpful to you: custom AI models. I want to allow players to load a text file from their system and then generate an AI model from it. So you could paste in a bunch of your own writing, or any writing you like, and generate songs based on them.

To get it working I do have to build a system to identify parts of speech based on sentence structure and surrounding words. That's considered to be a pretty difficult task, but I think I have a really good concept of how to pull it off with the statistical data I've built and my current AI systems. So, fingers crossed.

Adbot
ADBOT LOVES YOU

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
More Unity UI stuff. I am showing bound buttons along with some text. I'm putting them in a layout group so that the bindings are left of the text. I want the buttons to take just enough space to show themselves with a little padding and have the text take up the rest of the available space in the canvas (if needed). How do I do this?

Right now, the hierarchy is:

Parent: Canvas with horizontal layout group. Control child size width and height. Child force expand width and height. Middle center alignment.
Child #1: Canvas with horizontal layout group: icons. Images will be inserted here by logic. Control child size width and height. Child force expand width and height. Middle center alignment.
Child #2: Text TMPro canvas. Has a layout element with mind width set to 160. This kind of gets everything crammed together but it's a hack.

Height adjustment is necessary because the icons are larger than the display region at 1:1 scaling so I need them shrunk.

Alternate shenanigans: Can I easily parse metadata into a TMPro text box to represent button actions where I should insert icons? That would be cool with me too.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply