Jump to content

  • Log In with Google      Sign In   
  • Create Account

Wyrframe

Member Since 28 Jun 2000
Offline Last Active Today, 08:58 AM

#5297128 Generating Provinces From A Map

Posted by Wyrframe on 18 June 2016 - 09:32 AM

Here's an algorithm that might do what you want.

 

1) "Seed." Iterate over your map in small chunks, e.g. 6x6 tile/pixel chunks. In each chunk, randomly pick a tile inside. If it is land, assign it a new, unique province ID.

 

2) "Grow." Once you've done that for the whole map, iterate across the entire map repeatedly. For each tile that does not have an assigned province but is adjacent to at least one province, have it adopt the province of a random cardinally-adjacent tile (or any adjacent if you're using hexes). Repeat this process until you walk the map and find no unassigned tiles that have at least one assigned neighbours.

 

3) "Sweep." Remove all land that has no province assignment at all. These are any islands which you didn't hit during the seed step.

 

4) "Inspect." Walk the map and get data for every province. You'll want to be able to take a province ID and look up its total area (how many assigned tiles), a location inside its borders (any will do; top-left, original seed location, whatever), and any other data you want to track about them at this stage. You'll also want to generate an adjacency map at this time.

 

5) "Prune." You'll probably have some provinces too small for your purposes, which won't be able to grow in the next step. For each province under a size threshold which also has zero neighbours, turn it into water and discard the province.

 

6) "Conquer." At this point, the average size of a province is going to be around the 6x6 area (remember the chunk size, in 1?). But you'll have lots of variety in size and shape everywhere. They will all have grown into irregular, blobby shapes. Now what you should do is start fusing these micro-provinces together! Start randomly picking provinces from the bottom 25% or so of them when ranked by size, and have it merge with a random neighbour. Overwrite the neighbour's tile assignments with its conqueror's, union the adjacency sets, and re-insert the new larger province in the rankings. The wider the conqueror selection is, the more variety in final province sizes you'll have at the end.




#5296550 Help with UV mapping procedural game

Posted by Wyrframe on 14 June 2016 - 07:42 PM

For exclusively plane-aligned faces, yeah it's overkill. I had domes and arbitrary 2D CSG polygons extruded upwards into buildings to cope with.




#5296513 Help with UV mapping procedural game

Posted by Wyrframe on 14 June 2016 - 11:55 AM

Although it's highly dependent on art style, I've used an object-space trimapping technique to avoid U/V mapping on my procedural terrain and CSG buildings. Each "material texture" is actually three textures, for the XZ, XY, and YZ planes. In the pixel shader, I use object-space position and a (uniform) scaling parameter to sample each of the three textures, then use the object-space surface normal to slerp between the three samples.

 

Con: no texture alignment; it's only suitable for tiled or detail textures on static objects.

Con: is relatively quite expensive when applied mostly to planar-aligned geometry.

Pro: works on any geometry; with good texture selection, it looks like natural, carved, or poured material.

Pro: no mapping or stretching artefacts.




#5294647 Isometric projection angles...

Posted by Wyrframe on 02 June 2016 - 09:05 AM

Right, but your viewing angle is not aligned with world axes. You need to recalculate the ball's "display" rotation based on its "physics" rotation. Assuming in your Spindizzy example that +X is down-right, +Y is up-right, and +Z is straight up, your camera is 60° around X and 45° around Z away from looking straight down (sign will vary based on left- or right-handedness of rotation). That Z rotation should be increased or decreased by 90° each time you rotate the camera.

 

For minimal change from your current codebase and process... each frame you should make a COPY of your ball's physics rotation, and apply a view rotation to that to match it up to your viewing angle, and then render using that apparent rotation instead of the ball's actual rotation.




#5294474 Isometric projection angles...

Posted by Wyrframe on 01 June 2016 - 09:01 AM

The projection from the basic view direction looks fine to me. Although I do notice in the Spindizzy example, you don't appear to be applying any friction against the ball spinning freely about the world vertical axis, which might be cause the appearance of wobble.

 

As for rotating the view... you're just rotating the ball around the view Z axis. You need to rotate the projection of the ball around the world vertical axis instead. You can tell this is what is happening by leaving the ball stationary with the number at the top. Rotating the view should leave the number at the top from all four directions, but instead you're rotating the ball as though looking straight down on it (where the view and world vertical axes are parallel).




#5292378 how can i use the CreateTimerQueueTimer()?

Posted by Wyrframe on 18 May 2016 - 05:28 PM

        ULONG flags;
        DWORD dwPeridic;
        if(blnPeriodic==true)
        {
            flags = WT_EXECUTEDEFAULT;
            dwPeridic=(DWORD)intInterval;
        }
        else
        {
            flags = WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE;
            dwPeridic=0;
        }

        WT_SET_MAX_THREADPOOL_THREADS(flags,500);

Why not use the macro that actually exists, the way the documentation describes? The error you were getting is because the first parameter to the macro must be an assignable expression (an lvalue). Why do you need up to 500 threads to service your timer callbacks in the first place?

 

I have no idea what your (1) is asking.

 

