JFrame skipping some repaint() calls - java

I'm making a snake game and I've encountered an error.
I have tried two different loops: thread.sleep and Timer.schedule.
I have gotten the same problem.
It will be working fine, but at random intervals, it will start to skip every other frame for 6-10 frames.
In case I wasn't clear, 1 frame is
#Override public void paintComponent(Graphics G){...}
being called. (I have also tried paint)
This has occurred in some other games I've created, but not all. What can I do to fix it?
Here's a full copy of the code:
https://github.com/jnmcd/Snake/blob/master/Code.java
EDIT: I've done some debugging. It appears that the it's not a problem with the paint. The JPanel doesn't always update. What can I do to fix it?

I found what I needed to do. I had to add a revaidate() after the repaint().

Also In the checkKillCollisions you have to break the loop right after you found the losing condition.
Also if the game ends it keeps on showing the error message[Dialog] for which there i no end.So I have created a flag gameOver to check is game is over or not in Snake Class
static Boolean gameOver = false;//Defined in Snake Class
public void checkKillCollisions() {
boolean lose = false;
for (int i = 1; i < Snake.segments.size(); i++) {
if (Snake.segments.get(i).x == x && Snake.segments.get(i).y == y) {
lose = true;
break;//Have to do this
}
}
if (x >= 60 || x < 0 || y >= 60 || y < 0) {
lose = true;
}
if (lose) {
Snake.window.popUp("You Lose");
}
Snake.gameOver = lose;//Will set the gameOVer flag in Snake class
}
And I've modified the Loop class to stop running right after the gameOver flag is set to true
class Loop extends TimerTask {
#Override
public void run() {
if (!Snake.gameOver) {
Snake.updates();
Snake.window.render();
} else {
System.out.println("Game Over");
cancel();
Snake.window.dispose();
}
}
}

Related

My program suddenly stops receiving keyboard inputs

