I have a sprite in my game and I want to get it's center coordinates. The sprite can be rotated though so I can't just get it's x/y coordinates then add half of the sprite's width/height because the getWidth and getHeight methods return the dimensions of the original, unrotated sprite.
I tried getSceneCenterCoordinates() but that for some reason returns the same coordinates for all sprites even if they are nowhere near each other.
Here's a graphic to describe what I want, the red dot is the coordinate I want, and the width/height labels on the right side figure respresent what I WANT the getWidth/Height methods to return (but they don't):
You can use coordinates transformer
final float[] spriteCoordinates = sprite.convertLocalToSceneCoordinates(x,y);
final float canonX = spriteCoordinates[VERTEX_INDEX_X];
final float canonY = spriteCoordinates[VERTEX_INDEX_Y];
Sprite sprite_in_fixedpoint_of_the_first_sprite=new Sprite(canonX,canonY,textureregion)
Get the minimum and maximum value of all the corners (for both - x and y components).
Then take average from max and min to get middle:
middleX = (maxX + minX) / 2
Repeat the same for y component.
Consider something like this
Rectangle test = new Rectangle(100, 100, 50, 100, vboManager);
mainScene.attachChild(test);
System.out.println("Before RotCtrX = " + test.getRotationCenterX());
System.out.println("Before RotCtrY = " + test.getRotationCenterY());
test.setRotation(45);
System.out.println("After RotCtrX = " + test.getRotationCenterX());
System.out.println("After RotCtrY = " + test.getRotationCenterY());
and the result are
System.out(4526): Before RotCtrX = 25.0
System.out(4526): Before RotCtrY = 50.0
System.out(4526): After RotCtrX = 25.0
System.out(4526): After RotCtrY = 50.0
AndEngine Entities rotate around the center (unless you change the RotationCenter values), so applying setRotate() will not affect the "center" point location
those "center" points are relative to the Entity, so if you need the actual screen coordinates, you will need to add those to the getX() and getY() values - which BTW also won't change based solely on applying a setRotate()
I figured out how to use getSceneCenterCoordinates() properly, which is to hand it a float[]. Here is my solution:
float[] objCenterPos = new float[2];
obj.sprite.getSceneCenterCoordinates(objCenterPos);
Log.d(this.toString(), "Coordinates: ("+objCenterPos[0]+","+objCenterPos[1]+")");
Related
Currently i am trying to render a rectangle between the mouse and a body the catch is I want the line to have a maximum length.
Meaning when the distance between the 2 points on the screen is less than a certain amount the rectangle should be between the mouse and body. If not the rectangle should be between a radius(point on the line from body to mouse) and the body.
I am using some vector logic to calculate the point to draw but when I seem to go inside my if statement the line which is drawn in under 200 distance just disappears.
ShapeRenderer sr = new ShapeRenderer();
sr.setColor(Color.WHITE);
sr.begin(ShapeRenderer.ShapeType.Filled);
if (ballPosition.dst(mousePos) > 200) {
System.out.println("Entered If!");
//Calculate point a distance away from ballPosition
Vector2 cloneMousePos = new Vector2(mousePos);
Vector2 dir = cloneMousePos.sub(ballPosition);
dir = dir.nor().scl(100);
Vector2 test = ballPosition.add(dir);
mousePos = test;
}
System.out.println("MousePos: " + mousePos.x + ", " + mousePos.y);
sr.rectLine(ballPosition, mousePos, 4f);
sr.end();
This is inside a Screen class I find it strange since when the distance is less than 200 the line draws perfectly, though from printing the x,y coordinates of the vectors it seems to be checking out.
Prints of the x,y coordinates of mousepos before moving a distance 200 out of body and after
MousePos: 213.0, 325.0
Entered If!
MousePos: 305.3836, 357.63123
EDIT:
On suggestion in the comments I have added some pictures.
Here a line between the ball and mouse is being drawn since the distance is under 200.
while here the distance becomes over 200 and we enter the if statement no line is drawn anymore unless we return to under 200.
Thanks!
Vector2 has a limit method to limit the length if greater than a certain value.
Vector2 dir = new Vector(mousePos).sub(ballPosition)
dir.limit(200f)
sr.rectLine(ballPosition, dir.add(ballPosition), 4f);
I am working on a 2D java game engine using AWT canvas as a basis. Part of this game engine is that it needs to have hitboxes with collision. Not just the built in rectangles (tried that system already) but I need my own Hitbox class because I need more functionality. So I made one, supports circular and 4-sided polygon shaped hitboxes. The way the hitbox class is setup is that it uses four coordinate points to serve as the 4 corner vertices that connect to form a rectangle. Lines are draw connecting the points and these are the lines that are used to detect intersections with other hitboxes. But I now have a problem: rotation.
There are two possibilities for a box hitbox, it can just be four coordinate points, or it can be 4 coordinate points attached to a gameobject. The difference is that the former is just 4 coordinates based on 0,0 as the ordin while the attached to gameobject stores offsets in the coordinates rather than raw location data, so (-100,-100) for example represents the location of the host gameobject but 100 pixels to the left, and 100 pixels up.
Online I found a formula for rotating points about the origin. Since Gameobject based hitboxes were centered around a particular point, I figured that would be the best option to try it on. This code runs each tick to update a player character's hitbox
//creates a rectangle hitbox around this gameobject
int width = getWidth();
int height = getHeight();
Coordinate[] verts = new Coordinate[4]; //corners of hitbox. topLeft, topRight, bottomLeft, bottomRight
verts[0] = new Coordinate(-width / 2, -height / 2);
verts[1] = new Coordinate(width / 2, -height / 2);
verts[2] = new Coordinate(-width / 2, height / 2);
verts[3] = new Coordinate(width / 2, height / 2);
//now go through each coordinate and adjust it for rotation
for(Coordinate c : verts){
if(!name.startsWith("Player"))return; //this is here so only the player character is tested
double theta = Math.toRadians(rotation);
c.x = (int)(c.x*Math.cos(theta)-c.y*Math.sin(theta));
c.y = (int)(c.x*Math.sin(theta)+c.y*Math.cos(theta));
}
getHitbox().vertices = verts;
I appologize for poor video quality but this is what the results of the above are: https://www.youtube.com/watch?v=dF5k-Yb4hvE
All related classes are found here: https://github.com/joey101937/2DTemplate/tree/master/src/Framework
edit: The desired effect is for the box outline to follow the character in a circle while maintaining aspect ratio as seen here: https://www.youtube.com/watch?v=HlvXQrfazhA . The current system uses the code above, the effect of which can be seen above in the previous video link. How should I modify the four 2D coordinates to maintain relative aspect ratio throughout a rotation about a point?
current rotation system is the following:
x = x*Cos(theta) - y *Sin(theta)
y = x*Sin(theta) + y *Cos(theta)
where theta is degree of rotation in raidians
You made classic mistake:
c.x = (int)(c.x*Math.cos(theta)-c.y*Math.sin(theta));
c.y = (int)(c.x*Math.sin(theta)+c.y*Math.cos(theta));
In the second line you use modified value of c.x. Just remember tempx = c.x
before calculations and use it.
tempx = c.x;
c.x = (int)(tempx*Math.cos(theta)-c.y*Math.sin(theta));
c.y = (int)(tempx*Math.sin(theta)+c.y*Math.cos(theta));
Another issue: rounding coordinates after each rotation causes distortions and shrinking after some rotations. It would be wise to store coordinates in floats and round them only for output, or remember starting values and apply rotation by accumulated angle to them.
I draw a rectangle with coordinates (x = 100, y = 100, width = 200, height = 100). Then I turn the shape of this rectangle around the center.
this.rotation.addListener((obs, old, fresh) -> {
Rotate rotate = new Rotate();
rotate.setAngle((double) fresh - (double) old);
rotate.setPivotX(x.getValue().doubleValue() + (width.getValue().doubleValue() / 2));
rotate.setPivotY(y.getValue().doubleValue() + (height.getValue().doubleValue() / 2));
shape.getTransforms().addAll(rotate);
});
How now to find out the coordinates of shape?
You can use the localToParent method to transform a point from the coordinate system of the Rectangle to the coordinate system of the parent.
Point2D topLeftInParent = shape.localToParent(shape.getX(), shape.getY());
If you simply need the x/y range in the parent where the Rectangle is displayed, you could also use getBoundsInParent:
Bounds parentBounds = shape.getBoundsInParent();
BTW: I do not recommend adding a new transform on every change. Instead I recommend adjusting the existing rotation:
Rotate rotate = new Rotate(0, shape.getX() + shape.getWidth()/2, shape.getX() + shape.getHeight()/2);
shape.getTransforms().add(rotate);
rotate.angleProperty().bind(this.rotation);
I am trying to create a Shape with the centre of the ship being in the middle.
one.x and one.z is the X and Z positions of the ship. The ship size is about 100 on the X, and 50 on the Z.
Shape my = new Rectangle(
(int) one.x - disToLeft, // upper-left corner X
(int) one.z - disToTop, // upper-left corner Y
disToLeft + disToRight, // width
disToTop + disToBottom // height
);
I'm then rotating the Shape, to of course be facing the correct way. This appears to work:
int rectWidth = (disToLeft + disToRight);
int rectHeight = (disToTop + disToBottom);
AffineTransform tr = new AffineTransform();
// rotating in central axis
tr.rotate(
Math.toRadians(one.rotation),
x + (disToLeft + disToRight) / 2,
z + (disToTop + disToBottom) / 2
);
my = tr.createTransformedShape(my);
I am then doing the exact same thing with another Shape, and testing for intersection. This works.
However, it feels like the Shape is the incorrect dimensions. Or something. My ship is colliding very far out to one side (outside where it graphically exists), but through the other side, I can almost go right through the ship before any collision is detected!
Basically the Shapes are simply intersecting at the wrong location. And I cannot work out why. Either the shape, the location, or the rotation must be wrong.
int disToLeft = 100;
int disToRight = 100;
int disToTop = 150;
int disToBottom = 100;
These are the distance from the centre to the left, right, top, and bottom sides.
I am using Z instead of Y because my game is in a 3D world and the sea level is pretty much the same (hence I don't need to worry about Y axis collision!).
Update:
After doing a lot of testing, I have discovered that the top of the rectangle is in the middle! I have done a lot of messing around, but without being able to graphically see the squares, it's been very hard to test.
This means that the box is on the side of the ship, like this:
Obviously when the ship on the left rotates to what it's like in this picture, a collision is detected.
It seems that your rotation is wrong. From my understanding of math it should be
tr.rotate(Math.toRadians(one.rotation), x + (disToRight - disToLeft) /2, z + (disToBottom - disToTop) /2);
Note the signs and the order of the variables
Edit:
Let's take apart the formula:
Your Rectangle is defined like this:
x-coordinate (x): one.x-disToLeft
y-coordinate (y): one.z-disToTop
width: disToLeft+disToRight
height: disToTop+disToBottom
The centre of the Rectangle (where you are rotating) is therefore:
(x+width/2)
(y+height/2)
if you replace x, width, y and height with the declarations above you get
(one.x-disToLeft + (disToLeft+disToRight)/2)
(one.z-disToTop + (disToTop+disToBottom)/2)
This is already the point you need, but it can be simplyfied:
one.x- disToLeft + (disToLeft+disToRight)/2
is equal to
one.x-(2*disToLeft/2)+(disToLeft/2)+(disToRight/2)
is equal to
one.x-(distoLeft/2) + (disToRight/2)
is equal to
one.x+(disToRight-disToLeft)/2
The other coordinate works exactly the same.
Im developing simple game. I have cca. 50 rectangles arranged in 10 columns and 5 rows. It wasn't problem to put them somehow to fit the whole screen. But when I rotate the canvas, let's say about 7° angle, the old coordinates does't fit in the new position of the coordinates. In constructor I already create and define the position of that rectangles, in onDraw method I'm drawing this rectangles (of course there are aready rotated) bud I need some method that colliding with the current rectangle. I tried to use something like this (i did rotation around the center point of the screen)
int newx = (int) ((x * Math.cos(ROTATE_ANGLE) - (y * Math.sin(ROTATE_ANGLE))) + width / 2);
int newy = (int) ((y * Math.cos(ROTATE_ANGLE) + (x * Math.sin(ROTATE_ANGLE))) + height / 2);
but it doesn't works (becuase it gives me absolute wrong new coordinates). x and y are coordinates of the touch that I'm trying to calculate new position in manner of rotation. ROTATE_ANGLE is the angle of rotation the screen.
Does anybody know how to solve this problem, I already go thorough many articles, wiki, wolframalpha categories but not luck. Maybe I just need some link to understand problem more.
Thank you
You use a rotation matrix.
Matrix mat = new Matrix(); //mat is identity
mat.postRotate(ROTATE_ANGLE); //mat is a rotation matrix of ROTATE_ANGLE degrees
float point[] = {10.0, 20.0}; //create a new float array representing the point (10, 20)
mat.mapPoints(point); //rotate the point by the requested amount
Ok, find the solution.
First it is important to convert from angle to radian
Then I personly need to negate that radian value.
That's all, this solution is correct