Java MouseAdapter - java

So I have my custom mouse adapter. I want to call a method if:
The x and y coordinates are in a Rectangle with for example the coordinates x = 40 y = 40 and the width = 10 length = 10. How can I check if the x and y coordinates (of the mouse) are in the rectangle?
I tried this:
#Override
public void mouseClicked(MouseEvent e) {
if(isXinBounds(e.getX()) || isYinBounds(e.getY())) {
//This happens if the mouse click is in the rectangle
}
}
//Check if the x coordinate of the mouse click is in the rectangle
private boolean isXinBounds(int x) {
if(x <= ob.getBounds().getX() + ob.getBounds().getWidth() / 2 && x >= ob.getBounds().getX() - ob.getBounds().getWidth() / 2) return true;
return false;
}
//Check if the y coordinate of the mouse click is in the rectangle
private boolean isYinBounds(int y) {
if(y <= ob.getBounds().getY() + ob.getBounds().getHeight() / 2 && y >= ob.getBounds().getY() - ob.getBounds().getHeight() / 2) return true;
return false;
}
But that didn't work

The x and y coordinates are in a Rectangle
The Rectangle class already supports a contains(…) method.
You can just use:
if (yourRectangle.contains(e.getPoint())
// do something

You're making a really weird formula to check if your click is in bounds of your rectangle.
If we set the rectangle coords:
x = 10
y = 10
width = 50
height = 50
And create a new Rectangle with those values:
Rectangle rect = new Rectangle(x, y, widht, height)
We can then do this for both X & Y
private boolean xIsInBounds(int x) {
if (x >= rect.x && x <= rect.width + x) {
return true;
}
return false;
}
Because we check for the X & Y values as they are going to be always the same, but we have to add the X & Y values to the width and height respectively due to it being moved due to the X & Y values not being on 0,0.
The other issue in your code is that you're asking:
if (xIsInBounds(...) || yIsInBounds(...)) { ... }
When it should be an && instead of ||.
Here's the code that produces the following output in the form of a Minimal Reproducible Example
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ClickOnBounds extends MouseAdapter {
private JFrame frame;
private JPanel pane;
private static final int X_COORD = 10;
private static final int Y_COORD = 10;
private static final int RECT_WIDTH = 50;
private static final int RECT_HEIGHT = 50;
private Rectangle rect = new Rectangle(X_COORD, Y_COORD, RECT_WIDTH, RECT_HEIGHT);
#SuppressWarnings("serial")
private void createAndShowGUI() {
frame = new JFrame(this.getClass().getSimpleName());
pane = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.draw(rect);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(70, 70);
}
};
pane.addMouseListener(this);
frame.add(pane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
if (xIsInBound(e.getX()) && yIsInBound(e.getY())) {
System.out.println("Yes! " + e.getX() + " " + e.getY());
} else {
System.out.println("No! " + e.getX() + " " + e.getY());
}
}
private boolean xIsInBound(int x) {
if (x >= rect.x && x <= rect.width + X_COORD) {
return true;
}
return false;
}
private boolean yIsInBound(int y) {
if (y >= rect.y && y <= rect.height + Y_COORD) {
return true;
}
return false;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new ClickOnBounds()::createAndShowGUI);
}
}
And, as you can see in the image above, it works perfectly.

Related

