How could I replicate the opposite of this lerping function? - java

In the lerping function below, it will slow down a camera which is following a moving object, and as the moving object slows down or stops the camera catches up to it. I need the opposite. I need the camera to move ahead of the moving object and slow down back to the object when the object slows/stops. I can't seem to make it work. Any ideas?
//this is the opposite of what I want.
float lerp = 0.1f;
Vector3 position = this.getCamera().position;
position.x += (Obj.x - position.x) * lerp;
position.y += (Obj.y - position.y) * lerp;

just increase to 110% instead of decreasing to 10%
float lerp = 1.1f;
position.x += (Obj.x + position.x) * lerp;
position.y += (Obj.y + position.y) * lerp;
Example:
public static void main(final String[] args)
{
double position = 0;
for (int i = 0; i < 100; i++)
{
position = (position + 10) * 1.1;
System.out.println("position = " + position);
}
}

Related

I have a point that follows the mouse, how would I give it a limited turning rate?

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;
}
}

How can I make my shape "point" at my player

I am trying to make a game where enemies spawn from the top (like a vertical scrolling game) and one kind of enemy will basically follow the player's X coordinate while going down. The enemy class is called Follower and right now it does points to the player (see update function on Follower) but it's not as accurate as I need it to be. For example, if the player accelerates, the follower won't be able to see him all the time.
One way to look at it is that I want the position of the player to be a coordinate in a radiant system and make the vertices of my Follower accurately just rotate and create a straight line looking at it every frame
here is the Follower Class:
public class Follower {
Player target; //follow this
//position
private Vector2 position;
private float x;
private float y;
//speed
private Vector2 velocity;
private float speed;
private float radians;
private float faceTarget;
//dimensions
private float[] shapeX;
private float[] shapeY;
private int numPoints; //vertices for the shape
private boolean remove; //to remove from the game
public Follower(float x,float y, Player target){
this.target = target;
this.x = x;
this.y = y;
velocity = new Vector2(0, 0);
numPoints = 4;
speed = 200;
shapeX = new float[numPoints];
shapeY = new float[numPoints];
radians = 3.1415f / 2;
setShape();
}
public void setShape(){
//top vertice
shapeX[0] = x + MathUtils.cos(radians) * 30;
shapeY[0] = y + MathUtils.sin(radians) * 30;
//left vertice
shapeX[1] = x + MathUtils.cos(radians - 4 * 3.1415f / 10) * 30;
shapeY[1] = y + MathUtils.sin(radians - 4 * 3.1415f / 10) * 30;
//bottom vertice
shapeX[2] = x + MathUtils.cos(radians + 3.1415f) * 60;
shapeY[2] = y + MathUtils.sin(radians + 3.1415f) * 60;
//left vertice
shapeX[3] = x + MathUtils.cos(radians + 4 * 3.1415f / 10) * 30;
shapeY[3] = y + MathUtils.sin(radians + 4 * 3.1415f / 10) * 30;
}
public boolean shouldRemove() {
return remove;
}
public void update(float dt) {
float angle = (float) Math.atan2(target.getPosition().y - y, target.getPosition().x - x); //angle between the follower and target
velocity.set((float) Math.cos(angle) * speed , -speed); //setting direction to follow the target
radians += Math.cos(angle) * dt; //THIS HERE IS MAKING IT ROTATE
x += velocity.x * dt;
y += velocity.y * dt;
setShape();
if(y <= 0 - 60)
remove = true;
else
remove = false;
}
public void draw(ShapeRenderer sp){
sp.setColor(1, 1, 1 ,1);
sp.begin(ShapeRenderer.ShapeType.Line);
for(int i = 0, j = shapeX.length - 1;
i < shapeX.length;
j = i++) {
sp.line(shapeX[i], shapeY[i], shapeX[j], shapeY[j]);
}
sp.end();
}
}
I am not adding the GameScreen because I do not see the need of showing how they are rendered, either way, it'll stay the same.
Also, with the line of code, I am using the Follower points to the player with the bottom vertice as the "eyes"
Thanks for the answers!

Billiards Balls Stuck Inside Each other

