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();
}
}
}
Related
I've been given an assignment to edit a game and add different elements to it, one was the ability to restore player life when interacting with an object which I have completed.
The next step is to stop this from working when the players life is max (100).
My idea then was to create a method with a condition (and if it is true, stop my life adding method from working / being called.)
Example:
private void checkMaxLife() {
if (playerLife==100) {
//Stop method addLife from working
}
}
Would this be possible and what is the syntax?
EDIT:
This was the fix, added playerLife < 100 to the collision method instead.
private void foodAddLife() {
//Check food collisions
for (int i = 0; i < food.length; ++i) {
if (playerLife < 100 && food[i].getX() == player.getX() && food[i].getY() == player.getY()) {
//We have a collision
++playerLife;
}
}
It seems you don't need checkMaxLife, just use the attribute playerLife in the method addLife
private void addLife() {
if (playerLife < 100) {
playerLife++; // or whatever value
}
}
With 2 methods, you see that one is useless
private boolean isFullLife() {
return playerLife >= 100;
}
private void addLife() {
if (!isFullLife()) {
playerLife++; // or whatever value
}
}
You just return the function when player life is MAX_VALUE.
private void addLife() {
if(playerLife>=100)
return;
// Do Whatever you need to do
}
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;
}
public static ArrayList<Hand> getPossibleHands(Hand h) {
ArrayList<Hand> allPossible = new ArrayList<Hand>();
addNext(allPossible, h);
return allPossible;
}
public static void addNext(ArrayList<Hand> poss, Hand h) {
if (h.cards.size() == 5)
poss.add(h);
else
for (int i = 0; i < 52; i++) {
Card c = Card.makeCard(i);
if (!h.contains(c))
h.add(c);
addNext(poss,h);
}
}
The code above is supposed to essentially take an incomplete poker board (anywhere from 0-4 cards) and return all possible complete boards (5 cards). The logic that I feel like it should follow is as follows: recurse through every combination of adding valid (not on the board already) cards until the size of the board is equal to 5 in which case it will add the board to the list and skip over the rest of the function.
However upon using a print statement at the beginning of the function I see that hand sizes of greater than 5 or being created. Since the first part of the function should catch all hands at 5 and terminate it there, I don't see how the code executes at the rest of the function.
Your class should receive stack overflow with an empty hand.
You send new Card(0) to the hand. This is added.
Then you call add next again - and the 'for' starts from 0 again. Checks adds 1. Then starts from 0 - it is there, does not add anything and starts over. Where it starts from 0. Does not do anything. Starts from 0. Ad infinum -> StackOverFlow.
You also need to reset to previous state of the hand every time you finish with 5 cards and backtrack.
If you want a recursive solution you can try :
private static ArrayList<Hand> getPossibleHands(Hand h) {
ArrayList<Integer> except;
if (h.cards == null) except = new ArrayList<>();
else
except = h.cards.stream().map(c -> (c.getCard())).collect(Collectors.toCollection(ArrayList::new));
ArrayList<Hand> allPossible = new ArrayList<>();
addNext(allPossible, h, except);
return allPossible;
}
private static void addNext(ArrayList<Hand> poss, Hand h, ArrayList<Integer> except) {
//assuming hands 0-4 - we don't need to check on entry, only when we add
Hand localHand = h.copy();
for (int i = 0; i < 52; i++) {
if (except.contains(i)) continue;
Card c = Card.makeCard(i);
if (!localHand.contains(c)) {
addNext(poss, localHand.copy(), copyExcept(except, i));
localHand.add(c);
if (localHand.cards.size() == 5) {
poss.add(localHand);
break;
}
}
}
}
private static ArrayList<Integer> copyExcept(ArrayList<Integer> except, int i) {
ArrayList<Integer> clonedExcept = new ArrayList<>(except);
clonedExcept.add(i);
return clonedExcept;
}
import java.util.ArrayList;
public class Hand {
ArrayList<Card> cards = new ArrayList<>();
public boolean contains(Card c) {
for (Card card : cards) {
if (card.getCard() == c.getCard())
return true;
}
return false;
}
public void add(Card c) {
cards.add(c);
}
Hand copy() {
Hand temp = new Hand();
for (Card c : cards) {
temp.add(new Card(c.getCard()));
}
return temp;
}
}
class Card {
private int card;
public Card(int card) {
this.card = card;
}
public static Card makeCard(int i) {
return new Card(i);
}
public int getCard() {
return card;
}
}
Initially, h is (presumably) empty. So addNext will loop through all possible cards, and since none of them are in the hand, add each card to the hand, regardless of how many cards are currently in the hand.
It looks to me like your for loop is eventually adding whole deck to hand.
In your loop you run 52 iterations. On each iteration you (conditionally) add a card to the hand and then you call your function recursively. But after that recursive call has returned, you go to the next iteration and again add a card to the hand.
So that '5 card restriction' does not restrict anything here.
I'm trying to learn Java and basically my approach has been to take the procedural style I learned with python, and apply it to Java. So I never use classes and just put everything in a single class with many methods(which I just use as python functions). I think I've hit a problem, and need to bite the bullet and use classes, but I'm having trouble wrapping my head around how to do it.
To simplify my problem(ignore the poor design- it's just to illustrate the point), I have a program that takes a list and within a for loop does some math on each item(in this case adds 1 to the value of the list). I only want it to do work on 2 items on the list and then stop(in this example it's the first 2 items but in my real program it could be anywhere in the list). Here's the working code that is similar to how I'm already doing it:
No Classes:
public class LearningClasses {
public static void main(String[] args) {
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
for (int i =0; i<100; i++){
if (check_size(data_list) == false ) {
break;
}
data_list[current_location] = (list[current_location]+1);
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
private static boolean check_size(int[] data_list) {
// TODO Auto-generated method stub
int count = 0;
for (int item : data_list) {
if (item != 0) {
count++;
if (count>=2) {
break;
}
}
}
if (count>=2) {
return false;
} else {
return true;
}
}
}
The problem with this code is although it works it's inefficient because it calculates the count on every iteration of the second for loop. In my program I cannot put anything above the first for loop but I can put anything below it, so I thought instead of doing the count every time maybe I could use a class to somehow maintain state and just increment the number as oppose to recalculating every time.
With classes:
public class LearningClassesCounter {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data());
for (int i =0; i<100; i++){
data_list[current_location] = (list[current_location]+1);
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
}
class Counter {
private int count; // current value
private boolean continue_or_not;
private int[] data_list;
// create a new counter with the given parameters
public Counter(int[] data_list) {
data_list = this.data_list;
count = 0;
continue_or_not = true;
}
public boolean check_data() {
// TODO Auto-generated method stub
int count = 0;
for (int item : data_list) {
if (item != 0) {
count++;
if (count>=3) {
break;
}
}
}
if (count>=3) {
return false;
} else {
return true;
}
}
// increment the counter by 1
public void increment() {
count++;
}
// return the current count
public int value() {
return count;
}
}
This doesn't work because it thinks the data_list is a null pointer(I know I'm declaring it null, but if I make it private int[] data_list = data_list it doesn't compile either). My ultimate goal is to have some kind of controls, in this case its limiting it to 2 items but I want to also add other limits like total value of al items cannot exceed X or cannot be lower than X and want to save CPU power by not having to do full calculations every time. So I think I need to be able to increment the values and then need to check that those increments haven't exceeded thresholds.
Can anyone help me understand what I'm doing wrong? Am I only wrong with syntax; or am I designing this wrong?
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data());
When you are calling checker.check_data(), its trying to parse through the data_list, but its empty. So, it throws a NullPointerException. The data_list is empty because inside your constructor, you may need to initialize like this this.data_list = data_list instead of data_list = this.data_list (here this.data_list has no reference so NULL)
If you avoid that call, the output will be 2,3,4,5,6,7,8,9,10,11.
I'm making a simulation in a 3D environment. So far, I have the movements of all the creatures, but it is not "smooth". I've tried quite a few things but was horribly wrong. Now I just have no idea what to do. I was thinking of implementing a vector (not vector class) but don't really know how.
import env3d.EnvObject;
import java.util.ArrayList;
abstract public class Creature extends EnvObject
{
/**
* Constructor for objects of class Creature
*/
public Creature(double x, double y, double z)
{
setX(x);
setY(y);
setZ(z);
setScale(1);
}
public void move(ArrayList<Creature> creatures, ArrayList<Creature> dead_creatures)
{
double rand = Math.random();
if (rand < 0.25) {
setX(getX()+getScale());
setRotateY(90);
} else if (rand < 0.5) {
setX(getX()-getScale());
setRotateY(270);
} else if (rand < 0.75) {
setZ(getZ()+getScale());
setRotateY(0);
} else if (rand < 1) {
setZ(getZ()-getScale());
setRotateY(180);
}
if (getX() < getScale()) setX(getScale());
if (getX() > 50-getScale()) setX(50 - getScale());
if (getZ() < getScale()) setZ(getScale());
if (getZ() > 50-getScale()) setZ(50 - getScale());
// collision detection
if (this instanceof Fox) {
for (Creature c : creatures) {
if (c.distance(this) < c.getScale()+this.getScale() && c instanceof Tux) {
dead_creatures.add(c);
}
}
}
}
}
import env3d.Env;
import java.util.ArrayList;
/**
* A predator and prey simulation. Fox is the predator and Tux is the prey.
*/
public class Game
{
private Env env;
private boolean finished;
private ArrayList<Creature> creatures;
/**
* Constructor for the Game class. It sets up the foxes and tuxes.
*/
public Game()
{
// we use a separate ArrayList to keep track of each animal.
// our room is 50 x 50.
creatures = new ArrayList<Creature>();
for (int i = 0; i < 55; i++) {
if (i < 5) {
creatures.add(new Fox((int)(Math.random()*48)+1, 1, (int)(Math.random()*48)+1));
} else {
creatures.add(new Tux((int)(Math.random()*48)+1, 1, (int)(Math.random()*48)+1));
}
}
}
/**
* Play the game
*/
public void play()
{
finished = false;
// Create the new environment. Must be done in the same
// method as the game loop
env = new Env();
// Make the room 50 x 50.
env.setRoom(new Room());
// Add all the animals into to the environment for display
for (Creature c : creatures) {
env.addObject(c);
}
// Sets up the camera
env.setCameraXYZ(25, 50, 55);
env.setCameraPitch(-63);
// Turn off the default controls
env.setDefaultControl(false);
// A list to keep track of dead tuxes.
ArrayList<Creature> dead_creatures = new ArrayList<Creature>();
// The main game loop
while (!finished) {
if (env.getKey() == 1) {
finished = true;
}
// Move each fox and tux.
for (Creature c : creatures) {
c.move(creatures, dead_creatures);
}
// Clean up of the dead tuxes.
for (Creature c : dead_creatures) {
env.removeObject(c);
creatures.remove(c);
}
// we clear the ArrayList for the next loop. We could create a new one
// every loop but that would be very inefficient.
dead_creatures.clear();
// Update display
env.advanceOneFrame();
}
// Just a little clean up
env.exit();
}
/**
* Main method to launch the program.
*/
public static void main(String args[]) {
(new Game()).play();
}
}
You haven't shown enough of your program. Basically, if you want animation to be smooth, and you want to do it yourself (as opposed to using JavaFX or something), then you need to do lots of inter-frames. So rather than advancing an entire timer tick, advance a 10th of a timer tick, move everything on a screen a tiny bit, and then advance again. You should have the background redraw happening every 10th of a second for smooth animation.
As vy32 mentioned, we need to see more of your code. But it looks like you are missing timing code.
What you probably want to do is check the time each iteration of your game loop and then sleep for a certain amount of time to achieve some desired frame rate. Otherwise your game loop will run hundreds of thousands of times a second.
Alternatively, you should be advancing your creatures by a distance that is proportional to the amount of time that has elapsed since the previous frame.
Here is an example of a very simple regulated loop ("fps" is the desired framerate):
private long frameLength = 1000000000 / fps;
public void run() {
long ns = System.nanoTime();
while (!finished) {
//Do one frame of work
step();
//Wait until the time for this frame has elapsed
try {
ns += frameLength;
Thread.sleep(Math.max(0, (ns - System.nanoTime())/10000000));
} catch (InterruptedException e) {
break;
}
}
}
It should be very easy to retrofit this into your game loop.