Variables are being reset, but effects are not taking place - java

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.

Related

How should I make my getMove() method interact with my GUI in my chess application?

I'm developing an application in Java to help me land my first job as a junior developer. It's a chess game with a GUI that both human players click on from the same machine.
When it's, say, white's turn to move, the application calls white's getMove(Interface interaction) method until a valid MoveAttempt is returned. Here's the getMove(Interface interaction) method of HumanPlayer:
public MoveAttempt getMove(Interface interaction) {
while(!interaction.selectionMade()) {
}
byte pieceFile = interaction.getPenultimateFile();
byte pieceRank = interaction.getPenultimateRank();
byte toFile = interaction.getUltimateFile();
byte toRank = interaction.getUltimateRank();
return new MoveAttempt(pieceFile, pieceRank, toFile, toRank, getIsWhite());
}
penultimateFile, penultimateRank, ultimateFile and ultimateRank are supposed to store the file (column) and rank (row) of the last two chess tiles clicked. This is achieved through this actionPerformed(ActionEvent event) which Interface has because it implements ActionListener
public void actionPerformed(ActionEvent event) {
LocalizedButton button = (LocalizedButton) event.getSource();
if(penultimateFile == -1) {
penultimateFile = button.getFile();
penultimateRank = button.getRank();
}
else {
ultimateFile = button.getFile();
ultimateRank = button.getRank();
}
}
and by calling this method before each call to getMove(Interface interaction)
public void resetClicks() {
penultimateFile = -1;
penultimateRank = -1;
ultimateFile = -1;
ultimateRank = -1;
}
So the idea is that a move attempt is not made until someone has clicked on two chess squares which is why I have a while loop indefinitely calling selectionMade():
public boolean selectionMade() {
return penultimateFile != -1 && penultimateRank != -1 && ultimateFile != -1 && ultimateRank != -1;
}
This didn't work---pieces didn't move---so in an attempt to see what was happening I put this print statement
System.out.println(interaction.getPenultimateFile() + ", " +
interaction.getPenultimateRank() + ", " +
interaction.getUltimateFile() + ", " +
interaction.getUltimateRank());
into the while loop to see what was going on and now it works---pieces move---except I may have encountered times in which it didn't work but I last I tried I couldn't get it to fail.
I don't want to print anything to the console; what should I do in lieu of having this while loop?
Edit: Putting boolean lol = 0 just above the loop and lol = !lol in the loop doesn't allow the code to work. Neither does calling doNothing().
Edit: Here's the source code: https://github.com/JosephBGriffith/Chess
Right now only the pawns work because I have other bugs that I need to fix. En passant works except the opponent piece doesn't get eliminated.
I would invert the control, so that the UI pushes moves to the game, rather than the game trying to pull moves from the UI.
So your game class might have:
class Game {
boolean move(int fromFile, int fromRank, int toFile, int toRank) { ... }
...
}
If the move wasn't legal (e.g. if it was the other player's turn) then move returns false and the move doesn't occur. That is, the internal state of the Game is unchanged.
And your actionPerformed method becomes:
public void actionPerformed(ActionEvent event) {
LocalizedButton button = (LocalizedButton) event.getSource();
if(penultimateFile == -1) {
penultimateFile = button.getFile();
penultimateRank = button.getRank();
}
else {
game.move(penultimateFile, penultimateRank, button.getFile(), button.getRank());
penultimateFile = -1;
}
}
You could use the return value of move to provide some feedback to the user if the move is illegal.
Something to note about this suggestion is that move is executed on the Swing event thread. In theory this is bad practice, although unless your move method is very slow it won't matter.
Read https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html and consider whether you want to use invokeLater.

Why is it adding more than 1 to my speed control?

