A newbie question. I have the following piece of Java code:
import acm.program.*;
import java.awt.Color;
import acm.graphics.*;
public class ufo extends GraphicsProgram{
private GRect ufo_ship;
boolean hasNotLost;
public void run (){
setup(); //places ufo_ship to initial position
hasNotLost = ufo_ship.getY() < 200; //checks if ufo_ship is
//above the bottom edge of window
while(hasNotLost){
move_ufo(); //moves ufo_ship
}
showMessage(); //shows that program ended
}
//remaining methods are here
}
When I run this code, the rectangle ufoship does not stop when it reaches the bottom of the window. I assume, that it's because it checks position of the ufoship only once, and not every time the rectangle moves.
Is there any way to correct it without writing simply while(ufo_ship.getY() < 200)?
hasNotLost = ufo_ship.getY() < 200; <- Does not assign expression to the variable, but the value to which that expression is being computed, so it of course is computed only once. You can extract it to other method
boolean hasNotLost(GRect ufo_ship){ return ufo_ship.getY() < 200; }
while(hasNotLost(ufo_ship))
{
...
}
ufo could have own class and that method so you would just call while(ufoShip.hasNotLost())
There is a number of ways you could do this, one of which you have highlighted in your question:
while(ufo_ship.getY() < 200)
You could also do:
while(hasNotLost) { move_ufo(); hasNotLost = ufo_ship.getY() < 200; }
Or could pass hasNotLost by reference into move_ufo() and do the check at the end of move_ufo(), or you could even integrate the check into move_ufo, and return false from it, so you could simply say:
while(move_ufo()) {}
while(hasNotLost){
move_ufo(); //moves ufo_ship
hasNotLost = ufo_ship.getY() < 200; //checks if ufo_ship is
//above the bottom edge of window
}
No, in your example code, you evaluate hasNotLost once and use that (now static) value in the while statement. It will always be true (as evaluate initially)
The proper solution is indeed
while(ufo_ship.getY() < 200) {
move_ufi();
}
or extract a method an do something like
while(ufoStillOnScreen(ufo)) {
move_ufi();
}
and evaluate the position in that extracted method.
Related
This function should check if the explosion hit a box and should be canceled on the first box it hits.
For example bsp.getBomb().getStrength() is currently 2, when a box is hit i=3, but the loop is executed one more time even if the condition isn't met, why is that?
public void detectBomb(BombSpritePair bsp) {
for(int i = 0; i <= bsp.getBomb().getStrength(); i++) {
if(bd.detect(bsp.getBomb().getX(), bsp.getBomb().getY()+i)) {
Sprite sprite = new Sprite(new Texture("gras.png"));
sprite.setPosition(bsp.getBomb().getX()*16, (bsp.getBomb().getY()+i)*16);
// i = bsp.getBomb().getStrength()+1;
sprites.add(sprite);
System.out.println("RIP"+i);
System.out.println(bsp.getBomb().getStrength());
break;
}
}
}
Try adding break to the loop:
public void detectBomb(BombSpritePair bsp) {
for(int i = 0; i <= bsp.getBomb().getStrength(); i++) {
if(bd.detect(bsp.getBomb().getX(), bsp.getBomb().getY() + i)) {
Sprite sprite = new Sprite(new Texture("gras.png"));
sprite.setPosition(bsp.getBomb().getX()*16, (bsp.getBomb().getY()+i)*16);
sprites.add(sprite);
System.out.println("RIP"+i);
System.out.println(bsp.getBomb().getStrength());
break;
}
}
}
You may be seeing duplicate print statements if you are calling the detectBomb method multiple times. Putting a breakpoint or print statement at the beginning of this method will help determine what the problem is.
Another thing to keep in mind is that you are creating a new Texture for the Sprite every time the method get executed - it would be wise to only instantiate the Texture once and share it with all subsequent Sprite instances that require it.
I'm working on a breakout game for an assignment and for part 2 of it I need to include code that stops the bat from being moved out of the boundaries. I'm pretty sure that I need to use an if statements but I don't know what exactly I should put inside the brackets for else (something that will enable the bat to move). I
This is the code in particular I'm talking about.
if (dist < 0)
{
}
else
{} // move
if ((dist + 150)> 600)
{
}
else
{} // move
(Part 2 is in the ModelBreakout class).
There are lots of classes and just so many different parts of the code that are to do with the movement of the bat and I don't know what to use for this part, I would appreciate a hint of what I need to do!
Edit: I removed all of the classes because people were complaining. If you would like to view the classes go to this page and scroll down to the title Mini project: The BreakOut game.
Thanks for any help. I'm not looking for anyone to do my work for me, I would just like some guidance, I've worked out that I need to do an if statement, I'm just not sure of what I need to put inside it.
TL;DR.
I recently created a similar game. Here's how I implemented it.
Racket Class
protected static final float MIN_X = 10;
protected static final float MAX_X = 590;
public void moveLeft()
{
if (x > MIN_X)
{
x -= 5;
}
}
public void moveRight()
{
if (x < MAX_X)
{
x += 5;
}
}
Player extends Racket
public void process(int key)
{
if (key == KeyEvent.VK_KP_LEFT || key == KeyEvent.VK_LEFT)
{
moveLeft();
}
else if (key == KeyEvent.VK_KP_RIGHT || key == KeyEvent.VK_RIGHT)
{
moveRight();
}
}
Edit: This is not the complete classes. It's just some items lifted from them. There's a key listener added to the game which passes the key to Player.process().
Edit 2: Updated my code. Your width is set to 600 so the boundaries can be 10 and 590. This should work for you
Looking at the classes there are built in methods for each object on the screen, so you could do something like this:
If( Bat.GetX() < 0 ) {
Bat.moveX( *INSERT THE X HERE* )
}
And you also could do a the same thing for the max width. Also if you do a simple fix like this make sure to change the refresh rate of the screen, otherwise you will see the bat Jumping to the new position.
I am making a chess game and need to figure out how to move the pieces. I have my pieces stored in an array squaresGrid[][] and I want to use the method moveTo to move the pieces. Currently this method simply marks a piece selected but I need it to take a second mouse click to choose the square to move the selected piece to but am not sure how best to do this.
public void actionPerformed(ActionEvent e)
{
for(int x = 0; x < 8; x++)
{
for(int y = 0; y < 8; y++)
{
if(e.getSource() == squaresGrid[x][y])
{
moveTo(e, squaresGrid[x][y]);
}
}
}
}
public void moveTo(ActionEvent e, JButton clicked)
{
clicked.setIcon(selected);
}
You don't do a "second actionPerformed". What you do is keep around state, and when a click happens, look at the state, and decide what the action should be.
For example, keep around a field called currentlySelected, pointing to the currently selected square (containing its coordinates, for example).
In the actionPerformed, when you receive a click, you look at currentlySelected.
If it is null, it means you are supposed to select the clicked square and put it in currentlySelected.
If it is not null, and the current click is in the same square, the user probably wants to de-select it. De-select and clear (put null) in currentlySelected.
If it is not null and not the same square, it means that you have to check if the move is legal. If it is legal, you can do the move, and clear currentlySelected. If it is not legal, you do what you think is the proper thing to do: perhaps de-select the original place and select the new one. Or just de-select and tell the user the move is not legal. Or keep it selected.
Remember to always clear your currentlySelected in the appropriate situations.
You don't need a second ActionListener or actionPerformed method, but rather you need a state-ful ActionListener, one that knows whether the button push represents the first push or the 2nd. A boolean variable could be all that is required for this. Another option is to use a variable to represent the first pushed location, set it equal to null initially and then set it equal to the position on the first push. On the 2nd push check if it is null or non-null and if non-null, the button push represents the 2nd push. Then set it back to null.
For example
public void actionPerformed(ActionEvent e) {
for(int x = 0; x < 8; x++) {
for(int y = 0; y < 8; y++) {
if(e.getSource() == squaresGrid[x][y]) {
if (gridLocation == null) {
// class to hold x and y location
gridLocation = new GridLocation(x, y);
} else {
// use gridLocation here
int firstX = gridLocation.getX();
int firstY = gridLocation.getY();
moveTo(e, x, y, firstX, firstY);
gridLocation = null;
}
}
}
}
}
I am programming a game, but I have ran into an error.
When the player collided with an object, player.hasCollided is set to true.
if(playerBounds.intersects(wolfBounds)){
player.hasCollided = true;
player.dead();
}
Now, when hasCollided is true, something from the LoseScreen class is printed out onto the screen:
if(player.hasCollided){
lose.start(g);
}
In player.dead(), the player's speed is set to 0.
public void dead(){
playerSpeed = 0;
coinBank += coinsCollected;
}
The problem is that in my InputHandler class I make it so that on the lose screen, when the choice is 1, and enter is pressed, restartGame() is called.
public void restartGame(){
obstacleWolf.getNewPosition();
obstacleHole.getNewPosition();
hasLost = false;
player.hasCollided = false;
player.playerSpeed = 5;
player.nextX = 1000;
player.coinsCollected = 0;
player.xElapsed = 0;
}
if(lose.choice == 1 && enter){
game.hasLost = false;
game.restartGame();
System.out.println(player.hasCollided + " " + player.playerSpeed);
}
Those variables ARE being set to what they are meant to be set to (for example playerSpeed becomes 5 from 0, and hasCollided is becoming false from true) but the effects are not taking place. So, like I showed before, lose.start(g); is only meant to be called when hasCollided is true, but even when it becomes false, it is still printed out on the screen.
Here is how the relevant variables/methods are being used:
public void move() {
x = x - player.playerSpeed;
}
(All moving objects share the same move method)
Parts of the game class:
public void tick(){
input.tick();
if(gameState){
player.tick();
player.move();
collision();
treeline.move();
obstacleHole.move();
obstacleWolf.move();
coin.move();
coin.tick();
}
I am not sure if I can make this question clearer. I can provide more code from different classes if needed.
The question can't be answered in its current form (see 2 comments above).
The reason for that is current code structure.
You need to refactor code, then you will find the problem.
Put all modification of player fields in methods of Player class.
Access fields only through methods. Making fields private is old good practice.
Then the only code you need to share would be this Player class.
In one thread environment, that's all.
Okay, I've got this game loop which never terminates --
public void run() {
setup();
addMouseListeners();
int Turns = NTURNS;
int TotalBricks = NBRICKS_PER_ROW * NBRICK_ROWS;
while ((Turns>0) && (TotalBricks>0)) {
moveBall();
checkForCollision();
pause(DELAY);
}
System.exit(0);
}
-- even though I have this method decrementing the Turns value every time the ball is missed:
private void checkForCollision() {
GObject collider = getCollidingObject();
if (collider !=null) {
if (collider == Paddle) {
vy= -vy;
}
else {
vy= -vy;
remove(collider);
TotalBricks = TotalBricks - 1;
}
}
if((ball.getX()>=(WIDTH-BALL_RADIUS)) || (ball.getX()<=0)) {
vx = -vx;
}
if(ball.getY()<=0) {
vy = -vy;
}
if(ball.getY()>=HEIGHT) {
Turns = Turns -1;
remove(ball);
newBall();
}
}
plus this
private int Turns;
at the bottom to ensure that the variable is shared among both methods.
No matter how many times the ball is missed, the game never stops.
What am I missing?
Thx
You are declaring a new Turns variable in your run method which is what is getting used by that method since it has a more local scope. This is called variable shadowing. Use a decent Java IDE like Eclipse and it will warn you when you do this. It's almost always a mistake.
http://www.xyzws.com/Javafaq/what-is-variable-hiding-and-shadowing/15
You're declaring your Turns variable twice, once for the entire class and once for the the run() method. Since you are also checking the value of the Turns variable that you've declared in the run() method, it never decreases because the one being used in checkForCollision() isn't the one that's being checked in the while loop.
In run(), this:
int Turns = NTURNS;
needs to be:
Turns = NTURNS;