I am trying to make a Mandelbrot program that allows zooming, but the zoom doesn't seem to be working, and i don't see what is wrong with the way i have implemented the zoom.I am using eclipse and the program doesn't return any errors. Here is my code:
import java.awt.Graphics;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
public class Mandelbrot extends JFrame {
private final int MAX_ITER = 570;
private static double ZOOM = 200;
private BufferedImage I;
private double zx, zy, cX, cY, tmp;
public static boolean zooming = false;
public Mandelbrot()
{
super("MandelbrotSet");
setBounds(100, 100, 800, 600);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
I = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
zx = zy = 0;
cX = (x - 400) / ZOOM;
cY = (y - 300) / ZOOM;
int iter = MAX_ITER;
while (zx * zx + zy * zy < 4 && iter > 0) {
tmp = zx * zx - zy * zy + cX;
zy = 2.0 * zx * zy + cY;
zx = tmp;
iter--;
}
I.setRGB(x, y, iter | (iter << 8));
}
}
setVisible(true);
while(1>0)
{
if(zooming)
{
revalidate();
repaint();
System.out.println("zooming");
zooming = false;
}
} }
#Override
public void paint(Graphics g) {
g.drawImage(I, 0, 0, this);
}
public static void main(String[] args) {
new Mandelbrot().addMouseWheelListener(new MouseWheelListener(){ public void mouseWheelMoved(MouseWheelEvent
e) {
if (e.getWheelRotation() < 0) {
ZOOM=ZOOM+100;
zooming = true;
} else
{
ZOOM=ZOOM-100;
zooming = true;
} } });
} }
Your constructor contains an endless loop. It therefore never returns and your MouseWheelListener is never added to the frame.
You calculate the BufferedImage exactly once (before the endless loop), so even if you would attach the MouseWheelListener before the loop it would have no effect.
I would move the calculation of the picture into its own method, call this method once from the constructor and once from your MouseWheelListener and remove the endless loop from the constructor.
public Mandelbrot()
{
super("MandelbrotSet");
//...
I = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
calculatePicture();
setVisible(true);
}
public void calculatePicture() {
for (int y = 0; y < getHeight(); y++) {
//...
}
repaint();
}
public static void main(String[] args) {
new Mandelbrot().addMouseWheelListener(new MouseWheelListener(){
public void mouseWheelMoved(MouseWheelEvent
e) {
//...
calculatePicture();
}
});
}
Related
I have been working on a flappy bird clone so I can get more practice programming. Everything in the game works, however the game has frame skips and lag drops, and I do not know how to make Java programs run more smoothly. Am I supposed to measure the amount of time a method takes and try to shorten that, or do I do something else? I have seen people explain how to program Java games, but there is hardly anything on improving the performance. Any advice would be helpful. Thank you.
Hazards class
package entity;
import java.util.ArrayList;
public class Hazards {
public ArrayList<Horizontal> hors;
public ArrayList<Vertical> verts;
public Hazards(int width, int height, int thickness) {
hors = new ArrayList<Horizontal>();
hors.add(new Horizontal(0, 0, width, thickness));
hors.add(new Horizontal(0, height-thickness, width, thickness));
verts = new ArrayList<Vertical>();
}
}
Horizontal class
package entity;
import java.awt.Rectangle;
public class Horizontal {
public int xPos, yPos, width, height;
public Rectangle bounds;
public Horizontal(int x, int y, int w, int h) {
this.xPos = x;
this.yPos = y;
this.width = w;
this.height = h;
this.bounds = new Rectangle(x, y, w, h);
}
public void updateBounds(int x, int y, int w, int h) {
this.xPos = x;
this.yPos = y;
this.width = w;
this.height = h;
this.bounds = new Rectangle(x, y, w, h);
}
}
Vertical class
package entity;
import java.awt.Rectangle;
import java.util.Random;
public class Vertical {
public int xPos, width, gapSize, gapPos;
public boolean scoredOn = false;
public Rectangle top, bottom;
public Vertical(int xPos, int width, int roofHeight, int floorHeight, int gapSize) {
this.xPos = xPos;
this.width = width;
this.gapPos = new Random().nextInt(floorHeight - gapSize) + roofHeight;
this.top = new Rectangle();
this.bottom = new Rectangle();
this.top.setBounds(xPos, 0, width, gapPos);
this.bottom.setBounds(xPos, gapPos + gapSize, width, floorHeight - roofHeight + top.height + gapSize);
}
}
Content class
package main;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JPanel;
public class Content extends JPanel {
private static final long serialVersionUID = 1L;
private Engine e;
private Rectangle bounds;
public Content(Engine engine) {
e = engine;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.clearRect(0, 0, this.getWidth(), this.getHeight());
// Roof and floor
g.setColor(Color.black);
for (int x = 0; x < e.e.hors.size(); x++) {
bounds = e.e.hors.get(x).bounds;
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
// Pipes
g.setColor(Color.black);
for(int x = 0; x < e.e.verts.size(); x++) {
bounds = e.e.verts.get(x).top;
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
bounds = e.e.verts.get(x).bottom;
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
// Player
g.setColor(Color.black);
g.fillRect((int) e.p.xPos, (int) e.p.yPos, e.p.size, e.p.size);
// Score
g.setColor(Color.blue);
g.setFont(new Font("Monospaced", Font.PLAIN, 40));
g.drawString(Integer.toString(e.p.score), e.width/2, 80);
}
}
Engine class
package main;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import entity.Hazards;
import entity.Vertical;
import screen.TitleScreen;
public class Engine implements Runnable {
public JFrame f;
public String title = "Flappy Bird";
public int width = 500, height = 500;
public Content c;
public boolean running = false;
public boolean playing = false;
public Thread t;
public Player p;
public Hazards e;
public TitleScreen ts;
public JPanel mainPanel;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Engine e = new Engine();
e.execute();
}
});
}
public void execute() {
ts = new TitleScreen(width, height);
e = new Hazards(width, height, 30);
p = new Player(this);
c = new Content(this);
c.setPreferredSize(new Dimension(width, height));
c.setLayout(null);
c.addKeyListener(p);
mainPanel = new JPanel();
mainPanel.setPreferredSize(new Dimension(width, height));
mainPanel.setLayout(null);
f = new JFrame();
f.setTitle(title);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
f.add(c);
// f.add(mainPanel);
f.pack();
f.createBufferStrategy(2);
f.setLayout(null);
f.setLocationRelativeTo(null);
f.setVisible(true);
c.requestFocus();
//ts.setScreen(mainPanel);
start();
}
public synchronized void start() {
if (running)
return;
running = true;
t = new Thread(this);
t.start();
}
public synchronized void stop() {
if (!running)
return;
running = false;
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
long lastime = System.nanoTime();
double AmountOfTicks = 60;
double ns = 1000000000 / AmountOfTicks;
double delta = 0;
int tick = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastime) / ns;
lastime = now;
if (delta >= 1) {
// Call all updates here
if (playing) {
p.updatePos();
tick++;
if (tick == 60) {
tick = 0;
p.distance += p.speed;
System.out.println(p.distance);
if ((p.distance % 4) == 0) {
System.out.println("Making new pipes-----------------------------------------------------");
e.verts.add(new Vertical(600, 10, 30, height - 30, 100));
}
}
for (int x = 0; x < e.verts.size(); x++) {
e.verts.get(x).top.x -= p.speed;
e.verts.get(x).bottom.x -= p.speed;
if(e.verts.get(x).top.x<-50) {
e.verts.remove(x);
System.out.println("removed a pipe");
}
if(p.xPos>e.verts.get(x).top.x && !e.verts.get(x).scoredOn) {
e.verts.get(x).scoredOn = true;
p.score++;
}
}
}
mainPanel.revalidate();
mainPanel.repaint();
f.revalidate();
f.repaint();
delta--;
}
}
}
}
Player class
package main;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Player implements KeyListener {
public int size = 10;
public double xPos = 50;
public double yPos = 240;
public double gravity = 3.4;
public double jumpForce = 16.6;
public double weight = 1;
public int speed = 2;
public int score = 0;
public int distance = 0;
public boolean jumping = false;
public double jumpTime = 10;
public int timed = 0;
public Rectangle bounds, temp, top, bottom;
public Engine en;
public Player(Engine engine) {
en = engine;
bounds = new Rectangle((int)xPos, (int)yPos, size, size);
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W && en.playing) {
jumping = true;
} else if (e.getKeyCode() == KeyEvent.VK_SPACE) {
en.playing = !en.playing;
}
if(jumping) {
timed = 0;
jumpForce = 16.6;
}
}
public void keyReleased(KeyEvent e) {
}
public void updatePos() {
// collide with floor or ceiling
for(int x = 0; x < en.e.hors.size(); x++) {
temp = en.e.hors.get(x).bounds;
if(bounds.intersects(temp)) {
en.playing = false;
jumping = false;
timed = 0;
jumpForce = 0;
yPos = 240;
score = 0;
en.e.verts.clear();
distance = 0;
gravity = 3.8;
}
}
// collide with pipe
for(int x =0; x <en.e.verts.size();x++) {
top = en.e.verts.get(x).top;
bottom = en.e.verts.get(x).bottom;
if(bounds.intersects(top)||bounds.intersects(bottom)) {
en.playing = false;
jumping = false;
timed = 0;
jumpForce = 0;
yPos = 240;
score = 0;
gravity =3.4;
en.e.verts.clear();
distance = 0;
}
}
if (jumping && en.playing) {
gravity = 3.4;
yPos -= jumpForce;
jumpForce -= weight;
if (jumpForce == 0) {
jumping = false;
jumpForce = 16.6;
}
}
//if(!jumping && en.playing) {
gravity += 0.1;
//}
System.out.println(gravity);
yPos += gravity;
bounds.setBounds((int)xPos, (int)yPos, size, size);
}
}
I am trying to adapt a program I have created for bouncing a ball in Java. I am very new so apologies if the solution is obvious. I have used the following code to create an array of bouncing balls, and then subsequently create two threads with the balls bouncing.
I am trying to achieve this without the array. So, that each thread has only 1 ball.
I feel like the answer is staring me in the face but I just cannot solve the issue. Any help would be greatly appreciated.
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class AClass implements Runnable {
private JFrame mainFrame;
private DrawPanel drawPanel;
// private java.util.List<Ball> balls;
private int windowWidth = 640;
private int windowHeight = 480;
private String windowLabel = "Multi-threaded ball application";
public void run() {
//balls = new ArrayList<>();
//Scanner sc = new Scanner(System.in);
//System.out.print("Enter the number of balls you would like to create:");
//int n = sc.nextInt();
//sc.close();
/* Generate balls */
//for (int i = 0; i < n; i++) {
Ball ball = new Ball(
/* Random positions from 0 to windowWidth or windowHeight */
(int) Math.floor(Math.random() * windowWidth),
(int) Math.floor(Math.random() * windowHeight),
/* Random size from 10 to 30 */
(int) Math.floor(Math.random() * 20) + 10,
/* Random RGB colors*/
new Color(
(int) Math.floor((Math.random() * 256)),
(int) Math.floor((Math.random() * 256)),
(int) Math.floor((Math.random() * 256))
),
/* Random velocities from -5 to 5 */
(int) Math.floor((Math.random() * 10) - 5),
(int) Math.floor((Math.random() * 10) - 5)
);
// balls.add(ball);
// }
/* Initialize program */
mainFrame = new JFrame();
drawPanel = new DrawPanel();
mainFrame.getContentPane().add(drawPanel);
mainFrame.setTitle(windowLabel);
mainFrame.setSize(windowWidth, windowHeight);
mainFrame.setVisible(true);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
//for (Ball b: balls) {
ball.update();
// }
/* Give Swing 10 milliseconds to see the update! */
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
mainFrame.repaint();
}
}
public class DrawPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
// for (Ball b: balls) {
ball.draw(graphics);
// }
}
}
class Ball {//ball class
private int posX, posY, size;
private Color color;
private int vx = 5;
private int vy = 5;
public Ball(int posX, int posY, int size, Color color, int vx, int vy) {
this.posX = posX;
this.posY = posY;
this.size = size;
this.color = color;
this.vx = vx;
this.vy = vy;
}
void update() {
if (posX > mainFrame.getWidth() || posX < 0) {
vx *= -1;
}
if (posY > mainFrame.getHeight() || posY < 0) {
vy *= -1;
}
if (posX > mainFrame.getWidth()) {
posX = mainFrame.getWidth();
}
if (posX < 0) {
posX = 0;
}
if (posY > mainFrame.getHeight()) {
posY = mainFrame.getHeight();
}
if (posY < 0) {
posY = 0;
}
this.posX += vx;
this.posY += vy;
}
void draw(Graphics g) {
g.setColor(color);
g.fillOval(posX, posY, size, size);
}
}
public static void main(String[] args) {
AClass ex = new AClass();
Thread t1= new Thread(ex);
Thread t2 = new Thread(ex);
t1.start();
t2.start();
//System.out.println("Hi");
}
}
First, Swing is not thread safe. You should not be updating the UI (or any state the UI relies on) from outside the context of the Event Dispatching Thread.
See Concurrency in Swing for more details.
I don't think your intention is the correct approach (trying to have each ball be it's own Thread), you're going to quickly end up with all sorts of issues trying to do collision detection, as the state of each ball is always changing independent of each other and it won't scale well. The array and a Swing Timer would be a more suitable solution.
This is the probably the closes I can get to what you want, the problem is, in order to paint it, you'd need a reference to the Ball, so I extended Ball from JPanel instead.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new SurfacePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Surface {
public Dimension getSize();
public void repaint();
}
public class SurfacePane extends JPanel implements Surface {
public SurfacePane() {
setLayout(null);
for (int index = 0; index < 10; index++) {
Ball ball = new Ball(
/* Random positions from 0 to windowWidth or windowHeight */
(int) Math.floor(Math.random() * 400),
(int) Math.floor(Math.random() * 400),
/* Random size from 10 to 30 */
(int) Math.floor(Math.random() * 20) + 10,
/* Random RGB colors*/
new Color(
(int) Math.floor((Math.random() * 256)),
(int) Math.floor((Math.random() * 256)),
(int) Math.floor((Math.random() * 256))
),
/* Random velocities from -5 to 5 */
(int) Math.floor((Math.random() * 10) - 5),
(int) Math.floor((Math.random() * 10) - 5),
this
);
add(ball);
ball.start();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
public class Ball extends JPanel {
private int posX, posY, size;
private Color color;
private int vx = 5;
private int vy = 5;
private Surface surface;
private Timer timer;
public Ball(int posX, int posY, int size, Color color, int vx, int vy, Surface surface) {
this.posX = posX;
this.posY = posY;
this.size = size;
this.color = color;
this.vx = vx;
this.vy = vy;
this.surface = surface;
setBackground(color);
setSize(size, size);
setOpaque(false);
}
public void start() {
if (timer != null) {
timer.stop();
}
timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
surface.repaint();
}
});
timer.start();
}
public void stop() {
if (timer == null) {
return;
}
timer.stop();
}
protected void update() {
int width = surface.getSize().width;
int height = surface.getSize().height;
if (posX > width || posX < 0) {
vx *= -1;
}
if (posY > height || posY < 0) {
vy *= -1;
}
if (posX > width) {
posX = width;
}
if (posX < 0) {
posX = 0;
}
if (posY > height) {
posY = height;
}
if (posY < 0) {
posY = 0;
}
this.posX += vx;
this.posY += vy;
setLocation(posX, posY);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
g.setColor(color);
g.fillOval(0, 0, size, size);
}
}
}
The problem with this approach (and even the Threaded approach) is, it's not going to scale well. For example, during my experimentation, I only got to about 5, 000 balls before I started have responsiveness issues (resizing the window lagged, alot), compared to roughly 20, 000 balls using an ArrayList (and a single Timer) - I'll be honest, the frame rate was terrible, but the UI remained relatively responsive - I could resize the window without lag
Single Timer, array based example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
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 Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new SurfacePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Surface {
public Dimension getSize();
public void repaint();
}
public class SurfacePane extends JPanel implements Surface {
private List<Ball> balls = new ArrayList<>(32);
public SurfacePane() {
for (int index = 0; index < 20_000; index++) {
Ball ball = new Ball(
/* Random positions from 0 to windowWidth or windowHeight */
(int) Math.floor(Math.random() * 400),
(int) Math.floor(Math.random() * 400),
/* Random size from 10 to 30 */
(int) Math.floor(Math.random() * 20) + 10,
/* Random RGB colors*/
new Color(
(int) Math.floor((Math.random() * 256)),
(int) Math.floor((Math.random() * 256)),
(int) Math.floor((Math.random() * 256))
),
/* Random velocities from -5 to 5 */
(int) Math.floor((Math.random() * 10) - 5),
(int) Math.floor((Math.random() * 10) - 5),
this
);
balls.add(ball);
}
Timer timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Ball ball : balls) {
ball.update();
}
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Ball ball : balls) {
ball.paint(g2d);
}
g2d.dispose();
}
}
public class Ball {
private int posX, posY, size;
private Color color;
private int vx = 5;
private int vy = 5;
private Surface surface;
private Timer timer;
public Ball(int posX, int posY, int size, Color color, int vx, int vy, Surface surface) {
this.posX = posX;
this.posY = posY;
this.size = size;
this.color = color;
this.vx = vx;
this.vy = vy;
this.surface = surface;
}
protected void update() {
int width = surface.getSize().width;
int height = surface.getSize().height;
if (posX > width || posX < 0) {
vx *= -1;
}
if (posY > height || posY < 0) {
vy *= -1;
}
if (posX > width) {
posX = width;
}
if (posX < 0) {
posX = 0;
}
if (posY > height) {
posY = height;
}
if (posY < 0) {
posY = 0;
}
this.posX += vx;
this.posY += vy;
}
public void paint(Graphics2D g2d) {
g2d.setColor(color);
g2d.fillOval(posX, posY, size, size);
}
}
}
I am trying to learn Java, coming from a C/assembly embedded systems background. After a few weeks of learning, I thought it would be fun to try and make a game, but I am having some problems with a JPanel being repainted at an inconsistent rate.
My "game" GUI consists of a single JFrame which contains a JPanel. As you can see, the main thread for the JFrame sleeps for 30 milliseconds and then updates "game" logic and redraws the JFrame and JPanel. Each time the JPanel is redrawn, I check that it took about 30 milliseconds. As you would expect, it never takes more than about 32 milliseconds between frame redraws.
In spite of the fact that the JPanel is definitely repainted every 30 milliseconds or so, The animation in it can be very jerky. On Ubuntu 14.10, it is extremely obvious, even though the time between calls to my JPanel's repaint() are still never more than 32ms apart.
The most vexing thing is that if I uncomment the lines
//this.resize(300 + a, 300);
//a = (a == 1)?(0):1;
in SimFrame.java, everything is perfectly smooth, which implies that my computer has the capability to update the JPanel at the rate I want.
Is there some way I can force the JFrame to update at the rate I want it to without doing the absurd .resize call?
Main.java
package jdemo;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Main
{
public static void main(String[] args)
{
SimFrame s = new SimFrame();
Thread t = new Thread(s);
t.start();
}
}
Sim.java
package jdemo;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.Timer;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class Sim extends JPanel implements KeyListener
{
/**
*
*/
private static final long serialVersionUID = 1L;
private int keys[] = new int[1024];
double x = 100;
double y = 100;
double dx = 0;
double dy = 0;
double theta = 0.0;
private int size = 0;
private int dsize = 1;
public Sim()
{
this.addKeyListener(this);
this.setFocusable(true);
}
long prevmillis;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D drawing = (Graphics2D)g;
//clear the background.
drawing.setColor(Color.WHITE);
drawing.fillRect(0, 0, this.getWidth() - 1, this.getHeight() - 1);
//System.out.printf("dt = %d\n", System.currentTimeMillis() - prevmillis);
prevmillis = System.currentTimeMillis();
drawing.setColor(Color.BLACK);
drawing.drawRect(0, 0, size, size);
drawing.setColor(Color.BLACK);
int[] xpoints = {(int)(x + 10 * Math.cos(Math.toRadians(theta))),
(int)(x + 5 * Math.cos(Math.toRadians(theta - 150))),
(int)(x + 5 * Math.cos(Math.toRadians(theta + 150)))};
int[] ypoints = {(int)(y + 10 * Math.sin(Math.toRadians(theta))),
(int)(y + 5 * Math.sin(Math.toRadians(theta - 150))),
(int)(y + 5 * Math.sin(Math.toRadians(theta + 150)))};
drawing.drawPolygon(xpoints, ypoints, 3);
}
public void updateLogic()
{
if(keys[KeyEvent.VK_UP] == 1)
{
size++;
}
else if(keys[KeyEvent.VK_DOWN] == 1)
{
size--;
}
//update theta.
if(keys[KeyEvent.VK_LEFT] == 1)
{
theta += 5;
}
if(keys[KeyEvent.VK_RIGHT] == 1)
{
theta -= 5;
}
if(theta > 360.1)
{
theta -= 360;
}
if(theta < -0.1)
{
theta += 360;
}
//update acceleration
if(keys[KeyEvent.VK_SPACE] == 1)
{
dx += 0.08* Math.cos(Math.toRadians(theta));
dy += 0.08 * Math.sin(Math.toRadians(theta));
}
dx *= 0.99;
dy *= 0.99;
//update position
x = x + dx;
y = y + dy;
System.out.printf("%f, %f\n", dx, dy);
//update size
if(size > 150)
{
dsize = -1;
}
if(size < 10)
{
dsize = 1;
}
size += dsize;
}
#Override
public void keyPressed(KeyEvent arg0)
{
// TODO Auto-generated method stub
keys[arg0.getKeyCode()] = 1;
System.out.printf("%d\n", arg0.getKeyCode());
}
#Override
public void keyReleased(KeyEvent arg0)
{
// TODO Auto-generated method stub
keys[arg0.getKeyCode()] = 0;
}
#Override
public void keyTyped(KeyEvent arg0)
{
// TODO Auto-generated method stub
}
}
SimFrame.java
package jdemo;
import jdemo.Sim;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class SimFrame extends JFrame implements Runnable
{
private Sim s;
public SimFrame()
{
this.s = new Sim();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(this.s);
this.pack();
this.setLocationRelativeTo(null);
this.setSize(200, 200);
}
#Override
public void run()
{
int a = 0;
this.setVisible(true);
while(true)
{
//repaint
s.updateLogic();
this.getContentPane().revalidate();
this.repaint();
//this.resize(300 + a, 300);
//a = (a == 1)?(0):1;
try
{
Thread.sleep(30);
}
catch(InterruptedException e)
{
System.out.printf("failed");
break;
}
}
}
}
Thank you very much.
Try this and if it works I'll transform it into a true answer (I just can't know if it will work on your system better than your current code):
public class SimFrame extends JFrame {
public SimFrame() {
setContentPane(new Sim());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private class Sim extends JPanel {
double x = 100;
double y = 100;
double dx = 0;
double dy = 0;
double theta = 0.0;
private int size = 0;
private int dsize = 1;
public Sim() {
addKeyListener(new Controller());
setFocusable(true);
setBackground(Color.WHITE);
new Timer(30, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dx *= 0.99;
dy *= 0.99;
// update position
x = x + dx;
y = y + dy;
// update size
if (size > 150)
dsize = -1;
if (size < 10)
dsize = 1;
size += dsize;
// update theta.
if (theta > 360.1) {
theta -= 360;
}
if (theta < -0.1) {
theta += 360;
}
repaint();
}
}).start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
};
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D drawing = (Graphics2D) g;
drawing.setColor(Color.BLACK);
drawing.drawRect(0, 0, size, size);
drawing.setColor(Color.BLACK);
int[] xpoints = {(int) (x + 10 * Math.cos(Math.toRadians(theta))), (int) (x + 5 * Math.cos(Math.toRadians(theta - 150))),
(int) (x + 5 * Math.cos(Math.toRadians(theta + 150)))};
int[] ypoints = {(int) (y + 10 * Math.sin(Math.toRadians(theta))), (int) (y + 5 * Math.sin(Math.toRadians(theta - 150))),
(int) (y + 5 * Math.sin(Math.toRadians(theta + 150)))};
drawing.drawPolygon(xpoints, ypoints, 3);
}
private class Controller extends KeyAdapter {
#Override
public void keyPressed(KeyEvent evt) {
switch (evt.getKeyCode()) {
case KeyEvent.VK_UP:
size++;
break;
case KeyEvent.VK_DOWN:
size--;
break;
case KeyEvent.VK_LEFT:
theta += 5;
break;
case KeyEvent.VK_RIGHT:
theta -= 5;
break;
case KeyEvent.VK_SPACE:
dx += 0.08 * Math.cos(Math.toRadians(theta));
dy += 0.08 * Math.sin(Math.toRadians(theta));
break;
}
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new SimFrame();
}
});
}
}
And yes, I know there's the OS's delay on holding a key, we'll get to it if it works.
Edit:
Simpler animation:
public class CopyOfSimFrame extends JFrame {
public CopyOfSimFrame() {
setContentPane(new Sim());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private class Sim extends JPanel {
private int size = 0;
private int dsize = 1;
public Sim() {
setBackground(Color.WHITE);
new Timer(30, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// update size
if (size >= 150)
dsize = -1;
if (size <= 0)
dsize = 1;
size += dsize;
repaint();
}
}).start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(150, 150);
};
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawRect(0, 0, size, size);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new CopyOfSimFrame();
}
});
}
}
Right now, I am trying to make a Hex Grid GUI that highlights whatever hex that the mouse is hovering over. However, the JPanel which is supposed to display the hexagons are not showing up.
I seriously have no idea what is happening between repaint() and paintComponents() in this case. I tried to look up solutions, which involve setting the JPanel into a visible hierachy, which I made sure I did, and it still is not working.
Code is slightly long
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
public class HexGridTester implements ActionListener, MouseListener, MouseMotionListener
{
private JFrame frame;
private TestPanel panel;
private double radius;
private double width;
private double side;
private double height;
private Location mouseover;
private class TestPanel extends JPanel
{
#Override
public void paintComponents(Graphics g)
{
System.out.println("CALLED");
super.paintComponents(g);
int[] xpoints = new int[6];
int[] ypoints = new int[6];
for(int c = 0; c < 15; c++)
{
for(int r = 0; r < 21; r++)
{
int dx = c * (int) width;
int dy = r * (int) height;
if(new Location(c, r).equals(mouseover))
{
g.setColor(Color.blue);
}
else
{
g.setColor(Color.black);
}
if(c % 2 != 0)
{
dy += height / 2;
}
for(int i = 0; i < 6; i++)
{
xpoints[i] = (int) ((int) 10 * Math.cos(i * 2 * Math.PI / 6) + dx);
ypoints[i] = (int) ((int) 10 * Math.sin(i * 2 * Math.PI / 6) + dy);
}
Polygon hex = new Polygon (xpoints, ypoints, 6);
g.fillPolygon(hex);
System.out.print("Drawing " + r + "," + c);
}
}
}
}
public HexGridTester(int r)
{
radius = r;
side = radius * 3/2;
width = radius * 2;
height = Math.sqrt(3) * radius;
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(0, 1));
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
panel = new TestPanel();
panel.setLayout(new GridLayout(0,1));
panel.addMouseListener(this);
panel.addMouseMotionListener(this);
frame.add(panel);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
panel.repaint();
}
#Override
public void actionPerformed(ActionEvent ae)
{
}
#Override
public void mouseClicked(MouseEvent me)
{
}
#Override
public void mousePressed(MouseEvent me)
{
}
#Override
public void mouseReleased(MouseEvent me)
{
}
#Override
public void mouseEntered(MouseEvent me)
{
}
#Override
public void mouseExited(MouseEvent me)
{
}
#Override
public void mouseDragged(MouseEvent me)
{
}
#Override
public void mouseMoved(MouseEvent me)
{
//System.out.println(me.getPoint().x + " " + me.getPoint().y + " " + mouseover);
mouseover = convert(me.getPoint().x, me.getPoint().y);
panel.repaint();
}
private Location convert(double x, double y)
{
double xt;
double yt;
double r;
double c;
double rt;
double ct;
double dr;
ct = x / side;
if(ct % 2 == 0)
{
rt = y / height;
}
else
{
rt = (y - ( height) / 2) / (height);
}
xt = x - ct * side;
yt = y - rt * height;
if(yt > (height /2))
{
dr = 1;
}
else
{
dr = 0;
}
if(xt > (radius * Math.abs(.5 - yt/height)))
{
c = ct;
r = rt;
}
else
{
c = ct - 1;
r = rt - c%2 + dr;
}
return new Location((int) c, (int) r);
}
private static void runTestWindow()
{
HexGridTester tester = new HexGridTester(25);
}
public static void main(String[] args)
{
Runnable run = new Runnable()
{
#Override
public void run()
{
runTestWindow();
}
};
javax.swing.SwingUtilities.invokeLater(run);
}
}
#Override
public void paintComponents(Graphics g)
{
System.out.println("CALLED");
super.paintComponents(g);
Should be:
#Override
public void paintComponent(Graphics g)
{
System.out.println("CALLED");
super.paintComponent(g);
Respect the paint chain. Don't override any method but paintComponent(Graphics) for any JComponent.
This is my class which I found on the Internet. It was originally an applet but I don't want to use it as an applet so I changed some methods (such as init() to a constructor).
However, it doesn't work. Would you please help me?
SignInFrame Frame:
public class SignInFrame extends javax.swing.JFrame {
Panel panel;
/** Creates new form SignInFrame */
public SignInFrame() {
initComponents();
}
public void init() {
getContentPane().add(panel = new Panel());
}
public void start() {
panel.start();
}
public void stop() {
panel.stop();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new SignInFrame().setVisible(true);
}
});
}}
Panel Dialog:
package ClientGUI;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
/**
*
* #author ICC
*/
public class Panel extends javax.swing.JPanel implements Runnable{
private Thread thread;
private BufferedImage bimg;
private static final int NUMPTS = 6;
// solid line stoke
protected BasicStroke solid = new BasicStroke(10.0f,
BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
// dashed line stroke
protected BasicStroke dashed = new BasicStroke(10.0f,
BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10, new float[] {5}, 0);
private float animpts[] = new float[NUMPTS * 2];
private float deltas[] = new float[NUMPTS * 2];
protected Paint fillPaint, drawPaint;
// indicates whether or not to fill shape
protected boolean doFill = true;
// indicates whether or not to draw shape
protected boolean doDraw = true;
protected GradientPaint gradient;
protected BasicStroke stroke;
public Panel() {
setBackground(Color.white);
gradient = new GradientPaint(0,0,Color.red,200,200,Color.yellow);
fillPaint = gradient;
drawPaint = Color.blue;
stroke = solid;
}
// generates new points for the path
public void animate(float[] pts, float[] deltas, int i, int limit) {
float newpt = pts[i] + deltas[i];
if (newpt <= 0) {
newpt = -newpt;
deltas[i] = (float) (Math.random() * 4.0 + 2.0);
} else if (newpt >= (float) limit) {
newpt = 2.0f * limit - newpt;
deltas[i] = - (float) (Math.random() * 4.0 + 2.0);
}
pts[i] = newpt;
}
/*
* generates random points with the specified surface width
* and height for the path
*/
public void reset(int w, int h) {
for (int i = 0; i < animpts.length; i += 2) {
animpts[i + 0] = (float) (Math.random() * w);
animpts[i + 1] = (float) (Math.random() * h);
deltas[i + 0] = (float) (Math.random() * 6.0 + 4.0);
deltas[i + 1] = (float) (Math.random() * 6.0 + 4.0);
if (animpts[i + 0] > w / 2.0f) {
deltas[i + 0] = -deltas[i + 0];
}
if (animpts[i + 1] > h / 2.0f) {
deltas[i + 1] = -deltas[i + 1];
}
}
gradient = new GradientPaint(0,0,Color.red,w*.7f,h*.7f,Color.yellow);
}
// calls animate for every point in animpts
public void step(int w, int h) {
for (int i = 0; i < animpts.length; i += 2) {
animate(animpts, deltas, i + 0, w);
animate(animpts, deltas, i + 1, h);
}
}
// sets the points of the path and draws and fills the path
public void drawDemo(int w, int h, Graphics2D g2) {
float[] ctrlpts = animpts;
int len = ctrlpts.length;
float prevx = ctrlpts[len - 2];
float prevy = ctrlpts[len - 1];
float curx = ctrlpts[0];
float cury = ctrlpts[1];
float midx = (curx + prevx) / 2.0f;
float midy = (cury + prevy) / 2.0f;
GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO);
gp.moveTo(midx, midy);
for (int i = 2; i <= ctrlpts.length; i += 2) {
float x1 = (midx + curx) / 2.0f;
float y1 = (midy + cury) / 2.0f;
prevx = curx;
prevy = cury;
if (i < ctrlpts.length) {
curx = ctrlpts[i + 0];
cury = ctrlpts[i + 1];
} else {
curx = ctrlpts[0];
cury = ctrlpts[1];
}
midx = (curx + prevx) / 2.0f;
midy = (cury + prevy) / 2.0f;
float x2 = (prevx + midx) / 2.0f;
float y2 = (prevy + midy) / 2.0f;
gp.curveTo(x1, y1, x2, y2, midx, midy);
}
gp.closePath();
if (doDraw) {
g2.setPaint(drawPaint);
g2.setStroke(stroke);
g2.draw(gp);
}
if (doFill) {
if (fillPaint instanceof GradientPaint) {
fillPaint = gradient;
}
g2.setPaint(fillPaint);
g2.fill(gp);
}
}
public Graphics2D createGraphics2D(int w, int h) {
Graphics2D g2 = null;
if (bimg == null || bimg.getWidth() != w || bimg.getHeight() != h) {
bimg = (BufferedImage) createImage(w, h);
reset(w, h);
}
g2 = bimg.createGraphics();
g2.setBackground(getBackground());
g2.clearRect(0, 0, w, h);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
return g2;
}
public void paint(Graphics g) {
Dimension d = getSize();
step(d.width, d.height);
Graphics2D g2 = createGraphics2D(d.width, d.height);
drawDemo(d.width, d.height, g2);
g2.dispose();
if (bimg != null) {
g.drawImage(bimg, 0, 0, this);
}
}
public void start() {
thread = new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
}
public synchronized void stop() {
thread = null;
}
public void run() {
Thread me = Thread.currentThread();
while (thread == me) {
repaint();
try {
Thread.sleep(10);
} catch (Exception e) { break; }
}
thread = null;
}
public static void main(String argv[]) {
SignInFrame n = new SignInFrame();
n.start();
}}
In your SignInFrame constructor, you call initComponents(), but that does not exist. I think you mean to call init(). Also your JFrame does not have a size set, when I ran this under linux (Java 1.6), it worked but was tiny, you should add a setSize call.
Try it with these edits:
public class SignInFrame extends javax.swing.JFrame {
Panel panel;
/** Creates new form SignInFrame */
public SignInFrame() {
setSize (600,600);
init();
}
public void init() {
getContentPane().add(panel = new Panel());
start();
}
public void start() {
panel.start();
}
public void stop() {
panel.stop();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new SignInFrame().setVisible(true);
}
});
}
}