static variable doesn't change - java

I started using jMonekyEngine and it's easy way of interacting with Swing GUI.
Following their tutorial here http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:swing_canvas
It all works and I get everything loaded,however I'm having trouble modifying things.
According to their tutorial, the constant update and happens here:
public void simpleUpdate(float tpf) {
geom.rotate(0, 2 * tpf, 0);
}
(this is an example from the tutorial on rotating objects).
what i'm trying to do is just increasing and decreasing the speed of rotation (by changing the 2 or tpf with a variable which gets update inside an ActionListener in the Swing gui.
However, since in their tutorial they stated that the swing gui is to be created inside the main method, I have to create a variable which is static in order to change it.
static float rotate = 0.0f;
it gets modified inside the main method, but when trying to use it like so:
public void simpleUpdate(float tpf) {
geom.rotate(0, rotate * tpf, 0);
}
it remains constant to the initial value.
I tried creating a GUI class to build the gui (extends JPanel) and using getters and setters, but still not go..
Any help would be appreciated!
Thanks!
EDIT:
Here's how I change the rotate value:
JButton faster = new JButton("Faster");
faster.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
rotate +=0.1f;
}
});
inside the main method. rotate is a static field.

This is working for me
http://test.jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_main_event_loop
http://test.jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_input_system?s[]=input
Is your action listener really triggering the event on click? maybe you have a problem there and not in the rotate variable. Note that I'm not using swing on this example..
import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
/** Sample 4 - how to trigger repeating actions from the main update loop.
* In this example, we make the player character rotate. */
public class HelloLoop extends SimpleApplication {
public static void main(String[] args){
HelloLoop app = new HelloLoop();
app.start();
}
protected Geometry player;
#Override
public void simpleInitApp() {
Box b = new Box(Vector3f.ZERO, 1, 1, 1);
player = new Geometry("blue cube", b);
Material mat = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
player.setMaterial(mat);
rootNode.attachChild(player);
initKeys();
}
/* This is the update loop */
#Override
public void simpleUpdate(float tpf) {
// make the player rotate
player.rotate(0, val*tpf, 0);
}
float val = 2f;
private void initKeys() {
// Adds the "u" key to the command "coordsUp"
inputManager.addMapping("sum", new KeyTrigger(KeyInput.KEY_ADD));
inputManager.addMapping("rest", new KeyTrigger(KeyInput.KEY_SUBTRACT));
inputManager.addListener(al, new String[]{"sum", "rest"});
}
private ActionListener al = new ActionListener() {
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("sum") ) {
val++;
}else if (name.equals("rest")){
val--;
}
}
};
}

Related

I am not sure what is incorrect

