Java/Processing - Moving object in an even line from node to node - java

My title probably does not make much sense which is why I am having a bit of an issue googling my problem.
I am trying to move a shape on the screen from one set of X/Y coordinates to another in a direct line.
So for example,
This is the class method for setting the new target direction.
void setTargetPosition(int targetX, int targetY) {
xTar = targetX;
yTar = targetY;
if (xPos > xTar)
xDir = -1;
else
xDir = 1;
if (yPos > yTar)
yDir = -1;
else
xDir = 1;
}
This would set the Direction of the X/Y variables and the following code would move the player on the screen.
void drawPlayer() {
fill(circleColour);
circle(xPos,yPos,35);
//stops player from moving once target destination has been reached
if (xPos == xTar)
xDir = 0;
if (yPos == yTar)
yDir = 0;
xPos += xDir;
yPos += yDir;
}
The above code does work mostly as intended but I need to find a way to proportionally change the X/Y coordinate so that it's more of a 'direct line' to the destination.
Sorry if this does not make sense. I don't know the right terms to use.

You have to use floating point values for the computation of the movement rather than integral values:
float xTar;
float yTar;
float xPos;
float yPos;
setTargetPosition just set xTar and yTar:
void setTargetPosition(float targetX, float targetY) {
xTar = targetX;
yTar = targetY;
}
In drawPlayer you have to compute the direction vector (PVector) from the objects position to the target:
PVector dir = new PVector(xTar - xPos, yTar - yPos);
if the length of the vector (mag()) is greater than 0, the you have to move the object:
if (dir.mag() > 0.0) {
// [...]
}
If you have to move the object, then compute the Unit vector by normalize(). Note, the length of a unit vector is 1. Multiply the vector by a certain speed by mult(). This scales the vector to a certain length. Ensure that the length of the vector is not greater than the distance to the object (min(speed, dir.mag())). Finally add the components of the vector to the position of the object:
dir.normalize();
dir.mult(min(speed, dir.mag()));
xPos += dir.x;
yPos += dir.y;
See the example:
class Player {
float xTar;
float yTar;
float xPos;
float yPos;
color circleColour = color(255, 0, 0);
Player(float x, float y)
{
xTar = xPos = x;
yTar = yPos = y;
}
void setTargetPosition(float targetX, float targetY) {
xTar = targetX;
yTar = targetY;
}
void drawPlayer() {
fill(circleColour);
circle(xPos,yPos,35);
float speed = 2.0;
PVector dir = new PVector(xTar - xPos, yTar - yPos);
if (dir.mag() > 0.0) {
dir.normalize();
dir.mult(min(speed, dir.mag()));
xPos += dir.x;
yPos += dir.y;
}
}
}
Player player;
void setup() {
size(500, 500);
player = new Player(width/2, height/2);
}
void draw() {
background(255);
player.drawPlayer();
}
void mousePressed() {
player.setTargetPosition(mouseX, mouseY);
}

Related

Processing - Add hitTest and mousePressed to an Animation with 100 balls

