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

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.

Related

JavaFX scene is not changing when root gets updated

I am trying to make a snake JavaFX game. The scene is a board that consists of 25x25 images. For now, I just want to make the snake go to the right before I add userInput. The first scene is loading from Controller.java and then in Main.java, I am calling run_game() method (inside controller.java) which changes the scene every second. The issue is that the first scene shows up but the scene does not get updated. There is no error, the program just keeps running till I stop it.
Here are the classes:-
Main.java
import javafx.application.Application;
import javafx.stage.Stage;
import java.util.Timer;
import java.util.TimerTask;
public class Main extends Application {
public Controller game;
#Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("Snake Game");
game = new Controller();
primaryStage.setScene(game.scene);
primaryStage.show();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
#Override
public void run() {
try {
game.run_game();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},0,1000);
}
public static void main(String[] args) { launch(args); }
}
Controller.java
import javafx.animation.AnimationTimer;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import java.util.TimerTask;
public class Controller {
public Snake snake;
public Board board;
public Food food;
public Movement move;
public static GridPane grid_pane;
public Scene scene;
// Creating all the necessary instances of snake game
public Controller() throws InterruptedException {
food = new Food();
grid_pane = new GridPane();
//assigning a random food position to the food apple
assign_random_position_to_food();
snake = new Snake(food);
board = new Board();
move = new Movement(snake);
board.generateBoard(food.row, food.col, snake);
Parent root = grid_pane;
scene = new Scene(root, Board.BOARDHEIGHT,Board.BOARDWIDTH);
}
public void run_game() throws InterruptedException {
snake = move.move_RIGHT();
scene.setRoot( grid_pane);
}
public void assign_board_to_grid(){
for ( int row = 0; row < board.board.length; ++row)
for( int col = 0; col < board.board[row].length; ++col )
grid_pane.add(board.board[row][col], row, col, 1, 1);
}
public void assign_random_position_to_food(){
food.RandomPosition();
}
}
Board.java
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
public class Board {
public static int BOARDHEIGHT = 500;
public static int BOARDWIDTH = 500;
public static int BLOCKHEIGHT = 20;
public static int BLOCKWIDTH = 20;
public static int TOTAL_BLOCKS_ROW = BOARDHEIGHT/ BLOCKHEIGHT;
public static int TOTAL_BLOCKS_COL = BOARDWIDTH/ BLOCKWIDTH;
public ImageView[][] board;
public Image black_square;
public Image apple;
public Image snake_dot;
public GridPane gridPane = new GridPane();
public void assign_images(){
try{
apple = new Image("images/apple.png");
snake_dot = new Image("images/dot.png");
black_square = new Image("images/black_square.png");
}catch(Exception e){
System.out.println("Error: related to the address of images");
}
}
public Board(){
assign_images();
//initializing the board
board = new ImageView[TOTAL_BLOCKS_ROW][TOTAL_BLOCKS_COL];
}
public void generateBoard(int food_x, int food_y, Snake snake_body) {
for(int row=0; row< TOTAL_BLOCKS_ROW; row++){
for(int col=0; col< TOTAL_BLOCKS_COL; col++){
if(row == food_x && col == food_y)// && check if it is not on snake body)
board[row][col] = new ImageView(apple);
else if( snake_body.is_snake_present(row,col) && col != 0)
board[row][col] = new ImageView(snake_dot);
else
board[row][col] = new ImageView(black_square);
// Setting the size of each block on the scene
board[row][col].setFitHeight(BLOCKHEIGHT);
board[row][col].setFitWidth(BLOCKWIDTH);
Controller.grid_pane.add(board[row][col], row, col, 1 ,1);
}
}
}
}
Movement.java
public class Movement {
public Snake snake;
public static int new_y_position;
public static int new_x_position;
public Movement(Snake snake){
this.snake = snake;
}
public Snake move_RIGHT(){
new_x_position = snake.getHead_x() + 1;
new_y_position = snake.getHead_y();
if(!check_if_snake_is_in_bounds(new_x_position, new_y_position))
return null;
//System.out.println(new_x_position);
snake.setHead_x(new_x_position);
Block b;
for (int i = snake.snake.size() - 1; i >= 0; --i){
b = snake.snake.get(i);
b.setX(b.getX() + 1);
snake.snake.set(i,b);
}
// System.out.println(snake);
return snake;
}
public Snake move_LEFT(){
new_x_position = snake.getHead_x() - 1;
new_y_position = snake.getHead_y();
if(!check_if_snake_is_in_bounds(new_x_position, new_y_position))
return null;
//snake is inbounds update position
snake.setHead_x(new_x_position);
Block b;
for (int i = snake.snake.size() - 1; i >= 0; --i){
b = snake.snake.get(i);
b.setX(b.getX() - 1);
snake.snake.set(i,b);
}
System.out.println(snake);
return snake;
}
public Snake move_UP(){
new_x_position = snake.getHead_x();
new_y_position = snake.getHead_y() + 1;
if(!check_if_snake_is_in_bounds(new_x_position, new_y_position))
return null;
//snake is inbounds update position
snake.setHead_y(new_y_position);
Block b;
for (int i = snake.snake.size() - 1; i >= 0; --i){
b = snake.snake.get(i);
b.setY(b.getY() + 1);
snake.snake.set(i,b);
}
System.out.println(snake);
return snake;
}
public Snake move_DOWN(){
new_x_position = snake.getHead_x();
new_y_position = snake.getHead_y() - 1;
if(!check_if_snake_is_in_bounds(new_x_position, new_y_position))
return null;
//snake is inbounds update position
snake.setHead_y(new_y_position);
Block b;
for (int i = snake.snake.size() - 1; i >= 0; --i){
b = snake.snake.get(i);
b.setY(b.getY() - 1);
snake.snake.set(i,b);
}
System.out.println(snake);
return snake;
}
public boolean check_if_snake_is_in_bounds(int x, int y){
return x >= 0 && x <= Board.TOTAL_BLOCKS_COL && y >= 0 && y <= Board.TOTAL_BLOCKS_ROW;
}
}
Snake.java
import java.util.ArrayList;
public class Snake {
public ArrayList<Block> snake = new ArrayList<>();
public int snake_size = snake.size();
int head_x, head_y;
public Snake(Food food){
// initializes a snake head location on board and stores it in a list.
do{
head_x = (int) (Math.random()*Board.TOTAL_BLOCKS_COL);
head_y = (int) (Math.random()*Board.TOTAL_BLOCKS_ROW);
}while(food.getRow() == head_x || food.getCol() == head_y);
//inserting head and a block in snake arraylist
snake.add(new Block(head_x, head_y));
snake.add(new Block(head_x - 1, head_y));
}
// Adds new body part when snake eats an apple.
public void add_snake_body() {
snake.add( retrieve_new_block_position() );
}
// gets new snake body part position.
public Block retrieve_new_block_position(){
int last_block_x = snake.get(snake_size - 1).getX();
int last_block_y = snake.get(snake_size - 1).getY();
int second_last_block_x = snake.get(snake_size - 2).getX();
int second_last_block_y = snake.get(snake_size - 2).getY();
int new_block_x;
int new_block_y;
if(second_last_block_x == last_block_x){
new_block_x = last_block_x;
new_block_y = last_block_y - 1;
}
else{
new_block_x = last_block_x - 1;
new_block_y = last_block_y;
}
return new Block(new_block_x, new_block_y);
}
//checks if a position is occupied by a snake body part.
public boolean is_snake_present(int row, int col){
int index = 0;
int snake_curr_block_x;
int snake_curr_block_y;
while(index < snake.size()){
snake_curr_block_x = snake.get(index).getX();
snake_curr_block_y = snake.get(index).getY();
if( snake_curr_block_x == row && snake_curr_block_y == col)
return true;
index++;
}
return false;
}
//GETTER & SETTER METHODS
public ArrayList<Block> getSnake() {
return snake;
}
public int getHead_x() {
return head_x;
}
public void setHead_x(int head_x) {
this.head_x = head_x;
}
public int getHead_y() {
return head_y;
}
public void setHead_y(int head_y) {
this.head_y = head_y;
}
}
Food.java
import java.util.Random;
public class Food {
int row;
int col;
public Food(){
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public void RandomPosition(){
this.row = (int) (Math.random() * Board.TOTAL_BLOCKS_ROW);
this.col = (int) (Math.random() * Board.TOTAL_BLOCKS_COL);
System.out.println(this.row+" -food- "+ this.col);
//need to check if it clashes with the snake body................
}
}
Block.java
public class Block {
private int x;
private int y;
public Block(int x, int y){
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}

why applyLinearImpulse is not working, using libgdx?

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!!

setting up win in the end of the game

I have a problem when i compile my code. I want to make my "Win" image to pop up when the score reaches 500 or over, but i get this error:
"incompatible types: int cannot be converted to score"
The problem is under my "private void LevelUp"()"
Here is my code:
import greenfoot.*;
/**
* Write a description of class MinionWorld here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class MinionWorld extends World
{
private long startMillis = 0;
private int numFrames = 0;
private final int groundHeight;
public static final double MAX_FORCE = 11;
public static final double MIN_FORCE = 7;
public static final double GRAVITY = 0.15;
public static final int LOWEST_ANGLE = 30;
private Player[] players;
private int curPlayer;
private int turnCountdown;
private int value;
Score score;
Banan Banan;
private int time, target;
public static int poin, level;
/**
* Constructor for objects of class Banana.
*
*/
public MinionWorld()
{
// Create a new world with 600x400 cells with a cell size of 1x1 pixels.
super(800, 500, 1, false);
groundHeight = 440;
players = new Player[] {new Minion()};
int x = getWidth() / 2;
for (Player p : players)
{
addObject(p, x, groundHeight);
}
curPlayer = 0;
turnCountdown = 10;
time = 1800;
poin = 0;
level = 1;
target = 150;
Greenfoot.setSpeed(50);
prepare();
}
private void showTime()
{
showText("Time: " + time/60, 700, 20);
}
private void showTarget()
{
showText("Target: "+target, 714, 50);
}
private void showLevel()
{
showText("Level: "+level, 50, 20);
}
private void countTime()
{
showTime();
if(time>0)
{
time--;
}
if (time == 0)
{
LevelUp();
}
}
private void lvup()
{
LvlUp LvlUp = new LvlUp();
addObject(LvlUp,400,250);
Greenfoot.delay(200);
removeObject(LvlUp);
}
private void win()
{
Win Win = new Win();
addObject(new Win(),400,250);
Greenfoot.delay(200);
}
public void started()
{
numFrames = 0;
startMillis = System.currentTimeMillis();
}
private double t;
public void act()
{
numFrames += 1;
t = getTimePerFrame();
if (turnCountdown > 0)
{
turnCountdown -= 1;
if (turnCountdown == 0)
{
players[curPlayer].startTurn();
}
}
countTime();
showTarget();
showLevel();
}
public void changeScore(int nilai)
{
if(score!=null)
{
score.setScore(nilai);
}
}
public double getTimePerFrame()
{
return (double)(System.currentTimeMillis() - startMillis) / (1000.0 * (double)(numFrames));
}
public boolean hitsGround(double startX, double startY, double endX, double endY)
{
return endY > groundHeight;
}
public void landed()
{
curPlayer = (curPlayer + 1) % players.length;
turnCountdown = 10;
}
private void LevelUp()
{
{
if(poin>=target)
{
level++;
if (level==2)
{
lvup();
time=1800;
target=350;
}
if (level==3)
{
lvup();
time=1800;
target=500;
}
}
else
{
if (score = 500)
{
Greenfoot.stop();
addObject(new Win(), 400,200);
}
else
{
addObject(new GameOver(),400,200);
addObject(new TryAgain(),360, 320);
addObject(new Exit(),460,320);
}
}
}
}
/**
* Prepare the world for the start of the program. That is: create the initial
* objects and add them to the world.
*/
private void prepare()
{
Menu Menu = new Menu();
Greenfoot.setWorld(Menu);
score = new Score();
Minion Minion = new Minion();
addObject(Minion, 373, 435);
Minion.setLocation(461, 400);
removeObject(Minion);
Evil1 evil1 = new Evil1();
addObject(evil1, 697, 212);
evil1.setLocation(577, 223);
Evil2 evil2 = new Evil2();
addObject(evil2, 259, 58);
evil2.setLocation(695, 63);
evil2.setLocation(693, 53);
Evil3 evil3 = new Evil3();
addObject(evil3, 742, 322);
evil3.setLocation(575, 321);
evil3.setLocation(323, 305);
evil3.setLocation(573, 319);
Evil4 evil4 = new Evil4();
addObject(evil4, 92, 117);
evil4.setLocation(92, 111);
Score score = new Score();
addObject(score, (697), 168);
score.setLocation(757, 247);
score.setLocation(561, 163);
score.setLocation(463, 124);
}
}
Here is my code for my Score class:
import greenfoot.*;
public class Score extends Actor
{
/**
* Act - do whatever the Score wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
public Score(){
GreenfootImage gfi = new GreenfootImage(200,200);
gfi.setColor(java.awt.Color.white);
gfi.setFont(new java.awt.Font("Las Vegas",java.awt.Font.PLAIN, 36));
gfi.drawString("0", 30, 30);
setImage(gfi);
}
public void setScore(int score)
{
GreenfootImage gfi = getImage();
gfi.clear();
gfi.drawString(score + "", 30,30);
setImage(gfi);
}
//just a little settlement
public void act()
{
if(MinionWorld.poin>9)
{
setLocation(445, getY());
}
}
}
Code for "move" class:
import greenfoot.*;
/**
* Write a description of class Move here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class Move extends Actor
{
int q = 0;
private int Evil = 0;
/**
* Act - do whatever the Fly wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
public void act()
{
}
public void flyy()
{
if (getX() == 0 || getX() == 799)
{
setLocation(getX(), 50+Greenfoot.getRandomNumber(320));
turn(180);
this.getImage().mirrorVertically();
q++;
}
}
public void right()
{
move(3/2);
}
public void left()
{
move(-3/2);
}
public void touch1()
{
if(isTouching(Banan.class))
{
MinionWorld MinionWorld = (MinionWorld) getWorld();
MinionWorld.poin = MinionWorld.poin + 10;
MinionWorld.changeScore(MinionWorld.poin);
removeTouching(Evil1.class);
setLocation(799, 50+Greenfoot.getRandomNumber(320));
left();
}
}
public void touch2()
{
if(isTouching(Banan.class))
{
MinionWorld MinionWorld = (MinionWorld) getWorld();
MinionWorld.poin = MinionWorld.poin + 10;
MinionWorld.changeScore(MinionWorld.poin);
removeTouching(Evil2.class);
setLocation(0, 50+Greenfoot.getRandomNumber(320));
right();
}
}
public void touch3()
{
if(isTouching(Banan.class))
{
MinionWorld MinionWorld = (MinionWorld) getWorld();
MinionWorld.poin = MinionWorld.poin + 10;
MinionWorld.changeScore(MinionWorld.poin);
removeTouching(Evil3.class);
setLocation(799, 50+Greenfoot.getRandomNumber(320));
left();
}
}
public void touch4()
{
if(isTouching(Banan.class))
{
MinionWorld MinionWorld = (MinionWorld) getWorld();
MinionWorld.poin = MinionWorld.poin + 10;
MinionWorld.changeScore(MinionWorld.poin);
removeTouching(Evil4.class);
setLocation(0, 50+Greenfoot.getRandomNumber(320));
right();
}
}
public void nulled2()
{
if (getWorld().getObjects(Evil2.class).isEmpty())
{
getWorld().addObject(new Evil2(), 0, 50+Greenfoot.getRandomNumber(320));
right();
}
}
public void nulled4()
{
if (getWorld().getObjects(Evil4.class).isEmpty())
{
getWorld().addObject(new Evil4(), 0, 50+Greenfoot.getRandomNumber(320));
right();
}
}
public void flyback1()
{
if(getX()<-15)
{
setLocation(800, 50+Greenfoot.getRandomNumber(320));
}
if(getX()>815)
{
setLocation(799, 50+Greenfoot.getRandomNumber(320));
turn(180);
this.getImage().mirrorVertically();
}
}
public void flyback2()
{
if(getX()<-35)
{
setLocation(0, 50+Greenfoot.getRandomNumber(320));
turn(180);
this.getImage().mirrorVertically();
}
if(getX()>834)
{
setLocation(0, 50+Greenfoot.getRandomNumber(320));
}
}
}
This is a little bit too long for a comment so I'll post it here.
You are most likely missing the following:
A field in your Score class.
A getter for that field`.
Fixing if (score = 500) and changing it to if (score.getScore() == 500).
So basically:
public class Score extends Actor {
private int score;
public void setScore(int score) {
this.score = score;
...
}
public int getScore() {
return this.score;
}
}
You are missing a score field. Your class should be like this:
public class Score extends Actor
{
private int score;
public int getScore(){
return score;
}
/**
* Act - do whatever the Score wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
public Score(){
GreenfootImage gfi = new GreenfootImage(200,200);
gfi.setColor(java.awt.Color.white);
gfi.setFont(new java.awt.Font("Las Vegas",java.awt.Font.PLAIN, 36));
gfi.drawString("0", 30, 30);
setImage(gfi);
}
public void setScore(int score)
{
GreenfootImage gfi = getImage();
gfi.clear();
this.score += score;
gfi.drawString(this.score + "", 30,30);
setImage(gfi);
}
//just a little settlement
public void act()
{
if(MinionWorld.poin>9)
{
setLocation(445, getY());
}
}
}
Then your if should be:
if(score.getScore() == 500){
//doStuff
}

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

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException in my vector3 class

Ok so I get this null Pointer exception and neither myself nor my lecturer can figure it out. (he reckons its bad logic and I'm inclined to agree)
I'm making my own 3d object and rendering it with direct world to screenpace co-ords for x and y. This gives me exactly what I want for the excercise and I am able to refine the numbers to get smooth rendering without dropping many frames on my course computer (meaning I cant reproduce the null pointer for my lecturer) but as soon as I run it on beast machine at home the code frames appear to be going much faster, and the cube I'm rendering flashes on and off repeatedly while spitting the null pointer exception to the console(even when I manipulate the numbers to slow it all down). It never crashes though.
Here are the classes that are being used.
Viewport.java(attatched to a JFrame)
package com.my3d.graphics;
import java.awt.BasicStroke;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import com.my3d.geometry.Cube;
import com.my3d.utils.Props;
public class Viewport extends Canvas implements Runnable
{
private static final long serialVersionUID = 1L;
private static final String DEFAULT_NAME = "Viewport";
private static int viewportCount = 0;
private static final BasicStroke stroke = new BasicStroke(0.5f);
private Cube cube;
private boolean running;
private String name;
private int number;
public Viewport()
{
super();
//name the Viewport
if(viewportCount < 10)
setThisName(DEFAULT_NAME +"_0" +viewportCount);
else
setThisName(DEFAULT_NAME +"_" +viewportCount);
//set Identity
setNumber(viewportCount);
//increment the Viewport counter
viewportCount++;
cube = new Cube();
cube.printCubeVertices();
cube.rotateZ(20);
cube.printCubeVertices();
cube.rotateX(20);
cube.printCubeVertices();
running = true;
}
public Viewport(String n)
{
setThisName(n);
viewportCount++;
cube = new Cube();
//cube.printCubeVertices();
//cube.rotateZ(20);
// cube.printCubeVertices();
//cube.rotateX(20);
//cube.printCubeVertices();
running = true;
}
public void tick()
{
//cube.rotateY(0.0001);
//cube.rotateX(0.0001);
repaint();
tock();
}
private void tock()
{
tick();
}
public void setThisName(String n)
{
name = n;
}
private void setNumber(int n)
{
number = n;
}
public Cube getCube()
{
return cube;
}
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(stroke);
Vertex[] verts = cube.getVerts();
for(int i = 0; i < verts.length; i++)
{
ArrayList<Vertex> links = verts[i].getLinks();
for(int j = 0; j < links.size(); j++)
{
Line2D l = new Line2D.Double(verts[i].getPosition().x()+500,/**/verts[i].getPosition().y()+400,/*|*/links.get(j).getPosition().x()+500,/**/links.get(j).getPosition().y()+400);
g2.setColor(Color.RED);
g2.draw(l);
}
}
}
#Override
public void run()
{
int frame = 0;
while(running)
{
if(frame == 1)
{
cube.rotateY(0.0004);
cube.rotateZ(-0.0005);
cube.rotateX(-0.0003);
}
if(frame > 200000)
{
//cube.rotateY(0.0001);
//cube.rotateZ(0.000015);
repaint();
frame = 0;
}
frame++;
}
}
}
Cube.java
package com.my3d.geometry;
import java.util.ArrayList;
import com.my3d.graphics.Vector3;
import com.my3d.graphics.Vertex;
public class Cube
{
private static final String DEFAULT_NAME = "Cube";
private static final double DEFAULT_SIZE = 100;
private static int cubeCount = 0;
private Vertex[] corners;
private Vector3 position;
private Vector3 rotation;
private String name;
private int number;
public Cube()
{
if(cubeCount < 10)
setName(DEFAULT_NAME +"_0" +cubeCount);
else
setName(DEFAULT_NAME +"_" +cubeCount);
//assign Id
number = cubeCount;
//Increment cube counter
cubeCount++;
corners = new Vertex[8];
for(int i = 0; i < 8; i++)
corners[i] = new Vertex();
corners[0].setPosition(new Vector3(DEFAULT_SIZE,DEFAULT_SIZE,DEFAULT_SIZE));
corners[1].setPosition(new Vector3(-DEFAULT_SIZE,DEFAULT_SIZE,DEFAULT_SIZE));
corners[2].setPosition(new Vector3(-DEFAULT_SIZE,DEFAULT_SIZE,-DEFAULT_SIZE));
corners[3].setPosition(new Vector3(DEFAULT_SIZE,DEFAULT_SIZE,-DEFAULT_SIZE));
corners[4].setPosition(new Vector3(DEFAULT_SIZE,-DEFAULT_SIZE,DEFAULT_SIZE));
corners[5].setPosition(new Vector3(-DEFAULT_SIZE,-DEFAULT_SIZE,DEFAULT_SIZE));
corners[6].setPosition(new Vector3(-DEFAULT_SIZE,-DEFAULT_SIZE,-DEFAULT_SIZE));
corners[7].setPosition(new Vector3(DEFAULT_SIZE,-DEFAULT_SIZE,-DEFAULT_SIZE));
corners[0].addLink(corners[1]);
corners[1].addLink(corners[2]);
corners[2].addLink(corners[3]);
corners[3].addLink(corners[0]);
corners[0].addLink(corners[4]);
corners[1].addLink(corners[5]);
corners[2].addLink(corners[6]);
corners[3].addLink(corners[7]);
corners[4].addLink(corners[5]);
corners[5].addLink(corners[6]);
corners[6].addLink(corners[7]);
corners[7].addLink(corners[4]);
// corners[0].addLink(corners[5]);
// corners[1].addLink(corners[6]);
// corners[2].addLink(corners[7]);
// corners[3].addLink(corners[4]);
//
// corners[0].addLink(corners[2]);
// corners[5].addLink(corners[7]);
setPosition(new Vector3());
}
public Cube(String n)
{
setName(n);
//assign Id
number = cubeCount;
//Increment cube counter
cubeCount++;
}
////////////////////////////////////////////////////////////////
//Setters
////////////////////////////////////////////////////////////////
private void setName(String n)
{
name = n;
}
private void setPosition(Vector3 v)
{
position = v;
}
public Vertex[] getVerts()
{
return corners;
}
public void printCubeVertices()
{
for(int i = 0; i < 8; i++)
System.out.println(corners[i].getPosition().toString());
}
public void rotateZ(double degrees)
{
for(int i = 0; i < corners.length; i++)
{
double tempZ = corners[i].getPosition().z();
double newX = (corners[i].getPosition().x()-position.x())*Math.cos(degrees)-(corners[i].getPosition().y()-position.y())*Math.sin(degrees);
double newY = (corners[i].getPosition().x()-position.x())*Math.sin(degrees)+(corners[i].getPosition().y()-position.y())*Math.cos(degrees);
corners[i].setPosition(new Vector3(newX,newY,tempZ));
}
}
public void rotateX(double degrees)
{
for(int i = 0; i < corners.length; i++)
{
double tempX = corners[i].getPosition().x();
double newZ = (corners[i].getPosition().z()-position.z())*Math.cos(degrees)-(corners[i].getPosition().y()-position.y())*Math.sin(degrees);
double newY = (corners[i].getPosition().z()-position.z())*Math.sin(degrees)+(corners[i].getPosition().y()-position.y())*Math.cos(degrees);
corners[i].setPosition(new Vector3(tempX,newY,newZ));
}
}
public void rotateY(double degrees)
{
for(int i = 0; i < corners.length; i++)
{
double tempY = corners[i].getPosition().y();
double newZ = (corners[i].getPosition().z()-position.z())*Math.cos(degrees)-(corners[i].getPosition().x()-position.x())*Math.sin(degrees);
double newX = (corners[i].getPosition().z()-position.z())*Math.sin(degrees)+(corners[i].getPosition().x()-position.x())*Math.cos(degrees);
corners[i].setPosition(new Vector3(newX,tempY,newZ));
}
}
}
Vertex.java
package com.my3d.graphics;
import java.util.ArrayList;
public class Vertex
{
private Vector3 position;
private ArrayList<Vertex> linked = new ArrayList<Vertex>();
public Vertex()
{
setPosition(new Vector3(0.0,0.0,0.0));
}
public Vertex(Vector3 v)
{
setPosition(v);
}
public void setPosition(Vector3 pos)
{
position = pos;
}
public void addLink(Vertex v)
{
linked.add(v);
}
public void removeLink(Vertex v)
{
linked.remove(v);
}
/////////////////////////////////////////////////////////////////
//Getters
/////////////////////////////////////////////////////////////////
public Vector3 getPosition()
{
return position;
}
public ArrayList<Vertex> getLinks()
{
return linked;
}
}
Vector3.java
package com.my3d.graphics;
public class Vector3
{
private double[] xyz;
// public double x;
// public double y;
// public double z;
public Vector3()
{
xyz = new double []{0.0,0.0,0.0};
// x = xyz[0];
// y = xyz[1];
// z = xyz[2];
}
public Vector3(double x,double y,double z)
{
xyz = new double []{x,y,z};
// xyz[0] = x;
// xyz[1] = y;
// xyz[2] = z;
}
public Vector3(double[] array)
{
try
{
if(array.length > 3)
{
RuntimeException e = new RuntimeException("The Vector3 is too big by (" +(array.length - 3) +") elements you muppet.\nremember that a Vector3 supports arrays with a length of 3. You have (" +array.length +")");
throw e;
}
if(array.length < 3)
{
RuntimeException e = new RuntimeException("The Vector3 is too small by (" +(3 - array.length) +") elements you muppet.\nremember that a Vector3 supports arrays with a length of 3. You have (" +array.length +")");
throw e;
}
xyz[0] = array[0];
xyz[1] = array[1];
xyz[2] = array[2];
}
catch(RuntimeException e)
{
System.out.println(e);
}
}
///////////////////////////////////////////////////////////////////////////
public void x(double a)
{
xyz[0] = a;
}
public void y(double a)
{
xyz[1] = a;
}
public void z(double a)
{
xyz[2] = a;
}
public double x()
{
return xyz[0];
}
public double y()
{
return xyz[1];
}
public double z()
{
return xyz[2];
}
public void normalize()
{
double length = Math.sqrt((xyz[0] * xyz[0]) + (xyz[1] * xyz[1]) + (xyz[2] * xyz[2]));
xyz[0] = xyz[0]/length;
xyz[1] = xyz[1]/length;
xyz[2] = xyz[2]/length;
}
public String toString()
{
return "(" + xyz[0] + "," + xyz[1] + "," + xyz[2] + ")";
}
}
The best I can do is trace it to public double x(){return xyz[0];}
in the Vector3 class when the paint method is called in the viewport class but when I try and step through they are never null. I get the impression that the jvm is catching up with itself while trying to reassign new positions to the vertices during the rotation.
Edit: Stacktrace
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at com.my3d.graphics.Vector3.x(Vector3.java:70)
at com.my3d.graphics.Viewport.paint(Viewport.java:107)
at java.awt.Canvas.update(Unknown Source)
at sun.awt.RepaintArea.updateComponent(Unknown Source)
at sun.awt.RepaintArea.paint(Unknown Source)
at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Additional Info:
Manager.java
package com.my3d.core;
import java.awt.Color;
import com.my3d.graphics.Viewport;
import com.my3d.graphics.Wind;
import com.my3d.utils.Props;
public class Manager {
/**
* #param args
*/
public static void main(String[] args)
{
Props.loadPropsFromFile();
Wind wind = new Wind();
wind.setVisible(true);
Viewport view = new Viewport("Main view");
view.setPreferredSize(Props.getWindowSize());
view.setBackground(Color.LIGHT_GRAY);
wind.add(view);
view.setVisible(true);
wind.pack();
view.run();
}
}
Wind.java
package com.my3d.graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import com.my3d.utils.Props;
import javax.swing.JFrame;
public class Wind extends JFrame
{
/**
*
*/
private static final long serialVersionUID = 1L;
private boolean fullScreen = false;
//Constructor
public Wind()
{
super(Props.getDefaultTitle() +Props.getTitleSplash());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fullScreen = Props.getFullScreen();
if (fullScreen)
{
setUndecorated(true);
GraphicsDevice vc;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
vc= ge.getDefaultScreenDevice();
vc.setFullScreenWindow(this);
}
else
{
setBounds(0,0,Props.getWindowWidth(),Props.getWindowHeight());
setLocationRelativeTo(null);
}
}
public void setTitle(String s)
{
//if(Props.getRandomSplashes())
super.setTitle(Props.getDefaultTitle() +s);
}
public void setRandomTitle()
{
if(Props.getRandomSplashes())
Props.setTitleSplash(Props.randomizeSplash());
super.setTitle(Props.getDefaultTitle() +Props.getTitleSplash());
}
public void setFullScreen(boolean b)
{
fullScreen = b;
}
//this method wont work >>
public void refactorWindow()
{
if (fullScreen)
{
setUndecorated(true);
GraphicsDevice vc;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
vc= ge.getDefaultScreenDevice();
vc.setFullScreenWindow(this);
}
else
{
setSize(Props.getWindowSize());
setLocationRelativeTo(null);
}
}
}
Props.java
package com.my3d.utils;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
import javax.imageio.ImageIO;
public class Props
{
private static String gameTitle;
private static String splashTitle;
private static Dimension windowSize;
//private static int gameState;
private static boolean fullScreen;
private static boolean randomSplashes;
private static BufferedImage tileSheet;
///////////////////////////////////////////////////////////////
//Getters
///////////////////////////////////////////////////////////////
public static Dimension getWindowSize()
{
return windowSize;
}
public static int getWindowWidth()
{
return (int) windowSize.getWidth();
}
public static int getWindowHeight()
{
return (int) windowSize.getHeight();
}
public static String getTitleSplash()
{
return splashTitle;
}
public static String getDefaultTitle()
{
return gameTitle;
}
public static boolean getFullScreen()
{
return fullScreen;
}
public static boolean getRandomSplashes()
{
return randomSplashes;
}
public static BufferedImage getTileSheet()
{
return tileSheet;
}
/////////////////////////////////////////////////////////////////////
//Setters
/////////////////////////////////////////////////////////////////////
public static void setWindowSize(int width, int height)
{
windowSize = new Dimension(width,height);
}
public static void setTitleSplash(String s)
{
splashTitle = s;
}
private static void setDefaultTitle(String s)
{
gameTitle = s;
}
////////////////////////////////////////////////////////////////////
//loader
////////////////////////////////////////////////////////////////////
public static void loadPropsFromFile()
{
File file = new File("res\\config\\props.props");
try
{
Scanner input = new Scanner(file);
String lInput = input.nextLine().trim();
setWindowSize(Integer.parseInt(lInput.substring(lInput.indexOf('=')+1,lInput.indexOf(','))),Integer.parseInt(lInput.substring(lInput.indexOf(',')+1,lInput.length())));
lInput = input.nextLine().trim();
if(lInput.substring(lInput.indexOf('=')+1,lInput.length()).equals("true"))
fullScreen = true;
else
fullScreen = false;
lInput = input.nextLine().trim();
if(lInput.substring(lInput.indexOf('=')+1,lInput.length()).equals("true"))
{
lInput = input.nextLine().trim();
setDefaultTitle(lInput.substring(lInput.indexOf('=')+1,lInput.length()));
randomSplashes = true;
setTitleSplash(randomizeSplash());
}
else
{
lInput = input.nextLine().trim();
setDefaultTitle(lInput.substring(lInput.indexOf('=')+1,lInput.length()));
setTitleSplash("");
randomSplashes = false;
}
lInput = input.nextLine().trim();
try
{
tileSheet = ImageIO.read(new File(loadFromDirectory(lInput.substring(lInput.indexOf('=')+1,lInput.length()))));
}
catch (IOException e)
{
System.out.println("Tilesheet Cannot be found.");
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
}
///////////////////////////////////////////////////////////////////
//Utility
///////////////////////////////////////////////////////////////////
public static String loadFromDirectory(String key)
{
String s = "";
File sFile = new File("res\\config\\dirs.dir");
try
{
Scanner sInput = new Scanner(sFile);
while(sInput.hasNextLine())
{
String st = sInput.nextLine().trim();
if(key.equals(st.substring(1,st.length())));
s = sInput.nextLine().trim();
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
return s;
}
public static String randomizeSplash()
{
if(randomSplashes)
{
File sFile = new File("res\\config\\splash.props");
ArrayList<String> sArray = new ArrayList<String>();
try
{
Scanner sInput = new Scanner(sFile);
while(sInput.hasNextLine())
{
sArray.add(sInput.nextLine().trim());
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
Random rand = new Random();
String s = sArray.get(rand.nextInt(sArray.size()));
splashTitle = s;
return s;
}
else
return "";
}
}
props.props
windowSize =1000,800
startInFullscreen =false
randomSplashes =false
defaultTitle =3D Prototype
tileSheet =tileSheet
dirs.dir
<startGame>
res\\img\\button\\Start_game_text.png
res\\img\\button\\Start_game_active.png
res\\img\\button\\Start_game_click.png
<quitGame>
res\\img\\button\\Quit_game_text.png
res\\img\\button\\Quit_game_active.png
res\\img\\button\\Quit_game_click.png
<menuBackground>
res\\img\\Menu_background.png
<resumeGame>
res\\img\\button\\Resume_game_text.png
res\\img\\button\\Resume_game_active.png
res\\img\\button\\Resume_game_click.png
<tileSheet>
res\\img\\Final_Sub_Hunt.png
Update: mark your field xyz in Vector3 as final. My reading of the JMM says that, without a synchronizer or final, it is legal for the Event Dispatch Thread (EDT), from whence your stack trace comes, to see that non-final field as not yet initialized by the constructor when the constructor is run in a separate (your Viewport.run()) thread. See this SO question or the JMM FAQ.
The correct place to look in the JLS for this is in Section 17.5 (though you really need to read all of 17, and a lot of times, to start to grok this):
An object is considered to be completely initialized when its
constructor finishes. A thread that can only see a reference to an
object after that object has been completely initialized is guaranteed
to see the correctly initialized values for that object's final
fields.
Note that the same guarantee does not hold for non-final fields; if you want safety there, you will need to use synchronization edges of some kind (explicit synchronizers, volatile, whatever.)
Related discussion from Alex Miller, who I think putters around StackOverflow as https://stackoverflow.com/users/7671/alex-miller and might poke his head in if we say hello.) And a related SO question.
Original Answer
Looks like you have an error in your Vector3(double[]) constructor, which never initializes the double[] xyz field. Only place I could find where that field would not be initialized and yield an NPE.
I can't tell from your code how many threads you have running around. If you are creating instances of Vector3 in one thread and placing them into a collection while they are being displayed by a separate rendering thread, it is possible you are observing them in a state of partial construction. Generally things are arranged to make this unlikely (I can't remember off the top of my head what the memory model says about publishing partially-constructed objects, but it can happen if you let this slip out of the constructor; I don't see that happening here.)
JA
catch(RuntimeException e)
{
System.out.println(e);
}
This segment allows you to create a Vector3 without properly initialising the array. That's a potiential problem.
Both of the non-default constructors make no attempt to check x, y or z is null before assigning them.
I would start there, then consider unit tests.

Categories