I am creating a small Java Jpanel game in which I am supposed to have a rocket that moves up and down via arrows and fires via space.
The firing method should work like this: Space bar pressed, thing fires and moves across screen , and then when it hits a certain x, it disappears. Also, you can only fire once until the other bullet disappears.
I do not know what I am doing wrong. For one, as soon as my code starts you can see a bullet flying across the screen.
2nd, the bullet is not disappearing.
3rd, even though the other bullet is still visible, it allows me to fire again.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class SpaceGame extends JPanel implements ActionListener{
Timer t = new Timer(2, this);
private ImageIcon rocket,asteroid,bullet;
private JLabel rocketlabel,ast1,ast2,ast3,bulletLabel;
public static int y=90,dy=0,bulletX=110,bulletY,i=0,canFire;
//public sound sound;
static boolean bulletFired=false;;
static JFrame f = new JFrame();
SpaceGame(){
this.setBackground(Color.black);
rocket = new ImageIcon(getClass().getResource("rocketFinal.png"));
rocketlabel= new JLabel(rocket);
this.add(rocketlabel);
asteroid = new ImageIcon(getClass().getResource("asteroid.png"));
ast1=new JLabel(asteroid);
ast2=new JLabel(asteroid);
ast3=new JLabel(asteroid);
bullet = new ImageIcon(getClass().getResource("bulletReal.png"));
bulletLabel = new JLabel(bullet);
canFire=1;
bulletLabel.setVisible(false);
this.add(ast1);this.add(ast2);this.add(ast3);this.add(bulletLabel);
f.addKeyListener(new controller());
this.setLayout(null);
this.setVisible(true);
}
public class controller implements KeyListener{
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode== KeyEvent.VK_UP) {
dy=-1;
}
if(keyCode== KeyEvent.VK_DOWN) {
dy=1;
}
if(keyCode== KeyEvent.VK_SPACE) {
if(canFire==0) {
System.out.println(String.valueOf(canFire));
bulletFired = true;
bulletY = y;
bulletX=110;
}canFire=1;
}
}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch(key) {
case KeyEvent.VK_UP: dy=0; break;
case KeyEvent.VK_DOWN: dy=0; break;
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
rocketlabel.setBounds(45,y,rocket.getIconWidth(),80);
fireBullet();
paintStars(g);
t.start();
}
public void paintStars(Graphics g) {
g.setColor(Color.yellow);
for(int i=0; i<5;i++) {
Random rand = new Random();
int o = rand.nextInt(500);
int p = rand.nextInt(300);
g.fillOval(o, p, 3, 3);
}
}
public void actionPerformed(ActionEvent e) {
if(y==-20) y=249;
if(y==250)y=-20;
y+=dy;
if(bulletFired=true) {
bulletX++;
if(bulletX==455)bulletFired=false;bulletLabel.setVisible(false);System.out.println(String.valueOf(bulletX)); canFire=0;
}
repaint();
}
public void fireBullet(){
if(bulletFired=true) {
bulletLabel.setVisible(true);
bulletLabel.setBounds(bulletX,bulletY+25,bullet.getIconHeight(),bullet.getIconWidth());
}
}
public static void main(String[] args) {
String filepath = "SpaceGameMusic.wav";
musicStuff musicPlayer = new musicStuff();
musicPlayer.playMusic(filepath);
SpaceGame t = new SpaceGame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(t);
f.setSize(500,335);
f.setVisible(true);
f.setResizable(false);
}
}
For one, as soon as my code starts you can see a bullet flying across the screen.
The paintComponent() method is for painting only. You can't control when Swing will determine a component needs to be repainted.
So, for example:
t.start();
should NOT be in the painting method. As soon as the frame is made visible the panel will be painted and the Timer will be started.
You application code should control when the Timer is started.
Other issues:
you should not be using static variables. The variable should simply be instances of your class.
the paintStars() method should not generate random locations. Again. a painting method should only paint the current state of the class. So if you want to change the location of the stars you should have a method like randomizeStars(). In this method you would update an ArrayList of Point objects. Each Point instance would represent the location of a star. Then the paintStars() method would simply iterate through the ArrayList and paint each star.
you should not be using a KeyListener. A KeyListener only works if a component has focus. You can't guarantee that your component will lose focus. Instead you should be using Key Bindings. Key bindings allow you to handle a KeyEvent even if the component doesn't have focus. See Motion Using the Keyboard for more information and a working example.
you can only fire once until the other bullet disappears
Your canFire variable should be a boolean variable so it only has true/false values. Again you have a method that sets the state. Your game logic will then check the state before firing the bullet again.
if(y==-20) y=249;
if(y==250)y=-20;
Don't hardcode values. The number should be based on the size of your panel. So you use methods like getWidth() and getHeight() to determine the current size of the panel.
The problem was quite simply that I had forgotten to use == in my if(boolean) statements.

JavaFX - drawing (snake) in a loop

