Graphics arch not exact - java

I have to draw precise archs in java. I am currenlty using Graphics2D.fillArc(). The problem is that it only accepts ints and the archs are not precise and i cant make the archs degree increase smoothly. Does anyone know a workaround this?

Here's my SSCCE using Arc2D.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Arc2D;
import javax.swing.*;
#SuppressWarnings("serial")
public class ChangingArcs extends JPanel {
private static final Color ARC_FILL_COLOR = Color.RED;
private static final int TIMER_DELAY = 20;
private static final int ARC_X = 100;
private static final int ARC_Y = 100;
private static final int ARC_W = 500;
private static final int ARC_H = 500;
protected static final double DELTA_EXTEND = 0.5;
private Arc2D arc;
private double extend = 0;
public ChangingArcs() {
new Timer(TIMER_DELAY, new ActionListener() {
public void actionPerformed(ActionEvent e) {
extend += DELTA_EXTEND;
extend %= 360;
double start = -extend/2;
arc = new Arc2D.Double(ARC_X, ARC_Y, ARC_W, ARC_H, start, extend, Arc2D.PIE);
repaint();
}
}).start();
}
public Dimension getPreferredSize() {
return new Dimension(ARC_W + 2 * ARC_X, ARC_H + 2 * ARC_Y);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
if (arc != null) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(ARC_FILL_COLOR);
g2.fill(arc);
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("ChangingArcs");
frame.getContentPane().add(new ChangingArcs());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}

Related

MouseListener for a custom circle object is not working when it is drawn to a JPanel Gameboard object

I am developing the peg game in java, and I have been stuck on getting a hole to change color when it is clicked on to indicate that it has been selected. I currently have 3 classes, all of which extend JPanel:
Display.java: creates the JFrame and renders the gameboard to the JFrame.
GameBoard.java: Holds the logic for rendering the gameboard.
Hole.java: Renders a hole and holds the logic for the MouseListener. When one clicks on a hole, it should turn blue to indicate that it is selected.
I am able to render the holes onto the gameboard, however, the MouseListener does not work; When I click on a hole, it does not turn blue.
Below are the three classes:
Display.java
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.logging.*;
public class Display extends JPanel {
private static final long serialVersionUID = 1L;
private static String staticClassName = Display.class.getName();
private static Logger logger = Logger.getLogger(staticClassName);
private final static Logger LOGGER = Logger.getLogger(staticClassName);
private static String title;
private static int width;
private static int height;
private static JFrame frame;
private static JPanel mainPanel;
private static GameBoard gameBoard;
public Display(String title, int width, int height){
logger.info(staticClassName +".Constructor: Constructing Display");
Display.title = title;
Display.width = width;
Display.height = height;
logger.info(staticClassName +".Constructor: Display constructed.");
initDisplay();
}
private static void initDisplay() {
logger.info(staticClassName +".initDisplay(): Entering method");
try {
logger.info(staticClassName +".initDisplay(): About to create JFrame");
frame = new JFrame(title);
frame.setLocationByPlatform(true);
frame.setVisible(true);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPanel = new JPanel();
logger.info(staticClassName +".initDisplay(): About to create GameBoard object");
gameBoard = new GameBoard();
mainPanel.add(gameBoard);
frame.getContentPane().add(mainPanel);
frame.pack();
} catch (Exception e) {
logger.info(staticClassName +".initDisplay(): Failed to render display: " + e);
}
logger.info(staticClassName +".initDisplay(): Exiting Method");
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
LOGGER.setLevel(Level.INFO);
Display d = new Display("Peg Game", 800, 800);
} catch (Exception e) {
}
}
});
}
}
GameBoard.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import java.util.logging.Logger;
import javax.swing.JPanel;
public class GameBoard extends JPanel {
private static final long serialVersionUID = 1L;
private static String staticClassName = GameBoard.class.getName();
private static Logger logger = Logger.getLogger(staticClassName);
private static final int RGB1 = 223;
private static final int RGB2 = 191;
private static final int RGB3 = 159;
private static final int WIDTH = 800;
private static final int HEIGHT = WIDTH;
private Path2D path = new Path2D.Double();
private static Color boardColor = new Color(RGB1, RGB2, RGB3);
private int [] adjacentHoles1;
public GameBoard() {
logger.info(staticClassName +".Constructor: Constructing GameBoard");
double firstX = (WIDTH / 2.0) * (1 - 1 / Math.sqrt(3));
double firstY = 3.0 * HEIGHT / 4.0;
path.moveTo(firstX, firstY);
path.lineTo(WIDTH - firstX, firstY);
path.lineTo(WIDTH / 2.0, HEIGHT / 4.0);
path.closePath();
logger.info(staticClassName +".Constructor: GameBoard constructed");
}
#Override
protected void paintComponent(Graphics g) {
logger.info(staticClassName +".paintComponent(): Entering method");
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(boardColor);
g2.fill(path);
int xPos = 390;
int yPos = 310;
// I was rendering up to 15 holes, but took them out for purpose of
// shortening my example
for (int i = 0; i < 15; i ++ ) {
if (i == 0) {
// Declare the hole here
Hole hole = new Hole(i, xPos, yPos, adjacentHoles1);
// Render it here
hole.paintComponent(g2);
yPos += 50;
}
}
logger.info(staticClassName +".paintComponent(): Exiting method");
}
#Override
public Dimension getPreferredSize() {
logger.info(staticClassName +".getPreferredSize(): Entering method");
if (isPreferredSizeSet()) {
logger.info(staticClassName +".getPreferredSize(): isPreferredSizeSet() == true. Exiting method");
return super.getPreferredSize();
}
logger.info(staticClassName +".getPreferredSize(): isPreferredSizeSet() == false. Exiting method");
return new Dimension(WIDTH, HEIGHT);
}
}
Hole.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.logging.Logger;
import javax.swing.JPanel;
public class Hole extends JPanel {
private static final long serialVersionUID = 1235245435988434L;
private static String staticClassName = Hole.class.getName();
private static Logger logger = Logger.getLogger(staticClassName);
private int holeNumber;
private int xPos, yPos;
private final int HOLEWIDTH = 20;
private final int HOLEHEIGHT = HOLEWIDTH;
private static final int RGB1 = 0;
private static final int RGB2 = 0;
private static final int RGB3 = 0;
private static Color defaultCircleColor = new Color(RGB1, RGB2, RGB3);
private static Color selectedCircleColor = Color.BLUE;
private static Color circleColor = defaultCircleColor;
private int [] adjacentHoles;
public Hole (int holeNumber, int xPos, int yPos, int [] adjacentHoles) {
logger.info(staticClassName +".Constructor: Constructing Hole");
this.holeNumber = holeNumber;
this.xPos = xPos;
this.yPos = yPos;
this.adjacentHoles = adjacentHoles;
initComponents();
}
#Override
protected void paintComponent(Graphics g) {
logger.info(staticClassName +".paintComponent(): Entering method");
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(circleColor);
g2.fillOval(xPos,yPos,HOLEWIDTH,HOLEHEIGHT);
logger.info(staticClassName +".paintComponent(): Exiting method");
}
private void initComponents() {
addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent event) {
selectHole(event);
}});
}
public void selectHole(java.awt.event.MouseEvent event) {
logger.info(staticClassName +"------------------------------------------------");
logger.info(staticClassName +".selectHole(): Entering method");
if (circleColor == defaultCircleColor) {
circleColor = selectedCircleColor;
repaint();
}
else {
circleColor = defaultCircleColor;
repaint();
}
logger.info(staticClassName +".selectHole(): Exiting method");
logger.info(staticClassName +"------------------------------------------------");
}
#Override
public Dimension getPreferredSize() {
logger.info(staticClassName +".getPreferredSize(): Getting the preferred size of the circle.");
return new Dimension(800, 800);
}
}
As a side note, if you notice that I could be using better coding practices anywhere in my code, please let me know.
So, your basic problem is right here...
for (int i = 0; i < 15; i ++ ) {
if (i == 0) {
// Declare the hole here
Hole hole = new Hole(i, xPos, yPos, adjacentHoles1);
// Render it here
hole.paintComponent(g2);
yPos += 50;
}
}
Hole is component, you should never call any paint method of component, but, you component is also not "live", meaning that it can never receive ANY events.
What you should do instead, is attach the MouseListener to the GameBoard and test if the mouse was clicked at a place there is a hole.
The simplest solution is to make use of the "shapes" API and generate a list of "holes". This can then be simply iterated over to paint and check to see if the mouse was clicked within it.
I've not gone to a great deal of effort in determining the location of the holes, instead I've just laid them out in rows/cols, but you should get the basic idea of the intended solution
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Display extends JPanel {
private static final long serialVersionUID = 1L;
private static String staticClassName = Display.class.getName();
private static Logger logger = Logger.getLogger(staticClassName);
private final static Logger LOGGER = Logger.getLogger(staticClassName);
private static String title;
private static int width;
private static int height;
private static JFrame frame;
private static JPanel mainPanel;
private static GameBoard gameBoard;
public Display(String title, int width, int height) {
logger.info(staticClassName + ".Constructor: Constructing Display");
Display.title = title;
Display.width = width;
Display.height = height;
logger.info(staticClassName + ".Constructor: Display constructed.");
initDisplay();
}
private static void initDisplay() {
frame = new JFrame(title);
frame.setLocationByPlatform(true);
frame.setVisible(true);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPanel = new JPanel();
gameBoard = new GameBoard();
mainPanel.add(gameBoard);
frame.getContentPane().add(mainPanel);
frame.pack();
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
LOGGER.setLevel(Level.INFO);
Display d = new Display("Peg Game", 800, 800);
} catch (Exception e) {
}
}
});
}
public static class GameBoard extends JPanel {
private static final long serialVersionUID = 1L;
private static String staticClassName = GameBoard.class.getName();
private static Logger logger = Logger.getLogger(staticClassName);
private static final int RGB1 = 223;
private static final int RGB2 = 191;
private static final int RGB3 = 159;
private static final int WIDTH = 800;
private static final int HEIGHT = WIDTH;
private Path2D path = new Path2D.Double();
private static Color boardColor = new Color(RGB1, RGB2, RGB3);
private int[] adjacentHoles1;
private Shape[] holes;
private Shape selectedHole;
public GameBoard() {
logger.info(staticClassName + ".Constructor: Constructing GameBoard");
double firstX = (WIDTH / 2.0) * (1 - 1 / Math.sqrt(3));
double firstY = 3.0 * HEIGHT / 4.0;
path.moveTo(firstX, firstY);
path.lineTo(WIDTH - firstX, firstY);
path.lineTo(WIDTH / 2.0, HEIGHT / 4.0);
path.closePath();
logger.info(staticClassName + ".Constructor: GameBoard constructed");
holes = new Shape[15];
int yPos = 310;
int index = 0;
for (int row = 0; row < 3; row++) {
int xPos = 390;
for (int col = 0; col < 5; col++) {
holes[index] = new Ellipse2D.Double(xPos, yPos, 50, 50);
index++;
xPos += 50;
}
yPos += 50;
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
selectedHole = null;
for (Shape hole : holes) {
if (hole.contains(e.getPoint())) {
selectedHole = hole;
break;
}
}
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
logger.info(staticClassName + ".paintComponent(): Entering method");
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(boardColor);
g2.fill(path);
g2.setColor(Color.BLACK);
for (Shape hole : holes) {
g2.fill(hole);
}
if (selectedHole != null) {
g2.setColor(Color.RED);
g2.fill(selectedHole);
}
logger.info(staticClassName + ".paintComponent(): Exiting method");
}
#Override
public Dimension getPreferredSize() {
logger.info(staticClassName + ".getPreferredSize(): Entering method");
if (isPreferredSizeSet()) {
logger.info(staticClassName + ".getPreferredSize(): isPreferredSizeSet() == true. Exiting method");
return super.getPreferredSize();
}
logger.info(staticClassName + ".getPreferredSize(): isPreferredSizeSet() == false. Exiting method");
return new Dimension(WIDTH, HEIGHT);
}
}
}

