How do you scale game difficulty with a curve? - math

I would just like to start by saying my calculus is terrible and I have next to no experience with using it.
I am trying to find an algorithm to help scaling in my game. Specifically it should scale the amount of waves that spawn per level. Ideally it will take any number as a level up to the max integer value. There would also be a minimum value and a maximum value that would be the minimum waves and maximum waves. So:
level = 0 to infinity
minValue = 3
maxValue = 40
result = an algorithm that will have a max curvature of the max value and shouldnt exceed it no matter what value the level is. I'm not sure how to calculate this but I think it would also need some kind of threshold that i could control to dictate the curvature based on the the level.

Try the next approach:
mult = Min(1, (level/MaxLevel)**Somepower))
minValue + (maxValue - minValue) * mult
Choose Somepower value suitable for your tasks. For example, value 2 gives parabola (note that value might be less than 1)
If you want more complex curve, show a picture of desired form.
Edit:
For the case when curve tends but does not become above some level, you can choose some function with horizontal asymptote. For example:
max * x /(x+1)
or
max * arctan(k*x) * 2 / Pi

Related

How to compare two Ratios of Rectangles / Sizes to determine their percentages of differences?

I have a ractangle whose ratio is 80:40 and other rectangles with similar aspect ratios within a humbral for example 80:35, 85:45, that unbral is a decimal or integer.
My problem is that I need to compare other rectangles with the first one and determine a difference in their respective aspect ratios in percentages, for example: 80:30 is 20% different in aspect ratio than 80:40.
(20% is not a calculated data, it is an example idea, because I don't know how to do it).
Could it be that a totally opposite aspect ratio is 100% different? For example: 80:40 is 100% different than 40:80
Imagine that you have a collection of rectangles and a target rectangle and you have to filter the collection leaving only those rectangles that have an aspect ratio similar to the target rectangle.
Sample:
private float GetDiffRatio(FloatSize size1, FloatSize size2) {
float fixedR1 = size1.Width / size1.Height;
if (fixedR1 >= 0)
// Invert and negative.
fixedR1 = -(size1.Height / size1.Width);
float fixedR2 = size2.Width / size2.Height;
if (fixedR2 >= 0)
// Invert and negative.
fixedR2 = -(size2.Height / size1.Width);
float rDiff = fixedR1 - fixedR2;
return rDiff * 100f;
}
Test:
float diffRatio = GetDiffRatio(new FloatSize(100f, 50f), new FloatSize(50f, 100f));
Results = -100f
Test2 (inverted order of parameters):
float diffRatio = GetDiffRatio(new FloatSize(50f, 100f), new FloatSize(100f, 50f));
Results = 100f
I am not sure that this is a valid or correct form, I do not know if it can generate any condition that returns a wrong percentage of similarity.
The answer to this question depends a lot on what exactly you're trying to do or you're planning to uses this similarity function for. I find it very unintuitive to say that opposite aspect ratio leads to 0% similarity. I think comparing two rectangles r1=(2.1,2) and r2=(2,2.1) should be a lot more similar to each other then for example r3=(1,5) r4=(5,1).
This is not me saying that it couldn't be useful in some case to have a similarity function like your's, I just want to explain that it depends a lot on what you're doing ...
I would say a very obvious solution would be to just divide width by height of every rectangle and take as similarity-function s1 the absolute value from both values subtracted. So for my provided examples the result would be:
s1(r1,r2) = | 2.1/2 - 2/2.1 | = 0.0976...
s1(r2,r3) = | 1/5 - 5/1 | = 4.8
If it is also important that you have values between 0 and 1 you could additionally plug this values in for example this function ...
where
b must be smaller than 0 and is a parameter with what you can controll how fast the funciton converges to 1. YOu can play around with it here: https://www.desmos.com/calculator/nwlq3ujouq
In the case you really want something as you suggested, i would simply do the following:
You take your constraint that every rectangle is between the ratio a:b and c:d. Than you calculate x1=a/b and x2=c/d and then you interpolate the value from zero to one between those values so:
h(x1) = 0
h(x2) = 1
if you need more details on how to do this look here https://en.wikipedia.org/wiki/Linear_interpolation but i think it's very straight forward.
The similarity function s3 can then be build again with the absolute value of the difference
s3=| h(r1)-h(r2) |

Position(t) on cubic bezier curve

The only equation to calculate this that I can find involves t in the range [0, 1], but I have no idea how long it will take to travel the entire path, so I can't calculate (1 - t).
I know the speed at which I'm traveling, but it seems to be a heavy idea to calculate the total time beforehand (nor do I actually know how to do that calculation). What is an equation to figure out the position without knowing the total time?
Edit To clarify on the cubic bezier curve: I have four control points (P0 to P1), and to get a value on the curve with t, I need to use the four points as such:
B(t) = (1-t)^3P0 + 3t(1-t)^2P1 + 3t^2(1-t)P2 + t^3P3
I am not using a parametric equation to define the curve. The control points are what define the curve. What I need is an equation that does not require the use of knowing the range of t.
I think there is a misunderstanding here. The 't' in the cubic Bezier curve's definition does not refer to 'time'. It is parameter that the x, y or even z functions based on. Unlike the traditional way of representing y as a function of x, such as y=f(x), an alternative way of representing a curve is by the parametric form that represents x, y and z as functions of an additional parameter t, C(t)=(x(t), y(t), z(t)). Typically the t value will range from 0 to 1, but this is not a must. The common representation for a circle as x=cos(t) and y=sin(t) is an example of parametric representation. So, if you have the parametric representation of a curve, you can evaluate the position on the curve for any given t value. It has nothing to do with the time it takes to travel the entire path.
You have the given curve and you have your speed. To calculate what you're asking for you need to divide the total distance by the speed you traveled given that time. That will give you the parametric (t) you need. So if the total curve has a distance of 72.2 units and your speed is 1 unit then your t is 1/72.2.
Your only missing bit is calculating the length of a given curve. This is typically done by subdividing it into line segments small enough that you don't care, and then adding up the total distance of those line segments. You could likely combine those two steps as well if you were so inclined. If you have your given speed, just iteration like 1000th of the curve add the line segment between the start and point 1000th of the way through the curve, and subtract that from how far you need to travel (given that you have speed and time, you have distance you need to travel), and keep that up until you've gone as far as you need to go.
The range for t is between 0 and 1.
x = (1-t)*(1-t)*(1-t)*p0x + 3*(1-t)*(1-t)*t*p1x + 3*(1-t)*t*t*p2x + t*t*t*p3x;
y = (1-t)*(1-t)*(1-t)*p0y + 3*(1-t)*(1-t)*t*p1y + 3*(1-t)*t*t*p2y + t*t*t*p3y;

Simple math formula verification (normalize 0-100)

How do I normalize any given number between 0 and 100?
The min is 0 and the max has no bounds (it's the search volume for a keyword).
normalized = (x-min(x))/(max(x)-min(x)) won't work since I have no definition of max.
Arcus tangens
Algebraically, you might start with some function that has poles, e.g. tan, and use its inverse, atan. That inverse will never exceed a given limit, namely π/2 in this case. Then you can use a formula of the kind
f(x) = 100 * 2/π * atan(x - min)
If that doesn't produce “nice” results for small inputs, you might want to preprocess the inputs:
f(x) = 100 * 2/π * atan(a*(x - min))
for some suitably chosen a. Making a larger than one increases values, while for 0 < a < 1 you get smaller values. According to a comment, the latter is what you'd most likely want.
You could even add a power in there:
f(x) = 100 * 2/π * atan(a*(x - min)^b) = 100 * 2/π * atan(pow(a*(x - min), b))
for some positive parameter b. Having two parameters to tweak gives you more freedom in adjusting the function to your needs. But to decide on what would be good fits, you might have to decide up front as to what values you'd expect for various inputs. A bit like in this question, although there the input range is not unbounded.
Stereographic projection
If you prefer geometric approaches: you can imagine your input as the positive half of the x axis, namely the ray from (0,0) to (∞,0). Then imagine a circle with center (0,1) and radius 1 sitting on that line. If you connect the point (0,2) with any point on the ray, the connecting line will intersect the circle in one other point. That way you can map the ray onto the right half of the circle. Now take either the angle as seen from the center of the circle, or the y coordinate of the point on the circle, or any other finite value like this, normalize input and output properly, and you have a function matching your requirements. You can also work out a formula for this, and atan will likely play a role in that.

How to find the average of a set of bearings [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do you calculate the average of a set of angles?
If I have a set of bearings, ranging from 1-360, how can I find the average? Usually to find the average one would add them all up and divide by the number of items. The problem here is that doing that in the case of [1, 359], 2 bearings, would result in in 180, which in fact should be 360. Any ideas?
Represent the angles as vectors with Norm=1 and average the sum.
x1 = {cos(a),sin(a)}
x2 = {cos(b),sin(b)}
(x1+x2)/2 = {(cos(a)+cos(b))/2,(sin(a)+sin(b))/2}
which means the angle for the mean is
atan2((sin(a)+sin(b)) /(cos(a)+cos(b)))
Just beware of controlling the possible overflow when the denominator is close to zero.
It isn't clear from your question what you're trying to define the "average" to be... for directions on a circle there is no clear-cut obvious notion of average.
One interpretation is the value x that is the closest fit to the set of provided values, in the least-squares sense, where the distance between two bearings is defined as the smallest angle between them. Here is code to compute this average:
In[2]:= CircDist[a_, b_] := 180 - Mod[180 + a - b, 360]
In[6]:= Average[bearings_] :=
x /. NMinimize[
Sum[CircDist[x, bearings[[i]]]^2, {i, 1, Length[bearings]}],
x][[2]]
In[10]:= Average[{1, 359}]
Out[10]= -3.61294*10^-15
So what you want is the middle of two bearings - what happens if you have {90, 270}? Is the desired answer 0 or 180? This is something to consider.. also what's the middle of three bearings?
One thing you could do is:
Take the first two bearings in your set
Work out the difference between the two in either direction (i.e. [1, 359] would give 2 degrees in one direction, and 358 in the other)
If you want the desired angle to be the middle of the acutest of the two, take that as your difference and add to the anti-clockwise most of the pair (i.e. 359)
Use this as the new bearing and the next (i.e. 3rd in set) as the other bearing, and repeat, until all are 'middled'.
Off the top of my head, I don't think this is going to be fair, it'll probably bias it in one direction though (i.e. maybe in preference of the later values in your set).

Collision Detection between Accelerating Spheres

I am writing a physics engine/simulator which incorporates 3D space flight, planetary/stellar gravitation, ship thrust and relativistic effects. So far, it is going very well, however, one thing that I need help with is the math of the collision detection algorithm.
The iterative simulation of movement that I am using is basically as follows:
(Note: 3D Vectors are ALL CAPS.)
For each obj
obj.ACC = Sum(all acceleration influences)
obj.POS = obj.POS + (obj.VEL * dT) + (obj.ACC * dT^2)/2 (*EQ.2*)
obj.VEL = obj.VEL + (obj.ACC * dT)
Next
Where:
obj.ACC is the acceleration vector of the object
obj.POS is the position or location vector of the object
obj.VEL is the velocity vector of the object
obj.Radius is the radius (scalar) of the object
dT is the time delta or increment
What I basically need to do is to find some efficient formula that derives from (EQ.2) above for two objects (obj1, obj2) and tell if they ever collide, and if so, at what time. I need the exact time both so that I can determine if it is in this particular time increment (because acceleration will be different at different time increments) and also so that I can locate the exact position (which I know how to do, given the time)
For this engine, I am modelling all objects as spheres, all this formula/algorithm needs to do is to figure out at what points:
(obj1.POS - obj2.POS).Distance = (obj1.Radius + obj2.Radius)
where .Distance is a positive scalar value. (You can also square both sides if this is easier, to avoid the square root function implicit in the .Distance calculation).
(yes, I am aware of many, many other collision detection questions, however, their solutions all seem to be very particular to their engine and assumptions, and none appear to match my conditions: 3D, spheres, and acceleration applied within the simulation increments. Let me know if I am wrong.)
Some Clarifications:
1) It is not sufficient for me to check for Intersection of the two spheres before and after the time increment. In many cases their velocities and position changes will far exceed their radii.
2) RE: efficiency, I do not need help (at this point anyway) with respect to determine likely candidates for collisions, I think that I have that covered.
Another clarification, which seems to be coming up a lot:
3) My equation (EQ.2) of incremental movement is a quadratic equation that applies both Velocity and Acceleration:
obj.POS = obj.POS + (obj.VEL * dT) + (obj.ACC * dT^2)/2
In the physics engines that I have seen, (and certainly every game engine that I ever heard of) only linear equations of incremental movement that apply only Velocity:
obj.POS = obj.POS + (obj.VEL * dT)
This is why I cannot use the commonly published solutions for collision detection found on StackOverflow, on Wikipedia and all over the Web, such as finding the intersection/closest approach of two line segments. My simulation deals with variable accelerations that are fundamental to the results, so what I need is the intersection/closest approach of two parabolic segments.
On the webpage AShelley referred to, the Closest Point of Approach method is developed for the case of two objects moving at constant velocity. However, I believe the same vector-calculus method can be used to derive a result in the case of two objects both moving with constant non-zero acceleration (quadratic time dependence).
In this case, the time derivative of the distance-squared function is 3rd order (cubic) instead of 1st order. Therefore there will be 3 solutions to the Time of Closest Approach, which is not surprising since the path of both objects is curved so multiple intersections are possible. For this application, you would probably want to use the earliest value of t which is within the interval defined by the current simulation step (if such a time exists).
I worked out the derivative equation which should give the times of closest approach:
0 = |D_ACC|^2 * t^3 + 3 * dot(D_ACC, D_VEL) * t^2 + 2 * [ |D_VEL|^2 + dot(D_POS, D_ACC) ] * t + 2 * dot(D_POS, D_VEL)
where:
D_ACC = ob1.ACC-obj2.ACC
D_VEL = ob1.VEL-obj2.VEL (before update)
D_POS = ob1.POS-obj2.POS (also before update)
and dot(A, B) = A.x*B.x + A.y*B.y + A.z*B.z
(Note that the square of the magnitude |A|^2 can be computed using dot(A, A))
To solve this for t, you'll probably need to use formulas like the ones found on Wikipedia.
Of course, this will only give you the moment of closest approach. You will need to test the distance at this moment (using something like Eq. 2). If it is greater than (obj1.Radius + obj2.Radius), it can be disregarded (i.e. no collision). However, if the distance is less, that means the spheres collide before this moment. You could then use an iterative search to test the distance at earlier times. It might also be possible to come up with another (even more complicated) derivation which takes the size into account, or possible to find some other analytic solution, without resorting to iterative solving.
Edit: because of the higher order, some of the solutions to the equation are actually moments of farthest separation. I believe in all cases either 1 of the 3 solutions or 2 of the 3 solutions will be a time of farthest separation. You can test analytically whether you're at a min or a max by evaluating the second derivative with respect to time (at the values of t which you found by setting the first derivative to zero):
D''(t) = 3 * |D_ACC|^2 * t^2 + 6 * dot(D_ACC, D_VEL) * t + 2 * [ |D_VEL|^2 + dot(D_POS, D_ACC) ]
If the second derivative evaluates to a positive number, then you know the distance is at a minimum, not a maximum, for the given time t.
Draw a line between the start location and end location of each sphere. If the resulting line segments intersect the spheres definitely collided at some point and some clever math can find at what time the collision occurred. Also make sure to check if the minimum distance between the segments (if they don't intersect) is ever less than 2*radius. This will also indicate a collision.
From there you can backstep your delta time to happen exactly at collision so you can correctly calculate the forces.
Have you considered using a physics library which already does this work? Many libraries use far more advanced and more stable (better integrators) systems for solving the systems of equations you're working with. Bullet Physics comes to mind.
op asked for time of collision. A slightly different approach will compute it exactly...
Remember that the position projection equation is:
NEW_POS=POS+VEL*t+(ACC*t^2)/2
If we replace POS with D_POS=POS_A-POS_B, VEL with D_VEL=VEL_A-VEL_B, and ACC=ACC_A-ACC_B for objects A and B we get:
$D_NEW_POS=D_POS+D_VEL*t+(D_ACC*t^2)/2
This is the formula for vectored distance between the objects. In order to get the squared scalar distance between them, we can take the square of this equation, which after expansion looks like:
distsq(t) = D_POS^2+2*dot(D_POS,D_VEL)*t + (dot(D_POS, D_ACC)+D_VEL^2)*t^2 + dot(D_VEL,D_ACC)*t^3 + D_ACC^2*t^4/4
In order to find the time where collision occurs, we can set the equation equal to the square of the sum of radii and solve for t:
0 = D_POS^2-(r_A+r_B)^2 + 2*dot(D_POS,D_VEL)*t + (dot(D_POS, D_ACC)+D_VEL^2)*t^2 + dot(D_VEL,D_ACC)*t^3 + D_ACC^2*t^4/4
Now, we can solve for the equation using the quartic formula.
The quartic formula will yield 4 roots, but we are only interested in real roots. If there is a double real root, then the two objects touch edges at exactly one point in time. If there are two real roots, then the objects continuously overlap between root 1 and root 2 (i.e. root 1 is the time when collision starts and root 2 is the time when collision stops). Four real roots means that the objects collide twice, continuously between root pairs 1,2 and 3,4.
In R, I used polyroot() to solve as follows:
# initial positions
POS_A=matrix(c(0,0),2,1)
POS_B=matrix(c(2,0),2,1)
# initial velocities
VEL_A=matrix(c(sqrt(2)/2,sqrt(2)/2),2,1)
VEL_B=matrix(c(-sqrt(2)/2,sqrt(2)/2),2,1)
# acceleration
ACC_A=matrix(c(sqrt(2)/2,sqrt(2)/2),2,1)
ACC_B=matrix(c(0,0),2,1)
# radii
r_A=.25
r_B=.25
# deltas
D_POS=POS_B-POS_A
D_VEL=VEL_B-VEL_A
D_ACC=ACC_B-ACC_A
# quartic coefficients
z=c(t(D_POS)%*%D_POS-r*r, 2*t(D_POS)%*%D_VEL, t(D_VEL)%*%D_VEL+t(D_POS)%*%D_ACC, t(D_ACC)%*%D_VEL, .25*(t(D_ACC)%*%D_ACC))
# get roots
roots=polyroot(z)
# In this case there are only two real roots...
root1=as.numeric(roots[1])
root2=as.numeric(roots[2])
# trajectory over time
pos=function(p,v,a,t){
T=t(matrix(t,length(t),2))
return(t(matrix(p,2,length(t))+matrix(v,2,length(t))*T+.5*matrix(a,2,length(t))*T*T))
}
# plot A in red and B in blue
t=seq(0,2,by=.1) # from 0 to 2 seconds.
a1=pos(POS_A,VEL_A,ACC_A,t)
a2=pos(POS_B,VEL_B,ACC_B,t)
plot(a1,type='o',col='red')
lines(a2,type='o',col='blue')
# points of a circle with center 'p' and radius 'r'
circle=function(p,r,s=36){
e=matrix(0,s+1,2)
for(i in 1:s){
e[i,1]=cos(2*pi*(1/s)*i)*r+p[1]
e[i,2]=sin(2*pi*(1/s)*i)*r+p[2]
}
e[s+1,]=e[1,]
return(e)
}
# plot circles with radius r_A and r_B at time of collision start in black
lines(circle(pos(POS_A,VEL_A,ACC_A,root1),r_A))
lines(circle(pos(POS_B,VEL_B,ACC_B,root1),r_B))
# plot circles with radius r_A and r_B at time of collision stop in gray
lines(circle(pos(POS_A,VEL_A,ACC_A,root2),r_A),col='gray')
lines(circle(pos(POS_B,VEL_B,ACC_B,root2),r_B),col='gray')
Object A follows the red trajectory from the lower left to the upper right. Object B follows the blue trajectory from the lower right to the upper left. The two objects collide continuously between time 0.9194381 and time 1.167549. The two black circles just touch, showing the beginning of overlap - and overlap continues in time until the objects reach the location of the gray circles.
Seems like you want the Closest Point of Approach (CPA). If it is less than the sum of the radiuses, you have a collision. There is example code in the link. You can calculate each frame with the current velocity, and check if the CPA time is less than your tick size. You could even cache the cpa time, and only update when acceleration was applied to either item.

Resources