public class Game
{
private EnemyShip enemy1;
private EnemyShip enemy2;
private EnemyShip enemy3;
private PlayerShip player;
/**
* Initialises user's ship and guns
*/
public Game()
{
player = new PlayerShip();
enemy1 = new EnemyShip();
enemy2 = new EnemyShip();
enemy3 = new EnemyShip();
Can I make this enemy1,2,3 to be an array? I want to use enemy on a loop.
Or is there a way to make a loop for variable that is not an array? Like if I run the loop enemy1 will increment and become enemy2.
EnemyShip[] enemies = new EnemyShip[3];
for (int i=0; i<enemies.length; i++) { enemies[i] = new EnemyShip(); }
will give you an array of 3 EnemyShip objects. If the loop you're looking for is one that gives you a different instance variable each iteration then no you can't do that; you need to have them in a collection. However you can simplify the loop if you don't care about the index:
for (EnemyShip enemy : enemies) {
//do something with enemy object
}
As others have suggested, just do:
EnemyShip[] enemies = new EnemyShip[3];
for (int i = 0; i < enemies.length; i++) {
enemies[i] = new EnemyShip();
}
However, I think you should reconsider using an array. Using an array limits you to having, at maximum, as many enemies as will fit into the array.
Do you really know that you want at most 3 enemies at compile-time?
Why not make things more flexible and use a List instead? This will allow you to track as many enemies as you want to create at run-time. So for example, if the player is doing well you create more, if the player is doing poorly you create less.
List<Enemy> enemies = new ArrayList<Enemy>(3); // 3 is the expected capacity
for (int i = 0; i < 3; i++) {
createEnemy();
}
... elsewhere...
public void createEnemy() {
enemies.add(new EnemyShip());
}
Requirements change, particularly in game development. Try to avoid committing to things too early.
Related
I have a game template which has two classes as its levels.
The game has a player, enemies, treasure chests, and walls.
When I run the program, it loads Level 1, successfully. I have designed the code so if a certain condition is met, Level 2 must load. Now, Level 2 loads. But certain elements from Level 1 remain on screen, ignoring certain elements from Level 2.
To be exact:
From Level 2, it loads the player's initial coordinates, the treasure chests, and the final destination, ignoring the enemies and the walls.
It brings with itself from Level 1 to Level 2: the walls, the treasure chests, and the enemies. The latter two are in a frozen state. They don't function.
//Instance variables:
private int lvlCount = 1;
// Game() method
public Game(Stage stage) {
this.score = new SimpleIntegerProperty(0);
this.mobs = new ArrayList<>();
this.hitBoxes = new ArrayList<>();
this.treasure = new ArrayList<>();
this.newLevel = new ArrayList<>();
this.enemyCount = 0;
bg();
loadLevel(1);
living();
stuff();
mob2();
finalText();
stage.setOnShown(e -> this.run());
}
//The switch for loading the Levels:
void loadLevel(int in) {
switch (in) {
case 1:
this.level = new Level1();
break;
case 2:
this.level = new Level2(); // placeholder for second level
break;
}
hitBoxes.clear(); // clear the list of hitboxes
mobs.clear(); // remove any existing old mobs
this.getChildren().addAll(hitBoxes); // add all the hitboxes for the walls to the scene
background.setImage(level.getImage()); // get the background image
hitBoxes.addAll(level.getWalls()); // get all the wall hitboxes
enemyCount = level.getEnemyCount(); // get the enemy count from the level
chestCount = level.treasureCount(); // get the treasure count from the level
this.initTreasure(chestCount); // add the treasure chests for the level
this.initMobs(enemyCount); // initialize our mobs
lvlCount = level.lvlCount();
this.initLevel(lvlCount);
}
//The collision check:
private void collisionCheck() {if (r.getFill().equals(Color.WHITE)){lvlCount--;}
//Main Game loop method:
private void play() {
AnimationTimer gameLoop = new AnimationTimer() {
public void handle(long arg0) {
for (int i = 0; i < mobs.size(); i++) {
MOB m = mobs.get(i);
if (m instanceof Enemy) {
((Enemy) m).moveCheck(arg0);
}
}
collisionCheck();
if (lvlCount == 0){
loadLevel(2);} //The condition that loads Level 2
gameLoop.start();
}
Please help me to figure out how I can load Level 2, successfully.
Please note that it does not produce any errors in the console. So, I am having a very hard time figuring out where the problem lies.
I only pasted the code that I thought is necessary to achieve my goal. Here you can see the full code, for veiwing purposes only, no download necessary:
http://paste.mooc.fi/955c6d30
Thank you very much in advance.
I am programming a small space-themed dungeon crawler game with a GUI made with Swing in Java. I am using the MVC programming paradigm. The game is represented as a grid on which buttons can be clicked to move the player over the board or attack enemies.
In the model/logic of the game I generate an abstract representation of the game environment using a 2D array by randomly assigning objects to x (column) and y (row) coordinates using the following method:
//methods
public void setGalaxy() {
galaxyArray = new GalacticObject[this.row][this.col];
//construct the array
Random rand = new Random();
int random;
for (int i = 0; i < this.row; i++) {
for (int j = 0; j < this.col; j++) {
GalacticObject obj = new GalacticObject(i,j);
random = rand.nextInt(100);
if (random < 5) {
//asteroid (5 percent chance)
obj.makeAsteroid();
} else if (random < 9) {
//blackhole (4 percent chance)
obj.makeBlackHole();
} else {
//rest is open (= empty)
obj.makeOpen();
}
galaxyArray[i][j] = obj;
}
}
}
Now I want to draw the actual GUI game board backed by this 2D array of objects in a JPanel container using a grid of JButtons. I want to basically call all the objects in the galaxyArray and draw a JButton with an corresponding image overlay at the corresponding coordinates in a ButtonGrid. What would be the best way to achieve this using Swing?
Currently, I also have written the following draft for a method that draws a JButtonGrid but I still fail to see what is the best strategy of having it backed by a 2D array of objects.
Furthermore, adding the icon for the buttons is not working for reasons unclear to me. (I commented that part out.)
public JPanel makeGameBoard() {
/** This method makes a first version of the game board when the object is first called */
//create a new JPanel
JPanel boardPanel = new JPanel();
// create a gridButton of JButtons defined by the width and length
JButton[][] gridButton = new JButton[this.boardWidth][this.boardLength];
// set layout
boardPanel.setLayout(new GridLayout(this.boardWidth,this.boardLength));
//for-loops to place buttons in gridButton
for(int y = 0; y < this.boardLength; y++) {
for(int x = 0; x < this.boardWidth; x++){
// creates new button (with coordinates as string); gridButton[x][y] needs to be reused as coordinate system
gridButton[x][y]=new JButton(x+":"+y);
gridButton[x][y].setActionCommand(x+":"+y);
gridButton[x][y].setText("");
gridButton[x][y].addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
String com = e.getActionCommand();
System.out.println(com);
}
});
// add icon to every button
// try {
// Image img = ImageIO.read(getClass().getResource("resources/invisible.png"));
// gridButton[x][y].setIcon(new ImageIcon(img));
// }
// catch (IOException ex) {
// System.out.println("Image file for gridButton not found!");
// }
// add the gridButton to the panel
boardPanel.add(gridButton[x][y]);
}
}
//return boardPanel
return boardPanel;
}
Essentially I am wondering what is the best strategy to access the objects stored in the galaxyArray from my makeGameBoard method so that the variables of the objects in the array can be used to draw an image on the button with corresponding coordinates in the grid.
/*EDIT Thanks to the suggestion and linked tutorials from the friendly people below, I have made it work! Here is the code for the board View for anyone having similar questions:
public void updateGameBoard(Galaxy board) {
/** This method initializes the board when the galaxy is first created in the game logic and updates it throughout the game */
Galaxy galaxyArray = board;
for (int r = 0; r < this.boardWidth; r++) {
for (int c = 0; c < this.boardLength; c++) {
//make galactic object and extract info from Galaxy
GalacticObject temporary = new GalacticObject(r,c);
temporary = galaxyArray.getGalacticObject(r,c);
//check the object and set the corresponding tile image
if (temporary.isAsteroid()) {
gridButton[r][c].setText("A");
} else if (temporary.isAsteroidField()) {
gridButton[r][c].setText("AF");
} else if (temporary.isBlackHole()) {
gridButton[r][c].setText("BH");
} else if (temporary.isOpen()) {
gridButton[r][c].setText("");
}
}
}
}
The exact details depend on how you implement the observer pattern. Following this outline, the example game cited here simply lets the main view, RCView, keep a private reference to the array named board, which is maintained by the game model, RCModel. Because RCView implements the Observer interface, the view's update() implementation simply iterates through the board and updates its array of tiles in response. Note that the update() method signature includes a reference to the Observable requesting the update. In your example,
public void update(Observable model, Object arg) {
GalacticObject galaxyArray = ((GameModel) model).getGalaxyArray();
//loop though model, updating view components
this.repaint();
}
I am wondering if there is a bit of code or that can apply a method from a class to all of the objects in the ArrayList? I'm making a basic space invaders program and I am trying to implement a move method that will apply to all of enemies, so that they move in a group rather than individually.
I've created the items in the array list here:
for (int i = 0; i < 6; i++) {
venWidth = venWidth - 139;
enemyList.add(new Venusian("/venusian.jpg", venWidth, height));
}
for (int i = 6; i < 12; i++) {
merWidth = merWidth - 145;
enemyList.add(new Mercurian("/mercurian.jpg", merWidth, merHeight));
}
for (int i = 12; i < 18; i++) {
marWidth = marWidth - 125;
enemyList.add(new Martian("/martian.jpg", marWidth, marHeight));
}
Here is where I call the move method:
for (int i = 0; i < enemyList.size(); i++) {
Invader Invaders = (Invader) enemyList.get(i);
Invaders.draw(g);
Invaders.Move(1024);
This makes them move independently and overlap, at the moment I am just moving them right and left using the boundaries of my created window. So is there any way of moving them together at the same time? I have searched for a way to apply a class method to all of the lists items but I haven't found anything after a couple of hours.
Any material, sources or advice relating to this would be greatly appreciated.
You will have to come up with a solution that can decouple the Invaders you are moving from those you are displaying.
This is due to the fact that your individual Invaders will always be more or less sequentially moved - even if you are working with multiple threads, etc. Even if you would start using Java8 Lambdas to write your code like this:
ArrayList<Invader> badGuys;
//fill your List here
badGuys.forEach( badGuy -> badGuy.move());
This would also create intermediate states where some Invaders were moved, some were not.
So you have to make sure that you only draw a consistent set of Invaders to your screen. You could do this several ways:
Only draw to screen after all Invaders were moved
Make a copy of your invaders for drawing, while the Invaders are being moved. After all Invaders were moved, start displaying the Invaders from the moved List
...
1st Edit: How do you draw the Invaders to screen? Is this happening in separate threads?
3rd EDIT: Okay so maybe you can stop your timerThread before starting to move your Invaders. And when you are finished with moving them you can restart the timer again. Check what methods your timer offers It should have start() and stop() or maybe suspend() methods.
Do something like this:
timer.stop();
badGuys.moveAll();
timer.start();
2nd EDIT: Just looked over your code again. There is no need for you to start your for loop number 2 and 3 from indexes other than 0. Your code will be easier to read if for example you just say:
for (int i = 0; i < 6; i++) { // start from 0 (to 6) instead of 6 to 12
merWidth = merWidth - 145;
enemyList.add(new Mercurian("/mercurian.jpg", merWidth, merHeight));
}
create an interface like Moveable. and put Move method on it. then implement it on Venusian, Martian and Mercurian. and use this interface on arraylist
interface Moveable {
public void Move(int dist);
}
class Mercurian implements Moveable {
public void Move(int dist)
{
//do something
}
}
class Venusian implements Moveable {
public void Move(int dist)
{
//do something
}
}
class Martian implements Moveable {
public void Move(int dist)
{
//do something
}
}
ArrayList<Moveable> enemyList = new ArrayList<Moveable>();
I'm working on my assignment which is to create a TicTacToe checker, and for some reason I'm unable to think of a way to do the first steps of creating the game. We read in from a text file that contains a line which represents one game; for example:
x,x,o, , ,x, ,o,o
That would look like this on a traditional board:
x|x|o
-----
| |x
-----
|o|o
Here's what I have so far:
class TicTacToe{
static String[][] game;
public TicTacToe(int size){
this.game = new String[size][size];
}
public static TicTacToe create(String input){
String tokens = input.split(",");
int size = (int)Math.sqrt(tokens.length); //For setting a size
// of the board
return null;
}
}
What I don't understand is how to return a new TicTacToe object: when I write my methods for checking rows, columns, etc. how will I get the board to check on? Am I going about this the right way?
[W]hen I write my methods for checking rows, columns, etc. how will I
get the board to check on?
The instance of your object should contain all of the information about the board. You have this (mostly) done already - game is the field which contains the information about the board. The only catch is that every board will contain the same board information, and if it's updated, it will contain the updated information.
If you want to treat this like a factory, then there are four things that you'll want to do:
Remove the static modifier from game. It's unnecessary and will lead to inconsistent states across multiple objects.
Make your constructor private - unless I'm missing something, there's no reason to initialize it outside of the factory.
private TicTacToe(int size) {
game = new String[size][size];
}
Or, better yet:
private TicTacToe(String[][] hydratedBoard) {
game = hydratedBoard;
}
I'll show you why in a moment.
Implement TicTacToe.create(String), and return the fully hydrated object. A suggestion would be to create the String[][] implicitly, create the object with that passed in as an argument to the constructor, and return your TicTacToe object.
public static TicTacToe create(String input) {
String[][] board = new String[3][3];
int i = 0; // count the row we're on
String[] tokens = input.split(",");
for(int j = 0; j < board.length; j++) {
if (j % 3 == 0) { // advanced to the end of the column set (SO)
i++;
}
board[i][j] = tokens[i*3 + j];
}
return new TicTacToe(board);
}
Provide some sort of getter to the board object. You might not have to do this per the assignment, but it's good practice. It could be either a straight-up getter on the String[][], or some sort of pretty-print representation; I don't know. I'll leave this implementation to the reader instead.
You're overthinking it. Rather than "return null;", use "return new TicTacToe(size);".
Although, usually when I create a static factory method (like your "create" method) I make the constructor private so it can only be called from the static create method.
...and then you will need to update the board if you want to actually remember the x/o positions you passed in...
Here I added an integration test for this game that might give you some ideas of how to create/think about the game.
public void testWinnerPlayerIWithVerticalLine() {
this.displayUnitTestDescription("Integration Test for having player 'X' as winner on a vertical line use case");
final IBoardGame<TicTacToeMove, TicTacToePlayer> ticTacTocGame = new TicTacToeGame();
final String playerIDisplayName = "X";
final String playerIIDisplayName = "O";
final TicTacToePlayer playerI = new TicTacToePlayer(playerIDisplayName);
final TicTacToePlayer playerII = new TicTacToePlayer(playerIIDisplayName);
ticTacTocGame.setGamePlayers(new TicTacToePlayer[]{playerI, playerII});
TicTacToePlayer[][] expectedBoardInteractionSnapshot = new TicTacToePlayer[][]{
new TicTacToePlayer[]{playerI, null, playerII},
new TicTacToePlayer[]{playerI, playerII, null},
new TicTacToePlayer[]{playerI, playerII, playerI}
};
ticTacTocGame.start();
ticTacTocGame.makeMove(new TicTacToeMove(0, 0));
ticTacTocGame.makeMove(new TicTacToeMove(1, 1));
ticTacTocGame.makeMove(new TicTacToeMove(2, 2));
ticTacTocGame.makeMove(new TicTacToeMove(0, 2));
ticTacTocGame.makeMove(new TicTacToeMove(2, 0));
ticTacTocGame.makeMove(new TicTacToeMove(2, 1));
ticTacTocGame.makeMove(new TicTacToeMove(1, 0));
this.displayBoardPlayerInteractionSnapshot(ticTacTocGame);
final TicTacToePlayer[][] actualBoardInteractionSnapshot = ticTacTocGame.getPlayerInteractionSnapshotBoard();
Assert.assertFalse(ticTacTocGame.isGameDraw());
Assert.assertTrue(ticTacTocGame.existWinner());
Assert.assertEquals(ticTacTocGame.getWinner().getDisplayName(), playerIDisplayName);
Assert.assertArrayEquals(actualBoardInteractionSnapshot, expectedBoardInteractionSnapshot);
}
If you are interested to find out more you can find the whole java implementation of the TicTacToe game: https://github.com/ncaralicea/tictactoe
So I'm just messing around learning to create a Space invaders type game. I can get the bad guys to move, Great!!. Hero moves, Great!! Bullets move, Great!! However I try to remove my bullets once they leave the screen as to not eat up all resources and it force closes on me once it gets rid of the bullet. It goes off the screen. Hits the int of -2 and then we use the remove() and boom. Force Close.
Here is my code. I'm wondering if they access the size() at the same time and just cause a force close because of it.
//I removed everything that doesn't pertane to the bullets.
public class GameScreen{
Bullet bullet = world.bullet;
public GameScreen(Game game) {
super(game);
world = new World();
}
//Draws our bullets.
int bulletLength = bullet.bullets.size();
for(int i = 0; i < bulletLength; i++) {
Placement part = bullet.bullets.get(i);
x = part.x * 32 + 11;
y = part.y * 32;
g.drawPixmap(Assets.bullet, x, y);
}
Class that holds my bullets.
public class Bullet {
public List<Placement> bullets = new ArrayList<Placement>();
public Bullet() {
}
public void shoot(int x, int y){
bullets.add(new Placement(x,y));
}
public void advance(){
int len = bullets.size(); // gets all bullets.
for(int i = 0; i < len; i++) {
bullets.get(i).y --;
if (bullets.get(i).y <= -2){//removes them once they are off the screen.
bullets.remove(i);
}
}
}
This is what I use to keep track of placement.
package com.learning.planecomander;
public class Placement {
public int x, y;
public Placement(int x, int y) {
this.x = x;
this.y = y;
}
}
When going through your list to remove bullets, you can remove bullets from a list but that affects the list immediately instead of after your loop is done. Since you are traversing to the length of the list at the start, you are going off the end of the list since you've removed elements. An example is probably more helpful than that description.
Let's say you have a list with three bullets (which I'll call a, b, c to make the example easier). On a pass through the list, a and c are fine but b needs to be removed.
i = 0;
bullets[0] = a;
bullets[1] = b;
bullets[2] = c;
First loop goes fine, second loop starts like this
i = 1;
bullets[0] = a;
bullets[1] = b;
bullets[2] = c;
We remove b, but the loop keeps going
i = 2;
bullets[0] = a;
bullets[1] = c;
OH CRAP ARRAYINDEXOUTOFBOUNDS! PROGRAM CRASHES!
The way to solve this is to use a temp list to store the bullets that need to be removed, and then once your update loop is finished, make a call to bullets.removeAll(temp)
Doing two passes is a good answer. It makes the loops simpler and easy to understand. If you'd like to do it in one pass though, iterate through the list in reverse order, and when you remove a bullet you can go to the next one and not worry about blasting past the end of the ArrayList.
Alternatively, you can keep your bullets in a linked list, and run through the list with an Iterator, which you can also use to remove items from the list with. Removing from the beginning middle or end of an linked list is always a constant time operation. Whereas removing from the beginning of an ArrayList can be more expensive. If you need random access to the elements in the list, then they can be inefficient. Keep in mind though, if you're only dealing with a handful of objects, then it doesn't really matter.
For bonus points, you might want to put all of your objects in a list, and then have your central loop process them all and have your game objects respond polymorphically to calls like dead?, think, move, draw or whatever you think is appropriate.