Extrapolate Animation Curve (Endless game balancing curve) - unity3d

I need a curve editor to make balancing of endless game then I tried to use AnimationCurve.
I need to set a curve to a certain range ex. [0;1] and if I want a value over 1, the result of the Evaluation have to extrapolate the curve. I want to be able to compute Y from X and X from Y.
The problem is AnimationCurve have only 3 WrapMode (Clamp, PingPong, Loop).
How to extrapolate an AnimationCurve ?
Is there a better tool to make curve with extrapolation (post and pre curve) ?

For real extrapolation I think you'd have to implement your own system based on Bézier mathematics. Me at least am not aware of unity providing it out of the box.
A work around for it could be to just define values beyond the 0 to 1 range to cover the extents, animation curves do allow this, I don't think there are to many issues with that.
Another solution, to stay in 0 to 1 range still but achieve the same effect, would be to model the curve from 0 to 1 so that it would cover extreme values within that range and remap the time for curve evaluation given by the object to a 0 to 1 range.
E.g.:
// define range extents
float rangeMin = -5f, rangeMax = 5f;
var range = 10f;
// range could be calculated at runtime if necessary:
// [to] (higher value) - [from] (lower value) = [range]
// 5f - -5f = 10f
var timeRaw = 0; // variable provided value
var time01 = (timeRaw - rangeMin) / range;
// reult by timeRaw = 0: (0 - -5) / 10 = 0.5
// reult by timeRaw = 5: (5 - -5) / 10 = 1.0
// reult by timeRaw = -5: (-5 - -5) / 10 = 0.0
Combining both solutions allow you to cover even more extreme values.

Related

Moving an object along a path with constant speed

I have an object path composed by a polyline (3D point array) with points VERY unevenly distributed. I need to move an object at constant speed using a timer with interval set at 10 ms.
Unevenly distributed points produce variable speed to the human eye. So now I need to decide how to treat this long array of 3D points.
The first idea I got was to subdivide long segments in smaller parts. It works better but where points are jam-packed the problem persists.
What's the best approach in these cases? Another idea, could be to simplify the original path using Ramer–Douglas–Peucker algorithm, then to subdivide it evenly again but I'm not sure if it will fully resolve my problem.
This should be a fairly common problem in many areas of the 3D graphics, so does a proven approach exist?
I made a JavaScript pen for you https://codepen.io/dawken/pen/eYpxRmN?editors=0010 but it should be very similar in any other language. Click on the rect to add points.
You have to maintain a time dependent distance with constant speed, something like this:
const t = currentTime - startTime;
const distance = (t * speed) % totalLength;
Then you have to find the two points in the path such that the current distance is intermediate between the "distance" on the path; you store the "distance from start of the path" on each point {x, y, distanceFromStart}. The first point points[i] such that distance < points[i].distanceFromStart is your destination; the point before that points[i - 1] is your source. You need to interpolate linearly between them.
Assuming that you have no duplicate points (otherwise you get a division by zero) you could do something like this.
for (let i = 0; i < points.length; i++) {
if (distance < points[i].distanceFromStart) {
const pFrom = points[i - 1];
const pTo = points[i];
const f = (distance - pFrom.distanceFromStart) / (pTo.distanceFromStart- pFrom.distanceFromStart);
const x = pFrom.x + (pTo.x - pFrom.x) * f;
const y = pFrom.y + (pTo.y - pFrom.y) * f;
ctx.fillRect(x - 1, y - 1, 3, 3);
break;
}
}
See this pen. Click on the rectangle to add points: https://codepen.io/dawken/pen/eYpxRmN?editors=0010

Find collision time given distance and speed

Suppose I have an object A at position x = 0 and object B at position x = 16.
Suppose A have this code:
public class Move : MonoBehaviour
{
float speed = 0.04f;
Update()
{
transform.Translate(speed, 0, 0);
}
}
My question is: how to evaluate how many seconds (precisely) will it take for A to collide with B?
If I apply the formula S = S0 + vt, it won't work correctly, because I don't know how to measure how many frames it will pass in a second to exactly measure what speed is.
First of all you shouldn't do that. Your code is currently framerate-dependent so the object moves faster if you have a higher framerate!
Rather use Time.deltaTime
This property provides the time between the current and previous frame.
to convert your speed from Unity Units / frame into Unity Units / second
transform.Translate(speed * Time.deltaTime, 0, 0);
this means the object now moves with 0.04 Unity Units / second (framerate-independent).
Then I would say the required time in seconds is simply
var distance = Mathf.Abs(transform.position.x - objectB.transform.position.x);
var timeInSeconds = distance / speed;
Though .. this obviously still assumes by "collide" you mean at the same position (at least on the X axis) .. you could also take their widths into account since their surfaces will collide earlier than this ;)
var distance = Mathf.Abs(transform.position.x - objectB.transform.position.x) - (objectAWidth + objectBWidth);
var timeInSeconds = distance / speed;

