I'm fairly new to Java and I'm having a problem with arrays in a game I am creating, which is similar to Bejeweled.
In this game, I have one class called Tile, which represents one colored tile on the board, along with its column and row (integers)on the board. I have another class for the board, called Board, that manages these tiles in a 2D array of integers, organized by column and row.
My problem occurs I swap two tiles on the screen. When this happens, their columns and rows are swapped, but the array that they are saved in does not recognize this change. On the screen, everything looks fine. The two tiles will switch positions.
For instance, if I have two adjacent tiles that I want to switch, at (column0, row0) and (column1, row0). In my array of tiles, these are tiles array[0][0] and array[1][0]. When I switch them, the first tile is now at the second tile's old position, and the second tile is now at the first tile's old position. However, the first tile is still recognized as array[0][0], even though it should now be array[1][0].
The significance of this is that my program will not recognize three consecutive tiles with the same color, and therefore it will not clear them from the board.
Is there anything I can do to fix this?
If you have any suggestions at all, that would be great. Thank you.
Not sure what exactly is wrong from your description. The code should look similar to this:
class Tile {
int col;
int row;
void setPos(int newCol, int newRow) {
col = newCol;
row = newRow;
}
class Board {
Tile[][] array;
void swap(int col0, int row0, int col1, int row1) {
// Get hold of the tile objects to swap
Tile tile0 = array[col0][row0];
Tile tile1 = array[col1][row1];
// Swap the positions stored in the tile objects
tile0.setPos(col1, row1);
tile1.setPos(col0, row0);
// Swap the tile objects in the array
array[col0][row0] = tile1;
array[col1][row1] = tile0;
}
}
Related
I have a TiledMap map with some object layers like "wall", "door", "spike"...
Each layer has only rectangles, at their specific positions.
What is the best way I could check if a specific cell of the tile layer contains an object from a specific object layer?
To do something like if Cell of the tile layer at (x,y) contains an object from a object layer "wall", say "can't move there".
I just started using libGDX and Tiles, and the current way of detecting something like this that I can think of would be to create all those rectangles and check if they overlap with the player rectangle each time a player moves to the next cell.
But that would be checking every single object, and I need to just check the one cell the player is currently in.
One way you could reduce computation (this only works if the walls/doors/etc. are all static and don't move or change shape) is by keeping a 2D array of booleans (basically your TiledMap) with true meaning that tile is blocked and vice versa.
In pseudocode:
// Initially all grid cells are un-blocked
boolean[][] gridBlockedByWall = new boolean[MAP_HEIGHT][MAP_WIDTH]; //Replace with your grid size
// Loop over each wall and set array (change depending on your implementation)
for (Rectangle wall: walls) {
// Here we run over every wall and column covered by this rectangle and set it as blocked
for (int row = wall.y; row < wall.y + wall.height; row++) {
for (int col = wall.x; col < wall.x + wall.width; col++) {
gridBlockedByWall[row][col] = true;
}
}
}
Now to test if position (x, y) is blocked by a wall simply do gridBlockedByWall[y][x] which will run in constant time.
all. I'm working on a small game in which a 2D array is created to house each tile of the "map" of the game. The game spawns a player and a bunch of assorted items. The cells look like this:
private String [][] cells;
...
public void set(int cellX, int cellY, String str)
{
cells[cellX][cellY] = str;
}
with each String stating what the cell in each place looks like. For instance, sometimes a wall spawns and sometimes passages are created (this is all read in from a file). So the question is this:
How can I randomly generate objects on certain cells? For instance, if I have 36 cells total (6x6), but only 23 of them can be "moved" on by the player, how can I randomly generate items that have an equal chance to spawn on each?
The code I have thus far is this.
public void draw()
{
for (int x = 0; x < cells.length; x++)
{
for (int y = 0; y < cells[w].length; y++)
{
if(cells[x][y] == "W"){
Cell wall = new Cell(config.wallImage());
wall.draw(config, x, y);
if(cells[x][y] == "P"){
Cell passage = new CellPassage(config.passageImage());
// This is where I need to check to see if the item is okay
// to be placed. If it is unable, nothing will be added to
// the Cell passage.
//passage.attemptToAdd(item);
passage.draw(config, x, y);
}
}
}
hero.draw();
}
So, had a discussion in chat with OP and this is the problem, which seemed a little confusing from the question post:
There are Item, such as Key and Gem, that may spawn in each round.
Those Item have a limit number that must be spawned every round. For example, there may spawn 5 Gem every round.
They must spawn in passages with an equal probability.
So, to solve this issue, my suggestion is:
Creating an ArrayList of Cell. Store all the cells of passages.
Generate a random number between 0 and array length - 1.
Repeat until the limit of needed items is reached.
It should look something like this:
public void addItem(Item item, int limit)
{
ArrayList<Cell> passages = new ArrayList<Cell>();
for(int x = 0; x < cells.length; x++)
{
for (int y = 0; y < cells[w].length; y++)
{
if (cells[x][y] == "P") //if it's a passage
passages.add(new Cell(x,y));
}
}
Random rand = new Random();
while(spawnedItems < limit){
if(passages.size() == 0)
throw LimitImpossibleError();
int randomNum = rand.nextInt(passages.size());
items.add(new ItemPosition(item, passages.get(randomNum))); //assuming that you have a global ArrayList of Item and respective Cell (ItemPosition) to draw them later
}
}
Another question of the OP in the discussion was how to draw the Item later. So, I gave him 2 suggestions:
Change the representation of the maze to some Object that represents what's in the maze. For example, CellInfo, which could be parent of Wall, Passage, Item, etc. This, however, would require much change on the actual work. He's actually reading the maze from a file, for example.
Having an ArrayList with Item and the respective Cell where it should be drawn. In the draw method, after drawing all the walls and passages (the only things represented in the maze with String), traverse this ArrayList and draw them in the respective position.
You could create an ArrayList of Points that are eligible to have an item on them, and then randomly select them using [your ArrayList's name].get(Math.random() * [your ArrayList's name].size())
As the title says, I'm having trouble with my Java code when it comes to finally drawing the counters on my abacus. the code compiles and runs but the counters are drawn starting from the first row instead of the top row. On top of this the counters do not stack in each column, one counter appears and moves up and down the column depending on which button is clicked which is correct but the counters should either be adding as I left click or subtracting as I right click.
I've spent a couple of hours on this and I'm sure it's something silly but my brain has stopped working and I cant think of any solutions.
Anyway, here is my code.
AbacusPanel.java
public void paint(Graphics g)
{
g.setColor(Color.gray);
g.fillRect(0,0,getWidth(), getHeight());
g.setColor(Color.black);
Graphics2D g2 = (Graphics2D)g;
// we'll use Graphics2D for it's "draw" method -
// neater than the Graphics "drawRect" suppled
// (which you could also use)
for (int i = 0;i<numCols;i++)
{
for(int j = 0;j<numRows;j++)
{
g2.draw(getRect(i,j));
}
}
for(int thisCol= 0; thisCol < numCols; thisCol++)
{
for(int thisRow = 0; thisRow < numRows; thisRow++)
{
for(int counters=0; counters<=myAbacus.getNumCounters(thisCol); counters++)
{
Rectangle r2 = getRect(thisCol,myAbacus.getNumCounters(thisCol));
g2.setColor(Color.red);
g2.fillOval(r2.x, r2.y, r2.width, r2.height);
}
}
}
}
Hopefully someone out there can point me in the right direction and sorry if any of this isn't formatted how you would like. This is my first question post and I have tried to make it easy on the eyes.
As per my comment:
When you draw the placeholders for stones, you iterate over columns and then rows. But when when draw the counters, you only iterate over columns and not rows. Why not rows also? And shouldn't the result of getNumCounters() take both column & row as inputs, since you're trying to get the number of counters per position on the mancala board, right?
In answer to your second question, I would have to believe that getNumCounters() would have to take both the row and column as inputs. Since you've got two rows on the mancala board, and the number of stones is dependent upon both the column and whether it is in the first or second row, it wouldn't make sense otherwise.
Also, a third thing to think about. In your rectangle, when you're drawing your counters, it seems would need to vary the position where they are -- it appears to me that each of your counters is going to stack on top of each other, so 20 counters will look no different than 1.
Background:
I have two 2d arrays. Each index within each 2d array represents a tile which is drawn on a square canvas suitable for 8 x 8 tiles.
The first 2d array represents the ground tiles and is looped and drawn on the canvas using the following code:
//Draw the map from the land 2d array
map = new Canvas(mainFrame, 20, 260, 281, 281);
for(int i=0; i < world.length; i++){
for(int j=0; j < world[i].length; j++){
for(int x=0; x < 280; x=x+35){
for(int y=0; y < 280; y=y+35){
Point p = new Point(x,y);
map.add(new RectangleObject(p,35,35,Colour.green));
}
}
}
}
This creates a grid of green tiles 8 x 8 across as intended.
The second 2d array represents the position on the ground. This 2d array has everyone of its indexes as null apart from one which is comprised of a Person class.
Problem
I am unsure of how I can draw the position on the grid. I was thinking of a similar loop, so it draws over the previous 2d array another set of 64 tiles. Only this time they are all transparent but the one tile which isn't null. In other words, the tile where Person is located.
I wanted to use a search throughout the loop using a comparative if statement along the lines of
if(!(world[] == null)){
map.add(new RectangleObject(p,35,35,Colour.red));}
However my knowledge is limited and I am confused on how to implement it.
Do not use a second Array at all. Simply create a RectangleObject named, for example, currentPosition or activeTile or personPosition.
You, however, do not really need to store the Point in the RectangleObject. Either use a 2D RectangleObject array for that (so that you can use the indexes to access them) and exclude the Point information in the RectangleObject,
or
create a List of RectangleObjects and add the Point information - but do not increment by 35, but rather by 1. When you're drawing the tiles, you can still (by knowing the index) figure out where to put the tile (e.g. indexX*tileWidth, indexY*tileHeight).
(It's not quite clear from what you've written what world and map are used for. Please explain so I can give a better answer)
Not sure how to approach this problem.
Basically, I want a Pixel -> Tile representation of a 400x400 window. Each coordinate on the screen, e.g 120x300 should be part of a tile. My smallest sprite is 4 pixels, so we can say that 1 tile = 4 pixels. The player and enemy sprites are all 20 x 20, so each player/bad guy will occupy 5 tiles.
Then I want to use this Map class to:
Retrieve the x/y coordinates of a player/monster sprite by suppling the index/id of the tile.
Knowing where the boundaries are, so it doesn't move the sprite beyond 400x400, thus hiding it.
Collision detection, knowing whether a tile is vacant or not.
How can this be done? Talking specifically about the x,y->tile or tile index->x,y conversion (for drawing the sprites appropriately) here.
Firstly, split out the concept of a pixel, which is just concerned with representation, with a tile, which is an actual game object with constraints it places on the game.
I find a good way to disentangle things like this is to start out sketching out the rough API of what you want. Something like:
public class Board {
public Board (int width, int height){.. }
public boolean isOccupied(int x, int y){.. }
public void moveTo(Point from, Point to) { ..
(maybe throws an exception for outofbounds )
where all internal units of the board are in tiles, not pixels.
Then pixel information can be derived from the board independantly from the tile representation with a bit of internal multiplication-
public Point getPixelPosition(int xTilePos, int yTilePos, int pixelsPerTile)..
The tiles can be internally represented as a 2d array or a single array, in which case you'd use some kind of internal representation scheme to map your array to the board squares, thus the mod arithmetic.
Short answer: Multiplication and Modulo operations.
But if this is stumping you, I'd suggest you do a serious math refresher before trying to write a game.
Also your statement
My smallest sprite is 4 pixels, so we
can say that 1 tile = 4 pixels. The
player and enemy sprites are all 20 x
20, so each player/bad guy will occupy
5 tiles.
doesn't work out for any reasonable geometry. If by "1 tile = 4 pixels" you mean that the tiles are 2x2, then a player takes 100, not five. If you mean they are 4x4 then players take 25, which still isn't 5.
/** size of a tile in pixel (for one dimension)*/
int TILE_SIZE_IN_PIXEL = 4;
/** size of a piece in tiles (for one dimension)*/
int PIECE_SIZE_IN_TILE = 5;
public int tileToPixel(int positionInTiles){
return TILE_SIZE_IN_PIXEL * positionInTiles;
}
/** returns the tile coordinate to which the given tile coordinate belongs
Note: tileToPixel(pixelToTile(x)) only returns x if x is the upper or left edge of a tile
*/
public int pixelToTile(int positionInPixel){
return positionInPixel / TILE_SIZE_IN_PIXEL;
}
You'll probably want methods operating on two arguments (x and y at) as well.
For the ID->piece conversion and vice versa you have various approaches available. Which one to choose depends on the exact requirements (speed, size of game ...). So make sure that you are hiding the implementation details, so you can change them later on.
I'd start with a real easy solution:
public class Piece{
/** x position measured in tiles */
private int x;
/** y position measured in tiles */
private int y;
/** I don't think you need this, but you asked for it. I'd pass around Piece instances instead */
private final Long id;
public void getX(){
return x;
}
public void getY(){
return y;
}
public void getID(){
return id;
}
}
public class Board(){
private Set<Long,Piece> pieces = new HashMap<Piece>(pieces);
public Piece getPieceOnTile(int tileX, int tileY){
for(Piece piece:pieces){
if (isPieceOnTile(piece, tileX, tileY)) return piece;
}
}
private boolean isPieceOnTile(piece, tileX, tileY){
if (piece.getX() < tileX) return false;
if (piece.getX() > tileX + PIECE_SIZE_IN_TILE) return false;
if (piece.getY() < tileY) return false;
if (piece.getY() > tileY + PIECE_SIZE_IN_TILE) return false;
return true;
}
}
Hope that gets you started. All code is writen without a compiler nearby so it will include typos and of course bugs, which may be distributed under the creative commons license.
The approach of keeping the pieces in a set should work well if there are not to many pieces. It should work better than a 2D array as long as most board area does not contain a piece. The whole thing currently assumes there are no overlapping pieces. If you need those getPieceOnTile must return a Collection of pieces. A set if order does not matter, a List if it does.