I'm working on a school project and I have to create a person's face in java that the user of my app can edit. Each facial characteristic is supposed to have a couple of options, so the first one I tried doing is the eye. However, I'm having trouble when I try to interact with the user in the eyeComponent class.
It prints the users color options (1-4) in the JVM, and opens a blank JFrame window, but in the JVM, it doesn't allow for a user's response. After it prints out the color options, the program just ends, and I'm not sure why it's not allowing the user to respond. I posted the code for both the EyeComponent and PersonViewer classes below.
EyeComponent
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
import java.util.Scanner;
public class EyeComponent extends JComponent
{
public void paintComponent(Graphics g)
{
Scanner in = new Scanner(System.in);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D.Double head = new Ellipse2D.Double(5,20,100,150);
System.out.println("What color would you like the eyes to be?");
System.out.println("Select \n1:blue \n2:red \n3:yellow \n4:green");
int response = in.nextInt();
if (response == 1)
{ g2.setColor(Color.BLUE);}
else if (response == 2)
{ g2.setColor(Color.RED);}
else if (response == 3)
{ g2.setColor(Color.YELLOW);}
else if (response == 4)
{ g2.setColor(Color.GREEN);}
g2.draw(head);
}
}
PersonViewer
import javax.swing.*;
import java.util.Scanner;
public class personViewer //creates class called engine of scope public
{
public static void main (String [] args) //main method for engine class
{
JFrame frame = new JFrame();
frame.setSize(150, 250);
frame.setTitle("Face");
EyeComponent component = new EyeComponent();
frame.add(component);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Never use a Scanner or any blocking code inside of paintComponent. Ever. In fact this blocking code should never be called on the Swing event thread, but especially so in paintComponent as it will grind your program's graphics to a halt. Just don't do it.
This is (another) Event Dispatching Thread issue.
You should NEVER request input from the user via the console from within a GUI program, apart from breaking the whole point of GUI, you have know experienced what happens when you block the main event/repaint thread.
Swing (like all GUI's) are event driven environments. The user clicks or types something and the program responds to it. In this form, they are unlike console programs, which tend to be more linear in nature.
Swing uses a single thread to perform all it's painting and event notification from. Doing anything that stops this thread from running will cause you application to appear as if it has hung and become non-responsive.
Start by having a read of Creating GUIs with Swing and then have a read of Performing Custom Painting and finally I would highly recommend you take a look at Painting in AWT and Swing
Simple Example
Do not have your scanner in a method which you do not have control about.
I refactored you code a bit to more OOP approach.
import javax.swing.*;
import java.awt.Color;
import java.util.Scanner;
public class PersonViewer // creates class called engine of scope public
{
public static void main(String[] args) // main method for engine class
{
Configurator conf = Configurator.getInstance();
Scanner in = new Scanner(System.in);
System.out.println("What color would you like the eyes to be?");
System.out.println("Select \n1:blue \n2:red \n3:yellow \n4:green");
int response = in.nextInt();
switch (response) {
case 1:
conf.setEyeColor(Color.BLUE);
break;
case 2:
conf.setEyeColor(Color.RED);
break;
case 3:
conf.setEyeColor(Color.YELLOW);
break;
case 4:
conf.setEyeColor(Color.GREEN);
break;
}
JFrame frame = new JFrame();
frame.setSize(150, 250);
frame.setTitle("Face");
EyeComponent component = new EyeComponent();
frame.add(component);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
public class EyeComponent extends JComponent {
Configurator conf = Configurator.getInstance();
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Ellipse2D.Double head = new Ellipse2D.Double(5, 20, 100, 150);
g2.setColor(conf.getEyeColor());
System.out.println(conf.getEyeColor());
g2.draw(head);
}
}
import java.awt.Color;
public class Configurator {
private static Configurator instance = null;
public static Configurator getInstance() {
if (instance==null) {
instance = new Configurator();
System.out.println("first called");
}
else {
System.out.println("next calls");
}
return instance;
}
private Color eyeColor;
public Color getEyeColor() {
return eyeColor;
}
public void setEyeColor(Color eyeColor) {
this.eyeColor = eyeColor;
}
}
Hope this help to get a point. And it works.
Related
I am creating a small Java Jpanel game in which I am supposed to have a rocket that moves up and down via arrows and fires via space.
The firing method should work like this: Space bar pressed, thing fires and moves across screen , and then when it hits a certain x, it disappears. Also, you can only fire once until the other bullet disappears.
I do not know what I am doing wrong. For one, as soon as my code starts you can see a bullet flying across the screen.
2nd, the bullet is not disappearing.
3rd, even though the other bullet is still visible, it allows me to fire again.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class SpaceGame extends JPanel implements ActionListener{
Timer t = new Timer(2, this);
private ImageIcon rocket,asteroid,bullet;
private JLabel rocketlabel,ast1,ast2,ast3,bulletLabel;
public static int y=90,dy=0,bulletX=110,bulletY,i=0,canFire;
//public sound sound;
static boolean bulletFired=false;;
static JFrame f = new JFrame();
SpaceGame(){
this.setBackground(Color.black);
rocket = new ImageIcon(getClass().getResource("rocketFinal.png"));
rocketlabel= new JLabel(rocket);
this.add(rocketlabel);
asteroid = new ImageIcon(getClass().getResource("asteroid.png"));
ast1=new JLabel(asteroid);
ast2=new JLabel(asteroid);
ast3=new JLabel(asteroid);
bullet = new ImageIcon(getClass().getResource("bulletReal.png"));
bulletLabel = new JLabel(bullet);
canFire=1;
bulletLabel.setVisible(false);
this.add(ast1);this.add(ast2);this.add(ast3);this.add(bulletLabel);
f.addKeyListener(new controller());
this.setLayout(null);
this.setVisible(true);
}
public class controller implements KeyListener{
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode== KeyEvent.VK_UP) {
dy=-1;
}
if(keyCode== KeyEvent.VK_DOWN) {
dy=1;
}
if(keyCode== KeyEvent.VK_SPACE) {
if(canFire==0) {
System.out.println(String.valueOf(canFire));
bulletFired = true;
bulletY = y;
bulletX=110;
}canFire=1;
}
}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch(key) {
case KeyEvent.VK_UP: dy=0; break;
case KeyEvent.VK_DOWN: dy=0; break;
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
rocketlabel.setBounds(45,y,rocket.getIconWidth(),80);
fireBullet();
paintStars(g);
t.start();
}
public void paintStars(Graphics g) {
g.setColor(Color.yellow);
for(int i=0; i<5;i++) {
Random rand = new Random();
int o = rand.nextInt(500);
int p = rand.nextInt(300);
g.fillOval(o, p, 3, 3);
}
}
public void actionPerformed(ActionEvent e) {
if(y==-20) y=249;
if(y==250)y=-20;
y+=dy;
if(bulletFired=true) {
bulletX++;
if(bulletX==455)bulletFired=false;bulletLabel.setVisible(false);System.out.println(String.valueOf(bulletX)); canFire=0;
}
repaint();
}
public void fireBullet(){
if(bulletFired=true) {
bulletLabel.setVisible(true);
bulletLabel.setBounds(bulletX,bulletY+25,bullet.getIconHeight(),bullet.getIconWidth());
}
}
public static void main(String[] args) {
String filepath = "SpaceGameMusic.wav";
musicStuff musicPlayer = new musicStuff();
musicPlayer.playMusic(filepath);
SpaceGame t = new SpaceGame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(t);
f.setSize(500,335);
f.setVisible(true);
f.setResizable(false);
}
}
For one, as soon as my code starts you can see a bullet flying across the screen.
The paintComponent() method is for painting only. You can't control when Swing will determine a component needs to be repainted.
So, for example:
t.start();
should NOT be in the painting method. As soon as the frame is made visible the panel will be painted and the Timer will be started.
You application code should control when the Timer is started.
Other issues:
you should not be using static variables. The variable should simply be instances of your class.
the paintStars() method should not generate random locations. Again. a painting method should only paint the current state of the class. So if you want to change the location of the stars you should have a method like randomizeStars(). In this method you would update an ArrayList of Point objects. Each Point instance would represent the location of a star. Then the paintStars() method would simply iterate through the ArrayList and paint each star.
you should not be using a KeyListener. A KeyListener only works if a component has focus. You can't guarantee that your component will lose focus. Instead you should be using Key Bindings. Key bindings allow you to handle a KeyEvent even if the component doesn't have focus. See Motion Using the Keyboard for more information and a working example.
you can only fire once until the other bullet disappears
Your canFire variable should be a boolean variable so it only has true/false values. Again you have a method that sets the state. Your game logic will then check the state before firing the bullet again.
if(y==-20) y=249;
if(y==250)y=-20;
Don't hardcode values. The number should be based on the size of your panel. So you use methods like getWidth() and getHeight() to determine the current size of the panel.
The problem was quite simply that I had forgotten to use == in my if(boolean) statements.
I've made a JFrame with a canvas on it and I want to draw on that canvas. At a later date the canvas will be updating many times a second so I am using a buffer strategy for this. Here is the code:
package mainPackage;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class TickPainter {
//just some presets for a window.
public static JFrame makeWindow(String title, int width, int height) {
JFrame mainWindow = new JFrame();
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setSize(width, height);
mainWindow.setVisible(true);
mainWindow.setLocationRelativeTo(null);
mainWindow.setTitle(title);
return mainWindow;
}
public static void main(String[] args) {
JFrame mainWindow = makeWindow("Practice", 800, 600);
Canvas mainCanvas = new Canvas();
mainWindow.add(mainCanvas);
mainCanvas.setSize(mainWindow.getWidth(), mainWindow.getHeight());
mainCanvas.setBackground(Color.white);
mainCanvas.createBufferStrategy(3);
BufferStrategy bufferStrat = mainCanvas.getBufferStrategy();
Graphics g = bufferStrat.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(250, 250, 250, 250);
g.dispose();
bufferStrat.show();
}
}
The program does not draw the black rectangle as intended, I feel like I've missed something really obvious here and I just can't see it. At the moment the program just makes a blank white canvas. I feel like part of the issue is that the buffer is just passing the frame with the rectangle faster than I can see, but there is no frame to load after that so I don't know why it's doing this.
A BufferStrategy has a number of initial requirements which must be meet before it can be rendered to. Also, because of the nature of how it works, you might need to repeat a paint phases a number of times before it's actually accepted by the hardware layer.
I recommend going through the JavaDocs and tutorial, they provide invaluable examples into how you're suppose to use a BufferStrategy
The following example uses a Canvas as the base component and sets up a rendering loop within a custom Thread. It's very basic, but shows the basic concepts you'd need to implement...
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TestCanvas canvas = new TestCanvas();
JFrame frame = new JFrame();
frame.add(canvas);
frame.setTitle("Test");
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
canvas.start();
}
});
}
public class TestCanvas extends Canvas {
private Thread thread;
private AtomicBoolean keepRendering = new AtomicBoolean(true);
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void stop() {
if (thread != null) {
keepRendering.set(false);
try {
thread.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public void start() {
if (thread != null) {
stop();
}
keepRendering.set(true);
thread = new Thread(new Runnable() {
#Override
public void run() {
createBufferStrategy(3);
do {
BufferStrategy bs = getBufferStrategy();
while (bs == null) {
System.out.println("get buffer");
bs = getBufferStrategy();
}
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
// Get a new graphics context every time through the loop
// to make sure the strategy is validated
System.out.println("draw");
Graphics graphics = bs.getDrawGraphics();
// Render to graphics
// ...
graphics.setColor(Color.RED);
graphics.fillRect(0, 0, 100, 100);
// Dispose the graphics
graphics.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (bs.contentsRestored());
System.out.println("show");
// Display the buffer
bs.show();
// Repeat the rendering if the drawing buffer was lost
} while (bs.contentsLost());
System.out.println("done");
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
} while (keepRendering.get());
}
});
thread.start();
}
}
}
Remember, the point of BufferStrategy is to give you full control over the painting process, so it works outside the normal painting process generally implemented by AWT and Swing
"At a later date the canvas will be updating many times a second so I am using a buffer strategy for this" - Before going down the "direct to hardware" solution, I'd consider using a Swing Timer and the normal painting process to see how well it works
I tried making a sprite animation in JAVA using Swing. The code below is an array of ImageIcon which I'm going to iterate through in order to show the several different images (only 2 for testing purposes).
But I don't know how to properly time each iteration. I mean, when I compile the code the label I'm working on, only displays the last image of the array (obviously), but I want it to display the first one for some ms and the other one after.
I made some research and saw some suggestions regarding Time class, but I don't really know how to implement it in these circunstances. I also tried to use sleep, which works fine in C++, but only came up with thread.sleep which doesn't work in this case.
The animation is supposed to simulate a playing card being turned around (for the Monopoly game).
Can anyone give me some input on the matter?
import javax.swing.ImageIcon;
import javax.swing.JLabel;
public class Sprite2 {
private ImageIcon[] sprites;
private ImageIcon a = new ImageIcon("C:/Users/Guilherme/Desktop/G/FEUP/2º Ano/2nd semester/Eclipse repos/Sprite/src/images/ball.jpg");
private ImageIcon b = new ImageIcon("C:/Users/Guilherme/Desktop/G/FEUP/2º Ano/2nd semester/Eclipse repos/Sprite/src/images/transferir.jpg");
public Sprite2() {
sprites = new ImageIcon[] {a, b};
}
public void render(JLabel lbl) {
for (int i = 0; i < sprites.length; i++) {
lbl.setIcon(sprites[i]);
//sleep(1000); - Looking for a similar Java function which is able to delay each iteration and make it look like a gif
}
}
You can use Swing timer, see How to Use Swing Timers for more details.
You should not use sleep() on Event Dispatch Thread as it will stop the thread from processing painting and other UI related events and the UI will become frozen. For more details see The Event Dispatch Thread tutorial.
I figured it out using timer.
For some reason, the first frame wouldn't show up in the first animation, hence sprites[0] and [1] are the same image.
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Sprite extends JPanel implements ActionListener{
private ImageIcon[] sprites = new ImageIcon[4];
private Timer time;
private int delay = 500, currentFrame = 0;
private ImageIcon a0 = new ImageIcon("C:/Users/Guilherme/Desktop/G/FEUP/2º Ano/2nd semester/Eclipse repos/Sprite/src/images/ball.jpg");
private ImageIcon a1 = new ImageIcon("C:/Users/Guilherme/Desktop/G/FEUP/2º Ano/2nd semester/Eclipse repos/Sprite/src/images/transferir.jpg");
private ImageIcon a2 = new ImageIcon("C:/Users/Guilherme/Desktop/G/FEUP/2º Ano/2nd semester/Eclipse repos/Sprite/src/images/smurf_sprite.png");
public Sprite() {
sprites[0] = a0;
sprites[1] = a0;
sprites[2] = a1;
sprites[3] = a2;
time = new Timer(delay, this);
time.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
sprites[currentFrame].paintIcon(this, g, 0, 0);
if (currentFrame == sprites.length-1) {
time.stop();
}
else currentFrame++;
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public static void main(String[] arg) {
JFrame f = new JFrame();
Sprite s = new Sprite();
f.add(s);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(500,400);
}
}
Here is my code:
import java.applet.AudioClip;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import acm.graphics.GLabel;
import acm.program.GraphicsProgram;
import javax.imageio.ImageIO;
import acm.util.MediaTools;
public class FlappyBird extends GraphicsProgram {
public Background background; //background image
public UpTube uptube; //one of the pipes
public DownTube downtube; //other pipe
public Bird bird;
//image for the bird
public static final int APPLICATION_WIDTH = 882;
public static final int APPLICATION_HEIGHT = 772;
public void run(){
addKeyListeners();
background = new Background();
add(background);
uptube = new UpTube();
add(uptube);
downtube = new DownTube();
add(downtube);
bird = new Bird();
add(bird);
public void jump(){
for(int i =0;i<5;i++){
bird.move(3,-7);
pause(100);
}
for(int i =0;i<15;i++){
bird.move(5, -4);
pause(100);
}
for(int i =0;i<15;i++){
bird.move(7,0);
pause(100);
}
for(int i =0;i<15;i++){
bird.move(5,7);
pause(100);
}
for(int i =0;i<15;i++){
bird.move(3,-7);
pause(100);
}
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_SPACE){
jump();
However, when I run this and I press the Space Bar, it doesn't show the bird's individual movements, it just teleports the bird to the end location after the pause(100) is over for each for statement. How do I make it so that it updates the bird's location each time I move it?
I dont know about the API you are using but I have made many graphics utilities, games and programs in java and there are some basic principles you must know; the one you seem to be having an 'issue' with is you assume the rendering is done one another thread (happening while this code is running) or will completely redraw whenever the bird moves - this is not the case in most graphics renderers, instead they simply redraw after all processing of every frame.
So, what you will need to do is either get rendering on another thread so the for loop can run while the rendering is happening at a different rate, or, implement more state-machine like code where it knows what it should do each frame (e.g move the bird every 100ms, 15 times).
my final goal for this application is to animate several items in the same JPanel at a different speed using a thread for each item.the first part is done however the items move at the same speed and i have no idea on how to fix this problem.
package javagamestutos;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
public class Board extends JPanel implements Runnable {
private Star star;
private Thread animator;
ArrayList<Star> items=new ArrayList<Star>();
public Board() {
setBackground(Color.BLACK);
setDoubleBuffered(true);
star=new Star(25,0,0);
Star star2=new Star(50,20,25);
items.add(star2);
items.add(star);
}
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
for (Star s : this.items) {
g2d.drawImage(s.starImage, s.x, s.y, this);
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void run() {
while(true){
try {
for (Star s : this.items) {
s.move();
}
repaint();
Thread.sleep(star.delay);
} catch (InterruptedException ex) {
Logger.getLogger(Board.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
here is the star class wich is the moving item.
package javagamestutos;
import java.awt.Image;
import javax.swing.ImageIcon;
/**
*
* #author fenec
*/
public class Star {
Image starImage;
int x,y;
int destinationX=200,destinationY=226;
boolean lockY=true;
int delay;
public Star(int delay,int initialX,int initialY){
ImageIcon ii = new ImageIcon(this.getClass().getResource("star.png"));
starImage = ii.getImage();
x=initialX;
y=initialY;
this.delay=delay;
}
void moveToX(int destX){
this.x += 1;
}
boolean validDestinatonX(){
if(this.x==this.destinationX){
this.lockY=false;
return true;
}
else
return false;
}
void moveToY(int destY){
this.y += 1;
}
boolean validDestinatonY(){
if(this.y==this.destinationY)
return true;
else
return false;
}
void move(){
if(!this.validDestinatonX() )
x+=1;
if(!this.validDestinatonY() && !this.lockY)
y+=1;
/*if(!this.validDestinatonY())
y+=1;
*/
}
}
and here is the skeleton of the animation that extends a JFrame :
package javagamestutos;
import javax.swing.JFrame;
public class Skeleton extends JFrame {
public Skeleton() {
add(new Board());
setTitle("Stars");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300, 280);
setLocationRelativeTo(null);
setVisible(true);
setResizable(false);
}
public static void main(String[] args) {
new Skeleton();
}
}
do you have any idea how to achieve my goals?am i using threads proprely?
thank you in advance.
That's because you're invoking the "move" method at a fixed rate specified by the delay of the first "start"
Thread.sleep(star.delay);
So if you move them a little every "n" milliseconds, they will seems to move at the same peace.
If you want them to move at different speed, you have to move them in different thread ( you are using only one now ) Bear in mind the comment by omry,
EDIT
I did something similar just recently
I have two different things so animate so I have two timers ( timers use threads underneath, but they can repeat the execution code every fixed rate ).
The first apply the text to a JLabel every second ( 1000 ms )
final Timer timer = new Timer();
timer.scheduleAtFixedRate( new TimerTask() {
public void run(){
setText();
}
}, 0, 1000 );
And other change the displaying image every 10 seconds ( 10,000 ms )
final Timer imageTimer = new Timer();
imageTimer.scheduleAtFixedRate( new TimerTask() {
public void run() {
setImage();
}
}, 0, 10000 );
I have a video of the result here:
For more advanced ( and nice ) time management you MUST take a look at the "Timing Framework" project which adds additional capabilities to timers.
You should be painting in the AWTDispatchThread. To do that you will want to use something like SwingUtilities.invokeLater(Runnable); This applies not only to your animation, but to the creation and setting visible of your JFrame as well. Failing to do this could result in deadlocks with the painting thread. Also, when moving your painting operations into the SwingUtilites methods, you will not want to include any while(true) loops, as that will commandeer your painting thread.
Generally Swing components should be used from the AWT Event Dispatch Thread (EDT). repaint is one of the methods that is supposedly okay to use off EDT. However, your Star is not and should not be thread-safe.
The easiest approach is to go for EDT-only (at least to start with). Instead of using Thread use javax.swing.Timer which fires on the EDT.
Misc comments: There should be no need for your paint method to dispose of the graphics object sent to it, or for it to sync using Toolkit. The component need not be set to double-buffered, but should be set opaque (JPanel is not guaranteed to be opaque). You should just extend JComponent instead of JPanel, as this is not a panel. It's generally not a great idea for outer classes to implement Runnable. Prefer private variables.
I would suggest you take a look at the open source library trident which does just that, its author, Kirill Grouchnikov is well-known in the Swing world (he is the author of the famous Substance look & feel).
Trident should help you solve the problem of having different objects move at different speeds, without having to create one thread per object (which is a problem in the end).
if you are sure you want to paint in the threads, you can use :
update(getGraphics());
instead of repaint.
this is generally considered bad practice, as you normally paint stuff in the AWT thread.