Player and Blocks collision (Terraria) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I am creating a game like Terraria. I already have a player and I can place blocks and delete them by clicking on an existing block. But I can´t figure out how to make player and block collision. I want to create physics like in terraria. Can you help me somehow?
Here are my 3 classes (I have 4 but the 4. class is only JFrame class):
Here is my Main Class (gameloop):
package Package;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Game extends JPanel implements ActionListener, MouseListener, KeyListener {
Timer gameLoop = new Timer(5, this);
private static final long serialVersionUID = 1L;
public static final int WIDTH = 1500;
public static final int HEIGHT = 900;
public static final Dimension windowSize = new Dimension(WIDTH, HEIGHT);
Player player = new Player();
public static ArrayList<Block> blocks = new ArrayList<Block>();
private int xDistance;
private int yDistance;
public Game() {
setPreferredSize(windowSize);
setFocusable(true);
addMouseListener(this);
addKeyListener(this);
setBackground(Color.WHITE);
for (int i = 0; i < Game.WIDTH; i += 50) {
for (int j = Game.HEIGHT - 150; j < Game.HEIGHT; j += 50) {
blocks.add(new Block(i, j));
}
}
start();
}
public void start() {
gameLoop.start();
}
public void stop() {
gameLoop.stop();
}
public void paint(Graphics g) {
for (Block b : blocks) {
b.render(g);
}
player.render(g);
}
public void actionPerformed(ActionEvent e) {
player.move();
player.offScreen();
repaint();
}
public void mouseClicked(MouseEvent e) {}
public void mousePressed(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
boolean foundBlock = false;
xDistance = mouseX % 50;
yDistance = mouseY % 50;
for (Block b : blocks) {
if (b.x == mouseX - xDistance && b.y == mouseY - yDistance) {
if (mouseX >= player.x - 150 && mouseX <= player.x + 200 && mouseY >= player.y - 150 && mouseY <= player.y + 250) {
blocks.remove(b);
foundBlock = true;
break;
}
}
}
if (foundBlock == false) {
if (mouseX >= player.x - 150 && mouseX <= player.x + 200 && mouseY >= player.y - 150 && mouseY <= player.y + 250) {
blocks.add(new Block(mouseX - xDistance, mouseY - yDistance));
}
}
}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
int arrows = e.getKeyCode();
if (arrows == KeyEvent.VK_D) {
player.xSpeed = 2;
}
if (arrows == KeyEvent.VK_A) {
player.xSpeed = -2;
}
}
public void keyReleased(KeyEvent e) {
int arrows = e.getKeyCode();
if (arrows == KeyEvent.VK_D) {
player.xSpeed = 0;
}
if (arrows == KeyEvent.VK_A) {
player.xSpeed = 0;
}
}
}
Here is my Player class:
package Package;
import java.awt.Color;
import java.awt.Graphics;
public class Player {
public int x = 14 * 50;
public int y = Game.HEIGHT - (5 * 50);
public int xSpeed = 0;
public int ySpeed = 0;
public boolean jump = false;
public int ticks = 6;
public void render(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(x, y, 50, 100);
}
public void move() {
x += xSpeed;
y += ySpeed;
}
public void offScreen() {
if (x <= 0) {
xSpeed = 0;
} else if (x + 50 >= Game.WIDTH) {
xSpeed = 0;
}
}
}
Here is my Block Class:
package Package;
import java.awt.Color;
import java.awt.Graphics;
public class Block {
public int x;
public int y;
public Block(int x, int y) {
this.x = x;
this.y = y;
}
public void render(Graphics g) {
g.setColor(Color.GRAY);
g.fillRect(x, y, 50, 50);
g.setColor(Color.BLACK);
g.drawRect(x, y, 50, 50);
}
}
You don't want to store you blocks this way:
public static ArrayList<Block> blocks = new ArrayList<Block>();
Instead, create a structure that easily allows you to access blocks by their coordinates. Maybe:
public static HashMap<Integer, HashMap<Integer, Block>>()
... where the 1st Integer is the X coordinate and the 2nd is the Y. That way, you can quickly find the blocks that have any chance of colliding with the player, instead of checking every block in the world every iteration.
Also, why is this static? It shouldn't be, I think.
To check for collisions (I assume to prevent players from moving through blocks), just figure out the coordinates of where the player would wind up after the proposed move and see if the players bounding rectangle (the rectangle from the upper left of the player's sprite to the lower right) overlaps the bounding rectangle of any block.
But it's really important: arrange the blocks so you don't have to check them all! Only the blocks in a very narrow coordinate range can possibly be collisions, so make sure you can access blocks by range quickly.

Java Animation, update animation with frequency of 1x, 1y

When my animation is in progress figures get stuck together. I think it's because if Figure get velocity x=5 y=5 i move them and then check if they hit anything and my figure can be already inside 2nd figure.
I want to check if they hit anything more often but im not sure how to put my methods in actionPerformed method.
Velocity of figures is not constant.
Do you have any ideas, examples or suggestions?
public class PaintFigures extends JPanel implements ActionListener {
static List<Figure> figuresList = new ArrayList<Figure>();
Timer t = new Timer(5, this);
public PaintFigures(List<Figure> figuresList) {
PaintFigures.figuresList = figuresList;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
t.start();
for (Figure figure : figuresList) {
figure.drawItself(g2d);
}
}
#Override
public void actionPerformed(ActionEvent e) {
FiguresUpdate.update(figuresList); // Check if they hit anything (other figure or frame)
FiguresUpdate.move(figuresList); // move them
repaint();
}
}
Runnable Example Here
Class main
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test extends JPanel implements ActionListener {
static private List<Square> figuresList = new ArrayList<Square>();
Timer t = new Timer(5, this);
public static void main(String[] args) {
Square s1 = new Square(40);
Square s2 = new Square(60);
Square s3 = new Square(20);
figuresList.add(s1);
figuresList.add(s3);
figuresList.add(s2);
JFrame frame = new JFrame("Figures Animation");
frame.setSize(700, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new Test();
panel.setBackground(Color.GRAY);
frame.getContentPane().add(BorderLayout.CENTER, panel);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
t.start();
for (Square figure : figuresList) {
figure.drawItself(g2d);
}
}
#Override
public void actionPerformed(ActionEvent e) {
Test.update(figuresList); // Check if they bounce
// FiguresUpdate.move(figuresList); // move them
repaint();
}
public static void update(List<Square> list) {
updateFlags(list);
for (int i = 0; i < list.size(); i++) {
list.get(i).setLocationX(
list.get(i).getLocationX() + (list.get(i).getVelocityX()));
list.get(i).setLocationY(
list.get(i).getLocationY() + (list.get(i).getVelocityY()));
if (list.get(i).getLocationX() < 0
|| list.get(i).getLocationX() > 680 - (list.get(i)
.getWidth())) {
WallXBounceDetected(list.get(i));
}
if (list.get(i).getLocationY() < 0
|| list.get(i).getLocationY() > 360 - (list.get(i)
.getHeight())) {
WallYBounceDetected(list.get(i));
}
for (int j = i + 1; j < list.size(); j++) {
if (list.get(i).getBounds().intersects(list.get(j).getBounds())
&& (!list.get(i).getDidHeBounce())
&& (!list.get(j).getDidHeBounce())) {
System.out.println(list.get(i).getClass().getSimpleName());
FigureBounceDetected(list.get(i), list.get(j));
}
}
}
}
public static void updateFlags(List<Square> list) {
for (int i = 0; i < list.size(); i++) {
list.get(i).setDidHeBounce(false);
}
}
public static void WallXBounceDetected(Square f) {
f.setVelocityX(-f.getVelocityX());
}
public static void WallYBounceDetected(Square f) {
f.setVelocityY(-f.getVelocityY());
}
public static void FigureBounceDetected(Square f1, Square f2) {
// Elastic Collision
// Figure 1
double newSpeedF1X = (f1.getVelocityX() * (f1.getMass() - f2.getMass()) + (2 * f2
.getMass() * f2.getVelocityX()))
/ (f1.getMass() + f2.getMass());
double newSpeedF1Y = (f1.getVelocityY() * (f1.getMass() - f2.getMass()) + (2 * f2
.getMass() * f2.getVelocityY()))
/ (f1.getMass() + f2.getMass());
// Figure 2
double newSpeedF2X = (f2.getVelocityX() * (f2.getMass() - f1.getMass()) + (2 * f1
.getMass() * f1.getVelocityX()))
/ (f1.getMass() + f2.getMass());
double newSpeedF2Y = (f2.getVelocityY() * (f2.getMass() - f1.getMass()) + (2 * f1
.getMass() * f1.getVelocityX()))
/ (f1.getMass() + f2.getMass());
f1.setLocationX(f1.getLocationX() + (newSpeedF1X));
f1.setLocationY(f1.getLocationY() + (newSpeedF1Y));
f2.setLocationX(f2.getLocationX() + (newSpeedF2X));
f2.setLocationY(f2.getLocationY() + (newSpeedF2Y));
// new velocity
f1.setVelocityX(newSpeedF1X);
f1.setVelocityY(newSpeedF1Y);
f2.setVelocityX(newSpeedF2X);
f2.setVelocityY(newSpeedF2Y);
// flag true
f1.setDidHeBounce(true);
f2.setDidHeBounce(true);
}
}
Class Square.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.Random;
public class Square {
Rectangle2D.Double square;
private double locationX = 120;
private double locationY = 120;
private double velocityX =1;
private double velocityY =1;
private double width;
private double height = width;
private double mass = width;
private boolean didHeBounce=false;
Color color;
public Square(int width) {
this.width = width;
height = this.width;
mass = height;
Random r = new Random();
if(r.nextInt(2)>0){
velocityX=-1;
} else {
velocityX=1;
}
if(r.nextInt(2)>0){
velocityY=-1;
} else {
velocityY=1;
}
locationX =r.nextInt(540);
locationY= r.nextInt(220);
}
public void drawItself(Graphics g){
Graphics2D g2d = (Graphics2D) g;
square = new Rectangle2D.Double(locationX,locationY,height,width);
g2d.fill(square);
g.setColor(Color.BLUE);
}
public boolean getDidHeBounce() {
return didHeBounce;
}
public void setDidHeBounce(boolean didHeBounce){
this.didHeBounce = didHeBounce;
}
public double getLocationX() {
return locationX;
}
public void setLocationX(double locationX) {
this.locationX = locationX;
}
public double getLocationY() {
return locationY;
}
public void setLocationY(double locationY) {
this.locationY = locationY;
}
public double getVelocityX() {
return velocityX;
}
public void setVelocityX(double velocityX) {
this.velocityX = velocityX;
}
public double getVelocityY() {
return velocityY;
}
public void setVelocityY(double velocityY) {
this.velocityY = velocityY;
}
public double getMass() {
return mass;
}
public double getHeight() {
return height;
}
public double getWidth() {
return width;
}
public Rectangle2D getBounds() {
return square.getBounds2D();
}
}
Hello first of all you moved them here:
f1.setLocationX(f1.getLocationX() + (newSpeedF1X));
f1.setLocationY(f1.getLocationY() + (newSpeedF1Y));
f2.setLocationX(f2.getLocationX() + (newSpeedF2X));
f2.setLocationY(f2.getLocationY() + (newSpeedF2Y));
So it's not frequency problem.
Problem has to be in formula and it is.
You got:
//figure 1
newSpeedF1X = velocityXF1*(MassF1-MassF2)+(2*MassF2*VelocityXF2)/(MassF1+MassF2)
newSpeedF1Y = velocityYF1*(MassF1-MassF2)+(2*MassF2*VelocityXF2)/(MassF1+MassF2)
// Figure 2
newSpeedF2X = velocityXF2*(MassF2-MassF1)+(2*MassF1*VelocityXF1)/(MassF1+MassF2)
newSpeedF2Y = velocityYF2*(MassF2-MassF1)+(2*MassF1*VelocityXF1)/(MassF1+MassF2)
And in newSpeedF2Y should be VelocityYF1 not X
newSpeedF2Y = velocityYF2*(MassF2-MassF1)+(2*MassF1*VelocityYF1)/(MassF1+MassF2)
Additional remarks
Wall bounce detect:
I noticed your figures getting stuck in walls and you change their velocity to -velocity when they are out of bunds so they cant get out.
To avoid figures getting stuck in wall you should do something like this:
public void wallXBounceDetect(Figure f) {
f.setVelocityX(wallBounceDetect(f.getLocationX(), f.getWidth(), canvas.getWidth(), f.getVelocityX()));
}
public void wallYBounceDetect(Figure f) {
f.setVelocityY(wallBounceDetect(f.getLocationY(), f.getHeight(), canvas.getHeight(), f.getVelocityY()));
}
public double wallBounceDetect(double location, double size, double maxValue, double velocity) {
if ((location < 0 && velocity < 0) || (location + size > maxValue && velocity > 0)) {
return -velocity;
}
return velocity;
}
Where canvas is your class with method PaintComponent which extends JPanel.
It has to do with the laws you are applying. If the bouncing is not long enough they will probably stick forever. A simple rule: if the two figures collide and figure 1 is lower than figure 2 (f1.xf2.x) f1 is bounced a bit back otherwise (f1.x>f2.x) it's bounced a bit forward. It seems to work for me right now. You need to check the laws and what values they give (newSpeedF1X etc)
public static void FigureBounceDetected(Square f1, Square f2) {
// Elastic Collision
// Figure 1
double newSpeedF1X = (f1.getVelocityX() * (f1.getMass() - f2.getMass()) + (2 * f2
.getMass() * f2.getVelocityX()))
/ (f1.getMass() + f2.getMass());
double newSpeedF1Y = (f1.getVelocityY() * (f1.getMass() - f2.getMass()) + (2 * f2
.getMass() * f2.getVelocityY()))
/ (f1.getMass() + f2.getMass());
// Figure 2
double newSpeedF2X = (f2.getVelocityX() * (f2.getMass() - f1.getMass()) + (2 * f1
.getMass() * f1.getVelocityX()))
/ (f1.getMass() + f2.getMass());
double newSpeedF2Y = (f2.getVelocityY() * (f2.getMass() - f1.getMass()) + (2 * f1
.getMass() * f1.getVelocityX()))
/ (f1.getMass() + f2.getMass());
System.out.println("prev "+f1.getprevx()+" "+newSpeedF1X+" "+newSpeedF1Y+" "+newSpeedF2X+" "+newSpeedF2Y);
// f1.setLocationX(f1.getLocationX() + (newSpeedF1X));
// f1.setLocationY(f1.getLocationY() + (newSpeedF1Y));
// f2.setLocationX(f2.getLocationX() + (newSpeedF2X));
// f2.setLocationY(f2.getLocationY() + (newSpeedF2Y));
if(f1.getLocationX()<f2.getLocationX()) f1.setLocationX(Math.max(0, f1.getLocationX()-f1.getWidth()));
else f1.setLocationX(Math.min(700-f1.getWidth(), f1.getLocationX()+f1.getWidth()));
// new velocity
// f1.setVelocityX(newSpeedF1X);
// f1.setVelocityY(newSpeedF1Y);
// f2.setVelocityX(newSpeedF2X);
// f2.setVelocityY(newSpeedF2Y);
// flag true
f1.setDidHeBounce(true);
f2.setDidHeBounce(true);
}
}
Some other changes are minor
for (int j = i + 1; j < list.size(); j++) {
int ij=j%list.size();
if (list.get(i).getBounds().intersects(list.get(j).getBounds())
&& (!list.get(i).getDidHeBounce())
&& (!list.get(ij).getDidHeBounce())
) {
System.out.println(list.get(i).getClass().getSimpleName());
FigureBounceDetected(list.get(i), list.get(ij));
}
public void drawItself(Graphics2D g){
Color c=g.getColor();
Graphics2D g2d = (Graphics2D) g;
square = new Rectangle2D.Double(locationX,locationY,height,width);
g.setColor(Color.BLUE);
g.fill(square);
g.setColor(c);
}

JPanel creates twice

I am trying to make a GUI for a battleship game. One class is for creating the GUI itself and a second class is on top of it to manage the board in the game. My problem is that the JPanel creates twice once a mouse click happens (the mouse click is supposed to be where one is firing in the game and then marks that as a hit/miss). I'm not sure why it is creating twice. Is it because of the passing of a panel? Code below and a photo of what the code generates.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BattleshipApplet extends JApplet implements MouseListener {
private final JButton playButton = new JButton("Play");
private final JLabel msgBar = new JLabel("Click Play to start game");
private BoardPanel panel;
public BattleshipApplet(){
playButton.addActionListener(this::playButtonClicked);
addMouseListener(this);
}
public void init(){
configureGui();
}
private void configureGui(){
setLayout(new BorderLayout());
JPanel buttons = new JPanel(new FlowLayout(FlowLayout.LEFT));
buttons.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
buttons.add(playButton);
add(buttons, BorderLayout.NORTH);
msgBar.setBorder(BorderFactory.createEmptyBorder(10,10,5,5));
add(createBoardPanel(), BorderLayout.CENTER);
add(msgBar, BorderLayout.SOUTH);
}
private BoardPanel createBoardPanel(){
panel = new BoardPanel();
return panel;
}
private void displayMessage(String msg){
msgBar.setText(msg);
}
private void playButtonClicked(ActionEvent event){
displayMessage("Play button clicked!");
}
public void mouseClicked(MouseEvent e) {
panel.mouseClickedAt(e.getX(), e.getY());
e.consume();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
}
The board class using JPanel
[![import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class BoardPanel extends JPanel {
int mx, my;
boolean rect1Clicked;
//gamePlay a;
public void init(){
rect1Clicked = false;
}
/***Your applet shall show the status of the board before and after
each shot, including the number of shots made and the status of
each place (no shot or hit/miss shot). ***/
public void paint(Graphics g){
boolean miss = false;
for (int i=0; i<11; i++){
g.setColor(Color.blue);
g.drawLine(20,20+i*28, 300, 20+i*28);
}
for (int i=0; i<11; i++)
g.drawLine(20+i*28,20,20+i*28,300);
//if inside board
if(rect1Clicked == true){
g.setColor(Color.green);
//aligns to square to check in computer board for hit/miss
int bx =(my-20)/28;
int by =(mx-20)/28;
//check hit on board
//if shot was a miss
if(miss == true ){
//update to white
g.setColor(Color.white);
}
//if shot was a hit
if(miss == false){
//update to red
g.setColor(Color.red);
}
//compare to line for fill
int fillx = mx/2;
int filly = my/2 ;
if(mx<=47){
fillx = 20;
}
if(mx>47 && mx<=75){
fillx = 48;
}
if(mx>75 && mx<=103){
fillx = 76;
}
if(mx>103 && mx <=131){
fillx = 104;
}
if(mx>131 && mx<=159){
fillx = 132;
}
if(mx>159 && mx<=187){
fillx = 160;
}
if(mx>187 && mx <=215){
fillx = 188;
}
if(mx>215 && mx <=243){
fillx = 216;
}
if(mx>243 && mx <=271){
fillx = 244;
}
if(mx>271 && mx<=299){
fillx = 272;
}
if(mx>299){
fillx = 300;
}
//y comparisons
if(my<=47){
filly = 20;
}
if(my>47 && my<=75){
filly = 48;
}
if(my>75 && my<=103){
filly = 76;
}
if(my>103 && my <=131){
filly = 104;
}
if(my>131 && my<=159){
filly = 132;
}
if(my>159 && my<=187){
filly = 160;
}
if(my>187 && my <=215){
filly = 188;
}
if(my>215 && my <=243){
filly = 216;
}
if(my>243 && my <=271){
filly = 244;
}
if(my>271 && my<=299){
filly = 272;
}
if(my>299){
filly = 300;
}
g.drawString("("+mx+","+my+")",mx,my);
//25 describes size of square
g.fillOval(fillx, filly, 25, 25);
}
}
public void game(BoardPanel p){
//while game plays
}
public void mouseClickedAt(int x, int y){
mx = x;
my = y;
//user clicked inside of board space
if(mx>20 && mx<300 && my>20 && my<300){
//send to board in MainBattleship
rect1Clicked = true;
}
//updates board
repaint();
}
}][1]][1]
I am so lost, thank you for any help!
Suggestions:
Don't override a JPanel's paint method but rather its paintComponent method as this is safer, and later when you want to do animation, will result in smoother animation.
Most important you almost always need to call the super's painting method within your own, else the JPanel will not remove previous image artifacts that need to be cleaned up. So if you continue to override paint (although I recommend against, this) the first line of your override should be super.paint(g);, or if you override paintComponent then the first line should be super.paintComponent(g);, of course assuming that you're methods use a Graphics parameter named g.
Also, add the MouseListener to the JPanel, not to the applet, since it is the mouse click location on the panel that matters to you.
Also, use a grid of components or some math to greatly simplify your code -- that ugly list of if blocks should be replaced by a much simpler for loop, one using basic math.
Consider extracting that logic discussed in the point above out of your painting method and into a model of some kind, perhaps a 2D array of boolean.
You're using a lot of "magic" numbers in your code, numbers that should be changed to a combination of constants and mathematically derived numbers.
Notice what happens if you click on your GUI, and then resize it, or if you minimize and then restore it -- you lose all red circles except for the last one pressed. This is another reason to use a grid of boolean or other model to hold state of the game, and then use this model when drawing your GUI.
On further thinking, you might want a 2D array of an enum or an int array, since the grid cell state will likely be more than 2 values (true or false), but rather will be three values -- untested, hit, and miss, and you'll likely want to fill your oval with red if a hit or white if a miss.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import javax.swing.*;
public class GridExample {
private static void createAndShowGui() {
final GridPanel gridPanel = new GridPanel();
JButton resetBtn = new JButton(new AbstractAction("Reset") {
#Override
public void actionPerformed(ActionEvent e) {
gridPanel.reset();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(resetBtn);
JFrame frame = new JFrame("GridExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gridPanel);
frame.getContentPane().add(btnPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class GridPanel extends JPanel {
private static final int ROWS = 10;
private static final int CELL_WIDTH = 28;
private static final int PAD = 20;
private static final int PREF_W = ROWS * CELL_WIDTH + 2 * PAD;
private static final int PREF_H = PREF_W;
private static final Color GRID_COLOR = Color.blue;
private static final Color CIRCLE_COLOR = Color.red;
private static final int SML_GAP = 2;
private boolean[][] grid = new boolean[ROWS][ROWS];
public GridPanel() {
addMouseListener(new MyMouse());
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void reset() {
grid = new boolean[ROWS][ROWS]; // fills grid with false
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// draw grid:
g2.setColor(GRID_COLOR);
for (int i = 0; i <= ROWS; i++) {
int x1 = PAD + i * CELL_WIDTH;
int y1 = PAD;
int x2 = x1;
int y2 = PAD + CELL_WIDTH * ROWS;
g2.drawLine(x1, y1, x2, y2);
g2.drawLine(y1, x1, y2, x2);
}
// iterate through the grid boolean array
// draw red circles if the grid value is true.
g2.setColor(CIRCLE_COLOR);
int w = CELL_WIDTH - 2 * SML_GAP; // width of the circle to draw
int h = w;
// nested for loop to go through the grid array
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[r].length; c++) {
if (grid[r][c]) {
int x = PAD + c * CELL_WIDTH + SML_GAP;
int y = PAD + r * CELL_WIDTH + SML_GAP;
g2.fillOval(x, y, w, h);
}
}
}
}
private class MyMouse extends MouseAdapter {
public void mousePressed(MouseEvent e) {
int x = e.getPoint().x;
int y = e.getPoint().y;
if (x < PAD || y < PAD) {
// clicked above or to right of grid
return;
}
int r = (y - PAD) / CELL_WIDTH;
int c = (x - PAD) / CELL_WIDTH;
// if clicked to right or below grid.
// the < 0 part is likely unnecessary, but why not be extra safe?
if (r >= ROWS || c >= ROWS || r < 0 || c < 0) {
return;
}
grid[r][c] = true;
repaint();
}
}
}

SnakeGame how to make the tail follow the head?

I am making a snake game, and I am stuck at where making the tails follow the head. And I heard using an add and remove on the head and tails could make that happen, but I have no idea where to start with that.
Here's my code so far:
Screen.java
public class Screen extends JPanel implements ActionListener, KeyListener {
public static final JLabel statusbar = new JLabel("Default");
public static final int WIDTH = 800, HEIGHT = 800;
Timer t = new Timer(100, this);
int x = 400;
int y = 400;
int size = 5; //increase size if eat
private boolean right = false, left = false, up = false, down = false;
int head = 0;
private LinkedList<BodyPart> snake = new LinkedList<BodyPart>();
private BodyPart b;
public Screen(){
initSnake();
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void update(){
}
public void direction(){
if(right) x+=10;
if(left) x-=10;
if(up) y-=10;
if(down) y+=10;
}
public void trackOutBound(){
if(x < 0 || x > 800 || y < 0 || y > 800) {
x = 400;
y = 400;
}
}
public void initSnake(){
if(snake.size() == 0){
b = new BodyPart(x, y);
for(int i = 0; i < size; i++) {
snake.add(b);
}
System.out.println(snake);
}
}
public static void main(String[] args) {
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(new Color(10, 50, 0));
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
for(int i = 0; i < WIDTH / 10; i++) {
g.drawLine(i * 10, 0, i * 10, HEIGHT);
}
for(int i = 0; i < HEIGHT / 10; i++) {
g.drawLine(0, i * 10, WIDTH, i * 10);
}
int tempx = 0, tempy = 0;
int temp = 0;
for(int i = 0; i < size; i++){
if(i == head) {
snake.get(i).x = x;
snake.get(i).y = y;
snake.get(i).draw(g);
g.setColor(Color.blue);
g.fillRect(x, y, 10, 10);
g.setColor(Color.white);
g.drawRect(x, y, 10, 10);
} else if(i > 0 && up) {
snake.get(i).x = x;
snake.get(i).y = y + temp;
snake.get(i).draw(g);
} else if(i > 0 && down) {
snake.get(i).x = x;
snake.get(i).y = y - temp;
snake.get(i).draw(g);
} else if(i > 0 && left) {
snake.get(i).x = x + temp;
snake.get(i).y = y;
snake.get(i).draw(g);
} else if(i > 0 && right) {
snake.get(i).x = x - temp;
snake.get(i).y = y;
snake.get(i).draw(g);
}
temp += 10;
}
/*
if(snake.size() == 5){
snake.add(b);
size += 1;
}
*/
}
#Override
public void actionPerformed(ActionEvent e) {
direction();
trackOutBound();
repaint();
// System.out.println(snake);
statusbar.setText("(" + x + " , " + y + ")");
}
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT && !left) {
up = false;
down = false;
right = true;
}
if(key == KeyEvent.VK_LEFT && !right) {
up = false;
down = false;
left = true;
}
if(key == KeyEvent.VK_UP && !down) {
left = false;
right = false;
up = true;
}
if(key == KeyEvent.VK_DOWN && !up) {
left = false;
right = false;
down = true;
}
}
#Override
public void keyReleased(KeyEvent e) {}
}
BodyPart.java
public class BodyPart {
int x;
int y;
public BodyPart(int x, int y) {
this.x = x;
this.y = y;
}
public void draw(Graphics g) {
this.x = x;
this.y = y;
g.setColor(Color.red);
g.fillRect(x, y, 10, 10);
g.setColor(Color.white);
g.drawRect(x, y, 10, 10);
}
}
Frame.java
public class Frame extends JPanel {
private static JLabel statusbar = new JLabel("Default");
public void statusbar(){
statusbar = Screen.statusbar;
}
public static void main(String[] args) {
JFrame f = new JFrame();
Screen s = new Screen();
f.add(s);
f.add(statusbar, BorderLayout.SOUTH);
f.setSize(800, 800);
f.setVisible(true);
f.setLocationRelativeTo(null);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Now this code would only make the tails flip to the horizontal or vertical, is it possible to make the tails follow the head by using this code? or I need to change my code?
Thank you
The basic idea is, you need some kind of List which contains ALL the points of the snake. Conceptually, the List would contain virtual coordinates, that is 1x1 would represent a coordinate in virtual space, which presented a place on a virtual board (which would have some wide and height).
You could then translate that to the screen, so this would allow each part of the snake to be larger then a single pixel. So, if each part was 5x5 pixels, then 1x1 would actually be 5x5 in the screen.
Each time the snake moves, you add a new value to the head and remove the last value from tail (assuming it's not growing). When you needed to paint the snake, you would simply iterate over the List, painting each point of the snake.
The following is a simple example, which uses a LinkedList, which pushes a new Point onto the List, making a new head, and removing the last element (the tail) on each cycle.
Which basically boils down to...
snakeBody.removeLast();
snakeBody.push(new Point(xPos, yPos));
As a runnable concept
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Snake {
public static void main(String[] args) {
new Snake();
}
public Snake() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
public enum Direction {
UP, DOWN, LEFT, RIGHT
}
private int xPos, yPos;
private Direction direction = Direction.UP;
private LinkedList<Point> snakeBody = new LinkedList<>();
public TestPane() {
xPos = 100;
yPos = 100;
for (int index = 0; index < 50; index++) {
snakeBody.add(new Point(xPos, yPos));
}
bindKeyStrokeTo("up.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), new MoveAction(Direction.UP));
bindKeyStrokeTo("down.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), new MoveAction(Direction.DOWN));
bindKeyStrokeTo("left.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), new MoveAction(Direction.LEFT));
bindKeyStrokeTo("right.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), new MoveAction(Direction.RIGHT));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
switch (direction) {
case UP:
yPos--;
break;
case DOWN:
yPos++;
break;
case LEFT:
xPos--;
break;
case RIGHT:
xPos++;
break;
}
if (yPos < 0) {
yPos--;
} else if (yPos > getHeight() - 1) {
yPos = getHeight() - 1;
}
if (xPos < 0) {
xPos--;
} else if (xPos > getWidth() - 1) {
xPos = getWidth() - 1;
}
snakeBody.removeLast();
snakeBody.push(new Point(xPos, yPos));
repaint();
}
});
timer.start();
}
public void bindKeyStrokeTo(String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
for (Point p : snakeBody) {
g2d.drawLine(p.x, p.y, p.x, p.y);
}
g2d.dispose();
}
public class MoveAction extends AbstractAction {
private Direction moveIn;
public MoveAction(Direction direction) {
this.moveIn = direction;
}
#Override
public void actionPerformed(ActionEvent e) {
direction = this.moveIn;
}
}
}
}
Now, this has no collision detection or other functionality, but you can move the snake around and it will follow itself
For snake style movement, you can, from the tail to the head, move each BodyPart position to the position of the BodyPart ahead of it. For the head there is no part ahead so you have to write decision code whether to simply move the same direction as the part before it or a new direction based on input. Then update the screen.

Move an Oval in java

I made a mini code that draw oval and link each other , now i try to move the oval(Circle) but I have a problem (in coding)
// Panneau.java
public class Panneau extends JPanel {
private int R = 20;
private boolean isDrag = false;
String text = "stack";
int x = 250, y = 200;
int height = 50, width = 50;
Random Rnd = new Random();
int rand=Rnd.nextInt();
int r=Math.abs(rand%250);
int r2=Math.abs(rand%250);
public Panneau() {
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if ((x<=e.getX() && x+R>=e.getX()) && ( y<=e.getY() && y+R>=e.getY())) {
moveVertex(e.getX(),e.getY());
isDrag = true;
}
}
#Override
public void mouseReleased(MouseEvent e) {
isDrag = false;
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (isDrag) moveVertex(e.getX(),e.getY());
}
});
}
private void moveVertex(int x1, int y1) {
if ((x!=x1) || (y!=y1)) {
x=x1-10;
y=y1-10;
repaint();
}
}
#Override
protected void paintComponent(Graphics g){
// declaration
super.paintComponent(g);
g.setColor(Color.black);
g.drawLine(x,y,x+r,y+r2);
g.setColor(Color.yellow);
g.fillOval(x-height/2, y-width/2,width, height);
g.fillOval((x-height/2)+r, (y-width/2)+r2,width, height);
FontMetrics fm = g.getFontMetrics();
double textWidth = fm.getStringBounds(text, g).getWidth();
g.setColor(Color.blue);
g.drawString(text, (int) (x - textWidth/2),(int) (y + fm.getMaxAscent() / 2));
g.drawString(text, (int) (x - textWidth/2)+r,(int) (y + fm.getMaxAscent() / 2)+r2);
}
}
I must move the two circles and the line must not move(Graph node)
please help me and thanks :)
After the update ( thanks to MadProgrammer) now I can move all the figure ( but if I clicked in the red circle only) , I want to move just circles thanks :)
Basically, because instead of using reapint(int, int) you could use repaint()
private void moveVertex(int x1, int y1) {
int OFFSET = 1;
if ((x != x1) || (y != y1)) {
x = x1 - 10;
y = y1 - 10;
repaint();
}
}
This will ensure that the entire component is repainted.
While I wouldn't discount the use of repaint(int, int), because your painting process is relatively simple, it's not going to provide you with a great deal of benefit at this stage
Updated with additional example
IF I understand, you want to be able to move a single node and have the line remain joined.
While it might be possible to implement within the code you have available, a simpler soltution would be to take advantage of the 2D Graphics Shape API, this provides a number of really useful functions, including determining of points fall within a given shape.
It also means you don't need to keep track of a large number of parameters, but instead, get a self contained object that just knows how it should be painted...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestGraphNode {
public static void main(String[] args) {
new TestGraphNode();
}
public TestGraphNode() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Panneau());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Panneau extends JPanel {
private int radius = 50;
private String text = "stack";
private List<Ellipse2D> nodes;
private Ellipse2D dragged;
private Point offset;
public Panneau() {
nodes = new ArrayList<>(25);
nodes.add(new Ellipse2D.Float(50 - (radius / 2), 100 - (radius / 2), radius, radius));
nodes.add(new Ellipse2D.Float(350 - (radius / 2), 100 - (radius / 2), radius, radius));
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
for (Ellipse2D node : nodes) {
if (node.contains(e.getPoint())) {
System.out.println("Clicked...");
dragged = node;
// Adjust for the different between the top/left corner of the
// node and the point it was clicked...
offset = new Point(node.getBounds().x - e.getX(), node.getBounds().y - e.getY());
// Highlight the clicked node
repaint();
break;
}
}
}
#Override
public void mouseReleased(MouseEvent e) {
// Erase the "click" highlight
if (dragged != null) {
repaint();
}
dragged = null;
offset = null;
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (dragged != null && offset != null) {
// Adjust the position of the drag point to allow for the
// click point offset
Point to = e.getPoint();
to.x += offset.x;
to.y += offset.y;
// Modify the position of the node...
Rectangle bounds = dragged.getBounds();
bounds.setLocation(to);
dragged.setFrame(bounds);
// repaint...
repaint();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
// declaration
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Draw the connecting lines first
// This ensures that the lines are under the nodes...
Point p = null;
for (Ellipse2D node : nodes) {
g2d.setColor(Color.BLACK);
Point to = node.getBounds().getLocation();
to.x += radius / 2;
to.y += radius / 2;
if (p != null) {
g2d.draw(new Line2D.Float(p, to));
}
p = to;
}
// Draw the nodes...
for (Ellipse2D node : nodes) {
g2d.setColor(Color.yellow);
g2d.fill(node);
if (node == dragged) {
g2d.setColor(Color.BLUE);
g2d.draw(node);
}
g2d.setColor(Color.BLUE);
FontMetrics fm = g.getFontMetrics();
int textWidth = fm.stringWidth(text);
int x = node.getBounds().x;
int y = node.getBounds().y;
int width = node.getBounds().width;
int height = node.getBounds().height;
g.drawString(text,
x + ((width - textWidth)) / 2,
y + ((height - fm.getHeight()) / 2) + fm.getAscent());
}
g2d.dispose();
}
}
}

Categories

Resources