Java Click on a object and output a message - java

Im currently making a game in my spare time to improve my java but im having trouble with one of the things i want to do. Ive made the game so i can put a item into a certain position. In this example its a tower in a certain location. When this tower is placed in this location and i click on the tower i want it to output a message. However ive tried many ways to do this and i havent been able to find a solution. The code i have for this is:
public static void click(int X, int Y){
System.out.println("X. " + X + " Y. " + Y);
if(Screen.room.block[X][Y].airID == Value.tower){
System.out.println("Tower clicked");
}
}
When the tower is placed in a location the code i use for this is:
if(holdsItem){
for(int y=0; y<Screen.room.block.length; y++){
for(int x=0; x<Screen.room.block[0].length; x++){
if(Screen.room.block[y][x].contains(Screen.mse)){
if(Screen.room.block[y][x].groundID != Value.ground && Screen.room.block[y][x].airID == Value.tower){
Screen.room.block[y][x].airID = heldID;
}
}
}
}
}
When i put down a tower by:
System.out.println(Screen.room.block[y][x]);
i get
Block[x=243,y=260,width=52,height=52]
This works fine and the tower is placed. I then wanted to use the location of what the tower is placed and then if that location is pressed the message would print in the console. However this doesnt happen. Can anyone help me fix this problem.
I use a mouse listener which is:
public void mouseClicked(MouseEvent e) {
e.getX();
e.getY();
Block.click(e.getX(), e.getY());
}
When i click on a location i get:
System.out.println("X. " + X + " Y. " + Y);
X. 257 Y. 298
if this helps.