This is my first question so I'll just get straight to it.
I've been developing a little 2D platformer game in Java using the Eclipse Neon IDE. I've been able to overcome any issues I've encountered so far except for the one I'm about to tell you.
As game controls usually go, I've set up the WASD keys for movement and the SPACEBAR for jumping. The character I control does respond to the key inputs so I know that this code works, but for some reason after the program has been running for about 3 minutes or so, the character stops receiving key inputs and I get this error:
java.awt.AWTEventMulticaster.keyPressed(Unknown Source)
I've tried fiddling with the code to see if I could fix it myself, but I can't figure out what's causing the problem.
Here's the relevant section of code from my Player class. You probably don't need to pay attention to any of the variables in the keyPressed() and keyReleased() methods, but just the methods themselves:
public void keyPressed(KeyEvent keyID) { //This method checks to see which keys the user has pressed
int key = keyID.getKeyCode();
if (debug == false && key == KeyEvent.VK_F1) {
debug = true;
}
else if (debug == true && key == KeyEvent.VK_F2) {
debug = false;
}
if (death == false) {
if (key == KeyEvent.VK_SPACE && jumping == false) {
//Player.key = 2;
velY = ySpeed;
jumping = true;
Sound.playSound("audio/playerJump.wav");
}
else if (key == KeyEvent.VK_D && rightIntersect == true) {
velX = 0;
lastKeyPressed = 'D';
Player.key = 1;
}
else if (key == KeyEvent.VK_D && rightIntersect == false) {
velX = xSpeed;
lastKeyPressed = 'D';
Player.key = 1;
}
if (key == KeyEvent.VK_A) {
velX = -xSpeed;
lastKeyPressed = 'A';
Player.key = -1;
}
}
else if (key == KeyEvent.VK_R && death == true) {
for (int i = 0; i < GameFrame.getPlayerList().size(); i++) {
Player p = GameFrame.getPlayerList().get(i);
GameFrame.removePlayer(p);
GameFrame.addPlayer(new Player(GameFrame.xPosStart, GameFrame.yPosStart));
death = false;
GameFrame.level = 1;
GameFrame.mainTimer.setInitialDelay(0);
GameFrame.mainTimer.start();
}
}
}
public void keyReleased(KeyEvent keyID) { //This method checks to see which keys the user has released
int key = keyID.getKeyCode();
if (key == KeyEvent.VK_A || key == KeyEvent.VK_D) {
Player.key = 0;
velX = 0;
}
}
And here's the code for my KeyAdapt class that the Player class references:
public class KeyAdapt extends KeyAdapter {
Player p;
public KeyAdapt (Player player) {
p = player;
}
public void keyPressed (KeyEvent keyID) {
p.keyPressed(keyID);
}
public void keyReleased (KeyEvent keyID) {
p.keyReleased(keyID);
}
Again, this code does work. It just suddenly stops working after the program has been running for a certain amount of time.
Does anyone know what might be causing this issue?
(If more information is needed, I can provide the entire code for the Player class).
Does anyone know what might be causing this issue?
It is not possible to say given the code you have shown us.
I suggest that you add some debugging code. For example, add something to keyPressed that logs the event received, and the state of variables such as death, jumping etcetera.
You say:
I get this error:
java.awt.AWTEventMulticaster.keyPressed(Unknown Source)
That looks like part of a line from a stacktrace, not an error message. If this is a stacktrace, you need to show us the entire trace including the exception at the beginning.
Finally, you should not do this:
if (death == false) {
The correct way to write that is:
if (!death) {
It is more concise, but more importantly it is less fragile. Imagine if you had mistyped your version as:
if (death = false) {
One character difference. Easy to overlook. And it completely changes the meaning of the statement. It is a bad idea to use == and != to test boolean variables.
None of code that you showed us breaks because of this, but this bad habit could be used elsewhere in your code, and that might be the source of your problem.

Finch robot programming

I am writing a program where I have to make my finch robot follow an object. I have written it so that the finch will begin by sensing objects around it once it has been tapped on the top. As soon as I tap the top and cover the sensors, a red light is supposed to turn on and it will follow the object in the direction of the covered sensor. While it is moving, it should be making a buzzing sound and have the light change from red to green. When I stop moving the object, the finch is supposed to turn it's nose back to red and wait until it is either tapped twice to end the program or until the object is moved for it to continue following. However, when I tap it, nothing happens.
Here is my code:
import edu.cmu.ri.createlab.terk.robot.finch.Finch;
public class FollowingAnObject
{
static Finch myF = new Finch();
public static void main(String[] args)
{
myF = new Finch();
}
public FollowingAnObject()
{
while (true)
{
//This begins the movement of the finch
if (myF.isTapped() == true && myF.isObstacleLeftSide() == true && myF.isObstacleRightSide() == true && myF.isObstacle() == true)
{
//LED colours are red, green and blue
myF.setLED(R,0,0);
myF.setWheelVelocities(velocityLeft, velocityRight);
//Triggers the RunAgain function to true so that the program does not stop in one run so that the Finch will continue to move
boolean RunAgain = true;
while(RunAgain)
{
//Calling the Move method for the Finch movements
Move();
//Inside the while, RunAgain loop , there is a conditional statement that makes the program terminate if the Finch has been tapped twice
if (myF.isTapped()==true && myF.isTapped()==true)
{
break;
}
}
}
}
}
// Method for all of the Finch movements
public static void Move()
{
if (myF.isObstacleRightSide() == false && myF.isObstacleLeftSide() == false && myF.isObstacle() == true)
{
MoveStraight();
}
else if (myF.isObstacleRightSide() == false && myF.isObstacleLeftSide() == true)
{
MoveLeft();
}
else if ( myF.isObstacleRightSide() == true && myF.isObstacleLeftSide() == false)
{
MoveRight();
}
else if (myF.isObstacleRightSide()==true && myF.isObstacleLeftSide()==true)
{
StopMoving();
}
}
//All of the variables have been declared
static int Buzz = 300;
static int BuzzDuration = 12;
static int R = 250;
static int G = 250;
static int velocityLeft = 150;
static int velocityRight = 150;
static int turnLeft = -50;
static int turnRight = -50;;
//If the finch is moving straight, the light will be green and both of the wheels will move at 150
public static void MoveStraight()
{
myF.setLED(0, G, 0);
myF.setWheelVelocities(velocityLeft, velocityRight);
myF.buzz(Buzz, BuzzDuration);
}
public static void MoveLeft()
{
//If the finch is moving left, the light will be green, the left wheel will move at -50 and the right wheel will move at 150
myF.setLED(0, G, 0);
myF.setWheelVelocities(turnLeft, velocityRight);
myF.buzz(Buzz, BuzzDuration);
}
public static void MoveRight()
//If the finch is moving right, the light will be green the left wheel will move at 150 and the right wheel will move at -50
{
myF.setLED(0, G, 0);
myF.setWheelVelocities(velocityLeft, turnRight);
myF.buzz(Buzz, BuzzDuration);
}
public static void StopMoving()
//if the Finch is not moving, the colour of the light will be red and the buzzing will stop
{
myF.setLED(R, 0 , 0);
myF.stopWheels();
myF.buzz(Buzz, BuzzDuration);
}
}
Your main method is empty. Java starts at main, so you need to start your new Finch in main.

Shoot more than one bullet

I'm having problems with my character shooting. When SPACE button is pressed character shoot one bullet. But when I press SPACE for example twice I should got two bullets shoot from my character. Unfortunately I got only one bullet at the time and when my bullet collides with something (for example wall) only then other second bullet is shooted! I understand than ArrayList update only one bullet at the time and when that bullet is deleted then update another. How I need to get the double (or even more) Bullets effect?
Here is my Player class
public class CoolGuy extends GameObject{
private ArrayList<PlayerBullet> bullets;
/*Tones of code here */
public void shoot(float delta){
if(PlayerBullet.shoot){
if(index != 0){
index++;
}
bullets.add(new PlayerBullet(full.x, full.y + sprite.getHeight()/2 - 30));
}
}
public void update(float delta) {
if(bullets.size() > 0){
if(bullets.get(index) != null){
bullets.get(index).update(delta);
}
for(GameObject t : list){
if(t instanceof Brick){
if(bullets.size() > 0 && bullets.get(index) != null && bullets.get(index).hits(t.getHitBox()) == 1){
bullets.remove(index);
}
}
}
}
}
}
And here's my Bullet class
public class PlayerBullet extends ItemObject{
private Sprite sprite;
private Rectangle full;
public static boolean shoot;
public PlayerBullet(int x, int y){
......
......
}
public int hits(Rectangle r) {
if(full.overlaps(r)){
return 1;
}
return -1;
}
public void update(float delta) {
full.x += (delta * 500);
setPosition(full.x,full.y);
}
}
And here in my main class
player1.update(Gdx.graphics.getDeltaTime());
if(Gdx.input.isKeyJustPressed(Input.Keys.SPACE)){
player1.shoot(Gdx.graphics.getDeltaTime());
}
I can't tell what your index parameter is supposed to be (the stuff you do with it doesn't make any sense to me), but it sure seems to be the source of the problem.
First of all, in the shoot method, you only increment it if it's non-zero, so if it is zero, it will forever be zero.
Then in render you are only updating a single bullet instead of all the bullets in the array.
The clearest solution to me (although again I don't know what you were trying to track with the index parameter) would be to completely remove the index parameter. Then replace ArrayList with libgdx's Array class, which allows fast modification and removal during a loop, and change your render method like this.
public void update(float delta) {
for (int i=bullets.size-1; i>=0; i--) { //count backward for safe removals
PlayerBullet bullet = bullets.get(i);
for(GameObject t : list){
if(t instanceof Brick){
if(bullet.hits(t.getHitBox()) == 1){
bullets.removeIndex(i);
}
}
}
}
}

Loop to change Boolean to false after time?

This should be very simple but I can't seem to work it out.
I want to create a method which will return a boolean false value after a period of time once called.
I have tried for, while and switch statements but none have the desired affect.
REASON: I have an on touch event which which changes a boolean value to activate a game state. I want this value to change back to false after a period of time to avoid the user holding the the touch event to keep the game state indefinitely.
I have tried the below method in my game loop to change the value back false after a period of time. This will be called at the same time as the state activate method is called.
private void stateCounter() {
int count = 100;
for (int i =0; i < count ; i++) {
stateBoolean = true;
}
stateBoolean = false;
}
private void stateCounter() {
int count = 1;
while (count < 100) {
stateBoolean = true;
count++;
}
stateBoolean = false;
}
What is the best way to do this?
use Handler.PostDelayed Method to perform some tasks after an interval. For example
Handler h = new Handler();
h.postDelayed(new Runnable(){
public void run(){
// perform your tasks here
}
},interval);
But One thing is not clear to me. do you want to change the counter when the touch is completed (i,e the finger is up). In that case you can use this
yourButton.setOnTouchListener(new OnTouchListener () {
public boolean onTouch(View view, MotionEvent event) {
else if (event.getAction() == android.view.MotionEvent.ACTION_UP) {
// call the method now
}
}
}

JPanel freezes my whole application when trying to draw on it

I am coding Oregon Trail for a school project and I am implementing the hunting mini game. We are using model view presenter with a card layout. When the HuntingPanel gets switched to it calls run, and the JOptionPane comes up, but then the whole application freezes and I have to force quit. I coded the entire hunting game in a separate project, and just now brought the files over to the Oregon Trail game. It works fine in its own project with its own JFrame. I'm not sure what to do.
I call this to initialize the panel, switch to it, and run the game.
public void initialize(int ammo) {
player.setBullets(ammo);
bulletLabel.setText("Bullets: "+player.getBullets());
presenter.switchToPanel(OregonTrailPresenter.HUNTING_PANEL);
run();
}
This is my run method.
public void run() {
// starting message
JOptionPane.showMessageDialog(null, "You have reached a nearby field to hunt. You will stay\nhere until " +
"you run out of ammunition or click Return to Trail.");
// while the player has bullets or doesn't click return to trail
while (player.getBullets() > 0 && stillHunting) {
// creates random animals
checkForAnimal();
// moves and updates screen
repaint();
update();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
endHunting();
}
And here are other method used.
private void checkForAnimal() {
int x = 0;
int y = rand.nextInt(MAX_Y)-40;
int rand1 = rand.nextInt(100);
String str = null;
if (rand1 < 50) {
str = "left";
x = MAX_X-40;
}
else if (rand1 >= 50) {
str = "right";
x = 0;
}
double gen = rand.nextGaussian(); // gen is a number from -inf to +inf
gen = Math.abs(gen); // gen is now a number from 0 to inf
if (gen >= 1.9 && gen < 2.1) { //1.19%
animalList.add(new Bunny(x,y,str));
}
if(gen >= 2.1 && gen < 2.2) { //0.9%
animalList.add(new Bear(x,y,str));
}
if (gen >= 2.2 && gen < 2.3) {
animalList.add(new Deer(x,y,str));
}
}
public void update() {
for (int i = 0; i < animalList.size(); i++) {
animalList.get(i).move();
}
}
You have to implement javax.swing.Timer instead of Thread.sleep(int), because this code line freezes all GUI during EDT until Thread.sleep(int) ends. Here is demonstrations what happens if the GUI is delayed during EDT by Thread.sleep(int)
Your program "freezes" because you did not start a new thread for the while loop. Since the panel updates and redraws are handled in the main thread, you are preventing them from happening. To fix this problem you have to start a new thread. You can do this by making your class implement runnable and use new Thread(this).start() to run your loop.
class HuntingGame extends JPanel implements Runnable {
public void initialize(int x) {
//...
new thread(this).start();// This will run your 'run()' method in a new thread.
}
}

Categories