Found plenty of questions that were similar, but nothing that answers my own problem. It's probably something really bloody simple, but it's late and I can't fathom it. I've got an android game I'm working on, where you touch the screen and it 'fires' a sprite in that direction. I've got most of the code working, however, after the sprite fires and moves off, it gets to the touch point and then just wiggles. I would like it to carry on along that angle and eventually bounce around...
Here's my code (well the bits that matter):
List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
int len = touchEvents.size();
for(int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if(event.type == TouchEvent.TOUCH_UP) {
touchPoint.set(event.x, event.y);
guiCam.touchToWorld(touchPoint);
}
}
//Log.d("PANDAM", touchPoint.x + "|" + touchPoint.y);
float speed = 112f;
double theta = 180.0 / Math.PI * Math.atan2(panda_y - touchPoint.y, panda_x - touchPoint.x);
Log.d("PANDAM", " > "+theta+" < ");
movePanda(theta, speed, deltaTime);
And the "movePanda" method:
private void movePanda(double angle, float speed, float deltaTime)
{
panda_x += speed * Math.cos(angle)*deltaTime;
panda_y += speed * Math.sin(angle)*deltaTime;
}
My question is, how do I get the panda to carry on along the touch vector and not spaz out when it reaches the original touch point?
You seem to be recalculating the angle each step of the animation, but you actually need to remember what the angle was when you first started moving. As you pass the original touch point, the angle changes to point the other direction, so if you reclcalculate it every animation step, it will change and eventually point the other way.
Related
I had written before about implementing a map in my libgdx project.
I did that using a snapshot of said google map, importing the GPS bounds of the snapshot, the route-latlong values, a locationservice (via interface) and the snapshot as Gdx.files.local string.
Hopefully, the last issue I have right now is that the route is rotated about 45 degrees clockwise. Otherwise my 'enemies' walk a perfect path. I already figured out that I had to 'flip' my y-axis; before that it was rotated AND flipped upside down.
I was hoping someone here with more experience might have dealt with something similar before and has some advice :)
This is basically the code that creates a Waypoint array, after converting the GPS coordinates to pixel-coordinates that correspond to the gps-bounds of the map-snapshot (bottom-left-corner and upper-right-corner see here, as well as the width and height of the map-texture.
private void convertPathToScreen(double[] gpsRoute){
for(int i = 0; i<gpsRoute.length; i++){
if(i % 2 != 0) {
screenRouteCoordinates[i] =
x_GpsToScreenConversion(gpsRouteCoordinates[i]);
}
else{
screenRouteCoordinates[i] =
y_GpsToScreenConversion(gpsRouteCoordinates[i]);
}
}
}
public int x_GpsToScreenConversion(double x_pointInGpsCoords){
double percentage = 1 - Math.abs((x_pointInGpsCoords - x_GpsMin) /
(x_GpsMax - x_GpsMin));
return (int)((percentage* Math.abs(mapWidth - mapOrigin)) + mapOrigin);
}
public int y_GpsToScreenConversion(double y_pointInGpsCoords){
double percentage = (y_pointInGpsCoords - y_GpsMin) / (y_GpsMax - y_GpsMin);
return (int)((percentage* Math.abs(mapHeight - mapOrigin)) + mapOrigin);
}
Edit: Now that I think of it, the error might be in my pathfinding code, although I tested it before moving my project forward and it worked solidly for all values I put in. Anyway, for completness...es sake
private void calculatePathing(){
angle = (float) (Math.atan2(waypointsToGoal[waypoint].y - getY(), waypointsToGoal[waypoint].x - getX()));
velocity.set((float) Math.cos(angle) * speed, (float) Math.sin(angle) * speed);
}
So the question is basically: How do I fix the 90° clockwise rotation that buggers up my game? Can I rotate the coordinates of the array around the center of the map (where all enemies walk to) or is there a mistake in the conversion-code here?
Solution: (Patchwork, but it gets the job done!)
I simply rotated my waypoints by the degree I needed around the destination-point. It doesn't solve the underlying issue, but it solves the symptom.
private void createWaypointArray(){
//formula requires radians
double angle = Math.toRadians(90);
double current_x;
double current_y;
// waypointCache.size()-1 gets me the last waypoint, the destination around which I rotate
double center_x = waypointCache.get(waypointCache.size()-1).x;
double center_y= waypointCache.get(waypointCache.size()-1).y;
// Loop through Vector2 Array, rotate the points around destination and save them
for(int i = 0; i < waypointCache.size()-1; i++){
current_x = waypointCache.get(i).x;
current_y = waypointCache.get(i).y;
waypointCache.get(i).x = (float)((current_x-center_x) * Math.cos(angle) - (current_y-center_y) * Math.sin(angle) + center_x);
waypointCache.get(i).y = (float)((current_x-center_x) * Math.sin(angle) + (current_y-center_y) * Math.cos(angle) + center_y);
// this does work, but also translates the points because it rotates around the
// worldaxis, usable when points lie on normal kartesian axis I guess
// waypointCache.get(i).rotate(90);
}
this.wayPointArray = waypointCache.toArray(new Vector2[waypointCache.size()]);
}
I am trying to shoot an object(a spell) depending on the rotation of the players arm. The spell is supposed to come out of the hand and shoot towards where the mouse cicked(the arm rotates and points to where the mouse is). This is how the arm rotates in game.
public boolean mouseMoved(int screenX, int screenY) {
tmp.x = screenX;
tmp.y = screenY;
tmp.z = 0;
cam.unproject(tmp);
rot = MathUtils.radiansToDegrees * MathUtils.atan2((float)tmp.y - (float)player.getArmSprite().getY() - player.getArmSprite().getHeight(),
tmp.x -player.getArmSprite().getX() - player.getArmSprite().getWidth());
if (rot < 0) rot += 360;
//Last right or left means if hes looking left or right
if(player.lastRight)
player.setObjectRotation(rot + 80);
if(player.lastLeft)
player.setObjectRotation(-rot - 80);
And this is how the spell is supposed to shoot based off rotation
//destination is a vector of where on screen the mouse was clicked
if(position.y < destination.y){
position.y += vel.y * Gdx.graphics.getDeltaTime();
}
if(position.x < destination.x){
position.x += vel.x * Gdx.graphics.getDeltaTime();
}
However this is very wonky and never really reacts the way it supposed to with a few exceptions. It fires from the hand and then if the y axis is equal it completely evens out and goes till it reaches the x position, I want it to fire from the hand to the position clicks perfectly straight from point a to point b, this is clearly a rotation problem that I just can't seem to figure out how to tackle.
Here is an image of what is happening
Example image
The red indicates where I clicked, as you can see it reached the x pos first and now is traveling to the y when it should have reached the x and y pos of where I clicked first
Any help with this problem is extremely appreciated!
I'm pretty bad at radians and tangents but luckily we have vectors.
Since you have the rot ation in degrees of the arm. I advice to use Vectors to use for any Vector related math now.
//A vector pointing up
Vector2 direction = new Vector2(0, 1);
//Let's rotate that by the rotation of the arm
direction.rotate(rot);
Now direction is the direction the arm is pointing. If your rotation is calculated where up = 0. So you might need to rotate it 180, 90 or -90 degrees. Or in the case you did something silly any degrees.
Your spell should have a Vector too for it's position. Set that to the hand or wherever you want to start from. Now all you need to do is scale that direction since it's currently has a length of 1. If you want to move 5 units each frame you can do direction.scl(5) now it is of length 5. But technically speaking it's no direction anymore now everybody calls it velocity so let's do.
//when you need to fire
float speed = 5;
Vector2 velocity = direction.cpy().scl(speed);
//update
position.add(velocity);
draw(fireballImage, position.x, position.y);
I copied direction first, otherwise it would also be scaled. Then I just added the velocity to the position and draw using that Vector.
And to show Vectors are awesome you should see this awesome badlogic vs mouse program I created. https://github.com/madmenyo/FollowMouse there are just a view lines of my own code. It just takes a little bit of vector knowledge and it's very readable.
I have the following methods in my program which keep a ball continuously bouncing. I have tried modifying but can't seem to get the ball to stop at the bottom of my GUI. My main goal is to have the methods simulate as if you were bouncing a real ball.
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
}
public void verticalBounce(Container container) {
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
UPDATE:
Ball bounces and stops at the bottom of the gui.
public void verticalBounce(Container container) {
deltaY = deltaY - gravity;
y = y + deltaY;
if (y > getHeight()) {
y = getHeight(); // reset location
deltaY = (int) (deltaY * -0.9); // slows down ball
}
}
None of that code looks correct. You need to implement the equation(s) of rectilinear motion:
http://en.wikipedia.org/wiki/Linear_motion
The one you need is s = ut + 0.5 * a * t * t, where
s = distance
u = an initial velocity - regard as the speed at which it hits the ground
a = acceleration due to gravity (you can probably have this pretty arbitrary)
t = time
You reverse the sign of a on the way up.
To simulate lossy bouncing, reduce u by taking a certain factor of energy E out of the system:
new_u * new_u = (1 - E)u * u.
(This comes from the formula for the kinetic energy of a moving body).
I can see from your question that you are capable of implementing this, so I won't provide code; just the physics.
First, a bouncing ball doesn't have a random element in it. Its all determined by the forces acting on the ball and the speed and direction of the ball. If you add a little randomness, it may make it look a little more realistic because of things like wind and unbalance in the ball but its very little.
To program it, assume the ball gets shot up from the ground at some speed. You need to store:
Y = location in units above the ground. Start at 0.
deltaY = speed in units per time interval. Negative is down. Positive is up. Start at 10.
gravity = acceleration in units of change per time interval. Gravity is always negative and constant. Start with -2 and try some values.
Unless you want the ball to disappear off the screen as it reaches the top of the bounce, you will need to select a ceiling height. Say 100. (Which is best chosen to match your graphics area's height, though.)
So for every time interval/tick/loop you do the following:
Adjust for gravity by subtracting gravity from deltaY. (If the ball is moving down it will move faster. If its moving up, it will move slower.)
Move the ball by adding deltaY to Y.
Then you have to check: Did the ball hit the ground or the ceiling? Is Y greater than the ceiling value or less than the ground one (0).
If so, you have to bounce it by:
Move Y such that if it was X past the boundary (ground/ceiling) it becomes X within the boundary. (If Y = 110 and ceiling = 100, set Y to 90. If Y = -5, set it to +5.)
Negate deltaY. In a bounce the direction reverses. (deltaY = -deltaY)
Reduce deltaY by a percentage. Some energy is lost in the bounce so speed is slower after a bounce. (deltaY = deltaY * 0.90 or some other amount) #Bathsheba calls that removing energy from the system.
That's all there is to it. You have to fiddle with the numbers to make it take off at a reasonable speed. You have to adjust the time interval. You don't have to match real life. Just do what looks good.
As time goes by, the speed will reduce to 0.
(And despite what I said before, adding or subtracting a small random amount actually looks kind of cool.)
Your ball is bouncing randomly instead of slowly decreasing in velocity. You need to lower your velocity every bounce until the velocity is under minimumMovement then make the velocity 0 and stop bouncing.
I'm trying to create a simple Android game, a 2D action shooter which has 2 control sticks (circles) on the screen, the left one is movement control and the right one weapon control. Direction is being controlled by the position of your thumb relative to the circle’s center.
I've been following a tutorial on this site: http://www.kilobolt.com/day-7-creating-an-android-game-from-start-to-finish.html but it only gave me the base to work on. I have no programming experience so I'm quite lost now.
I got the movement working only on TOUCH_DOWN event, the hero moves to about where it should but to change direction I have to lift my thumb and touch the circle again. TOUCH_DRAGGED (or ACTION_MOVE) is broken because if I drag my finger across the circle the character moves really fast. I guess the problem is too many touch events are being handled, but I have no idea how to fix it.
How can I change this so that I can drag my thumb around the circle and the hero will change its direction instantly, and keep its speed constant all the time? Also the speed should be the same no matter how close or far from the center of the circle you touch.
private void updateRunning(List<TouchEvent> touchEvents, float deltaTime) {
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if (event.type == TouchEvent.TOUCH_DOWN || event.type == TouchEvent.TOUCH_DRAGGED) {
if (inBounds(event, 50, 300, 150, 150, 'c')) {
ctrl.setX(event.x);
ctrl.setY(event.y);
ctrl.direction();
hero.move(ctrl.getDirX(), ctrl.getDirY());
}
}
if (event.type == TouchEvent.TOUCH_UP) {
if (inBounds(event, 0, 0, 35, 35,'r')) {
pause();
}
hero.stopMove();
}
}
hero.update();
The movement: hero's speedX and speedY are added to hero's centerX and centerY on every hero.update() call.
public void move(float x, float y) {
speedX += x * MOVESPEED;
speedY += y * MOVESPEED;
}
This method that handles the x & y speed. Found it here at stackoverflow, and because touch_down event is working ok, I guess it's doing it's job. Although I feel it's not exactly how it's supposed to be. L_STICK_C is a constant with values of 100 and 350 (center of the circle).
public void direction() {
dir.x = x - L_STICK_C.x;
dir.y = y - L_STICK_C.y;
double hyp = Math.sqrt(dir.x * dir.x + dir.y * dir.y);
dir.x = (float) (dir.x / hyp);
dir.y = (float) (dir.y / hyp);
}
I suggest you look into some game programming tutorials. You usually would not move the character directly from the touch input. You'd set a game state variable once a game loop which would correspond to the position of your thumb inputs. Then you'd only update the hero once per game loop based on those inputs. This lets allows you to keep the game input control code, and hero code separate, and makes it re-usable for other parts of your game.
EDIT:
Based on your code, every time you drag your finger, you generate a bunch of dragged events. So you are adding onto your characters speed for each event. You should probably just be looking at the distance to center and x / y of the input on the last touch event, not all of them.
I'm writing a simple game right now and I need to be able to detect collisions between many objects (checking if 10 objects collide with any 20 other objects but not between the two groups). I've written some simple code that works now but causes the game to slow down extremely after I detect the collision (in Java by the way):
//Check for collisions between tanks and bullets
ArrayList<Object> objectsToRemove = new ArrayList<Object>();
for (int i = 0; i < tanksOnScreen.size(); i += 1) {
//Get tank
Tank tank = tanksOnScreen.get(i);
for (int e = 0; e < bulletsOnScreen.size(); e += 1) {
//Get bullet
Bullet bullet = bulletsOnScreen.get(e);
//Check for collision
if (tank.collides(bullet.x, bullet.y, 10, 10)) {
System.out.println("Collide");
objectsToRemove.add(bullet);
objectsToRemove.add(tank);
break;
}
}
}
for (Object obj:objectsToRemove) {
if (obj.getClass().equals(Bullet.class)) {
bulletsOnScreen.remove(bulletsOnScreen.indexOf(obj));
} else if (obj.getClass().equals(Tank.class)) {
tanksOnScreen.remove(tanksOnScreen.indexOf(obj));
}
}
And the collides() method of the tank:
public boolean collides(float px, float py, float pwidth, float pheight) {
// If the distance between the two centers of the lines on x and y axis
// Is less than the distance of half the w and h added together, the objects
// Are colliding
float x1 = (px > x) ? x : px, x2 = (px > x) ? px : x, y1 = (py > y) ? y : py, y2 = (py > y) ? py : y;
float w1 = (x1 < x2) ? width : pwidth, w2 = (x1 < x2) ? pwidth : width, h1 = (y1 < y2) ? height : pheight, h2 = (y1 < y2) ? pheight : height;
if ((x2 + w2/2) - (x1 + w1/2) < (w1/2 + w2/2)&&(y2 + h2/2) - (y1 + h1/2) < (h1/2 + h2/2)) {
return true;
} else {
return false;
}
}
I assume the lag is because of the double for loops, to iterate over the objects. I'm not sure how to eradicate these for loops or how to get the bullets in a certain region of the screen and only check these bullet without using another for loop (segregation, I think). Can anyone point me in the right direction for collision detection with many objects? I don't mind what language the answer is in, even if it is pseudo code.
Thanks,
Ben
Edit 1
I'm right now using the Slick graphics API for java, which provides you with an update and render method to add rendering and game logic. I placed this collision detection in the update method (which is getting called every frame - about 60 times a second). The slowness occurs after the collision happens, and the objects are removed from the screen - which I find odd. Maybe a break command after deleting the objects in the for loop will eradicate it?
Edit 2
Thanks for all the answers guys, and the references are a great help for the future. I fixed the problem only by swapping the bullet and tank for loops, so it didn't continue to loop after the bullet was destroyed. I shouldn't have asked the question, as it was quite easy to fix in the end. Dave and Banthar were right in saying that the problem wasn't with the code, and that it should be instantaneous.
One good idea is to use octree. As the bullets will be moving I assume that you will need a kinetic version of it - there are a bunch of articles on kinetic data structures on the internet.
Also if you want to detect collisions between more complex convex polygons, I recommend you to use gjk algorithm which is very fast for such calculation. Note that this will speed up only the collision detection time for a pair of objects, the number of pairs will still remain the same.
Unless I'm missing something, or there's additional code you haven't shown, you're running in O(n^2), where n is 20. It should seem instantaneous to the user.
Try stepping through it in the debugger to see where it's slowing down.
Edit to elaborate: your expensive operation is not in the code you've posted. It's somewhere else, being called by the code you've posted.
Thanks for all the answers guys, and the references are a great help for the future. I fixed the problem only by swapping the bullet and tank for loops, so it didn't continue to loop after the bullet was destroyed. I shouldn't have asked the question, as it was quite easy to fix in the end. Dave and Banthar were right in saying that the problem wasn't with the code, and that it should be instantaneous.