C++ 2D Box-Collision, is this right? - c++

Well I've got a 2D box collision code that basically loops through every block in a list called "Blocks" and it checks if I'm near the sides and whatnot.
It works very well except for the bottom of the block. When I'm jumping up towards the bottom I want my player to simply "bounce" off. It does this, but it is very glitchy. It's hard to explain so I was hoping you guys could possibly spot out what's wrong with my bottom collision code.
Here's the entire thing (this is ran in a loop):
for(unsigned int i = 0; i<blocks.size(); i++){
Block &b = blocks.at(i);
if(!b.passable==true){
//Check if we are on the sides
if(y + height + vspeed >= b.worldY+2 && y + vspeed <= b.worldY+b.height)
{
//Right side
if(x + hspeed <= b.worldX+b.width-1 && x + hspeed > b.worldX+b.width + hspeed-2)
{
x = b.worldX + b.width; hspeed = 0;
}
//Left side
if(x + width + hspeed >= b.worldX +1 && x + width + hspeed <= b.worldX + hspeed + 2)
{
x = b.worldX - width; hspeed = 0;
}
}
//Check if we are on the top or the bottom
if(x + width + hspeed >= b.worldX+2 && x + hspeed <= b.worldX+b.width-2)
{
if(y + height + vspeed >= b.worldY && y + height + vspeed <= b.worldY + vspeed + 1 && jumpstate=="falling")
{
y = b.worldY - height; jumpstate.assign("ground"); vspeed = 0;
}
if(y + vspeed <= b.worldY + b.height && y + vspeed >= b.worldY + b.height + vspeed - 1 && jumpstate=="jumping")
{
y = b.worldY + b.height; jumpstate.assign("falling"); vspeed = 0;
}
}
}
}

I'm not sure you'll get it to work like this. I'll explain a solution that I thought of for some collision detection and bouncing that works smoothly. Record the time interval from when you last checked collisions and adjusted position. If Xplayer+Vplayer*deltaT>Xtarget (if the player would overlap the target) then compute the actual time when it would be touching the target deltaTtouch=(Xtarget-Xplayer)/Vplayer. Now bounce the player back Xplayer=Xtarget-Vplayer*(deltaT-deltaTtouch). You'll have to figure out all the cases when moving forward, backward, up, down.
LE: You can also implement gravity, this involves solving a quadratic equation for finding out the deltaTtouch.

Well I can see a few little details:
1) In this line the hspeed when checking the old position is quite redundant, best to remove it for clarity.
if(x + hspeed <= b.worldX+b.width-1 && x + hspeed > b.worldX+b.width + hspeed-2)
Becomes:
if(x + hspeed <= b.worldX + b.width - 1 && x > b.worldX + b.width - 2)
Same goes for the other similar lines.
2) The small offsets of -2 and -1 are a bit confusing I presume you are trying to achieve a small buffer such that a slight amount of overlap is required. Especially this line where you have used a < instead of the <= you have used every else:
if(x + hspeed <= b.worldX+b.width-1 && x + hspeed > b.worldX+b.width + hspeed-2)
To keep consistancy with the rest of the program I would probably write:
if(x + hspeed <= b.worldX + b.width - 1 && x >= b.worldX + b.width - 1)
3) You seem to be missing a few of your small offsets in the vert checks:
So this check first:
if(y + height + vspeed >= b.worldY && y + height + vspeed <= b.worldY + vspeed + 1 && jumpstate=="falling")
You seem to have forgotten your small offset:
if(y + height + vspeed >= b.worldY + 1 && y + height <= b.worldY + 1 && jumpstate=="falling")
Then the second check:
if(y + vspeed <= b.worldY + b.height && y + vspeed >= b.worldY + b.height + vspeed - 1 && jumpstate=="jumping")
Offset again:
if(y + vspeed <= b.worldY + b.height - 1 && y >= b.worldY + b.height - 1 && jumpstate=="jumping")
4) You will need to be very careful that vspeed and jumpstate always remain in sync as the sign of vspeed needs to always match jumpstate or you will miss collisions. I imagine this might be where your problem is coming from.
5) In both directions if speed exceeds the block size you will skip collision detection and fire through the block.
if(y + height + vspeed >= b.worldY+2 && y + vspeed <= b.worldY+b.height)
The second check in these lines will be false if speed is higher than b.height and the y coords are similar.
Hope that helps some.