Right now you are using pixels to get the location of your object, so you need to check more than the exact "origin" pixel for each block.
public static void click(int X, int Y){
System.out.println("X. " + X + " Y. " + Y);
//Look for every block in the matrix
for ( int i = 0; i<Screen.room.block.length; i++ ) {
for ( int j = 0; j<Screen.room.block[0].length; j++ ) {
if(Screen.room.block[i][j].airID == Value.tower){
//Check if we hit within the block's bounds
if ( X >= i && X <= i+blockWidth &&
Y >= j && Y <= j+blockHeight )
System.out.println("Tower clicked");
return;
}
}
}
}
A common practice is to store your objects in some kind of list or uni-dimensional array, so that you can avoid the
for ( int i = 0; i<Screen.room.block.length; i++ ) {
for ( int j = 0; j<Screen.room.block[0].length; j++ ) {
and just do
for ( int i = 0; i<Screen.room.blocks.length; i++ ) {
to check for every block and to avoid having such a big matrix when you must check every block anyway.
Another approach: you could give each block a place in a checkers-like matrix and then transform the mouse clicked event coordinates from pixels to "block" coordinates:
public void mouseClicked(MouseEvent e) {
int x = e.getX() / widthOfABlockInPixels;
int y = e.getY() / heightOfABlockInPixels;
Block.click(x, y);
}
Say your objects are 100x100 pixels, then this would give you the right block coordinates for
(160, 150) => (1, 1)
(60, 50) => (0, 0)
and so on.

This might sound a little over-simplified, but, then again, I'm just spit-balling here. Have you thought about implementing the message into a JOptionPane.showMessageDialog? Not sure if that would be what you're looking for.

Related

How to change RGB colour depending on mouse position in Processing3?

I am writing a little program in Processing3 that enables me to change the background to a specific colour RGB code stored in arrays. Each vale for R, G and B is stored in a separate array.
Changing the mouse horizontal position changes the colour of the background.
However this solutions code is quite repetitive, and there is a lot of if/else statements. I want to use a for() loop to simplify the code and make it less repetitive. However, i am struggling to include the mouse position variable in the for() loop. Is there to simplify this code using a for() loop and somehow map the mouse position to access array items? This is the code I have right now:
int[] r = {255,249,240,233,227};
int[] g = {115,138,157,173,187};
int[] b = {0,18,63,94,120};
void setup() {
size(500, 500);
}
void draw() {
int x = mouseX;
if(x >= 0 && x <=100) {
background(r[0], g[0], b[0]);
}
else if (x >= 101 && x <= 200){
background(r[1], g[1], b[1]);
}
else if (x >= 201 && x <= 300){
background(r[2], g[2], b[2]);
}
else if (x >= 301 && x <= 400){
background(r[3], g[3], b[3]);
}
else {
background(r[4], g[4], b[4]);
}
}
I wish to simplify the code to something more like this:
int[] r = {255,249,240,233,227};
int[] g = {115,138,157,173,187};
int[] b = {0,18,63,94,120};
void setup() {
size(500, 500);
}
void draw() {
for(int i=0; i<r.length; i++) {
background(r[i],g[i],b[i]);
}
}
However, I don't know how to change this code in a way, that the background colour would change depending on mouse horizontal position, as it is shown in the first example.
Thank you for your reply and help!
If your steps between your different values are 100, then you can just divide the input X value by 100. Integer division will take care of the rest.
The if statement is just to make sure it stays within the bounds of your array.
int mouseX = ...;
int i = mouseX / 100;
if(i < r.length && i < g.length && i < b.length)
{
background(r[i], g[i], b[i]);
}

Making false sudoku coordinate red

Yoo, hope this isn't too specific.
I'm making a sudoku and I got method that takes care of all the false x and y-coordinates for every wrong (to make them go red); which I layer in a string. If I find an incorrect number I layer the coordinates as: x,y for every wrong and then add more like: x,y,x,y,x,y ...
SudokuResultCount is my other class where I keep the coordinates, and FalseCoordinates is the string where I keep them. So when I press "Correct my sudoku"-button this method goes.
This is made in this method:
public static void totalfalsecoordinates(int array[][], int array2[][]){
SudokuResultCount.setFalseCoordinates("");
for(int x=0; x < 9; x++)
{
for(int y=0; y < 9; y++){
try{
if(array2[x][y] != array[x][y]&& array2[x][y] != 0)
{
SudokuResultCount.setFalseCoordinates(x + y + "");
}
}
catch(Exception e){
}
}
}
}
I run this method later on in this method:
try{
int falseCoordinatesLength = SudokuResultCount.getFalseCoordinates().length();
if(falseCoordinatesLength > 0)
{
SudokuMetoder.totalfalsecoordinates(KeepingUpWithTheSudokus.getSolution(), KeepingUpWithTheSudokus.getStartingvalues());
int targetStringchar = 0;
int targetStringchar1= 1;
int numbersOfLoops = SudokuResultCount.getFalseCoordinates().length();
int realnumbersOfLoops = numbersOfLoops/2;
for(int number = 0; number < realnumbersOfLoops; targetStringchar = targetStringchar + 2, targetStringchar1 = targetStringchar1 + 2, number++){
char a_char = SudokuResultCount.getFalseCoordinates().charAt(targetStringchar);
char b_char = SudokuResultCount.getFalseCoordinates().charAt(targetStringchar1);
int x = Character.getNumericValue(a_char);
int y = Character.getNumericValue(b_char);
System.out.println(y);
// int x = (int)a_char;
// int y = (int)b_char;
textFields[x][y].setStyle("-fx-border-color: red ; -fx-border-width: 2px ;");
}
}
}
catch(Exception e3){
String str = "2" + "2" + "";
char b_char = str.charAt(0);
int x = Character.getNumericValue(b_char);
System.out.println(x);
textFields[2][3].setStyle("-fx-border-color: red ; -fx-border-width: 2px ;");
textFields[2][3].setStyle("-fx-background-color: transparent, #909090, transparent, red;");
}
If the number of the string length > 0 then search through. And since I take two numbers from the String at one time, I take the length of the String and divide it by two.
Then I make them into characters so I can decide which one to take.
If I go through the coordinates: 0,1
Any wrongs? Ok then make array[0][1] shine red - otherwise move on.
Then it moves 0,1 2,3 4,5 ...
Ask for removal if too specific!
thanks
Won't most likely help anyone, but I found the answer. It messed up where I added x + y + "" into the String in which i layered the coordinates. I had to do: "" + x + "" + y + ""

ArrayList throwing error: "Concurrent Modification Exception" from code in different class

I am aware that this is a frequently asked question, but I am stuck on how to solve it with my code.
I have a button on my GUI that allows me to add extra "turtles" to the graphics window, this adds a turtle to an arraylist which is showing flocking behaviour, from a gameloop structure. How can i make it so i can add as many turtles as i wish without this error being shown?
The game loop is as follows:
private void gameLoop()
{
while(true) //The order in which the turtles move, and when which algorithm is executed
{
for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
{
(turtles.get(i)).unDrawTurtle();
(turtles.get(i)).update(1000);
hello.setText("X: " + (turtles.get(i)).getPositionX() + " Y: " + (turtles.get(i)).getPositionY());
}
for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
{
(turtles.get(i)).cohesian(turtles); //MAKE BOIDS ATTRACT
}
for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
{
(turtles.get(i)).drawTurtle();
}
for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
{
(turtles.get(i)).wrapPosition((turtles.get(i)).getPositionX(), (turtles.get(i)).getPositionY());
}
//Here we are making sure the turtles are on the screen
Utils.pause(deltaTime/2);
}
Here is the code for the button adding turtles to the ArrayList:
addTurtleButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
turtles.add(new RandomTurtleB(canvas, 400, 300, currentSpeed, 0));
}
} );
removeTurtleButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
turtles.remove(turtles.size() - 1);
canvas.removeMostRecentLine();
canvas.removeMostRecentLine();
canvas.removeMostRecentLine();
canvas.removeMostRecentLine();
}
} );
And in a different class is the cohesion method which is adding turtles/changing the contents of the ArrayList:
public void cohesian(ArrayList<DynamicTurtle> turtles)
{
double flockingDistanceLimit = 50;
double numberOfFlockers = 0;
double combinedX = 0;
double combinedY = 0;
double averageCombinedX;
double averageCombinedY;
//ouble moveToFlock;
//double turnToFlock;
double distanceToPotentialFlock;
for (DynamicTurtle t : turtles) //SCAN FOR ALL TURTLES
{
if(this.getPositionX() != t.getPositionX() && this.getPositionY() != t.getPositionY()) //MAKE SURE TURTLE ISNT SCANNING ITS SELF
{
distanceToPotentialFlock = Math.sqrt(Math.pow((this.getPositionX()-t.getPositionX()),2 ) + Math.pow((this.getPositionY()-this.getPositionY()),2)); //FIND DISTANCE TO TURTLE
System.out.println("distanceToPotentialFlock: " + distanceToPotentialFlock); //PRINT TO SCREEN HOW FAR AWAY THE TURTLE IS
if(distanceToPotentialFlock < flockingDistanceLimit) //MAKE SURE THE FOUND TURTLE IS WITHIN RANGE
{
combinedX = combinedX + t.getPositionX(); //FIND SUMMATION OF X POSITIONS
combinedY = combinedY + t.getPositionY(); //FIND SUMMATION OF Y POSITIONS
numberOfFlockers++; //AS A FLOCKER HAS BEEN FOUND INCREMENT THE NUMBER OF FLOCKERS
System.out.println("distanceToPotentialFlock: " + distanceToPotentialFlock);
System.out.println("numberOfFlockers: " + numberOfFlockers);
if(numberOfFlockers > 0)
{
averageCombinedX = (combinedX / numberOfFlockers); //FIND AVERAGE X POSITION
averageCombinedY = (combinedY / numberOfFlockers); //FIND AVERAGE Y POSITION
System.out.println("XFLOCK: " + averageCombinedX + "YFLOCK: " + averageCombinedY);
double angleRad = Math.atan2(averageCombinedY, averageCombinedX);
double angleDeg = Math.toDegrees(angleRad);
// place in 0,360 range
if(angleDeg < 0)
{
angleDeg = 360 - (-angleDeg);
}
this.turn(angleDeg);
this.move(10);
}
}
}
}
I would greatly appreciate any assisance in helping me solving this problem. Regards, James.
You get a concurrent modification exception since you are adding or removing to the main turtles list each time a button is pressed. You should take some time to read Event Dispatch Threads in Java.
Basically, you are actually dealing with a multi-threading application since the click event of the button happens to execute on a different thread and would be modifying a shared variable - the turtles list which currently is not a thread-safe data structure.
Refer the SO query for some context. So one solution here would be to use a thread-safe data structure like CopyOnWriteArrayList.
Would this be slow? My guess would be no - since in your application a lot of time is spent in iterating over the turtles list compared to adding or removing them. This SO query gives a good description of the performance for CopyOnWriteArrayList
Hope this gives you a head start to solve your problem.

java: tetris random block generated upon row clear

I'm trying to make the game Tetris in java.
I've gotten it to the point where:
a new block is generated when it hits the floor or its y+1 is not null (meaning there's another block under it)
public void collisionCheck(int x, int y) {
if (activetile.getY() == this.height-2 || getTileAt(x, y+1) != null) {
activetile = new Tile(this, 0, 0);
}
}
A row clears when the bottom row is full of non-null values, or the Tetris pieces (for y = 4 (the floor), loop through x till x = 4 and check if all non-null)
public void checkBottomFull(int x, int y) {
while (getTileAt(x,y) != null) {
say("(" + x + ", " + y +")");
if (x == 3) {
say("row is full");
//replace full row with tiles from above
for (int i = 0; i < 4; i++) {
for (int j = 5; j > 0; j--) {
grid[j][i] = getTileAt(i,j-1);
grid[j-1][i] = null;
}
}
break;
}
x++;
}
}
Right now, I'm using keys to move the block:
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_DOWN) {
activetile.setLocation(activetile.getX(), activetile.getY()+1);
System.out.println("coordinates: " + activetile.getX() + ", " + activetile.getY());
collisionCheck(activetile.getX(),activetile.getY());
checkBottomFull(0,4);
repaint();
}
}
There's two issues I'm having:
1) In the picture you'll notice I've dropped the block all the way to the floor... and the row cleared. After it's cleared, it will generate a block to the top left (x=0, y=1) which I have no control over.
2) On the floor there seems to be a red line... which I'm assuming is a row of blocks hidden by the JFrame... I'm not sure why that's there.
FYI: If you're wondering why grid[j][i] has the rows and columns flipped (aka, why it's not grid[i][j]) is because I instantiated it as grid = new Tile[height][width];
Any thoughts?
Thanks!
It is hard to say what is wrong without actually debugging your app.
But maybe try this one:
public void checkBottomFull(int x, int y) {
while (getTileAt(x,y) != null) {
say("(" + x + ", " + y +")");
if (x == 3) {
say("row is full");
//replace full row with tiles from above
for (int i = 0; i < 4; i++) {
for (int j = 4; j >= 0; j--) {
grid[j][i] = getTileAt(i,j-1);
grid[j-1][i] = null;
}
}
break;
}
x++;
}
}
You have 5 rows (indexed from 0 to 4) and 4 columns (indexed from 0 to 3).
What values of height and width do you pass to:
grid = new Tile[height][width];
Because from what I see you should do something like that:
grid = new Tile[5][4];
Bah,
Turns out in the key event, I needed to check if the bottom was full before checking if there is a collision.
I guess what was happening is, when I was checking collisionCheck(activetile.getX(),activetile.getY()); before checkBottomFull(0,4);, when the bottom was full, it would clear the row and set the current row equal to the row above it: grid[j][i] = getTileAt(i,j-1);, the problem was that collisionCheck was generating a new piece and the that newly generated piece was getting cleared and replaced by checkBottomFull.
Putting the collision check after the checkBottomFull ensures that the newly generated piece won't be replaced if bottom is full.

