LibGDX - isKeyPressed() do not count just one - java

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;

Related

Changes to Array not reflecting in program?

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;
}

Handling sequences of mouse clicks where each click is dependant on previous ones

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();
}
}**

Greenfoot - isKeyDown() seems to hold its value

This is a sprinting function for a game, if the player has greater then 0% spring left then he can sprint, if it is at 0% the player cannot sprint. If the player is not sprinting then the sprint % will start to regenerate.
The problem:
When the player hits 0% sprint the player is still able to sprint.
public class User extends Characters
{
private int walk = 3;
private int run = 10;
private int speed = walk;
private boolean isRunning = false;
private int runDuration = 100;
private int baseRunDuration = 100;
private int runCoolDown = 300;
public void act()
{
playerMove();
}
//Contains movement inputs as well as run imputs
void playerMove(){
getWorld().showText("Run Duration: " + runDuration, 100, 100);
if(Greenfoot.isKeyDown("w") ){
setLocation(getX(), getY()-speed);
}
if(Greenfoot.isKeyDown("a")){
move(-speed);
}
if(Greenfoot.isKeyDown("s")){
setLocation(getX(), getY()+speed);
}
if(Greenfoot.isKeyDown("d")){
move(+speed);
}
if(Greenfoot.isKeyDown("shift") && runDuration > 0){
if(runDuration > 0){
isRunning = true;
speed = run;
runDuration--;
}
}
else{
speed = walk;
isRunning = false;
}
if(isRunning == false){
if(runDuration < baseRunDuration){
runDuration++;
}
}
}
}
Obicere is right that you are either sprinting, or you're alternately sprinting and not sprinting, giving a half-speed sprint. There's various ways to fix this. I'd suggest only recharging your sprint when you're not moving. You can do this using a boolean to keep track of whether you've moved this frame, or simply by using else-if to change your middle block of code to:
if(Greenfoot.isKeyDown("w") ){
setLocation(getX(), getY()-speed);
}
else if(Greenfoot.isKeyDown("a")){
move(-speed);
}
else if(Greenfoot.isKeyDown("s")){
setLocation(getX(), getY()+speed);
}
else if(Greenfoot.isKeyDown("d")){
move(+speed);
}
else if(runDuration < baseRunDuration){
runDuration++;
}
Note the new elses, and the final clause on the end which is moved up from the bottom of your code.

How to delete entity when "health <= 0"?

Ive been followin an online tutorial for a top down shooter game, but the tut is unfinished (and I dont see the creator continuing it), so Id like to complete it myself. So far, the tutorial has helped me to give the player health and a string above it to show how much health, but nothing happens when health gets to and goes below 0. It just goes down in the increment I set. Id like the game to close when there is no more health, so how would I go about doing this?
This is what happens when the player gets hit by an enemy bullet:
private void playerBulletCollision(){
for (Bullet b:mobBullets){
if (b.collisionBox.intersects(player.collisionBox)){
player.health -= b.damage;
b.isAlive = false;
break;
}
}
}
And this is what happens when player bullet hits enemy
private void mobBulletCollision(){
for (Bullet b:bullets){
for (Entity m: mobs){
if (b.collisionBox.intersects(m.collisionBox)){
m.health -= b.damage;
b.isAlive = false;
break;
}
}
}
}
so how can I make it so the game ends when player health is no more? Sorry if my explanation isnt clear or the code I showed isnt enough/not relevant. Tell me and Ill fix it to the best of my abilities.
Thank you
Edit: I tried to make it so it checks to see if health <= 0 and if it does it despawns:
private void playerBulletCollision(){
for (MobBullet b:mobBullets){
if (b.collisionBox.intersects(player.collisionBox)){
player.health -= b.damage;
b.isAlive = false;
break;
}
if(player.health <=0)
player.isAlive = false;
}
}
It didnt work.
Edit 2: This is the process to remove the dead enemies. I think because there is no such thing for the player, player.health = false; does nothing.
private void removeDead(){
for (int i = 0; i <bullets.size(); i++){
if (bullets.get(i).isAlive == false )
bullets.remove(i);
}
for (int i = 0; i <mobs.size(); i++){
if (mobs.get(i).isAlive == false )
mobs.remove(i);
}
for (int i = 0; i <mobBullets.size(); i++){
if (mobBullets.get(i).isAlive == false )
mobBullets.remove(i);
}
bullets.trimToSize();
mobs.trimToSize();
mobBullets.trimToSize();
}
How should this piece be modified to incorporate the player?
You should do this. On a collision you decrement the health and after the loop you check the player health if this is <=0 you set isAlive to false.
private void playerBulletCollision(){
for (MobBullet b:mobBullets){
if (b.collisionBox.intersects(player.collisionBox)){
player.health -= b.damage;
b.isAlive = false;
break;
}
}
if(player.health <=0){
player.isAlive = false;
}

Javafx - Syncronization delay - card flips

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();
}
}
}

Categories

Resources