import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
public class Turtle extends Actor
{
/**
* Act - do whatever the Turtle wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
int laufmenge;
public void act()
{
if(Greenfoot.isKeyDown("left")){
move(-speed);
}
if(Greenfoot.isKeyDown("right")){
move(speed);
}
if(Greenfoot.isKeyDown("up")){
setLocation(getX() ,getY() -speed);
}
if(Greenfoot.isKeyDown("down")){
setLocation(getX() ,getY() +speed);
}
if(Greenfoot.isKeyDown("x")){
if(speed<10) speed++;
}
if(Greenfoot.isKeyDown("y")){
if(speed>0) speed--;
}
System.out.println(speed);
}
private int speed=1;
}
This is code from Greenfoot because i am currently trying to learn coding. I cant understand why when i execute the programm and control the speed he is changing the value by more than one. I guess it will be an easy question.
And is it possible to put the increase and decrease of the speed on one button with two letters like the >< key? i didnt work in my case.
This happens because act() is called in rapid succession. Even if you just press and release x, act() will have run several times while the key is down, and therefore updated the speed several times.
To avoid that, you can track whether or not you've adjusted the speed since the first time you noticed that the button was pressed.
For example, you can have a private bool adjustedSpeed = false; in your class, and then do:
if(Greenfoot.isKeyDown("x")){
if(speed<10 && !adjustedSpeed) speed++;
adjustedSpeed = true;
} else if(Greenfoot.isKeyDown("y")){
if(speed>0 && !adjustedSpeed) speed--;
adjustedSpeed = true;
} else {
adjustedSpeed = false
}

Turns issue in java game [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I've created a simple game which a player plays against computer.
I've got an issue in the timing of the turns, the computer should be the first to make a move than the real player should make his move by clicking LeftChoice or RightChoice button.
Here's my problem at code:
public class GameForm extends javax.swing.JFrame {
/**
* Creates new form GameForm
*/
final int SIZE = 10;
int CurrentSize = 10;
int PC_SUM=0;
int HUMAN_SUM=0;
boolean PC_TURN = true;
int[] RandArr = new int[SIZE];
public GameForm() {
initComponents();
}
public void init(){
for(int i = 0 ; i<SIZE;i++){
RandArr[i] = (int)(Math.random()*100)+1;
}
jTextField3.setText("");
jTextField4.setText(Integer.toString(PC_SUM));
jTextField5.setText(Integer.toString(HUMAN_SUM));
}
public void HUMAN_updateLeft(){
HUMAN_SUM+=RandArr[0];
jTextField5.setText(Integer.toString(HUMAN_SUM));
jTextField1.setText(Arrays.toString(RandArr));
CurrentSize--;
int [] NewRand = new int[CurrentSize];
for(int i = 1 ; i<=CurrentSize;i++){
NewRand[i-1] = RandArr[i];
}
RandArr = NewRand;
jTextField2.setText(Arrays.toString(RandArr));
PC_TURN = true;
}
public void HUMAN_updateRight(){
HUMAN_SUM+=RandArr[CurrentSize-1];
jTextField5.setText(Integer.toString(HUMAN_SUM));
jTextField1.setText(Arrays.toString(RandArr));
CurrentSize--;
int [] NewRand = new int[CurrentSize];
for(int i = CurrentSize-1 ; i>=0;i--){
NewRand[i] = RandArr[i];
}
RandArr = NewRand;
jTextField2.setText(Arrays.toString(RandArr));
PC_TURN = true;
}
public static boolean WhoIsBigger(int[] arr){
int even=0,odd=0;
for(int i=0;i<arr.length;i+=2){
if(i%2==0){
even+=arr[i];
odd+=arr[i+1];
}
else{
odd+=arr[i];
even+=arr[i+1];
}
}
return even>odd;
}
public void PC_updateLeft(){
PC_SUM+=RandArr[0];
jTextField4.setText(Integer.toString(PC_SUM));
jTextField1.setText(Arrays.toString(RandArr));
CurrentSize--;
int [] NewRand = new int[CurrentSize];
for(int i = 1 ; i<=CurrentSize;i++){
NewRand[i-1] = RandArr[i];
}
RandArr = NewRand;
jTextField2.setText(Arrays.toString(RandArr));
}
public void PC_updateRight(){
PC_SUM+=RandArr[CurrentSize-1];
jTextField4.setText(Integer.toString(PC_SUM));
jTextField1.setText(Arrays.toString(RandArr));
CurrentSize--;
int [] NewRand = new int[CurrentSize];
for(int i = CurrentSize-1 ; i>=0;i--){
NewRand[i] = RandArr[i];
}
RandArr = NewRand;
jTextField2.setText(Arrays.toString(RandArr));
}
public void PC_TURN(){
if(WhoIsBigger(RandArr))
PC_updateLeft();
PC_updateRight();
}
public void FullGame(){
while(RandArr.length>0){
if(PC_TURN){
PC_TURN();
PC_TURN = false;
}
}
}
//start button listener
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
init();
jTextField2.setText(Arrays.toString(RandArr));
jTextField1.setText("-");
jButton1.setEnabled(false);
FullGame();
}
//left button listener
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
HUMAN_updateLeft();
}
//right button listener
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
HUMAN_updateRight();
}
How can i know that the real player has made his move so it'll change PC_TURN to True and the game will move on?
Firstly, you should follow Java Naming Conventions when it comes to naming your variables. As it stands, PC_TURN looks as though it is a constant, although it is not a constant since you are changing it's value. So a more appropriate name would be pcTurn.
You also seem to have a method called PC_TURN() which I am assuming is the method which causes the computer to take it's turn and do something. So it would be better if this was named something descriptive like takePCTurn(). Notice the use of camelCase throughout. Capital letters at the start of a name should be reserved for classes and interfaces, not variables or methods.
The same goes for your method name
public void FullGame()
should be written as
public void fullGame()
Keeping to coding conventions like this make it easier for others to read and understand your code and keep everything neat and tidy. It's a good habit to get into. :)
I don't know where your left and right buttons are being declared or what you have named them, but you will need to add an event listener to each button which causes something to happen when they are clicked. I also am unsure about the purpose of RandArr.length > 0. You really don't need a loop here since this is an application with a GUI, it is never going to close unless you explicitly tell it to (e.g by clicking the close button). So I will just give you a generic solution.
You basically want the players turn to trigger the computer to take it's turn until some game over condition is met.
Example:
//Assuming this is called when the Start button is clicked
public void fullGame() {
takePCTurn();
}
public void takePCTurn() {
//Do PC's turn logic
//You might want to check if the Computer Won the game here
}
class PlayerTurnListener implements ActionListener() {
public void actionPerformed(ActionEvent e) {
//Do Player's turn logic
//You might want to check if the Player Won the game here
takePCTurn();
}
}
//We can create an instance of our listener and add it to both buttons
PlayerTurnListener playerTurnListener = new PlayerTurnListener();
leftButton.addActionListener(playerTurnListener);
rightButton.addActionListener(playerTurnListener);
So the first thing that happens is fullGame() is called by your Start button which then calls takePCTurn(); causing the computer to take it's turn. Now nothing will happen until the player clicks the left or right button. When they do this, the PlayerTurnListener's actionPerformed() method is called and you can do some logic in there and then takePCTurn(); will be called once again.
Rinse and repeat until gameover.
Hope that helps :)
You should attach a clickListener onto the left and right buttons. Then when the user clicks one that event will be fired. You should change PC_TURN to true there and re-run the loop if needed.
Example:
JButton yourButton = new JButton("Your Button");
yourButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
PC_TURN = true;
// extra code
}
});
If this is a Swing or other GUI then you will need to get rid of the while loop.
Remember that GUI programs are non-linear and are event-driven, and so rather than a restricting while loop which risks completely feezing your GUI, you would change the program's state depending on whose turn it is -- have a variable indicating whose turn it is -- and then change the behavior of the program based on the state.
If you need more specific help, then you're going to need to ask a much more complete question including one with enough code and explanation to allow us to understand your problem better (but not too much code).
Regarding the code you've posted:
Yes, definitely get rid of that while loop.
Your code is hard to understand, mainly because you're variable naming is poor. Rather than using variable names like jTextField1, use names that make logical sense, that make your code "self-debuggin", such as humanScoreField and computerScoreField, etc.
Also learn and follow standard Java naming practices including having all variables start with lower case letters, classes with upper case letters, use camelCase for all except for constants which are all upper-case.
Tell more about just what this code is supposed to be doing, what the buttons and the JTextfields represent, what behaviors you desire, etc...

