I'm trying to implement a functionality within a game that I've made where if you press a button, the car will auto complete a lap of the track without any user input.
To do this, I've created functions for each direction of movement.
I needed to create a delay between each function call, otherwise it'll complete the lap the instant I press the button to initialise it. I've added the following:
public void driveCar()
{
Timer t = new Timer(1000 * 1, new ActionListener() {
public void actionPerformed(ActionEvent e) {
move(MOVE_RIGHT);
move(MOVE_DOWN);
}
});
t.start();
}
If I only have the MOVE_RIGHT, it'll act as a loop and continuously run this method and move one space to the right every second however, I'm trying to make it so that it'll move one step to the right once, and then one step downwards. Currently, it's just moving diagonally every tick.
How can I implement a solution that carries out each call as if it's a list of instructions?
If you want the action of the timer to alternately move right or move down on each tick, you need a field tracking the progress:
Timer t = new Timer(1000 * 1, new ActionListener() {
private boolean moveRight = true;
public void actionPerformed(ActionEvent e) {
if (moveRight)
move(MOVE_RIGHT);
else
move(MOVE_DOWN);
moveRight = ! moveRight;
}
});
If you have more than two different actions, you can use a step counter:
Timer t = new Timer(1000 * 1, new ActionListener() {
private int step = 0;
public void actionPerformed(ActionEvent e) {
switch (step) {
case 0:
move(MOVE_RIGHT);
break;
case 1:
move(MOVE_DOWN);
break;
case 2:
move(MOVE_UP);
break;
}
step = (step + 1) % 3;
}
});
UPDATE: If you want to walk a specific path, use an array:
final int[] path = { MOVE_RIGHT, MOVE_DOWN, MOVE_UP, MOVE_UP, MOVE_LEFT, MOVE_DOWN };
Timer t = new Timer(1000 * 1, new ActionListener() {
private int step = 0;
public void actionPerformed(ActionEvent e) {
move(path[step]);
step = (step + 1) % path.length;
}
});
Related
I need the text of the button to be 16 at first. As the button is clicked, it needs that 16 to half, and half again and again when it is clicked and when it gets to 1, it needs to stay to 1.
int n=16;
JButton button4 = new JButton(String.valueOf(n));
frame.add(button4);
button4.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button4.setText(String.valueOf(n/2));
}
});
So far I tried this, but it just gets to 8, and nothing more.
I added the frame, and that stuff I just need this button figured out
The code below will continually divide n in half until it reaches 1 and then remain there.
int n=16;
JButton button4 = new JButton(String.valueOf(n));
frame.add(button4);
button4.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button4.setText(String.valueOf(n));
if( n > 1)
n = n / 2;
}
});
Ensure that you define n outside of the method in the class header.
The main issue is that you do not modify n. So you just keep setting the text to 16 / 2 = 8
You could modify n (ex: n /= 2) or you could read the button's text, convert to int, halve it, set the button's text to that. No need for n.
button4.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
JButton b = (JButton)e.getSource();
int n = Integer.parseInt(b.getText());
if (n > 1) {
b.setText(String.valueOf(n / 2));
}
}
catch (Exception ex) {}
}
});
This code can be reused for any button.
I'm making a Simon game, while doing it, I created an method that called "Computer" that is activated when the game is starting and after that, every time after the player successes to repeat the sequence.
Here is the code:
private void Computer(){
rounds.setText("Round " + index);
new CountDownTimer(500, 500) {
public void onTick(long millisUntilFinished) {
}
public void onFinish()
{
ResetArray(Player);
//Pushing buttons
Red.setClickable(false);
Blue.setClickable(false);
Green.setClickable(false);
Yellow.setClickable(false);
for (int i = 0; i < index; i++)
{
final Handler handler = new Handler();
final int temp=Game[i];
if (temp == 0)
{
Red.setImageResource(R.drawable.red1);
handler.postDelayed(new Runnable() {
#Override
public void run()
{
StartSound(red);
Red.setImageResource(R.drawable.red);
}
}, 100);
}
if (temp == 1)
{
Green.setImageResource(R.drawable.green1);
handler.postDelayed(new Runnable() {
#Override
public void run() {
StartSound(green);
Green.setImageResource(R.drawable.green);
}
}, 100);
}
if (temp == 2)
{
Blue.setImageResource(R.drawable.blue1);
handler.postDelayed(new Runnable() {
#Override
public void run() {
StartSound(blue);
Blue.setImageResource(R.drawable.blue);
}
}, 100);
}
if (temp == 3)
{
Yellow.setImageResource(R.drawable.yellow1);
handler.postDelayed(new Runnable() {
#Override
public void run() {
StartSound(yellow);
Yellow.setImageResource(R.drawable.yellow);
}
}, 100);
}
}
Red.setClickable(true);
Blue.setClickable(true);
Green.setClickable(true);
Yellow.setClickable(true);
}
}.start();
}
So basically, what iv'e done here is a short delay, of 500 milliseconds, and then it is starting with the self "pushing". This is for create some space between the beginning of the game/starting a new round.
Index- round number.
Game- an array that iv'e created, where there is 50 random numbers which presents the sequence, every round i'm adding one for the index.
Red, Green, Blue, Yellow - References for ImageButtons.
The handler delay is to give some time between the button pressing (which presented by switching the image resource to a same color but brighter, that gives the effect of pressing a button) and un-press it, without it, the changing will be so fast so the player will not be able to see any graphical change.
Basically I need a way to stop the program for a while between each pushing. I need a delayer that will delay the loop every time at it's beginning. The countdowntimer and the Handler are not suitable because the program keeps "running" after the declaring and setting those, the only effect is that the buttons are pushed together but in a delay, which is not what I need.
The result now is that the buttons are seems pushed together and I need to separate their pushing in some way.
Iv'e tried everything, and I could not find nothing.
Thanks,
Ziv.
Using a Handler and postDelayed(...) IS exactly what you need but you're a approaching it wrong.
Basically what you are doing is running through your for loop almost instantly and at each loop you're calling postDelayed(...) with a delay of 100ms.
I'll explain further - suppose index is 4 and it only takes 1ms to go through each run of the for loop. When the 4 runs of the loop are complete you'll have 4 postDelayed events with times of 100ms, 99ms, 98ms & 96ms - - to all intents and purposes, when they trigger they all appear to trigger at once.
One easy way around this with your code is to increase each delay based on the loop count...
int delayTime;
for (int i = 0; i < index; i++)
{
delaytime = (i + 1) * 100;
final Handler handler = new Handler();
final int temp=Game[i];
if (temp == 0)
{
Red.setImageResource(R.drawable.red1);
handler.postDelayed(new Runnable() {
#Override
public void run()
{
StartSound(red);
Red.setImageResource(R.drawable.red);
}
}, delayTime); // NOTE USING delayTime AS THE DELAY
}
//
// REPEAT THE ABOVE CODE FOR BLUE, GREEN & YELLOW HANDLER DELAYS
}
In other words when i=0, delayTime will be 100ms, when i=1, delayTime is 200ms etc etc
probably you want to sleep the thread for 500 milliseconds, then you can do this to slept your thread.
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I'm working on a grapher that gets an expression like x^2 + t from the user and then will ask the user for range of x and t .
t in here is the timer variable.
so in x^2 + t the user for example will choose the -10 to 10 for x and 1 to 5 for t . now by clicking the draw button in GUI program the code will start plotting the expression from minimum t (1 in here) and after each second(or any time period) will increase the t value by one and draw the expression with new t (2 ,3 until it reaches the maximum range).
how can make the event handler to do this? I have found a way to draw multiple graphs but I can't make a delay so the minimum to maximum .
I know I should use timer but I don't know how to use in this part of the code
the Link for the whole code
this is the part of code in plotter class that should be changed :
// Grapher
drawButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try {
String testSpring = null;
String tVarString = null;
for (int i = 0; i < 5; i++) {
testSpring = inputExpression;
tVarString = String.valueOf(i);
testSpring = testSpring.replaceAll("t", tVarString);
Equation equation = new Equation(testSpring);
graph.addEquation(equation);
}
}
catch (EquationSyntaxException e) {
e.printStackTrace();
}
}
});
This is the picture of the program :
my priority is to make the program run just by clicking draw button
but It would be better if this timer could be influence JSlider
so the min and max of t would be min and max of Jslider and by clicking draw it would start drawing by every time slider knob would point at a value for t
Take a look at How to use Swing Timers
This will allow you to setup a callback at a regular interval, which is executed from within the context of the EDT, making it safe to update the UI from within
public void actionPerformed(ActionEvent arg0) {
Timer timer = new Timer(1000, new ActionListener() {
private int iteration;
#Override
public void adtionPerformed(ActionEvent evt) {
try {
String testSpring = null;
String tVarString = null;
testSpring = inputExpression;
tVarString = String.valueOf(iteration);
testSpring = testSpring.replaceAll("t", tVarString);
Equation equation = new Equation(testSpring);
graph.addEquation(equation);
} catch (EquationSyntaxException e) {
e.printStackTrace();
} finally {
iteration++
if (iteration > 4) {
((Timer)evt.getSource()).stop();
}
}
}
});
timer.start();
}
});
I'm making a snake game(for those who don't know) where the snake is controlled by an AI using different algorithms to catch the food. The difference with the regular game is that the snake doesn't move unless a command has been sent by the AI.
My problem is that as soon as I run the AI, the AI creates a stack of commands to be executed to catch the food but my GUI just freezes; probably because it can't keep up with the amount of repaints that the move stacks cause. Through console logs, I can see that AI and the game logic is still running.
I tried to do Thread.sleep() after each move but I guess this just makes the entire program including the GUI sleep. I also have a Timer for my paintComponent but that doesn't seem to change anything.
How can you make your program sleep so that the GUI can catch up to what's happening?
EDIT:
Ok guys, I tried your solutions and it's still not working as it should. I don't really want to just dump the code here but I'm really lost. I have a timer that should repaint on a 140 millisecond interval(that's the value of DELAY), the commands are sent on a different thread which goes to sleep after each key press for 1000 milliseconds and I call repaint() after each call to move()... Here is relevant code(the original code without my modifications here):
private void initGame() {
dots = 5;
for (int z = 0; z < dots; z++) {
x[z] = 50 - z * 10;
y[z] = 50;
}
locateApple();
for (int k = blockNb - 1; k > 0; k--) {
locateBlock(k, apple_x, apple_y);
}
if (blocks) {
locateBlock(0, apple_x, apple_y);
}
timer = new Timer(DELAY, this);
timer.start();
startAi();
}
// AI CONTROLLER
public void startAi() {
Ai theAi = new Ai();
String move = "";
switch (ai) {
case "BFS":
move = theAi.bfs(this);
break;
}
//AI returns a string where each char is a move command
autoMove(move);
}
public void autoMove(String move) {
try {
Robot robot = new Robot();
System.out.println(move);
if (move != "#No") {
Thread thread = new Thread(new Runnable() {
public void run() {
for (int j = 0; j < move.length(); j++) {
if (move.charAt(j) == 'l') {
robot.keyPress(KeyEvent.VK_LEFT);
robot.keyRelease(KeyEvent.VK_LEFT);
}
if (move.charAt(j) == 'r') {
robot.keyPress(KeyEvent.VK_RIGHT);
robot.keyRelease(KeyEvent.VK_RIGHT);
}
if (move.charAt(j) == 'u') {
robot.keyPress(KeyEvent.VK_UP);
robot.keyRelease(KeyEvent.VK_UP);
}
if (move.charAt(j) == 'd') {
robot.keyPress(KeyEvent.VK_DOWN);
robot.keyRelease(KeyEvent.VK_DOWN);
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
thread.run();
}
} catch (AWTException e) {
e.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
private void doDrawing(Graphics g) {
if (inGame) {
g.drawImage(apple, apple_x, apple_y, this);
for (int j = 0; j < blockNb; j++) {
g.drawImage(block, block_x[j], block_y[j], this);
}
for (int z = 0; z < dots; z++) {
if (z == 0) {
g.drawImage(head, x[z], y[z], this);
} else {
g.drawImage(ball, x[z], y[z], this);
}
}
Toolkit.getDefaultToolkit().sync();
} else {
// gameOver(g);
}
}
private void move() {
for (int z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}
if (leftDirection) {
x[0] -= DOT_SIZE;
}
if (rightDirection) {
x[0] += DOT_SIZE;
}
if (upDirection) {
y[0] -= DOT_SIZE;
}
if (downDirection) {
y[0] += DOT_SIZE;
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (inGame) {
repaint();
}
}
private class TAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) {
leftDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) {
rightDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_UP) && (!downDirection)) {
upDirection = true;
rightDirection = false;
leftDirection = false;
}
if ((key == KeyEvent.VK_DOWN) && (!upDirection)) {
downDirection = true;
rightDirection = false;
leftDirection = false;
}
move();
checkApple();
checkCollision();
repaint();
}
}
EDIT 2: Also, I just wanted to point out that I tried to move without relying on a robot but to no avail.
Part 1:
Difference bettween Thread.sleep:
When you use it in main Thread(the Thread which java use to run the program)
then your whole program just freeze for that reason.
When you use A Thread for example(follow code)
new Thread(new Runnable(){
public void run(){
//do something...
while(flag==false)
Thread.sleep(a given time) //it need and try catch
else
//do your move
});
then only this Thread freeze (for a given time) or (Whatever you transform it to freeze).
In your case you can use a flag so every time a commant is hitten by user
the flag is going true and then again false to keep stopped the part of the
game you want but the main Thread your programms need to work still works
(if it is a window or anything...)
Part 2:(Basic form of your Thread)(The flag i use must be seen by all Methods)(public or private)
new Thread(new Runnable() {
public void run() {
flag=true;
while(flag==true){
if(move.equals("yes")){
//your code
move="no";
}else
Thread.sleep(20); //Sleep For a While(and then check again)
}
//That means that your Thread will run all over your game
//until game over (when game over just do the flag=false;)
//and The Thread will stop-exit
}});
*About Repaint Method(Dont call the repaint method too fast)
Call it only when the player make a move(this is the time that the frame
need to be repainted[Ok if you have .gif images in your game just dont see this]
Part 3:(When i made a similar game what i did)
Before some months i tried a similar game.The basic idea was a player who must past a labirinth so....
For each level i had one class like this...
public abstarct class Level2(){
//The game was into a panel like your.
//Here i added .setFocusable and .addKeyListener to panel
//Here it was an
public void actionListener(){
//The actionListener checked if the player found the door(for next level)
//Here it was the repaint so every time something happened repaint()
repaint();
}//End of Action Listener
//Use the paint or paintComponent what you need..
public void paint[or paintComponent](Graphics g){
//the 'squares' and the icons the had to be *repainted* again
}
//Here i had an extra class into this for the KeyListeners
//And I added the KeyListener like your game(up,down,left,right)
//I i said before i added this KeyListener to the panel
private class TAdapter extends KeyAdapter {
//KeyPressed,Released...etc
}
}
Thats the basic idea and for your game i think.
The Thread it's an extra option i can't help more you must find the way...
You should have a single "update" looped, from which your execute update commands and repaint request.
A simple approach would be to use a Swing Timer, which can trigger updates to a listener at regular intervals. It has the benefit of been triggered within the context of the EDT making it safe to update the UI from within. See How to use Swing Timers for more details
A more complex approach would be to use a Thread, which contained some kind of loop. This would perform the required updates and schedule repaint, but you'd need to insert Thread.sleep in to allow time for the updates to occur at a regular bases. The problem with this is you will need to synchronise your updates so that you don't update the model while painting is occurring as well synchronise you updates to the UI with the EDT
You need to have some sort of game scheduler loop and an understanding of how it works.
Here is some example code for java swing:
http://staticvoidgames.com/tutorials/swing/swingTimers
Another way to simplify things along with the scheduler is to make your game turn based at first. That is when the player moves 1turn (ie input) the game does all its processing and blocks on user input till the processing is done (ie single loop).
Every time your game AI outputs a new move, you need to call paint, but you also need to wait for whatever event is called when the painting is done before you output your next move, and you may want to wait like a second longer or something, play around with it
pseudo code
def fun 0 // entry point for program
// hook paint done event to func 1
call fun 2
def fun 1 // event handler method for when painting done
call fun 2
def fun 2 // function that does AI work
// do game logic
// call paint
The idea of my program is to select one name from a list that saved before in other JFrame. I'd like to print in the label all names one after the other with small delay between them, and after that stop at one of them. The problem is that lbl.setText("String"); doesn't work if there is more than one setText code.
Here is the part of my code :
public void actionPerformed(ActionEvent e)
{
if (RandomNames.size != 0)
{
for (int i = 0; i < 30; i++)
{
int rand = (int)(Math.random() * RandomNames.size);
stars.setText(RandomNames.list.get(rand));
try
{
Thread.sleep(100);
}
catch (InterruptedException err)
{
err.printStackTrace();
}
}
int rand2 = (int)(Math.random() * RandomNames.size);
stars.setText(RandomNames.list.get(rand2));
RandomNames.list.remove(rand2);
RandomNames.size = RandomNames.list.size();
}
if (RandomNames.list.size() == 0)
{
last.setText("\u062A\u0645 \u0638\u0647\u0648\u0631 \u062C\u0645\u064A\u0639 \u0627\u0644\u0623\u0633\u0645\u0627\u0621 \u0627\u0644\u062A\u064A \u0641\u064A \u0627\u0644\u0642\u0627\u0626\u0645\u0629 !");
}
}
Don't use a loop or Thread.sleep. Just use a javax.swing.Timer. The following will cause 30 iterations occurring every 1000 milliseconds. You can adjust the code in the actionPerformed accordingly to what you wish to happen every so many milliseconds.
int count = 0;
...
Timer timer = new Timer(1000, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
if (count == 30) {
((Timer)e.getSource()).stop();
} else {
int rand = (int) (Math.random()* RandomNames.size);
stars.setText(RandomNames.list.get(rand));
count++;
}
}
});
timer.start();
If you want you can just set up the Timer in the constructor, and start() it in the actionPerformed of another button's listener.
See more at How to use Swing Timers