public class Player {
private Sprite enemy;
public Rectangle bounds;
private SpriteBatch batch;
private float deltaTime;
private float timer;
private ArrayList<Sprite> enemies;
private Iterator<Sprite> enemyIterator;
private ArrayList<Vector2> posCoordinate;
Sprite newEnemy;
public void create(){
batch=new SpriteBatch();
timer=0;
enemy=new Sprite(new Texture(Gdx.files.internal("spr_player.png")));
bounds=new Rectangle(200,700,82,80);
enemies=new ArrayList<Sprite>();
posCoordinate=new ArrayList<Vector2>();
newEnemy=Pools.obtain(Sprite.class);
}
public void update(){
deltaTime=Gdx.graphics.getDeltaTime();
enemyIterator=enemies.iterator();
timer+=1*deltaTime;
if(timer>=1f){
newEnemy(); //method called every second
timer-=1;
}
}
public void newEnemy(){
Vector2 position=Pools.obtain(Vector2.class); //vector2 is created for each enemy every second.
position.set(200,700);
posCoordinate.add(position);
newEnemy=Pools.obtain(Sprite.class); //enemy created every second
newEnemy.set(enemy);
enemies.add(newEnemy);
}
public void draw(SpriteBatch batch){
//this is where the enemy position is set and movement
for(Sprite enemy:enemies){
enemy.draw(batch);
}for(Vector2 position:posCoordinate){
newEnemy.setPosition(position.x,position.y);
position.y-=2;
}
}
}
newEnemy() method is being called every second that's why a new sprite is being rendered every second.
Basically what I'm trying to do is that when a new enemy is spawned, it must move downward until it goes outside the screen.But what is happening is that the enemy will only move for one second.
I think you've confused things by introducing the member variable newEnemy. You have a method that creates a new enemy and adds it to your enemies list, and after that, there should not be a reason to reference it separately from the list, so you should just allow the newEnemy reference to be discarded.
Therefore, you should remove the Sprite newEnemy line from your class, and just declare it within the newEnemy() method.
Also, there's no need for your list of Vector2's for positions, because the Sprite class already stores a position. You just need to move the individual sprites. So remove everything related to posCoordinate as well. Your newEnemy() method should just look like this:
private void newEnemy(){
Sprite newEnemy = Pools.obtain(Sprite.class);
newEnemy.set(enemy); //I recommend renaming your `enemy` variable to something like `prototypeEnemy` for clarity
newEnemy.setPosition(200, 700); //need to start it at correct location.
enemies.add(newEnemy);
}
Finally, in your draw method (which is the wrong place for updates) you're trying to move only the most recent enemy created, instead of moving all of them. Note that every iteration of the loop is affecting the same instance: newEnemy, which is only the last enemy you created.
Here's how I would revise your class.
1) The movement speed should be a constant, measured in world units per second, so declare something like this at the top of your class:
private static final float ENEMY_SPEED = -120f;
2) At the bottom of your update() method, you can add this to cause all of your enemies to move:
for (Sprite sprite : enemies){
sprite.translateY(deltaTime * ENEMY_SPEED);
}
3) Under that, you can add a check for when they are off screen, so you can remove them. The iterator instance must be used to avoid a ConcurrentModificationException.
Iterator<Sprite> enemyIterator = enemies.iterator();
while (enemyIterator.hasNext()){
Sprite sprite = enemyIterator.next();
if (sprite.getY() + sprite.getHeight() < screenBottom) //screenBottom is something you can calculate from your camera like camera.getPosition().y - camera.getHeight()/2
removeEnemy(sprite);
}
4) And to remove them, since you're using pooling, you should put them back in the pool when you finish with them
private void removeEnemy(Sprite sprite){
enemies.remove(sprite);
Pools.free(sprite);
}
5) In your draw method, remove the second for loop, now that we're handling the position update in the update method.
Related
hey am a beginner in Libgdx. i am a bit confused about disposing the stuff.
Texture brickTexture;
Array<Brick> bricks;
public Game {
brickTexture = new Texture("brick.png");
bricks = new Array<Brick>();
for (int i = 0; i < 10; i++) {
Brick brick = new Brick(i, brickTexture);
bricks.add(brick);
}
}
void dispose () {
brickTexture.dispose(); // brick texture loaded in this class
for (Brick brick : bricks) brick.brickTexture.dispose(); // disposing the public texture which was earlier passed on to the brick class
}
Should both of the lines be in the dispose method or only the first one ?
You only have to do this once. It's the same Texture object so when you dispose it on any reference no other object can use it anymore. It's disposed.
Also you might want to check out AssetManager class, which handles disposing stuff for you.
You are using "bricktexture" for every "Brick" in the ArrayList, so you are basically pointing to the same object so you should only dispose "bricktexture" once.
If you also want to "free" the array, probably you should call
bricks.clear();
Which will become empty (as with no elements inside).
My Sprite are spawned at a random time, after being spawned the the move upward until they get on a certain position then they should be removed. That's what I've been trying to do but I always get an error.
//this method is called at random time
public void newEnemy(){
Sprite enemy= Pools.obtain(Sprite.class);
enemy.set(enemySpr);
enemy.setPosition(200,150);
enemies.add(enemy);
}
//removing the enemy
while (enemyIterator.hasNext()){
Sprite nextEnemy=enemyIterator.next();//<--error here,this is line 66
if(enemySpr.getY()+enemySpr.getHeight()>=treeObj.treeSpr.getY()){
removeEnemy(nextEnemy);
}
}
//removeEnemy method
public void removeEnemy(Sprite sprite){
enemies.remove(sprite);
Pools.free(sprite);
}
//this is the error there I get:
Exception in thread "LWJGL Application" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at com.dreamroad.savethetree.EnemyClass.update(EnemyClass.java:66)
at com.dreamroad.savethetree.MyGdxGame.render(MyGdxGame.java:51)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:215)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)
Process finished with exit code 0
I think this is the reason why I get the error, but I'm not sure:
public void draw(SpriteBatch batch){
for(Sprite drawEnemy:enemies) { //enemies is the ArrayList
drawEnemy.draw(batch);
drawEnemy.translateY(deltaTime * movement);
}
}
As Subler says, the problem here is that you're trying to remove something from a list at the same time as iterating over it.
However, there's an easier solution. Simply call remove() on the iterator. This will remove the iterator's current element.
//removing the enemy
while (enemyIterator.hasNext()) {
Sprite nextEnemy = enemyIterator.next();
if(enemySpr.getY() + enemySpr.getHeight() >= treeObj.treeSpr.getY()) {
enemyIterator.remove();
Pools.free(nextEnemy);
}
}
The problem is that youre trying to remove something in a list you're currently iterating over, the thing i've always done in a situation like this is create an extra list which holds the Sprites that should be deleted, and then delete them after iterating over the list (or, at the end of your update method, or something like that)
A short code sample that illustrates my idea:
//removing the enemy
//Initialize a list to store the sprites to be removed
List<Sprite> toBeRemovedSprites = new ArrayList<Sprite>();
while (enemyIterator.hasNext()){
Sprite nextEnemy=enemyIterator.next(); //I get the error here..<--
if(enemySpr.getY()+enemySpr.getHeight()>=treeObj.treeSpr.getY()){
removeEnemy(nextEnemy);
toBeRemovedSprites.add(nextEnemy);
}
}
//Remove the sprites that should be deleted, after iterating over the list
for(Sprite s : toBeRemovedSprites){
enemies.remove(s);
}
//removeEnemy method
public void removeEnemy(Sprite sprite){
//Remove this line that removes the sprite from the list
//enemies.remove(sprite);
Pools.free(sprite);
}
Another thing you could do is just to use the remove function of the iterator,
imagine it could look something like this:
//removing the enemy
while (enemyIterator.hasNext()){
Sprite nextEnemy=enemyIterator.next(); //I get the error here..<--
if(enemySpr.getY()+enemySpr.getHeight()>=treeObj.treeSpr.getY()){
removeEnemy(nextEnemy, enemyIterator);
}
}
//removeEnemy method
public void removeEnemy(Sprite sprite, Iterator<Sprite> enemyIterator){
//Change the line to remove using the iterator
//enemies.remove(sprite);
enemyIterator.remove();
Pools.free(sprite);
}
I want to make it so that numerous sprites appear on the screen using an ArrayList. I'm getting and error for .add(R.drawable...
private Sprite sprite;
private ArrayList<Sprite> spritesArrayList;
spritesArrayList= new ArrayList<Sprite>();
for (Sprite sprite : spritesArrayList) {
spritesArrayList.add(R.drawable.spritesheet);}
I have written the following code. I would like to stop drawings once object one the collision has occurred. Unfortunately, it only stops drawing the object only when the collision is occurring and then starts drawing the object again.
To give an example of what I am trying to learn is: player collects coin, coin disappears. if the player misses coin, the coin still appears on screen.
The idea is to learn the basic concepts before I start putting things together. Copying code without understanding is no fun. Thanks in advance.
batcher.begin();
if (egg.collected) {
batcher.draw(AssetLoader.textureEgg, eggRect.x, eggRect.y, eggRect.width, eggRect.height);
}
batcher.end();
My egg class:
public class Egg {
private Rectangle egg;
private Vector2 location;
public Egg(float x, float y){
location = new Vector2(x, y);
egg = new Rectangle(location.x, location.y, 10, 15);
}
public void update(float delta) {
egg.x--;
if (egg.x < -20) {
egg.x = 137;
};
}
public boolean collected = false;
public Rectangle getEgg() {
return egg;
}
public boolean isCollected() {
return collected;
}
}
The result of the above code is: The game crashes with following errors.
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.mygdx.gameworld.GameRenderer.render(GameRenderer.java:60)
at com.mygdx.screens.GameScreen.render(GameScreen.java:32)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:214)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)
Tenfour04 is right. Since collides is true when the two objects overlaps, it will stop drawing while they overlap and start to draw again. Save the return value to member variable.
Create a member variable in your Egg class to keep track of whether the egg has been collected:
public boolean collected = false;
If you want to practice good encapsulation, you could make this variable private and give it a getter and setter, but I'll keep it simple like this.
Then in what appears to be your game or screen class, you need to tell the egg when it's collected:
if (eggRect.overlaps(boundingRect))
egg.collected = true;
Now, you should only draw the egg if it is not collected:
batcher.begin();
if (!egg.collected){
batcher.draw(AssetLoader.textureEgg, eggRect.x, eggRect.y, eggRect.width, eggRect.height);
}
batcher.end();
By the way, it's kind of weird that your Egg class extends Rectangle, but you aren't using it as a Rectangle but rather as a container for some other Rectangle. You might as well remove "extends Rectangle".
I'm creating a small game in android. Anything that needs to be drawn on screen extends my VisibleObject class, I then have a Manager class that i can add all my visible game objects to and each frame i tell the manager to call the draw function of everything within it.
Here's were objects are initialised and added to the manager:
#Override
public void surfaceCreated(SurfaceHolder holder) {
fps = new TextDrawable(Color.BLACK, 14, 100, 40, 40);
player = new Player();
map = new Map();
leftTouch = new TouchCircle(Color.GRAY);
manager.add("fpsText", fps);
manager.add("leftTouch", leftTouch);
manager.add("player", player);
manager.add("map", map);
gameloop = new GameLoop(getHolder(), this, fps);
gameloop.setRunning(true);
gameloop.start();
}
Now the problem i'm having is with the draw order, if you look at the order the objects are added to the manager for reference..
I can tell you for certain that the player is being drawn on top of
the map! These are both drawn by drawing there respective bitmaps with drawBitmap(..).
However the fpsText and leftTouch are being drawn underneath the map! These are drawn using drawText(..) and drawOval(..) respectively.
Even though they implement different Canvas.draw.. functions, I would expect them all to be drawn in order as I just pass the canvas object i have to my manager class and then let the manager cycle through each object passing it that canvas to draw with.
Can anyone clear up for me why bitmaps seem to be drawn on top and what the solution should be to get my fps and touch area drawn above the player and map bitmaps? I'd Appreciate it.
EDIT: I am using private ConcurrentSkipListMap<String, VisibleObject> objectMap; within my manager to store the objects and drawing like so..
public void draw(Canvas c){
for (Map.Entry<String, VisibleObject> object : objectMap.entrySet()){
synchronized(object){
object.getValue().draw(c);
}
}
}
Bitmaps are not drawn on top of the text unless you draw Bitmap after you drawn text (and position overlaps).
You haven't disclose onDraw method so I can't be sure, but I suspect that you are not calling drawing methods in right order.
How does you manager stores the values added to it? Maybe you use Map implementation that doesn't maintain order of elements added (most implementations don't, LinkedHashmap does).