Object not moving in correct direction - java

Alright, I'm trying to do some simple object moving in the direction of where you touched the screen.
If I touch directly northwest of the object, it'll kind of move into the direction of the touch position. If I touch directly southeast of the object, it will kind of move into the direction of the touch position as well. However, if I touch directly northeast of the object, it'll move into the opposite direction towards the southwest. If I touch directly southwest of the object, it'll also move to the opposite direction towards northeast.
Also, if I touch north of the object, but just a little to the west, it will go straight west with a little to the north. Same with touching west of the object with a little bit to the north, it'll go straight north with a little bit to the west. Same thing for other directions.
Really, all the directions are from somewhat to obviously incorrect. I've been doing some paper calculations as well and I've seemed to be getting some correct angles, but at this point I'm completely stumped.
Does anyone know what the problem may be?
package com.badlogic.androidgames.texasholdem;
import java.util.List;
import android.util.FloatMath;
import com.badlogic.androidgames.framework.Game;
import com.badlogic.androidgames.framework.Graphics;
import com.badlogic.androidgames.framework.Input.TouchEvent;
import com.badlogic.androidgames.framework.Screen;
public class MainMenuScreen extends Screen {
public static float TO_RADIANS = (1 / 180.0f) * (float) Math.PI;
public static float TO_DEGREES = (1 / (float) Math.PI) * 180;
float num_x = 0; // Position of object on X axis
float num_y = 0; // Position of object on Y axis
float angle = 0;
public MainMenuScreen(Game game) {
super(game);
}
public void update(float deltaTime) {
Graphics g = game.getGraphics();
List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
game.getInput().getKeyEvents();
int len = touchEvents.size();
for(int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if(event.type == TouchEvent.TOUCH_UP) {
if(inBounds(event, 0, 0, g.getWidth(), g.getHeight()) ) {
// Calculate the angle of the direction between two points
angle = (float) Math.atan2(event.x - num_x, event.y - num_y) * TO_DEGREES;
if (angle < 0)
angle += 360;
// This is just to give me numbers on the Math.atan2 result, angle, to/from X position, and to/from Y position
System.out.println("Pressed! - ATAN: " + Math.atan2(event.x - num_x, event.y - num_y)
+ " - ANGLE:" + angle + " - POS: " + event.x + "tx/"
+ (int)num_x + "fx " + event.y + "ty/" + (int)num_y + "fy");
}
}
}
// Moving object in direction at 1f speed
num_x += (1f * (float) Math.cos(angle * TO_RADIANS));
num_y += (1f * (float) Math.sin(angle * TO_RADIANS));
}
private boolean inBounds(TouchEvent event, int x, int y, int width, int height) {
if(event.x > x && event.x < x + width - 1 &&
event.y > y && event.y < y + height - 1)
return true;
else
return false;
}
public void present(float deltaTime) {
Graphics g = game.getGraphics();
g.drawPixmap(Assets.background, 0, 0);
g.drawPixmap(Assets.backcard, (int)num_x, (int)num_y);
}
public void pause() {
Settings.save(game.getFileIO());
}
public void resume() {
}
public void dispose() {
}
}