I want to create an ArrayList of ball objects, which should be in a loop until there are 100 pieces.
Now my problem: I must implement a function hitTest, so that when you click on a ball it gets removed. In the same position, there should appear two balls then, which go into a different direction.
Can someone help me? I am so lost...
Here's my code so far:
Ball b;
ArrayList<Ball> balls;
void setup() {
size(800, 800);
balls = new ArrayList<Ball>();
for (int i = 0; i<100; i++) {
drawBall();
}
}
void draw() {
background(255);
//b.update();
for (int i= 0; i<balls.size(); i++) {
balls.get(i).update();
}
}
void drawBall() {
Ball b = new Ball();
balls.add(b);
}
class Ball {
private float x;
private float y;
private float ballSize;
private float dirX;
private float dirY;
private boolean moving = true;
Ball() {
this.x = width/2;
this.y = height/2;
this.ballSize = random(10.0, 30.0);
this.dirX = random(-3.0, 3.0);
this.dirY = random(-3.0, 3.0);
if (this.dirX<1.0 && this.dirX>1.0) //1 statt -1 macht zufälliger { this.dirX = 1.0; }
if (this.dirY<1.0 && this.dirY>1.0) {
this.dirY = 1.0;
}
}
public void update() {
stroke(255);
fill(random(255), random(255), random(255), random(255));
ellipse( this.x, this.y, this.ballSize, this.ballSize);
if (this.moving == true) {
this.x += this.dirX;
this.y += this.dirY;
}
if (this.x+ this.ballSize/2> width ||this.x- this.ballSize/2<0) {
this.dirX= dirX*-1;
}
if (this.y+ this.ballSize/2> height ||this.y- this.ballSize/2<0) {
this.dirY= dirY*-1;
}
}
}
Break your problem down into smaller, simpler steps.
e.g.
when you click on a ball, it gets removed. In the same position, there should appear two balls then, which go into a different direction.
when you click on a ball: you can mix the dist() function (to check if the distance between the mouse and a ball is smaller then the radius) with mouseClicked() (or mousePressed() / mouseReleased())
it gets removed: you already called balls.add(). Similarly you can call balls.remove() passing the ball object or index to remove (depending on the case)
same position: you need to remember (store the coordinates) of the ball that was clicked to add two balls at the same position
different direction: you already do that in the Ball() constructor: you can apply the same logic on each new ball.
Here's a basic sketch to illustrate point 1, using dist():
void draw(){
background(255);
int ballX = 50;
int ballY = 50;
int ballRadius = 35;
if(dist(ballX, ballY, mouseX, mouseY) < ballRadius){
fill(0,192,0);
}else{
fill(192,0,0);
}
ellipse(ballX,ballY, ballRadius * 2, ballRadius * 2);
}
Paste this in a new sketch, run it and you should get the hang of using dist() in the context of your problem.
Regarding points 2,3,4 here's a modified version of your sketch with comments and a slightly different approach: instead of removing a ball to add a new one at the exact location with a different direction, simply randomise the direction. Visually it will look similar to a new ball (except the random size/colour). With the clicked ball being re-used, only a second one is added:
Ball b;
ArrayList<Ball> balls;
void setup() {
size(800, 800);
balls = new ArrayList<Ball>();
for (int i = 0; i<100; i++) {
drawBall();
}
}
void draw() {
background(255);
//b.update();
for (int i= 0; i<balls.size(); i++) {
// pass the mouse coordinates to each ball to check if it's hovered or not
balls.get(i).update(mouseX, mouseY);
}
}
// on mouse pressed
void mousePressed(){
for (int i= 0; i<balls.size(); i++) {
// make current ball reusable in this loop
Ball ball = balls.get(i);
// if ball is hovered
if(ball.isHovered){
// randomize direction of current ball
ball.setRandomDirection();
// add a new ball from the current location
balls.add(ball.copy());
}
}
}
void drawBall() {
Ball b = new Ball();
balls.add(b);
}
class Ball {
private float x;
private float y;
private float ballSize;
private float dirX;
private float dirY;
private boolean moving = true;
private color fillColor;
// property to keep track if the ball is hovered or not
private boolean isHovered;
Ball() {
this.x = width/2;
this.y = height/2;
this.ballSize = random(10.0, 30.0);
this.setRandomDirection();
this.fillColor = color(random(255), random(255), random(255), random(255));
}
// extract random direction calls into a re-usable function (handy for click / collision)
void setRandomDirection(){
this.dirX = random(-3.0, 3.0);
this.dirY = random(-3.0, 3.0);
if (this.dirX<1.0 && this.dirX>1.0) { //1 statt -1 macht zufälliger { this.dirX = 1.0; }
if (this.dirY<1.0 && this.dirY>1.0) {
this.dirY = 1.0;
}
}
}
public void update(int x, int y) {
// euclidean distance between this ball's coordinates a given x y position (e.g. mouse)
isHovered = dist(this.x, this.y, x, y) < this.ballSize / 2;
// optional: use stroke color to visually display highlighted ball
if(isHovered){
stroke(0);
}else{
stroke(255);
}
fill(fillColor);
ellipse( this.x, this.y, this.ballSize, this.ballSize);
if (this.moving == true) {
this.x += this.dirX;
this.y += this.dirY;
}
if (this.x + this.ballSize / 2 > width ||
this.x - this.ballSize / 2 < 0) {
this.dirX= dirX*-1;
}
if (this.y + this.ballSize / 2 > height ||
this.y - this.ballSize / 2 < 0) {
this.dirY= dirY*-1;
}
}
// utility function: simply copies this ball's x,y position to the new one
Ball copy(){
Ball clone = new Ball();
clone.x = this.x;
clone.y = this.y;
return clone;
}
}
The copy() method is flexible enough that it's ease to remove one ball to add two more if that is an absolute must. For example:
// on mouse pressed
void mousePressed(){
for (int i= 0; i<balls.size(); i++) {
// make current ball reusable in this loop
Ball ball = balls.get(i);
// if ball is hovered
if(ball.isHovered){
// add two new balls from the current location
balls.add(ball.copy());
balls.add(ball.copy());
// remove ball
balls.remove(i);
}
}
}

