Reputation: 49
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Racing extends JFrame {
private static final long serialVersionUID = -198172151996959655L;
//makes the screen size
final int WIDTH = 900, HEIGHT = 650;
//keeps track of player speed
double plSpeed = .5;
//numbers that represent direction
final int UP = 0, RIGHT = 1, DOWN = 2, LEFT = 3, STOP = 5, START = 6;
//keeps track of player direction
int p1Direction = START;
//makes player 1's car
Rectangle p1 = new Rectangle ( 100, 325, 30, 30 );
Rectangle foreground = new Rectangle( 500, 500, 200, 200 );
//constructor
public Racing() {
//define defaults for the JFrame
super ("Racing");
setSize( WIDTH, HEIGHT );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setBackground(Color.BLACK);
//start the inner class
Move1 m1 = new Move1();
m1.start();
}
//draws the cars and race track
public void paint(Graphics g) {
super.paint(g);
//draw p1
g.setColor(Color.RED);
g.fillRect(p1.x,p1.y,p1.width,p1.height);
g.setColor(Color.GREEN);
g.fillRect(foreground.x,foreground.y,foreground.width,foreground.height);
}
private class Move1 extends Thread implements KeyListener {
public void run() {
//makes the key listener "wake up"
addKeyListener(this);
//should be done in an infinite loop, so it repeats
while (true) {
//make try block, so it can exit if it errors
try {
//refresh screen
repaint();
//makes car increase speed a bit
if (plSpeed <= 7) {
plSpeed += .2;
}
//lets the car stop
if (plSpeed==0) {
p1Direction = STOP;
}
//moves player based on direction
if (p1Direction==UP) {
p1.y -= (int) plSpeed;
}
if (p1Direction==DOWN) {
p1.y += (int) plSpeed;
}
if (p1Direction==LEFT) {
p1.x -= (int) plSpeed;
}
if (p1Direction==RIGHT) {
p1.x += (int) plSpeed;
}
if (p1Direction==STOP) {
plSpeed = 0;
}
//delays refresh rate
Thread.sleep(75);
}
catch(Exception e) {
//if an error, exit
break;
}
}
}
//have to input these (so it will compile)
public void keyPressed(KeyEvent event) {
try {
//makes car increase speed a bit
if (event.getKeyChar()=='w' ||
event.getKeyChar()=='a' ||
event.getKeyChar()=='s' ||
event.getKeyChar()=='d') {
plSpeed += .2;
repaint();
}
} catch (Exception I) {}
}
public void keyReleased(KeyEvent event) {}
//now, to be able to set the direction
public void keyTyped(KeyEvent event) {
if (plSpeed > 0) {
if (event.getKeyChar()=='a') {
if (p1Direction==RIGHT) {
p1Brake();
} else {
if (p1Direction==LEFT) {
} else {
p1Direction = LEFT;
}
}
}
if (event.getKeyChar()=='s') {
if (p1Direction==UP) {
p1Brake();
} else {
if (p1Direction==DOWN) {
} else {
p1Direction = DOWN;
}
}
}
if (event.getKeyChar()=='d') {
if (p1Direction==LEFT) {
p1Brake();
} else {
if (p1Direction==RIGHT) {
} else {
p1Direction = RIGHT;
}
}
}
if (event.getKeyChar()=='w') {
if (p1Direction==DOWN) {
p1Brake();
} else {
if (p1Direction==UP) {
} else {
p1Direction = UP;
}
}
}
if (event.getKeyChar()=='z') {
p1Brake();
}
}
}
public void p1Brake () {
try {
while (plSpeed != 0) {
plSpeed -= .2;
Thread.sleep(75);
}
} catch (Exception e) {
plSpeed = 0;
}
}
}
//finally, to start the program
public static void main(String[] args) {
Racing frame = new Racing();
frame.setVisible( true );
frame.setLocationRelativeTo( null );
frame.setResizable( false );
}
}
This is an SSCCE of my code. If I add super.paint(g); to the top of this, inside the class, then it gets all flashy. If I leave that out, then whenever you move the player, then it creates a line of where the player has been-without repainting. I need to know how to - and where to repaint. The closest I have gotten to my answer here here:
http://www.java-forums.org/awt-swing/37406-repaint-without-flashing.html
but they have an applet (which I have never dealt with before, and assuming it would be rather tricky to translate the code from applet to frames). Can anybody help me with this?
Notes:
I didn't know you could make a frame with awt, because I was happy and familiar with swing, so I didn't want to change. Sorry about that. As you can see, whatever i draw flashes, not just the player.
Andrew, here's my screenshot:
Oh, and it doesn't register P2.
Upvotes: 3
Views: 3779
Reputation: 156
Changing the code from applet to JFrame is not hard at all. Rename the class's extension to JPanel:
public class Racing extends JPanel
then in the method where you instantiate a new Racing
change it to instantiate a new JFrame
and any method in racing like setTitle(...)
that now throws an error move to the method that instantiates the new JFrame, as (whatever you named the JFrame reference).setTitle(...)
Then apply the following code to the rest of the JFrame:
JFrame.add(new Racing());
JFrame.setSize(*the size of Racing window*);
Upvotes: 0
Reputation: 168815
I made a number of changes. Here are some I can recall.
JPanel
, and moved painting to paintComponent()
.Thread
and Thread.sleep(n)
& replaced with a Timer
/ActionListener
.JFrame
. Instead sets a preferred size for the JPanel
(the actual drawing area) and calls JFrame.pack()
to get the correct overall size.setLocationByPlatform(true)
instead of the very splash-screen like setLocationRelativeTo(null)
.Check the code carefully for further tips.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Racing extends JPanel implements KeyListener {
private static final long serialVersionUID = -198172151996959655L;
//keeps track of player speed
double plSpeed = .5;
//numbers that represent direction
final int UP = 0, RIGHT = 1, DOWN = 2, LEFT = 3, STOP = 5, START = 6;
//keeps track of player direction
int p1Direction = START;
//makes player 1's car
Rectangle p1 = new Rectangle ( 100, 25, 30, 30 );
//constructor
public Racing() {
//define defaults for the JFrame
setBackground(Color.BLACK);
//makes the screen size
setPreferredSize(new Dimension(400,50));
//makes the key listener "wake up"
addKeyListener(this);
setFocusable(true);
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
//refresh screen
repaint();
//makes car increase speed a bit
if (plSpeed <= 7) {
plSpeed += .2;
}
//lets the car stop
if (plSpeed==0) {
p1Direction = STOP;
}
//moves player based on direction
if (p1Direction==UP) {
p1.y -= (int) plSpeed;
}
if (p1Direction==DOWN) {
p1.y += (int) plSpeed;
}
if (p1Direction==LEFT) {
p1.x -= (int) plSpeed;
}
if (p1Direction==RIGHT) {
p1.x += (int) plSpeed;
}
if (p1Direction==STOP) {
plSpeed = 0;
}
}
};
Timer t = new Timer(75,al);
t.start();
}
//draws the cars and race track
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//draw p1
g.setColor(Color.RED);
g.fillRect(p1.x,p1.y,p1.width,p1.height);
}
//have to input these (so it will compile)
public void keyPressed(KeyEvent event) {
System.out.println(event);
try {
//makes car increase speed a bit
if (event.getKeyChar()=='w' ||
event.getKeyChar()=='a' ||
event.getKeyChar()=='s' ||
event.getKeyChar()=='d') {
plSpeed += .2;
//repaint();
}
} catch (Exception I) {}
}
public void keyReleased(KeyEvent event) {}
//now, to be able to set the direction
public void keyTyped(KeyEvent event) {
if (plSpeed > 0) {
if (event.getKeyChar()=='a') {
if (p1Direction==RIGHT) {
p1Brake();
} else {
if (p1Direction==LEFT) {
} else {
p1Direction = LEFT;
}
}
}
if (event.getKeyChar()=='s') {
if (p1Direction==UP) {
p1Brake();
} else {
if (p1Direction==DOWN) {
} else {
p1Direction = DOWN;
}
}
}
if (event.getKeyChar()=='d') {
if (p1Direction==LEFT) {
p1Brake();
} else {
if (p1Direction==RIGHT) {
} else {
p1Direction = RIGHT;
}
}
}
if (event.getKeyChar()=='w') {
if (p1Direction==DOWN) {
p1Brake();
} else {
if (p1Direction==UP) {
} else {
p1Direction = UP;
}
}
}
if (event.getKeyChar()=='z') {
p1Brake();
}
}
}
public void p1Brake () {
try {
while (plSpeed != 0) {
plSpeed -= .2;
}
} catch (Exception e) {
plSpeed = 0;
}
}
//finally, to start the program
public static void main(String[] args) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
JFrame f = new JFrame("Racing");
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
f.add(new Racing());
f.pack();
f.setLocationByPlatform(true);
f.setResizable( false );
f.setVisible( true );
}
});
}
}
Upvotes: 3
Reputation: 3642
You should never attempt to draw directly onto the canvas, use a background thread that keeps the next frame ready always and swap it with the old one.
while (state == RUNNING)
{
long beforeTime = System.nanoTime();
gEngine.update(); // update stuff like game score life etc..
Canvas c = null;
try
{
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder)
{
drawable.setBounds(0, 0, 800, 600);
drawable.draw(c); // flash new background if required for the new frame
gEngine.draw(c); // update game state
}
} finally
{
if (c != null)
{
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
this.sleepTime = delay
- ((System.nanoTime() - beforeTime) / 1000000L);
try
{
if (sleepTime > 0)
{
Thread.sleep(sleepTime);
}
} catch (InterruptedException ex)
{
Logger.getLogger(PaintThread.class.getName()).log(Level.SEVERE,
null, ex);
}
}
}
Upvotes: 1