As for your (2)... SetTimer() and KillTimer() deliver timer events as WM_EVENT events, and require a window handle. CreateTimerQueueTimer lets you specify arbitrary callback functions and callback parameters instead. AFAIK this design decision has nothing to do with the periodicity or precision of the timers associated with them.




#5292371 Introducing Stanza: A New Optionally-Typed General Purpose Programming Langua...

Posted by Wyrframe on 18 May 2016 - 05:11 PM

Trying to take prisoners in one of programming's holy wars is not user-friendly.

 

Maybe the language is useful. I can see some of the nicer features I got used to in Objective Caml hiding under the surface. Maybe the library is even robust and the compiler optimization fantastic.

 

But I don't have faith that any of these are true, after reading...

 

 

Indentation is important in Stanza programs. Be careful when trying out the examples.

And don't use tabs. Stanza won't let you. We don't like tabs.

 

Well, good for you. But this aggressive, inflammatory approach to user-friendliness just lost you an entire market of potential users who aren't even going to give the time of day to that attitude. It comes across as petty, and that's not something you want a reputation for. If you have a technical reason for blacklisting \t, put that in the documentation instead.

 

 

 

Also, a bug report: on 64-bit Ubuntu with 2 GB of RAM, after following the instructions to install Stanza and successfully running `stanza version`, I try to compile the "Hello World" example, and this causes `cc` to crash with an out-of-memory error while trying to consume a 7.6 MiB "tmp1.s" assembly.

[dispos@vbox: ~/mystanza]$ time ./stanza examples/helloworld.stanza -o helloworld
cc -std=c99 'tmp1.s' '/home/dispos/mystanza/runtime/driver.c' -o 'helloworld' -lm
Cannot allocate memory

real    0m38.292s
user    0m5.576s
sys     0m1.796s

[dispos@vbox: ~/mystanza]$ cc -v 2>&1 | tail -n 1
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)

[dispos@vbox: ~/mystanza]$ date -R --reference=../lstanza.zip
Wed, 18 May 2016 15:40:50 -0700



#5292358 how can i use the CreateTimerQueueTimer()?

Posted by Wyrframe on 18 May 2016 - 04:18 PM

Exactly as it says in the documentation: Due Time is how long until the timer first fires. Period is how long AFTER THAT it will fire again, and then again, and then again... unless it is zero. If you are getting a crash when you use a nonzero period, it sounds like something about your handler is crashing on the second or some subsequent timer firing.

 

If you expect the timer to fire once, and then never again, give a Period of zero. If you need it to fire multiple times over time, give it a period and debug your callback for what's really going on.

 

 

Also, on a resource waste note... you are creating a TimerQueue (a somewhat heavyweight object) for each of your timers, and then creating only one TimerQueueTimer (a lightweight object) in each of them.




#5285676 Optimizing Chunks [Distance]

Posted by Wyrframe on 07 April 2016 - 06:22 PM

Spotted it. You're gonna kick yourself.

for (int y = minY; x <= maxY; y++)
{
    float dY = y * 16 - playery;
    for (int z = minZ; x <= maxZ; z++)

Hint: what variable are you testing against in your Y/Z bounds checks?

 

And this is why we use an IDE that highlights all occurrences of a variable when you put the caret or mouse over it, folks. :)




#5285674 Typing skills

Posted by Wyrframe on 07 April 2016 - 06:18 PM

"Sufficient and competent, respectively."

 

 

 

 

Your ability to proof-read and debug your code is more important, because once you learn to type, generally you'll write what you intended to first time... its the things which you didn't have in your mental model of the code at the time you were writing it that are going to bite you most often. More bugs are caused by getting the logic of a test or a looping structure wrong, than are caused by having one too few semicolons or one too many minus signs.




#5285428 Gamepads in Assembly

Posted by Wyrframe on 06 April 2016 - 08:52 AM


(be sure to support USB hubs as well, not every USB port will have its own dedicated connection to the controller)
Just FYI, hubs are a mandatory part of the protocol. Even the ports on your PC are actually downstream-facing ports of an internal hub. If you only have one port on your entire computer, that's internally a hub with one downstream-facing port. The only difference between it and an external port multiplexer is that the built-in hubs' upstream interface is a PCI client controller or suchlike, instead of being an upstream USB port.


#5284066 Optimizing Chunks [Distance]

Posted by Wyrframe on 29 March 2016 - 09:13 AM


This loads (for an 8 x 8 x 8 planet) from 1, 1, 1 to 1, 1, 8 before throwing out of bounds exceptions (On !ischunkloaded[x, y, z]). When I try to catch the exception and figure out what values are breaking it, unity crashes.
Try just printing to console each x,y,z and distance, or comment out that entire if construct and debugging it. Possibly, Unity is trying to evaluate ischunkloaded[x,y,z] and show you the value, but not trapping the same exception that's being thrown at runtime.

 

Alternatively, if it is a bounds issue, print out all of minX/Y/Z and maxX/Y/Z before entering the loop. Find out what axis we're off on.

 

Also, I noticed a problem in the bounds logic I gave you. This may be part of it.