Currently, I'm playing around with JavaFX as I'm writing a Snake game for my Java Fundamentals class final project. I'm not that new to creating simple games with animations as I've made a bit of them using PyGame module and SDL in C. Anyway, now I'm quite struggling with understanding the correlations of some objects in JavaFX, especially when combined with SceneBuilder's FXMLs.
I just can't understand how to create an equivalent of gameloop I used to implement in PyGame or SDL. What I want to do with the code below is to enter the gameloop as soon as a new Game object is created and draw the state of the game continuously on the gameCanvas created in the SceneBuilder. I think I can easily manage all the stuff later, but I just can't sort it out how to create a legit bond between the FXML canvas and the gameloop I want to run.
GameController.java
public class GameController implements Initializable, ControlledScreen {
#FXML
private Canvas gameCanvas;
#Override
public void setScreenParent(ScreensController screenPage) {
// THIS IS FOR SCENE MANAGEMENT CONCEPT
}
Game.java
public class Game implements Runnable {
public static final int EASY = 1,
MEDIUM = 2,
HARD = 3;
int difficultyLevel, score = 0;
Snake snake;
Food food;
boolean isRunning = true;
public void setLevelEasy() {
difficultyLevel = EASY;
}
public void setLevelMedium() {
difficultyLevel = MEDIUM;
}
public void setLevelHard() {
difficultyLevel = HARD;
}
#Override
public void run() {
while (isRunning) {
}
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
}
You cant use FXML file to create new scene. Use this instead
public class Screen extends Application implements Runnable
{
#Override
public void start ( Stage primaryStage )
{
Pane pane = new Pane ();
Scene scene = new Scene(pane,500,300);
primaryStage.setScene ( scene );
primaryStage.show ();
}
#Override
public void run ()
{
launch ();
}
}
anything you want to add goes to pane element your canvas etc.
and by the way make dificulty enum not int like
enum {easy,medium,hard}
that way nobody can set dificulty level to something does not exist.

Need Help adding a difficulty option for User functionality

Quick question, I have developed 3 A.I's each with a different depth.
Currently to choose what A.I you want to play against you have to go into the java file called Main.java and change it to whichever one you want. The line to change is:
chessGame.setPlayer(Piece.COLOR_BLACK, ai3);//Here A.I is assigned
I want to allow the user to have an option at the start of the game to choose the A.I. I was hoping for some help with the interface, I was thinking something something like a JOptionpane might work.
(I'm just not sure how to do one for the A.I selection)
Current A.I's
ai1
ai2
ai3
package chess;
import chess.ai.SimpleAiPlayerHandler;
import chess.gui.ChessGui;
import chess.logic.ChessGame;
import chess.logic.Piece;
public class Main {
public static void main(String[] args) {
// Creating the Game
ChessGame chessGame = new ChessGame();
// Creating the Human Player
//Human Player is the Object chessGui
ChessGui chessGui = new ChessGui(chessGame);
//Creating the A.I's
SimpleAiPlayerHandler ai1 = new SimpleAiPlayerHandler(chessGame);//Super Dumb
SimpleAiPlayerHandler ai2 = new SimpleAiPlayerHandler(chessGame);//Dumb
SimpleAiPlayerHandler ai3 = new SimpleAiPlayerHandler(chessGame);//Not So Dumb
// Set strength of AI, how far they can see ahead
ai1.maxDepth = 1;
ai1.maxDepth = 2;
ai3.maxDepth = 3;
//Assign the Human to White
chessGame.setPlayer(Piece.COLOR_WHITE, chessGui);
//Assign the not so dumb A.I to black
chessGame.setPlayer(Piece.COLOR_BLACK, ai3);
// in the end we start the game
new Thread(chessGame).start();
}
}
Thanks for any help.
You should probably use a JComboBox to allow the user to select among the 3 options available. If you make a splash JFrame with this JComboBox you can then create your main game frame afterward and pass it the value from the JComboBox.
For example, you could have the JComboBox give options of difficulty setting Easy, Medium, and Hard. Using an action listener on a JButton get the selected value from the JComboBox and convert it to int value appropriate for your minimax algorithm. That is, pass 1 for easy, 2 for medium, and 3 for hard.
Next change your ai class so that maxDepth is in the constructor. Then when you instantiate your ai, just give it the value that was passed forward from the previous frame and you will have created the only ai you need at the right difficulty setting.
EDIT:
It looks like you managed to get something similar working which is great! In case it helps you, I have included a brief example of how I would have done this below. Note that I also set it up such that your SimpleAiPlayerHandler constructor also takes an int value for instantiating the maxDepth variable. You'll need to add this. Since it uses classes I don't have, I can't compile it. However, if anyone else needs to do something similar, just remove everything in the DifficultyListener except the print statement and the line that get's the difficulty from the JComboBox and you'll see it working (and compiling).
import javax.swing.*;
import java.awt.event.*;
public class ChessSplash extends JFrame {
private final JComboBox<Difficulty> difficultySetting;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ChessSplash gui = new ChessSplash();
gui.setVisible(true);
}
});
}
public enum Difficulty {
EASY(1, "Easy"), MEDIUM(2, "Medium"), HARD(3, "Hard");
private final int intValue;
private final String stringValue;
private Difficulty(int intValue, String stringValue) {
this.intValue = intValue;
this.stringValue = stringValue;
}
#Override
public String toString() {
return stringValue;
}
};
public ChessSplash() {
super("Chess Game");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
difficultySetting = new JComboBox<>(Difficulty.values());
JButton startButton = new JButton("Start Game");
startButton.addActionListener(new DifficultyListener());
JPanel mainPanel = new JPanel();
add(mainPanel);
mainPanel.add(difficultySetting);
mainPanel.add(startButton);
pack();
}
private class DifficultyListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
//Declare AI
SimpleAiPlayerHandler ai;
//Declare and Instantiate Chess Game
ChessGame chessGame = new ChessGame();
//Human Player is the Object chessGui
ChessGui chessGui = new ChessGui(chessGame);
//Assign Human Player to White
chessGame.setPlayer(Piece.COLOR_WHITE, chessGui);
//Get the selected difficulty setting
Difficulty difficulty = (Difficulty)difficultySetting.getSelectedItem();
//Instantiate Computer AI pass it the maxDepth for use in the constructor
ai = new SimpleAiPlayerHandler(difficulty.intValue, chessGame);
//Assign Computer Player to Black
chessGame.setPlayer(Piece.COLOR_BLACK, ai);
//Demonstrate the enum combobox works
System.out.println(difficulty.intValue);
//Dispose of the splash JFrame
ChessSplash.this.dispose();
//Start your game thread (I would probably do something to move this
//onto the EDT if you're doing this is swing personally
new Thread(chessGame).start();
}
}
}

