I have an image that rotating in a counter clockwise direction. Now, I want it to move in a random direction during or whenever it touch the wall. The problem is I can't do it, please help me about this matter.
This is my code :
private double x;
private double y;
private double speed;
public void move(long dt)
{
double dt_s = dt / 1e9;
double dx = speed * dt_s;
double dy = speed * dt_s;
final double right_border = 100;
final double up_border = 100;
final double down_border = 0.0;
final double left_border = 0.0;
x += dx;
if (x >= right_border)
{
x = right_border;
if (y >= down_border)
{
y += dy;
}
}
if (y > up_border)
{
y = up_border;
if (x >= left_border)
{
speed *= -1;
}
}
if (x <= left_border)
{
x = left_border;
if (y <= up_border)
{
y += dy;
}
}
if (y < down_border)
{
y = down_border;
if (x <= right_border)
{
speed *= -1;
}
}
}
First you must solve the problem of your class being directionless - you have speed, but your direction is fixed at 45 degree north east (increment x and y the same).
Add direction to your class as follows:
...
private double speed;
private double angle; // in radians - makes math easier
public void move(long dt) {
...
double dx = speed * dt_s * Math.sin(angle);
double dy = speed * dt_s * Math.cos(angle);
...
Now to head in a random direction:
myObject.setAngle(Math.PI * 2 * Math.random()); // Math.PI * 2 = 360 degrees
If hitting a wall, you will have to limit your angle to an angle that's away from the wall you are hitting. I'll leave that to you, but it will take the form of:
myObject.setAngle(minAngle + ((maxAngle - minAngle) * Math.random()));
This is one possible solution.
Generate a random point (x,y) on one of the boundaries (other than the boundary that the image just hit), and make the image move towards that point. All you have to do is, find the slope between the point P1(x1,y1) it just hit, and the random point just generated P2(x2,y2). Using the slope you can find the equation of the line, it has to travel in. You're done!!
Related
I have a point that follows the mouse that I made in Processing.
void move() {
double slope = (y - mouseY)/(x-mouseX);
double atanSlope = atan(slope);
if (slope < 0 && mouseY < y ) {
x += cos(atanSlope)*(speed);
y += sin(atanSlope)*(speed);
} else if (slope >= 0 && mouseY < y) {
x -= cos(atanSlope)*(speed);
y -= sin(atanSlope)*(speed);
} else if (slope > 0) {
x += cos(atanSlope)*(speed);
y += sin(atanSlope)*(speed);
} else {
x -= cos(atanSlope)*(speed);
y -= sin(atanSlope)*(speed);
}
}
How could I change this or add to this to make the point have a limited turning rate? What I had in mind would be similar to the missiles in this game. https://scratch.mit.edu/projects/181364872/
I don't know how I'd even start to limit the turning rate of the point. Any help would be appreciated.
(I tagged java too, because though this is in Processing, Processing is pretty much Java with built in methods at times.)
One way to do this is to keep the object current direction. You can then use the cross product of the vector to the mouse, and the vector along the object's direction to find the angle it needs to turn to point to the mouse. You can then limit the turn and add the change to get the new direction.
double direction = ?; // the current direction of object in radians
double x = ?; // the current position
double y = ?;
double maxTurn = ?; // Max turn speed in radians
double speed = ?;
void move() {
double mvx = mouseX - x; // get vector to mouse
double mvy = mouseY - y;
double dist = Math.sqrt(mvx * mvx + mvy * mvy); // get length of vector
if(dist > 0){ // must be a distance from mouse
mvx /= dist; // normalize vector
mvy /= dist;
double ovx = Math.cos(direction); // get direction vector
double ovx = Math.sin(direction);
double angle = Math.asin(mvx * ovy - mvy * ovx); // get angle between vectors
if(-mvy * ovy - mvx * ovx < 0){ // is moving away
angle = Math.sign(angle) * Math.PI - angle; // correct angle
}
// angle in radians is now in the range -PI to PI
// limit turn angle to maxTurn
if(angle < 0){
if(angle < -maxTurn){
angle = -maxTurn;
}
}else{
if(angle > maxTurn){
angle = maxTurn;
}
}
direction += angle; // turn
// move along new direction
x += Math.cos(direction) * speed;
y += Math.sin(direction) * speed;
}
}
The following code is called every 50ms.
// Start point
private double x;
private double y;
private double z;
private double y1;
#Override
public void run() {
double x1 = Math.cos(y1);
double z1 = Math.sin(y1);
double y2 = 4D - y1;
double x2 = Math.sin(y2);
double z2 = Math.cos(y2);
// First new point
double pX1 = x + x1;
double pY1 = y + y1;
double pZ1 = z + z1;
// Second new point
double pX2 = x + x2;
double pY2 = y + y2;
double pZ2 = z + z2;
if (y1 > 4D) {
y1 = 0D;
} else {
y1 = y1 + 0.1D;
}
}
Here is the output in a game. It generates two helices.
I cannot control more than the radius.
I am looking for code I can easily customize to fit my preferences.
How do I control the following aspects?
How fast the helix rises.
Where the helix begins.
helix is circular shape with 'linear' movement of the plane
you use plane xz as helix base and y axis as height
so you need:
r - radius
d - distance between two screws (the y movement after full circle)
t - parameter <0,1> determining the position on helix
h0,h1 - start end height of helix (y-axis)
a0 - angular start position [rad]
Now how to get the point on helix as function of parameter these parameters
aa=fabs(h1-h0)*2.0*M_PI/d; // angular speed coefficient
// if you need opposite angular direction then add aa=-aa;
x=r*cos(a0+aa*t);
z=r*sin(a0+aa*t);
y=h0+((h1-h0)*t);
aa can be precomputed once
now if t=0.0 then you get the start point of helix
if t=1.0 then you got the endpoint of helix
so speed is just how much you add to t during animation per timer cycle
d controls number of screw loops
h1-h0 is the helix height
code is in C++ (sorry I am not a JAVA coder)
One part of the helix begins at:
(x, y, z) = (1.0, 0.0, 0.0)
And the other at:
(x, y, z) = (-0.8, 4.0, -0.7)
And the particle rises at a rate of 0.1 (from y1 = y1 + 0.1D).
So, to control how fast the particles rise, just change this value.
To control where the helix begins you need to change the angle. For example, add some value to the sines and cosines. Like this:
Math.cos(y1 + dy);
To make more rotations before restarting from the ground you can multiply the angle. Make it twice as fast:
Math.cos(2 * y1);
Helix is circular shape with progressive Y value.
// Start point
private double x;
private double y;
private double z;
private double degree;
private double rY;
#Override
public void run() {
// We use the same formula that is used to find a point of a circumference
double rX = Math.cos(degree);
double rZ = Math.sin(degree);
// New point
double pX = x + rX;
double pY = y + rY;
double pZ = z + rZ;
if (degree > 2D * Math.PI) {
degree = 0D;
} else {
degree = degree + 0.2D;
}
if (pY > 2D) {
pY = 0D;
} else {
pY = pY + 0.02D;
}
}
I am having a user draw a line on the screen, there is a start point and a end point. If the user extends over a certain angle I change the position of the endpoint so the user cannot extend beyond the specified angle. However it seems that when I cacluate the angle the user is drawing and make suer it is not over MAX ANGLE, and set the angle to the MAX ANGLE, there is a difference. This can be seen by when I draw the line, once i get to a certain angle, the line jumps and locks at the MAX ANGLE, but there shouldnt be any jump, it should be smooth, like the line ran into a invisible barrier. This could just be me though, my PosX and PosY are floats.
private void CheckAngle() {
double adj = Math.abs(PosX - PosX2);
double c1 = adj;
double c2 = Math.abs(PosY - PosY2);
double hyp = Math.hypot(c1, c2);
double angle = Math.cos((adj/hyp));
angle = angle * 100;
if (angle > MAX_ANGLE) {
double opp = (Math.tan(MAX_ANGLE) * Math.abs(PosX - PosX2));
if (PosY > PosY2) {
PosY2 =(float) (PosY - opp);
} else {
PosY2 =(float) (PosY + opp);
}
}
}
My answer was a combination of using radians, as well as unsing
Math.acos() & Math.atan()
so the final code looks like this
private void CheckAngle() {
double adj = Math.abs(PosX - PosX2);
double opp = Math.abs(PosY - PosY2);
double hyp = Math.sqrt((adj*adj)+(opp*opp));
double angle = Math.acos((adj/hyp));
angle = angle * 100;
angle = Math.toRadians(angle);
if (angle > MAX_ANGLE) {
opp = (Math.atan(MAX_ANGLE) * adj);
if (PosY > PosY2) {
PosY2 =(float) (PosY - opp);
} else {
PosY2 =(float) (PosY + opp);
}
}
}
Here's the conversion:
final double MAX_ANGLE = Math.toRadians(80);
Note that this is identical to saying:
final double MAX_ANGLE = 80 * Math.PI / 180;
I have an object(which is a ball) having its position at the top of the screen that fall directly whenever I start running the program. The problem is that the ball fall to its constant speed, I want it to fall accelerating with gravity effects and when it reach the ground, I want it to bounce a few more times before it stop moving. Could someone help me about this?
Here's what I've tried:
public class Balls
{
private double x;
private double y;
private double speed;
private double mass;
private final double gravity = -9.8;
private final double width = 100;
private double height = 100;
private final Board board;
private boolean isFalling = false;
private double distance_y;
private double distance_x = 0;
public Balls(double x, double y, double speed, double mass, Board board)
{
this.x = x;
this.y = y;
this.board = board;
this.speed = convertToMeterSpeed(speed);
this.mass = mass;
}
private double convertToMeterSpeed(double speed)
{
return speed / 3.6;
}
public void moveBall(long dt)
{
double time = dt / 1e9; // seconds
double diameter_y = height / 2.0;
double radius = (diameter_y / 2.0);
double velocity_y = speed * dt / 1e9;
distance_y = board.getHeight() - y;
if (distance_y - radius > 0)
{
isFalling = true;
}
if (isFalling)
{
if (distance_y >= height)
{
distance_y = distance_y + (0.5 * gravity * (time * time)); // represents the 1/2,
distance_y = board.getHeight() - height;
y += velocity_y;
}
else
{
isFalling = false;
}
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
}
}
}
public void render(Graphics2D g2d)
{
g2d.fillOval((int) x, (int) y, (int) width, (int) height);
}
}
speed = v0 + gt^2/2,
where
v0 - initial speed
g = 9.81 on Earth.
t - time
Now you can calculate the speed at any time.
You probably want to define a maximum speed (terminal velocity) so your ball doesn't accelerate to an enormous speed. Gravity accelerates at 9.8m/s/s. Once the ball hits the "ground" you just reverse the speed and update the current position to make it bounce, then on your next iteration gravity will be applied again so it will go back down. Eventually, the speed will get to 0 as the ball doesnt bounce so much, and will stop.
Here's an (untested) example:
private static final double GRAVITY = 9.8;
private static final double TERMINAL_VELOCITY = 100;
private double speed;
private int current_y;
public void fallAndBounce() {
speed = speed + GRAVITY;
if (speed > TERMINAL_VELOCITY) { speed = TERMINAL_VELOCITY; }
if (current_y >= bottomOfScreen)
{
//We have hit the "ground", so bounce back up. Reverse
//the speed and divide by 4 to make it slower on bouncing.
//Just change 4 to 2 or something to make it faster.
speed = -speed/4;
}
current_y += speed;
}
Your problem is that you are trying to animate a ball falling, but you are instead writing an algorithm for solving its position given a certain time.
This means you should take your time variable dt completely out of the equation, and just move your ball with each iteration of a loop like this:
while (true)
{
moveBall();
render();
try {
Thread.sleep(10)
} catch(InterruptedException e) {
e.printStackTrace();
}
}
Also, change your variables slightly:
// Add this to your variables
private final double GRAVITY = -9.8; // Final variables should be capitalized
private final double TERMINAL_VELOCITY = -30; // Whatever you want it to be
Here is the main change:
public void moveBall()
{
double diameter_y = height / 2.0;
double radius = (diameter_y / 2.0);
double velocity_y = speed * dt / 1e9;
distance_y = board.getHeight() - y;
if (distance_y - radius > 0)
{
isFalling = true;
}
if (isFalling)
{
if (height < distance_y)
{
if (velocity_y <= TERMINAL_VELOCITY)
velocity_y += GRAVITY; // implementing acceleration (gravity)
// just means adding it to velocity.
y += velocity_y;
}
Really, I don't know how this was possibly working before.
I'm trying to move a sprite across the screen in a straight line, towards on the location where've I touched the screen, what i did was upon the update() in each loop , it checks to see if the current sprite's location x y is == to the destination x ,y . if it hasn't sprite's x++ and y++...
the thing is ..it ain't moving in a straight line... as there are cases where the x or y coordinate reaches the destination x or y first... how do i changed it so that the both x and y meets the destination together?
my current pseudo code for the sprite object
destX = destination X
destY = destination Y
posX = current X
posY = current Y
public void update(){
if(destX > posX && destY < posY)
{
posX++;
posY--;
}
else if (destX > posX && destY > posY){
posX++;
posY++;
}
else if(destX < posX && destY > posY)
{
posX--;
posY++;
}
else if(destX < posX && destY < posY){
posX--;
posY--;
}
else if(destX < posX)
posX--;
else if(destX > posX)
posX++;
else if(destY < posY)
posY--;
else if(destY > posY)
posY++;
Check out: http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
This simple algorithm will tell you each X,Y coordinate on a line between two points. You could use this algorithm to compute all of the positions it needs to visit, store the coordinates in an array, and iterate over the array as you update the position.
From the Article:
function line(x0, x1, y0, y1)
int deltax := x1 - x0
int deltay := y1 - y0
real error := 0
real deltaerr := abs (deltay / deltax) // Assume deltax != 0 (line is not vertical),
// note that this division needs to be done in a way that preserves the fractional part
int y := y0
for x from x0 to x1
plot(x,y)
error := error + deltaerr
if error ≥ 0.5 then
y := y + 1
error := error - 1.0
This is the most primitive version. The article contains a better generalized algorithm that you should look at.
I am dealing with a similair problem as yours. (I have an arraylist holding the history of positions my player has gone and I want to use that to rewind the game.)
Instead of simply increasing x and y position with 1 you can:
Calculate the angle between the source postion and your destination
position.
Calculate the new direction using a variable which
represents the speed
Update your postion using calculated direction
I made a class of that. I hope it is usefull.
import java.awt.geom.Point2D;
public class MyVelocityCalculator {
public static void main(String[] args) {
Point2D.Double currentPosition = new Point2D.Double();
Point2D.Double destinationPosition = new Point2D.Double();
currentPosition.setLocation(100, 100);
destinationPosition.setLocation(50, 50);
Double speed = 0.5;
Point2D.Double nextPosition = MyVelocityCalculator.getVelocity(currentPosition, destinationPosition, speed);
System.out.println("player was initially at: "+currentPosition);
System.out.println("player destination is at: "+destinationPosition);
System.out.println("half seconds later player should be at: "+nextPosition);
}
public static final Point2D.Double getVelocity(Point2D.Double currentPosition, Point2D.Double destinationPosition, double speed){
Point2D.Double nextPosition = new Point2D.Double();
double angle = calcAngleBetweenPoints(currentPosition, destinationPosition);
double distance = speed;
Point2D.Double velocityPoint = getVelocity(angle, distance);
nextPosition.x = currentPosition.x + velocityPoint.x;
nextPosition.y = currentPosition.y + velocityPoint.y;
return nextPosition;
}
public static final double calcAngleBetweenPoints(Point2D.Double p1, Point2D.Double p2)
{
return Math.toDegrees( Math.atan2( p2.getY()-p1.getY(), p2.getX()-p1.getX() ) );
}
public static final Point2D.Double getVelocity(double angle, double speed){
double x = Math.cos(Math.toRadians(angle))*speed;
double y = Math.sin(Math.toRadians(angle))*speed;
return (new Point2D.Double(x, y));
}
}
Don't use integers. This is a very bad idea to work with ints. Use floats. The main concept is: define the number of steps you want to perform (s). Compute differences in X and Y (diffX and diffY). Don't take absolute values: Compute them this way
float diffX = destX - currentX;
Then compute the xMove and yMove values by dividing diffX and diffY by s (number of steps).
float moveX = diffX / s;
float moveY = diffY / s;
And now you have to add for each iteration the moveX and moveY values to the current position.
And for drawing it, you should use Graphics2D, which supports floating points. If you don't want to use Graphics2D, you can round the floats to ints, using Math.round(float).