I have various entities in my game that have hit-boxes defined by Vector array's,
one of my entities rotates slowly to follow the player's movements so naturally I need the hit-box to rotate too.
My code results in warped and distorted lines as I draw each vertex to the screen. My entites are 64 x 64 in size so + 32 indicates the center of the object.
public void rotateVertices(Vector2[] vertices, double angle) {
double cos = Math.cos(angle);
double sin = Math.sin(angle);
for(int i = 0; i < vertices.length; i++){
Vector2 v = vertices[i];
vertices[i].x = ((v.x - (x + 32)) * cos - (v.y - (y + 32)) * sin) + (x + 32);
vertices[i].y = ((v.x - (x + 32)) * sin + (v.y - (y + 32)) * cos) + (y + 32);
}
}
my constructor:
public EnemyTriBall(Handler handler, float x, float y) {
super(handler, x, y, 3, 6);
vertices[0] = new Vector2(x + 25, y + 13);
vertices[1] = new Vector2(x + 64, y + 33);
vertices[2] = new Vector2(x + 25, y + 53);
}
Here:
Vector2 v = vertices[i];
You don't make a copy of the old vector, you just reference vectices[i]. So when you do this:
vertices[i].x = ((v.x - (x + 32)) * cos - (v.y - (y + 32)) * sin) + (x + 32);
you modify x of of the original vector. Then in the next line:
vertices[i].y = ((v.x - (x + 32)) * sin + (v.y - (y + 32)) * cos) + (y + 32);
You use old v.y but new v.x which gives you weird results. The easiest fix would be to get x and y and use them instead:
float vx = vertices[i].x;
float vy = vertices[i].y;
vertices[i].x = ((vx - (x + 32)) * cos - (vy - (y + 32)) * sin) + (x + 32);
vertices[i].y = ((vx - (x + 32)) * sin + (vy - (y + 32)) * cos) + (y + 32);
There might be other issues, I did not check the formulas but I'd start with this one.
Related
I've spent almost a week to figure this out, but I still cant find a solution.
The language is Java.
Bellow is my current formula for rotating a random point:
rotatedx = (int) ((x - centerx)*Math.cos(theta) - (y - centery)*Math.sin(theta) + centerx);
rotatedy = (int) ((y - centery)*Math.cos(theta) + (y - centery)*Math.sin(theta) + centery);
Bellow is how I calculate theta (trying to make the point rotate when the user moves his/her mouse):
double dx = mousex - centerx;
double dy = mousey - centery;
theta = Math.atan2(dy, dx);
The formula works, sort of.
int onex = 100, oney = 100;
int twox = 150, twoy = 100;
int threex = 100, threey = 150;
int fourx = 150, foury = 150;
int centerx = 125, centery = 125;
onex = (int) ((onex - centerx)*Math.cos(theta) - (oney - centery)*Math.sin(theta) + centerx);
oney = (int) ((oney - centery)*Math.cos(theta) + (oney - centery)*Math.sin(theta) + centery);
twox = (int) ((twox - centerx)*Math.cos(theta) - (twoy - centery)*Math.sin(theta) + centerx);
twoy = (int) ((twoy - centery)*Math.cos(theta) + (twoy - centery)*Math.sin(theta) + centery);
threex = (int) ((threex - centerx)*Math.cos(theta) - (threey - centery)*Math.sin(theta) + centerx);
threey = (int) ((threey - centery)*Math.cos(theta) + (threey - centery)*Math.sin(theta) + centery);
fourx = (int) ((fourx - centerx)*Math.cos(theta) - (foury - centery)*Math.sin(theta) + centerx);
foury = (int) ((foury - centery)*Math.cos(theta) + (foury - centery)*Math.sin(theta) + centery);
But it only works when all point's (including the center point) X equals to it's Y, so only point one and four works. Point two and three were in a weird motion, moving back and forth passing through the center point.
Perhaps Someone could tell me how to rotate a point around another point when the user move's the mouse? or how do I convert the Theta value into degrees and rotate the point with degrees instead of theta?
Its my first time posting on this site.
You have a typo in rotating formula for rotatedy, you use (y - centery) in both expressions. There should be x in the second term:
rotatedy = (int) ((y - centery)*Math.cos(theta) + (x - centerx)*Math.sin(theta) + centery);
The same is true for oney, twoy, threey, foury.
The problem was solved, I was being stupid.
Instead of Transforming the original point's X and Y,
onex = (int) ((onex - centerx)*Math.cos(theta) - (oney - centery)*Math.sin(theta) +
centerx);
oney = (int) ((oney - centery)*Math.cos(theta) + (oney - centery)*Math.sin(theta) +
centery);
I should declare a new point, and my formula was incorrect:
newonex = (int) ((onex - centerx)*Math.cos(theta) - (oney - centery)*Math.sin(theta) +
centerx);
newoney = (int) ((onex - centerx)*Math.cos(theta) + (oney - centery)*Math.sin(theta) +
centery);
Im trying to work out how to smooth a big list of longitude latitude points i currently draw a line from point to point and interpolate each point in-between but as i change direction it shows a sharp turn where i would like to smooth this out to a neat curve, but i dont know exactly where the turns are so i need an algorithm to smooth over an average of points.
I have done some research into this already and had a look at the Bezier curve but does not work as i expect, i took the implementation that i found here.
http://sourcecodesforfree.blogspot.co.uk/2013/05/33-bezier-curve.html
I cant really find much documentation on how the Bezier Curve algorithm works, or at least not fully understanding how it works.
function bspline(lats, lons) {
var i, t, ax, ay, bx, by, cx, cy, dx, dy, lat, lon, points;
points = [];
// For every point
for (i = 2; i < lats.length - 2; i++) {
for (t = 0; t < 1; t += 0.2) {
ax = (-lats[i - 2] + 3 * lats[i - 1] - 3 * lats[i] + lats[i + 1]) / 6;
ay = (-lons[i - 2] + 3 * lons[i - 1] - 3 * lons[i] + lons[i + 1]) / 6;
bx = (lats[i - 2] - 2 * lats[i - 1] + lats[i]) / 2;
by = (lons[i - 2] - 2 * lons[i - 1] + lons[i]) / 2;
cx = (-lats[i - 2] + lats[i]) / 2;
cy = (-lons[i - 2] + lons[i]) / 2;
dx = (lats[i - 2] + 4 * lats[i - 1] + lats[i]) / 6;
dy = (lons[i - 2] + 4 * lons[i - 1] + lons[i]) / 6;
lat = ax * Math.pow(t + 0.1, 3) + bx * Math.pow(t + 0.1, 2) + cx * (t + 0.1) + dx;
lon = ay * Math.pow(t + 0.1, 3) + by * Math.pow(t + 0.1, 2) + cy * (t + 0.1) + dy;
points.push(new google.maps.LatLng(lat, lon));
}
}
return points;
}
Above code in JavaScript else logic are same just change bit variables and method as JAVA then check
Or
please find an Algorithm from this link en.wikipedia.org/wiki/Interpolation#Linear_interpolation
I'm trying to draw line over all circle surface, my current shape look like:
My wrong attempt:
for (int i = 0; i < 24; i++) {
g.drawLine(xCenter - clockRadius + i , yCenter - clockRadius + i, xCenter - clockRadius + i + 5,
yCenter - clockRadius + i + 5);
}
I'm trying to draw a full clock :
You are looking for cosinus and sinus.
Your clock is a circle, and you can easily translate your steps into degrees on that circle. If you want to have 24 steps, 12 would be 180° (or π) and 24 would be 360°, or 2π. So to get the correct angles for each index, just devide 2π (360°) by 24 and multiply it by the current index. Then feed that resulting angle to the cos and sin functions, which give you the x and y coordinates respectively:
double x = Math.cos(2 * Math.PI / 24 * i);
double y = Math.sin(2 * Math.PI / 24 * i);
Of course you can optimize the 2 and the 24 into one constant that you define somewhere and then use in your code.
I suspect that you want to draw small segments - ticks, centered at circumference and directed from the circle center. In this case use trigonometry alike hour hands drawing.
for (int i = 0; i < 24; i++) {
double ang = i * Math.Pi / 12;
g.drawLine((int) (xCenter + (clockRadius - 5) * Math.Cos(ang)),
(int) (yCenter + (clockRadius - 5) * Math.Sin(ang)),
(int) (xCenter + (clockRadius + 5) * Math.Cos(ang)),
(int) (yCenter + (clockRadius + 5) * Math.Sin(ang)));
}
You need to calculate points over 360 degree not just 24, so you have the radius and angel rotation (angel rotation from 0 to 360) to get the proper point of (x,y) we need to multiply sin or cos of angel with radius.
for (int i = 0; i < 360; i++) {
int x = (int) (clockRadius * Math.cos(i)) + xCenter;
int y = (int) (clockRadius * Math.sin(i)) + yCenter;
g.drawLine(x, y, x + 5, y + 5);
}
Note: for better result you may need to develop two loops, one for right (180) part and another for left (180) part.
Edit: to get the right direction you need to check for angel e.g:
int xV = 0, yV = 0;
if (i <= 90){
xV = 5;
yV = 5;
}
I'm trying fill my Ellipse, the code works although I was wondering if there is a more efficient approach.
This will fill the first half of the circle given a percentage. And then it will fill the second half of the circle.
Let me know if you want to see any other functions. I was mainly concerned about filling it.
public void drawOrb() {
this.icon.drawSprite(this.xPos - this.icon.getWidth() / 2, 29 - this.icon.getHeight() / 2);
int radius = 19;
fillCircleAlpha(this.xPos, this.yPos, radius, 0, 35); // Draws a filled circle given a radius and alpha value.
Ellipse2D.Double circleToAvoid = drawCircle(this.xPos - radius, this.yPos - radius, radius * 2, 0, //The inner circle.
125);
Ellipse2D.Double circleToStart = drawCircle(this.xPos - (radius + 4), this.yPos - (radius + 4),
radius * 2 + 8, 0, 150); // The outer circle.
radius = 23;
int r2 = radius * radius;
int area = r2 << 2;
int rr = radius << 1;
for (int area2 = (int) (area * progress * 2.0), i = 0; i < area2; ++i) { //
int tx = i % rr;
int ty = i / rr;
if (!circleToAvoid.contains(circleToStart.getCenterX() + tx, circleToStart.getY() + ty) //If the index is inside the circle.
&& circleToStart.contains(circleToStart.getCenterX() + tx, circleToStart.getY() + ty)) {
drawPixelsWithOpacity(16777215, this.yPos + ty - radius, 1, 1, 75, this.xPos + tx); // Used to fill each pixel within the circle.
}
}
if (progress > 0.5) {
for (int area3 = (int) (area * (progress - 0.5) * 2.0), j = 0; j < area3; ++j) {
int tx2 = j % rr;
int ty2 = j / rr;
if (!circleToAvoid.contains(circleToStart.getCenterX() - tx2, circleToStart.getMaxY() - ty2)
&& circleToStart.contains(circleToStart.getCenterX() - tx2 - 1.0,
circleToStart.getMaxY() - ty2)) {
drawPixelsWithOpacity(16777215, (int) circleToStart.getMaxY() - ty2, 1, 1, 75,
(int) circleToStart.getCenterX() - tx2 - 1);
}
}
}
radius = 19;
drawCircle(this.xPos - (radius + 4), this.yPos - (radius + 4), radius * 2 + 8, 0, 150);
}
public static void drawPixelsWithOpacity(int color, int yPos, int pixelWidth, int pixelHeight, int opacityLevel, int xPos) {
if (xPos < topX) {
pixelWidth -= topX - xPos;
xPos = topX;
}
if (yPos < topY) {
pixelHeight -= topY - yPos;
yPos = topY;
}
if (xPos + pixelWidth > bottomX)
pixelWidth = bottomX - xPos;
if (yPos + pixelHeight > bottomY)
pixelHeight = bottomY - yPos;
int l1 = 256 - opacityLevel;
int i2 = (color >> 16 & 0xff) * opacityLevel;
int j2 = (color >> 8 & 0xff) * opacityLevel;
int k2 = (color & 0xff) * opacityLevel;
int k3 = width - pixelWidth;
int l3 = xPos + yPos * width;
if (l3 > pixels.length - 1) {
l3 = pixels.length - 1;
}
for (int i4 = 0; i4 < pixelHeight; i4++) {
for (int j4 = -pixelWidth; j4 < 0; j4++) {
int l2 = (pixels[l3] >> 16 & 0xff) * l1;
int i3 = (pixels[l3] >> 8 & 0xff) * l1;
int j3 = (pixels[l3] & 0xff) * l1;
int k4 = ((i2 + l2 >> 8) << 16) + ((j2 + i3 >> 8) << 8) + (k2 + j3 >> 8);
pixels[l3++] = k4;
}
l3 += k3;
}
}
public static Ellipse2D.Double drawCircle(final int x, final int y, final int diameter, final int color, final int opacity) {
final Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
for (int i = 0; i < diameter; ++i) {
for (int i2 = 0; i2 < diameter; ++i2) {
if (circle.contains(i + x, i2 + y) && (!circle.contains(i + x - 1, i2 + y - 1) || !circle.contains(i + x + 1, i2 + y + 1) || !circle.contains(i + x - 1, i2 + y + 1) || !circle.contains(i + x + 1, i2 + y - 1))) {
drawPixelsWithOpacity(color, i2 + y, 1, 1, opacity, i + x);
}
}
}
return circle;
}
I have two equations (Distance and slope of a line formula)
d = sqrt( (x2 - x1)^2 + (y2 - y1)^2 )
m = (y2 - y1) / (x2 - x1)
Known: d, m, x1, y1
Unknown: x2, y2
The problem is the distance equation isn't linear...
Is there a way to code this in java (using Android compatible libraries) to solve? I tried doing simple guessing but it is too slow.
Thanks
EDIT: Code for triangle
Point p1 = new Point();
Point p2 = new Point();
projection.toPixels(gp1, p1);
projection.toPixels(gp2, p2);
Point p3 = new Point();
double slope = (p2.y - p1.y) / (p2.x - p1.x);
double x = 0;
if (p2.y - p1.y >= 0 && p2.x - p1.x >= 0) {
x = - Math.sqrt(600 / (1 + slope*slope)) + p2.x;
} else if (p2.y - p1.y >= 0 && p2.x - p1.x < 0) {
x = Math.sqrt(600 / (1 + slope*slope)) + p2.x;
} else if (p2.y - p1.y < 0 && p2.x - p1.x >= 0) {
x = - Math.sqrt(600 / (1 + slope*slope)) + p2.x;
} else if (p2.y - p1.y < 0 && p2.x - p1.x < 0) {
x = Math.sqrt(600 / (1 + slope*slope)) + p2.x;
}
double y = -slope*p2.x + slope*x + p2.y;
p3.set((int) x, (int) y);
double inverseSlope = 0;
if (slope == 0) {
inverseSlope = Double.MAX_VALUE;
} else {
inverseSlope = -1 / slope;
}
x = -Math.sqrt(300 / (1 + inverseSlope*inverseSlope)) + p3.x;
y = -Math.sqrt(300 / (1 + inverseSlope*inverseSlope))*inverseSlope + p3.y;
Point p4 = new Point();
p4.set((int) x, (int) y);
x = Math.sqrt(300 / (1 + inverseSlope*inverseSlope)) + p3.x;
y = Math.sqrt(300 / (1 + inverseSlope*inverseSlope))*inverseSlope + p3.y;
Point p5 = new Point();
p5.set((int)x, (int) y);
Path path = new Path();
path.moveTo(p2.x, p2.y);
path.lineTo(p4.x, p4.y);
path.moveTo(p4.x, p4.y);
path.lineTo(p5.x, p5.y);
path.moveTo(p5.x, p5.y);
path.lineTo(p2.x, p2.y);
path.moveTo(p2.x, p2.y);
canvas.drawPath(path, mPaint);
It appears it is being caused by slope is always an integer so when it is < 1 it is 0 which is not good...
Please review the algebra below:
Define
x = x2-x1
and
y = y2-y1
Then
m * x = y
and
d^2 = x^2 + m^2 * x^2 = (1 + m^2) * x^2
Therefore
x = sqrt(d^2 / (1 + m^2))
then
x2 - x1 = sqrt(d^2 / (1 + m^2))
so
x2 = sqrt(d^2 / (1 + m^2) + x1
Similarly
y = sqrt(d^2 / (1 + m^2)) * m
y2 = sqrt(d^2 / (1 + m^2)) * m + y1
So the answer is:
x2 = sqrt(d^2 / (1 + m^2)) + x1
y2 = sqrt(d^2 / (1 + m^2)) * m + y1
the "library" you're looking for is called mathematics :)
you can ask wolfram alpha:
http://www.wolframalpha.com/input/?i=solve+d+%3D+sqrt%28+%28x2+-+x1%29%5E2+%2B+%28y2+-+y1%29%5E2+%29%2C+m+%3D+%28y2+-+y1%29+%2F+%28x2+-+x1%29+over+the+reals
(don't ask me why it knows x2 and y2 are interresting)
you can do such things by hand, but be very careful not to drop signs. even though this stuff is taught in school they have little respect for detail. note that in this case there are two possible solutions and you need ensure that d > 0 in all cases!