Method slows execution paintComponent()

I have a small problem. In carrying out the method paintComponent() during the animation I have to constantly update the variable bgImage. But it takes a lot of time, so that the animation slows down.
A block of code with the problem:
public class ProblemClass extends JComponent {
private static final int FRAME_FREQUENCY = 30;
private final Timer animationTimer;
public ProblemClass() {
this.animationTimer = new Timer(1000 / FRAME_FREQUENCY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint(); // When the animation started is often invoked repaint()
}
});
}
// Other code...
/**
* Start animation from another class
*/
public void startAnimation() {
this.animationTimer.start();
}
#Override
protected void paintComponent(Graphics g) {
// GraphicsUtils.gaussianBlur(...) it's a long-time operation
BufferedImage bgImage = GraphicsUtils.gaussianBlur(AnotherClass.getBgImage());
g2.drawImage(bgImage, 0, 0, null);
// Other code...
}
}
I read on the Internet that I need run long task in parallel thread (SwingWorker), but I have no idea how to do it in my case. How can I solve this problem?
P.S. Sorry for my bad English, it's not my first language.
The best you're going to do is having the image update outside of the paint method, and only redraw whenever a new image is ready. Take your existing code, and add a persistent reference to the image, which gets drawn onto the JComponent each paint method. Then have your animation timer do the Gaussian blur and update your image.
public class ProblemClass extends JComponent {
private static final int FRAME_FREQUENCY = 30;
private final Timer animationTimer;
//persistent reference to the image
private BufferedImage bgImage;
public ProblemClass() {
this.animationTimer = new Timer(1000 / FRAME_FREQUENCY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Update the image on each call before repainting
bgImage = GraphicsUtils.gaussianBlur(AnotherClass.getBgImage());
repaint();
}
});
}
/**
* Start animation from another class
*/
public void startAnimation() {
this.animationTimer.start();
}
#Override
protected void paintComponent(Graphics g2) {
g2.drawImage(bgImage, 0, 0, null);
// Other code...
}
}
There is no generic way to solve this when you generate a new background image every time and then blur it. GaussianBlur is a slow operation, period.
If AnotherClass.getBgImage() delivers images from a predefined set of images, then apply the blur once to each image in the set, problem goes away.
If you create the image in AnotherClass.getBgImage() dynamically, then you may be able to speed it up by changing the image creation to create a blurred image from the start. Depending on what is done to create the image this may or may not be feasible.
If neither of the above works out, you need to investigate other options to produce the blurred image which are faster; there are simpler blurring methods that are generally faster but look somewhat similar to a gaussian.
You see it all boils down to getting rid of calling GaussianBlur repeatedly on the performance critical path.
You should extract logic from painter. Painters are called constrantly and should be executed very fast.
BufferedImage bgImage = GraphicsUtils.gaussianBlur(AnotherClass.getBgImage());
This line has to be executed every time? maybe you could use a field to store the image and the painter could just paitn the image, not applying each time a gaussianBlur.
Try this:
public class ProblemClass extends JComponent {
private static final int FRAME_FREQUENCY = 30;
private final Timer animationTimer;
private final BufferedImage bgImage;
public ProblemClass() {
bgImage = GraphicsUtils.gaussianBlur(AnotherClass.getBgImage());
this.animationTimer = new Timer(1000 / FRAME_FREQUENCY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint(); // When the animation started is often invoked repaint()
}
});
}
// Other code...
/**
* Start animation from another class
*/
public void startAnimation() {
this.animationTimer.start();
}
#Override
protected void paintComponent(Graphics g2) {
// GraphicsUtils.gaussianBlur(...) it's a long-time operation
g2.drawImage(bgImage, 0, 0, null);
// Other code...
}
}