Related

2D obstacle collision

Hi I am trying to make 2d collision but I dont get it to work
i am doing :
if (collider.posX + collider.sizeX >= obstacle.posX && obstacle.posX + obstacle.sizeX >= collider.posX && collider.posY + collider.sizeY >= obstacle.posY)
the obstacle cannot move on the y axis so this is why i only check for
collider.posY + 50 >= obstacle.posY
the collision works but they are only start when the obstacle is half in the collider
What about:
if( obstacle.posX >= collider.posX &&
obstacle.posX <= collider.posX + collider.sizeX &&
obstacle.posY >= collider.posY &&
obstacle.posY <= collider.posY + collider.sizeY
)
This code should check if obstacle point intersects collider rectangle.
This is better solution because it detects overlapping between 2 rectangles:
if ( obstacle.posX <= collider.posX + collider.sizeX &&
obstacle.posX + obstacle.sizeX >= collider.posX &&
obstacle.posY <= collider.posY + collider.sizeY &&
obstacle.posY + obstacle.sizeY >= collider.posY )
You're running into logical errors, seen by the following code:
collider.posX + collider.sizeX >= obstacle.posX
Suppose the two colliding objects are circles with their positions being their center points. The first object is moving in the positive X direction while the second is static (stationary). You need to check if the first object's X position plus its radius (not diameter) touches the second object's X position minus its radius.
Example code:
collider.posX + (collider.sizeX / 2) >= obstacle.posX - (obstacle.sizeX / 2)
Note: The above inequality assumes that collider.sizeX represents the diameter of collider.
Presumably later on you'll also need to check if the first object is passed the second object. Since the above inequality only accounts for the first object having an increasing X position and its X position being less than the second object's X position.

Rectangle collision (C++)