if event x> x then x must be positive to move toward event.x
the problem here is that when event.x< x then your moving x must be negative
int dx,dy;
dx = (1f * (float) Math.cos(angle * TO_RADIANS));
dy = (1f * (float) Math.sin(angle * TO_RADIANS));
if(event.x<x){
dx=-dx;}
if(event.y<y){
dy=-dy;}
num_x+=dx;
num_y+=dy;
this way is simpler but less precise....
public void update(){
//(find dif between item x, and touch x)
float xdif=destx-x;
float ydif=desty-y;
if(x<destx){
dx=xdif/8;
}
else if(x>destx){
//we devide both x and y differences by the same number
dx=xdif/8;
}
else if(x==destx){
dx=0;
}
if(y<desty){
dy=ydif/5;
}
else if(y>desty){
dy=ydif/5;
}
else if(y==desty){
dy=0;
}
x+=dx;
y+=dy;
there u go, pathing in a straight line between two points, item.x and touch x.

Firstly, the math - I think the problem is that, for example, tan(135deg) = tan (-45deg) = -1. Therefore, atan has return values ranging between -90deg and 90deg as a resolution to ambiguity (look at its graph here). I think La5t5tarfighter's solution - negating the x movement in some cases - is on the right track, but you need to negate the y component in those cases as well. You could try that, but it would be much simpler if you used libGDX's Vector2 class. This is how I'd do it:
move.set(touchX, touchY); // y should be through flipping or unproject() before this
move.sub(objectPos); // move now points from object to where you touched
move.nor(); // now 1 unit long
move.scl(SPEED*deltaTime); // multiplied by a constant and delta - framerate-independent
objectPos.add(move);
You could even chain it into just one line if you want:
objectPos.add(move.set(x,y).sub(objectPos).nor().scl(SPEED*deltaTime));
Secondly, you're not using a Camera. I'm not completely sure what the default coordinate system is, but I believe the y axis points up which is not the same as the one used for inputs - Input.getY() is given with an y axis pointing down from the top left corner. If you had a Camera, you'd do this:
cam.unproject(someVector.set(Gdx.input.getX(), Gdx.input.getY(), 0));
Lacking that, you might need to flip the y axis:
event.y = Gdx.graphics.getHeight() - event.y;
Still, this could be wrong. Try drawing the object right at the touch position - if I'm right in this, it'll seem mirrored vertically. If it draws correctly where you touch, ignore this part.

Related

How do you make a Bitmap image point forward the entire time it's moving and turning?

Is there some sort of formula for rotating the arrow in this link right here to make sure it's always pointing toward the red? Each time I've tried, I'd always get a number that's off, and the arrow's rotation is not in sync with the arrow's turning and movement.
A couple of snippets of code to show what I'm working with:
arrow.moveX(true);
arrow.moveY(true);
if(arrow.turning) {
arrow.turn(player.direction / (0.75 * arrow.getSpeed()));
}
The arrow's speed is 12.5 units/time if that's important. As for the movement itself:
public void moveX(boolean turn) {
if(turn) {
x += speed * Math.cos(angle);
} else {
x += speed;
}
}
public void moveY(boolean turn) {
if(turn) {
y += speed * Math.sin(angle);
} else {
y += speed;
}
}
I'm trying to figure out how to render the arrow's sprite make sure that the pointer itself is facing that "forward" direction that it's moving in, no matter how much it rotates. Here is the render method itself if that's necessary:
#Override
public void render(Canvas c, Paint p) {
matrix.setTranslate((float)x, (float)y);
if(alive) {
matrix.postRotate(drawnAngle, (float) (x + width / 2), (float) (y + height / 2));
} else {
matrix.postRotate(angle, (float) (x + width / 2), (float) (y + height / 2));
angle += speed * 2;
}
c.drawBitmap(getSprite(), matrix, p);
}
The variable drawnAngle has a value of 0 right now, it's a placeholder. It was just my attempt of trying to find the right number to rotate the arrow by.
So I've actually spent hours trying to figure this out, and the moment I decide to post for help, I figured it out! It turns out that while I was using radians in the first snippet of code (the actual movement), I was supposed to be using degrees in the actual rotate in that last snippet!
I changed drawnAngle to (float)(angle * (180 / Math.PI)) and this worked as a solution for me!
Hopefully no one else has this problem.

Centering Camera onto object

I have a Camera class that basically follows the player around the map and keeps him centered on the screen. The math im applying works great until the scale(Zooming in and OUt) of the camera is altered. Here it is:
x = -cell.x - cell.mass/2 + Game.width/2 / sX;
// Where x is the Camera's X, Cell is the Player and sX is the scale factor
I've been playing around with different equations but they all fail once the scale is altered. I can't seem to wrap my head around this and I could really use some insight on how to factor it in.
Here are some bits of the Camera Class:
public void set(Graphics bbg){
Graphics2D g2 = (Graphics2D)bbg;
g2.translate(x, y);
g2.scale(sX, sY);
}
public void unset(Graphics bbg){
Graphics2D g2 = (Graphics2D)bbg;
g2.translate(-x, -y);
}
public void scale(double sx, double sy){
sX = sx;
sY = sy;
}
public void Update(Cell cell){
scale(0.9,0.9);
x = -cell.x - cell.mass/2 + Game.width/2 / sX;
y = -cell.y - cell.mass/2 + Game.height/2 / sY;
}
public double toWorldX(int x){
return x - this.x / sX;
}
public double toWorldY(int y){
return y - this.y / sY;
}
The first image displays the result when the scale factor is 1(Normal Zoom). The second image displays the result when the scale factor is 0.9(Zoomed Out).
I'm having a little difficulty in determining what some of your variables mean (such as cell.mass, I'm assuming it is the size) and I assume that Game.width is the actual width of the window. It would help to know what EXACTLY happen when the zoom is changed (like is the "center" of the zoom at a particular corner of the screen).
Now for an answer, without know what happens to the actual zoom... have you tried the addition of parenthesis like this...
x = ((cell.x + cell.mass/2) - Game.width/2) / sX;
or (because you use '-' a lot, I'm not sure how your coordinates work)
x = ((-cell.x - cell.mass/2) + Game.width/2) / sX;
Just an idea.
The working equation for making the camera follow a player while factoring a scale factor is:
x =((cell.x + cell.mass * 0.5) - Game.width/sX * 0.5);

drawCircle of Android's canvas draws not a circle

I'm trying to draw a circle on my canvas. Pseudocode of my algorithm looks like that
double R = 1.0;
// Draw 11 points, lying on the circle with the radius of 1
// and angle from 0 to 90 degrees
for(int i=0; i<=10; i++)
{
drawPoint( R*cos(PI*i/20), R*sin(PI*i/20) );
}
// Draw a circle with center at the (0; 0) and with the radius of 1
drawCircle(0, 0, R);
That's what I've got:
Looks fine, but there is one problem. When I increase radius only points with angles 0, 45 and 90 lie on a circle.
That's how it looks 72 degrees:
There is no any info about accuracy of the method drawCircle on developer.android.com.
I guess that it draws, based on the values at points with angles 0, 45, 90, ..., and calculate line in other positions very approximately.
I know, that I can draw circle as accurate as I want to, if I'll draw it like a polyline with tiny step, but it will work very slow.
So I want to find out - is there any methods to draw circle accurate in Android?
UPD 1:
How do I draw a points:
int x, y;
x = getPixelX(point.getX());
y = getPixelY(point.getY());
canvas.drawCircle(x, y, point.radius, paint);
Where getPixelX and getPixelY takes a coorditate of the point on plane and returns the same coordinate on the screen, basing on scale and offset.
I thought that I could make some mistake in those methods, but they work perfectly with the lines. I can zoom in lines and there is no error, all the points lies just on the line.
UPD 2:
There are comments, that probably I make a mistake in my calculations. I do not argue, perhaps you're right. So here is my "calculations".
How do I zoom in:
public void mouseWheelMoved(MouseWheelEvent e) {
// zoomQ is 0.9 or 1.1
double zoomQ = (e.getWheelRotation() + 10) / 10.0;
scaleX *= zoomQ;
scaleY *= zoomQ;
}
How do I move the plane:
public void mouseDragged(MouseEvent e) {
centerX -= (e.getX() - lastMouseX)/scaleX;
centerY -= (e.getY() - lastMouseY)/scaleY;
lastMouseX = e.getX();
lastMouseY = e.getY();
}
How do getPixelX/Y works:
public int getPixelX(double planeX) {
return (int)Math.round( scaleX*(planeX - centerX) + ScreenWidth/2 );
}
public int getPixelY(double planeY) {
return (int)Math.round( scaleY*(planeY - centerY) + ScreenHeight/2 );
}

Basic 2D path finding (no graph needed)

I am working on a game (just for my own fun) in Processing (a variant of Java), and have run into a problem. I have a projectile class that is created and managed by a Castle class, and it goes towards an Enemy class (which is a moving target). What I am trying to do (conceptually) is make this projectile find its intended target (Euclidian distance), say its 20 units away, and move 5 units along that line (i.e. 1/4 of the way there). My problem is that I don't know how to extract the x and y components of that vector to update this projectile's position. Here is my projectile class currently:
class Projectile{
private PImage sprite;
private Enemy target;
private int x;
private int y;
private int speed;
public Projectile(PImage s, Enemy t, int startx, int starty, int sp) throws NullPointerException{
if(t == null){
if(debug){
println("Null target given to Projectile(), throwing exception");
}
throw new java.lang.NullPointerException("The target of the projectile is null");
}
sprite = s;
target = t;
x = startx;
y = starty;
speed = sp;
if(debug){
println("Projectile created: " + t + " starting at position: " + startx + " " + starty);
}
}
public void update(){
if(target != null){
int goingToX = target.getCenterX() ;
int goingToY = target.getCenterY();
//find the total distance to the target
float d = dist(this.x, this.y, target.getCenterX(), target.getCenterY());
//divide it by the velocity vector
d /= speed;
//get the dx and dy components of the vector
}else{//target is null, i.e. already destroyed by something else
//destroy this projectile
//if the higher functions were correct, then nothing needs to go here
//this should be deleted as long as it checks for this.hitTarget()
return;
}
}
public void render(){
image(sprite, x, y, 10, 10);
}
//checks if it hit the target, but does a little bit of rounding because the sprite is big
//done this way in the interest of realism
public boolean hitTarget(){
if(target != null){
if(abs(x - target.getCenterX()) <= 5 && abs(y - target.getCenterY()) <= 5 ){
return true;
}else{
return false;
}
}
//this activates if the target is null, which marks this for deletion
return true;
}
}
I've been researching this for hours and realized my approach was unnecessarily complicated when I was looking into converting floats into strings, formatting them to some number of decimal places, then trying to convert that into a fraction which I would then reduce. I feel like this is far easier than I realize, but I am lacking the math background to do it. All necessary changes should only need to be done in Projectile.update(). Thanks!
Assuming that you want your projectile to 'track' the target, then you can use a simple bit of trig to work out the relative speeds in x and y:
//Calculate the differences in position
float diffX = target.getCenterX() - this.x;
float diffY = target.getCenterY() - this.y;
//Calculate the angle
double angle = Math.atan2(diffY, diffX);
//Update the positions
x += Math.cos(angle) * speed;
y += Math.sin(angle) * speed;
This essentially calculates the angle between the projectile and the target, then moves the projectile in that direction, based on the speed given.

OpenGL + Processing: Rotate and move based on direction

I'm trying to rotate and move a triangle into a certain direction, based on the pointing direction of the triangle. In theory, I calculate the sine and cosine of the direction (0-360 degrees) and add these values to the x- and y-position, right? It just doesn't work.
Also, the triangle should point up in the beginning, not down.
public void speedUp() {
float dirX, dirY;
speed *= acceleration;
if(speed > 50) speed = 50;
println("dir: " + direction + " x: " + cos(direction) + " y: " + sin(direction));
dirX = cos(direction);
dirY = sin(direction);
xPos+=dirX;
yPos+=dirY;
}
public void redraw() {
GL gl = pgl.beginGL(); // always use the GL object returned by beginGL
gl.glTranslatef(xPos, yPos, 0);
gl.glRotatef(direction, 0, 0, 1000);
gl.glBegin(GL.GL_TRIANGLES);
gl.glColor4f(0.1, 0.9, 0.7, 0.8);
gl.glVertex3f(-10, -10, 0); // lower left vertex
gl.glVertex3f( 10, -10, 0); // lower right vertex
gl.glVertex3f( 0, 15, 0); // upper vertex
gl.glEnd();
}
It looks like you need to convert from polar coordinates(moving about using an angle and a radius) to cartesian coordinates(moving about using the x and y).
The formula looks a bit like this:
x = cos(angle) * radius;
y = sin(angle) * radius;
So, as #Lie Ryan mentions, you also need to multiply with speed (which is your radius in polar coordinates).
Either have your angle in degrees but use radians() when using cos,sin as they work with radians, or use radians, and use degrees() with glRotatef, up to you
Also, you might want to have a look at glPushMatrix() and glPopMatrix(). Bascially, they allow you to nest transformations. Whatever transformations you do withing the blocks, they affect just that block locally.
Here's what I mean, use w,a,s,d keys:
import processing.opengl.*;
import javax.media.opengl.*;
float direction = 0;//angle in degrees
float speed = 0;//radius
float xPos,yPos;
void setup() {
size(600, 500, OPENGL);
}
void keyPressed(){
if(key == 'w') speed += 1;
if(key == 'a') direction -= 10;
if(key == 'd') direction += 10;
if(key == 's') speed -= 1;
if(speed > 10) speed = 10;
if(speed < 0) speed = 0;
println("direction: " + direction + " speed: " + speed);
}
void draw() {
//update
xPos += cos(radians(direction)) * speed;
yPos += sin(radians(direction)) * speed;
//draw
background(255);
PGraphicsOpenGL pgl = (PGraphicsOpenGL) g;
GL gl = pgl.beginGL();
gl.glTranslatef(width * .5,height * .5,0);//start from center, not top left
gl.glPushMatrix();
{//enter local/relative
gl.glTranslatef(xPos,yPos,0);
gl.glRotatef(direction-90,0,0,1);
gl.glColor3f(.75, 0, 0);
gl.glBegin(GL.GL_TRIANGLES);
gl.glVertex2i(0, 10);
gl.glVertex2i(-10, -10);
gl.glVertex2i(10, -10);
gl.glEnd();
}//exit local, back to global/absolute coords
gl.glPopMatrix();
pgl.endGL();
}
You don't actually need the { } for the push and pop matrix calls, I added them like a visual aid. Also, you can do this without push/pop, by concatenating your transforms, but it's handy to know those are there for your when you need them. Might come in handy when you want to shoot some GL_LINES out of that triangle...pew pew pew!
HTH
You have your units messed up. glRotatef excepts degrees and the trigonometrical functions expect radians. This is the most obvious mistake.
Also, speed is never used in your snippet. I suppose that every frame you're using it somehow, but in the code you pasted there's:
xPos+=dirX
Which is basically "add direction to the position" - not making much sense, unless you want to "move it exactly 1 unit in the given direction instantenously at the moment when speedUp() is called. The usual approach for continous movement would be to:
// each frame:
xPos += dirX * speed * deltaTime;
yPos += dirY * speed * deltaTime;
Try this:
dirX = speed * cos(direction);
dirY = speed * sin(direction);
You are obviously new to OpenGl, so I would recommend you, that you look into quaternions to do your roations. Here are two pretty nice article about this matter: Gamedev and Nehe. I would recommend you to use the Quaternion class from the JMonkeyEngine. Just remove the savable and some other interfaces and you can use them with ease. Here they are located: JMonkey Source
I also use the JME math classes for my own projects. I have already striped most of the dependencies and you can download some classes from here: Volume Shadow. However the Quaternion class is missing, but you WILL need Vector3f :D.

Categories

Resources