Calculate hue angle range for red colours

I'm trying to correctly calculate colour hue angle range. Given an input default hue say 120 and a threshold value of 20 the range is between 100 - 140 (yes, I know - complex math).
Now in the application, when filtering an image, I can check if a given pixel falls into that range:
let inputHue = 120
let threshold = 20
let minHue = inputHue - threshold // 100
let maxHue = inputHue + threshold // 140
if (pixelHue > minHue && pixelHue < maxHue) {
// do something
}
Now the problem is with red colours range where the most saturated red colour is at 0/360 on the colour wheel. Given an input hue of 10 the minHue is now -10 (with a threshold of 20) and maxHue is 30. Because of that negative value for minHue the condition fails:
let pixelHue = 355 // this falls into a valid red range I want to get
let minHue = -10
let maxHue = 30
if (pixelHue > minHue && pixelHue < maxHue) {
// do something
}
Does anyone know how to tackle this problem of a colour wheel? I'm trying to develop a general solution that would work for any given input hue (not only red colours).
Thanks in advance.
Hues should be considered modulo 360. Hence the range for red is 0-30 AND 350-360.
Now your value of 355 passes because (355>350 AND 355<30) OR (350>30 AND (355>350 OR 355<30)).
The critical bit here starts after the first OR. In normal arithmetic, you check against lower and upper bound, and you have to pass both tests. But in modular arithmetic, if the lower bound is higher than the upper bound, the range wraps around 0 and you only need to pass one of the two both tests.
To recap: (hue>min AND hue<max) OR (min>max AND (hue>min OR hue<max))
A possible approach: Imagine both hue values as points on a circle, and compare the "shorter" angular distance between these points with the threshold:
let diff = abs(pixelHue - inputHue)
if min(diff, 360 - diff) <= threshold {
// do something
}

Procedural structure generation