Why is this flood-fill algorithm not working?

For this question: Is there a proper algorithm for detecting the background color of a figure?, I will need to create a flood-fill algorithm to be able to separate all my pixels in groups of the same color.
I did this recursively, but it gives me a stack-overflow error. So I had to choose the iterative, queue based algorithm found here: http://en.wikipedia.org/wiki/Flood_fill#Alternative_implementations
First of all, I begin a search over all the matrix elements (elements being instances of the Pixel class).
private PixelGroup[] generatePixelGroupsFromMatrix(Pixel[][] matrix) {
PixelGroup[] tempGroups = new PixelGroups[9999999]; // Nevermind the 9999999....
int groupsFound = 0;
Pixel pixel;
for (int y = 0; y < matrix.length; ++y) {
for (int x = 0; x < matrix[0].length; ++x) {
pixel = matrix[y][x];
if (!pixel.evaluated) {
// This pixel has never been evaluated
// Therefore, it belongs to a new group
// First, we make a new group
PixelGroup newGroup = new PixelGroup();
// Begin search for connected pixels with the same color. All pixels found will belong to this new group.
findPixelsConnectedWith(pixel,newGroup);
tempGroups[groupsFound] = newGroup;
++groupsFound;
}
}
}
PixelGroup[] result = new PixelGroup[groupsFound];
for (int i = 0; i < groupsFound; ++i) {
result[i] = tempGroups[i];
}
return result;
}
So, Pixel has the following values: x, y, evaluated (boolean) and color (integer).
Then, PixelGroup is simply a class capable of holding pixels (it works).
And this is the method that is giving me trouble:
private void findPixelsConnectedWith(Pixel pixel, GroupOfPixels group) {
QueueOfPixels queue = new QueueOfPixels();
queue.add(pixel);
Pixel currentPixel;
int x,y;
Pixel neighbor;
while((currentPixel = queue.nextPixel()) != null) {
if (currentPixel.color == pixel.color && !currentPixel.evaluated) {
// This pixel has the required color, and has not been evaluated. It meets our needs.
// Add to group.
group.addPixel(currentPixel);
// Flag it as evaluated. So in the future, it will be ignored.
currentPixel.evaluated = true;
// Evaluate all 8 possible directions to find neighbor pixels
int[] xDirections = {0,1,1,1,0,-1,-1,-1};
int[] yDirections = {-1,-1,0,1,1,1,0,-1};
for (int i = 0; i < 8; ++i) {
x = xDirections[i];
y = yDirections[i];
if (pixelExists(currentPixel.y + y,currentPixel.x + x)) {
// There exists a pixel in this direction!
neighbor = getPixel(currentPixel.y + y,currentPixel.x + x);
queue.add(neighbor);
}
}
}
}
}
If you're curious, here is my QueueOfPixels class. I had to make my own with only vectors (school assignment requirement): https://codereview.stackexchange.com/questions/17823/vector-based-flood-fill-algorithm-queue-class (as far as I can tell, it simply works).
WHAT IS THE PROBLEM?
Alright, I have tested this with this image, which is 5x2 pixels (you'll need to zoom in a lot to see it): http://i.stack.imgur.com/xV0Lf.gif - the first row only has black pixels, and the second they're white. The program tells me it has found 6 pixel groups (when it should have been only 2!)
WHAT HAVE I TRIED TO DEBUG THE PROBLEM?
Well, first, before calling findPixelsConnectedWith, I placed this line:
System.out.println("The pixel (" + x + "," + y + ") has not been evaluated. Evaluating now.");
And this was the result:
The pixel (0,0) has not been evaluated. Evaluating now.
The pixel (1,0) has not been evaluated. Evaluating now.
The pixel (2,0) has not been evaluated. Evaluating now.
The pixel (3,0) has not been evaluated. Evaluating now.
The pixel (4,0) has not been evaluated. Evaluating now.
The pixel (0,1) has not been evaluated. Evaluating now.
So, as you can see, it seems like the code is unable to work with the first row (black pixels) since it thinks that every pixel in that row has not been evaluated (I expected it to say that (0,0) was not evaluated and done). But when it starts working with the second row, it does seem to work as expected (find (0,1) and then it is over).
But I still am unable to find out what is going on. Any ideas?
Edit:
My getPixel and pixelExists functions:
private boolean pixelExists(int y, int x) {
return (y > 0 && y < pixelMatrix.length) && (x > 0 && x < pixelMatrix[0].length);
}
private Pixel getPixel(int y, int x) {
return pixelMatrix[y][x];
}
Your pixelExists method should use y >= 0 and x >= 0 instead of y > 0 and x > 0.
private boolean pixelExists(int y, int x) {
return (y >= 0 && y < pixelMatrix.length) && (x >= 0 && x < pixelMatrix[0].length);
}
This may not be the only problem, but it will certainly prevent you from getting the correct answers.
Maybe pixelExists method has "y > 0" part while it should has "y>=0"?

Categories

Resources