Cannot use MouseEvents in main

What I'm trying to do
Making a Pong game where the Y axis gets the value from my cursor according to the application
What did I tried
private void pallet() {
ycur=(int)MouseInfo.getPointerInfo().getLocation().getY();
}
This way I get the Y value according to my monitor instead of the application.
I also tried to use the MouseEvent.getY(), but I get the error when trying to call this method from the main.
private void pallet() {
ycur=(int)MouseInfo.getPointerInfo().getLocation().getY();
}
This is how my code looks like, I think the problem lies in how I'm using my main and methods but I'm not sure.
public class MyFirst extends JPanel {
public int x = 500, y = 300, border = 30;
public boolean goingDown = true;
public int ycur, cursor;
public void moveBall() {
x++;
if (goingDown == true) {
y++;
} else if (goingDown == false) {
y--;
}
if (y == getHeight() - border) {
goingDown = false;
} else if (y == 0) {
goingDown = true;
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 30, 30);
g.fillRect(30, ycur, 15, 100);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Pong");
frame.pack();
frame.setSize(1000, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
MyFirst game = new MyFirst();
frame.add(game);
while (true) {
game.pallet(e);
game.moveBall();
game.repaint();
Thread.sleep(10);
}
}
public void pallet(MouseEvent e) {
ycur=e.getY();
}
}
Problems with your code:
As already mentioned, you're fighting against Swing's event-driven architecture. Instead of a while true loop, use listeners, including a MouseMotionListener ot track the changes in the mouse location, and an ActionListener tied to a Swing Timer to move the ball.
Avoid using Thread.sleep(...) in Swing GUI's except with great care as this can put the entire application to sleep.
Avoid putting too much logic within the main method. This method should be short, should create the key objects, connect them, set the program in motion and that's it.
Paint with the paintComponent method, not the paint method. It results in smoother animation with its double buffering.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class MoveBallTest extends JPanel{
private static final int PREF_W = 1000;
private static final int PREF_H = 600;
private static final int TIMER_DELAY = 12;
private static final int SPRITE_WIDTH = 30;
private static final Color OVAL_SPRITE_COLOR = Color.RED;
private static final Color RECT_SPRITE_COLOR = Color.BLUE;
private static final int DELTAY_Y = 1;
private boolean goingDown = true;
private Timer timer = new Timer(TIMER_DELAY, this::timerActionPerformed);
private int ovalSpriteY;
private int rectSpriteY;
public MoveBallTest() {
timer.start();
MyMouse myMouse = new MyMouse();
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(OVAL_SPRITE_COLOR);
g.fillOval(SPRITE_WIDTH, ovalSpriteY, SPRITE_WIDTH, SPRITE_WIDTH);
g.setColor(RECT_SPRITE_COLOR);
g.fillRect(SPRITE_WIDTH, rectSpriteY, SPRITE_WIDTH / 2, SPRITE_WIDTH * 3);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void timerActionPerformed(ActionEvent e) {
if (ovalSpriteY <= 0) {
goingDown = true;
} else if (ovalSpriteY >= getHeight() - SPRITE_WIDTH) {
goingDown = false;
}
ovalSpriteY += goingDown ? DELTAY_Y : -DELTAY_Y;
repaint();
}
private class MyMouse extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
rectSpriteY = e.getY();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MoveBallTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MoveBallTest());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

Placement of a JPanel within a JPanel

I'm trying to code a simple Pong and I have the background panel which contains a Bar panel. So of course I need to be able to place the bar on the size and move it vertically at request. Now I'm just trying to put it in a starting position. If I don't disable the layout the bar gets placed in the top center regardless of location setting, but if I disable the layout and set location it just doesn't show up. I'm not sure what I missing. Here is a code snippet if it can be relevant:
public PongPanel() {
setLayout(null);
setPreferredSize(SIZE);
setBackground(Color.BLACK);
player_one_bar = new Bar();
add(player_one_bar);
player_one_bar.setLocation(10, getSize().height/2-3);
}
If you set the layout manager as null you'll have to specify the exact coordinates of the panel, meaning something like -
setBounds(10, 10, 20, 100);
Will put the panel at location (10,10) with Width of 20 and Height of 100.
If by "bar" you mean Pong game paddle, then it shouldn't be a component at all but rather a logical entity that represents a position, which is visually represented by a sprite that gets drawn in the JPanel's paintComponent method.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class PongPaddle extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 500;
private static final int RECT_X = 20;
private static final int RECT_W = 10;
private static final int RECT_H = 60;
private static final int STARTING_Y = (PREF_H - RECT_H) / 2;
private static final int TIMER_DELAY = 15;
private static final int DELTA_PADDLE = 3;
private boolean paddle1GoingDown = true;
private boolean paddle2GoingDown = false;
private Rectangle paddle1 = new Rectangle(RECT_X, STARTING_Y, RECT_W, RECT_H);
private Rectangle paddle2 = new Rectangle(PREF_W - RECT_X - RECT_W,
STARTING_Y, RECT_W, RECT_H);
public PongPaddle() {
setBackground(Color.black);
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
int deltaPaddle1 = paddle1GoingDown ? 1 : -1;
deltaPaddle1 *= DELTA_PADDLE;
int x = paddle1.getLocation().x;
int y = paddle1.getLocation().y + deltaPaddle1;
if (y + RECT_H >= PREF_H) {
paddle1GoingDown = false;
}
if (y <= 0) {
paddle1GoingDown = true;
}
paddle1.setLocation(x, y);
int deltaPaddle2 = paddle2GoingDown ? 1 : -1;
deltaPaddle2 *= DELTA_PADDLE;
x = paddle2.getLocation().x;
y = paddle2.getLocation().y + deltaPaddle2;
if (y + RECT_H >= PREF_H) {
paddle2GoingDown = false;
}
if (y <= 0) {
paddle2GoingDown = true;
}
paddle2.setLocation(x, y);
repaint();
if (!PongPaddle.this.isShowing()) {
((Timer) e.getSource()).stop();
}
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.white);
if (paddle1 != null) {
g2.fill(paddle1);
}
if (paddle2 != null) {
g2.fill(paddle2);
}
}
private static void createAndShowGui() {
PongPaddle mainPanel = new PongPaddle();
JFrame frame = new JFrame("PongPaddle");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Key Listener isn't working

I've been experimenting with creating a java game but I've hit a roadblock, I can't get java to listen to any of my keys even when I'm just using print statements to test it out. From what I understand I've implemented KeyListener correctly and added the key listener to the Applet but it still isn't working.
My main class:
import java.awt.*;
import javax.swing.*;
public class Container extends JApplet implements Runnable {
private static final long serialVersionUID = 1L;
public static Dimension size = new Dimension(720,560); //Size of Screen
private static final int PIXELSIZE = 2;
public static Dimension pixel = new Dimension(size.width/PIXELSIZE,
size.height/PIXELSIZE); // Dimesions of screen in terms of pixels
public static final String NAME = "Game";
public static boolean isRunning = false;
private Image screen;
public static Level level;
public static MainCharacter p1;
public Container(){
setPreferredSize(size);
addKeyListener(p1);
}
public void start(){
new Tile();
level = new Level();
p1 = new MainCharacter(20,40);
isRunning = true;
new Thread(this).start();
}
public void tick(){
p1.tick();
}
public void render(){
Graphics g = screen.getGraphics();
g.setColor(new Color(130,160,255));
g.fillRect(0, 0, pixel.width, pixel.height);
level.render(g);
p1.render(g);
g = getGraphics();
g.drawImage(screen, 0, 0, size.width, size.height,
0, 0, pixel.width, pixel.height, null);
g.dispose();
}
public void run() {
screen = createVolatileImage(pixel.width,pixel.height);
while(isRunning){
tick();
render();
try{
Thread.sleep(5);
}catch(InterruptedException e){}
}
}
public static void main(String[] args){
Container container = new Container();
JFrame frame = new JFrame();
frame.add(container);
frame.pack();
frame.setTitle(NAME);
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
container.start();
}
public static void right(){
p1.right();
}
public static void left(){
p1.left();
}
}
My character class:
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class MainCharacter extends Tall implements KeyListener{
public double fallSpeed = 1.5;
public double moveSpeed = 1.0;
public double xSpeed = 1;
public MainCharacter(int width, int height){
setBounds(Container.pixel.width/2 - width/2,
Container.pixel.height/2 - height/2,
width, height);
}
public void tick(){
if(Container.level.space[(int)(x+width)][(int)(y+height)] &&
Container.level.space[(int)(x)][(int)(y+height)] &&
Container.level.space[(int)(x+width)][(int)(y)] &&
Container.level.space[(int)(x)][(int)(y)])
y += fallingSpeed;
}
public void render(Graphics g){
g.drawImage(Tile.tileset_terrain, (int)x, (int)y,
(int)(x+width),(int)(y+height),
Tile.CHARACTER[0]*Tile.TILE_SIZE,
Tile.CHARACTER[1]*Tile.TILE_SIZE,
Tile.CHARACTER[0]*Tile.TILE_SIZE +(int)width,
Tile.CHARACTER[1]*Tile.TILE_SIZE + (int)height, null);
}
public void right(){
x += xSpeed;
}
public void left(){
x -= xSpeed;
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("hey");
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("hey");
}
#Override
public void keyTyped(KeyEvent e) {
System.out.println("hey");
}
}
It looks like p1 is null when you add it as a KeyListener.
You add it as a KeyListener here:
public Container(){
setPreferredSize(size);
System.out.println(p1); // try this...
addKeyListener(p1);
}
But instantiate it here:
public void start(){
new Tile();
level = new Level();
p1 = new MainCharacter(20,40);
isRunning = true;
new Thread(this).start();
}
KeyListeners are fickle. They require that the component they are registered to are not only focusable, but have keyboard focus.
It's recommend that instead, you should use Key Bindings instead

Java repaint() not working

I am making a simple program to paint a graph and some points in it. The points should be made with methods while changing coordinates of the g.fillOval but actually its painting only the last point.
Here is the code:
import javax.swing.*;
import java.awt.*;
public class PointGraphWriter extends JPanel
{
JFrame korniza = new JFrame();
private int x;
private int y;
private int length;
private String OX;
private String OY;
private String emri;
private int y_height;
private int x_num;
public PointGraphWriter()
{
int width= 500;
korniza.setSize(width,width);
korniza.setVisible(true);
korniza.setTitle(emri);
korniza.getContentPane().add(this);
}
public void paintComponent(Graphics g)
{
g.drawLine(x,y,x+length,y);
g.drawLine(x,y,x,y-length);
g.drawString(OX,x+length, y+15);
g.drawString(OY,x-15,y-length);
g.drawString("0", x -15,y);
g.drawString("0", x,y+15);
g.fillOval(x_num,y-y_height-2, 4 ,4);
}
public void setTitle(String name)
{
emri= name;
this.repaint();
}
public void setAxes(int x_pos, int y_pos, int axis_length, String x_label, String y_label)
{
x= x_pos;
y=y_pos;
length= axis_length;
OX = x_label;
OY = y_label;
}
public void setPoint1(int height)
{
y_height=height;
x_num = x-2;
this.repaint();
}
public void setPoint2(int height)
{
y_height=height;
x_num = x + length/5-2;
this.repaint();
}
}
and here is the main method:
public class TestPlot
{
public static void main(String[] a)
{
PointGraphWriter e = new PointGraphWriter();
e.setTitle("Graph of y = x*x");
e.setAxes(50, 110, 90, "5", "30");
int scale_factor = 3;
e.setPoint1(0 * scale_factor);
e.setPoint2(1 * scale_factor);
}
}
Please have a look at this example. Something in lines of this, you might have to incorporate in your example, to make it work. Simply use a Collection to store what you have previously painted, and when the new thingy comes along, simply add that thingy to the list, and repaint the whole Collection again. As shown below :
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
public class RectangleExample {
private DrawingBoard customPanel;
private JButton button;
private Random random;
private java.util.List<Rectangle2D.Double> rectangles;
private ActionListener buttonActions =
new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
Rectangle2D.Double rectangle = new Rectangle2D.Double(
(double) random.nextInt(100), (double) random.nextInt(100),
(double) random.nextInt(100), (double) random.nextInt(100));
rectangles.add(rectangle);
customPanel.setValues(rectangles);
}
};
public RectangleExample() {
rectangles = new ArrayList<Rectangle2D.Double>();
random = new Random();
}
private void displayGUI() {
JFrame frame = new JFrame("Rectangle Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(5, 5));
customPanel = new DrawingBoard();
contentPane.add(customPanel, BorderLayout.CENTER);
button = new JButton("Create Rectangle");
button.addActionListener(buttonActions);
contentPane.add(button, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new RectangleExample().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
class DrawingBoard extends JPanel {
private java.util.List<Rectangle2D.Double> rectangles =
new ArrayList<Rectangle2D.Double>();
public DrawingBoard() {
setOpaque(true);
setBackground(Color.WHITE);
}
public void setValues(java.util.List<Rectangle2D.Double> rectangles) {
this.rectangles = rectangles;
repaint();
}
#Override
public Dimension getPreferredSize() {
return (new Dimension(300, 300));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Rectangle2D.Double rectangle : rectangles) {
g.drawRect((int)rectangle.getX(), (int)rectangle.getY(),
(int)rectangle.getWidth(), (int)rectangle.getHeight());
}
System.out.println("WORKING");
}
}
See Custom Painting Approaches for examples of the two common ways to do painting:
Keep a List of the objects to be painted
Paint onto a BufferedImage
The approach you choose will depend on your exact requirement.

Categories

Resources