I have a voxel based game in development right now and I generate my world by using Simplex Noise so far. Now I want to generate some other structures like rivers, cities and other stuff, which can't be easily generated because I split my world (which is practically infinite) into chunks of 64x128x64. I already generated trees (the leaves can grow into neighbouring chunks), by generating the trees for a chunk, plus the trees for the 8 chunks surrounding it, so leaves wouldn't be missing. But if I go into higher dimensions that can get difficult, when I have to calculate one chunk, considering chunks in an radius of 16 other chunks.
Is there a way to do this a better way?
Depending on the desired complexity of the generated structure, you may find it useful to first generate it in a separate array, perhaps even a map (a location-to-contents dictionary, useful in case of high sparseness), and then transfer the structure to the world?
As for natural land features, you may want to google how fractals are used in landscape generation.
I know this thread is old and I suck at explaining, but I'll share my approach.
So for example 5x5x5 trees. What you want is for your noise function to return the same value for an area of 5x5 blocks, so that even outside of the chunk, you can still check if you should generate a tree or not.
// Here the returned value is different for every block
float value = simplexNoise(x * frequency, z * frequency) * amplitude;
// Here it will return the same value for an area of blocks (you should use floorDiv instead of dividing, or you it will get negative coordinates wrong (-3 / 5 should be -1, not 0 like in normal division))
float value = simplexNoise(Math.floorDiv(x, 5) * frequency, Math.floorDiv(z, 5) * frequency) * amplitude;
And now we'll plant a tree. For this we need to check what x y z position this current block is relative to the tree's starting position, so we can know what part of the tree this block is.
if(value > 0.8) { // A certain threshold (checking if tree should be generated at this area)
int startX = Math.floorDiv(x, 5) * 5; // flooring the x value to every 5 units to get the start position
int startZ = Math.floorDiv(z, 5) * 5; // flooring the z value to every 5 units to get the start position
// Getting the starting height of the trunk (middle of the tree , that's why I'm adding 2 to the starting x and starting z), which is 1 block over the grass surface
int startY = height(startX + 2, startZ + 2) + 1;
int relx = x - startX; // block pos relative to starting position
int relz = z - startZ;
for(int j = startY; j < startY + 5; j++) {
int rely = j - startY;
byte tile = tree[relx][rely][relz]; // Get the needing block at this part of the tree
tiles[i][j][k] = tile;
}
}
The tree 3d array here is almost like a "prefab" of the tree, which you can use to know what block to set at the position relative to the starting point. (God I don't know how to explain this, and having english as my fifth language doesn't help me either ;-; feel free to improve my answer or create a new one). I've implemented this in my engine, and it's totally working. The structures can be as big as you want, with no chunk pre loading needed. The one problem with this method is that the trees or structures will we spawned almost within a grid, but this can easily be solved with multiple octaves with different offsets.
So recap
for (int i = 0; i < 64; i++) {
for (int k = 0; k < 64; k++) {
int x = chunkPosToWorldPosX(i); // Get world position
int z = chunkPosToWorldPosZ(k);
// Here the returned value is different for every block
// float value = simplexNoise(x * frequency, z * frequency) * amplitude;
// Here it will return the same value for an area of blocks (you should use floorDiv instead of dividing, or you it will get negative coordinates wrong (-3 / 5 should be -1, not 0 like in normal division))
float value = simplexNoise(Math.floorDiv(x, 5) * frequency, Math.floorDiv(z, 5) * frequency) * amplitude;
if(value > 0.8) { // A certain threshold (checking if tree should be generated at this area)
int startX = Math.floorDiv(x, 5) * 5; // flooring the x value to every 5 units to get the start position
int startZ = Math.floorDiv(z, 5) * 5; // flooring the z value to every 5 units to get the start position
// Getting the starting height of the trunk (middle of the tree , that's why I'm adding 2 to the starting x and starting z), which is 1 block over the grass surface
int startY = height(startX + 2, startZ + 2) + 1;
int relx = x - startX; // block pos relative to starting position
int relz = z - startZ;
for(int j = startY; j < startY + 5; j++) {
int rely = j - startY;
byte tile = tree[relx][rely][relz]; // Get the needing block at this part of the tree
tiles[i][j][k] = tile;
}
}
}
}
So 'i' and 'k' are looping withing the chunk, and 'j' is looping inside the structure. This is pretty much how it should work.
And about the rivers, I personally haven't done it yet, and I'm not sure why you need to set the blocks around the chunk when generating them ( you could just use perlin worms and it would solve problem), but it's pretty much the same idea, and for your cities too.
I read something about this on a book and what they did in these cases was to make a finer division of chunks depending on the application, i.e.: if you are going to grow very big objects, it may be useful to have another separated logic division of, for example, 128x128x128, just for this specific application.
In essence, the data resides is in the same place, you just use different logical divisions.
To be honest, never did any voxel, so don't take my answer too serious, just throwing ideas. By the way, the book is game engine gems 1, they have a gem on voxel engines there.
About rivers, can't you just set a level for water and let rivers autogenerate in mountain-side-mountain ladders? To avoid placing water inside mountain caveats, you could perform a raycast up to check if it's free N blocks up.

How to swap negative rotation values over to positive rotation values?

Example: I have a circle which is split up into two halfs. One half goes from 0 to -179,99999999999 while the other goes from 0 to 179,99999999999. Typical example: transform.rotation.z of an CALayer. Instead of reaching from 0 to 360 it is slip up like that.
So when I want to develop a gauge for example (in theory), I want to read values from 0 to 360 rather than getting a -142 and thinking about what that might be on that 0-360 scale.
How to convert this mathematically correctly? Sine? Cosine? Is there anything useful for this?
Isn't the normalization achieved by something as simple as:
assert(value >= -180.0 && value <= +180.0);
if (value < 0)
value += 360.0;
I'd probably put even this into a function if I'm going to need it in more than one place. If the code needs to deal with numbers that might already be normalized, then you change the assertion. If it needs to deal with numbers outside the range -180..+360, then you have more work to do (adding or subtracting appropriate multiples of 360).
while (x < 0) {
x = x + 360;
}
while (x > 360) {
x = x - 360;
}
This will work on any value, positive or negative.
((value % 360) + 360) % 360
The first (value % 360) makes it to -359 to 359.
The + 360 removes any negative number: Value now 1 to 719
The last % 360 makes it to 0
to 359
Say x is the value with range (-180, 180), y is the value you want display,
y = x + 180;
That will change shift reading to range (0, 360).
If you don't mind spending a few extra CPU cycles on values that are already positive, this should work on any value -360 < x < 360:
x = (x + 360) % 360;
I provide code to return 0 - 360 degree angle values from the layer's transform property in this answer to your previous question.