int minX = (int)Mathf.Max(0, (playerx - loadRange) / 16) + 1;
int maxX = (int)Mathf.Min(planetSize, playerx + loadRange + 15) / 16 + 1;
if (minX > planetSize / 16 || maxX < 1) continue;

Note two things. First, division doesn't flatten at 1, it flattens at 0, so we have to add one after the division to get the right indexes. Second, I've moved the division by 16 out of the upper bound calculation, since both terms were being divided, and there was a possible rounding error going on there as it was.

 

Is is because you access the ischunkloaded ranging from 1..8 and not 0..7?
OP has said that his array is 1-indexed, though not why. I don't know if that's a Unity thing, or part of how he designed his ischunkloaded array.


#5283903 Optimizing Chunks [Distance]

Posted by Wyrframe on 28 March 2016 - 01:44 PM

So, when you say "planets over 1,000 chunks"... do you means planets made up of a 10x10x10 cube of chunks? Or do you mean planets of a diameter or radius of 1,000 chunks (1000 x 1000 x 1000)? Because there's six orders of magnitude difference between how many chunks that totals up to.

 

Totally aside from that, there's two whole categories of things you're doing suboptimally here.

 

* You're testing every chunk of every planet for being in or out of range of every player... when in fact, you should at worst be iterating over the chunks currently loaded for that player to find which ones to unload, and then searching for chunks that need to become loaded.

* You're iterating over all players, and presumably, all planets (assuming this FixedUpdate() function is a member of your planet object) outside this loop.

* You're re-sorting the list every time you add an item to it, instead of only sorting it once after all adds.

 

You can exclude a lot of tests by adding layers of guards here:

* You can exclude an entire player/planet test based on the player being too far from that planet to even consider testing chunks of that planet.

* You can also only iterate over only the chunks which are inside the bounding cube of that player's range, instead of testing every cube of the entire planet.

* You can test against range-squared, instead of range, to save you a square root calculation per chunk/player pair. Here's some pseudocode fragments which may help...

float loadRange = 200;                      // Extract this magic constant from the inner loop to somewhere more maintainable.
float loadRangeSq = loadRange * loadRange;  // Calculate its square.
int currentLoad = toLoad.Size();            // Memorize the current length of the load queue.

int playerx = (int)(player.transform.position.x - this.transform.position.x);  // Express player's position relative to planet.
[... and for the other two axes ...]
int minX = max(1, (playerx - loadRange) / 16);               // Calculate extends of bounding rectangle of view, in chunk units.
int maxX = min(planetSize, (playerx + loadRange + 15) / 16); // Ditto. Note the +15 to cause rounding up.
if( minX > planetSize || maxX < 1 ) continue;                // Stop looking at this player if the planet is entirely out of range.
for(int x = minx; x <= maxx; x++)    // Use the calculated bounds, not the whole planet.
{
float dX = x * 16 - playerx;  // Only need to calculate this once per X term. Could even make this cheaper; I leave it as exercise for the reader.
[... Y and Z loops too ...]
// And now; the entire inner loop body.
float distanceSq = dX*dX + dY*dY + dZ*dZ;  // This, too, can be made cheaper. How is an exercise to the reader.

if( distanceSq < loadRangeSq && !isChunkLoaded[x,y,z] && LoadDone ) {
    toLoad.Add( [...] );
    // Presumably, after the chunk is loaded it is added to that player's chunks-displayed list.
  }
}
// And then, outside of the X loop again...
if( toLoad.Size() > currentLoad ) {
    // Only re-sort if we did add anything.
    toLoad.Sort( [...] );
}

That's the load-queue populator. You should iterate over the player's current chunk list and un-load any that are now out of range, because the player's current view list is probably *always* going to be smaller than the number of chunks that *might* be in the player's view.

 

Also, if this load/unload is the server-side view of chunks, remember to load chunks when ANY player enters range, but don't unload a chunk until ALL players are out of range.




#5283483 SpriteFont render Umlaute

Posted by Wyrframe on 25 March 2016 - 05:44 PM

Are you certain that the font you're loading has glyphs for the characters you're trying to render? Check the return value of TTF_GlyphMetrics.




#5279569 Need help with a schoolproject

Posted by Wyrframe on 04 March 2016 - 05:18 PM

So my main question is how long would it take for a programmer (preferably with 3 years or less of experience) to do these tasks.

If you have specific experience with all of these features (because these aren't "tasks") in small scale, you should be able to slap-dash something with all of this together in a few months.

 

If you have never done most of these, expect it to take 1-10 years of part-time work.

 

 

Remember; a task is something you can actually do. "Design the Store API", "Replace Existing PRNG UI with Dice+Physics", "Rebalance turret building cost". A feature is something you expect to be able to see when looking at the product. "Friends list", "In-game Store", "Server".

 

As a word of advice with regards to designing a Gantt chart of the tasks needed to develop something... if you can't nail a task down to a single-digit number of hours, either the task is too big and nebulous still and you need to break it up into smaller parts, or you don't really know how long it is going to take because you don't know what work is required to complete that task.






PARTNERS