Aiming in LibGDX using the mouse

I am making a game in libGDX and I am having trouble setting up the Bullet class. I am unable to get the projectiles to go to the mouse location.
I have tried to use Math.atan() to find the angle that I need to fire at but I couldn't get that to work. right now I am just using the distance to find velocity on the x and y-axis.
private static final int SPEED = 500;
private static Texture texture;
String path = "C:\\Users\\minicodcraft\\Downloads\\game\\core\\assets\\";
private float x, y; // starting position
private float xVelocity, yVelocity;
private float yPos; // the y position of the mouse input
private float xPos; // the x position of the mouse input
public Bullet(float x, float y, float yPos, float xPos) {
this.x = x;
this.y = y;
this.xPos = xPos;
this.yPos = yPos;
this.xVelocity = 0f;
this.yVelocity = 0f;
calcDirection();
if (texture == null) {
texture = new Texture(path + "Bullet.png");
}
}
private void calcDirection() {
float xDistanceFromTarget = Math.abs(xPos - x);
float yDistanceFromTarget = Math.abs(yPos - y);
float totalDistanceFromTarget = xDistanceFromTarget + yDistanceFromTarget;
xVelocity = xDistanceFromTarget / totalDistanceFromTarget;
yVelocity = yDistanceFromTarget / totalDistanceFromTarget;
if (xPos < x) {
xVelocity *= -1;
}
if (yPos < y) {
yVelocity *= -1;
}
}
public void update(float deltaTime) {
if (x > 0 && y > 0) {
x += xVelocity * SPEED * deltaTime;
y += yVelocity * SPEED * deltaTime;
} else if (x < 0 && y > 0) {
x -= xVelocity * SPEED * deltaTime;
y += yVelocity * SPEED * deltaTime;
} else if (x > 0 && y < 0) {
x += xVelocity * SPEED * deltaTime;
y -= yVelocity * SPEED * deltaTime;
} else if (x < 0 && y < 0) {
x -= xVelocity * SPEED * deltaTime;
y -= yVelocity * SPEED * deltaTime;
}
}
public void render(SpriteBatch batch) {
batch.draw(texture, x, y);
}
The following code gives a velocity towards the mouse position from the player's position:
float diffX = mouse.x - player.x;
float diffY = mouse.y - player.y;
float angle = (float) Math.atan2(diffY, diffX);
float velX = (float) (Math.cos(angle));
float velY = (float) (Math.sin(angle));
Vector2 velocity = new Vector2(velX, -velY);
velocity.nor();
velocity.scl(magnitudeSpeed);
velocity.scl(deltaTime);
Then velocity.x is the x component of the velocity. Respective for y. No need to multiply by speed and deltaTime again, already done above.

(Java / Processing) How to create several instances of an object on different positions on the screen?

