LibGDX Storing Vector2 Coordinates, Retrieving Them, & Displaying Stored Objects

Hi, java noob here :clue: I’m currently making a tetris like puzzle game that only a pair of single randomly generated gem/blocks.

So far I’ve been able to
-create my various screens
-generate a gem pair & apply a random coloured texture to each individual gem
-move and rotate the gem/block pair about the screen using keyboard inputs
-collision detection so gem/block pairs cannot leave the play area.
-generate a new gem pair as soon as the current gem as fallen and reached the bottom of the screen.

My problem.
As soon as my gem pair reaches the bottom of the screen, it disappears and a new gem pair is generated at the top of the screen. I believe this is because I haven’t stored the data for the gem pair anywhere so it just gets wiped from memory as soon as the method for create a gempair is called again. So to prevent this I thought I should create an array to store my blocks.

static Array<Block> deadBlocks = new Array<Block>();

I have created a method that will add each ge/block pair that has reached the bottom of the screen into the array.
sidenote*I made a design choice early on to have individual gems block1 and block2 instead of having a single object that held both blocks (I haven’t had a chance to really experiment so I’m not sure how you’d do that either).

static void deadBlocks(){

static Block block1 = Block.getBlock1();
static Block block2 = Block.getBlock2();

deadBlocks.add(block1);
deadBlocks.add(block2);

if(!(deadBlocks.size==0)){
	for(int i=0; i<deadBlocks.size;i++){
	sprite.begin();
	block1 = deadBlocks.get(i);
	block2 = deadBlocks.get(i++);
	sprite.draw(Block.blockTextures(block1, block2), deadBlocks.get(i).position.x, deadBlocks.get(i).position.y, Block.SIZE, Block.SIZE);
	sprite.draw(Block.blockTextures(block2, block1), deadBlocks.get(i++).position.x, deadBlocks.get(i++).position.y, Block.SIZE, Block.SIZE);
	sprite.end();

System.out.println("deadBlocks i x " + deadBlocks.get(i).position.x + ", y " + deadBlocks.get(i).position.y);
System.out.println("deadBlocks i++ x " + deadBlocks.get(i++).position.x + ", y " + deadBlocks.get(i++).position.y);

In the above code I have my array deadBlocks. I have used a separate class to create the blocks but for clarity I thought it would be best to remove those references in the code. (Block.SIZE should be just SIZE in this case).

I copied over my draw method from my gem/block pair creation method into the deadblocks method. I made adjusts to the position x and y so that pulls this data from the array. I used system.out so I could see if the correct information was being stored, it is, I’ve also checked using the debugger tool.

There seems to be a problem with null values so I enclosed my method call in my renderer class with an if statement that makes sure that the method is not called until the array is no longer empty.

The game runs fine until the first gem pair hits the bottom of the screen.

My system.out.prints the following (I realized I’m


GROUND COLLISION
deadBlocks i x 240.0, y 59.88349
deadBlocks i++ x 240.0, y -0.11639786
..
...
....
Exception in thread "LWJGL Application" java.lang.IndexOutOfBoundsException: index can't be >= size: 4 >= 4
	at com.badlogic.gdx.utils.Array.get(Array.java:127)
	at com.mygame.blockgame.GroundedBlocks.groundedBlocks(DeadBlocks.java:37)
	at com.mygame.blockgame.BlockControl.blockWallCollision(BlockControl.java:158)
	at com.mygame.blockgame.BlockControl.update(BlockControl.java:225)
	at com.mygame.blockgame.GameScreen.render(GameScreen.java:46)
	at com.badlogic.gdx.Game.render(Game.java:46)
	at com.mygame.blockgame.BlockGame.render(BlockGame.java:69)
	at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:206)
	at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)


Line 37 is the systemoutprint ln with i++ in the deadblocks method
Line 158 is the method call to my deadblocks method
Line 225 is the method call to my collision detection method
Line 46 is the movement update call in my render method of the game screen class

I’m guessing there is something wrong with how I’ve implemented the sprite draw method. I don’t understand the error about index can’t be greater or equal to 4. The game does crash when the 2nd block pair reaches the bottom, so I’m guessing because each block pair has two blocks thats where the 4 comes from, but I still do not know why it crashes at that point.

Apologies for the long post.

Many thanks

The deadBlocks.size returns the size of the Array, so if there are 4 elements in the Array it returns 4.
The deadblocks.get(int idx) method instead uses the index, starting with 0. So the 4th element ist deadblocks.get(3).

You are iterating througth the Array with i<deadblocks.size, which is the rigth way to do, but inside the loop you call deadblocks.get(i++).
So in the last iteration you have an IndexOutOfBoundException, because you call deadblocks.get(i++) while the last index is i.

Ah thanks that makes sense, you are right, when I comment out block2 from my deadBlock method it runs without incident :slight_smile:

What is the correct way to iterate through to get my 2nd block pair?

I’m thinking a While loop might be a good idea,
psuedo
While (i=0 ;i <= deadBlock.size){
block1 = deadBlock(i)
block2 = deadBlock(i+1)
}

or a for loop within a for loop. :point:

psuedo
for(i=0;i<deadBlock.size;i++){
for(j=1; j<deadBlock.size;j++){

drawSprite code here

}

I was also thinking I could try setting a max size of my array, ie since my game works on a 6 x 14 grid a max of 84 single blocks is needed to fill the screen. But I’m also thinking this might be a waste of memory if it’s not used, since the minimum for a game over is just 14 single blocks.

Thanks for your advice

No, don’t use a while loop. Might cause hangs.

What are you doing here exactly? I am confused, what is with this:


if(!(deadBlocks.size==0)){
   for(int i=0; i<deadBlocks.size;i++){
   sprite.begin();
   block1 = deadBlocks.get(i);
   block2 = deadBlocks.get(i++);
   sprite.draw(Block.blockTextures(block1, block2), deadBlocks.get(i).position.x, deadBlocks.get(i).position.y, Block.SIZE, Block.SIZE);
   sprite.draw(Block.blockTextures(block2, block1), deadBlocks.get(i++).position.x, deadBlocks.get(i++).position.y, Block.SIZE, Block.SIZE);
   sprite.end();

I don’t get why you are trying to draw 2 blocks at once and what is sprite.end() and sprite.begin() doing?

I think you are over-complicating this, what is wrong with just this?



for (Block block : deadBlock){
    block.draw(spriteBatch);
    }


Have your blocks set the position and all that of the sprite themselves, inside that draw method.

I did not really understand why you need to have a “block-pair” and what you want to do with those pairs but for me both of your mentioned ways to iterate througth the Array don’t seem to be rigth.
In the first one (while-loop) the you never increment i, i+1 does not increment i, but will just give you the value i+1.
For better understanding:


i = 1;
System.out.println(i+1);
System.out.println(i);

Will result in:
2
1


i = 1;
System.out.println(i++);
System.out.println(i);

Will result in:
1
2


i = 1;
System.out.println(++i);
System.out.println(i);

Will result in:
2
2

The second approach (the 2 for-loops) will give you every Block-Pair-combination, as for every step in the outer loop you iterate through the whole Array in the inner loop.

If i understood it rigth, you want to achieve the following:
Block0, Block1
Block2, Block3
Block4, Block5

This can be achieved by using a for loop like this:


for(int i = 0; i < deadBlocks.size-1; i+=2) {
     Block block1 = deadBlocks.get(i);
     Block block2 = deadBlocks.get(i+1);
}

I guess that should work.

Yeh the while loop didn’t work, the nested for loops did though.
In that snippet of code I wanted to make sure that the draw code was not executed if the array was empty. I am probably over complicating things here.

One of the design decisions I made was have individual blocks, but I needed them to be generated on screen as a pair of blocks. The best way to illustrate this is if you look at a game like Super Puzzle Fighter

Here like tetris a random block is generated into the game space for the user to control till it reaches the bottom of the screen. However each block is made up of 2 gems, these are randomly selected at different priorities. I wanted to do the same but I could only figure out how to draw each gem and manipulate them individually not as as pair. E.g my rotation method doesn’t actually rotate the objects, it moves block2 to a new position around block1. So for if I want block2 to appear above block1 I would just tell the game that block2’s Y coordinate is block1’s Y coordinate but + the size of the block. If I want it on the left or right of block1 then I’d do the same but with the x coordinates.

sprite.begin() and sprite.end() are methods for the spritebatch used to draw textures on to objects, this seems to be a requirement of the libgdx framework

I will try your suggestion to optimize my code. thanks

Block pair explained above, please see video.

Yeh I figured I was iterating incorrectly using i+1, the nested loop seems to work fine

Yes that’s exactly it. Oh wow even simpler, I’ll try this now. Many thanks

sprite.begin() and sprite.end() are used to begin() the SpriteBatch, with which the Sprites are drawn.
If you draw all Blocks with the same SpriteBatch, you should only call begin() and end() once per render loop.
This is, because SpriteBatch.end() causes the SpriteBatch to flush all the things drawn with it, which is pretty expensive.
If you instead just end() once, it will only flush when really needed (its “buffer” is full, you call flush() method and once, when you call end()).

Just another thing:
You said you are using pairs to rotate them rigth. That does not mean, that you need to draw() them in pairs.
If it is easier for you, to manage the Blocks in pairs, thats fine, but as logic and view should be seperated, you still should be able to draw each block alone.

Thanks for that, I removed the begin() and the whole thing seems to run smoother 8)

You are totally right I don’t need to do that at all! I’ve now removed the nested loop and draw a single block each time the loop is iterated. I’ve gone back to my blocktexture constructor and removed block2. Two blocks are still being generated randomly so this is perfect.


for(int i=0; i<deadBlocks.size;i++){
   
 block1 = deadBlocks.get(i);
 sprite.draw(Block.blockTextures(block1), deadBlocks.get(i).position.x, deadBlocks.get(i).position.y, Block.SIZE, Block.SIZE);
 sprite.end();
}


Now I have to figure out how to render the blocks stored in the array as blocks on the screen.

I’m thinking I need to return the object

Adding a return statement of block1 doesn’t do anything, I was thinking maybe I could try adding a variable to the sprite.draw because that holds the texture data and the coordinates.

Block deadBlock = sprite.draw(Block.blockTextures(block1), deadBlocks.get(i).position.x, deadBlocks.get(i).position.y, Block.SIZE, Block.SIZE);

then I could return deadBlock

EDIT

so that didn’t work because there is an object mismatch I must return a Block not a SpriteBatch.

I’ve also just realized that my array might be storing any texture data. :emo: I will double check with the debugger in a moment

thanks

2nd Edit

Yeh no texture data so I need to figure out how to store the spritebatch data in an array instead.

Edit 3

I think there is texture data being stored, I noticed that renderValue of the block is stored which is the name of the random number assigned to each texture colour

In this case renderValue1 of 2 indicates block1 is coloured green and renderValue2 of 8 indicates block2 is a destruction block of colour yellow

Edit 4

I hate my code, I’ve confused myself :yawn:

Why do you need to return the Block?
I guess after drawing it you really don’t need it anymore (at least in this render loop).
Just store the position inside the Block and draw the Block at the given position.
If the question is the color, cause Blocks can be “united”, then just store the color to.

Another approach would be (just a little idea, i did not think about it much) to have a structure like this:
You have got a class Block, which holds a List, a Color and the position.
The BlockPart can then just hold the relative position (position “inside” the Block), which is changed on rotate.
So basicly a Block is the whole thing, containig more BlockPart s, which are the 1 Tile-Pieces.
Then Iterate througth the Block-List/Array and draw every BlockPart of that Block in the given Color.

I’ve been going about it the wrong way. It would seem that trying to draw from another class was causing the problem. I just added the for loop including draw code to the main block draw code, pulled the correct data from the array and it worked.

Thanks for pointing me in the correct direction, much appreciated 8)