I had glitching in speech marks because I am farily sure it is not a glitch.
I have just recently started to code using JFrames, in fact I started Java at school couple months ago, but recently I have tried to push my understanding using these handy frames.
I made a program which would bounce a ball around the frame, and I wanted to make it so there would be 2 (for now they would not collide) however whenever I try to add another it simply shows one.
Here is the code:
public static void main(String[] args) throws InterruptedException{
JFrame frame = new JFrame("Hello There");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
frame.setLayout(new FlowLayout());
Main ball = new Main();
Main ball2 = new Main();
ball2.SetValues(200, 200, Color.BLUE);
frame.add(ball2);
frame.add(ball);
while (true) {
ball.move();
ball.repaint();
ball2.move();
ball2.repaint();
Thread.sleep(5);
}
}
public void move() {
x = x + xDirection;
y = y + yDirection;
if (x < 0) { //If Ball has gone off the screen on x direction
xDirection = 1; //Start moving to the right
} else if (x > getWidth() - 50) { //If x has gone off the screen to the right
xDirection = -1;//Start moving to the left
}
if (y < 0) { //If Ball has gone off the screen on x direction
yDirection = 1; //Start moving to the right
} else if (y > getHeight() - 50) { //If x has gone off the screen to the right
yDirection = -1;//Start moving to the left
}
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(color);
g.fillOval(x, y, 50, 50);
}
I recently added the line "frame.setLayout(new FlowLayout()" and it appears to show the 2 balls but they are in a glitched state.
Could anyone help me out?
You should not sleep or do any long process on Swing thread, nor should you update the gui from other threads. See Concurrency in Swing
One alternative is to use javax.swing.Timer :
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ball.move();
ball.repaint();
ball2.move();
ball2.repaint();
}
});
timer.start();
Another alternative is to use a separate thread
It is also recommended to read Performing Custom Painting
Related
i have to do an exercise of java swing.
draw a simple circle/ball (done)
move a circle (done)
from a starting point (half of jpanel(x),0(y)) move this circle/ball that follow an arch direction and bounce when the circle touch the end of screen side (in my case the window it's only x: 0-300 y: 0-300, it's a very little windows)
when the screen end (see picture that i have linked below) continue to bounce in arch movement following the sides of screen until ball return in initial position,no need to be exactly initial position but bounce must is infinite and continuosly(sorry for my english)
https://imgur.com/jNtxeld
what's the function that i need for doing an arch movement? i can't use graphic2d or existent class in java, i need function to apply for x,y for move this ball
i know arch formula from mathematic but i don't know how apply in java in this case, i think i need a function for get all points of a arch position and then i can apply to x and y for move the ball.
help
i have this code
public class Ani2 extends JPanel implements Runnable{
private final int DELAY =105;
public Ani2(){
JFrame jf = new JFrame();
jf.setSize(300,300);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(this);
jf.setVisible(true);
}
private Thread animator;
int x=150, y=150;
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(red);
Graphics2D g2d = (Graphics2D)g;
g2d.fillOval(x,y, 20, 20);
g.dispose();
}
public static void main(String[] args) {
new Ani2();
}
#Override
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (true) {
x += 1;
y -= 1;
repaint();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = DELAY - timeDiff;
if (sleep < 0)
sleep = 2;
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
beforeTime = System.currentTimeMillis();
}
}
}
I'm guessing that "arch function" means physics.
Imagine your ball sitting at rest on a ledge at height h above a surface. The ball has mass m; gravity exerts a force on the ball equal to m*g in the down direction.
The equations of motion for the ball are:
F = m*a
This is a vector equation, because force, acceleration, velocity, and displacement are all vector quantities.
I can use calculus to solve for the distance the ball falls from the height after giving it a push in the positive x-direction (initial x-velocity).
The result will be a quadratic equation.
So I have a program that I'm trying to create for a class, and I need to create a country scene with a farm and a sun. The sun has to bounce up and down. The current problem I'm facing is that the sun keeps going down, and won't bounce up. Here is my code:
import javax.swing.*;
import java.awt.*;
/**
* Date: Oct 14, 2016
* Author:
* Description: Shows a country side with a farm and a sun bouncing up and down.
*/
public class WeAreInThePictures extends JFrame
{
ImageIcon sun, farm, bG; //assigns sun, farm and background to an image variable
static int x = 0, y = -50; //starting position of the sun
static int ySpeed = 10; //speed in y direction
static double delay = 1.0;
public WeAreInThePictures() {
super ("We Are In The Pictures!");
setSize (852, 480);
bG = new ImageIcon ("1.jpg");
sun = new ImageIcon ("sun.png");
farm = new ImageIcon ("farm.png");
setVisible (true);
}
public static void main(String[] args) {
new WeAreInThePictures ();
}
public void paint (Graphics g)
{
for (int i = 0; i < 1000; i++)
{
bG.paintIcon (this, g, 0, 0);
farm.paintIcon (this, g, 500, 50);
y = y + ySpeed;
if (ySpeed > 0)
{
sun.paintIcon (this, g, x, y);
for (int j = 0; j < 550000; j++)
{
delay = Math.pow (delay, 1);
}
}
else if (y > 50)
{
ySpeed = ySpeed - 1;
}
else if (y <= 0)
{
ySpeed = ySpeed - 1;
}
}
}
}
Can someone explain to me what is wrong, how i should fix it and why the problem is occurring?
Your problem is that you appear to have written this code without looking at any Swing Graphics tutorial or similar question on this site regarding Swing animation (why?). You're drawing directly in the JFrame, something that you shouldn't be doing, you've got object mutation code within a paint method, again something that you shouldn't be doing.
Instead do as you recommended in the tutorials, and most any other similar question on this site, in fact, search the problem before asking:
Draw in the paintComponent method of a JPanel that is displayed in a JFrame.
Use a Swing Timer for your animation loop
Change the speed's direction in the timer's ActionListener, not in a paintComponent method.
I am working on a simple game which requires 1 player (the square) and some enemies that spawn randomly inside the play-area. I am running into an issue currently, because when I run my program, pressing any arrow key will repaint not only the player's new location, but it will also re-spawn all the enemies into the new locations.
I have gone through my code a few times and I am still stumped as to why this is happening. Any help would be greatly appreciated.
P.S. I am not a very experienced programmer, so some of this code may not be as efficient as possible and some things may be incorrect; feel free to point out any errors besides the issue at hand. Thanks!
Main Class
public class Eat {
public static void main(String[] args) {
// Creating the main frame
JFrame main = new JFrame("Eat 'Em All - Version 1.0.2");
main.setSize(497, 599);
main.setLocationRelativeTo(null);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setResizable(false);
// Colours and borders
Border areaBorder = new LineBorder(Color.LIGHT_GRAY, 3);
// Creating main JPanel
JPanel area = new JPanel();
area.setLayout(new BoxLayout(area, BoxLayout.PAGE_AXIS));
area.setBackground(Color.WHITE);
main.setContentPane(area);
// Creating the drawing/image/player
DrawPlayer player = new DrawPlayer();
player.setPreferredSize(new Dimension(497, 539));
player.setOpaque(false);
// Enemies
DrawEnemy enemy = new DrawEnemy();
enemy.setPreferredSize(new Dimension(497, 539));
enemy.setBackground(Color.WHITE);
// Creating the control panel for buttons, etc
JPanel control = new JPanel();
control.setPreferredSize(new Dimension(497, 60));
control.setLayout(new GridLayout(1, 2, 0, 0));
control.setBorder(areaBorder);
JLabel welcome = new JLabel(" Welcome to Eat 'Em All |--| Press 'Start'");
JButton start = new JButton("Start");
// Adding it all to the frame
main.add(enemy);
enemy.add(player);
control.add(welcome);
control.add(start);
area.add(control);
// Adding keylistener and making button false
player.addKeyListener(player);
player.setFocusable(true);
start.setFocusable(false);
enemy.setFocusable(false);
// Bring frame to front and visible
main.toFront();
main.setVisible(true);
System.out.println(player.getWidth() / 2);
System.out.println(player.getHeight() / 2);
}
}
Drawing Player Class
public class DrawPlayer extends JPanel implements KeyListener {
long xPosition = 0;
long yPosition = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Making loop to get points and move it
// Center of area is x: 245 y: 255
int xPoints[] = {235, 255, 255, 235, 235, 255};
int yPoints[] = {265, 265, 245, 245, 265, 245};
for (int i = 0; i < xPoints.length; i++) {
xPoints[i] += xPosition;
yPoints[i] += yPosition;
}
g.setColor(Color.BLUE);
g.drawPolygon(xPoints, yPoints, xPoints.length);
}
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_DOWN:
if (yPosition == 245) {
yPosition -= 5;
} else {
yPosition += 5;
}
break;
case KeyEvent.VK_UP:
if (yPosition == -245) {
yPosition += 5;
} else {
yPosition -= 5;
}
break;
case KeyEvent.VK_LEFT:
if (xPosition == -235) {
xPosition += 5;
} else {
xPosition -= 5;
}
break;
case KeyEvent.VK_RIGHT:
if (xPosition == 235) {
xPosition -= 5;
} else {
xPosition += 5;
}
break;
}
repaint();
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
Drawing Enemies Class
public class DrawEnemy extends JPanel {
public void paintComponent(Graphics f) {
super.paintComponent(f);
for (int i = 0; i < 10; i++ ){
f.setColor(Color.RED);
f.drawOval((int)(Math.random() * ((440 - 0) + 0) + 0), (int)(Math.random() * ((500 - 0) + 0) + 0), 50, 50);
}
}
}
Your have a problem here:
public void paintComponent(Graphics f) {
super.paintComponent(f);
for (int i = 0; i < 10; i++ ){
f.setColor(Color.RED);
f.drawOval((int)(Math.random() * ((440 - 0) + 0) + 0), (int)(Math.random() * ((500 - 0) + 0) + 0), 50, 50);
}
}
You've got program logic inside of a painting method, something you should never do, since you never have full control over when or even if a painting method will be called. The solution, get the randomization out of the paintComponent method and into its own separate method, one that you call if and only if you want to randomize the enemies, and not every time you repaint.
Other issues:
Separate your program logic from your GUI.
For instance you should have a non-GUI Enemy class, one that has fields for its own position, its size, its movement, perhaps a move() method, perhaps a collision(Player p) method.
You should have only one JPanel that does drawing and this should be its only job.
Again, you don't tie movement of anything to the painting method.
You would want a game loop of some sort, perhaps a Swing Timer. This will generate regularly spaced ticks that will prod Enemies and Players to move.
Get rid of KeyListener code and favor Key Bindings. The latter is much less kludgy when it comes to component focus. Do check the tutorial for this.
I have recently started using a mac to develop on and i am having a strange problem.
Take the Program below:
public class Driver {
public static void main(String [ ] args) {
SolarSystem SSpanel = new SolarSystem(600, 600);
SSpanel.drawSolarObject(0, 0, 30, "YELLOW");
}
}
the SolarSystem class extends JFrame and basically when the new SolarSystem is created it makes a panel of that size.
the drawSolarObjects basically draws a circle of a certain colour and size. finishedDrawing actually makes the object appear on the panel.
The example above does work but I have more complex requirements which involve putting this into a while loop.
this is where it gets weird, if i run the below program with cmd on a windows computer it works fine and prints the yellow circle to the screen. On my mac, adding this while loop causes it to just create the panel but not paint the yellow circle.
public class Driver{
public static void main(String [ ] args) {
boolean oMove = true;
SolarSystem SSpanel = new SolarSystem(600, 600);
while(oMove){
SSpanel.drawSolarObject(0, 0, 30, "YELLOW");
SSpanel.finishedDrawing();
}
}
}
I put a print into my loop to check it was running through it and that showed that it was definitely running through the loop.
Does anyone know what could be causing this?
Ive am adding the functions so you can get a better picture
SolarSystem Constructer:
public SolarSystem(int width, int height)
{
this.width = width;
this.height = height;
this.setTitle("The Solar System");
this.setSize(width, height);
this.setBackground(Color.BLACK);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
drawSolarObject Function:
public void drawSolarObject(double distance, double angle, double diameter, String col)
{
Color colour = this.getColourFromString(col);
double centreOfRotationX = ((double) width) / 2.0;
double centreOfRotationY = ((double) height) / 2.0;
double rads = Math.toRadians(angle);
double x = (int) (centreOfRotationX + distance * Math.sin(rads)) - diameter / 2;
double y = (int) (centreOfRotationY + distance * Math.cos(rads)) - diameter / 2;
synchronized (this)
{
if (things.size() > 1000)
{
System.out.println("\n\n");
System.out.println(" ********************************************************* ");
System.out.println(" ***** Only 1000 Entities Supported per Solar System ***** ");
System.out.println(" ********************************************************* ");
System.out.println("\n\n");
this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
}
else
{
SolarObject t = new SolarObject((int)x, (int)y, (int)diameter, colour);
things.add(t);
}
}
}
finishedDrawing function:
public void finishedDrawing()
{
try
{
this.repaint();
Thread.sleep(30);
}
catch (Exception e) { }
synchronized (this)
{
things.clear();
}
}
This all works fine on a windows PC
Your code risks tying up the Swing event thread preventing it from drawing on your GUI, and effectively freezing your program. Instead use a Swing Timer, not a while loop to achieve your goal.
e.g.,
final SolarSystem SSpanel = new SolarSystem(600, 600);
int timerDelay = 100;
new Timer(timerDelay, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do repeated action in here
}
}).start();
As an aside, I was going to place,
SSpanel.drawSolarObject(0, 0, 30, "YELLOW");
SSpanel.finishedDrawing();
inside my timer code, but it wouldn't make sense because this code isn't "dynamic" and doesn't change anything or do any animation.
Im almost finished with this car project im working on but cant seem to get the key events to work. I think it has to do with my action listener with my timer but im not sure. When I press the up arrow key the timer delay is supposed to decrease and vice versa for the down arrow key. I have the commands written but they are not registering input. If anyone could give me some pointers I'd appreciate it
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class RaceCar extends JFrame{
public RaceCar(){
add(new CarPic());
}
public static void main(String[] args){
JFrame frame = new RaceCar();
frame.setTitle("Brady Kedge: Race Car");
frame.setSize(300, 150);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public class CarPic extends JPanel implements KeyListener
{
private int x = 0;
private int y = 150;
private int z = 300;
Timer mytimer = new Timer(50, new ActionListener());
public CarPic()
{
mytimer.start();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
y = getHeight();
z = getWidth();
g.setColor(Color.WHITE);
g.fillRect(0, 0, z, y);
Polygon polygon = new Polygon();
polygon.addPoint(x + 10, y - 20);
polygon.addPoint(x + 20, y - 30);
polygon.addPoint(x + 30, y - 30);
polygon.addPoint(x + 40, y - 20);
if(x < z - 40)
{
g.setColor(Color.BLACK);
g.fillOval(x + 10, y - 10, 10, 10);
g.fillOval(x + 30, y - 10, 10, 10);
g.setColor(Color.BLUE);
g.fillRect(x, y - 20, 50, 10);
g.setColor(Color.BLUE);
g.fillPolygon(polygon);
}
else
x = 0;
}
public void actionPerformed(ActionEvent e){
x+=10;
repaint();
}
#Override
public void keyTyped(KeyEvent k) {
//Fill
}
#Override
public void keyPressed(KeyEvent k) {
int delay = mytimer.getDelay();
if(k.getKeyCode() == KeyEvent.VK_UP)
mytimer.setDelay(delay > 10 ? delay - 10 : 0);
else if(k.getKeyCode() == KeyEvent.VK_DOWN)
mytimer.setDelay(delay < 5000 ? delay + 10 : 5000);
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
}
First of all, you never register a KeyListener with your component (implementing KeyListener isn't enough).
Second of all, KeyListener will only raise KeyEvents if the component it is registered to has focus and is focusable.
A better solution would be to use the key bindings API, which provides you with the means to configure the focus level at which a component will trigger key events.
Also, personally, instead of modifying the Timer delay, I would have use a speed modifier (of type double) which would be percentage of the speed you want. In this way 1 would normal speed, 0.5 half speed and 2 double speed, for example.