why applyLinearImpulse is not working, using libgdx? - java

I need some help when I try make a game, which is controlled by commands. I need to use textarea and I try to pass the value from textarea to contructer. But my game is not working. I know what mistake is appeared because I call contructer 2 times. I add some code:
public class inputs extends Game implements Disposable {
private Skin skin;
private Viewport viewport;
public Stage stage;
private Table table;
private TextButton button;
public TextArea TF;
private Main game;
public SpriteBatch spriteBatch;
public inputs(final SpriteBatch sb, final Main game){
viewport = new FitViewport(1200, 624, new OrthographicCamera());
stage = new Stage(viewport, sb);
skin = new Skin(Gdx.files.internal("data/uiskin.json"));
button = new TextButton("Send", skin, "default");
TF = new TextArea("", skin);
TF.setWidth(300);
TF.setHeight(570);
TF.setPosition(0,54);
button.setWidth(300);
button.setHeight(54);
button.setPosition(0, 0);
button.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
spriteBatch = new SpriteBatch();
setScreen(new MainCodeProgram(game,TF.getText(),spriteBatch));
TF.setText("");
button.setTouchable(Touchable.disabled);
}
});
stage.addActor(TF);
stage.addActor(button);
Gdx.input.setInputProcessor(stage);
Gdx.input.setInputProcessor(stage);
}
public void setButtonTouchable(){
button.setTouchable(Touchable.enabled);
}
#Override
public void create() {
}
#Override
public void dispose() {
stage.dispose();
}
}
Main.java :
public class Main extends Game {
public SpriteBatch spriteBatch;
public static int Width = 400;
public static int Height = 208;
public static final short objectwhit = 32;
public static final short mariowhit= 2;
public static final short itemwhit = 256;
public static float PPM = 100;
public static final short marioheadwhit = 512;
public static final short blockwhit = 4;
public static final short coinwhit = 8;
public static final short nothing = 0;
public static final short ground = 1;
public static final short destroyedwhit = 16;
public static final short enemywhit = 64;
public static final short enemyheadwhit = 128;
public static inputs inp1;
#Override
public void create () {
spriteBatch = new SpriteBatch();
inp1 = new inputs(spriteBatch,this);
setScreen(new MainCodeProgram(this,null,spriteBatch));
}
#Override
public void dispose() {
super.dispose();
spriteBatch.dispose();
}
}
Pseudocode recognize :
public class MainCodeProgram extends JFrame implements Screen, TextInputListener, Disposable {
static ArrayList<String> firstintkint = new ArrayList<String>();
static ArrayList<Integer> firstintvalue = new ArrayList<Integer>(); //int
private Main game;
private OrthographicCamera orthographicCamera;
private TextureAtlas textureAtlas;
public static int whichlevel=1;
private Mario player;
public Stage stage;
private Hud hud;
private TmxMapLoader maploader;
private TiledMap tilemap;
static int walks = 0;
private OrthogonalTiledMapRenderer renderer;
private Viewport viewport;
private World world;
private Array<Item> items;
private LinkedBlockingQueue<ItemVector> itemstoSpawn;
String text="";
private Box2DDebugRenderer b2dr;
private OtherWorldCreator otherWorldCreator;
public String kodas;
public boolean b =false;
public MainCodeProgram(){
}
public MainCodeProgram(Main game, String text,SpriteBatch spriteBatch) {
if(text == null){
textureAtlas = new TextureAtlas("All.pack");
this.game= game;
orthographicCamera = new OrthographicCamera();
viewport = new FitViewport(Main.Width / Main.PPM, Main.Height / Main.PPM, orthographicCamera);
viewport.apply();
hud = new Hud(game.spriteBatch);
newlevel();
otherWorldCreator = new OtherWorldCreator(this);
player = new Mario( this);
world.setContactListener(new WorldContact());
items = new Array<Item>();
itemstoSpawn = new LinkedBlockingQueue<ItemVector>();
}
if(text != null){
b = true;
textureAtlas = new TextureAtlas("All.pack");
this.game= game;
orthographicCamera = new OrthographicCamera();
viewport = new FitViewport(Main.Width / Main.PPM, Main.Height / Main.PPM, orthographicCamera);
viewport.apply();
hud = new Hud(spriteBatch);
newlevel();
otherWorldCreator = new OtherWorldCreator(this);
player = new Mario( this);
world.setContactListener(new WorldContact());
items = new Array<Item>();
itemstoSpawn = new LinkedBlockingQueue<ItemVector>();
input(text);
}
}
public TextureAtlas getAtlas(){return textureAtlas;}
#Override
public void show() {}
int i = 0, kur = 1;
public void handleInput(float dt) {
if (player.currentstate!= Mario.State.died) {
;
}
}
public void spawnItem(ItemVector idef)
{
itemstoSpawn.add(idef);
}
public void handleSpawningItems(){
if(!itemstoSpawn.isEmpty())
{
ItemVector idef = itemstoSpawn.poll();
if(idef.type == Mushroom.class){items.add(new Mushroom(this, idef.position.x,idef.position.y));}
}
}
public void update(float dt)
{
handleInput(dt);
handleSpawningItems();
world.step(1 / 60f, 6, 2);
player.update(dt);
for (Enemy enemy: otherWorldCreator.getEbemies()) {
enemy.update(dt);
if(enemy.getX() < player.getX() + 224 / Main.PPM){enemy.b2body.setActive(true);}
}
for(Item item : items){item.update(dt);}
hud.refresh(dt);
if(player.currentstate!= Mario.State.died){orthographicCamera.position.x = player.b2body.getPosition().x;}
orthographicCamera.update();
renderer.setView(orthographicCamera);
}
public boolean gameOver()
{
if(player.currentstate== Mario.State.died && palyer.getStateTimer() > 3){return true;}
if(whichlevel== 5){return true;}
else if(player.getY() <0){return true;}
else{return false;}
}
public boolean Youwonn()
{
if(whichlevel==4){return true;}
else{return false;}
}
#Override
public void render(float delta) {
update(delta);
int k = 0;
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.render();
b2dr.render(world, orthographicCamera.combined);
game.spriteBatch.setProjectionMatrix(orthographicCamera.combined);
game.spriteBatch.begin();
game.draw(game.spriteBatch);
for (Enemy enemy: otherWorldCreator.getEbemies())
enemy.draw(game.spriteBatch);
for(Item item : items)
item.draw(game.spriteBatch);
game.spriteBatch.end();
game.spriteBatch.setProjectionMatrix(hud.stage.getCamera().combined);
hud.stage.draw();
if(gameOver())
{
whichlevel= 1;
game.setScreen(new GameOverWorld(game));
dispose();
}
if ((player.getX() > 15 && whichlevel< 4)) {
whichlevel++;
if(whichlevel!=4){
game.setScreen(new MainCodeProgram(game,"",""));
dispose();
}
}
if (whichlevel==4)
{
game.setScreen(new WinWindow(game));
dispose();
}
Main.inp1.stage.draw();
}
#Override
public void resize(int width, int height) {viewport.update(width,height);}
public World getWorld(){ return world;}
public TiledMap getMap(){return tilemap;}
#Override
public void pause() {}
#Override
public void resume() {}
#Override
public void hide() {}
public void newlevel()
{
maploader = new TmxMapLoader();
if(whichlevel== 1){tilemap = maploader.load("mario1lvl.tmx");
}
if (whichlevel== 2){tilemap = maploader.load("mario2lvl.tmx");}
if (whichlevel== 3){tilemap = maploader.load("mario3lvl.tmx");}
if (whichlevel== 4){
game.setScreen(new WinWindow(game));}
renderer = new OrthogonalTiledMapRenderer(tilemap, 1 / Main.PPM);
orthographicCamera.position.set(viewport.getWorldWidth() / 2, viewport.getWorldHeight() / 2, 0);
world = new World(new Vector2(0, -10 ), true);
b2dr = new Box2DDebugRenderer();
}
#Override
public void dispose() {
tilemap.dispose();
renderer.dispose();
world.dispose();
b2dr.dispose();
hud.dispose();
}
public void input(String text) {
ArrayList<String> pseudocode = new ArrayList<String>();
this.text = text;
i = 0;
String str = text;
String split[] = str.split("/");
for (String spacebar : split) {
pseudocode.add(spacebar);
i = 0;
}
int foras = 0;
for (int i = 0;i < pseudocode.size(); i++) {
if(pseudocode.get(i).equals("jump")||pseudocode.get(i).equals("jump;")){jump();}
if(pseudocode.get(i).startsWith("int")){recognizeint(pseudocode.get(i));}
if(pseudocode.get(i).startsWith("for"))
{
recognizefor(pseudocode.get(i));
foras++;
}
if(pseudocode.get(i).startsWith("while")){ recognizewhile(pseudocode.get(i));}
if(pseudocode.get(i).endsWith("--")||pseudocode.get(i).endsWith("--;"))
{
if(foras == 0){minuminus(pseudocode.get(i));}
else{foras--;}
}
if(pseudocode.get(i).endsWith("++")||pseudocode.get(i).endsWith("++;"))
{
if(foras==0){plusplus(pseudocode.get(i));}
else{foras--;}
}
if(istheend){
walks = 0;
istheend = false;
}
}
}
#Override
public void canceled() {
}
public void jump()
{
if(istheend){
try {Thread.sleep(1*walks);
} catch (InterruptedException e) {e.printStackTrace();}}
else{try {Thread.sleep(50*walks);
} catch (InterruptedException e) {e.printStackTrace();}}
walks = 0;
if(player.b2body.getLinearVelocity().y == 0){
if(b == true) {
player.b2body.applyLinearImpulse(new Vector2(0, 4f), player.b2body.getWorldCenter(), true); //Mistake is here
}
}
else if(player.b2body.getLinearVelocity().y != 0){
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
player.b2body.applyLinearImpulse(new Vector2(0, 4f), player.b2body.getWorldCenter(), true);
}
}
}
Mistake is here:
public void jump()
{
if(istheend){
try {Thread.sleep(1*walks);
} catch (InterruptedException e) {e.printStackTrace();}}
else{try {Thread.sleep(50*walks);
} catch (InterruptedException e) {e.printStackTrace();}}
walks = 0;
if(player.b2body.getLinearVelocity().y == 0){
if(b == true) {
player.b2body.applyLinearImpulse(new Vector2(0, 4f), player.b2body.getWorldCenter(), true); //Mistake is here
}
}
else if(player.b2body.getLinearVelocity().y != 0){
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
player.b2body.applyLinearImpulse(new Vector2(0, 4f), player.b2body.getWorldCenter(), true);
}
}
Thank you very much for help