Java Rectangle Collision Intersection (Not always working)

I'm currently working on a tile collision system for an RPG style game and it mostly working except for some inconsistency with rectangle intersection.
protected void tileCollision()
{
AnimatedSprite player = findPlayer();
for(int i = 0; i < _sprites.size(); i++)
{
AnimatedSprite spr = _sprites.get(i);
for(int j = 0; j < tileWithinRange.length; j++)
{
Tile tile = tileWithinRange[j];
if(tile != null)
{
if(tile.getBounds().intersects(player.getBounds()))
{
player.setCollided(true);
tileCollision(player, tile, -1, -1);
} else
{
player.setCollided(false);
}
}
}
}
}
When I first collide with a tile upon launching the game, it always returns true, but if I move along a column of tiles, I start getting false returns and then after a while I only get false returns.
Here is an image of the player intersecting with a tile
There is an obvious intersection here, yet in this scenario, the variable collided returned false.
What is going wrong that the intersection isn't always registering?`
There is too little info here to really know what's happening, but something looks fishy here:
if(tile.getBounds().intersects(player.getBounds()))
{
player.setCollided(true);
tileCollision(player, tile, -1, -1);
} else
{
player.setCollided(false);
}
Since you are checking multiple tiles against the player in a loop, what if the player collides with the first tile, but doesn't collide with the second tile? You'd end up calling player.setCollided(false); even though he collided with a former tile, overwriting that true collision state with a false one. That might explain the behavior you're getting where you're getting only false returns after a while (perhaps because of the order in which you are checking the tiles makes it so you keep overwriting true states with false states).
I'm not sure if that's desirable or not to have these kinds of side effects, but it is a bit confusing at the very least to have this kind of collision state first being turned on and then overwritten with off within the same loop. If that's undesirable behavior, perhaps what you're after needs you to break out of the loop if a collision occurs. Or perhaps what you want is something more like this:
player.setCollided(false);
for(int j = 0; j < tileWithinRange.length; j++)
{
Tile tile = tileWithinRange[j];
if(tile != null && tile.getBounds().intersects(player.getBounds()))
{
player.setCollided(true);
tileCollision(player, tile, -1, -1);
}
}
}
Or maybe your bounds/intersection function is genuinely malfunctioning -- it's too hard to tell with so little code/info (we don't know how these are implemented).
It's good to be able to isolate your code and learn how to construct test cases to test out individual functions in little pieces independently. You want to eliminate suspects through a process of elimination with a testing procedure that allows you to figure out, "Okay, this part works perfectly in every case, let's move on to the next thing." Otherwise it becomes a guessing game trying to figure out what went wrong. One of the easiest ways to lose a time of time/productivity in development is to write a bunch of code first and then try to narrow down what went wrong in hindsight, instead of testing each little babystep. Mistakes get more expensive the later you discover them and the more suspects you have to go through in an investigation.
I ended up rewriting the method into a boolean which made it return true when colliding and false when not. Here is the new code.
public boolean tileCollision() {
AnimatedSprite player = findPlayer();
for(int j = 0; j < tileWithinRange.length; j++) {
Tile tile = tileWithinRange[j];
if(tile != null) {
if(tile.getTileBounds().intersects(player.getBounds()) ) {
return true;
}
}
}
return false;
}

Counters not decrementing or not being read in Breakout

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;

Categories

Resources