I am unable to create several instances of the waveClock object even though I have put it in an array and marked the centre positions for each object. I would like to create 4 objects in one window, all responding to different sound frequencies/beat onsets etc
Could someone shed some light on how to go about this? I believe it may be an issue with the centerX and centerY variables in the waveClock class
ArrayList<waveClock> waveClocks = new ArrayList<waveClock>();
//global variables
float angnoise, radiusnoise;
float xnoise, ynoise;
float angle = -PI/6;
float radius;
float strokeCol = 254;
int strokeChange = -1;
int speed; //changes speed of visualisation once beat is detected?
void setup()
//for every waveClock we need 180 pixels width, then add 20 pixels for first gap
size(740, 650);
background(255);
//code is called
waveClocks.add(new waveClock(100, height/2, minRadius, bassColour, lowBassBand, highBassBand, numberOfLowOnsetsThreshold));
waveClocks.add(new waveClock(280, height/2, minRadius, midColour, lowMidBand, highMidBand, numberOfMidOnsetsThreshold));
waveClocks.add(new waveClock(460, height/2, minRadius, highColour, lowHighBand, highHighBand, numberOfHighOnsetsThreshold));
waveClocks.add(new waveClock(640, height/2, minRadius, veryHighColour, lowVeryHighBand, highVeryHighBand, numberOfVeryHighOnsetsThreshold));
//set the min and max radius of each of the viz circles
/* for (int i = 0; i < waveClocks.size(); i++) {
//go through the arraylist of waveClocks and set the min and max radius of each circle
waveClocks.get(i).setMinMaxRadius(minRadius, maxRadius);
}*/
song.play();
beat = new BeatDetect(song.bufferSize(), song.sampleRate());
bl = new BeatListener(beat, song);
}
void draw() {
//clear the screen by painting it black
//background(0);
for (int i = 0; i < waveClocks.size(); i++) {
//has there been a beat in the range? get(circle ID).low band, high band etc.
if (beat.isRange(waveClocks.get(i).getLowBand(), waveClocks.get(i).getHighBand(), waveClocks.get(i).getOnsetThreshold())) {
waveClocks.get(i).setMaxRadius();
}
//waveClocks.get(i).drawCircle();
waveClocks.get(i).drawWaveClock();
}
}
waveClock class in a separate tab
//class is an architecture blueprint
//objects are the actual buildings built from the methods (can make as many as you like)
//constructor is the builder/constructor literally
class waveClock {
float centerX; //co-ordinates of circle's position
float centerY; //co-ordinates of circle's position
float radius; //avg radius
// float minRadius; //smallest size it can be
// float maxRadius; //biggest size it can be
color col; //colour
int onsetThreshold; //
int lowBand; //looks at lowest band of frequency and makes circle sensitive to it
int highBand; //looks at highest band of frequency and makes circle sensitive to it
boolean onset; //has there been an onset (beat has occurred or not?)
//the constructor
waveClock(float x, float y, float r, color c, int lb, int hb, int t) {
centerX = x;
centerY = y;
radius = r;
col = c;
lowBand = lb;
highBand = hb;
onsetThreshold = t;
}
void drawWaveClock() {
radiusnoise += 0.005;
radius = (noise(radiusnoise)*350) + 1;
angnoise += 0.005;
angle += (noise(angnoise)*6) - 3;
if (angle > 360) {
angle -= 360;
} else if (angle < 0) {
angle += 360;
}
xnoise += 0.01;
ynoise =+ 0.01;
float centerX = width/2 + (noise(xnoise)*100) - 50;
float centerY = height/2 + (noise(ynoise)*100) - 50;
float rad = radians(angle);
float x1 = centerX + (radius*cos(rad));
float y1 = centerY + (radius*sin(rad));
float opprad = rad + PI;
float x2 = centerX + (radius*cos(opprad));
float y2 = centerY + (radius*sin(opprad));
strokeCol += strokeChange;
if (strokeCol > 354) {
strokeChange = -1;
} else if (strokeCol < 0) {
strokeChange = 1;
}
stroke(strokeCol, 60);
strokeWeight(1);
line(x1, y1, x2, y2);
}
}
You aren't ever using the class-level centerX and centerY variables. Instead, you're recalculating a new centerX and centerY in the drawWaveClock() function.
float centerX = width/2 + (noise(xnoise)*100) - 50;
float centerY = height/2 + (noise(ynoise)*100) - 50;
These are all drawn from the center of the screen, so the waves will end up in the same position.
In the future, please try to narrow your problem down to a MCVE that demonstrates the problem. Also please use proper naming conventions- classes start with an upper-case letter, for example. Good luck.

Queuing movement to multiple points is inaccurate

