I want to make a game that loops through an array every 1 second and then when the 'x' key is pressed the array stops printing, and the next 'x' key press the array resumes from the current element and loops again. my game starts with x and if i press again it just prints every 1 second. how do i add functionality and keep track of cards in the deck
My program is in java frame
public class Game {
private JFrame frame;
public static String[] cards = { "Jack", "Queen", "King" };
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Menu window = new Menu();
Timer timer = new Timer();
window.frame.setVisible(true);
//timer for card loops
timer.schedule(new GoCards(cards), 0, 1000);
window.frame.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e)
{
char key = e.getKeyChar();
if(key == 'x')
{
//pause the timer and if i press again then resume timer
timer.cancel();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class GoCards extends TimerTask
{
String[] deck;
public GoCards(String[] cards)
{
deck = cards;
}
public void run()
{
for(int i = 0; i < 3; i++)
{
Thread.sleep(1000);
System.out.println(deck[i]);
}
}
Yours is a Swing application, so no, don't use Thread.sleep(...), not unless you want to risk putting your entire GUI to sleep, and don't use a java.util.Timer, since this does not work well with the Swing event thread. Instead you will want to use the tool best suited for the job -- a Swing Timer, aka javax.swing.Timer. The Timer can be started by calling start() on it and stopped simply by calling stop(), and you set the delay in milliseconds in its constructor. Also, use of a KeyListener is risky as it won't work if anything, such as a JButton for instance, steals the focus. Better to use Key Bindings. You can find links to the Swing tutorials and other Swing resources here: Swing Info.
You can make use of a timer such as wait
Thread.sleep(milliseconds);
Then keep track of each key press / iteration with a new counter n.
Checking for key presses would be a matter of simply handling them as they come in, or something as arbitrary as checking each iteration for any particular key.
Related
I've recently started to try to learn java. I thought maybe making small games would be the best way to get familiar with java, so that's what I'm doing. So, I started my first game, and it's looking good. It's just a grid with a player in the center. Once I tried adding player movement I realized I'd need a game loop to check for key presses. That's what I tried. All I can say is that I've never made a game loop before, so this is what I attempted:
public static void main(String[] args) {
GamePanel panel = new GamePanel();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGui();
double ns = 1000000000.0 / 60.0;
double delta = 0;
long lastTime = System.nanoTime();
long timer = System.currentTimeMillis();
while (true) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
panel.checkKeys();
delta--;
}
}
}
});
}
Here's the issue... When I run this, my game just crashes. It doesn't even let me close out of the game. What is going on? Just in case, I will show more of the GamePanel code (please tell me if you need any more code).
public GamePanel() {
setLayout(new GridLayout(tiles_count, tiles_count));
setBackground(Color.gray);
setFocusable(true);
addKeyListener(this);
tile_size = 40;
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_A) {
System.out.println("A PRESSED");
player.x += 40;
left = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_A) {
System.out.println("A RELEASED");
left = false;
}
}
#Override
public void keyTyped(KeyEvent e) {
}
public void checkKeys() {
if(left) {
System.out.println("LEFT");
} else {
System.out.println("!LEFT");
}
}
The game structure is like this: I have a Main class, which runs a GamePanel class as the main(String args) {} function. This issue might have to be with the fact that im using the run method in the Main class instead of the GamePanel class.
What am I doing wrong? Any help is very much appreciated!
Your while loop will never exit, and thus your program can never repaint, etc.
However, for a game loop like this, you do want an infinite loop --- you just want to run it in a different thread. In this way, the rest of your program is not blocked by the infinite loop, however you are still able to run your game loop tasks.
To do this, we make a new thread, and run our loop in there instead. Note also that after each loop we sleep for a little while (ideally you'd want to do this with time deltas, etc, this is just an example) --- this means that we cap the amount of frames per second, meaning that we don't overwork the processor for no good reason.
Thread t = new Thread(new Runnable(){
public void run() {
while (true) {
// your update logic here
try {
Thread.sleep(16);
}
catch(InterruptedException) {}
}
}
});
t.start();
I believe the issue is that you have an infinite loop. This occurs when the condition for your loop will always remain true. while(True). You either need to implement a break; statement which will terminate the loop or use a condition in your while loop that will run the loop until a certain condition is met while(some-condition == true). Hopefully, this helps.
https://codesnippets.fandom.com/wiki/Infinite_Loop
I have a JFrame with two buttons. One of the buttons when clicked moves (btnMove) the other button(shape) from the present position to another.I am using a thread as a timer to count in seconds but each time the counter increments, the button moves back to its original position.
public class FrameTh extends JFrame {
class count extends Thread {
public int p = 0;
public void run() {
for (int i = 1; i < 100; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e);
}
lblCounter.setText("Seconds: " + i);
}
}
}
count t1 = new count();
private void formWindowActivated(java.awt.event.WindowEvent evt) {
t1.start();
}
private void btnMoveActionPerformed(java.awt.event.ActionEvent evt) {
shape.setLocation(23, 44);
}
The core problem is you're fighting the layout management API, which when you call setText is causing the container to be invalidated and relayed out
You might consider using something like JLayeredPane, but remember, you become entirely responsible for the size and position of the component
The other problem you have is you're violating the single threaded nature of Swing, Swing is not thread safe, meaning you shouldn't update the ui from out of the Event Dispatching Thread.
To solve that particular problem you should use a Swing Timer instead of a thread, see How to use Swing Timers for more details
What I am trying to do is an Appled which throws 2 threads, each running a counter which increases itself via an infinite loop
I then use a while(true) in the Applet's paint() method, which continuously paints the counters, the problem is that I have also 2 buttons, each intended to stop each thread, but the infinite loop in the paint() method doesn't let me neither click none of them nor close the Applet's window nor anything
Here a screenshot followed by the code
btw I'm certain the problem is the paint() loop as if I disable the loop I can interact with the buttons, but the counters are obviously not updated, and weird thing is that I put the mouse cursor over the buttons to show it took the form like when you want to resize a windows but the imprpant didn't capture it :/
http://i.imgur.com/PJnDI4u.png
public class MainApplet extends Applet implements ActionListener {
private static final long serialVersionUID = -2500043816999861110L;
private Font fuente;
private Button bUno, bDos;
private HiloContador hUno, hDos;
public void init() {
setBackground(Color.LIGHT_GRAY);
fuente = new Font("Verdana",Font.BOLD,26);
bUno = new Button("Parar");
bUno.addActionListener(this);
bDos = new Button("Parar");
bDos.addActionListener(this);
bUno.setSize(40,20);
add(bUno);
bDos.setSize(40,20);
add(bDos);
hUno = new HiloContador(20);
hUno.start();
hDos = new HiloContador(40);
hDos.start();
}
#SuppressWarnings({ "deprecation", "static-access" })
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(bUno)){
hUno.parar();
bUno.setLabel("1 parado");
}else if (e.getSource().equals(bDos)){
hDos.parar();
bDos.setLabel("2 parado");
}
}
public void paint(Graphics g) {
while (true){
g.clearRect(1,1,getSize().width,getSize().height); //dibuja la ventana
g.setFont(fuente);
g.drawString(hUno.getContador()+"",40,60);
g.drawString(hDos.getContador()+"",100,60);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
in case it helps anyone, solved deleting the infinite loop and adding this method
Timer timer = new Timer();
timer.schedule( new TimerTask() {
public void run() {
repaint();}
}, 0, 1000);
I have one three rectangles in my canvas. I wanted to change the colours of three rectangles
in a slow manner one by one.
For example: When starting the application, user should be able to see three rectangles with the same colour (blue).
After 2 secons that rectangles colour should change to red.
Again after 2 secons the next rectangles colour should get changed.
The last one is also done the same way, that means after 2 seconds of the 2nd rectangle.
I wrote in my own way. But it is not working. All the rectanlges are changed together. I want one by one.
Could anyone give me the logic.
final Runnable timer = new Runnable() {
public void run() {
//list of rectangles size =3; each contain Rectangle.
for(int i = 0 ; i < rectangleList.size();i++){
if(rectangleListt.get(i).getBackgroundColor().equals(ColorConstants.blue)){
try {
rectangleList.get(i).setBackgroundColor(ColorConstants.yellow);
Thread.sleep(1500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//rectSubFigureList.get(i).setBorder(null);
}/*else{
rectSubFigureList.get(i).setBackgroundColor(ColorConstants.blue);
}*/
}
You're likely calling Thread.sleep inside of Swing's event thread or EDT (for event dispatch thread), and this will cause the thread itself to sleep. Since this thread is responsible for all of Swing's graphics and user interactions, this will in effect put your entire application to sleep, and is not what you want to have happen. Instead, read up on and use a Swing Timer for this.
References:
Swing Timer tutorial
Swing Event Dispatch Thread and Swingworker tutorial
To expand on Hidde's code, you could do:
// the timer:
Timer t = new Timer(2000, new ActionListener() {
private int changed = 0; // better to keep this private and in the class
#Override
public void actionPerformed(ActionEvent e) {
if (changed < rectangleList.size()) {
rectangleList.setBackgroundColor(someColor);
} else {
((Timer) e.getSource()).stop();
}
changed++;
}
});
t.start();
You can set a Timer:
// declaration:
static int changed = 0;
// the timer:
Timer t = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Change the colour here:
if (changed == 0) {
// change the first one
} else if (changed == 1) {
// change the second one
} else if (changed == 2) {
// change the last one
} else {
((Timer) e.getSource()).stop();
}
changed ++;
}
});
t.start();
I am making a simple board game in java, where I want to animate a dice roll. So I flash pictures of a dice like this:
public Timer roll_dice = new Timer(50, this);
...
public void actionPerformed(ActionEvent evt) {
if(roll_dice.getDelay() > 500){
roll_dice.setDelay(50);
roll_dice.stop();
movePiece();
}else{
roll_dice.setDelay(roll_dice.getDelay() + 50);
dice_panel.repaint(0);
}
}
}
movePiece(){
//do some more painting
}
So the die is going so show random numbers for a few times, and then slowly settle on a number. After that is done I would like to call the movePiece() method. However, as it is, the the repaint occurs sporadically and screws everything up so that movePiece() gets called before the dice roll is actually finished animating.
Does anyone have any ideas how I can call movePiece only after the final repaint has happened?
So the die is going so show random numbers for a few times, and then slowly settle on a number. After that is done I would like to call the movePiece() method. However, as it is, the the repaint occurs sporadically and screws everything up so that movePiece() gets called before the dice roll is actually finished animating.
What worries me here is why your painting is occurring sporadically -- it simply shouldn't be doing that, and perhaps that is what you need to fix. I wonder if you're reading in the images from the file each time you do the drawing or some other cause for slowing the drawing down. If you need more help regarding this issue, then you'll have to give us more information on how you do your painting. Regardless, you should avoid having program logic be dependent on painting as you don't have full control over when or even if painting will occur.
Rather than redrawing images and calling repaint(), why not simply put your rolling dice images into ImageIcons on program start up, and then in your Swing Timer, swap icons in a JLabel? Then stop your Timer when the delay gets long enough and in that if block, move your piece.
So, assuming that you have several dice, each can be displayed by a JLabel that is held in an array of JLabel called diceLabels, and the ImageIcons can be held in an array called diceIcons. Then you can do something like:
public void actionPerformed(ActionEvent e) {
if (roll_dice.getDelay() > 500) {
roll_dice.setDelay(50);
roll_dice.stop();
movePiece(); // I like this -- this shouldn't change
} else {
roll_dice.setDelay(roll_dice.getDelay() + 50);
// dice_panel.repaint(0);
for (JLabel dieLabel : diceLabels) {
int randomIndex = random.nextInt(diceIcons.length);
dieLabel.setIcon(diceIcons[randomIndex]);
}
}
}
I like your logic on when you call movePiece() and I think that this should remain unchanged.
You can call the rolling in another thread and join() the current thread to the rolling one. That way the main code will wait until the roll thread dies (finished rolling).
public void actionPerformed(ActionEvent evt) {
if(roll_dice.getDelay() > 500){
Thread rollerThread = new RollerThread();
rollerThread.start();
rollerThread.join();
movePiece();
}
else{
roll_dice.setDelay(roll_dice.getDelay() + 50);
dice_panel.repaint(0);
}
}
private RollerThread extends Thread
{
public void run(){
roll_dice.setDelay(50);
roll_dice.stop();
}
}
However, this might not work with the EDT - because repaints should be scheduled to the queue. Maybe you can shedule the event using the SwingUtilities.invokeAndWait():
public void actionPerformed(ActionEvent evt) {
Thread thread = new Thread(){
public void run(){
if(roll_dice.getDelay() > 500){
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
roll_dice.setDelay(50);
roll_dice.stop();
}
});
movePiece();
}
else{
roll_dice.setDelay(roll_dice.getDelay() + 50);
dice_panel.repaint(0);
}
}
};
thread.start();
}
Does anything change if you put that call to movePiece(); in a SwingUtilities.invokeLater(Runnable);?
if(roll_dice.getDelay() > 500){
roll_dice.setDelay(50);
roll_dice.stop();
SwingUtilities.invokeLater(new Runnable() {
public void run() { movePiece(); }
});
}
...