I seem to have a problem switching screens in libGDX. It switches to GameScreen, but it doesn't switch back to main screen nor to game over screen.
My game class:
#Override
public void create() {
menu();
}
public void play(){
this.setScreen(new GameSc(this));
play = true;
}
public void menu(){
this.setScreen(new GameMenu(this));
menu = true;
}
public void gameOver(){
this.setScreen(new GameOver(this));
}
My GameScreen class (which implements screen):
public GameSc(GameRunner runner) {
this.runner = runner;
background = new Texture(Gdx.files.internal("Textures/background.png"));
batch = new SpriteBatch();
box = new Box(this);
txt = new Texture(Gdx.files.internal("Textures/Enemies/Boxers/Enemy.png"));
snakes = new ArrayList<Snake>();
enemies = new ArrayList<Enemy>();
shape = new ShapeRenderer();
Gdx.gl.glClearColor(1f, 1f, 1f, 1f);
new Thread(new Runnable() {
#Override
public void run() {
while(true){
update();
}
}
}).start();
snakeThread();
enemyThread();
}
#Override
public void show() {
//initialize
}
#Override
public void resize(int width, int height) {
}
#Override
public void render(float dt) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//Drawing an image.
batch.begin();
batch.draw(background, 0,0 , Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.end();
box.render(batch);
for (int i = 0; i < snakes.size(); i++) {
snakes.get(i).render(shape);
}
for (int i = 0; i < enemies.size(); i++) {
enemies.get(i).render(batch);
}
}
public void update(){
box.update();
for (int i = 0; i < snakes.size(); i++) {
snakes.get(i).update();
}
for (int i = 0; i < snakes.size(); i++) {
if(!(snakes.get(i).isAlive)){
snakes.remove(i);
System.out.println(snakes.size());
}
}
}
private void snakeThread(){
new Thread(new Runnable() {
Random r = new Random();
//float[]anglem = {30,40,50,60,70,80,90,100};
#Override
public void run() {
while(true){
int x = r.nextInt(Gdx.graphics.getWidth()-50);
int y = r.nextInt(Gdx.graphics.getHeight()-50);
int delay = r.nextInt((6000-2000)+1)+2000;
int speed = MathUtils.random(50, 150);
float angle = (float) r.nextInt((110-30)+1)+30;
int length = MathUtils.random(15, 25);
try {
spawnSnake(x, y, angle, length, speed);
//System.out.println(delay);
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
box.update();
}
private void enemyThread(){
new Thread(new Runnable() {
#Override
public void run() {
while(true){
int x = MathUtils.random(Enemy.UNIFORM_WIDTH, Gdx.graphics.getWidth()-Enemy.UNIFORM_WIDTH);
int y = 0;
int speed = 15;
int delay = MathUtils.random(400, 600);
try {
spawnEnemy(x, y, speed, txt);
for (int i = 0; i < enemies.size(); i++) {
if(enemies.get(i).getY()<0){
enemies.remove(i);
}
}
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
box.update();
}
public void spawnSnake(int x, int y, float angle, int length, int speed){
Snake snake = new Snake(angle,new Vector2(x,y),speed,length);
snakes.add(snake);
}
public void spawnEnemy(int x, int y, int speed, Texture currentTexture){
Enemy enemy = new Enemy(x , y , speed, Enemy.UNIFORM_WIDTH, Enemy.UNIFORM_HEIGHT, txt);
enemies.add(enemy);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
if(runner.menu==false){
runner.getScreen().dispose();
shape.dispose();
batch.dispose();
}
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
This is how i change a screen (doesn't work):
if (bounds.contains(g.snakes.get(i).snake.get(y).x, g.snakes.get(i).snake.get(y).y) && isAlreadyTouched) {
isAlreadyTouched = false;
g.runner.play=false;
g.runner.gameOver();
}
You can find the whole source here.
Managed to solve this issue by moving g.runner.setScreen(new GameOver(this)) to another thread.
There are many ways to tackle a problem and I don't want to read through the source you posted but the line you posted does certainly not change the screen.
if (bounds.contains(g.snakes.get(i).snake.get(y).x, g.snakes.get(i).snake.get(y).y) && isAlreadyTouched) {
isAlreadyTouched = false;
g.runner.play=false;
g.runner.gameOver();
}
I'm not sure about the architecture of your source, there might be listener events that get triggered by g.runner.gameOver(); or g.runner.play = false` and then the following solution would create a mess for you eventually.
if (bounds.contains(g.snakes.get(i).snake.get(y).x, g.snakes.get(i).snake.get(y).y) && isAlreadyTouched) {
isAlreadyTouched = false;
g.runner.play=false;
g.runner.gameOver();
//Now set a screen
((Game)Gdx.app.getApplicationListener).setScreen(new GameOver(this);
}
I personally like to work with screens like I did above. Whenever I need to change a screen I cast the ApplicationListener to Game so I can set a new (or push a existing) screen.
But like I said, you might have deleted or not yet implemented code that should call the methods in your Game class to change the screen.
Related
When I use normal JPanel initialized inside main instead of extended class. The button is added to a panel without problem and after launch is displayed in a center of a frame (default layout).
I would like to be able to add buttons inside an extended class. This problem occurs in Screen class aswell, where I need a Play Again button or Next Level button. The Screen is class extended by a JPanel too and JButtons are initialized inside the constructor aswell.
I'm not sure if the wrong part is in way of adding the components or in writing a code for a JPanel.
Here is the code:
Main:
public static void main(String[] args) {
// window - class JFrame
theFrame = new JFrame("Brick Breaker");
// game panel initialization
GamePanel gamePanel = new GamePanel(1);
theFrame.getContentPane().add(gamePanel);
// base settings
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theFrame.setLocationRelativeTo(null);
theFrame.setResizable(false);
theFrame.setSize(WIDTH, HEIGHT);
theFrame.setVisible(true);
}
GamePanel Class:
public class GamePanel extends JPanel {
// Fields
boolean running;
boolean clicked = false;
private int rows = 8, colms = 11, N = rows * colms, level; // numbers of rows and columns
private int colmsC, rowsC;
private BufferedImage image;
private Graphics2D g;
private MyMouseMotionListener theMouseListener;
private MouseListener mouseListener;
private int counter = 0;
// entities
Ball theBall;
Paddle thePaddle;
Bricle[] theBricks;
Screen finalScreen;
public GamePanel(int level) {
// buttons
JButton pause = new JButton(" P ");
add(pause);
this.level = level;
init(level);
}
public void init(int level) {
// level logic
this.rowsC = level + rows;
this.colmsC = level + colms;
int count = rowsC * colmsC;
thePaddle = new Paddle();
theBall = new Ball();
theBall.setY(thePaddle.YPOS - thePaddle.getHeight() + 2);
theBall.setX(thePaddle.getX() + thePaddle.getWidth() / 2 - 5);
theBricks = new Bricle[count];
theMouseListener = new MyMouseMotionListener();
addMouseMotionListener(theMouseListener);
mouseListener = new MyMouseListener();
addMouseListener(mouseListener);
// make a canvas
image = new BufferedImage(BBMain.WIDTH, BBMain.HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// specific Bricks initialized
int k = 0;
for (int row = 0; row < rowsC; row++) {
for (int col = 0; col < colmsC; col++) {
theBricks[k] = new Bricle(row, col);
k++;
}
}
running = true;
}
public void playGame() {
while (running) {
//update
if (clicked) {
update();
}
// draw
draw();
// display
repaint();
// sleep
try {
Thread.sleep(20);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// update loop ( like playGame )
public void update() {
// ball moving
checkCollisions();
theBall.update();
}
public void draw() {
// background
g.setColor(Color.WHITE);
g.fillRect(0,0, BBMain.WIDTH, BBMain.HEIGHT-20);
// the bricks
int k = 0;
for (int row = 0; row < rowsC; row++) {
for (int col = 0; col < colmsC; col++) {
theBricks[k].draw(g, row, col);
k++;
}
}
// the ball and the paddle
theBall.draw(g);
thePaddle.draw(g);
// counter
String countString = new Integer(this.counter).toString();
g.drawString(countString, 20, 20);
// WIN / LOOSE SCREEN
if (this.counter == this.N * 20) {
win();
}
if (theBall.getRect().getY() + theBall.getRect().getHeight() >= BBMain.HEIGHT) {
loose();
}
}
public void paintComponent(Graphics g) {
// retype
Graphics2D g2 = (Graphics2D) g;
// draw image
g2.drawImage(image, 0, 0, BBMain.WIDTH, BBMain.HEIGHT, null);
// dispose
g2.dispose();
}
public void pause() {
this.running = false;
finalScreen = new Screen(this.level, counter);
finalScreen.draw(g,"GAME PAUSED");
}
public void win() {
this.running = false;
finalScreen = new Screen(this.level, counter);
finalScreen.draw(g,"YOU WIN");
}
public void loose () {
this.running = false;
finalScreen = new Screen(this.level, counter);
finalScreen.draw(g,"YOU LOOSE");
}
public void addScore() {
this.counter += 20;
theBall.setDY(theBall.getDY() - 0.001);
}
// Mouse Listeners
private class MyMouseListener implements MouseListener {
#Override
public void mouseClicked(MouseEvent e) {
clicked = true;
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
private class MyMouseMotionListener implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
if (clicked)
thePaddle.mouseMoved(e.getX());
}
}
}
This question already has answers here:
Can I start a thread again after it has died?
(5 answers)
Closed 6 years ago.
I am creating a demo game in Android for learning purposes. In the game, when a collision is detected between two objects - I want to show a "game over" dialog. Inside the dialog box there is a play again button. When pressed, the thread should be started again.
I am getting the following error java.lang.IllegalThreadStateException: Thread already started .
Here is my code:
public class GamePanel extends SurfaceView implements Runnable {
private Thread thread = null;
private Ball ball;
private SurfaceHolder surfaceHolder;
private Paint paint;
private Canvas canvas;
volatile boolean playing = true;
private int hurdleCount = 3;
private Hurdles[] hurdles;
private int screenX, screenY;
private Rect ball_detectCollision;
public GamePanel(Context context, final int screenX, final int screenY) {
super(context);
ball = new Ball(context, screenX, screenY);
surfaceHolder = getHolder();
this.screenX = screenX;
this.screenY = screenY;
paint = new Paint();
canvas = new Canvas();
hurdles = new Hurdles[hurdleCount];
for (int i = 0; i < hurdleCount; i++) {
hurdles[i] = new Hurdles(context, screenX, screenY);
}
ball_detectCollision = new Rect(ball.getBall_x(), ball.getBall_y(), ball.getBitmap().getWidth(), ball.getBitmap().getHeight());
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("Surface Created");
setUpdated_x(ball.getBall_x());
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
System.out.println("Surface Changed");
thread = new Thread(GamePanel.this);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("Surface Destroyed");
}
});
}
public int getUpdated_x() {
return updated_x;
}
public void setUpdated_x(int updated_x) {
this.updated_x = updated_x;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
setUpdated_x((int) event.getX());
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_DOWN:
initial_X = getUpdated_x();
break;
case MotionEvent.ACTION_MOVE:
if (getUpdated_x() < screenX - ball.getBitmap().getWidth() || getUpdated_x() > screenX - ball.getBitmap().getWidth()) {
draw(getUpdated_x());
}
break;
}
return true;
}
private void draw(int updatedValue) {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.RED);
canvas.drawBitmap(ball.getBitmap(), updatedValue, ball.getBall_y(), paint);
ball.setBall_x(updatedValue);
ball_detectCollision.left = ball.getBall_x();
ball_detectCollision.top = screenY - ball.getBitmap().getHeight() - 260;
ball_detectCollision.right = ball.getBall_x() + ball.getBitmap().getWidth();
ball_detectCollision.bottom = screenY - ball.getBitmap().getHeight() - 260 + ball.getBitmap().getHeight();
for (int i = 0; i < hurdleCount; i++) {
canvas.drawBitmap(hurdles[i].getBitmap(), hurdles[i].getX(), hurdles[i].getY(), paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
#Override
public void run() {
while (playing) {
update();
draw(getUpdated_x());
control();
}
}
private void update() {
for (int i = 0; i < hurdleCount; i++) {
hurdles[i].update();
if (Rect.intersects(getBall_detectCollision(), hurdles[i].getDetectCollision())) {
System.out.println("Collision Detected");
playing = false;
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
showGameOverMessage();
}
});
}
}
}
public void pause() {
playing = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void showGameOverMessage() {
Toast.makeText(getContext(), "Game Over", Toast.LENGTH_SHORT).show();
Dialog showDialog = new Dialog(getContext());
showDialog.setContentView(R.layout.dialog_game_over);
Button playAgainButton = (Button) showDialog.findViewById(R.id.playAgainButton);
playAgainButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
playing = true;
thread.start();
}
});
showDialog.show();
}
}
You can't restart a stopped thread. The solution is to simply instantiate a new one and start it.
When the game is over, just stop the thread and play again button should kick a new thread.
If you need to save any instance of your previous thread, do save them in external variables. There are plenty of options in this case anyway.
Edit
You stopped your thread perfectly. You just have to start a new thread when you want the new game to be started.
I would suggest to keep a function like this and remove implements Runnable.
private void startGame() {
// Start a new game
playing = true;
Thread thread = new Thread() {
#Override
public void run() {
try {
while (playing) {
update();
draw(getUpdated_x());
control();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
I'm trying to make a small app that bounces balls around the frame of the window. When I add more than 1 ball to the list; it doesn't loop through them as expected.
Here's my code:
The Main Class:
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private List<Ball> balls = new ArrayList<Ball>();
private List<Ball> tempballs = new ArrayList<Ball>();
private static Timer t;
public void addBall(Ball b) {
tempballs.add(b);
}
public void initUI() {
this.setSize(500, 500);
this.setDefaultCloseOperation(3);
this.setVisible(true);
}
private BufferStrategy bs;
private Random r = new Random();
public void paint() {
if (!tempballs.isEmpty()) {
balls.addAll(tempballs);
tempballs = new ArrayList<Ball>();
}
int i = 0;
System.out.println(balls.size());
for (Ball b : new ArrayList<Ball>(balls)) {
i++;
System.out.println(i);
if ((bs = this.getBufferStrategy()) == null) {
this.createBufferStrategy(2);
return;
}
if (bs.contentsLost() || bs.contentsRestored()) {
return;
}
if (b.y >= this.getHeight() - 100) {
b.ydirection = -r.nextDouble() * 5;
}
if (b.y < 20) {
b.ydirection = r.nextDouble() * 5;
}
if (b.x >= this.getWidth() - 100) {
b.xdirection = -r.nextDouble() * 5;
}
if (b.x < 0) {
b.xdirection = r.nextDouble() * 5;
}
b.x += b.xdirection;
b.y += b.ydirection;
if (b.xdirection > 0)
b.xdirection += 0.1;
else
b.xdirection += -0.1;
if (b.ydirection > 0)
b.ydirection += 0.1;
else
b.ydirection += -0.1;
Graphics g = bs.getDrawGraphics();
g.fillOval((int) b.x, (int) b.y, 100, 100);
bs.show();
g.dispose();
bs.dispose();
}
i = 0;
}
public static void main(String[] args) {
try {
final Main m = new Main();
m.addMouseListener(new Mouse(m));
m.initUI();
t = new Timer();
TimerTask tt = new TimerTask() {
#Override
public void run() {
m.paint();
}
};
t.schedule(tt, Calendar.getInstance().getTime(), 20);
} catch (ConcurrentModificationException e) {
e.printStackTrace();
}
}
}
Here's the Ball class:
public class Ball {
private Random r = new Random();
public double y, x, ydirection, xdirection;
public Ball(int x, int y) {
this.y = y;
this.x = x;
ydirection = r.nextGaussian() * 5;
xdirection = r.nextGaussian() * 5;
}
}
and the mouse listener:
public class Mouse implements MouseListener {
Main m;
public Mouse(Main m) {
this.m = m;
}
#Override
public void mouseClicked(MouseEvent e) {
m.addBall(new Ball(e.getX(), e.getY()));
System.out.println("cl");
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
Additional details:
It only loops through the first item in the list, but the list size grows.
I'm using java 6, but I will change versions if needed.
If your loop does not behave as intended, try to find out why it is cancelled. You have two return statements in your loop which could cause this behavior. Make sysouts before those returns to figure out which one is the cause. Then find out why your if around the return is true. To digg deeper you can use your IDE's debugging mode and place breakpoints at interesting lines or use the step mode to run one line of code at a time.
Besides this you can place both if before the loop, the values they are checking should not change while you are in the paint() function (you are using the UI thread which might change them).
You have below return statements inside the loop. If the execution reaches any of the return statements, the loop ends.
Figure out, if you are entering these conditions and returning for the first value in the list.
if ((bs = this.getBufferStrategy()) == null) {
this.createBufferStrategy(2);
return;
}
if (bs.contentsLost() || bs.contentsRestored()) {
return;
}
// playerBall extends Animate class
//Even after entity becomes invisible,collision is detected
Collision occurs at the point where entity was before getting detached.
private void ballsR(){
registerUpdateHandler(new FPSLogger());
Random r = new Random();
int i= r.nextInt(7)+1;
if(count<1){
ballForColl[0] = ball;
count++;
System.out.println(count);
}
registerUpdateHandler(this.ballsDet = new TimerHandler(5.0f,true, new ITimerCallback() {
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
// TODO Auto-generated method stub
/* ball.setVisible(false);
ball.setIgnoreUpdate(true);
ball.detachSelf();
ball.clearUpdateHandlers();
#override*/
resourcesManager.engine.runOnUpdateThread(new Runnable() {
#Override
public void run() {
/* Now it is save to remove the entity! */
//pScene.detachChild(SpriteRemoveExample.this.mFaceToRemove);
detachChild((ball));
ball.setIgnoreUpdate(true);
}
});
// detachChild(ball);
// unregisterUpdateHandler(ball) ;
}
}));
/************************************************************/
//my player ball class
public playerBall(final float pX, final float pY, final TiledTextureRegion pTextureRegion,VertexBufferObjectManager vbom) {
super(pX, pY, pTextureRegion,vbom);
this.mPhysicsHandler= new PhysicsHandler(this);
this.registerUpdateHandler(this.mPhysicsHandler);
this.mPhysicsHandler.setVelocity(DEMO_VELOCITY, DEMO_VELOCITY);
// System.out.println("this is srs1");
}
#Override
protected void onManagedUpdate(final float pSecondsElapsed) {
if(this.mX < 0) {
// System.out.println("this is srs");
this.mPhysicsHandler.setVelocityX(DEMO_VELOCITY);
} else if(this.mX + this.getWidth() > 800) {
this.mPhysicsHandler.setVelocityX(-DEMO_VELOCITY);
}
if(this.mY < 0) {
this.mPhysicsHandler.setVelocityY(DEMO_VELOCITY);
} else if(this.mY + this.getHeight() > 480) {
this.mPhysicsHandler.setVelocityY(-DEMO_VELOCITY);
}
super.onManagedUpdate(pSecondsElapsed);
}
}
What is "ball"? is it an Sprite, AnimatedSprite, Circle...
Does it contain a Body?
If the latter is true, you're probably forgetting to remove it from the physics world...
Try this:
final PhysicsConnector physicsConnector =
physicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(shape);
mEngine.runOnUpdateThread(new Runnable()
{
#Override
public void run()
{
if (physicsConnector != null)
{
physicsWorld.unregisterPhysicsConnector(physicsConnector);
body.setActive(false);
physicsWorld.destroyBody(bbody);
scene.detachChild(shape);
}
}
});
I am trying to get my circle to move so I can keep devolping my small applet game for school, but for some reason Its not moving and I can not figure out why.
public class StartingPonit extends Applet implements Runnable{
int x = 0;
int y = 0;
int dx = 1;
int dy = 1;
int radis = 20;
private Image i;
private Graphics doubleG;
#Override
public void init() {
setSize(800,600);
}
#Override
public void start() {
Thread thread = new Thread(this);
thread.start(); // thread info;
}
#Override
public void run() {
x =+ dx;
y =+ dy;
//thread info
while (true){
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException ex) {
Logger.getLogger(StartingPonit.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
#Override
public void stop() {
}
public void destory() {
}
#Override
public void update(Graphics g) {
if(i == null){
i = createImage(this.getSize().width,getSize().height); //double bbuffering
doubleG = i.getGraphics();
}
doubleG.setColor(getBackground());
doubleG.fillRect(0,0, this.getSize().width,this.getSize().height);
doubleG.setColor(getForeground());
paint(doubleG);
g.drawImage(i, 0, 0, this);
}
#Override
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.fillOval(x-radis, y-radis, radis*2, radis*2); //size of object
}
}
You aren't updating x and y in your loop
//thread info
while (true){
repaint();
x += dx;
y += dy;
//rest the same
}
You have also mispelt destroy() -- public void destory() -- should be public void destroy()