I am designing a billiards game for my Java class. I am having an issue with the billiard balls collisions. The balls hit into each other and occasionally slide into each other, becoming stuck. I can't seem to identify the cause of this error. I was hoping somebody could assist me in finding the cause of the issue. My code is below. Thank You.
float cueX = 200;
float cueY = 225;
float cueDeltaX;
float cueDeltaY;
float ballWidth = 25;
float score = 0;
Billiards[] billiards = new Billiards[3];
void setup()
{
size (850, 450);
background(0);
fill(#29B748);
rect(0, 0, 599, 599);
billiards[0] = new Billiards(600, 225, 0, 0, false, "", 0);
billiards[1] = new Billiards(625, 211, 0, 0, false, "", 1);
billiards[2] = new Billiards(625, 239, 0, 0, false, "", 2);
//billiards[3] = new Billiards(625, 250, 0, 0, false, "", 2);
}
void draw()
{
background(0);
fill(#FFFFFF);
stroke(#A6A7A6);
text("DeltaX: " + cueDeltaX + " Delta Y: " + cueDeltaY, 20, 20);
text(score, 500, 20);
fill(#29B748);
rect(25, 25, 799, 399);
poolCueLines();
drawCue();
moveCue();
cueBounce();
cueFriction();
drawBilliards();
billiards[0].collision();
billiards[0].moveBall();
billiards[0].billiardBounce();
billiards[0].billiardFriction();
billiards[1].collision();
billiards[1].moveBall();
billiards[1].billiardBounce();
billiards[1].billiardFriction();
billiards[2].collision();
billiards[2].moveBall();
billiards[2].billiardBounce();
billiards[2].billiardFriction();
}
void poolCueLines() {
if (mousePressed)
{
stroke(#FFFFFF);
line(cueX, cueY, mouseX, mouseY);
}
}
void mouseReleased()
{
cueDeltaX = (cueX - mouseX)/50;
cueDeltaY = (cueY - mouseY)/50;
}
void drawCue() {
noStroke();
fill(0);
fill(#FFFFFF);
stroke(#A6A7A6);
ellipse(cueX, cueY, ballWidth, ballWidth);
noFill();
}
void moveCue() {
cueX += cueDeltaX;
cueY += cueDeltaY;
}
void cueBounce() {
if (cueX > width-25-ballWidth/2 || cueX < 25 + ballWidth/ 2) {
cueDeltaX = -cueDeltaX;
cueDeltaX = cueDeltaX * 0.6;
if (cueX < 25+ ballWidth/2) {
cueX = 26 + ballWidth/2;
} else {
cueX = width-26-ballWidth/2;
}
}
if (cueY > height-25-ballWidth/2 || cueY < 25 + ballWidth/ 2) {
cueDeltaY = -cueDeltaY;
cueDeltaY = cueDeltaY * 0.6;
if (cueY < 25+ ballWidth/2) {
cueY = 26 + ballWidth/2;
} else {
cueY = height-26-ballWidth/2;
}
}
}
void drawBilliards() {
//Yellow Ball 1
fill(#ffff00);
stroke(#A6A7A6);
ellipse(billiards[0].ballXpos, billiards[0].ballYpos, ballWidth, ballWidth);
//Blue 2
fill(#000099);
stroke(#A6A7A6);
ellipse(billiards[1].ballXpos, billiards[1].ballYpos, ballWidth, ballWidth);
//Red 3
fill(#ff0000);
stroke(#A6A7A6);
ellipse(billiards[2].ballXpos, billiards[2].ballYpos, ballWidth, ballWidth);
}
void cueFriction() {
cueDeltaX = cueDeltaX * 0.995;
cueDeltaY = cueDeltaY * 0.995;
}
class Billiards
{
float ballXpos;
float ballYpos;
float deltaXball;
float deltaYball;
int billiardsNum;
Billiards(float tempXpos, float tempYpos, float deltaXbill, float deltaYbill, boolean stripe, String stripeColor, int billiardNum) {
ballXpos = tempXpos;
ballYpos = tempYpos;
deltaXball = deltaXbill;
deltaYball = deltaYbill;
billiardsNum = billiardNum;
}
void collision() {
if (cueX > ballXpos-ballWidth && cueX < ballXpos+ballWidth) {
if (cueY < ballYpos+ballWidth && cueY > ballYpos-ballWidth) {
cueDeltaX = -cueDeltaX * 0.8;
deltaXball = -cueDeltaX * 0.6;
cueDeltaY = -cueDeltaY * 0.8;
deltaYball = -cueDeltaY * 0.6;
}
}
int ballNum = 0;
for (int i=0; i < 3; i++) {
if (billiards[ballNum].ballXpos > ballXpos-ballWidth && billiards[ballNum].ballXpos < ballXpos+ballWidth) {
if (billiards[ballNum].ballYpos < ballYpos+ballWidth && billiards[ballNum].ballYpos > ballYpos-ballWidth) {
if (billiardsNum == ballNum) {
} else {
//if (billiards[ballNum].deltaXball < 0.2 || billiards[ballNum].deltaYball < 0.2) {
if (deltaXball > 0){
billiards[ballNum].ballXpos += -3;
}else if (deltaXball < 0){
billiards[ballNum].ballXpos += 3;
}
if (deltaYball > 0){
billiards[ballNum].ballXpos += -3;
}else if (deltaYball < 0){
billiards[ballNum].ballXpos += 3;
}
billiards[ballNum].deltaXball = -billiards[ballNum].deltaXball * 0.8;
deltaXball = -billiards[ballNum].deltaXball * 0.6;
billiards[ballNum].deltaYball = -billiards[ballNum].deltaYball * 0.8;
deltaYball = -billiards[ballNum].deltaYball * 0.6;
//}
//} else {
// billiards[ballNum].deltaXball = -billiards[ballNum].deltaXball * 0.8;
// deltaXball = -billiards[ballNum].deltaXball * 0.6;
// billiards[ballNum].deltaYball = -billiards[ballNum].deltaYball * 0.8;
// deltaYball = -billiards[ballNum].deltaYball * 0.6;
//}
}
}
}
ballNum += 1;
}
}
void moveBall() {
ballXpos += deltaXball;
ballYpos += deltaYball;
}
void billiardBounce() {
if (ballXpos > width-25-ballWidth/2 || ballXpos < 25 + ballWidth/ 2) {
deltaXball = -deltaXball;
deltaXball = deltaXball * 0.6;
if (ballXpos < 25+ ballWidth/2) {
ballXpos = 26 + ballWidth/2;
} else {
ballXpos = width-26-ballWidth/2;
}
}
if (ballYpos > height-25-ballWidth/2 || ballYpos < 25 + ballWidth/ 2) {
deltaYball = -deltaYball;
deltaYball = deltaYball * 0.6;
if (ballYpos < 25+ ballWidth/2) {
ballYpos = 26 + ballWidth/2;
} else {
ballYpos = height-26-ballWidth/2;
}
}
}
void billiardFriction() {
deltaXball = deltaXball * 0.995;
deltaYball = deltaYball * 0.995;
}
}
Well, the problem is in your collision code. You've got a lot of magic hard-coded numbers in there, and zero comments describing what they're for. That's going to make this very hard to debug, which makes it hard to help you.
But one thing that jumps out to me is that you're handling collision separately from movement. This might be okay, but with how you're doing it, you can get yourself in this situation:
Imagine Ball A being between Ball B and Ball C.
Ball A is moving to the right.
You check Ball A's collision, and it collides with Ball B. Now you tell Ball A to start moving left.
You then move Ball A to the left, but you don't check whether that will result in a collision. So now Ball A and Ball C are colliding.
Ball C was moving to the right, but then you check its collision. Sure enough it's colliding with Ball A, so you tell it to start moving to the left.
Now Ball A and Ball C are both moving to the left, even though they're colliding.
You might want to go through and add comments until you understand exactly what your code is doing. But honestly, this isn't exactly an easy problem. You might be better off starting over with a blank sketch and starting with something simpler. Try to narrow your problem down to an MCVE. Instead of posting your entire sketch, just get it narrowed down to a specific case with two circles colliding using hard-coded values instead of user input.
You also might want to take a look at the CircleCollision example that comes with the Processing editor. Just go to File -> Examples -> Topics -> Motion -> CircleCollision, and you'll see a sketch that shows an example of handling circle collisions.
Here is the collision code from that example:
void checkCollision(Ball other) {
// get distances between the balls components
PVector bVect = PVector.sub(other.position, position);
// calculate magnitude of the vector separating the balls
float bVectMag = bVect.mag();
if (bVectMag < r + other.r) {
// get angle of bVect
float theta = bVect.heading();
// precalculate trig values
float sine = sin(theta);
float cosine = cos(theta);
/* bTemp will hold rotated ball positions. You
just need to worry about bTemp[1] position*/
PVector[] bTemp = {
new PVector(), new PVector()
};
/* this ball's position is relative to the other
so you can use the vector between them (bVect) as the
reference point in the rotation expressions.
bTemp[0].position.x and bTemp[0].position.y will initialize
automatically to 0.0, which is what you want
since b[1] will rotate around b[0] */
bTemp[1].x = cosine * bVect.x + sine * bVect.y;
bTemp[1].y = cosine * bVect.y - sine * bVect.x;
// rotate Temporary velocities
PVector[] vTemp = {
new PVector(), new PVector()
};
vTemp[0].x = cosine * velocity.x + sine * velocity.y;
vTemp[0].y = cosine * velocity.y - sine * velocity.x;
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
/* Now that velocities are rotated, you can use 1D
conservation of momentum equations to calculate
the final velocity along the x-axis. */
PVector[] vFinal = {
new PVector(), new PVector()
};
// final rotated velocity for b[0]
vFinal[0].x = ((m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) / (m + other.m);
vFinal[0].y = vTemp[0].y;
// final rotated velocity for b[0]
vFinal[1].x = ((other.m - m) * vTemp[1].x + 2 * m * vTemp[0].x) / (m + other.m);
vFinal[1].y = vTemp[1].y;
// hack to avoid clumping
bTemp[0].x += vFinal[0].x;
bTemp[1].x += vFinal[1].x;
/* Rotate ball positions and velocities back
Reverse signs in trig expressions to rotate
in the opposite direction */
// rotate balls
PVector[] bFinal = {
new PVector(), new PVector()
};
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
// update balls to screen position
other.position.x = position.x + bFinal[1].x;
other.position.y = position.y + bFinal[1].y;
position.add(bFinal[0]);
// update velocities
velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
}
}
You can also view web-based versions of the above example:
Circle Collision
Bouncy Bubbles

Two-Dimensional circular collision with odd error

I am a visual learner working on a simple 2D game that requires balls to bounce off of each other with no spin.
I have followed the code in many links and chose to use the example found at Ball to Ball Collision - Detection and Handling
My code however results in both the ball accelerating out of control and also somehow removing balls from the playing field on striking. If someone could describe my errors to me that would be much appreiated. However I would find just as much help in step by step pictures describing the math behind the collisions found in the link above.
public void resolveCollision2(PoolBall ball) {
vector delta = new vector(getXPos() - ball.getXPos(), getYPos() - ball.getYPos());
float d = (float) delta.getMagnitude();
vector mtd = delta.scalerMultiply((32.0 - d) / d);
vector reset = mtd.scalerMultiply(0.5);
XPos = XPos + reset.getXlen();
YPos = YPos + reset.getYlen();
ball.setXPos(ball.getXPos() - reset.getXlen());
ball.setYPos(ball.getYPos() - reset.getYlen());
vector v1 = new vector(getXVel(), getYVel());
vector v2 = new vector(ball.getXVel(), ball.getYVel());
vector v = v1.subtract(v2);
float vn = v.dot(mtd.normalize());
if(vn > 0.0f) return;
float i = (-(1.0f + 0.1f) * vn);
vector impulse = mtd.scalerMultiply(i);
vector v1prime = v1.add(impulse);
vector v2prime = v2.subtract(impulse);
setXVel(Math.sqrt(v1prime.getXlen()));
setYVel(Math.sqrt(v1prime.getYlen()));
ball.setXVel(Math.sqrt(v2prime.getXlen()));
ball.setYVel(Math.sqrt(v2prime.getYlen()));
}
public void poolBallPoolBallCollision() {
double XDif = 0.0;
double YDif = 0.0;
double XDif2 = 0.0;
double YDif2 = 0.0;
for (int i = 0; i < 15; i++) {
for (int j = i + 1; j < 15; j++) {
if (colliding(ballList[i], ballList[j])) {
ballList[i].resolveCollision2(ballList[j]);
}
}
}
}
Things to note
balls have equal mass
no friction
no spin

Making mouse movements humanlike (using an arc rather than a straight line to the destination)

I am making and auto clicker using java.awt.Robot. One of the concerns i have however is the movements aren't very humanlike. Can anyone suggest some changes to my code to make it more human like? Right now it just moves in a straight line.
/**
*
* #param robot The java.awt.Robot being utilized
* #param sx The start x position of the mouse
* #param sy The start y potition of the mouse
* #param ex The end x position of the mouse
* #param ey The end y position of the mouse
* #param speed The speed at which to travel
*/
public void moveMouse(Robot robot, int sx, int sy, int ex, int ey, int speed){
for (int i=0; i<100; i++){
int mov_x = ((ex * i)/100) + (sx*(100-i)/100);
int mov_y = ((ey * i)/100) + (sy*(100-i)/100);
robot.mouseMove(mov_x,mov_y);
robot.delay(speed);
}
}
Update:
I decided to go with an algorithm that makes use of Bézier Curves. It's been a very long time since I implemented the change, but I wanted to post it here just in case people would find it useful in the future. Here is what I ended up with:
public class MouseEvent{
public int getMouseX(){
return MouseInfo.getPointerInfo().getLocation().x;
}
public int getMouseY(){
return MouseInfo.getPointerInfo().getLocation().y;
}
public void moveMouse(int speed, int destX, int destY, int ranX, int ranY){
Mouse.moveMouse(new Robot(), new Point(getMouseX(),getMouseY()), new Point(destX, destY), speed, ranX, ranY);
}
}
public class Mouse {
public static void moveMouse(Robot robot, Point s, Point e, int speed, int ranX, int ranY){
if(Math.abs(e.x-s.x) <= ranX && Math.abs(e.y-s.y) <= ranY)
return;
Point[] cooardList;
double t; //the time interval
double k = .025;
cooardList = new Point[4];
//set the beginning and end points
cooardList[0] = s;
cooardList[3] = new Point(e.x+random(-ranX,ranX),e.y+(random(-ranY,ranY)));
int xout = (int)(Math.abs(e.x - s.x) /10);
int yout = (int)(Math.abs(e.y - s.y) /10);
int x=0,y=0;
x = s.x < e.x
? s.x + ((xout > 0) ? random(1,xout) : 1)
: s.x - ((xout > 0) ? random(1,xout) : 1);
y = s.y < e.y
? s.y + ((yout > 0) ? random(1,yout) : 1)
: s.y - ((yout > 0) ? random(1,yout) : 1);
cooardList[1] = new Point(x,y);
x = e.x < s.x
? e.x + ((xout > 0) ? random(1,xout) : 1)
: e.x - ((xout > 0) ? random(1,xout) : 1);
y = e.y < s.y
? e.y + ((yout > 0) ? random(1,yout) : 1)
: e.y - ((yout > 0) ? random(1,yout) : 1);
cooardList[2] = new Point(x,y);
double px = 0,py = 0;
for(t=k;t<=1+k;t+=k){
//use Berstein polynomials
px=(cooardList[0].x+t*(-cooardList[0].x*3+t*(3*cooardList[0].x-
cooardList[0].x*t)))+t*(3*cooardList[1].x+t*(-6*cooardList[1].x+
cooardList[1].x*3*t))+t*t*(cooardList[2].x*3-cooardList[2].x*3*t)+
cooardList[3].x*t*t*t;
py=(cooardList[0].y+t*(-cooardList[0].y*3+t*(3*cooardList[0].y-
cooardList[0].y*t)))+t*(3*cooardList[1].y+t*(-6*cooardList[1].y+
cooardList[1].y*3*t))+t*t*(cooardList[2].y*3-cooardList[2].y*3*t)+
cooardList[3].y*t*t*t;
robot.mouseMove((int)px, (int)py);
robot.delay(random(speed,speed*2));
}
}
}
public void moveMouse(int sx, int sy, int ex, int ey, int speed) throws AWTException {
Robot robot = new Robot();
int a = 10;
boolean flag = true;
for (int i = 0; i < 100; i++) {
int mov_x = ((ex * i) / 100) + (sx * (100 - i) / 100);
int mov_y = ((ey * i) / 100) + (sy * (100 - i) / 100);
if (flag == true) {
robot.mouseMove(mov_x + a, mov_y); // adds 10 to X-axis
flag = false;
} else {
robot.mouseMove(mov_x - 2 * a, mov_y); // subtracts 20 to X-axis
flag = true;
}
robot.delay(speed);
}
}
Just manipulated your code. This moves the mouse in straight path in X-direction. You can achieve what you want from here. Just get the ideas. You can move any way you want if you can manipulate mov_x and mov_y .
You could use Catmull-Rom method. Generate random controlpoints somewhere around the endpoints and maybe where the straight line would be, asking for coordinates on every step moving from start to end (parameter t, from zero to one).
See demo applets and source: http://www.cse.unsw.edu.au/~lambert/splines/

Categories

Resources