I'm currently using this collision code:
( // tx = other x, tex = other end x etc.
( // horizontal collision
(xpos >= tx && xpos <= tex)
||
((xpos + w) <= tex && (xpos + w) >= tx)
)
&&
( // vertical collision
(ypos >= ty && ypos <= tey)
||
((ypos + h) <= tey && (ypos + h) >= ty)
)
)
However, it only detects if the top left pixel, the top right pixel, the bottom left pixel, or the bottom right pixel is within the rectangle to test. I don't know what to do, it already took forever to get to the current collision testing method I'm using, what can I change to fix this problem?
Do I understand correctly that one rectangle extends horizontally from xpos to xpos + w and vertically from ypos to ypos + h, and the other extends horizontally from tx to tex and vertically from ty to tey? With w, h, tex − tx, and tey − ty all being positive?
If so, then you can write:
xpos <= tex && xpos + w >= tx // horizontal collision
&& ypos <= tey && ypos + h >= ty // vertical collision
Alternatively, you may find it easier to reason about if you calculate the conditions whereby they don't collide, and just add a !:
!(
xpos > tex // first rectangle entirely to right of second
|| xpos + w < tx // first rectangle entirely to left of second
|| ypos > tey // first rectangle entirely above second
|| ypos + h < ty // first rectangle entirely below second
)
(The two versions are equivalent, due to one of De Morgan's laws.)

Determine if angle lies between 2 other angles

I am trying to figure out whether a angle lies between 2 other angles. I have been trying to create a simple function to perform this but none of my techniques will work for all possible values of the angles.
Can you help me edit my function to correctly determine if a angle lies between 2 other angles?
In the above picture; I use the green point as the central point, then I determine the angle of each line to the green point. I then calculate the angle of the black point to the green point. I am trying to check if the angle of the black dot is BETWEEN the 2 lines' angles.
NOTE: In my case; an angle(targetAngle) is said to lie between 2 other angles IF the difference between the 2 angles is < 180 degrees AND the targetAngle lies in the cavity made by those 2 angles.
The following code should work but it fails for these(which do lie between the angle):
- is_angle_between(150, 190, 110)
- is_angle_between(3, 41, 345)
bool is_angle_between(int target, int angle1, int angle2)
{
int rAngle1 = ((iTarget - iAngle1) % 360 + 360) % 360;
int rAngle2 = ((iAngle2 - iAngle1) % 360 + 360) % 360;
return (0 <= rAngle1 && rAngle1 <= rAngle2);
}
// Example usage
is_angle_between(3, 41, 345);
Another technique I attempted which also doesn't work:
int is_angle_between(int target, int angle1, int angle2)
{
int dif1 = angle1-angle2;
int dif2 = angle2-angle1;
int uDif1 = convert_to_positive_angle( dif1 ); // for eg; convert -15 to 345
int uDif2 = convert_to_positive_angle( dif2 );
if (uDif1 <= uDif2) {
if (dif1 < 0) {
return (target <= angle1 && target >= angle2);
}
else return (in_between_numbers(iTarget, iAngle1, iAngle2));
}
else {
if (dif2 < 0) {
return (target <= angle1 && target >= angle2);
}
else return (in_between_numbers(iTarget, iAngle1, iAngle2));
}
return -1;
}
bool is_angle_between(int target, int angle1, int angle2)
{
// make the angle from angle1 to angle2 to be <= 180 degrees
int rAngle = ((angle2 - angle1) % 360 + 360) % 360;
if (rAngle >= 180)
std::swap(angle1, angle2);
// check if it passes through zero
if (angle1 <= angle2)
return target >= angle1 && target <= angle2;
else
return target >= angle1 || target <= angle2;
}
Inspired by a post about Intervals in modular arithmetic:
static bool is_angle_between(int x, int a, int b) {
b = modN(b - a);
x = modN(x - a);
if (b < 180) {
return x < b;
} else {
return b < x;
}
}
where (in case of checking angles) modN() would be implemented as
// modN(x) is assumed to calculate Euclidean (=non-negative) x % N.
static int modN(int x) {
const int N = 360;
int m = x % N;
if (m < 0) {
m += N;
}
return m;
}
void normalize( float& angle )
{
while ( angle < -180 ) angle += 360;
while ( angle > 180 ) angle -= 360;
}
bool isWithinRange( float testAngle, float a, float b )
{
a -= testAngle;
b -= testAngle;
normalize( a );
normalize( b );
if ( a * b >= 0 )
return false;
return fabs( a - b ) < 180;
}
If angle2 were always 0, and angle1 were always between 0 and 180, this would be easy:
return angle1 < 180 && 0 < target && target < angle1;
if I'm reading the requirements correctly.
But it's not that hard to get there.
int reduced1 = (angle1 - angle2 + 360) % 360; // and imagine reduced2 = 0
if (180 < reduced1) { angle2 = angle1; reduced1 = 360 - reduced1; } // swap if backwards
int reducedTarget = (target - angle2 + 360) % 360;
return reduced1 < 180 && 0 < reducedTarget && reducedTarget < reduced1;
I've done this before by comparing angles.
In the sketch above vector AD will be between AB and AC if and only if
angle BAD + angle CAD == angle BAC
Because of floating point inaccuracies I compared the values after rounding them first to say 5 decimal places.
So it comes down to having an angle algorithm between two vectors p and q which is simply put like:
double a = p.DotProduct(q);
double b = p.Length() * q.Length();
return acos(a / b); // radians
I'll leave the vector DotProduct and Length calculations as a google search exercise. And you get vectors simply by subtracting the coordinates of one terminal from the other.
You should of course first check whether AB and AC are parallel or anti-parallel.
All the top answers here are wrong. As such I feel it is necessary for me to post an answer.
I'm just reposting a portion of an answer which I posted here: https://stackoverflow.com/a/42424631/2642059 That answer also deals with the case where you already know which angle is the lefthand side and righthand side of the reflexive angle. But you also need to determine which side of the angle is which.
1st to find the leftmost angle if either of these statements are true angle1 is your leftmost angle:
angle1 <= angle2 && angle2 - angle1 <= PI
angle1 > angle2 && angle1 - angle2 >= PI
For simplicity let's say that your leftmost angle is l and your rightmost angle is r and you're trying to find if g is between them.
The problem here is the seem. There are essentially 3 positive cases that we're looking for:
l ≤ g ≤ r
l ≤ g ∧ r < l
g ≤ r ∧ r < l
Since you're calculating the lefthand and righthand sides of the angle, you'll notice there is an optimization opportunity here in doing both processes at once. Your function will look like:
if(angle1 <= angle2) {
if(angle2 - angle1 <= PI) {
return angle1 <= target && target <= angle2;
} else {
return angle2 <= target || target <= angle1;
}
} else {
if(angle1 - angle2 <= PI) {
return angle2 <= target && target <= angle1;
} else {
return angle1 <= target || target <= angle2;
}
}
Or if you need it you could expand into this nightmare condition:
angle1 <= angle2 ?
(angle2 - angle1 <= PI && angle1 <= target && target <= angle2) || (angle2 - angle1 > PI && (angle2 <= target || target <= angle1)) :
(angle1 - angle2 <= PI && angle2 <= target && target <= angle1) || (angle1 - angle2 > PI && (angle1 <= target || target <= angle2))
Note that all this math presumes that your input is in radians and in the range [0 : 2π].
Live Example
Is angle T between angles A and B, there are always two answers: true and false.
We need specify what we mean, and in this case we're looking for the normalized small sweep angles and whether our angle is between those values. Given any two angles, there is a reflex angle between them, is the normalized value of T within that reflex angle?
If we rotate A and B and T such that T = 0 and normalize A and B to within +-hemicircumference (180° or 2PI). Then our answer is whether A and B have different signs, and are within a hemicircumference of each other.
If we subtract the angle from test, then add 180° (so A is relative to T+180). Then we mod by 360 giving us a range between [-360°,360°] we add 360° and mod again (note, you could also just check if it's negative and add 360 if it is), giving us a value that is certain to be [0°,360°]. We subtract 180° giving us a value between [-180°,180°] relative to T+180°-180° aka, T. So T is now angle zero and all angles fall within the normalized range. Now we check to make sure the angles have a sign change and that they are not more than 180° apart, we have our answer.
Because the question asks in C++:
bool isAngleBetweenNormalizedSmallSweepRange(int test, int a, int b) {
int a_adjust = ((((a - test + 180)) % 360) + 360) % 360 - 180;
int b_adjust = ((((b - test + 180)) % 360) + 360) % 360 - 180;
return ((a_adjust ^ b_adjust) < 0) && ((a_adjust - b_adjust) < 180) && ((a_adjust - b_adjust) > -180);
}
We can also do some tricks to simplify out the code and avoid any unneeded modulo ops (see comments below). Normalize will move angle a into the range [-180°,180°] relative to angle t.
int normalized(int a, int test) {
int n = a - test + 180;
if ((n > 360) || (n < -360)) n %= 360;
return (n > 0)? n - 180: n + 180;
}
bool isAngleBetweenNormalizedSmallSweepRange(int test, int a, int b) {
int a_adjust = normalized(a,test);
int b_adjust = normalized(b,test);
return ((a_adjust ^ b_adjust) < 0) &&
((a_adjust > b_adjust)? a_adjust-b_adjust: b_adjust-a_adjust) < 180;
}
Also if we can be sure the range is [0,360], we can make do with a simpler if statement
bool isAngleBetweenNormalizedSmallSweepRange(int test, int a, int b) {
int dA = a - test + 180;
if (dA > 360) {
dA -= 360;
}
int a_adjust = (dA > 0) ? dA - 180 : dA + 180;
int dB = b - test + 180;
if (dB > 360) {
dB -= 360;
}
int b_adjust = (dB > 0) ? dB - 180 : dB + 180;
return ((a_adjust ^ b_adjust) < 0)
&& ((a_adjust > b_adjust) ? a_adjust - b_adjust : b_adjust - a_adjust) < 180;
}
JS Fiddle test of the code
I've found this quote from this thread:
if a point P is inside triangle ABC, then
Area PAB+Area PBC +Area PAC=Area ABC
notice that if P is on the edge of AB, BC, or CA, the above hold. But
effectively, one of the area PAB, PBC, PAC is 0 (so just make sure you
check that).
if P is outside, the above equality does NOT hold...
How to determine area? you have two options: 1) Heron's theorem,
involves sqrt, slower 2) the more perferred way is the cross products
(or effectively, the half of absolute value of (sum of the down
products minus the sum of up products))
for example, if A=(x1,y1) B=(x2,y2), C=(x3,y3) Area=
abs(x1*y2+x2*y3+x3*y1-x1*y3-x3*y2-x2*y1)/2
also you might want to be careful about floating point errors...
instead of checking for strict inequality, check for abs(b-a)
Hopefully that will help
Using a similar style of function as in your question, I have had good luck with the following methods:
public static bool IsInsideRange(double testAngle, double startAngle, double endAngle)
{
var a1 = System.Math.Abs(AngleBetween(startAngle, testAngle));
var a2 = System.Math.Abs(AngleBetween(testAngle, endAngle));
var a3 = System.Math.Abs(AngleBetween(startAngle, endAngle));
return a1 + a2 == a3;
}
public static double AngleBetween(double start, double end)
{
return (end - start) % 360;
}
I know this post is old, but there doesn't seem to be an accepted answer and I have found the following approach to be quite reliable. Although it might be more than what you need. It supports angle ranges larger than 180 degrees (as well as larger than 360 degrees and negative angles). It also supports decimal accuracy.
The method uses this normalize() helper function to convert angles into the right space:
float normalize( float degrees )
{
//-- Converts the specified angle to an angle between 0 and 360 degrees
float circleCount = (degrees / 360.0f);
degrees -= (int)circleCount * 360;
if( 0.0f > degrees )
{
degrees += 360.0f;
}
return degrees;
}
Here's the solution:
bool isWithinRange( float start, float end, float angle )
{
if( fabsf( end - start ) >= 360.0f )
{
//-- Ranges greater or equal to 360 degrees cover everything
return true;
}
//-- Put our angle between 0 and 360 degrees
float degrees = normalize( angle );
//-- Resolve degree value for the start angle; make sure it's
// smaller than our angle.
float startDegrees = normalize( start );
if( startDegrees > degrees )
{
startDegrees -= 360.0f;
}
//-- Resolve degree value for the end angle to be within the
// same 360 degree range as the start angle and make sure it
// comes after the start angle.
float endDegrees = normalize( end );
if( endDegrees < startDegrees )
{
endDegrees += 360.0f;
}
else if( (endDegrees - startDegrees) >= 360.0f )
{
endDegrees -= 360.0f;
}
//-- All that remains is to validate that our angle is between
// the start and the end.
if( (degrees < startDegrees) || (degrees > endDegrees) )
{
return false;
}
return true;
}
Hope this helps someone.
If you have angles $$a$ and $b$, and wan't to see if angle x is between these angles.
You can calculate the angle between a->x and a->b.
If ∠a->x is less than ∠a->b, x must be between a and b.
The distance between to angles, a and b
function distanceBetweenAngles(a, b) {
distance = b - a;
if (a > b) {
distance += 2*pi;
}
return distance;
}
Then you can do
// Checks if angle 'x' is between angle 'a' and 'b'
function isAngleBetween(x, a, b) {
return distanceBetweenAngles(a, b) >= distanceBetweenAngles(a, x);
}
This assumes you are using Radians, and not Degrees, as one should. It removes a lot of unnecessary code.

