I am trying to move a circle in a straight line. But my Code is not giving expected results. I m using mouseMotionListener to constantly get the target points and x_pos and y_pos are co-ordinated for my circle. I am using trigonometric function sin cos and atan, to move the object in straight line --its a logic i have seen here from a question posted on stack overflow--
but it is not giving me the expected results, am i doing something wrong plz help:
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import java.awt.*;
import javax.swing.*;
public class Snake extends JPanel {
static Snake snake = new Snake();
static Co_Ordinates co = new Co_Ordinates();
static int x_pos = 10, y_pos = 500;
static int slope;
int delta_x,delta_y;
double direction;
double x_inc,y_inc;
public Snake() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d=(Graphics2D)g;
g2d.setColor(Color.green);
g2d.fillArc(x_pos, y_pos, 20, 20, 0, 360);
try {
Thread.sleep(10);
} catch (Exception e) {
}
/*if(x_pos==co.x_Cur){
if(co.y_Cur>=y_pos)
y_pos++;
else if(co.y_Cur<=y_pos)
y_pos--;
}
else if(y_pos==co.y_Cur){
if(co.x_Cur>=x_pos)
x_pos++;
else if(co.x_Cur<=x_pos)
x_pos--;
}
*/
//slope=((co.y_Cur - y_pos) / (co.x_Cur - x_pos));
//y_pos = slope*x_pos+y_pos;
//x_pos++;
//System.out.println("...");
if(x_pos!=co.x_Cur&&y_pos!=co.y_Cur){
int delta_x = co.x_Cur - x_pos;
int delta_y = co.y_Cur - y_pos;
direction = Math.atan(delta_y / delta_x); // Math.atan2(deltaY, deltaX) does the same thing but checks for deltaX being zero to prevent divide-by-zero exceptions
double speed = 5.0;
x_inc = (speed * Math.cos(direction));
y_inc = (speed * Math.sin(direction));
x_pos+=x_inc;
y_pos+=y_inc;
}
//x_pos = co.x_Cur;
repaint(10);// parameters
}
public void move() {
}
public static void main(String args[]) {
JFrame jf = new JFrame();
jf.add(co);
jf.addMouseMotionListener(co);
jf.addMouseListener(co);
jf.add(snake);
jf.setSize(600, 600);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
}
}
class Co_Ordinates extends JPanel implements MouseMotionListener, MouseListener {
static int slope;
static Snake sn = new Snake();
static int x_Cur=sn.x_pos-20;
static int y_Cur=sn.y_pos-40;
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
x_Cur = e.getX() - 20;
y_Cur = e.getY() - 40;
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}// Class Listener ends here
In the code where you used Math.atan should be changed to Math.atan2.
atan only gives angle values between -90deg and 90deg.
atan2 gives angle values between -180deg and 180deg.
I have modified that part of the code as below.
First, change atan to atan2
Second, make the speed become zero if the circle meets the mouse pointer (the target?)
Third is a minor one but, you don't need the if-condition unless performance is critical.
Please try with this one.
// if(x_pos!=co.x_Cur&&y_pos!=co.y_Cur){
delta_x = co.x_Cur - x_pos;
delta_y = co.y_Cur - y_pos;
direction = Math.atan2(delta_y, delta_x);
double speed = Math.sqrt(delta_x*delta_x + delta_y*delta_y);
speed = Math.min(speed, 5.0);
x_inc = (speed * Math.cos(direction));
y_inc = (speed * Math.sin(direction));
x_pos+=x_inc;
y_pos+=y_inc;
//}
Related
I am not very good with using multiple classes in java, as I've always found it easier to do all of my code in 1 class. Recently I've found the need to use a second class for a game I'm making and I'm running into an error.
Right now I'm just trying to spawn the enemy where and when the user clicks.
Main Class -
package joey.rts;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class RTSMain extends JFrame implements MouseListener{
/**
*
*/
private static final long serialVersionUID = -7122370886923000314L;
public static BufferedImage menu,enemy;
public static boolean onmenu,oneenemy;
public static void main(String[] args){
new RTSMain();
}
public RTSMain(){
init();
}
public void init(){
setSize(1700,1100);
setVisible(true);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("RTS");
addMouseListener(this);
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
if(onmenu == true){
g2.drawImage(menu,0,0,this);
}
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
Enemy enemy = new Enemy();
int x = e.getX();
int y = e.getY();
enemy.spawnEnemy(x, y);
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}
Enemy class -
package joey.rts;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class Enemy{
/**
*
*/
public static BufferedImage enemy;
private static final long serialVersionUID = 7898827977636314494L;
public static RTSMain rts;
public static void main(String[] args){
try{
enemy = ImageIO.read(new File(javax.swing.filechooser.FileSystemView.getFileSystemView().getHomeDirectory() + "\\enemy.png"));
} catch (Exception e){
e.printStackTrace();
}
}
public static void spawnEnemy(int x, int y){
Graphics g = rts.getGraphics();
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(enemy,x,y,null);
}
}
In your Main class update your mouseClicked function to be :
#Override
public void mouseClicked(MouseEvent e) {
Enemy enemy = new Enemy();
int x=e.getX(); // get mouse positionX
int y=e.getY();//get mouse positionY
enemy.spawnEnemy(x,y);//spawn Enemy
}
Consider saving the enemy objects if you need to reuse it later.
Also I see no need to extend anything in Enemy Class.
I've Updated Your Main and your Enemy class :
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
public class Main extends JFrame implements MouseListener{
/**
*
*/
private static final long serialVersionUID = -7122370886923000314L;
public static BufferedImage menu,enemy;
public static boolean onmenu,oneenemy;
public static void main(String[] args){
new Main().setVisible(true);
}
public Main(){
init();
}
public void init(){
setSize(1700,1100);
setVisible(true);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("RTS");
addMouseListener(this);
}
#Override
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
if(onmenu == true){
g2.drawImage(menu,0,0,this);
}
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
Enemy enemy = new Enemy();
int x = e.getX();
int y = e.getY();
enemy.spawnEnemy(x, y,this.getGraphics());
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}
And this is the Enemy class :
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
public class Enemy{
public static BufferedImage enemy;
private static final long serialVersionUID = 7898827977636314494L;
public Enemy(){
try {
//MAKE SURE THAT THIS IS THE CORRECT IMAGE PATH
enemy = ImageIO.read(new File(javax.swing.filechooser.FileSystemView.getFileSystemView().getHomeDirectory() + "\\enemy.png"));
} catch (IOException ex) {
Logger.getLogger(Enemy.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void spawnEnemy(int x, int y,Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(enemy,x,y,null);
}
}
I've removed the instance variable of Main that was on Enemy class.
I've removed the static modifier for the spawnEnemy function.
I've sent the graphics object as an attribute to spawnEnemy function .
I've Moved the code that was in main method in Enemy class to the Enemy Constructor.
Hope it helps !
It just seemed easier to paste an answer than to try to explain it in a comment. Your OO is a bit off. Add this to your RTSMain class:
protected ArrayList<Enemy> enemies = new ArrayList<Enemy>();
protected BufferedImage enemyImage = null;
...
public void init() {
...
// everything you already have...
enemyImage = //read in your enemy image here
...
}
...
#Override
public void mouseClicked(MouseEvent e) {
// this takes place of Enemy.spawn(), get rid of it
int x = e.getX(); // get mouse positionX
int y = e.getY(); //get mouse positionY
Enemy enemy = new Enemy( enemyImage, x, y );
Enemies.add( enemy );
// Iterate over list above to draw each enemy in your paintComponent method
}
Also, JFrame doesn't have a paintComponent() method, which you need to override to do your painting (paint() is deprecated). Add a JPanel, override it's paintComponent() and so on. For a game, you'll probably want to create a game loop to do your painting, unless it's very turn-based.
Happy coding.
I'm working on a game project. The aim is clicking the balls and drop them into the basket which is below in the JPanel. I created some ways to do that but I can't achieve it. In my opinion, when the user click the ball's center with a margin of error (because the program can't catch the real point of balls), the program understands the action and runs the function of this issue. After clicking the ball it should be dropped down straight but the other balls should be continued. I use MouseListener#mousePressed method, but it doesn't work or I'm missing some parts. In addition, I made some changes in my source code, but I want to listen your advices so I am writing this topic.
I wrote a method which finds the mouse and ball coordinates. So when I make some changes to it, I can achieve my project goal. You can see the editing in the picture.
This is my source code ;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Game {
public Game() {
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("MultipleBallApp");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new BallControl());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class BallControl extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private BallPanel ballPanel = new BallPanel();
private JButton Suspend = new JButton("Suspend");
private JButton Resume = new JButton("Resume");
private JButton Add = new JButton("+1");
private JButton Subtract = new JButton("-1");
private JScrollBar Delay = new JScrollBar();
public BallControl() {
// Group buttons in a panel
JPanel panel = new JPanel();
panel.add(Suspend);
panel.add(Resume);
panel.add(Add);
panel.add(Subtract);
// Add ball and buttons to the panel
ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
Delay.setOrientation(JScrollBar.HORIZONTAL);
ballPanel.setDelay(Delay.getMaximum());
setLayout(new BorderLayout());
add(Delay, BorderLayout.NORTH);
add(ballPanel, BorderLayout.CENTER);
add(panel, BorderLayout.SOUTH);
this.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent clickEvent) {
// TODO Auto-generated method stub
System.out.println("X coordinate =" + clickEvent.getX());
System.out.println("Y coordinate = " + clickEvent.getY());
double radius1;
int x = 0;
double y = 0;
int radius = 15;
double xM = clickEvent.getX();
double yM = clickEvent.getY();
radius1 = Math.sqrt((xM - x) * (xM - x) + (yM - y)
* (yM - y));
System.out.println("Radius1 =" + radius1);
// ballPanel.list.get(0).setD
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
}
});
// Register listeners
Suspend.addActionListener(new Listener());
Resume.addActionListener(new Listener());
Add.addActionListener(new Listener());
Subtract.addActionListener(new Listener());
Delay.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
ballPanel.setDelay(Delay.getMaximum() - e.getValue());
}
});
}
class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Suspend) {
ballPanel.suspend();
} else if (e.getSource() == Resume) {
ballPanel.resume();
} else if (e.getSource() == Add) {
ballPanel.add();
} else if (e.getSource() == Subtract) {
ballPanel.subtract();
}
}
}
}
class BallPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private int delay = 30;
public ArrayList<AnimatedShape> list = new ArrayList<AnimatedShape>();
private AnimatedRectange rectangle;
public BallPanel() {
this.rectangle = new AnimatedRectange(-25, 373, 50, 25, Color.BLACK);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
// Create a timer with the initial delay
protected Timer timer = new Timer(delay, new ActionListener() {
/**
* Handle the action event
*/
#Override
public void actionPerformed(ActionEvent e) {
for (AnimatedShape ball : list) {
ball.update(getBounds());
}
rectangle.update(getBounds());
repaint();
}
});
public void add() {
int radius = 15;
// Randomised position
int x = (int) (Math.random() * (getWidth() - (radius * 2)))
+ radius;
int y = (int) (Math.random() * (getHeight() - (radius * 2)))
+ radius;
Color color = new Color((int) (Math.random() * 256),
(int) (Math.random() * 256), (int) (Math.random() * 256));
AnimatedBall ball = new AnimatedBall(x, y, radius, color);
list.add(ball);
}
// public void formula(MouseEvent clickEvent) {
// double radius1;
// int x = 0;
// double y = 0;
// int radius = 15;
// double xM = clickEvent.getX();
// double yM = clickEvent.getY();
// radius1 = Math.sqrt((xM - x) * (xM - x) + (yM - y) * (yM - y));
// System.out.println("Radius1 =" + radius1);
// }
public void subtract() {
if (list.size() > 0) {
list.remove(list.size() - 1); // Remove the last ball
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (AnimatedShape ball : list) {
ball.paint(this, g2d);
}
rectangle.paint(this, g2d);
}
public void suspend() {
timer.stop();
}
public void resume() {
timer.start();
}
public void setDelay(int delay) {
this.delay = delay;
timer.setDelay(delay);
}
}
public interface AnimatedShape {
public void update(Rectangle bounds);
public void paint(JComponent parent, Graphics2D g2d);
}
public abstract class AbstractAnimatedShape implements AnimatedShape {
private Rectangle bounds;
private int dx, dy;
public AbstractAnimatedShape() {
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
public Rectangle getBounds() {
return bounds;
}
public int getDx() {
return dx;
}
public int getDy() {
return dy;
}
public void setDx(int dx) {
this.dx = dx;
}
public void setDy(int dy) {
this.dy = dy;
}
#Override
public void update(Rectangle parentBounds) {// ball
Rectangle bounds = getBounds();
int dx = getDx();
int dy = getDy();
bounds.x += dx;
bounds.y += dy;
if (bounds.x < parentBounds.x) {
bounds.x = parentBounds.x;
setDx(dx *= -1);
} else if (bounds.x + bounds.width > parentBounds.x
+ parentBounds.width) {
bounds.x = parentBounds.x + (parentBounds.width - bounds.width);
setDx(dx *= -1);
}
if (bounds.y < parentBounds.y) {
bounds.y = parentBounds.y;
setDy(dy *= -1);
} else if (bounds.y + bounds.height > parentBounds.y
+ parentBounds.height) {
bounds.y = parentBounds.y
+ (parentBounds.height - bounds.height);
setDy(dy *= -1);
}
}
}
public class AnimatedBall extends AbstractAnimatedShape {
private Color color;
public AnimatedBall(int x, int y, int radius, Color color) {
setBounds(new Rectangle(x, y / 2, radius * 2, radius * 2));
this.color = color;
setDx(Math.random() > 0.5 ? 2 : -2);
// setDy(Math.random() > 0.5 ? 2 : -2);
}
public Color getColor() {
return color;
}
#Override
public void paint(JComponent parent, Graphics2D g2d) {
Rectangle bounds = getBounds();
g2d.setColor(getColor());
g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
public class AnimatedRectange extends AbstractAnimatedShape {
private Color color;
public AnimatedRectange(int x, int y, int width, int height, Color color) {
setBounds(new Rectangle(x, y, width, height));
this.color = color;
setDx(2);
}
// Don't want to adjust the vertical speed
#Override
public void setDy(int dy) {
}
#Override
public void paint(JComponent parent, Graphics2D g2d) {
Rectangle bounds = getBounds();
g2d.setColor(color);
g2d.fill(bounds);
}
}
/**
* Main method
*/
public static void main(String[] args) {
new Game();
}
}
At the end of your mousePressed method, you can go though all AnimatedShape objects, check whether they are an AnimatedBall. When the object is a ball, you can test whether the mouse click hits the ball. The mouse click hits the ball when the distance between the center of the ball and the mouse position is smaller than the ball radius. When the ball is hit, you can set its horizontal speed to 0, and the vertical speed to 5 or so.
for (AnimatedShape as : ballPanel.list)
{
if (as instanceof AnimatedBall)
{
AnimatedBall ball = (AnimatedBall)as;
Rectangle b = ball.getBounds();
int ballCenterX = b.x + b.width / 2;
int ballCenterY = b.y + b.height / 2;
Point p = new Point(ballCenterX, ballCenterY);
double d = p.distance(clickEvent.getPoint());
if (d < radius)
{
ball.setDx(0);
ball.setDy(5);
}
}
}
Note
In order to make this work properly, you have to attach this listener to the ballPanel. Originally, you had the line
this.addMouseListener(new MouseListener() {
in your code. You have to change this to
ballPanel.addMouseListener(new MouseListener() {
Otherwise, the mouse coordinates will refer to the wrong component!
Concerning the question from the comment
how can I stop and disapper clickedball's when they crash the bound
You may probably insert method to check this, and call this method in the actionPerformed method of your timer. Further explainations are probably beyond the scope of an anser on a Q&A site. Stackoverflow is not a homework-solution-generator.
I decided to re-write my game using Swing's painting technique paintComponent() method(someone on SO actually told me to use this method). I decided to use JPanel as the game's base instead of Canvas. My previous written game uses a Canvas but the game could not show up on my 64 bit desktop but could show up on my 32 bit labtop which is why this game had to be re-written.
Problem now is, while the ship's movement works, the drawing seems awfully slow(unless it is my laptop problem?) compare to what I did before which was using AWT's double buffering drawing technique. I spend a whole day but could not figure out what could possibly make the ship run faster.
public class Ship extends JLabel implements KeyListener{
private Image image;
private boolean turnRight;
private int x;
private int y;
private int speed = 5;
private boolean turnLeft;
public Ship(int x, int y)
{
this.x = x;
this.y = y;
try {
image = ImageIO.read(new File("Ship/Ship.PNG"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
addKeyListener(this);
}
public Image getImage()
{
return image;
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if(e.getKeyCode() == KeyEvent.VK_RIGHT)
{
x += speed;
setTurnRight(true);
setTurnLeft(false);
}
else if(e.getKeyCode() == KeyEvent.VK_LEFT)
{
x -= speed;
setTurnLeft(true);
setTurnRight(false);
}
// redraw yourself
repaint();
}
private void setTurnLeft(boolean turnLeft) {
// TODO Auto-generated method stub
this.turnLeft = turnLeft;
}
// swing custom painting
public void paintComponent(Graphics g)
{
if(x <= 0)
{
x = 0;
}
else if(x >= 610)
{
x = 610;
}
g.drawImage(getImage(), x, y, null);
}
public void setTurnRight(boolean turnRight)
{
this.turnRight = turnRight;
}
public boolean getTurnLeft()
{
return turnLeft;
}
public boolean getTurnRight()
{
return turnRight;
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
Normally, I would create a concept of a renderable element. I would maintain a list of these elements and update them accordingly within my main loop.
At the very least, each would have a concept of location, direction and rotation (if required), they would also be capable of been painted.
Within my main component, I would simply loop through all these elements and "draw" them, offset the Graphics context to allow for there position within the game space.
But that's not what you are doing...
Remember, components have a sense of location and size already, you shouldn't be trying to re-implement this requirement, instead, you should be finding ways to take advantage of it...(ie, don't maintain a reference to the x/y values ;))
The following is a simple example. It uses a JPanel to render the main image. The main loop (in this case a javax.swing.Timer), tells the component that it should update it's movement as required.
The ship itself is responding to key events by changing the rotation value by a given, variable, delta. This allows you to control the speed of the spin as you need (I've deliberately set it low to start with, so play around with it)
What you should resist doing, is changing the frame rate ;)
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
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;
import javax.swing.border.LineBorder;
public class BattleShipGame {
public static void main(String[] args) {
new BattleShipGame();
}
public BattleShipGame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new OceanPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class OceanPane extends JPanel {
private BattleShip ship;
public OceanPane() {
setLayout(new GridBagLayout());
ship = new BattleShip();
add(ship);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ship.move();
revalidate();
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
public static class BattleShip extends JPanel {
protected static final int MAX_TURN_RATE = 5;
private BufferedImage ship;
private float angle;
private float angleDelta;
public BattleShip() {
setOpaque(false);
try {
ship = ImageIO.read(new File("BattleShip.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
setFocusable(true);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "leftTurn");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "rightTurn");
am.put("leftTurn", new TurnAction(-0.1f));
am.put("rightTurn", new TurnAction(0.1f));
}
public void move() {
angle += angleDelta;
}
public void setAngle(float angle) {
this.angle = angle;
}
public float getAngle() {
return angle;
}
#Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(0, 0);
if (ship != null) {
double rads = Math.toRadians(getAngle());
double sin = Math.abs(Math.sin(rads)), cos = Math.abs(Math.cos(rads));
int w = ship.getWidth();
int h = ship.getHeight();
size.width = (int) Math.floor(w * cos + h * sin);
size.height = (int) Math.floor(h * cos + w * sin);
}
return size;
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (ship != null) {
Graphics2D g2d = (Graphics2D) g.create();
double rads = Math.toRadians(getAngle());
double sin = Math.abs(Math.sin(rads)), cos = Math.abs(Math.cos(rads));
int w = ship.getWidth();
int h = ship.getHeight();
int newWidth = (int) Math.floor(w * cos + h * sin);
int newHeight = (int) Math.floor(h * cos + w * sin);
AffineTransform at = new AffineTransform();
at.translate((newWidth - w) / 2, (newHeight - h) / 2);
at.rotate(Math.toRadians(getAngle()), w / 2, h / 2);
g2d.drawImage(ship, at, this);
g2d.dispose();
}
}
protected class TurnAction extends AbstractAction {
protected float delta;
public TurnAction(float delta) {
this.delta = delta;
}
#Override
public void actionPerformed(ActionEvent e) {
angleDelta += delta;
if (angleDelta > MAX_TURN_RATE) {
angleDelta = MAX_TURN_RATE;
} else if (angleDelta < (MAX_TURN_RATE * -1)) {
angleDelta = (MAX_TURN_RATE * -1);
}
}
}
}
}
I would recommend having a class which extends JPanel, using a javax.swing.Timer in there, defining your 1000/fps and your ActionListener, in which you use a repaint() which uses a paintComponent that you will make that would call upon the draw method in your Ship, which is now called paintComponent.
So, as that explaination was terrible, here is some code:
public class Class_Name extends JPanel()
{
Ship ship = new Ship(0,0);
javax.swing.Timer timer = new javax.swing.Timer(1000/60, new ActionListener(){
repaint();
});
public void paintComponent(Graphics g)
{
super.paintComponent();
ship.draw(g);
}
}
and the draw is, what is now called paintComponent.
If this didn't answer your question, please let me know.
I've created a basic Java program that creates a rectangle on startup and every time it is clicked, the rectangle grows and changes to a different (random) color. here's my code:
package rectPAK;
import javax.swing.JFrame;
public class DisplayRect {
public static void main(String[] args) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setBounds(0,0,1000,1000);
window.getContentPane().add(new MyCanvas());
window.setVisible(true);
}
}
and then myCanvas is this:
package rectPAK;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Random;
import javax.swing.JComponent;
public class MyCanvas extends JComponent{
int W = 100;
int H = 100;
int r;
int g;
int b;
int trans;
int maxRandNum = 255;
int xPoint;
int yPoint;
public MyCanvas() {
this.addMouseListener(m);
this.addMouseMotionListener(ml);
}
Random rand = new Random();
MouseListener m = new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
W = W + 20;
H = H + 20;
r = rand.nextInt(maxRandNum);
g = rand.nextInt(maxRandNum);
b = rand.nextInt(maxRandNum);
trans = rand.nextInt(maxRandNum);
repaint();
}
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
};
MouseMotionListener ml = new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {
Point p = e.getLocationOnScreen();
xPoint = p.x;
yPoint = p.y;
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
};
public void paint(Graphics gr) {
gr.setColor(Color.BLACK);
gr.drawRect(xPoint, yPoint, W, H);
gr.setColor(new Color(r,g,b,trans));
gr.fillRect(xPoint, yPoint, W, H);
}
}
now my question is this: how do i make it so that when i right-click on the rectangle, it reverts to the previous size and color? i Know it's a lot to ask, but i cant find anything about it...
Thanks a lot.
Use a set of "previous" variables (eg previousX, previousY, previousR, etc) to store the old info before every update, and create a right click event to call a method like your paint method to set the object's variables to previousX, previousY, etc.
Every time you generate a random number, store it as the previous instance. This way you will be able to go back one step. If you want to go back all the way to the first one, then you should store each created rectangle's parameters in an stack of sorts, where you could pop out each previous stage.
Once that is done you should create a method for handling right clicks, and in that method, you should set the rectangles parameters to the previous value.
I want to achieve the effect of java in the brush, the mouse returned to the point, move the mouse faster, thinner lines.
Here is a program which demonstrates what you are trying to achieve.
This program is not perfect, but should get you started with what you are trying to build.
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
public class PaintBrush {
JFrame f;
Canvas c;
int x=-1, y=-1;
public PaintBrush() {
f = new JFrame();
f.setSize(600, 400);
c = new Canvas() {
public void paint(Graphics g) {
// super.paint(g);
}
};
f.getContentPane().add(c);
c.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseDragged(MouseEvent e) {
if(x==-1){
x = e.getX();
y = e.getY();
}
int diffx = Math.abs(x - e.getX());
int diffy = Math.abs(y - e.getY());
System.out.println("diffx:"+diffx+"\t"+"diffy:"+diffy);
int speed = (int) Math.sqrt((diffx + diffy));
if(speed>1){
c.getGraphics().fillOval(x, y, 20-speed*2, 20-speed*2);
}else {
c.getGraphics().fillOval(x, y, 20, 20);
}
System.out.print("Speed:"+speed + "\t");
System.out.println("x:"+e.getX());
x = e.getX();
y = e.getY();
}
});
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
public static void main(String[] args) {
new PaintBrush();
}