I believe your code it is a little confusing, for the ApplyLinearImpulse works in your HandleInput you send a command jump() and inside the Entity you make the jump() method and also to make the animation to join the b2body, with update(dt) method + getState() + getFrame().
Your jump() method should be simple like this
public void jump(){
if(currentState != State.Jumping){
b2body.applyLinearImpulse(new Vector2(0,4f), b2body.getWorldCenter(), true);
currentState=State.JUMPING
}
}
What should be stuck the applyLinearImpulse are the conditions you included. Try to remove it all and leave only the main stuff. Use also LOGS everywhere Gdx.app.log("MESSAGE:", "" + variable); and you can start seeing what is going in and out with your methods and variables, and find your mistake.
Also, if you would like to learn more and don't forget any detail regarding map / viewport / b2bodies, follow this tutorial that I use as my guide for B2Box (Youtube / Github), it is very quick and easy to follow and you are going to love use B2Box for everything :-) and also continue with LibGdx Framework developments.
Click here Youtube Tutorial.
Click here GitHub codes.
I hope it helps you.
Cheers!!

Related

LibGDX: How to show/hide an overlay popup menu from the main game screen repetitively

I am doing a game called Fuego Peligro (based from another LibGDX "tutorial" project called Ninja Rabbit by nfantone, https://github.com/nfantone/ninja-rabbit) as my Thesis on my BIT course on my university, and I want an overlay menu of somesorts to show/hide over the main game screen.
The popup menu is like a checkpoint that displays a simple trivia-type minigame from the main platforming game. It is called through a Telegraph (handleMessage) method. The only problem is when the message is repeated and if the popup has been shown before, it does not want to re-show again.
All of the files and other details are here in this link: https://github.com/NinjaSiren/FuegoPeligro
All the .java files are here: https://github.com/NinjaSiren/FuegoPeligro/tree/master/core/src/com/mygdx/fuegopeligro
Here's the java class that calls all in-game overlay to render: LevelGraphicsProcessor.java
public class LevelGraphicsProcessor implements GraphicsProcessor, Telegraph {
private final LevelRenderer mapRenderer;
private final GameOverOverlay gameOver;
private final LevelEndOverlay levelEnd;
private MultipleChoice multipleChoice;
private FourPicsOneWord fourPicsOneWord;
private LetterPuzzle letterPuzzle;
private Wordscapes wordscapes;
private boolean renderGameOver;
private boolean renderLevelEnd;
private boolean minicamSelection;
private final CurrentPlayerStatus status;
private final NinjaRabbit ninja;
private final Entity entity;
public LevelGraphicsProcessor(final AssetManager assets, final LevelRenderer mapRenderer,
final FuegoPeligro game, final NinjaRabbit ninjaRabbit,
final CurrentPlayerStatus player) {
status = player;
ninja = ninjaRabbit;
if (ninjaRabbit == null) {
throw new IllegalArgumentException("'character' cannot be null"); }
this.entity = ninjaRabbit;
gameOver = new GameOverOverlay(game.getBatch(), assets, game);
levelEnd = new LevelEndOverlay(game.getBatch(), assets, game);
multipleChoice = new MultipleChoice(assets, game, ninjaRabbit);
fourPicsOneWord = new FourPicsOneWord(assets, game, ninjaRabbit);
letterPuzzle = new LetterPuzzle(assets, game, ninjaRabbit);
wordscapes = new Wordscapes(assets, game, ninjaRabbit);
this.mapRenderer = mapRenderer;
MessageManager.getInstance().addListeners(this, MessageType.GAME_OVER.code());
MessageManager.getInstance().addListeners(this, MessageType.FINISH_LEVEL.code());
MessageManager.getInstance().addListeners(this, MessageType.COLLECTED.code());
}
#Override
public void update(final Entity character, final Camera camera) {
mapRenderer.render((OrthographicCamera) camera);
}
/*
* (non-Javadoc)
*
* #see com.mygdx.fuegopeligro.graphics.GraphicsProcessor#draw(com.mygdx.fuegopeligro.entity.Entity,
* com.badlogic.gdx.graphics.g2d.Batch)
*/
#Override
public void draw(final Entity entity, final Batch batch) {
mapRenderer.update();
if (renderGameOver) {
gameOver.render(Gdx.graphics.getDeltaTime());
} else if (renderLevelEnd) {
levelEnd.render(Gdx.graphics.getDeltaTime());
} else if (minicamSelection) {
multipleChoice.render(Gdx.graphics.getDeltaTime());
wordscapes.render(Gdx.graphics.getDeltaTime());
letterPuzzle.render(Gdx.graphics.getDeltaTime());
fourPicsOneWord.render(Gdx.graphics.getDeltaTime());
entity.changeState(NinjaRabbitState.IDLE);
byte worldValue = status.getCurrentWorld();
//short levelValue = status.getCurrentLevel();
short mgValue = status.getMGValue();
if (worldValue == 1) {
//short easyValue = status.getEqaValue();
if (mgValue == 1) {
multipleChoice.setVisible(true);
Gdx.input.setInputProcessor(multipleChoice.stage);
if (multipleChoice.enterAnswer.isPressed()) {
multipleChoice.setVisible(false);
Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
}
} else if (mgValue == 2) {
wordscapes.setVisible(true);
Gdx.input.setInputProcessor(wordscapes.stage);
if (wordscapes.enterAnswer.isPressed()) {
wordscapes.setVisible(false);
Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
}
} else if (mgValue == 3) {
letterPuzzle.setVisible(true);
Gdx.input.setInputProcessor(letterPuzzle.stage);
if (letterPuzzle.enterAnswer.isPressed()) {
letterPuzzle.setVisible(false);
Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
}
} else if (mgValue == 4) {
fourPicsOneWord.setVisible(true);
Gdx.input.setInputProcessor(fourPicsOneWord.stage);
if (fourPicsOneWord.enterAnswer.isPressed()) {
fourPicsOneWord.setVisible(false);
Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
}
}
} else if (worldValue == 2) {
//short hardValue = status.getHqaValue();
if (mgValue == 1) {
multipleChoice.setVisible(true);
Gdx.input.setInputProcessor(multipleChoice.stage);
if (multipleChoice.enterAnswer.isPressed()) {
multipleChoice.setVisible(false);
Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
}
} else if (mgValue == 2) {
wordscapes.setVisible(true);
Gdx.input.setInputProcessor(wordscapes.stage);
if (wordscapes.enterAnswer.isPressed()) {
wordscapes.setVisible(false);
Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
}
} else if (mgValue == 3) {
letterPuzzle.setVisible(true);
Gdx.input.setInputProcessor(letterPuzzle.stage);
if (letterPuzzle.enterAnswer.isPressed()) {
letterPuzzle.setVisible(false);
Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
}
} else if (mgValue == 4) {
fourPicsOneWord.setVisible(true);
Gdx.input.setInputProcessor(fourPicsOneWord.stage);
if (fourPicsOneWord.enterAnswer.isPressed()) {
fourPicsOneWord.setVisible(false);
Gdx.input.setInputProcessor(new NinjaRabbitInputProcessor(ninja));
}
}
}
}
}
#Override
public boolean handleMessage(final Telegram msg) {
renderGameOver = msg.message == MessageType.GAME_OVER.code();
renderLevelEnd = msg.message == MessageType.FINISH_LEVEL.code();
minicamSelection = msg.message == MessageType.COLLECTED.code();
return true;
}
#Override
public void resize(final int width, final int height) {
gameOver.resize(width, height);
levelEnd.resize(width, height);
multipleChoice.resize(width, height);
wordscapes.resize(width, height);
letterPuzzle.resize(width, height);
fourPicsOneWord.resize(width, height);
}
#Override
public void dispose() {
gameOver.dispose();
levelEnd.dispose();
multipleChoice.dispose();
wordscapes.dispose();
letterPuzzle.dispose();
fourPicsOneWord.dispose();
}
}
Here is one of the popup minigame I want to show when a the Message is received, and hidden when a button is clicked.: MultipleChoice.java
public class MultipleChoice implements Disposable {
private static final String QUESTION_LABEL = "CHECKPOINT: MULTIPLE CHOICE";
private static final String ENTER_ANSWER = "ENTER";
private static final String HINT_ANSWER = "HINT";
public final Stage stage;
private final NinjaRabbit ninja;
private final Label QuestionLabel;
private final Label QuestionText;
private final TextButton answer1;
private final TextButton answer2;
private final TextButton answer3;
private final TextButton answer4;
public final TextButton enterAnswer;
private final TextButton enterHints;
private final Table table;
public MultipleChoice(final AssetManager assets, final FuegoPeligro game,
final NinjaRabbit ninjaRabbit) {
stage = new Stage(new ScreenViewport(), game.getBatch());
ninja = ninjaRabbit;
Label.LabelStyle style = new Label.LabelStyle();
AssetManager assetManager = new AssetManager();
assetManager.load(Assets.GAME_UI_SKIN);
assetManager.finishLoading();
Skin skin = assetManager.get(Assets.GAME_UI_SKIN);
style.fontColor = Color.WHITE;
style.font = assets.get(Assets.HUD_FONT);
QuestionLabel = new Label(QUESTION_LABEL, style);
style.fontColor = Color.WHITE;
style.font = assets.get(Assets.HUD_FONT);
QuestionText = new Label("", style);
answer1 = new TextButton("", skin);
answer1.addListener(new ClickListener() {
#Override
public void clicked(final InputEvent event, final float x, final float y) {
}
});
answer2 = new TextButton("", skin);
answer2.addListener(new ClickListener() {
#Override
public void clicked(final InputEvent event, final float x, final float y) {
}
});
answer3 = new TextButton("", skin);
answer3.addListener(new ClickListener() {
#Override
public void clicked(final InputEvent event, final float x, final float y) {
}
});
answer4 = new TextButton("", skin);
answer4.addListener(new ClickListener() {
#Override
public void clicked(final InputEvent event, final float x, final float y) {
}
});
// enter answer
enterAnswer = new TextButton(ENTER_ANSWER, skin);
enterAnswer.addListener(new ClickListener() {
#Override
public void clicked(final InputEvent event, final float x, final float y) {
}
});
// enter hints
enterHints = new TextButton(HINT_ANSWER, skin);
enterHints.addListener(new ClickListener() {
#Override
public void clicked(final InputEvent event, final float x, final float y) {
}
});
table = new Table();
table.setFillParent(true);
table.setDebug(true);
table.add(QuestionLabel).expand(true, false).center();
table.row().pad(20, 0, 0, 10);
table.add(QuestionText).expand(true, false);
table.row().pad(10, 0, 0, 20);
table.add(answer1).expand(true, false);
table.add(answer2).expand(true, false);
table.row().pad(10, 0, 0, 20);
table.add(answer3).expand(true, false);
table.add(answer4).expand(true, false);
table.row().pad(10, 0, 0, 20);
table.add(enterAnswer).expand(true, false);
table.add(enterHints).expand(true, false);
table.setVisible(false);
stage.addActor(table);
stage.setKeyboardFocus(table);
}
public void render(final float delta) {
Gdx.gl20.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl20.glDisable(GL20.GL_BLEND);
stage.getBatch().end();
stage.act(delta);
stage.draw();
stage.getBatch().begin();
}
public void resize(final int width, final int height) { stage.getViewport().update(width, height); }
#Override
public void dispose() {
stage.dispose();
}
public void setVisible(boolean value) {
table.setVisible(value);
}
}
When using LibGDX, the standard convention for UI is to use Scene2D, and Scene2D objects must be contained within a Stage - to use a window like overlay, one can use the special Table derivative: the Window class.
Any Actors you wish to be in the overlay can be added to the Window instance and positioned within just like its own Stage or Table, and the Window can be added to the scene and removed from the scene - even faded in and out using the fade(In/Out) actions (instead of directly adding and removing as is done in the following example):
public class ExampleClass {
...
private Stage stage = new Stage(...);
private Window popUp = new Window("...");
private TextButton windowButton1 = ..., windowButton2 = ...;
...
public ExampleClass() {
...
Gdx.setInputProcessor(stage); //Allows input to Scene2D components - important!
//Register click listeners to buttons to close window when clicked
windowButton1.addListener(new CloseButtonListener(this));
windowButton2.addListener(new CloseButtonListener(this));
...
//Add buttons to window
popUp.add(windowButton1);
popUp.add(windowButton2);
...
}
//Run when message is received
public void messageReceived() {
...
stage.add(popUp); //Add window to stage you want to overlay
...
}
...
public Stage getStage() {
return stage;
}
public Window getPopUp() {
return popUp;
}
...
}
class CloseButtonListener implements ClickListener { //Inner class for handling button clicks, multiple can be created for different button types with different logic when window is closed.
private ExampleClass exampleInstance;
public CloseButtonListener(ExampleClass exampleInstance) {
this.exampleInstance = exampleInstance;
}
//Remove the window from the stage when the button is clicked, handles any other logic too depending on button.
#Override
public void clicked(InputEvent event, float x, float y) {
...
exampleInstance.addAction(Actions.removeActor());
...
}
}

LibGDX: Making random and different Pipes appear (Flappy Bird Style Game)

I'm new to the Android game making scene and for my first game, I made a successful Flappy Bird clone thanks to LibGdx, coffee, and Youtube. To make it NOT be a total clone however, I'm trying to add different types of pipes and this is where I need help with.
I'm trying to make it so that the 4 different types of pipes (or trees, as they are in my game) would appear randomly to make it unpredictable but so far I've only ever managed to make 1 type appear. Here are the codes I used for 2 of the types and for my Play State.
HTree class implementation:
public class HTree {
public static final int TREE_WIDTH = 52;
private static final int FLUCTUACTION = 130;
private static final int TREE_GAP = 100;
private static final int LOWEST_OPENING = 120;
private Texture toptree,bottomtree;
private Vector2 postoptree,posbottree;
private Rectangle boundsTop,boundsBot;
private Random rand;
public HTree(float x){
toptree = new Texture("uppertree.png");
bottomtree = new Texture("bottomtree.png");
rand = new Random();
postoptree = new Vector2(x, rand.nextInt(FLUCTUACTION) + TREE_GAP + LOWEST_OPENING);
posbottree = new Vector2(x, postoptree.y - TREE_GAP - bottomtree.getHeight());
boundsTop = new Rectangle(getPostoptree().x,getPostoptree().y, toptree.getWidth(), toptree.getHeight());
boundsBot = new Rectangle(getPosbottree().x,getPosbottree().y, bottomtree.getWidth(), bottomtree.getHeight());
}
public Texture getToptree() {
return toptree;
}
public Texture getBottomtree() {
return bottomtree;
}
public Vector2 getPostoptree() {
return postoptree;
}
public Vector2 getPosbottree() {
return posbottree;
}
public void reposition(float x){
postoptree.set(x, rand.nextInt(FLUCTUACTION) + TREE_GAP + LOWEST_OPENING);
posbottree.set(x, postoptree.y - TREE_GAP - bottomtree.getHeight());
boundsTop.setPosition(postoptree.x,postoptree.y);
boundsBot.setPosition(posbottree.x,posbottree.y);
}
public boolean collides(Rectangle player){
return player.overlaps(boundsTop) || player.overlaps(boundsBot);
}
public void dispose(){
toptree.dispose();
bottomtree.dispose();
}
}
HTree2 class implementation:
public class HTree2 {
public static final int TREE_WIDTH = 52;
private static final int FLUCTUACTION = 130;
private static final int TREE_GAP = 100;
private static final int LOWEST_OPENING = 120;
private Texture toptree2,bottomtree2;
private Vector2 postoptree2,posbottree2;
private Rectangle boundsTop2,boundsBot2;
private Random rand;
public HTree2(float x){
toptree2 = new Texture("uppertree2.png");
bottomtree2 = new Texture("bottomtree2.png");
rand = new Random();
postoptree2 = new Vector2(x, rand.nextInt(FLUCTUACTION) + TREE_GAP + LOWEST_OPENING);
posbottree2 = new Vector2(x, postoptree2.y - TREE_GAP - bottomtree2.getHeight());
boundsTop2 = new Rectangle(getPostoptree().x,getPostoptree().y, toptree2.getWidth(), toptree2.getHeight());
boundsBot2 = new Rectangle(getPosbottree().x,getPosbottree().y, bottomtree2.getWidth(), bottomtree2.getHeight());
}
public Texture getToptree() {
return toptree2;
}
public Texture getBottomtree() {
return bottomtree2;
}
public Vector2 getPostoptree() {
return postoptree2;
}
public Vector2 getPosbottree() {
return posbottree2;
}
public void reposition2(float x){
postoptree2.set(x, rand.nextInt(FLUCTUACTION) + TREE_GAP + LOWEST_OPENING);
posbottree2.set(x, postoptree2.y - TREE_GAP - bottomtree2.getHeight());
boundsTop2.setPosition(postoptree2.x,postoptree2.y);
boundsBot2.setPosition(posbottree2.x,posbottree2.y);
}
public boolean collides2(Rectangle player){
return player.overlaps(boundsTop2) || player.overlaps(boundsBot2);
}
public void dispose2(){
toptree2.dispose();
bottomtree2.dispose();
}
}
HPlayState class implementation:
public class HPlayState extends HState {
private static final int TREE_SPACING = 125;
private static final int TREE_COUNT = 4;
private static final int GROUND_Y_OFFSET = -50;
private HBird bird;
private Texture bg;
private Texture ground;
private Vector2 groundPos1,groundPos2;
private Array<HTree> trees;
private Array<HTree2> trees2;
public HPlayState(HGameStateManager gsm) {
super(gsm);
bird = new HBird(50,300);
cam.setToOrtho(false, HBonGame.WIDTH/2,HBonGame.HEIGHT/2);
bg = new Texture("background3.jpg");
ground = new Texture("ground.png");
groundPos1 = new Vector2(cam.position.x-cam.viewportWidth/2,GROUND_Y_OFFSET);
groundPos2 = new Vector2((cam.position.x-cam.viewportWidth/2) + ground.getWidth(),GROUND_Y_OFFSET);
trees = new Array<HTree>();
trees2 = new Array<HTree2>();
for(int i=1; i <= TREE_COUNT; i++){
trees.add(new HTree(i * (TREE_SPACING + HTree.TREE_WIDTH)));
}
for (int i=1; i >= TREE_COUNT; i++){
trees2.add(new HTree2(i * (TREE_SPACING + HTree2.TREE_WIDTH)));
}
}
#Override
protected void handleInput() {
if (Gdx.input.justTouched())
bird.jump();
}
#Override
public void update(float dt) {
handleInput();
updateGround();
bird.update(dt);
cam.position.x = bird.getPosition().x + 80;
for (int i=0; i < trees.size; i++ ){
HTree tree = trees.get(i);
if (cam.position.x - (cam.viewportWidth / 2) > tree.getPostoptree().x + tree.getToptree().getWidth()){
tree.reposition(tree.getPostoptree().x + ((HTree.TREE_WIDTH + TREE_SPACING) * TREE_COUNT));
}
if(tree.collides(bird.getBounds())){
gsm.set(new HGameOverState(gsm));
}
}
for (int i=0; i < trees2.size; i++ ){
HTree2 tree2 = trees2.get(i);
if (cam.position.x - (cam.viewportWidth / 2) > tree2.getPostoptree().x + tree2.getToptree().getWidth()){
tree2.reposition2(tree2.getPostoptree().x + ((HTree2.TREE_WIDTH + TREE_SPACING) * TREE_COUNT));
}
if(tree2.collides2(bird.getBounds())){
gsm.set(new HGameOverState(gsm));
}
}
if (bird.getPosition().y <= ground.getHeight()+GROUND_Y_OFFSET){
gsm.set(new HGameOverState(gsm));
}
cam.update();
}
#Override
public void render(SpriteBatch sb) {
sb.setProjectionMatrix(cam.combined);
sb.begin();
sb.draw(bg,cam.position.x - (cam.viewportWidth/2), 0);
sb.draw(bird.getTexture(),bird.getPosition().x,bird.getPosition().y);
for (HTree tree : trees) {
sb.draw(tree.getToptree(), tree.getPostoptree().x, tree.getPostoptree().y);
sb.draw(tree.getBottomtree(), tree.getPosbottree().x, tree.getPosbottree().y);
}
for (HTree2 tree2 : trees2) {
sb.draw(tree2.getToptree(), tree2.getPostoptree().x, tree2.getPostoptree().y);
sb.draw(tree2.getBottomtree(), tree2.getPosbottree().x, tree2.getPosbottree().y);
}
sb.draw(ground, groundPos1.x,groundPos1.y);
sb.draw(ground, groundPos2.x,groundPos2.y);
sb.end();
}
#Override
public void dispose() {
bg.dispose();
bird.dispose();
ground.dispose();
for (HTree tree : trees){
tree.dispose();
}
for (HTree2 tree2 : trees2){
tree2.dispose2();
}
}
private void updateGround() {
if (cam.position.x - (cam.viewportWidth / 2) > groundPos1.x + ground.getWidth())
groundPos1.add(ground.getWidth() * 2, 0);
if (cam.position.x - (cam.viewportWidth / 2) > groundPos2.x + ground.getWidth())
groundPos2.add(ground.getWidth() * 2, 0);
}
#Override
public void resize(int width, int height) {
bird = new HBird(50,300);
}
}
I would recommend using an interface or a superclass of type HTree which all the other types can then extend from. E.g.
public abstract class HTree {
/*
All your class variables as declared
in your question
*/
public HTree(float x, String topTreeFile, String bottomTreeFile) {
/* Do all the setup stuff here */
// Set the textures
toptree = new Texture(topTreeFile);
bottomtree = new Texture(bottomTreeFile);
}
/*
All your normal getters and setters
and other functions here
*/
}
Then you would create 4 different classes which all extend from HTree as follows:
/* Different types of tree each extend the main HTree class */
public class HTree1 extends HTree {
public HTree1(float x) {
super(x, "uppertree.png", "lowertree.png");
/* Any other custom code for this tree type
can go here */
}
}
public class HTree2 extends HTree {
public HTree1(float x) {
super(x, "uppertree2.png", "lowertree2.png");
/* Any other custom code for this tree type
can go here */
}
}
/* And so on for HTree3 and HTree4 ... */
Finally, you can use any of these four different types as a HTree because they all extend from that class so they can be grouped into a single Array<HTree> and can be rendered/updated together in a single loop.
public class HPlayState extends HState {
/* Other class variables here ... */
/* Only one array for all different tree types */
private Array<HTree> trees;
public HPlayState(GameStateManager gsm) {
/* Same setup code ... */
trees = new Array<HTree>();
Random random = new Random();
for (int i = 1; i <= TREECOUNT; i++) {
/* Randomly pick which tree type to choose */
int treeType = rand.next(4); // 4 or however many different types of tree you have
float x = i * (TREE_SPACING + HTree.TREE_WIDTH);
if (treeType == 0) trees.add(new HTree1(x));
else if (treeType == 1) trees.add(new HTree2(x));
else if (treeType == 2) trees.add(new HTree3(x));
else trees.add(new HTree4(x));
}
}
/*
Rendering and updating code here
*/
}
Note: I haven't tested any of the code so there a might be a few typos or changes needed but it should work fine.

Magic movement in game tile by tile

I have a 2D tile game and my hero can use magic(in this case fire), and the goal is to make the fireball move tile by tile until it finds either a wall or an enemy and to make the game stop while the fire is moving. I already have the fire moving and stopping if there is a wall or an enemy(and damaging the enemy). The problem is i can't seem to make the game show the fireball change from tile to tile, which means when i launch the fireball the game automatically shows me the fireball in its last position before collision, and then it disappears from the tiles. Anyone got any ideas as to what I am doing wrong or what i should do to make the game update the fire tile by tile?
(Btw i thought it might have something to do with my observer but I've tried thread.sleep and wait() and it isn't quite working, maybe I am doing it the wrong way).Thank you for your help and if you guys need any code just ask.
public class ImageMatrixGUI extends Observable {
private static final ImageMatrixGUI INSTANCE = new ImageMatrixGUI();
private final String IMAGE_DIR = "images";
private final int SQUARE_SIZE;
private final int N_SQUARES_WIDTH;
private final int N_SQUARES_HEIGHT;
private JFrame frame;
private JPanel panel;
private JPanel info;
private Map<String, ImageIcon> imageDB = new HashMap<String, ImageIcon>();
private List<ImageTile> images = new ArrayList<ImageTile>();
private List<ImageTile> statusImages = new ArrayList<ImageTile>();
private int lastKeyPressed;
private boolean keyPressed;
private ImageMatrixGUI() {
SQUARE_SIZE = 48;
N_SQUARES_WIDTH = 10;
N_SQUARES_HEIGHT = 10;
init();
}
public static ImageMatrixGUI getInstance() {
return INSTANCE;
}
public void setName(final String name) {
frame.setTitle(name);
}
private void init() {
frame = new JFrame();
panel = new RogueWindow();
info = new InfoWindow();
panel.setPreferredSize(new Dimension(N_SQUARES_WIDTH * SQUARE_SIZE, N_SQUARES_HEIGHT * SQUARE_SIZE));
info.setPreferredSize(new Dimension(N_SQUARES_WIDTH * SQUARE_SIZE, SQUARE_SIZE));
info.setBackground(Color.BLACK);
frame.add(panel);
frame.add(info, BorderLayout.NORTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initImages();
new KeyWatcher().start();
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
lastKeyPressed = e.getKeyCode();
keyPressed = true;
releaseObserver();
}
});
}
synchronized void releaseObserver() {
notify();
}
synchronized void waitForKey() throws InterruptedException {
while (!keyPressed) {
wait();
}
setChanged();
notifyObservers(lastKeyPressed);
keyPressed = false;
}
private void initImages() {
File dir = new File(IMAGE_DIR);
for (File f : dir.listFiles()) {
assert (f.getName().lastIndexOf('.') != -1);
imageDB.put(f.getName().substring(0, f.getName().lastIndexOf('.')),
new ImageIcon(IMAGE_DIR + "/" + f.getName()));
}
}
public void go() {
frame.setVisible(true);
}
public void newImages(final List<ImageTile> newImages) {
synchronized (images) { // Added 16-Mar-2016
if (newImages == null)
return;
if (newImages.size() == 0)
return;
for (ImageTile i : newImages) {
if (!imageDB.containsKey(i.getName())) {
throw new IllegalArgumentException("No such image in DB " + i.getName());
}
}
images.addAll(newImages);
}
}
public void removeImage(final ImageTile image) {
synchronized (images) {
images.remove(image);
}
}
public void addImage(final ImageTile image) {
synchronized (images) {
images.add(image);
}
}
public void clearImages() {
synchronized (images) {
images.clear();
}
public void newStatusImages(final List<ImageTile> newImages) {
synchronized (statusImages) {
if (newImages == null)
return;
if (newImages.size() == 0)
return;
for (ImageTile i : newImages) {
if (!imageDB.containsKey(i.getName())) {
throw new IllegalArgumentException("No such image in DB " + i.getName());
}
}
statusImages.addAll(newImages);
}
}
public void removeStatusImage(final ImageTile image) {
synchronized (statusImages) {
statusImages.remove(image);
}
public void addStatusImage(final ImageTile image) {
synchronized (statusImages) {
statusImages.add(image);
}
}
public void clearStatus() {
synchronized (statusImages) {
statusImages.clear();
}
}
#SuppressWarnings("serial")
private class RogueWindow extends JPanel {
#Override
public void paintComponent(Graphics g) {
// System.out.println("Thread " + Thread.currentThread() + "
// repainting");
synchronized (images) {
for (ImageTile i : images) {
g.drawImage(imageDB.get(i.getName()).getImage(), i.getPosition().getX() * SQUARE_SIZE,
i.getPosition().getY() * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE, frame);
}
}
}
}
#SuppressWarnings("serial")
private class InfoWindow extends JPanel {
#Override
public void paintComponent(Graphics g) {
synchronized (statusImages) {
for (ImageTile i : statusImages)
g.drawImage(imageDB.get(i.getName()).getImage(), i.getPosition().getX() * SQUARE_SIZE, 0,
SQUARE_SIZE, SQUARE_SIZE, frame);
}
}
}
private class KeyWatcher extends Thread {
public void run() {
try {
while (true)
waitForKey();
} catch (InterruptedException e) {
}
}
}
public void update() {
frame.repaint();
}
public void dispose() {
images.clear();
statusImages.clear();
imageDB.clear();
frame.dispose();
}
public Dimension getGridDimension() {
return new Dimension(N_SQUARES_WIDTH, N_SQUARES_HEIGHT);
}
}

JOptionPane.showInputDialog() is called twice, why?

In the showDebugWindow() method inside a class I called, [TinyDebug], the JOptionPane.showInputDialog() is called twice even after I input the correct password, why is that?
Additionally, this code is being executed from an update() method in my Game class, which is called once every second.
Take a look below at the following sets of code for the problem.
Game:
public class Game extends TinyPixel {
private static Game game;
private static KeyManager keyManager;
private static MouseManager mouseManager;
private static GameStateManager sManager;
private boolean isRunning;
private int targetTime;
private final int frameCap = 60;
public Game(String gameTitle, String gameVersion, int gameWidth, int gameRatio, int gameScale) {
super(gameTitle, gameVersion, gameWidth, gameRatio, gameScale);
init();
}
public void init() {
Utilities.printMessage("\t\t-[" + Library.gameTitle + "]-" +
"\n[Game Version]: " + gameVersion +
"\n[Unique Build Number]: " + Utilities.generateCode(16));
ResourceLoader.loadImages();
ResourceLoader.loadMusic();
ResourceLoader.loadSound();
ResourceLoader.loadFonts();
keyManager = new KeyManager(this);
mouseManager = new MouseManager(this);
sManager = new GameStateManager(this);
}
#Override public void update() {
sManager.update();
mouseManager.update();
}
#Override public void render() {
BufferStrategy bs = tinyWindow.getCanvas().getBufferStrategy();
if (bs == null) {
tinyWindow.getCanvas().createBufferStrategy(3);
tinyWindow.getCanvas().requestFocus();
return;
}
Graphics g = bs.getDrawGraphics();
g.clearRect(0, 0, gameWidth, gameHeight);
sManager.render(g);
g.dispose();
bs.show();
}
public void start() {
if(isRunning) return;
isRunning = true;
new Thread(this, gameTitle + " " + gameVersion).start();
}
public void stop() {
if(!isRunning) return;
isRunning = false;
}
#Override public void run() {
isRunning = true;
targetTime = 1000 / frameCap;
long start = 0;
long elapsed = 0;
long wait = 0;
while (isRunning) {
start = System.nanoTime();
update();
render();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
if (wait < 0) wait = 5;
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
Utilities.printErrorMessage("Failed to Load " + gameTitle + " " + gameVersion);
}
}
stop();
}
public static KeyManager getKeyManager() {
return keyManager;
}
public static GameStateManager getsManager() {
return sManager;
}
public static Game getGame() {
return game;
}
}
GameLauncher:
public class GameLauncher {
public static void main(String[] args) {
new Game(Library.gameTitle, Library.gameVersion, 640, TinyPixel.Square, 1).start();
}
}
GameStateManager:
public class GameStateManager {
private int numStates = 3;
public static final int MenuState = 0;
public static final int LoadingState = 1;
public static final int GameState = 2;
public static GameState[] gStates;
private static int currentState;
private static String currentMusic;
protected Game game;
public GameStateManager(Game game) {
this.game = game;
init();
}
private void init() {
gStates = new GameState[numStates];
currentState = MenuState;
//currentMusic = Library.backgroundMusic;
//TinyPlayer.playMusic(currentMusic);
loadState(currentState);
}
private void loadState(int gState) {
if (gState == MenuState) gStates[gState] = new MenuState(game, this);
if (gState == LoadingState) gStates[gState] = new LoadingState(game, this);
if (gState == GameState) gStates[gState] = new PlayState(game, this);
}
private void unloadState(int gState) {
gStates[gState] = null;
}
public void setState(int gState) {
unloadState(gState);
currentState = gState;
loadState(gState);
}
private void changeMusic(String key) {
if (currentMusic.equals(key)) return;
TinyPlayer.stopMusic(currentMusic);
currentMusic = key;
TinyPlayer.loop(currentMusic);
}
public void update() {
try {
gStates[currentState].update();
} catch (Exception e) {}
}
public void render(Graphics g) {
try {
gStates[currentState].render(g);
} catch (Exception e) {}
}
public static int getCurrentState() {
return currentState;
}
}
GameState:
public abstract class GameState {
protected Game game;
protected GameStateManager sManager;
public GameState(Game game, GameStateManager sManager) {
this.game = game;
this.sManager = sManager;
init();
}
public abstract void init();
public abstract void update();
public abstract void render(Graphics g);
}
MenuState:
public class MenuState extends GameState {
private Rectangle playBtn, exitBtn;
private TinyDebug tinyDebug;
public static final Color DEFAULT_COLOR = new Color(143, 48, 223);
public MenuState(Game game, GameStateManager sManager) {
super(game, sManager);
init();
}
public void init() {
tinyDebug = new TinyDebug();
int xOffset = 90, yOffset = 70;
playBtn = new Rectangle(Game.getWidth() / 2 - xOffset, Game.getHeight() / 2, 180, 40);
exitBtn = new Rectangle(Game.getWidth() / 2 - xOffset, Game.getHeight() / 2 + yOffset, 180, 40);
}
public void update() {
if (Game.getKeyManager().debug.isPressed()) {
Game.getKeyManager().toggleKey(KeyEvent.VK_Q, true);
tinyDebug.showDebugWindow();
}
if (Game.getKeyManager().space.isPressed()) {
Game.getKeyManager().toggleKey(KeyEvent.VK_SPACE, true);
sManager.setState(GameStateManager.LoadingState);
}
if (Game.getKeyManager().exit.isPressed()) {
Game.getKeyManager().toggleKey(KeyEvent.VK_ESCAPE, true);
System.exit(0);
}
}
public void render(Graphics g) {
//Render the Background
g.drawImage(Library.menuBackground, 0, 0, Game.getWidth(), Game.getHeight(), null);
//Render the Game Version
TinyFont.drawFont(g, new Font(Library.gameFont, Font.PLAIN, 8), Color.white, "Version: " + Library.gameVersion, Game.getWidth() / 2 + 245, Game.getHeight() - 30);
//Render the Social Section
TinyFont.drawFont(g, new Font(Library.gameFont, Font.PLAIN, 8), Color.white, "#nickadamou", 20, Game.getHeight() - 60);
TinyFont.drawFont(g, new Font(Library.gameFont, Font.PLAIN, 8), Color.white, "#nicholasadamou", 20, Game.getHeight() - 45);
TinyFont.drawFont(g, new Font(Library.gameFont, Font.PLAIN, 8), Color.white, "Ever Tried? Ever Failed? No Matter. Try Again. Fail Again. Fail Better.", 20, Game.getHeight() - 30);
//Render the Debug Section
tinyDebug.renderDebug(g);
g.setColor(Color.white);
g.drawRect(playBtn.x, playBtn.y, playBtn.width, playBtn.height);
g.drawRect(exitBtn.x, exitBtn.y, exitBtn.width, exitBtn.height);
TinyFont.drawFont(g, new Font(Library.gameFont, Font.PLAIN, 14), Color.white, "Play Game [space]", playBtn.x + 10, playBtn.y + 25);
TinyFont.drawFont(g, new Font(Library.gameFont, Font.PLAIN, 14), Color.white, "Exit Game [esc]", exitBtn.x + 20, exitBtn.y + 25);
}
}
keyManager:
public class KeyManager implements KeyListener {
private Game game;
public KeyManager(Game game) {
this.game = game;
game.getTinyWindow().getCanvas().addKeyListener(this);
}
public class Key {
private int amtPressed = 0;
private boolean isPressed = false;
public int getAmtPressed() {
return amtPressed;
}
public boolean isPressed() {
return isPressed;
}
public void toggle(boolean isPressed) {
this.isPressed = isPressed;
if (isPressed) amtPressed++;
}
}
public Key up = new Key();
public Key down = new Key();
public Key left = new Key();
public Key right = new Key();
public Key space = new Key();
public Key debug = new Key();
public Key exit = new Key();
public void keyPressed(KeyEvent key) {
toggleKey(key.getKeyCode(), true);
}
public void keyReleased(KeyEvent key) {
toggleKey(key.getKeyCode(), false);
}
public void keyTyped(KeyEvent e) {}
public void toggleKey(int keyCode, boolean isPressed) {
game.getTinyWindow().getFrame().requestFocus();
game.getTinyWindow().getCanvas().requestFocus();
if (keyCode == KeyEvent.VK_W || keyCode == KeyEvent.VK_UP) {
up.toggle(isPressed);
}
if (keyCode == KeyEvent.VK_S || keyCode == KeyEvent.VK_DOWN) {
down.toggle(isPressed);
}
if (keyCode == KeyEvent.VK_A || keyCode == KeyEvent.VK_LEFT) {
left.toggle(isPressed);
}
if (keyCode == KeyEvent.VK_D || keyCode == KeyEvent.VK_RIGHT) {
right.toggle(isPressed);
}
if (keyCode == KeyEvent.VK_SPACE) {
space.toggle(isPressed);
}
if (keyCode == KeyEvent.VK_Q) {
debug.toggle(isPressed);
}
if (keyCode == KeyEvent.VK_ESCAPE) {
exit.toggle(isPressed);
}
}
#SuppressWarnings("unused")
private void debug(KeyEvent key) {
System.out.println("[keyCode]: " + key.getKeyCode());
}
}
TinyDebug:
public class TinyDebug {
private final String appTitle = Library.gameTitle;
private String tinyPassword, tinyBuildCode;
private boolean isAllowedDebugging = false;
private boolean isShowingTinyText = false;
public TinyDebug() {
tinyPassword = "test123"; // - Standard Password (Non-Renewable)
//tinyPassword = Utilities.generateCode(16); // - Stronger Password (Renewable)
writePasswordToFile(tinyPassword);
tinyBuildCode = Utilities.generateCode(16);
}
//TODO: This method invokes JOptionPane.showInputDialog() twice even after I input the correct password, why?
public void showDebugWindow() {
boolean hasRun = true;
if (hasRun) {
Clipboard cBoard = Toolkit.getDefaultToolkit().getSystemClipboard();
cBoard.setContents(new StringSelection(tinyPassword), null);
if (isAllowedDebugging() && isShowingTinyText()) return;
String userPassword = JOptionPane.showInputDialog("Input Password to Enter [TinyDebug].");
do {
if (userPassword.equals(tinyPassword)) {
JOptionPane.showMessageDialog(null, "[" + appTitle + "]: The Password Entered is Correct.", appTitle + " Message", JOptionPane.PLAIN_MESSAGE);
isAllowedDebugging(true);
isShowingTinyText(true);
break;
} else {
JOptionPane.showMessageDialog(null, "[Error Code]: " + Utilities.generateCode(16) + "\n[Error]: Password is Incorrect.", appTitle + " Error Message", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
} while (userPassword != null || userPassword.trim().isEmpty() != true);
}
hasRun = false;
}
#SuppressWarnings("unused")
public void renderDebug(Graphics g) {
if (isAllowedDebugging()) {
//TODO: Render Debug Information.
TinyFont.drawFont(g, new Font(Library.gameFont, Font.PLAIN, 8), Color.white, "Tiny Pixel [Debug]", 5, 10);
TinyFont.drawFont(g, new Font(Library.gameFont, Font.PLAIN, 8), Color.white, "#. [Options are Shown Here]", 10, 25);
if (isShowingTinyText()) {
String debugHeader = appTitle + " Information";
String debugPasswordField = appTitle + " Information:";
String debugBuildNumber = appTitle + " Unique Build #: " + getTinyBuildCode();
}
}
}
//TODO: This method prints the [Utilities.printMessage(appTitle + ": [tinyPassword] Generated and Stored # FilePath: \n" + logFile.getAbsolutePath());] twice, why?
private void writePasswordToFile(String tinyPassword) {
BufferedWriter bWriter = null;
try {
File logFile = new File("tinyPassword.txt");
Utilities.printMessage(appTitle + ": [tinyPassword] Generated and Stored # FilePath: \n" + logFile.getAbsolutePath());
bWriter = new BufferedWriter(new FileWriter(logFile));
bWriter.write(appTitle + " debug Password: " + tinyPassword);
} catch (Exception e) {
Utilities.printErrorMessage("Failed to Write [tinyPassword] to File.");
} finally {
try {
bWriter.close();
} catch (Exception e) {
Utilities.printErrorMessage("Failed to Close [bWriter] Object.");
}
}
}
public String getTinyPassword() {
return tinyPassword;
}
public String getTinyBuildCode() {
return tinyBuildCode;
}
public void isShowingTinyText(boolean isShowingTinyText) {
this.isShowingTinyText = isShowingTinyText;
}
public boolean isShowingTinyText() {
return isShowingTinyText;
}
public void isAllowedDebugging(boolean isAllowedDebugging) {
this.isAllowedDebugging = isAllowedDebugging;
if (isAllowedDebugging) showDebugWindow();
}
public boolean isAllowedDebugging() {
return isAllowedDebugging;
}
}
In showDebugWindow() method, you have this statement:
if (userPassword.equals(tinyPassword)) {
...
isAllowedDebugging(true); // Problematic statement
...
}
Which calls this method:
public void isAllowedDebugging(boolean isAllowedDebugging) {
this.isAllowedDebugging = isAllowedDebugging;
if (isAllowedDebugging) showDebugWindow(); // Second call?
}
As you see, when you set isAllowedDebugging switch, you also call the method, so when you enter password correct, this second call happens.

Swing Timers and Animations in JPanel

Im trying to animate 2 boxes to go from the top right to the bottom left of a JPanel. For the animation I'm using a Swing Timer and SwingUtilities.invokeLater(). The problem is that when I click the start button. It only animates and moves the blue box, but not the red one.
Heres the code:
//import neccessary stuff
public class Example extends JFrame {
public static void main(String[] args) {
Example e = new Example();
e.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
e.setSize(600, 565);
e.setVisible(true);
}</code>
private JButton startButton = new JButton("Start");
private JPanel theTable = new table();
public Example() {
add(startButton, BorderLayout.SOUTH);
add(theTable, BorderLayout.CENTER);
Handler handler = new Handler();
startButton.addActionListener(handler);
}
public ArrayList<Integer> xPos, yPos;
final int START_POSITION_X = 470;
final int START_POSITION_Y = 10;
final int[] END_POSITION_X = {70, 87};
final int END_POSITION_Y = 160;
private class table extends JPanel {
public table() {
xPos = new ArrayList<Integer>();
yPos = new ArrayList<Integer>();
xPos.add(START_POSITION_X); //default position for box1
yPos.add(START_POSITION_Y);
xPos.add(START_POSITION_X); //default position for box2
yPos.add(START_POSITION_Y);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(new Color(-16756217));
g.setColor(Color.RED);
g.fillRect(xPos.get(1), yPos.get(1), 89, 129);
g.setColor(Color.BLUE);
g.fillRect(xPos.get(0), yPos.get(0), 89, 129);
if (isAnimating) {
animator.start();
} else {
animator.stop();
isAnimating = false;
}
}
}
private class Handler implements ActionListener {
public void actionPerformed(ActionEvent e) {
Runnable r1 = new Runnable() {
#Override
public void run() {
animateCard(0, END_POSITION_X[0], END_POSITION_Y);
}
};
SwingUtilities.invokeLater(r1);
animateCard(1, END_POSITION_X[1], END_POSITION_Y);
}
}
public void animateCard(int card, int xDest, int yDest) {
cardID = card;
xDestination = xDest;
yDestination = yDest;
totalXDistance = Math.abs(xDestination - START_POSITION_X);
totalYDistance = Math.abs(yDestination - START_POSITION_Y);
animator.start();
}
int cardID;
int xDestination, yDestination, totalXDistance, totalYDistance;
boolean isAnimating = false;
Timer animator = new Timer(15, new ActionListener() {
int startVel = 20;
public void actionPerformed(ActionEvent e) {
double xRelDistance, xAbsDistance, xVel;
int xRealVel;
xAbsDistance = xDestination - xPos.get(cardID);
xRelDistance = xAbsDistance / totalXDistance;
xVel = startVel * xRelDistance;
double yRelDistance, yAbsDistance, yVel;
yAbsDistance = yDestination - yPos.get(cardID);
yRelDistance = yAbsDistance / totalYDistance;
yVel = startVel * yRelDistance;
if (xVel > 0) {
xRealVel = (int) java.lang.Math.ceil(xVel);
} else {
xRealVel = (int) java.lang.Math.floor(xVel);
}
xPos.set(cardID, xPos.get(cardID) + xRealVel);
int yRealVel;
if (xVel > 0) {
yRealVel = (int) java.lang.Math.ceil(yVel);
yPos.set(cardID, yPos.get(cardID) + yRealVel);
} else {
yRealVel = (int) java.lang.Math.floor(yVel);
}
yPos.set(cardID, yPos.get(cardID) + yRealVel);
if ((xPos.get(cardID) == xDestination) && (yPos.get(cardID) == yDestination)) {
isAnimating = false;
} else {
isAnimating = true;
}
repaint();
}
});
}
So all of those variable declared at the class level are shared... Your first call to animateCard will set them and then your second call to animateCard is going to completely overwrite the previous values. You need to change them from class variables to parameters of the animation.
Create a new class AnimationTask that implements ActionListener and save the variables in that class.
E.g.,
class AnimationTask implements ActionListener {
private int cardID;
private int xDest;
private int yDest;
private int totalXDistance;
private int totalYDistance;
public AnimationTask(int cardID, int xDest, int yDest) {
this.cardID = cardID;
this.xDest = xDest;
this.yDest = yDest;
this.totalXDistance = Math.abs(xDestination - START_POSITION_X);
this.totalYDistance = Math.abs(yDestination - START_POSITION_Y);
}
public void actionPerformed(ActionEvent e) {
// do your animation logic...
}
}
and use that custom class in your "animator"
E.g.,
Timer animator = new Timer(15, new AnimationTask(cardId, xDest, yDest);
put
animateCard(1, END_POSITION_X[1], END_POSITION_Y);
inside your run method:
public void run() {
animateCard(0, END_POSITION_X[0], END_POSITION_Y);
}

Categories