2D Box Collision - Is this right?

Well I've got a 2D box collision code that basically loops through every block in a list called "Blocks" and it checks if I'm near the sides and whatnot.
It works very well except for the bottom of the block. When I'm jumping up towards the bottom I want my player to simply "bounce" off. It does this, but it is very glitchy.
It's hard to explain so I was hoping you guys could possibly spot out what's wrong with my bottom collision code.
Here's the entire thing:
for(unsigned int i = 0; i<blocks.size(); i++){
Block &b = blocks.at(i);
if(!b.passable==true){
//Check if we are on the sides
if(y + height + vspeed >= b.worldY+2 && y + vspeed <= b.worldY+b.height)
{
//Right side
if(x + hspeed <= b.worldX+b.width-1 && x + hspeed > b.worldX+b.width + hspeed-2)
{
x = b.worldX + b.width; hspeed = 0;
}
//Left side
if(x + width + hspeed >= b.worldX +1 && x + width + hspeed <= b.worldX + hspeed + 2)
{
x = b.worldX - width; hspeed = 0;
}
}
//Check if we are on the top or the bottom
if(x + width + hspeed >= b.worldX+2 && x + hspeed <= b.worldX+b.width-2)
{
if(y + height + vspeed >= b.worldY && y + height + vspeed <= b.worldY + vspeed + 1 && jumpstate=="falling")
{
y = b.worldY - height; jumpstate.assign("ground"); vspeed = 0;
}
if(y + vspeed <= b.worldY + b.height && y + vspeed >= b.worldY + b.height + vspeed - 1 && jumpstate=="jumping")
{
y = b.worldY + b.height; jumpstate.assign("falling"); vspeed = 0;
}
}
}
}
My guess is that you should set vspeed = -vspeed; instead of vspeed = 0. Fully elastic bouncing means that the velocity gets mirrored in the box's side.
If you set it to zero, depending on the order in which you perform your updates, you might not move during a frame. And since you use <= and >= for bounds checking, you'll still be inside the box on the next frame, invoke the bouncing behaviour again, and get stuck with your head glued to the block.
My guess at your problem would be negative numbers in your inequality checks. For example, when going down, I guess vspeed will be negative. Depending on where you have set the origin of your box, this could mean that the condition
y + vspeed <= b.worldY + b.height
is always true.
As an aside, by adding a distance to a speed, you have assumed a magic dimension for the unit time. This makes your code brittle because if you change this magic number, then your equations will be wrong.
Try,
y + vspeed*unit_time <= b.worldY + b.height
If you want to handle the units at compile-time (and not pay for that multiplication), then use boost.units.
Additionally,
x + hspeed > b.worldX+b.width + hspeed-2
can be simplified to
x > b.worldX+b.width-2
And the significance of this magic number 2 is anyones guess. (why for instance do you have
//Check if we are on the sides
if(y + vspeed <= b.worldY+b.height)
but have a -2 in
//Check if we are on the top or the bottom
if( x + hspeed <= b.worldX+b.width-2)
)

