Calculating which drawn circle is the nearest to another one - java

i want to get the x and y of the circle with the lowest distance to my special circle. I am creating 25 circles with a timer and need to check every drawn circle on the field. What I already have is this:
protected void onDraw (android.graphics.Canvas canvas){
//If arrow-button was clicked, do ... get the circle with the lowest distance to viking circle
if (buttonClicked == true) {
//distance of the current circle from the viking
int tempCircleDistance = 0;
//the minimum distance we have found so far in our loop
int minCircleDistance = 0;
//index of the min circle we have found so far
int indexOfNearest=0;
for(int i = 0; i<circlesOnTheField; i++)
{
//help me Phytagoras
tempCircleDistance = (int) (Math.sqrt((viking.getX() - circles.get(i).getX())*
(viking.getX() - circles.get(i).getX())+
(viking.getY() - circles.get(i).getY())*
(viking.getY() - circles.get(i).getY()))-
(viking.getR() + circles.get(i).getR()));
//first cycle or did we find the nearest circle? If so update our variables
if(i==0||tempCircleDistance<minCircleDistance)
{
indexOfNearest=i;
minCircleDistance=tempCircleDistance;
}
}
if(circles.get(indexOfNearest).getIsDrawn() == true) {
//draw the line with the given index of the nearest circle
//At this point, nearest circle is calculated and we draw a line from viking to that circle
canvas.drawLine(viking.getX(), viking.getY(),
circles.get(indexOfNearest).getX(),
circles.get(indexOfNearest).getY(),
pgoal);
//Here we delete the circle and increase our variable frags for one more killed opponent.
deleteCircle(circles.get(indexOfNearest));
circlesOnTheField--;
frags++;
buttonClicked = false;
}
}
//END
//This is where the circles are drawn
for(int k = 0; k<circlesOnTheField; k++) {
canvas.drawCircle(circles.get(k).getX(), circles.get(k).getY(), circles.get(k).getR(), p3);
circles.get(k).setIsDrawn(true);
}
}
So I store my circles in the array called circles[] and have my fixed second circle viking to calculate the distance to. The variable arrowCircle should store the name of the nearest circle. Then I want to draw a line between the nearest circle to the viking circle.
Any ideas what's wrong?
Thanks in advance
I think the part with if(i>=1) {... might be incorrect.
Edited 21.09.15:
This is what happens on deleteCircle():
public static void deleteCircle(Circle circle) {
circles.remove(circle);
circlesOnTheField--;
}
And the addCircle():
public static void addCircle() {
if(circlesOnTheField >= 25) {
circlesOnTheField = 25;
}
else{
circlesOnTheField++;
}
}
I have one timer which executes addCircle() and another one with moveCircle():
public static void moveCircle() {
for(int i=0; i<circlesOnTheField; i++) {
//Move circles downwards
circles.get(i).setY(circles.get(i).getY()+5);
//Check if the circle collides with the viking
if(detectCollision(viking, circles.get(i))) {
deleteCircle(circles.get(i));
circles.get(i).setIsDrawn(false);
life--;
}
//Check if the circle intersects the goal line and recreate it if yes
if(intersects(circles.get(i).getX(), circles.get(i).getY(), circles.get(i).getR(), 0, 750, 500, 760)) {
deleteCircle(circles.get(i));
circles.get(i).setIsDrawn(false);
circlesInGoal++;
}
}
}
And finally, this is what is executed in the constructor:
public static void createNewCircleOnCanvas() {
//Collision Detection
circles.clear();
int createdCircles = 0;
outer: while (createdCircles < 25) {
int randomX = r.nextInt(500);
int randomY = r.nextInt(300);
candidate = new Circle(randomX, randomY, 33, "Circle"+createdCircles, false);
inner: for (int z = 0; z<createdCircles;z++) {
//If new created circle collides with any already created circle or viking, continue with outer
if (detectCollision(candidate, circles.get(z))) continue outer;
}
circles.add(candidate);
createdCircles++;
}

Im assuming getR() gives the radius?!
Then try this instead of your for loop:
//distance of the current circle from the viking
int tempCircleDistance = 0;
//the minimum distance we have found so far in our loop
int minCircleDistance = 0;
//index of the min circle we have found so far
int indexOfNearest=0;
for(int i = 0; i<circlesOnTheField; i++)
{
//help me Phytagoras
tempCircleDistance = (int) (Math.sqrt((viking.getX() - circles[i].getX())*
(viking.getX() - circles[i].getX())+
(viking.getY() - circles[i].getY())*
(viking.getY() - circles[i].getY()))-
(viking.getR() + circles[i].getR()));
//first cycle or did we find the nearest circle? If so update our variables
if(i==0||tempCircleDistance<minCircleDistance)
{
indexOfNearest=i;
minCircleDistance=tempCircleDistance;
}
}
//draw the line with the given index of the nearest circle
canvas.drawLine(viking.getX(), viking.getY(),
circles[indexOfNearest].getX(),
circles[indexOfNearest].getY(),
pgoal);
just copy paste and it will magically work ╰( ͡° ͜ʖ ͡° )つ──☆*:・゚
No need to go through the Array twice, just hold the index of the nearest circle in a variable

Related

JavaFX: Nested for loops for placing rectangles isn't working

I am trying to create a checkerboard by using for loops and creating different colored rectangles. I'm using two nested for loops: the 1st one that takes care of all rows starting with a black square and the 2nd one that takes care of all rows starting with a red square. I have a list of x coordinates and two separate lists for y coordinates: y1coords being all y coordinates that correspond to a row starting with a black square and y2coords being all y coordinates that correspond to a row starting with a red square.
//Nested for loop for every row starting with a black square
List<Double> y1coords = Arrays.asList(0.0,150.0,300.0,450.0);
List<Double> xcoords = Arrays.asList(0.0,75.0,150.0,225.0,300.0,375.0,450.0,525.0);
for (int j=0; j<y1coords.size(); j++)
{
for (int i=0; i<xcoords.size(); i++)
{
if (xcoords.get(i)%2 == 0)
{
Rectangle square = new Rectangle(75,75,Color.BLACK);
square.setX(xcoords.get(i));
square.setY(y1coords.get(j));
root.getChildren().add(square);
}
else
{
Rectangle square = new Rectangle(75,75,Color.RED);
square.setX(xcoords.get(i));
square.setY(y1coords.get(j));
root.getChildren().add(square);
}
}
}
//Nested for loop for every row starting with a red square
List<Double> y2coords = Arrays.asList(75.0,225.0,375.0,525.0);
for (int j=0; j<y2coords.size(); j++)
{
for (int i=0; i<xcoords.size(); i++)
{
if (xcoords.get(i)%2 != 0)
{
Rectangle square = new Rectangle(75,75,Color.BLACK);
square.setX(xcoords.get(i));
square.setX(y2coords.get(j));
root.getChildren().add(square);
}
else
{
Rectangle square = new Rectangle(75,75,Color.RED);
square.setX(xcoords.get(i));
square.setX(y2coords.get(j));
root.getChildren().add(square);
}
}
}
I want this to create a nice looking checkerboard, but it keeps giving me the first row completely black and doesn't do any of the rows starting with a red square. Visit https://pbs.twimg.com/media/D6szyy7X4AEMGtk.jpg:large to see what I mean.
edit your code in the second nested for loops
from
square.setX(y2coords.get(j));
to
square.setY(y2coords.get(j));
the final result is
if (xcoords.get(i) % 2 != 0) {
Rectangle square = new Rectangle(75, 75, Color.BLACK);
square.setX(xcoords.get(i));
/*here*/ square.setY(y2coords.get(j));
root.getChildren().add(square);
} else {
Rectangle square = new Rectangle(75, 75, Color.RED);
square.setX(xcoords.get(i));
/*and here*/ square.setY(y2coords.get(j));
root.getChildren().add(square);
}

How to make the bouncing ball collide with the array of rectangles on Processing?

im trying to make the bouncing ball bounce on the arrays of rectangles. I've looked at various other codes but cant seem to find a solution. Would appreciate any help!!!
Basically, i want the bouncing ball to recognise that theres the rectangles there and for it to be able to jump onto the rectangles.
PVector location; // Location of shape
PVector velocity; // Velocity of shape
PVector gravity; // Gravity acts at the shape's acceleration
PVector upwardForce;
PImage bg;
int radius = 10, directionX = 1, directionY = 0;
float x=20, y=20, speed=0.5;
int xarray[] = new int[20];
int yarray[] = new int[20];
// =========================================================
void setup() {
size(380,750);
location = new PVector(100,50);
velocity = new PVector(0.0,2.1);
upwardForce = new PVector(0.0,-10.0);
gravity = new PVector(0,0.4);
bg = loadImage("bg.png");
bg.resize(1600,1600);
background(0);
for(int i =0; i< 20;i++){
xarray[i]= i*100;
yarray[i] = 750-int(random(10))*50;
}
}
int xd =0, yd=0;
void draw() {
background(0);
noStroke();
xd--;
yd++;
// display image twice:
image(bg, y, 0);
image(bg, y+bg.height, 0);
// pos
y--;
if (y<-bg.height)
y=0;
for (int i = 0;i< 20;i++){
if (xarray[i] <100 && xarray[i]+100 >100){
fill(255,0,0);
}
else {
fill(255);
}
rect(xarray[i],yarray[i],100,1200);
fill(255);
xarray[i]=xarray[i]-4;
//yarray[i]=yarray[i]+1;
if (xarray[i] + 100 < 0){
xarray[i]+=2000;
// yarray[i]-=850;
}
}
// changing Position
x=x+speed*directionX;
y=y+speed*directionY;
// check boundaries
if ((x>width-radius) || (x<radius))
{
directionX=-directionX;
}
if ((y>height-radius) || (y<radius))
{
directionY=-directionY;
}
// draw
// if(direction==1)
// Add velocity to the location.
location.add(velocity);
// Add gravity to velocity
velocity.add(gravity);
// Bounce off edges
if ((location.x > width) || (location.x < 0)) {
velocity.x = velocity.x * -1;
}
if ((location.y > height) || (location.y < 0)){
// We're reducing velocity ever so slightly
// when it hits the bottom of the window
velocity.y = velocity.y * -0.95;
location.y = height;
}
// Display circle at location vector
stroke(255);
strokeWeight(0);
fill(255);
ellipse(location.x,location.y,30,30);
}
void keyPressed()
{
velocity.add(upwardForce);
}
The best advice we can give you is to break your problem down into smaller steps and to take those steps on one at a time.
For example, can you create a simple sketch that just shows a single hard-coded circle and a single hard-coded rectangle? Now add some code that prints a message to the console if they're colliding. You're going to have to do some research into collision detection, but here's a hint: a common technique is to treat the ball as a rectangle, so you can do rectangle-rectangle collision detection.
Get that working perfectly by itself, and then work your way forward in small steps. Can you add a second rectangle to your sketch? How about a third?
Then if you get stuck, you can post a MCVE (not your whole project, just a small example) along with a more specific question. Good luck.
Here's a few suggestions:
You're best off using a Rectangle class. That way, you don't have to store the locations in an array, and the collide function can be a method of the class. It's easier to just call the positions of the rectangles "x" and "y", but this would obviously conflict with the x and y global variables which you declared at the top of the code. Assuming that you would want to make the ball bounce if it collided, you would need to have a "ballLastx" and a "ballLasty" in order to keep track of which direction the ball came from. You would also need to store the Rectangles in an array or arrayList. It would be something like this:
PVector lastLocation;
Rectangle[] rects;
As for the rectangle class, here's how it would probably look like this:
class Rectangle {
float x, y;
Rectangle(float x_, float y_) {
x = x_;
y = y_;
}
void show() {
//Displays rectangle
if (x < 100 && x+100 > 100) fill(255,0,0);
else fill(255);
rect(x,y,100,1200);
fill(255);
x=x-4;
if (x + 100 < 0) x+=2000;
}
private boolean insideX(PVector pos) {
return (pos.x + 15 >= x && pos.x - 15 <= x+100);
}
private boolean insideY(PVector pos) {
return (pos.y + 15 >= y && pos.y - 15 <= x + 1200);
}
boolean collidedX() {
//Detects if the ball has collided along the x-axis
return ((insideX(location) && !insideX(lastLocation)) && insideY(location))
}
boolean collidedY() {
//Detects if the ball has collided along the y-axis
return ((insideY(location) && !insideY(lastLocation)) && insideX(location))
}
}
And then, in your setup function, you could declare the Rectangle classes in a for-loop:
//declare the rects array
rects = new Rectangle[20];
//declare each item of the rects array to be a Rectangle
for(int i = 0; i < rects.length; i++) {
rects[i] = new Rectangle(i*100, 750-int(random(0,10))*50;
}
In order to detect the collision and to bounce the ball, you would need to loop through all of the Rectangles and see if the ball should bounce off any of them:
boolean bouncex = false;
boolean bouncey = false;
//see if any of the rects are colliding with the ball
for(Rectangle r : rects) {
if(r.collidedX()) bouncex = true;
if(r.collidedY()) bouncey = true;
}
//if any are colliding, bounce the ball
if(bouncex) velocity.x = -velocity.x;
if(bouncey) velocity.y = -velocity.y;
Finally, don't forget to set the lastLocation PVector to the current location, just before moving the current location:
lastLocation = location.copy();
//move the ball...
Hope this was helpful!

Moving 2D Array For Space Invaders Game

So the title pretty much explains it all, recently I have learned about 2D arrays but I am a little confused on how to make the 2D array move correctly in this Space Invaders game I am creating.
Right now I have Aliens moving left to right (and vice versa), however, they don't all move down at the same time, they move down column by column. Anyone know where to edit the code?
Here is my code for the Aliens:
class Aliens {
int x = 100, y = 75, deltaX = 1;
Aliens (int x, int y) {
this.x = x;
this.y = y;
}
void drawAlien() {
fill(255);
rect(x, y, 25, 25);
}
void moveAlien() {
x = x + deltaX;
if (x >= width) {
y = y + 20;
deltaX = - deltaX;
} else if (x <=0) {
y = y + 20;
deltaX = - deltaX;
}
}
void updateAlien() {
drawAlien();
moveAlien();
}
}
and my main class:
import ddf.minim.*;
//Global Variables
PImage splash;
PFont roboto;
Defender player;
Aliens[][] alienArray = new Aliens[15][3];
Missile missile;
int gameMode = 0;
int score = 0;
void setup() {
size(1000, 750);
rectMode(CENTER);
textAlign(CENTER, CENTER);
splash = loadImage("Splash.png");
player = new Defender();
for (int row = 0; row < 15; row++) {
for (int column = 0; column < 3; column++) {
alienArray[row][column] = new Aliens((row + 1) * 50, (column + 1) * 50);
}
}
roboto = createFont("Roboto-Regular.ttf", 32);
textFont(roboto);
}
void draw() {
if (gameMode == 0) {
background(0);
textSize(75);
text("Space Invaders", width/2, height/8);
textSize(25);
text("Created by Ryan Simms", width/2, height/4);
textSize(45);
text("Press SPACE to Begin", width/2, height - 100);
image(splash, width/2-125, height/4 + 75);
} else if (gameMode == 1) {
background(0);
score();
player.updateDefender();
for (int row = 0; row < 10; row ++) {
for (int column = 0; column < 3; column++) {
alienArray[row][column].updateAlien();
}
}
if (missile != null) {
missile.updateMissile();
}
if (keyPressed) {
if (key == ' ') {
if (missile == null) {
missile = new Missile(player.x);
}
}
}
if (missile != null) {
if (missile.y <= 0) {
missile = null;
}
}
}
}
void score() {
textSize(20);
text("Score: " + score, 40, 15);
}
void keyPressed() {
if (key == ' ') {
gameMode = 1;
}
}
The logic flaw is in the moveAlien() method. You move the x position of an alien by a certain delta. If it is detected that the alien has passed some screen boundary (the x >= width and x <=0 checks), you invert the delta to reverse the movement of the alien, and also update the y position to have it move down.
Since the aliens are oriented in vertical columns, one column will always reach such a boundary while the others haven't yet. So that column will go down, and also begin reverting its movement. The other columns will then "catch up" later. So not only do they move down per column, the columns will also end up moving through one another.
You'll have to implement some logic to have your aliens move as a block, by detecting when the rightmost remaining alien has reached the right boundary, or the leftmost remaining alien has reached the left boundary, and then doing an update on all aliens to move down.
The idea of having each alien have its own state, putting the logic for controlling it in the alien class and calling that is actually good object-oriented design. It just so happens that for Space Invaders, the aliens all affect one another because they move in a block. As a result, your design results in them having too much individuality. Perhaps you can add some class that maintains state for the invader array as a whole (such as the leftmost and rightmost column still having an alien, direction of the entire block), control that in your movement loop and have it update the alien's location in turn.

Processing in Java - drawn clearing rectangle breaks after calling a method

I am using Processing in Java to perpetually draw a line graph. This requires a clearing rectangle to draw over drawn lines to make room for the new part of the graph. Everything works fine, but when I call a method, the clearing stops working as it did before. Basically the clearing works by drawing a rectangle in front of where the line is currently at
Below are the two main methods involved. The drawGraph function works fine until I call the redrawGraph which redraws the graph based on the zoom. I think the center variable is the cause of the problem but I cannot figure out why.
public void drawGraph()
{
checkZoom();
int currentValue = seismograph.getCurrentValue();
int lastValue = seismograph.getLastValue();
step = step + zoom;
if(step>offset){
if(restartDraw == true)
{
drawOnGraphics(step-zoom, lastY2, step, currentValue);
image(graphGraphics, 0, 0);
restartDraw = false;
}else{
drawOnGraphics(step-zoom, lastValue, step, currentValue);
image(graphGraphics, 0, 0);
}
} // draw graph (connect last to current point // increase step - x axis
float xClear = step+10; // being clearing area in front of current graph
if (xClear>width - 231) {
xClear = offset - 10; // adjust for far side of the screen
}
graphGraphics.beginDraw();
if (step>graphSizeX+offset) { // draw two clearing rectangles when graph isn't split
// left = bg.get(0, 0, Math.round(step-graphSizeX), height - 200); // capture clearing rectangle from the left side of the background image
// graphGraphics.image(left, 0, 0); // print left clearing rectangle
// if (step+10<width) {
// right = bg.get(Math.round(step+10), 0, width, height - 200); // capture clearing rectangle from the right side of the background image
// // print right clearing rectangle
// }
} else { // draw one clearing rectangle when graph is split
center = bg.get(Math.round(xClear), lastY2, offset, height - 200); // capture clearing rectangle from the center of the background image
graphGraphics.image(center, xClear - 5, 0);// print center clearing rectangle
}
if (step > graphSizeX+offset) { // reset set when graph reaches the end
step = 0+offset;
}
graphGraphics.endDraw();
image(graphGraphics, 0 , 0);
System.out.println("step: " + step + " zoom: " + zoom + " currentValue: "+ currentValue + " lastValue: " + lastValue);
}
private void redrawGraph() //resizes graph when zooming
{
checkZoom();
Object[] data = seismograph.theData.toArray();
clearGraph();
step = offset;
int y2, y1 = 0;
int zoomSize = (int)((width - offset) / zoom);
int tempCount = 0;
graphGraphics.beginDraw();
graphGraphics.strokeWeight(2); // line thickness
graphGraphics.stroke(242,100,66);
graphGraphics.smooth();
while(tempCount < data.length)
{
try
{
y2 = (int)data[tempCount];
step = step + zoom;
if(step > offset && y1 > 0 && step < graphSizeX+offset){
graphGraphics.line(step-zoom, y1, step, y2);
}
y1 = y2;
tempCount++;
lastY2 = y2;
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
graphGraphics.endDraw();
image(graphGraphics, 0, 0);
restartDraw = true;
}
Any help and criticisms are welcome. Thank you for your valuable time.
I'm not sure if that approach is the best. You can try something as simple as this:
// Learning Processing
// Daniel Shiffman
// http://www.learningprocessing.com
// Example: a graph of random numbers
float[] vals;
void setup() {
size(400,200);
smooth();
// An array of random values
vals = new float[width];
for (int i = 0; i < vals.length; i++) {
vals[i] = random(height);
}
}
void draw() {
background(255);
// Draw lines connecting all points
for (int i = 0; i < vals.length-1; i++) {
stroke(0);
strokeWeight(2);
line(i,vals[i],i+1,vals[i+1]);
}
// Slide everything down in the array
for (int i = 0; i < vals.length-1; i++) {
vals[i] = vals[i+1];
}
// Add a new random value
vals[vals.length-1] = random(height);//use seismograph.getCurrentValue(); here instead
}
You can easily do the same using a PGraphics buffer as your code suggests:
// Learning Processing
// Daniel Shiffman
// http://www.learningprocessing.com
// Example: a graph of random numbers
float[] vals;
PGraphics graph;
void setup() {
size(400,200);
graph = createGraphics(width,height);
// An array of random values
vals = new float[width];
for (int i = 0; i < vals.length; i++) {
vals[i] = random(height);
}
}
void draw() {
graph.beginDraw();
graph.background(255);
// Draw lines connecting all points
for (int i = 0; i < vals.length-1; i++) {
graph.stroke(0);
graph.strokeWeight(2);
graph.line(i,vals[i],i+1,vals[i+1]);
}
graph.endDraw();
image(graph,0,0);
// Slide everything down in the array
for (int i = 0; i < vals.length-1; i++) {
vals[i] = vals[i+1];
}
// Add a new random value
vals[vals.length-1] = random(height);//use seismograph.getCurrentValue(); here instead
}
The main idea is to cycle the newest data in an array and simply draw the values from this shifting array. As long as you clear the previous frame (background()) the graph should look ok.

How do I initiate particles to grow from anywhere on stage upon mouseClick?

I want to be able to create new particles from wherever I click on stage. I'm just stuck on adding the mouse portion and I've tried to add/pass parameters and I always get errors while I try setting the parameters. Any suggestions?
This is my current code:
float parSpeed = 1; //speed of particles
int nParticles = 1000; //# of particles
Particle[] particles;
void setup() {
size(700,700); //size of image (8.5 x 11 # 300px) is 3300,2550)
frameRate(60); //framerate of stage
background(0); //color of background
particles = new Particle[nParticles];
//start particle array
for(int i=0; i<nParticles; i++) {
particles[i] = new Particle();
}
}
void draw() {
fill(0,0,0,5); //5 is Alpha
rect(0,0,width,height); //color of rectangle on top?
translate(width/2, height/2); //starting point of particles
//start particle array
for(int i=0; i<nParticles; i++) {
particles[i].update();
particles[i].show();
}
}
//Particle Class
class Particle {
PVector pos; //position
float angle; //angle
float dRange; //diameter range
float dAngle; //beginning angle?
color c; //color
Particle() {
pos = new PVector(0,0);//new position for the particles.
angle = 1; //controls randomization of direction in position when multiplied
dRange = 0.01; // how big of a circle shold the particles rotate on
dAngle = 0.15; // -- maximum angle when starting
c = color(0,0,random(100, 255)); //set color to random blue
}
void update() {
float cor = .25*dRange*atan(angle)/PI;
float randNum = (random(2)-1)*dRange-cor; //Random number from (-dRange, dRange)
dAngle+=randNum; //We don't change the angle directly
//but its differential - source of the smoothness!
angle+=dAngle; //new angle is angle+dAngle -- change angle each frame
pos.x+=parSpeed*cos(angle);//random direction for X axis multiplied by speed
pos.y+=parSpeed*sin(angle);//rabdin durectuib for y axis multiplied by speed
}
void show() {
fill(c); //fill in the random color
noStroke(); //no stroke
ellipse(pos.x,pos.y,10,10); //make the shape
smooth(); //smooth out the animation
}
}
void keyPressed() {
print("pressed " + int(key) + " " + keyCode);
if (key == 's' || key == 'S'){
saveFrame("image-##.png");
}
}
void mouseReleased() {
print("mouse has been clicked!");
}
Overwrite the mouseReleased() method:
In there you'll need to:
capture the position of the mouse
create the new particle
update the position of the newly created particle.
add it to the array (the particle system)
This may look simple but you'll have to keep in mind an array cannot change sizes. I would advise that you create a ParticleSystem class that takes care of adding and removing particles from the system.
Edit: You might want to consider using an ArrayList instead of an Array of Particles. Have a look at this
In pseudo code this would look like this:
void mouseReleased() {
int particleX = mouseX;
int particleY = mouseY;
Particle P = new Particle();
P.setPos ( new PVector ( particleX, particleY ) ); // this needs to be implemented
ParticleSystem.add ( P ); // this needs to be implemented
}
I hope this will be a good start.
AH

Categories

Resources