I'm working on the physics for my GTA2-like game so I can learn more about game physics.
The collision detection and resolution are working great.
I'm now just unsure how to compute the point of contact when I hit a wall.
Here is my OBB class:
public class OBB2D
{
private Vector2D projVec = new Vector2D();
private static Vector2D projAVec = new Vector2D();
private static Vector2D projBVec = new Vector2D();
private static Vector2D tempNormal = new Vector2D();
private Vector2D deltaVec = new Vector2D();
// Corners of the box, where 0 is the lower left.
private Vector2D corner[] = new Vector2D[4];
private Vector2D center = new Vector2D();
private Vector2D extents = new Vector2D();
private RectF boundingRect = new RectF();
private float angle;
//Two edges of the box extended away from corner[0].
private Vector2D axis[] = new Vector2D[2];
private double origin[] = new double[2];
public OBB2D(float centerx, float centery, float w, float h, float angle)
{
for(int i = 0; i < corner.length; ++i)
{
corner[i] = new Vector2D();
}
for(int i = 0; i < axis.length; ++i)
{
axis[i] = new Vector2D();
}
set(centerx,centery,w,h,angle);
}
public OBB2D(float left, float top, float width, float height)
{
for(int i = 0; i < corner.length; ++i)
{
corner[i] = new Vector2D();
}
for(int i = 0; i < axis.length; ++i)
{
axis[i] = new Vector2D();
}
set(left + (width / 2), top + (height / 2),width,height,0.0f);
}
public void set(float centerx,float centery,float w, float h,float angle)
{
float vxx = (float)Math.cos(angle);
float vxy = (float)Math.sin(angle);
float vyx = (float)-Math.sin(angle);
float vyy = (float)Math.cos(angle);
vxx *= w / 2;
vxy *= (w / 2);
vyx *= (h / 2);
vyy *= (h / 2);
corner[0].x = centerx - vxx - vyx;
corner[0].y = centery - vxy - vyy;
corner[1].x = centerx + vxx - vyx;
corner[1].y = centery + vxy - vyy;
corner[2].x = centerx + vxx + vyx;
corner[2].y = centery + vxy + vyy;
corner[3].x = centerx - vxx + vyx;
corner[3].y = centery - vxy + vyy;
this.center.x = centerx;
this.center.y = centery;
this.angle = angle;
computeAxes();
extents.x = w / 2;
extents.y = h / 2;
computeBoundingRect();
}
//Updates the axes after the corners move. Assumes the
//corners actually form a rectangle.
private void computeAxes()
{
axis[0].x = corner[1].x - corner[0].x;
axis[0].y = corner[1].y - corner[0].y;
axis[1].x = corner[3].x - corner[0].x;
axis[1].y = corner[3].y - corner[0].y;
// Make the length of each axis 1/edge length so we know any
// dot product must be less than 1 to fall within the edge.
for (int a = 0; a < axis.length; ++a)
{
float l = axis[a].length();
float ll = l * l;
axis[a].x = axis[a].x / ll;
axis[a].y = axis[a].y / ll;
origin[a] = corner[0].dot(axis[a]);
}
}
public void computeBoundingRect()
{
boundingRect.left = JMath.min(JMath.min(corner[0].x, corner[3].x), JMath.min(corner[1].x, corner[2].x));
boundingRect.top = JMath.min(JMath.min(corner[0].y, corner[1].y),JMath.min(corner[2].y, corner[3].y));
boundingRect.right = JMath.max(JMath.max(corner[1].x, corner[2].x), JMath.max(corner[0].x, corner[3].x));
boundingRect.bottom = JMath.max(JMath.max(corner[2].y, corner[3].y),JMath.max(corner[0].y, corner[1].y));
}
public void set(RectF rect)
{
set(rect.centerX(),rect.centerY(),rect.width(),rect.height(),0.0f);
}
// Returns true if other overlaps one dimension of this.
private boolean overlaps1Way(OBB2D other)
{
for (int a = 0; a < axis.length; ++a) {
double t = other.corner[0].dot(axis[a]);
// Find the extent of box 2 on axis a
double tMin = t;
double tMax = t;
for (int c = 1; c < corner.length; ++c) {
t = other.corner[c].dot(axis[a]);
if (t < tMin) {
tMin = t;
} else if (t > tMax) {
tMax = t;
}
}
// We have to subtract off the origin
// See if [tMin, tMax] intersects [0, 1]
if ((tMin > 1 + origin[a]) || (tMax < origin[a])) {
// There was no intersection along this dimension;
// the boxes cannot possibly overlap.
return false;
}
}
// There was no dimension along which there is no intersection.
// Therefore the boxes overlap.
return true;
}
public void moveTo(float centerx, float centery)
{
float cx,cy;
cx = center.x;
cy = center.y;
deltaVec.x = centerx - cx;
deltaVec.y = centery - cy;
for (int c = 0; c < 4; ++c)
{
corner[c].x += deltaVec.x;
corner[c].y += deltaVec.y;
}
boundingRect.left += deltaVec.x;
boundingRect.top += deltaVec.y;
boundingRect.right += deltaVec.x;
boundingRect.bottom += deltaVec.y;
this.center.x = centerx;
this.center.y = centery;
computeAxes();
}
// Returns true if the intersection of the boxes is non-empty.
public boolean overlaps(OBB2D other)
{
if(right() < other.left())
{
return false;
}
if(bottom() < other.top())
{
return false;
}
if(left() > other.right())
{
return false;
}
if(top() > other.bottom())
{
return false;
}
if(other.getAngle() == 0.0f && getAngle() == 0.0f)
{
return true;
}
return overlaps1Way(other) && other.overlaps1Way(this);
}
public Vector2D getCenter()
{
return center;
}
public float getWidth()
{
return extents.x * 2;
}
public float getHeight()
{
return extents.y * 2;
}
public void setAngle(float angle)
{
set(center.x,center.y,getWidth(),getHeight(),angle);
}
public float getAngle()
{
return angle;
}
public void setSize(float w,float h)
{
set(center.x,center.y,w,h,angle);
}
public float left()
{
return boundingRect.left;
}
public float right()
{
return boundingRect.right;
}
public float bottom()
{
return boundingRect.bottom;
}
public float top()
{
return boundingRect.top;
}
public RectF getBoundingRect()
{
return boundingRect;
}
public boolean overlaps(float left, float top, float right, float bottom)
{
if(right() < left)
{
return false;
}
if(bottom() < top)
{
return false;
}
if(left() > right)
{
return false;
}
if(top() > bottom)
{
return false;
}
return true;
}
public static float distance(float ax, float ay,float bx, float by)
{
if (ax < bx)
return bx - ay;
else
return ax - by;
}
public Vector2D project(float ax, float ay)
{
projVec.x = Float.MAX_VALUE;
projVec.y = Float.MIN_VALUE;
for (int i = 0; i < corner.length; ++i)
{
float dot = Vector2D.dot(corner[i].x,corner[i].y,ax,ay);
projVec.x = JMath.min(dot, projVec.x);
projVec.y = JMath.max(dot, projVec.y);
}
return projVec;
}
public Vector2D getCorner(int c)
{
return corner[c];
}
public int getNumCorners()
{
return corner.length;
}
public static float collisionResponse(OBB2D a, OBB2D b, Vector2D outNormal)
{
float depth = Float.MAX_VALUE;
for (int i = 0; i < a.getNumCorners() + b.getNumCorners(); ++i)
{
Vector2D edgeA;
Vector2D edgeB;
if(i >= a.getNumCorners())
{
edgeA = b.getCorner((i + b.getNumCorners() - 1) % b.getNumCorners());
edgeB = b.getCorner(i % b.getNumCorners());
}
else
{
edgeA = a.getCorner((i + a.getNumCorners() - 1) % a.getNumCorners());
edgeB = a.getCorner(i % a.getNumCorners());
}
tempNormal.x = edgeB.x -edgeA.x;
tempNormal.y = edgeB.y - edgeA.y;
tempNormal.normalize();
projAVec.equals(a.project(tempNormal.x,tempNormal.y));
projBVec.equals(b.project(tempNormal.x,tempNormal.y));
float distance = OBB2D.distance(projAVec.x, projAVec.y,projBVec.x,projBVec.y);
if (distance > 0.0f)
{
return 0.0f;
}
else
{
float d = Math.abs(distance);
if (d < depth)
{
depth = d;
outNormal.equals(tempNormal);
}
}
}
float dx,dy;
dx = b.getCenter().x - a.getCenter().x;
dy = b.getCenter().y - a.getCenter().y;
float dot = Vector2D.dot(dx,dy,outNormal.x,outNormal.y);
if(dot > 0)
{
outNormal.x = -outNormal.x;
outNormal.y = -outNormal.y;
}
return depth;
}
public Vector2D getMoveDeltaVec()
{
return deltaVec;
}
};
I'm now just unsure how to compute the point of contact when I hit a
wall.
You can represent a wall with a simple plane.
The OBB-vs-plane intersection test is the simplest separating axis test of them all:
If two convex objects don't intersect, then there is a plane where
the projection of these two objects will not intersect.
A box intersects plane only if the plane normal forms a separating axis. Compute the projection of the box center and the projected radius (4 dot products and a few adds) and you're good to go (you also get penetration depth for free).
The condition looks as follows:
|d| <= a1|n*A1| + a2|n*A2| + a3|n*A3|
Here:
d distance from the center of the box to the plane.
a1...a3 the extents of the box from the center.
n normal of the plane
A1...A3 the x,y,z-axis of the box
Some pseudocode:
//Test if OBB b intersects plane p
int TestOBBPlane(OBB b, Plane p)
{
// Compute the projection interval radius of b onto L(t) = b.c + t * p.n
float r = b.e[0]*Abs(Dot(p.n, b.u[0])) +
b.e[1]*Abs(Dot(p.n, b.u[1])) +
b.e[2]*Abs(Dot(p.n, b.u[2]));
// Compute distance of box center from plane
float s = Dot(p.n, b.c) – p.d;
// Intersection occurs when distance s falls within [-r,+r] interval
return Abs(s) <= r;
}
The OBB-vs-OBB intersection test is more complicated.
Let us refer to this great tutorial:
In this case we no longer have corresponding separating lines that are
perpendicular to the separating axes. Instead, we have separating
planes that separate the bounding volumes (and they are perpendicular
to their corresponding separating axes).
In 3D space, each OBB only has 3 unique planes extended by its faces,
and the separating planes are parallel to these faces. We are
interested in the separating planes parallel to the faces, but in 3D
space, the faces are not the only concern. We are also interested in
the edges. The separating planes of interest are parallel to the faces
of the boxes, and the separating axes of interest are perpendicular to
the separating planes. Hence the separating axes of interest are
perpendicular to the 3 unique faces of each box. Notice these 6
separating axes of interest correspond to the 6 local (XYZ) axes of
the two boxes.
So there are 9 separating axes to consider for edges collision in
addition to the 6 separating axes we already have found for the faces
collision. This makes the total number of possible separating axes to
consider at 15.
Here are the 15 possible separating axes (L) you will need to test:
CASE 1: L = Ax
CASE 2: L = Ay
CASE 3: L = Az
CASE 4: L = Bx
CASE 5: L = By
CASE 6: L = Bz
CASE 7: L = Ax x Bx
CASE 8: L = Ax x By
CASE 9: L = Ax x Bz
CASE 10: L = Ay x Bx
CASE 11: L = Ay x By
CASE 12: L = Ay x Bz
CASE 13: L = Az x Bx
CASE 14: L = Az x By
CASE 15: L = Az x Bz
Here:
Ax unit vector representing the x-axis of A
Ay unit vector representing the y-axis of A
Az unit vector representing the z-axis of A
Bx unit vector representing the x-axis of B
By unit vector representing the y-axis of B
Bz unit vector representing the z-axis of B
Now you can see the algorithm behind the OBB-OBB intersection test.
Let's jump to the source code:
2D OBB-OBB: http://www.flipcode.com/archives/2D_OBB_Intersection.shtml
3D OBB-OBB: http://www.geometrictools.com/LibMathematics/Intersection/Intersection.html
P.S: This link http://www.realtimerendering.com/intersections.html will be useful to those, who wish to go beyond planes and boxes.
Related
I'm trying to visualize Mandelbrot's set with processing, and it's the first time I do something like this. My approach is pretty simple.
I have a function Z, which is literally just the set's main function (f(z)=z^2+c) and i do a loop for each pixel of the screen, every time i repeat the process of using Z() and using the result as the new z parameter in the function Z()
For some reason what shows up on the screen is only a diagonal line, and i have no idea of why that is.
Here's the full code:
void draw() {
int max_iterations = 100, infinity_treshold = 16;
for (int y = 0; y < 360; y++) {
for (int x = 0; x < 480; x++) {
float z = 0; // the result of the function, (y)
float real = map(x,0,480,-2,2); // map "scales" the coordinate as if the pixel 0 was -2 and the pixel 480 was 2
float imaginary = map(y,0,360,-2,2); // same thing with the height
int func_iterations = 0; // how many times the process of the equation has been excecuted
while (func_iterations < max_iterations) {
z = Z(z, real+imaginary);
if (abs(z) > infinity_treshold) break;
func_iterations++;
}
if (func_iterations == max_iterations) rect(x,y,1,1);
}
}
noLoop();
}
private float Z(float z, float c) {
return pow(z,2)+c;
}
The formula z = z^2 +c is meant to operate with Complex numbers. I recommend to use PVector to represent a complex number. e.g.:
private PVector Z(PVector z, PVector c) {
return new PVector(z.x * z.x - z.y * z.y + c.x, 2.0 * z.x * z.y + c.y);
}
See the example:
void setup() {
size(400, 400);
}
void draw() {
background(255);
int max_iterations = 100;
float infinity_treshold = 16.0;
for (int y = 0; y < width; y++) {
for (int x = 0; x < height; x++) {
float real = map(x, 0, width, -2.5, 1.5);
float imaginary = map(y, 0, height, -2, 2);
PVector c = new PVector(real, imaginary);
PVector z = new PVector(0, 0);
int func_iterations = 0;
while (func_iterations < max_iterations) {
z = Z(z, c);
if (z.magSq() > infinity_treshold)
break;
func_iterations++;
}
if (func_iterations == max_iterations) {
point(x, y);
}
}
}
noLoop();
}
private PVector Z(PVector z, PVector c) {
return new PVector(z.x * z.x - z.y * z.y + c.x, 2.0 * z.x * z.y + c.y);
}
See also
wikipedia - Mandelbrot set
Mandelbrot.java
You've declared z as float so it's a real number, it should be complex. I'm not familiar with processing, does it even have a complex number data type?
Another problem is at Z(z, real+imaginary) Real and imaginary are both floats, so real numbers, so their sum is a real number. You need to construct a complex number from the real and imaginary parts.
I am attempting to simulate a sphere, and shade it realistically given an origin vector for the light, and the sphere being centered around the origin. Moreover, the light's vector is the normal vector on a larger invisible sphere at a chosen point. The sphere looks off.
https://imgur.com/a/IDIwQQF
The problem, is that it is very difficult to bug fix this kind of program. Especially considering that I know how I want it to look in my head, but when looking at the numbers in my program there is very little meaning attached to them.
Since I don't know where the issue is, I'm forced to paste all of it here.
public class SphereDrawing extends JPanel {
private static final long serialVersionUID = 1L;
private static final int ADJ = 320;
private static final double LIGHT_SPHERE_RADIUS = 5;
private static final double LIGHT_X = 3;
private static final double LIGHT_Y = 4;
private static final double LIGHT_Z = 0;
private static final double DRAWN_SPHERE_RADIUS = 1;
private static final int POINT_COUNT = 1000000;
private static Coord[] points;
private static final double SCALE = 200;
public SphereDrawing() {
setPreferredSize(new Dimension(640, 640));
setBackground(Color.white);
points = new Coord[POINT_COUNT];
initializePoints();
for (int i = 0; i < points.length; i++) {
points[i].scale();
}
new Timer(17, (ActionEvent e) -> {
repaint();
}).start();
}
public void initializePoints() { //finding the points on the surface of the sphere (hopefully somewhat equidistant)
double random = Math.random() * (double)POINT_COUNT;
double offset = 2/(double)POINT_COUNT;
double increment = Math.PI * (3 - Math.sqrt(5));
for (int i = 0; i < POINT_COUNT; i++) {
double y = ((i * offset) - 1) + (offset / 2);
double r = Math.sqrt(1 - Math.pow(y, 2));
double phi = ((i + random) % (double)POINT_COUNT) * increment;
double x = Math.cos(phi) * r;
double z = Math.sin(phi) * r;
points[i] = new Coord(x, y, z);
}
}
public void drawSphere(Graphics2D g) {
g.translate(ADJ, ADJ); //shifting from origin for drawing purposes
Arrays.sort(points); //sorting points by their z coordinates
double iHat = -2 * LIGHT_X;
double jHat = -2 * LIGHT_Y; //Light vector
double kHat = -2 * LIGHT_Z;
double angL1 = 0;
if (Math.abs(iHat) != 0.0)
angL1 = Math.atan(jHat / iHat); //converting light vector to spherical coordinates
else
angL1 = Math.PI/2;
double angL2 = Math.atan(Math.sqrt(Math.pow(iHat, 2) + Math.pow(jHat, 2))/ kHat);
double maxArcLength = LIGHT_SPHERE_RADIUS * Math.PI; // maximum arc length
for (int i = 0; i < points.length; i++) {
if(points[i].checkValid()) {
double siHat = -2 * points[i].x;
double sjHat = -2 * points[i].y; //finding normal vector for the given point on the sphere
double skHat = -2 * points[i].z;
double angSF1 = -1 * Math.abs(Math.atan(sjHat / siHat)); // converting vector to spherical coordinates
double angSF2 = Math.atan(Math.sqrt(Math.pow(siHat, 2) + Math.pow(sjHat, 2))/ skHat);
double actArcLength = LIGHT_SPHERE_RADIUS * Math.acos(Math.cos(angL1) * Math.cos(angSF1) + Math.sin(angL1) * Math.sin(angSF1) * Math.cos(angL2 - angSF2)); //calculating arc length at this point
double comp = actArcLength / maxArcLength; // comparing the maximum arc length to the calculated arc length for this vector
int col = (int)(comp * 255);
col = Math.abs(col);
g.setColor(new Color(col, col, col));
double ovalDim = (4 * Math.PI * Math.pow(DRAWN_SPHERE_RADIUS, 2))/POINT_COUNT; //using surface area to determine how large size of each point should be drawn
if (ovalDim < 1) // if it too small, make less small
ovalDim = 2;
g.fillOval((int)points[i].x, (int)points[i].y, (int)ovalDim, (int)ovalDim); //draw this oval
}
}
}
#Override
public void paintComponent(Graphics gg) {
super.paintComponent(gg);
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawSphere(g);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Sphere");
f.setResizable(false);
f.add(new SphereDrawing(), BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
#SuppressWarnings("rawtypes")
private class Coord implements Comparable {
public double x;
public double y;
public double z;
public Coord(double x2, double y2, double z2) {
x = x2;
y = y2;
z = z2;
}
public void scale() {
x *= SCALE;
y *= SCALE; //drawing purposes
z *= SCALE;
}
public String toString() {
return x + " " + y + " " + z;
}
public int compareTo(Object c) {
double diff = this.z - ((Coord)c).z;
if (diff < 0)
return -1;
else if (diff > 0) //for sorting the array of points
return 1;
else
return 0;
}
public boolean checkValid() {
return (z > 0); //checks if need to draw this point
}
}
}
I was hoping to at least draw a realistic looking sphere, even if not completely accurate, and I couldn't tell you what exactly is off with mine
I am calculating distance of point from a line. But I am getting wrong distance. Following is my piece of code which is gettting distance from line.
float px,py,something,u;
px=x2-x1;
py=y2-y1;
something = px*px + py*py;
u = ((x - x1) * px + (y - y1) * py) /(something);
if( u > 1)
{
u = 1;
// MinDist=0;
}
else if (u < 0)
{
u = 0;
//MinDist=0;
}
float xx = x1 + u * px;
float yy = y1 + u * py;
float dx = xx - x;
float dy = yy - y;
float dist= (float)Math.sqrt((double)dx*dx +(double) dy*dy);
Dist is giving wrong answer.
From: http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Vector_formulation
distance(x=a+tn, p) = ||(a-p)-((a-p).n)n||
Where:
a = (x1, y1) //First point on line
n = |(x2-x1, y2-y1)| //Normalised direction vector
p = (x, y) //Query point
So, not going to do it all, but make functions and give meaningful names to help you follow the formular:
float[] a = new float[]{x1, y1};
float[] n = new float[]{x2-x1, y2-y1};
normalize(n);
float[] p = new float[]{x, y};
float[] aMinusP = subtract(a, p);
float aMinusPDotn = dot(aMinusP, n);
// vec2a.vec2b
float dot(float[] vec2a, float[] vec2b)
{
return vec2a[0]*vec2b[0] + vec2a[1]*vec2b[1];
}
// ||vec2||
float len(float[] vec2)
{
return (float)Math.Sqrt(dot(vec2, vec2));
}
// vec2/||vec2||
void normalize(float[] vec2)
{
float length = len(vec2);
vec2[0] /= length;
vec2[1] /= length;
}
// vec2a - vec2b
float[] subtract(float[] vec2a, float[] vec2b)
{
return new float[]{vec2a[0]-vec2b[0],vec2a[1]-vec2b[1]};
}
private void gotoPos()
{
spaceX = x2 - x;
spaceY = y2 - y;
if (Math.abs(spaceX) >= Math.abs(spaceY)) {
xSpeed = Math.round(spaceX * (3/Math.abs(spaceX)));
ySpeed = Math.round(spaceY * (3/Math.abs(spaceX)));
}
With this code I want to move an object to the position x2 and y2. x and y is the current position of the object. spaceX is the space that is between the object and the x position it should go to. The same for spaceY.
But I don't want the object to move more than 3 Pixels per draw.
Example: object position: x = 35, y = 22
Point it should go to: x2 = 79, y2 = 46
space between them: spaceX = 79-35 = 44, spaceY = 46-22 = 24
spaceX is bigger then spaceY so:
xSpeed = 44 * (3/44) = 3, ySpeed = 24 * (3/44) = 1.63 = 2
But it does not work like this. When I start the app the object does not go to x2 and y2.
If I change
xSpeed = spaceX;
ySpeed = spaceY;
The object moves to the position but I do not want it to go there instantly
Complete Code:
public class Sprite
{
private boolean walking = true;
private int actionWalk = 0;
private Random rnd;
private int checkIfAction;
private int nextAction = 0;
static final private int BMP_COLUMNS = 4;
static final private int BMP_ROWS = 4;
private int[] DIRECTION_TO_SPRITE_SHEET = { 1, 0, 3, 2 };
public int x=-1;
private int y=-1;
public int xSpeed;
private int ySpeed;
private int width;
private int height;
private int bottomSpace;
private Bitmap bmp;
private GameView theGameView;
private int currentFrame=0;
private int x2, y2;
private boolean isTouched;
private int spaceX, spaceY;
D
public Sprite(GameView theGameView, Bitmap bmp)
{
this.theGameView = theGameView;
this.bmp = bmp;
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
rnd = new Random();
xSpeed = 0;
ySpeed = 0;
}
public void shareTouch(float xTouch, float yTouch)
{
x2 = (int) xTouch;
y2 = (int) yTouch;
isTouched = true;
}
private void gotoPos()
{
spaceX = x2 - x;
spaceY = y2 - y;
if (Math.abs(spaceX) >= Math.abs(spaceY)) {
xSpeed = Math.round(spaceX * (3/Math.abs(spaceX)));
ySpeed = Math.round(spaceY * (3/Math.abs(spaceX)));
}
else {
xSpeed = spaceX;
ySpeed = spaceY;
}
}
D
private void bounceOff()
{
bottomSpace = theGameView.getHeight() - y;
if (x > theGameView.getWidth() - (width * theGameView.getDensity()) - xSpeed - bottomSpace / 2 || x + xSpeed < bottomSpace / 2)
{
xSpeed = -xSpeed;
}
x = x + xSpeed;
if (y > theGameView.getHeight() - (height * theGameView.getDensity()) - ySpeed || y + ySpeed < theGameView.getHeight() / 2)
{
ySpeed = -ySpeed;
}
y = y + ySpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
}
d
public void onDraw(Canvas canvas)
{
if (x == -1)
{
x = (theGameView.getWidth() / 2);
y = (theGameView.getHeight() / 2 + theGameView.getHeight() / 4);
}
if (isTouched == true)
{
gotoPos();
}
/* if (nextAction == 100)
{
action();
nextAction = 0;
}
nextAction += 1;*/
bounceOff();
int sourceX, sourceY;
if (walking == true)
{
sourceX = currentFrame * width;
}
else
{
sourceX = 0;
}
sourceY = getAnimationRow() * height;
Rect source = new Rect(sourceX, sourceY, sourceX + width, sourceY + height);
Rect destine = new Rect(x, y, (int) (x + (width * theGameView.getDensity())), (int) (y + (height * theGameView.getDensity())));
canvas.drawBitmap(bmp, source, destine, null);
}
d
private int getAnimationRow()
{
double directionDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2) + 2);
int spriteDir = (int) Math.round(directionDouble) % BMP_ROWS;
return DIRECTION_TO_SPRITE_SHEET[spriteDir];
}
}
Simple problem: you use integer arithmetic and don't understand this:
spaceX * (3/Math.abs(spaceX))
The result will be 0 in nearly all cases as 3/x with x > 3 is 0 all the time.
To make your program working use either floating point arithmetic or rewrite your formulas to work as expected.
To use floating point arithetic you have to change to
spaceX * (3.0/Math.abs(spaceX))
assuming that you variable spaceX is also floating point.
Also you can use
(spaceX * 3) / Math.abs(spaceX)
if you want to stay with integers (what I suppose).
Given points a Vector2d(x, y) and b Vector2d(x2, y2)-
Create a vector V from a to b by subtracting b from a as you did. Normalize vector V into a unit vector and multiply it with the distance you want. Then add the resulting vector to point a.
On update:
a.add(b.subtract(a).norm().multiply(d));
Depending on your vector implementation, modify properly the above pseudo code.
There is a logical fallacy in your code: what if Math.abs(spaceX) < Math.abs(spaceY))? Then your object would not move at all.
What you calculate, 'x-distance / y-distance', is usually considered angle, not speed. Speed is 'distance / time'. You can calculate the distance, and you should decide on a reasonable speed for your object. Since you know your fps -- 20 --, you can then calculate how many pixels your object needs to move in each frame.
I'm trying to maintain and then use a transformation matrix for a computer graphics program. It's a 3x3 matrix that stores scale, rotate, and translate information for (x,y) points.
My program can handle any individual case... i.e. if I only scale or only rotate it works fine. However, it does not seem to work when combining scale and rotate, and I think that has to do with how I combine rotation and scale in the code. The matrix is called transformation and is of type float. The following methods clear, rotate, scale, and translate (in that order) the matrix.
public void clearTransform()
{
transformation[0][0] = 1;transformation[0][1] = 0;transformation[0][2] = 0;
transformation[1][0] = 0;transformation[1][1] = 1;transformation[1][2] = 0;
transformation[2][0] = 0;transformation[2][1] = 0;transformation[2][2] = 1;
}
public void rotate (float degrees)
{
double r = degrees * (Math.PI/180);
float sin = (float)Math.sin(r);
float cos = (float)Math.cos(r);
transformation[0][0] *= cos;
transformation[1][1] *= cos;
if(transformation[0][1] == 0)
transformation[0][1] = -sin;
else
transformation[0][1] *= -sin;
if(transformation[1][0] == 0)
transformation[1][0] = sin;
else
transformation[1][0] *= sin;
}
public void scale (float x, float y)
{
transformation[0][0] *= x;
transformation[1][1] *= y;
}
public void translate (float x, float y)
{
transformation[0][2] += x;
transformation[1][2] += y;
}
For scale, the matrix hold info like this:
(Sx, 0, 0)
(0, Sy, 0)
(0, 0, 1)
for rotation, like this:
(cos(theta), -sin(theta), 0)
(sin(theta), cos(theta), 0)
(0, 0, 1)
for translation, this:
(1, 0, Tx)
(0, 1, Ty)
(0, 0, 1)
I don't think I'm correctly combining scale and rotate. Here is where I actually apply the transformation:
public float[] transformX(float[] x, float[] y, int n) {
float[] newX = new float[n];
for(int i = 0; i < n; i ++) {
newX[i] = (x[i] * transformation[0][0]) + (y[i] * transformation[0][1]) + transformation[0][2];
}
return newX;
}
public float[] transformY(float[] x, float[] y, int n) {
float[] newY = new float[n];
for(int i = 0; i < n; i ++) {
newY[i] = (x[i] * transformation[1][0]) + (y[i] * transformation[1][1]) + transformation[1][2];
}
return newY;
}
Where x and y are the pre-transformed point arrays, and n is the number of points
Thank you for any help!
I think the correct transformation should be: