I was trying to make a battleship clone but ended up running into one problem. I made a BattleShipGrid class that had two 2D arrays, one for each player. The array called p1/p2grid holds their ship and the locations the other player has shot at. The second array called p1/p2fire is the one that shows only where they shot, and not where the enemy ship is, though they can see where they’ve hit it. Im having a problem where I want to print player 1's fire grid after them firing to show if they missed or not. But each time I print player 1's fire grid it still sets everything as 0, like they never even fired on anything. I made 1 a miss and 3 a hit and 2 to represent the location of a ship.
Here is my code in my main:
boolean player1Turn = true;
if (player1Turn) {
fire = grid.fireAtPlayerTwo(x, y);
} else {
fire = grid.fireAtPlayerOne(x, y);
}
if (fire == 0) {
System.out.println("Miss!");
} else if (fire == 2) {
System.out.println("=====================================");
System.out.println("Hit!");
if (player1Turn) {
System.out.println(grid.printP1Fire());/* printing regular old empty array filled with zeros like when a player just starts and hasn't fired on anything.*/
} else {
System.out.println(grid.printP2Fire());
}
System.out.println("=====================================");
}
Here is my methods that I called when firing on the other player( fire at player one and fire at player two do the same thing but are named different ) :
int Empty = 0;
public int fireAtPlayerTwo ( int x, int y)
{
int result = p2Grid[x][y];
if (result == EMPTY) {
p1Grid[x][y] = MISS;/* This should change the value in p1Grid at that coordinate but it is not refelcting back in the main*/
p2Fire[x][y] = MISS;
} else if (result == SHIP) {
p1Grid[x][y] = HIT;
p2Fire[x][y] = HIT;
}
return result;
}
Related
As the title says, I'm having a problem with objects overlapping. I want them to be able to overlap because I need object X to be on top of object Y to get a point and if I remove object X from being on top of Y, I remove the said point. My problem then is, if object Y is created before object X, once I place object X on top of Y, I can no longer move it and it always outputs to the console, Object Y. I was wondering if there would be an easier way to fix this.
I try moving forward but the Box doesn't budge:
[
This is the code that I'm using to generate the level Data
private List<ImageTile> createLevel(){
ArrayList<Movable> aux1 = new ArrayList<>();
ArrayList<Immovable> aux2 = new ArrayList<>();
try {
Scanner sc = new Scanner(new File ("levels/level" + levelID + ".txt"));
String line = "";
while(sc.hasNextLine()) {
for (int y = 0; y < HEIGHT; y++) {
line = sc.nextLine();
for(int x = 0; x < WIDTH ; x++) {
levelObjects.add(new floor(new Point2D(x,y), "Floor", 0));//adding the floor before anything else
char letter = line.charAt(x); // checking the character in the X coordinate
if (letter == 'E') { // in case, there's a E, that's the starting position of the player
player = new Forklift(new Point2D(x,y), "Forklift_U", 2);
levelObjects.add(player);
objects.add(player);
} else if(letter != ' ') {
AbstractObject obj = ObjectCreation.readChar(letter, x, y); // going to look for the object in Factory to be put in the X and Y position
if(obj instanceof Immovable) {
aux2.add((Immovable) obj);
}else if(obj instanceof Movable) {
aux1.add((Movable) obj);
}
// comp.comprator(obj, obj);
objects.add(obj);
levelObjects.add(obj);//implementing said object into the Level
}
}
}
}
sc.close(); //Closing Scanner
} catch (FileNotFoundException e) {
System.out.println("No levels found!");
}
still = aux2;
moving = aux1;
return levelObjects;
}
Then I'm checking with the general move function if the box( or any object part of the instance Movable) can move to the next position
public void move(Direction direction) {
Vector2D pos = direction.asVector(); // Transforming the direction in a vector right off the bat.
Point2D currentPosition = getPosition(); // getting the current position of either player or object.
Point2D nextPosition = currentPosition.plus(pos); // the next position as to which the player or the object intend to go to.
if(isTransposable(nextPosition)) { // calls the function to see if the object is able to move to the next position, this prevents the boxes from pushing up into the walls and from into each other {
setPosition(nextPosition); //if it can, then the object will go to the next position
}
}
And this is to check whether or not the object can advance to the next position;
public boolean isTransposable(Point2D pos) { // is the object able to move to the next position
for(AbstractObject obj1 : Game.getInstance().getObjects()) { // for-each to get all the objects, with the exception of the floor, from the game.
if((obj1.isBlockable() && obj1.getPosition().equals(pos))){ // if the object is able to block and if it's position is the same as the nextPosition.
return false;
}
}
return true; // otherwise it's able to be walked on.
}
It was a simple case of having two lists and one having priority over the other.
In the picture, you can the box is on top of the target, but as soon as that happened, the engine would read the tile that came first, in this case being the Target one. Since that one is immovable it meant that it could not be pushed/moved by any means. Regardless if you had anything on top of it that could.
A way I used to fix it, was to simply check if the object was of class movable
public boolean isMovable(Point2D pos) {
for(AbstractObject obj1 : Game.getInstance().getObjects()) {
if((obj1.isMovable() && instanceof Movable)){
return true;
}
}
return false;
}
I am creating a tile based turn based game where you have multiple units under your command and they are controlled using mouse clicks (sort of like chess but with a lot more mechanics). They're all drawn using Java Graphics (g.drawImage or g.draw(shape)). Each mouse click from the user should carry out a certain task dependant on previous mouse clicks.
For example: To attack an enemy unit, you must first click your own unit, and then click an enemy unit. Or if you click your own unit but he has already attacked then your subsequent click on the enemy unit should not cause an attack.
The game uses a tick/render system where all user input is processed in the tick method (called multiple times a second) and then drawn to the screen using the render method(also called multiple times a second)
The way I have tackled this problem is using a lot of different variables and way too many if statements. I wont paste the whole code because it's very long but the handling mouse click section of it has been attatched below.
Once the tick method reaches a certain end it will call "checkwhattoshow" method which is even longer than this but it will give instructions to the render method to draw onto the screen.
The code half-works in respect to what i want it to, but what im mainly asking is if there is a more efficient way than making too many if statements and variables, to handle sequences of mouse clicks, as this all seems unnecessary and inefficient.
//class variables
private boolean unitclickedon; //if a friendly unit is selected
private int xTile, yTile;
private int onlyonce; //helps me perform a block of code only once
private int prevxTile, prevyTile;
private int speed; //distance the unit can move
private int maxRange; //how far the unit can attack
private Tile tile, newTile;
private Unit unit;
#Override
public void tick() {
//every time the left mouse button is clicked
if (handler.getMouseManager().buttonJustPressed(MouseEvent.BUTTON1)) {
//keep track of the tile you're clicking on
xTile = handler.getPosition().getCoordX();
yTile = handler.getPosition().getCoordY();
//if clicking outside of map do nothing
if (xTile > handler.getMap().getWidth() - 2
|| xTile < 1
|| yTile < 1
|| yTile > handler.getMap().getHeight() - 2) {
return;
}
//if you click on a unit
if (handler.getMap().getTileAt(xTile, yTile).getUnit() != null) {
//save the tile and unit info
tile = handler.getMap().getTileAt(xTile, yTile);
unit = tile.getUnit();
speed = unit.getSpeed();
maxRange = unit.getMaxRange();
//if nothing is currently selected at all
//select the unit and exit this method.
if (onlyonce++ == 0) {
unitclickedon = true;
prevxTile = xTile;
prevyTile = yTile;
//check what should render to the screen
checkWhatToShow();
return;
}
//if you've clicked on the same tile twice unselect the unit and reset
if (prevxTile == xTile && prevyTile == yTile) {
unitclickedon = false;
onlyonce = 0;
} else { // you're clicking on another unit
Unit prevUnit = handler.getMap().getUnit(prevxTile, prevyTile);
if (prevUnit.getOwner() == unit.getOwner()) { //selecting another one of your units
unitclickedon = true;
//check what should render to the screen
checkWhatToShow();
} else { //clicking an enemy unit
if (validAttack(prevxTile, xTile, prevyTile, yTile, maxRange + speed)) { //attack
System.out.println("attacking unit!");
unitclickedon = false;
prevUnit.setHasAttacked(true);
return;
} else { //cant attack
unitclickedon = false;
checkWhatToShow();
}
}
}
} else { //if you're not clicking on a unit
if (unitclickedon) { //you're attempting to move a unit
if (validMove(prevxTile, xTile, prevyTile, yTile, speed)) { //move the unit if its legal
tile = handler.getMap().getTileAt(prevxTile, prevyTile);
unit = tile.getUnit();
if (!unit.isActive() || unit.hasMoved()) {
unitclickedon = false;
return;
} else { //move the unit
newTile = handler.getMap().getTileAt(xTile, yTile);
tile.removeUnit();
newTile.addUnit(unit);
unit.setHasMoved(true);
unitclickedon = false;
onlyonce = 0;
}
} else { //dont move the unit because you're clicking outside of its range
unitclickedon = false;
onlyonce = 0;
}
} else { //you're not doing anything unit related
unitclickedon = false;
onlyonce = 0;
}
}
//record your last click
prevxTile = xTile;
prevyTile = yTile;
}
}
short version:
trying to tackle the problem of making a large version of this more efficient:
if (first mouse click does x1)
if (second mouse click does y)
third mouse click does z
if (second mouse click was y2)
third mouse click z2
if (first mouse click does x2)
bla bla bla
then getting the final result and rendering it onto the screen
thanks and sorry if it doesnt make sense :c
**you can something similar to :
List<Rule> rules = .... ; // your n rules initialized here somehow
for(Rule r : rules) {
if(r.condition()) {
r.action();
}
}**
I'm trying to do a game. When you press "A" my character was supposed to jump ONE square forward, but he is jumping like 7 squares each time I press the "A" key. Someone knows how to limit it to 1? I know why it is happening, but I didn't find any ways to do that until now.
My "Player" class code, that is my Character class:
ArrayList<Square> squareList = new ArrayList<Square>();
int count = 0;
Vector2 position = new Vector2(50,50);
if(Gdx.input.isKeyPressed(Keys.A))
{
j = j + 1;
position.x = squareList.get(i).getPosition().x;
position.y = squareList.get(i).getPosition().y;
i++;
}
Try this:
if (Gdx.input.isKeyJustPressed(Keys.A)) {
System.out.println("KEY PRESSED");
}
It only runs once when you press the key, but if you press and hold it only triggers once. Tested it.
Something like this i imagine would work:
if (Gdx.input.isKeyPressed(Input.Keys.P)) {
// Use a helper so that a held-down button does not continuously switch between states with every tick
if (pauseHelper) {
if (isPaused) {
Util.toConsole ("No longer paused");
isPaused = false;
}
else {
Util.toConsole ("Now paused");
isPaused = true;
}
pauseHelper = false;
}
}
else {
pauseHelper = true;
}
(See http://pastebin.com/vsVWeHj6)
However, technically you need to implement an InputProcessor provided by LibGDX to handle key presses.
Another way to do it if you don't want to implement an InputProcessor:
//Member variable:
boolean mAKeyWasPressed = false;
//In method:
boolean aKeyIsPressed = Gdx.input.isKeyPressed(Keys.A);
if (aKeyIsPressed && !mAKeyWasPressed)
//Just pressed. Do stuff here.
}
mAKeyWasPressed = aKeyIsPressed;
I'm actually working on a memory game and I'm stuck at the point where I should write the gameplay-part of the game.
So:
I have an array of N card objects. Each object has an attribute called cardNum - an identifier. I think I should write an actionListener on that array, so when I flip a card, it puts the flipped card's cardNum in an array of two elements and if the two elements of the array are equal, a pair is found.
The problem is that I just don't know how to get the last flipped card's cardNum.
Any help would be appreciated.
Here's the way I tried:
private void easyGame(Card[] cards) {
int flippedCards = 0;
int card1;
while(flippedCards != 24) {
for(int i=0; i<cards.length; i++) {
if(cards[i].getIsFlipped())
flippedCards ++;
}
if(flippedCards % 2 == 0 && flippedCards > 0)
for(int i=0; i<cards.length; i++) {
card1 = getCardIndByCardNum(cards[i].getCardNum(), cards, i);
if(!cards[card1].getIsFlipped()) {
for(int j=0; j<cards.length; j++) {
if(cards[i].getIsFlipped())
cards[i].flip();
}
flippedCards = 0;
break;
}
}
}
}
The problem is that if I call this method, the game won't be drawn. May I use use threads somehow?
EDIT
Here is how I get the indexes of the clicked cards, and I call it in the UI:
private void setCardHandlers() {
for(final Card card : cards) {
card.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
clickedCardInd = getChildren().indexOf(card)-1;
}
});
}
}
Than here is how I am using it:
setOnMouseReleased(new EventHandler<MouseEvent> () {
#Override
public void handle(MouseEvent t) {
int cardIndex = clickedCardInd; // get index of what user clicked
clickedCardInd = -1;
if (cardIndex != -1 && moveRequestedFlag) { // our controller waits for the move
// get the position and report
moveRequestedFlag = false; // we handled the move
//System.out.println(cardIndex);
nextMove.setMove(cardIndex); // this will unblock controller's thread
}
}
});
It has a delay on fliping cards, also in the easyGame the requestMove method sets both indexes to the same.
I would recommend splitting you responsibilities a bit into Model/View/Controller modules, which, in simplest case would look like :
Model - your game current state and data, i.e. cards array Cards mCards = new Cards[24];
View - your UI, that can reflect current state of mCards(model) on screen in Main thread
Controller - your main game logic. This is most complex part, responsible for
requesting/handling user move,
updating mCards(model) based on user move,
Requesting UI to re-draw.
Contoroller's code (easyGame method) should run on separate thread to not block the UI.
Below I sketched a skeleton code that should fit your requirements :
class Game {
/*
* controller - main logic
*/
void startEasyGame() {
// initialize cards array, shuffle if needed
// we start with zero cards flipped
int flippedCards = 0;
// main loop
while (flippedCards != mCards.length) {
// 1. show updated UI
mBoard.showUpdatedCards();
// 2. request player move
// and block current thread to wait till move is done
// the result of the move - index of the card
int index1 = requestMove();
// temporarily flip first card face-up
mCards[index1].flip();
// show it on screen
mBoard.showUpdatedCards();
// same for second card
int index2 = requestMove();
mCards[index2].flip();
mBoard.showUpdatedCards();
// 3. check the result
if (mCards[index1].getCardNum() == mCards[index2].getCardNum()) {
// hooray, correct guess, update count
// possibly show some encouraging feedback to user
flippedCards += 2;
} else {
// incorrect, flip cards back face down
mCards[index1].flip();
mCards[index2].flip();
}
} // end of while loop
// game ended -> show score and time
mBoard.showResult();
}
}
EDIT
Extra details on how to await for result from UI thread :
int requestMove() {
// 1. show user prompt to make a move
// ...
// 2. construct latch to wait for move done on UI thread
mBoard.moveRequestedFlag = true;
NextMove nextMove = new NextMove();
mBoard.nextMove = nextMove;
// 3. await for move and get the result
return nextMove.getMove();
}
then, somewhere in UI code :
// handling card onClick somewhere on UI thread
if (mBoard.moveRequestedFlag) { // our controller waits for the move
// get the position and report
int cardIndex = ... // get index of what user clicked
mBoard.moveReqestedFlag = false; // we handled the move
mBoard.nextMove.setMove(cardIndex); // this will unblock controller's thread
}
and NextMove utility class to sync threads :
public class NextMove {
private volatile int mCardIndex;
private final CountDownLatch mMoveReady = new CountDownLatch(1);
public int getMove() throws InterruptedException {
mMoveReady.await();
return mCardIndex;
}
public synchronized void setMove(int selectedCardIndex) {
if (mMoveReady.getCount() > 0) {
mCardIndex = selectedCardIndex;
mMoveReady.countDown();
}
}
}
I am trying to make a memory card game with 3 conditions:
when the player start the game the first click reveal the first card
if the player click in the second card there are 2 options
a. the second card have the same value as the first card. Hence keep both of them.
b. the second card have different value. Hence flip both back when click
I don't know what is the best way to deal with this problem. I thought of using if statement and making new method "state" which should have 3 outputs.
public void mousePressed() {
if(state==READY){
for (int i = 0; i < 6; i++) {
if(mouseX >= cards[i].x &&
mouseX <= cards[i].x+cards[i].WIDTH &&
mouseY >= cards[i].y &&
mouseY <= cards[i].y+cards[i].HEIGHT) {
cards[i].flip();
}
}
}
else if (state==FIRST_CHOSEN){
}
else{
}
}
I would break the problem into smaller problems.
Have several different methods that solve a little task that is required to tackle the larger end goal:
public void revealCard(Card card)
public boolean isMatch(Card card)
public void flipCardsBackOver(Card card1, Card card2);
And add an instance variable that stores the card that is already up. Once you have broken apart all of the separate challenges, then your problem becomes an easy one:
private Card CardOne; //instance variable
public void revealCard(Card myCard) {
myCard.flipCard(); //Whatever task you need to flip the card
if (CardOne = null) {
myCard = CardOne;
return;
}
if myCard.isMatch(CardOne)) {
//Do whatever you need to do when there is a match
}
else {
this.flipCardsBackOver(myCard, CardOne) //Flip all up cards over and set Card1
//to null
}
}