2D Box-Collisions, Platformer, my player "hovers" over blocks

If I set my player's "hspeed" variable (horizontal speed) to a slow enough speed,
then when he goes over a gap of 16x16 blocks, he will fall through as planned.
However if I set the "hspeed" variable high enough, he will go so fast that he hovers over it.
All though it works when I set it to a slow speed, it's too slow.
Here's an example:
http://img199.imageshack.us/img199/2685/demondj.png
Here's my collision code (loops through a list of blocks):
for(unsigned int i = 0; i<blocks.size(); i++){
Block &b = blocks.at(i);
if(!b.passable){
//Check if we are on the sides
if(y + height + vspeed >= b.worldY+2 && y + vspeed <= b.worldY+b.height)
{
//Right side
if(x + hspeed <= b.worldX+b.width+1 && x + hspeed > b.worldX+b.width + hspeed-1)
{
x = b.worldX + b.width; hspeed = 0;
}
//Left side
if(x + width + hspeed >= b.worldX +1 && x + width + hspeed <= b.worldX + hspeed + 1)
{
x = b.worldX - width; hspeed = 0;
}
}
//Check if we are on the top or the bottom
if(x + width + hspeed >= b.worldX+1 && x + hspeed <= b.worldX+b.width-1)
{
if(y + height + vspeed >= b.worldY && y + height + vspeed <= b.worldY + vspeed + 1 && jumpstate=="falling")
{
y = b.worldY - height; jumpstate.assign("ground"); vspeed = 0;
}
if(y + vspeed <= b.worldY + b.height && y + vspeed >= b.worldY + b.height + vspeed + 1 && jumpstate=="jumping")
{
y = b.worldY + b.height; jumpstate.assign("falling"); vspeed = 0;
}
}
}
}
Do I have a problem in my collision code?
Another problem is when I hit the bottom of a block, it's a bit glitchy.
He's supposed to bounce right off it, and he does, but he jitters if he's moving and he hits the bottom of a block.
Ok, a number of things here:
1) Too many magic numbers. Not sure exactly what the +2, +1, etc. truely mean. I'd like to see those as constants. Also, I'm paranoid about order of operations so I would surround everything in parenthesis, just in case :)
2) Unsure of what types your vars are. Assuming floats, but they feel like ints.
3) The bigger problem, your code as designed will not properly handle "large" velocity well. Something traveling faster than the width/height of your collidable area won't be reliably detected. Nor can you easily with this type of collision code. This is one side effect you are already seeing and my guess is the fudge factor adds you have contribute to the rest.
Consider using a vector based collision system instead. Treat each edge of the box as a line vector. You can then do very simple math to determine if a point starts one one side of the line and ends on the other (sign of cross product) and sign of dot will tell whether the point was within the line segment. Also, it allows your collision objects to be any shape and even makes the math extendable to 3D rather easily. This sort of system also is parallel processing friendlier as well.