I try to make a standard form for simple games, but every time I try to compile it on my mac, it says:
move.java:31: error: unreachable statement
repaint();
^
Note: move.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
1 error
When I tried to compile it on a windows computer, it worked just fine! I can't find anything about fixing this, and according to the java website the repaint() method isn't deprecated! This is my code:
import java.awt.*;
public class move extends java.applet.Applet implements Runnable {
Image osI;
Graphics osG;
Thread runner;
char currkey;
int x;
int y;
public void init() {
x = 0;
y = 1;
setBackground(Color.yellow);
osI = createImage(size().width, size().height);
osG = osI.getGraphics();
}
public void start() {
if (runner == null) {
runner = new Thread(this);
runner.start();
}
}
public void run() {
while (true) {
y = 1;
}
repaint();
try { Thread.sleep(1000); }
catch (InterruptedException e) { }
}
public void stop() {
if (runner != null) {
runner.stop();
runner = null;
}
}
public boolean keyDown(Event evt, int key) {
switch (key) {
case Event.DOWN:
x = 1;
break;
}
repaint();
return true;
}
public void paint(Graphics g) {
if (x == 1) {
g.drawString("x is 1!!!", 150, 150);
} else {
g.drawString("x is geen 1!!!", 150, 150);
}
if (y == 1) {
g.drawString("y is 1!!!", 150, 175);
} else {
g.drawString("y is geen 1!!!", 150, 175);
}
g.drawImage(osI, 0, 0, this);
osG.setColor(getBackground());
osG.fillRect(0, 0, size().width, size().height);
osG.setColor(getForeground());
}
}
You error isnt saying repaint() is deprecated. In fact, using deprecated methods inst an error at all.
Its because of your infinite loop:
while (true) {
y = 1;
}
repaint();
The error is because you have unreachable code
while (true) {
y = 1;
}
means that the repaint() method will never be called as the loop never ends.
This while-loop...
while (true) {
y = 1;
}
repaint();
Will never exit, therefore, repaint can NEVER be called
Thread#stop is deprecated...
runner.stop();
You should never use it. Instead, create a AtomicBoolean flag which you can use in your while-loop and while it's value is true, keep looping. In your stop method, set the AtomicBoolean's value to false and the loop will exit.
See Java Thread Primitive Deprecation for reasons why stop (and other Thread methods are deprecated)
Applet#size is deprecated...
osG.fillRect(0, 0, size().width, size().height);
Use getWidth and getHeight
java.awt.Applet is 15+ years out of date. Seriously, instead, you should be, at the very least, using JApplet, but even then, I would recommend moving your core logic to a JPanel and simply adding that to what ever container you want to use, apart from gaining double buffering support without any extra work, you also gain the flexibility to decide how to use the component, as frankly, there are better approaches then using an applet now days.
Related
I am programming a basic java game, but I am having an issue.
Everytime that I try it out, if I wait just for 10 seconds, the program stops working correctly. I've made a class called Drawable, which has a paint function. This paint function paints a rectangle on a certain area(given on the constructor).
And I have a thread that iterates over all drawables in an arraylist(added randomly, with another thread), and just substracts 1 to their x. When it stops working correctly, the character can jump and does all animations, but the drawables stop moving. At first I thought this might have given a ConcurrentModificationException error, but it didn't print it on the console.
So right now I don't really know what to do.
Here I add the Drawables:
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
while (Game.isPlayingGame) {
try {
Thread.sleep((long) (Math.random()*2000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
obstacles.add(new Drawable(
Constants.WIDTH,
(int) (Constants.HEIGHT / 2),
Constants.WIDTH - 100,
(int) (Constants.HEIGHT / 2) - 100,
Color.BLUE));
}
}
});
t2.start();
Here I move the Drawables:
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while (Game.isPlayingGame) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (Drawable d : obstacles) {
d.x -= 1;
d.x2 -= 1;
if (d.x2 < 0) {
obstacles.remove(d);
}
}
}
}
});
t.start();
paint method:
#Override
public void paint(Graphics g) {
super.paint(g);
floor.paint(g);
Graphics2D g2d = (Graphics2D) g;
AffineTransform ant = g2d.getTransform();
g2d.rotate(Math.toRadians(rotation),
character.x - Constants.characterSize / 2,
character.y - Constants.characterSize / 2);
character.paint(g);
g2d.setTransform(ant);
for (Drawable d : obstacles) {
d.paint(g);
System.out.println(rotation_down);
if (!rotation_down) {
if (!character.onCollision(floor)) {
character.y += (int) gravityAccel; // gravity
character.y2 += (int) gravityAccel; // gravity
gravityAccel += 0.1;
} else {
Screen.canJump = true;
gravityAccel = 0;
}
}
}
repaint();
}
Thanks in advance.
The proper synchronization depends on the exact internals of your Drawable. Also use CopyOnWriteArrayList. For the Drawable class, decrement of x and x2 should be atomic and synchronized with at least paint() method:
synchronized moveToLeft() {
x-=1;
x2-=1;
}
However, it does not make sense to have an object with x2 < 0 but this is a separate discussion.
You would also want to have
synchronized getX2() {
return x2;
}
and in your second thread do something like this:
if (d.getX2 == 0) {
obstacles.remove(d);
}
else {
d.moveToLeft();
}
The reason to do the check first is that if you do it other way around, you can and up in a situation when x2 is already -1, obstacles.remove(d) has not been called yet, and d.paint() is called. This could cause issues unless your paint() method can handle negative coordinates.
the Code is below. right now what it does is it constantly moves the letter and I only want it to move a over one character when I press the next letter instead of going over more. Also the x+=2 is another method I used and It also didn't work.. This is basically supposed to be a typing class... Please help.It also places all the letters in the same place.. I need it to place them one space apart and I can't press the same letter twice or it just moves the letter
public class Type_Client extends Applet implements KeyListener,Runnable
{
boolean pickA,pickB,pickC,pickD,pickE,pickF,pickG,pickH,pickI,pickJ,pickK=false;
boolean pickL,pickM,pickN,pickO,pickP,pickQ,pickR,pickS,pickT,pickU,pickV=false;
boolean pickW,pickX,pickY,pickZ=false;
boolean space=false;
boolean run=true;
int x=10;
Type t1;
Thread thr;
public void init()
{
t1 = new Type();
thr=new Thread(this);
thr.start();
addKeyListener(this);
}
public void keyTyped(KeyEvent k)
{
}
public void keyReleased(KeyEvent k)
{
}
public void keyPressed(KeyEvent k)
{
if(k.getKeyCode()==KeyEvent.VK_A)
{
pickA=true;
k.consume();
}
if(k.getKeyCode()==KeyEvent.VK_B)
{
pickB=true;
k.consume();
}
if(k.getKeyCode()==KeyEvent.VK_C)
{
pickC=true;
k.consume();
}
if(k.getKeyCode()==KeyEvent.VK_SPACE)
{
space=true;
k.consume();
//Spce++;
}
}
public void run()
{
while(run==true)
{
try{
Thread.sleep(20);
}
catch(Exception e){};
repaint();
}
}
public void paint(Graphics g)
{
if(pickA)
{
g.drawString(" a",x,10);
}
if(pickB)
{
g.drawString(" b",x,10);
x++;
x++;
}
if(pickC)
{
g.drawString(" c",x,10);
x++;
x++;
}
}
}
public void stop()
{
}
public void start()
{
}
}
There are many problems with your code.
First, the infinite repaint loop:
public void run() {
while(run==true) {
try {
Thread.sleep(20);
}
catch(Exception e) { };
repaint();
}
}
This is bad. Remove it and the thread that starts it!
You only need to repaint the JFrame/JPanel/Applet when something changes in how the application will draw itself (or when the window geometry changes or the window is exposed, but the toolkit already handles all of those cases).
Ok, so when does something change? Possibly any time you press a key.
public void keyPressed(KeyEvent k) {
// Your existing code here
repaint();
}
Instead of repainting every 20ms you are now only repainting after a key is pressed. This is probably still too often. Shift, Alt, Ctrl, Meta, Caps Lock are all keys; if you press any of those, a repaint will be triggered despite your application not processing any of those keys. But at least is a minor inefficiency.
Second, x is a field instead of a local paint variable. It is initialized to 10 when the application starts, and incremented when paint is called.
g.drawString(" b",x,10);
Will draw the string " b" at (10,10) when the application is started and VK_B is pressed. But the next time redraw is called (20ms later with your existing code), it will draw it at (12,10), and then (14, 10), and then (16, 10), and so on.
Instead, you probably want:
public void paint(Graphics g) {
int x = 10;
// Remainder of paint code ...
}
So that each time paint is called, it draws the same way (unless something changes in the applications state which causes paint to intentionally draw differently).
drawString uses pixel coordinates. The letter "A" is more than 2 pixels wide in any legible font. For example, in this ASCII art, the letters "A" and "B" are 5 "pixels" wide. To leave a gap between the letters, "B" would need to be drawn at least 6 pixels to the right of "A".
* ****
* * * *
* * ****
***** * *
* * * *
* * ****
<-7px->
You can use Graphics#getFontMetrics to determine how much to advance the position of each character based on the preceding characters, with a given font.
Or, you could use a constant advance of (say) 16 pixels.
private final static int ADVANCE = 16;
public void paint(Graphics g) {
int x = 10;
if (pickA) {
g.drawString("a", x, 10);
x += ADVANCE;
}
if (pickB) {
g.drawString("b", x, 10);
x += ADVANCE;
}
// ...
}
Or you could let the toolkit do the work for you, and draw a String.
public void paint(Graphics g) {
StringBuilder sb = new StringBuilder(27);
if (pickA) {
sb.append("a ");
}
if (pickB) {
sb.append("b ");
}
// ... remainder cases ...
g.drawString(sb.toString(), 10, 10);
}
Finally, your 26 pick(Letter) variables are just plain awful. Consider a different method of recording which keys have been pressed.
Some options:
boolean picked [] = new boolean[26]; // boolean array (1 per letter)
Set<Integer> picked = new HashSet<>(); // A set of VK_ codes
Set<Character> picked = new HashSet<>(); // A set of characters
BitSet picked = new BitSet(26); // A set of bits (1 per letter)
Here is the smallest working example I can make for you. Adapt as needed.
#SuppressWarnings("serial")
public class Type_Client extends Applet {
private String typed = "";
private KeyAdapter adapter = new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
char ch = e.getKeyChar();
if (ch >= ' ' && ch <= '~') {
typed += ch;
repaint();
}
}
};
#Override
public void start() {
addKeyListener(adapter);
}
#Override
public void stop() {
removeKeyListener(adapter);
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawString(typed, 10, 10);
}
}
I decided to make something fun as a break from reading programming books, and I have hit a snag. This is my first swing program, and am ready to wrap it up!
The problem: I clearly don't understand how threads work with Swing. I am writing a GUI for a black jack game, and I did all of the functionality first e.g. drawing a new card to the screen when the player hits, showing the dealer hit after the player decides to stay, etc. This all works.
When I added in the logic to check for a user bust when hitting, or who wins when the user decides to stay, the game instantly goes to the win/loss screen before drawing either: the card the user got that caused a bust, or; the cards that the dealer drew when hitting (if any).
I tried inserting Thread.sleep in various places, to no avail. The program would sleep before drawing the card, then end instantly as above (even though it was placed logically after the call to draw, and before the call to calculate a winner).
also I tried to follow the MVC paradigm here, just fyi.
P.S. my program runs on one thread, I do not explicitly instantiate another, but I vaguely remember reading that Swing spawns it's own thread for graphics stuff
Sorry for that long intro! Here is some code:
The Model class' pertinent methods
void hit() {
//run when button is clicked
player.hand.add(deck.deck.get(0));
deck.deck.remove(0);
}
boolean isBust() {
if (player.getScore() > 21)
return true;
return false;
}
void dealerHit() {
while (dealer.getScore() < 17) { //could implement soft 17 rules for more difficulty
dealer.hand.add(deck.deck.get(0));
setChanged();
notifyObservers();
deck.deck.remove(0);
//Here was one attempt
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
boolean isWin() {
//and another
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ((player.getScore() > dealer.getScore() && player.getScore() <= 21) || dealer.getScore() > 21)
return true;
return false;
}
void stay() {
dealerHit();
isWin();
}
View Class
void addHitListener(ActionListener HitListener) {
hit.addActionListener(HitListener);
}
void addStartListener(ActionListener StartListener) {
start.addActionListener(StartListener);
}
void addStayListener(ActionListener StayListener) {
stay.addActionListener(StayListener);
}
void display() {
JFrame myFrame = new JFrame("BlackJack");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setContentPane(this);
myFrame.setPreferredSize(new Dimension(700,550));
myFrame.pack();
myFrame.setVisible(true);
}
void addCards(Player p, Dealer d) {
topPanel.remove(start);
pcardPanel.add(playerlabel);
dcardPanel.add(dealerlabel);
for (Card c : p.hand) {
ImageIcon cc = new ImageIcon(c.img);
JLabel cC = new JLabel(cc);
//cC.setAlignmentX(alignmentX); use to get X alignment of card 1 & 2 for splits
//cC.setAlignmentY(alignmentY); same for Y, then increment by .3f
pcardPanel.add(cC);
}
for (Card c : d.hand)
dcardPanel.add(new JLabel(new ImageIcon(c.img)));
topPanel.add(new JLabel("Options: "));
topPanel.add(hit);
topPanel.add(stay);
validate();
repaint();
}
void endGame(boolean isWin) {
//I think I tried here, too
removeAll();
setBackground(new Color(0, 122, 0));
if (isWin == true)
add(new JLabel("You won!"));
else
add(new JLabel("You Lost"));
validate();
repaint();
}
public void hitPlayer(Player p) {
JLabel hits = new JLabel(new ImageIcon(p.hand.get(p.hand.size()-1).img));
//hits.setAlignmentY(alignmentY);
pcardPanel.add(hits);
validate();
repaint();
}
public void hitDealer(Dealer d) {
dcardPanel.add(new JLabel(new ImageIcon(d.hand.get(d.hand.size()-1).img)));
validate();
repaint();
}
Controller class:
public class Controller implements Observer {
BlackJack game;
Table t;
Controller(BlackJack game, Table t) {
this.game = game;
this.t = t;
this.game.addObserver(this);
this.t.addHitListener(new HitListener());
this.t.addStartListener(new StartListener());
this.t.addStayListener(new StayListener());
}
public void go() {
t.display();
}
public void update(Observable obj, Object observed) {
t.hitDealer(game.getDealer());
}
class HitListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
game.hit();
t.hitPlayer(game.getPlayer());
if (game.isBust() == true)
t.endGame(false);
}
}
class StartListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.addCards(game.getPlayer(), game.getDealer());
}
}
class StayListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
game.stay();
//doStay();
if (game.isWin() == true)
t.endGame(true);
else
t.endGame(false);
}
}
I just had a thought, since I'm doing this in the actionPerformed methods, could that be why sleep seemed to affect the GUI thread, and not draw the card(s) then sleep. I bet that is it. But I'm going to eat dinner, hopefully someone smarter than myself can lend a hand! Thanks in advance
P.P.S. if there are any typos (I don't think there are) just know that it all compiles and works! And no warnings, if that helps
Swing is indeed a single-thread library, like most UIs. There are also many optimizations to make it work fast. Case in point - most paintings are cached and displayed together. Even if this was not the case, you'd be relying on the speed of the system, which is not a good idea.
If you want a delayed action, you need to use swing's timer (not to be confused with the other timer class). That class has an action listener that goes off when the timer expires. In your case, you'd detect the win/bust condition, start the timer (e.g to fire in 2 seconds) and continue the drawing as usual.
This is a little too long for me to read and understand... But I guess your problem is because you are processing everything in the Event Dispatching Thread.
When you paint something on the GUI and then have more processing, the paint will actually reflect on the GUI only when the whole of the thread has finished processing. That's why you are not seeing your drawing before your Thread.sleep method.
Instead you should use SwingWorker to split your processing and GUI updating to different threads.
Look at this https://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
I'm new to Java so please forgive me asking for help, but after 4 hours of searching for a solution I'm really getting desperate.
I'm currently setting up a game and want to implement key controls. I tried to do this via KeyListener and KeyEventDispatcher but I just can't get it to work.
The KeyListener just won't react. I think that the method that is supposed to use it has the focus.
Here's the code:
public class Sins extends JFrame implements KeyEventDispatcher {
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED ) {
if(KeyEvent.VK_UP == e.getID()){
System.exit(0);
}
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
if(KeyEvent.VK_UP == e.getID()){
System.exit(0);
}
} else if (e.getID() == KeyEvent.KEY_TYPED) {
if(KeyEvent.VK_UP == e.getID()){
System.exit(0);
}
}
return false;
}
and here is the method where it is supposed to be working at:
public void run() {
setFocusable(true);
backgroundGraphics = (Graphics2D) background.getGraphics();
long fpsWait = (long) (1.0 / 30 * 1000);
requestFocusInWindow();
main: while (isRunning==true) {
long renderStart = System.nanoTime();
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(this);
x++;
requestFocusInWindow();
// Update Graphics
do {
Graphics2D bg = getBuffer();
if (isRunning == false) {
break main;
}
renderGame(backgroundGraphics); // this calls your draw method
if (scale != 1) {
bg.drawImage(background, 0, 0, width * scale, height
* scale, 0, 0, width, height, null);
} else {
bg.drawImage(background, 0, 0, null);
}
bg.dispose();
requestFocusInWindow();
this.requestFocus();
if(x ==5000){
isRunning=false;
}
} while (!updateScreen());
// Better do some FPS limiting here
long renderTime = (System.nanoTime() - renderStart) / 10000;
try {
Thread.sleep(Math.max(0, fpsWait - renderTime));
} catch (InterruptedException e) {
Thread.interrupted();
break;
}
renderTime = (System.nanoTime() - renderStart) / 10000;
}
this.dispose();
System.exit(0);
}
The program is currently closing itself after counting up to 5000. For test purposes I'm trying to close it via the up button but it just won't close that way.
I would really appreciate some help, as I said I'm new to Java.
The first problem you were facing with KeyListener is a well know and well documented (here on SO especially). KeyListener will only on respond if the component they are attached to is focusable and has keyboard focus. Think of a text field, when it doesn't have focus, it won't update.
Your second problem is using the KeyBoardFocusManager, which is simply overkill for this problem.
Instead, you should make use of the [Key Bindings] API, which is simpler the having to monitor the KeyBoardFocusManager and more robust then KeyListeners
I've got a working Java program and I would like to draw an object on the display every X seconds. What is the best way to do this? I was thinking of using a for loop and some sleep statements, but I'm curious if there is an easier or more efficient way to go about this.
Thanks.
The simplest way would be to use a javax.swing.Timer
Timer timer = new Timer(X, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Update the variables you need...
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
You might also like to have a read through
The Event Dispatching Thread
Concurrency in Swing
So you can understand why you should never use a while (true) { Thread.sleep(X) } call in Swing (inside the EDT)
ScheduledExecutorService might help here. The Javadoc shows example usage. Don't forget to call the shutdown method when you're finished.
Using Thread, this will draw a rectangle on the screen every XMilSeconds. This will stop after 5 runs. Edit the xMilSeconds for slower runs, and j > 4 for how many runs before stoping. It does freeze though, that I can't fix.
int i = 0;
private long xMilSeconds = 300;
private boolean paint;
public boolean running = true;
public void paint(Graphics g)
{
super.paint(g);
if(paint)
{
for(;i < i+1;)
{
g.drawRect(i+49,i+49,i+299,i+99);
g.setColor(Color.RED);
g.fillRect(i+49,i+49,i+299,i+99);
}
paint = false;
}
}
public void run()
{
while(running)
{
try
{
Thread.sleep(xSeconds);
paint = true;
repaint();
i++;
j++;
if(j > 4)
{
running = false;
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}