Why isn't my object moving on MouseMoved?

Simple question – why wouldn't an object move if it's the object of .move() inside onMouseMoved()? I'm trying to write Breakout as part of the Stanford 106A exercises on iTunes U and for some reason I can't get the paddle to track the mouse. I'm a java noob, so I'm sure it's something really simple. Could someone please take a look at this code?
/** Runs the Breakout program. */
public void run() {
setupBoard();
addMouseListeners();
}
/** Provides the initial GCanvas and blocks for the game */
private void setupBoard(){
this.setSize(APPLICATION_WIDTH,APPLICATION_HEIGHT);
addBricks();
paddle = new GRect(PADDLE_WIDTH, PADDLE_HEIGHT);
add(paddle, WIDTH/2-PADDLE_WIDTH/2,HEIGHT-PADDLE_Y_OFFSET);
}
public void MouseMoved(MouseEvent e){
paddle.move(e.getX()-paddle.getX(), 0);
}
private GRect paddle;
}
I'm not sure if having paddle be an instance variable is appropriate in this case, since its "value" doesn't change (the paddle's always the paddle), but if I just define it as a new GRect within setupBoard I get an error in the MouseMoved() method.
Your class that has the mouseMoved() method needs to implement the interface MouseMotionListener, and add the motion listener. Moreover, the event handler is mouseMoved() not MouseMoved(). So, e.g.:
public class Game extends JPanel implements MouseMotionListener {
public void run() {
addMouseMotionListener(this);
//...
}
public void mouseMoved(MouseEvent e) {
paddle.move(e.getX()-paddle.getX(), 0);
}
//...
};

Categories