I created a method that would move a sprite in any direction to a point at a constant speed. I then added a queuing system for each point to move to.
My problem is that if a point becomes queued, usually only the first movement will be correct, then the sprite will seem to move to random locations for other points. The weird part is if I add a
if((int) x != (int) moveInfo.getTargetX() && (int) y != moveInfo.getTargetY()){
...
}else{
this.setPosition(moveInfo.getTargetX(), moveInfo.getTargetY());
...
}
the sprite corrects itself to its target position after it finishes moving to its random point. I created a debugger and it wasn't the sprites image offsetting either as the x and y values were real.
Here is some code I created that may cause the problem...
x and y are doubles.
Movement to point queuing constructor:
Queue<MoveInfo> moveTo = new LinkedList<MoveInfo>();
MoveTo class
private class MoveInfo{
private double targetX, targetY;
private double deltaX, deltaY;
private double direction;
private double speed;
private boolean ai;
public MoveInfo(double targetX, double targetY, double speed){
this.targetX = targetX;
this.targetY = targetY;
this.speed = speed;
this.deltaX = targetX - x;
this.deltaY = targetY - y;
calculateDirection();
ai = false;
}
public void calculateDirection(){
this.direction = Math.atan2(deltaX, deltaY);
}
... //Setters and getters.
}
Called every game update:
private void moveToUpdate(){
if(!spriteMoving && !moveTo.isEmpty()){
if(!moveTo.peek().isAi()){
moveInfo = moveTo.poll();
spriteMoving = true;
System.out.println("Next X"+moveInfo.targetX+" Y"+moveInfo.targetY);
}
}else if(spriteMoving && moveInfo != null){
if((int) x != (int) moveInfo.getTargetX() && (int) y != moveInfo.getTargetY()){
double nextY = y + (moveInfo.getSpeed() * Math.cos(moveInfo.getDirection()));
double nextX = x + (moveInfo.getSpeed() * Math.sin(moveInfo.getDirection()));
setPosition(nextX, nextY);
}else{
this.setPosition(moveInfo.getTargetX(), moveInfo.getTargetY());
spriteMoving = false;
moveInfo = null;
}
}
}
If you wish to see other parts of the code, let me know in the comments.

Expecting TRIPLE_DOT, found ';'

I'm writing a program using Processing but I keep getting Expecting TRIPLE_DOT, found ';'.
What could be wrong?
class Collision {
Ball ball = new Ball();
Block block = new Block();
int ball_xpos;
int ball_rad;
int ball_ypos;
int block_width;
int block_height;
int block_control;
Collision(ball.xpos, ball.rad, ball.ypos, block.width, block.height, block.control){
//
}
void detect_() {
//not done yet
}
}
Ball class:
class Ball {
int rad = 30; // Width of the shape
float xpos, ypos; // Starting position of shape
float xspeed = 2.8; // Speed of the shape
float yspeed = 2.2; // Speed of the shape
int xdirection = 1; // Left or Right
int ydirection = 1; // Top to Bottom
Ball() {
ellipseMode(RADIUS);
// Set the starting position of the shape
xpos = width/2;
ypos = height/2;
}
void display() {
ellipseMode(CENTER);
ellipse(xpos, ypos, 410, 40);
}
void move() {
// Update the position of the shape
xpos = xpos + ( xspeed * xdirection );
ypos = ypos + ( yspeed * ydirection );
// Test to see if the shape exceeds the boundaries of the screen
// If it does, reverse its direction by multiplying by -1
if (xpos > width-rad || xpos < rad) {
xdirection *= -1;
}
if (ypos > height-rad || ypos < rad) {
ydirection *= -1;
}
// Draw the shape
ellipse(xpos, ypos, rad, rad);
}
}
In the parameter names in your constructor, the dots (.) should be replaced with _. And you should give types to those parameters:
Collision(int ball_xpos, int ball_rad, ... so on){
//
}
If you use ball.xpos, then compiler expects a var-args after the 1st dot(.) after ball.
But it seems like want to pass attributes of Ball class, to initialize the fields with the Ball class attribute. In that case, you should just pass a single parameter, that is a reference to Ball:
Collision(Ball ball) {
this.ball = ball;
}
But I don't see why at all you are having those fields (ball_xpos, ball_ypos) in Collision class, given that you also have a Ball type field. You can remove them, and just set ball reference to the reference passed in the above constructor.
Same thing for Block type reference. You are simply having copy of the fields of Block and Ball in Collision class again. Not needed.

Categories