LibGDX ColorAction.restart() doesnt work - java

I'm trying to loop the ColorAction animation.
Here is my code:
ColorAction action = new ColorAction();
ShapeRenderer shapeRenderer;
#Override
public void create () {
shapeRenderer = new ShapeRenderer();
action.setColor(Color.BLUE);
action.setEndColor(Color.GOLD);
action.setDuration(5);
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
int fps = Gdx.graphics.getFramesPerSecond();
curFrame++;
if (curFrame == fps*5) {
action.restart();
curFrame = 0;
}
action.act(Gdx.graphics.getDeltaTime());
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(action.getColor());
shapeRenderer.rect(100, 100, 40, 40);
shapeRenderer.end();
}
But this is not working properly. It's just plays the animation once and stops.
Can somebody explain me what am I doing wrong? Thanks.
After a couple of changes:
ColorAction actionBtG = new ColorAction();
ColorAction actionGtB = new ColorAction();
SequenceAction sequenceAction;
RepeatAction repeatAction = new RepeatAction();
ShapeRenderer shapeRenderer;
Color blue = new Color(Color.BLUE);
#Override
public void create () {
shapeRenderer = new ShapeRenderer();
actionBtG.setColor(blue);
actionBtG.setEndColor(Color.GOLD);
actionBtG.setDuration(5);
actionGtB.setColor(blue);
actionGtB.setEndColor(Color.BLUE);
actionGtB.setDuration(5);
sequenceAction = new sequenceAction(actionBtG,actionGtB);
repeatAction.setAction(sequenceAction);
repeatAction.setCount(RepeatAction.FOREVER);
}
#Override
public void render () {
repeatAction.act(Gdx.graphics.getDeltaTime());
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(blue);
shapeRenderer.rect(100, 100, 40, 40);
shapeRenderer.end();
}

problem solved? ... I had the same problem a few minutes ago... The problem is, that the startcolor, in your case blue, has the same color like the endcolor, if the action is over. So you can't see any action! I solved this problem by creating a new instance, but I think, reset the start color should also work. I will try it later.
This means for you: Try to set the color again, wenn you will restart your action!
EDIT:
I replaced the ColorAction with my own class now:
public class ColorTransitionAnimation extends TemporalAction {
private final Color start = new Color();
private final Color end = new Color();
private final Color animatedColor = new Color();
private RepeatType repeatType = RepeatType.REVERSE;
public enum RepeatType { REVERSE, RESTART }
public void setRepeatType(RepeatType repeatType) {
this.repeatType = repeatType;
}
protected void update (float percent) {
float r = start.r + (end.r - start.r) * percent;
float g = start.g + (end.g - start.g) * percent;
float b = start.b + (end.b - start.b) * percent;
float a = start.a + (end.a - start.a) * percent;
animatedColor.set(r, g, b, a);
}
#Override
protected void end() {
super.end();
if(repeatType == RepeatType.REVERSE)
setReverse(!isReverse());
restart();
}
public Color getAnimationColor () {
return animatedColor;
}
public void setStartColor (Color color) {
start.set(color);
}
public void setEndColor (Color color) {
end.set(color);
}
}

First of all, the call to setColor tells it what instance of Color to modify, so you don't want to pass it a pseudo constant like Color.BLUE or you will be modifying the "constant" itself. The LibGDX color class is mutable, so even though BLUE is static final, it can still be modified. You need to create your own Color instance for use with the action and pass that in.
myColor = new Color(Color.BLUE);
To do a color cycle, you need two ColorActions (one for each of the two colors you switching between), and they need to be in a SequenceAction together. Both of them should be set to your same Color instance. And then if you want it to cycle multiple times, wrap the SequenceAction in a RepeatAction.

Related

Memory Leakage. Constantly rises until game crashes

I'm new to android development and I'm having a problem regarding the memory used by my game. It constantly rises until it crashes. I would appreciate if you could help me. Thank you.
Also, regarding the Spritebatch do i need to call this.dispose in the java class where i extend to game for it to be disposed? If so where can i call it? Thank you
public class Zero implements Screen, InputProcessor {
Pmacgame game;
private Stage stage;
private Skin skin;
private Sound sound ,laser;
private Music musicbg;
private Sprite spritebg, playerImage;
private ImageButton imgbtnLeft, imgbtnRight, fire, color1, color2, color3, color4,
bullet1, bullet2, bullet3, bullet4;
public static final float fireDelay = 0.3f;
String rr2;
private static int o = 0;
Rectangle player;
ArrayList<Bullet> bullets;
ArrayList<Target> targets;
ArrayList<Explode> explodes;
//long lastDrop;
int score;
boolean a, b;
public static final float minSpawnTime = 0.5f;
public static final float maxSpawnTime = 1.25f;
float shootTimer, targetSpawnTimer;
Random random;
public static int select;
public static int dis = 0;
public float health = 1;
private Sprite greenBar, redBar, blueBar, pinkBar, greenBarO, redBarO, blueBarO, pinkBarO;
public Zero(Pmacgame game){
#Override
public void render(float delta) {
shootTimer += Gdx.graphics.getDeltaTime();
ArrayList<Bullet> bulletsToRemove = new ArrayList<>();
if (fire.isPressed() && shootTimer >= fireDelay) {
shootTimer = 0;
bullets.add(new Bullet(player.x + 32f));
}
for (Bullet bullet : bullets) {
bullet.update(Gdx.graphics.getDeltaTime());
if (bullet.remove)
bulletsToRemove.add(bullet);
}
targetSpawnTimer -= Gdx.graphics.getDeltaTime();
if (targetSpawnTimer<=0){
targetSpawnTimer = random.nextFloat() * (maxSpawnTime -minSpawnTime) + minSpawnTime;
targets.add(new Target(MathUtils.random(267, Gdx.graphics.getWidth()-350f)));
}
ArrayList<Target> targetsToRemove = new ArrayList<>();
for (Target target: targets){
target.update(delta);
if (target.remove)
targetsToRemove.add(target);
if (target.getY()<=0){
health -= 0.1f;
if (health<=0){
select = 0;
dis = 1;
this.dispose();
game.setScreen(new GameOverScreen(game, score));
return;
}
}
}
ArrayList<Explode> explodesToRemove = new ArrayList<>();
for (Explode explode: explodes){
explode.update(delta);
if (explode.remove)
explodesToRemove.add(explode);
}
explodes.removeAll(explodesToRemove);
for (Bullet bullet: bullets){
for (Target target: targets){
if (bullet.getCollisionRect().collidesWith(target.getCollisionRect())){
targetsToRemove.add(target);
bulletsToRemove.add(bullet);
score+=5;
explodes.add(new Explode(target.getX(), target.getY()));
sound.play(1f, 1.3f, 0f);
}
}
}
targets.removeAll(targetsToRemove);
bullets.removeAll(bulletsToRemove);
//Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.begin();
spritebg.draw(game.batch);
game.batch.draw(blueBarO, 0, 575, blueBarO.getWidth(), blueBarO.getHeight());
game.batch.draw(redBarO, 0, 550, redBarO.getWidth(), redBarO.getHeight());
game.batch.draw(greenBarO, 0, 525, greenBarO.getWidth(), greenBarO.getHeight());
game.batch.draw(pinkBarO, 0, 600, pinkBarO.getWidth(), pinkBarO.getHeight());
game.font.draw(game.batch, "SCORE: " + score, 40, Gdx.graphics.getHeight() - 40 );
for (Bullet bullet: bullets){
bullet.render(game.batch);
}
for (Target target: targets){
target.render(game.batch);
}
for (Explode explode: explodes){
explode.render(game.batch);
}
if (health == 0) greenBar.setSize(greenBar.getWidth(), 0f);
game.batch.draw(greenBar, 0, 525, greenBar.getWidth() * health, greenBar.getHeight());
game.batch.draw(redBar, 0, 550, redBar.getWidth(), redBar.getHeight());
game.batch.draw(blueBar, 0, 575, blueBar.getWidth(), blueBar.getHeight());
game.batch.draw(pinkBar, 0, 600, pinkBar.getWidth(), pinkBar.getHeight());
game.batch.draw(playerImage, player.x, player.y, player.width, player.height);
game.batch.end();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
if (a) player.x -= 450 * Gdx.graphics.getDeltaTime();
if (b) player.x += 450 * Gdx.graphics.getDeltaTime();
if (player.x < 65f + imgbtnLeft.getWidth() + imgbtnRight.getWidth())
player.x = 65f + imgbtnLeft.getWidth() + imgbtnRight.getWidth();
if (player.x > Gdx.graphics.getWidth() - 350f)
player.x = Gdx.graphics.getWidth() - 350f;
}
#Override
public void dispose () {
musicbg.dispose();
laser.dispose();
stage.dispose();
skin.dispose();
sound.dispose();
}
}
public class Pmacgame extends Game {
SpriteBatch batch;
BitmapFont font;
#Override
public void create () {
batch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("r.fnt"));
this.setScreen(new Zero(this));
}
#Override
public void render () {
super.render();
}
#Override
public void dispose() {
font.dispose();
batch.dispose();
}
}
I'm reading between the lines, but it looks like you must be loading a Texture in the constructor of Bullet/Target/Explosion, since I don't see you passing a Texture or TextureRegion reference to their constructors or render methods.
You should be loading all your Textures in a single class and passing references to your game objects for them to "borrow" and draw with. Otherwise, you are loading many copies of the same images for no reason.
Also, a Texture is a Disposable, which means it uses native memory and must have dispose() called on it before you let the garbage collector take it. Otherwise, the native memory is leaked.
In your case, all these Bullets, Targets, and Explosions are loading many Textures over and over and never disposing them when you remove them.
Regarding your question about the SpriteBatch. Yes, you should dispose of it in the same class you instantiate it, and dispose() is the right place to do it.
Edit, barebones example:
public class Assets implements Disposable {
public final Texture horse;
public final Texture bullet;
// etc.
public Assets (){
horse = new Texture("horse.png");
//...
}
public void dispose(){
horse.dispose();
//...
}
}
public class Zero implements Screen, InputProcessor {
private final Assets assets;
//...
public Zero (){
assets = new Assets();
//...
}
//...
public void dispose(){
assets.dispose();
//...
}
}
public class Bullet {
//...
public void render(SpriteBatch batch, Assets assets){
batch.render(assets.bullet, /*...*/);
}
}

How to display an indicator of the process of turning a large pixmap?

Need to rotate the big pixmap(from gallery) in my game.
I use the following code for this.
For example:
public class MyGdxGame extends ApplicationAdapter {
private int w = 720, h = 1280;
private Stage stage;
private Image bigImg, button, rotationIndicator;
private Pixmap pixmap0;
private Pixmap pixmap90;
private Texture textureBigImg;
private String buttonPath = "badlogic.jpg", bigImgPath = "DSC_0006.JPG"; //DSC_0006.JPG: 5504x3096
private Thread thread;
#Override
public void create () {
stage = new Stage(new FillViewport(w, h));
button = new Image(new Texture(buttonPath));
textureBigImg = new Texture(bigImgPath);
bigImg = new Image(textureBigImg);
rotationIndicator = new Image(new Texture(buttonPath));
rotationIndicator.setPosition(720-256,0);
button.setPosition(0,0);
bigImg.setBounds( 0,256, w, w*3096/5504f);
pixmap0 = new Pixmap(Gdx.files.internal(bigImgPath));
thread = new Thread(new Runnable() {
#Override
public void run() {
rotation();
}
});
button.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
super.clicked(event, x, y);
stage.addActor(rotationIndicator);
rotation(); //rotationIndicator draw only after the turn process.
//thread.start(); //I get a black screen.
}
});
stage.addActor(button);
stage.addActor(bigImg);
Gdx.input.setInputProcessor(stage);
}
private void rotation() {
pixmap90 = new Pixmap(pixmap0.getHeight(), pixmap0.getWidth(), pixmap0.getFormat());
for (int y = 0, a = 0; y<pixmap0.getWidth(); ++y, ++a) {
for (int x = 0, b = pixmap0.getHeight(); x<pixmap0.getHeight(); ++x, --b) {
pixmap90.drawPixel(x, y, pixmap0.getPixel(a, b));
}
}
textureBigImg.dispose();
textureBigImg = new Texture(pixmap90);
textureBigImg.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
bigImg.setDrawable(new TextureRegionDrawable(new TextureRegion(textureBigImg)));
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.draw();
}
#Override
public void dispose () {
pixmap0.dispose();
pixmap90.dispose();
textureBigImg.dispose();
}
}
The problem is that the big picture turns too long. From this freezing program.
I tried to do it in a separate thread, but I get a black screen.
I tried to display the turn indicator, but it is drawn only after the turn process.
Now I am trying to reduce pixmap, but on weak devices there is still freezing.
You cannot create new Texture objects or manipulate them in separate threads because they are OpenGL objects. Your rotate() method should send a runnable back to the GL thread to load the Texture after you're done creating the rotated pixmap.
So take all the code after your for loop in rotate() and wrap it in a Runnable. Call Gdx.app.postRunnable().

Add a menu screen with libgdx

I'm new at Java. I'm writing a simple game like Flappy Bird. I like the add menu screen before starting the game, like
-Start Game -Credits maybe options (maybe), something like that.
Here is my basic code for oncreate:
#Override
public void create () {
batch = new SpriteBatch();
background = new Texture("background.png");
smurf = new Texture("smurf.png");
gargamel1 = new Texture("gargamel.png");
gargamel2 = new Texture("gargamel.png");
gargamel3 = new Texture("gargamel.png");
distance = Gdx.graphics.getWidth() / 2;
random = new Random();
smurfX = Gdx.graphics.getWidth() / 2 - smurf.getHeight() / 2;
smurfY = Gdx.graphics.getHeight() / 3;
shapeRenderer = new ShapeRenderer();
smurfCircle = new Circle();
enemyCircles = new Circle[numberOfEnemies];
enemyCircles2 = new Circle[numberOfEnemies];
enemyCircles3 = new Circle[numberOfEnemies];
font = new BitmapFont();
font.setColor(Color.WHITE);
font.getData().setScale(5);
font2 = new BitmapFont();
font2.setColor(Color.WHITE);
font2.getData().setScale(8);
for (int i = 0; i<numberOfEnemies; i++){
enemyOffSet[i] = (random.nextFloat() - 0.5f) * (Gdx.graphics.getHeight() - 200);
enemyOffSet2[i] = (random.nextFloat() - 0.5f) * (Gdx.graphics.getHeight() - 200);
enemyOffSet3[i] = (random.nextFloat() - 0.5f) * (Gdx.graphics.getHeight() - 200);
enemyX[i] = Gdx.graphics.getWidth() - gargamel1.getWidth() / 2 + i * distance;
enemyCircles[i] = new Circle();
enemyCircles2[i] = new Circle();
enemyCircles3[i] = new Circle();
sound = Gdx.audio.newSound(Gdx.files.internal("lose.ogg"));
}
}
To have several Screens you must extend Game in your Main class.
Default when you create a libGdx project with the "gdx-setup.jar" the Main class extends ApplicationAdapter.
public class MultipleScreen extends Game {
Now you have a method: setScreen(Screen). With this method you can change Screens.
Here is a template which I use often for my projects. It also dispose the old screen:
public class MultipleScreen extends Game {
#Override
public void create () {
}
public void changeScreen(Screen newScreen){
Screen oldScreen = getScreen();
setScreen(newScreen);
//Dispose the old screen to release resources
if(oldScreen != null)
oldScreen.dispose();
}
#Override
public void render () {
//Clear the Screen
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//Render the current Screen
super.render();
}
#Override
public void dispose () {
//Dispose Assets which you used in the whole Game
}
}
Here I created a new method: changeScreen(Screen). This method uses the setScreen method of the Game to set the screen and additional dispose the old one.
Now to make an example we need two Screens:
public class MenuScreen implements Screen {
//We need MultipleScreen class to change the screen
private MultipleScreen game;
public MenuScreen(MultipleScreen game) {
this.game = game;
}
#Override
public void show() {
}
private float f = 0;
#Override
public void render(float delta) {
//A simple Timer which changes the screen after 10 seconds
f += delta;
if(f > 10000){
//Here you can add for example also the Level to the GameScreen which level the player choose
//game.changeScreen(new GameScreen(game, levelNumber));
game.changeScreen(new GameScreen(game));
}
}
...
}
And a GameScreen which simple displays the badlogic image:
public class GameScreen implements Screen {
private MultipleScreen game;
private SpriteBatch batch;
private Texture img;
public GameScreen(MultipleScreen game) {
this.game = game;
}
#Override
public void show() {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
}
#Override
public void render(float delta) {
//Here we don't need to add Gdx.gl.glClear...
//because we already have this in our MultipleScreen which does this for every subScreen
batch.begin();
batch.draw(img, 0, 0);
batch.end();
}
...
#Override
public void dispose() {
//This things will be disposed if we change to another Screen to save resources
batch.dispose();
img.dispose();
}
Now the last thing we must do is to set a Screen if our game Starts. So in the create() method of our Main class (in this case MultipleScreen) we add:
#Override
public void create () {
changeScreen(new MenuScreen(this));
}
Now if the game is over we will go back to MenuScreen. But instead of creating a new MenuScreen everyTime we can add a backToMenu() method in our Main class:
private MenuScreen menuScreen;
#Override
public void create () {
menuScreen = new MenuScreen(this);
backToMenu();
}
public void backToMenu(){
setScreen(menuScreen);
}
In our GameScreen we now can simple call: game.backToMenu(); to change back to MenuScreen without creating a new one.
Important
If we call setScreen() the show() method will be called and not the Constructor of the class.
So every Asset you dispose in the classes dispose() method you must create in the show() method not in the Constructor else you will have no Assets if you show a Screen a second time.
A hope this little guide will help you.
If you need more help you can find some tutorials in the Internet where they change Screen:
https://www.gamedevelopment.blog/full-libgdx-game-tutorial-project-setup/

Google Tango Java API: Scene update with Rajawali3D

I am new to Tango and have trouble using Rajawali for Project Tango.
Is there a way to dynamically add new objects onto CurrentScene whenever single tap event occurs?
I have tried using getCurrentScene().addChild(object) in addNote() function, which is called whenever single tap event occurs.
The scene's number of children increments whenever addNote() is called, but the visual scene is NOT getting updated.
Here is my code:
public class SampleRenderer extends TangoRajawaliRenderer {
public SampleRenderer(Context context) {
super(context);
}
#Override
protected void initScene() {
// Remember to call super.initScene() to allow TangoRajawaliArRenderer to set-up
super.initScene();
// Add a directional light in an arbitrary direction
DirectionalLight light = new DirectionalLight(1, 0.2, -1);
light.setColor(1, 1, 1);
light.setPower(0.8f);
light.setPosition(3, 2, 4);
getCurrentScene().addLight(light);
// Set-up a material: green with application of the light
Material material = new Material();
material.setColor(0xff009900);
material.enableLighting(true);
material.setDiffuseMethod(new DiffuseMethod.Lambert());
// Build a pyramid and place it roughly in front and a bit to the right
Object3D object1 = new NPrism(4, 0f, 0.2f, 0.2f);
object1.setMaterial(material);
object1.setPosition(-0.25, 0, -1);
getCurrentScene().addChild(object1);
Log.d("Tap", getCurrentScene().getNumChildren() + "");
}
public void addNote(float x, float y, float z){
Material stickyNoteMaterial = new Material();
stickyNoteMaterial.setColor(0xEFF2B900);
stickyNoteMaterial.enableLighting(true);
stickyNoteMaterial.setDiffuseMethod(new DiffuseMethod.Lambert());
Object3D note = new Sphere(0.1f, 24, 24);
note.setMaterial(stickyNoteMaterial);
note.setPosition(x, y, z);
getCurrentScene().addChild(note);
Log.d("Tap", getCurrentScene().getNumChildren() + "");
}
#Override
public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) {
}
#Override
public void onTouchEvent(MotionEvent event) {
}
}
Thanks in advance!
It turns out that I was trying to add objects at wrong time.
When I added objects on onRenderFrame(), the objects got created just fine.

How do i set the image to appear at the end of the timer in another random place?

Im trying to make image reappear at the end of the timer. i cant figure out what i did wrong. the image appears in a random spot in the beginning but thats it.
what i need is for the application to launch and then display the 3 dots in random places and every 1 second appear in another random place
public class Main extends ApplicationAdapter {
SpriteBatch batch;
Texture blue;
Texture red;
Texture green;
Sprite spriteb;
Sprite spriter;
Sprite spriteg;
int x;
int y;
Random random = new Random();
private float counter;
private int number;
#Override
public void create () {
batch = new SpriteBatch();
blue = new Texture("blue.png");
red = new Texture("red.png");
green = new Texture("green.png");
spriteb = new Sprite(blue);
spriter = new Sprite(red);
spriteg = new Sprite(green);
spriteb.setPosition(random.nextInt(Gdx.graphics.getWidth()), random.nextInt(Gdx.graphics.getHeight()));
spriter.setPosition(random.nextInt(Gdx.graphics.getWidth()), random.nextInt(Gdx.graphics.getHeight()));
spriteg.setPosition(random.nextInt(Gdx.graphics.getWidth()), random.nextInt(Gdx.graphics.getHeight()));
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
spriteb.draw(batch);
spriter.draw(batch);
spriteg.draw(batch);
batch.end();
}
public void render (float deltaTime) {
counter -= deltaTime;
if (counter <= 0) {
spriteb.setPosition(random.nextInt(Gdx.graphics.getWidth()), random.nextInt(Gdx.graphics.getHeight()));
counter += 1000; // add one second
batch.begin();
spriteb.draw(batch);
batch.end();
}
}
}
Don't invent a wheel. I think this solution will be good for you:
Timer.schedule(
new Task(){
#Override
public void run() {
spriteb.setPosition(random.nextInt(Gdx.graphics.getWidth()), random.nextInt(Gdx.graphics.getHeight()));
spriter.setPosition(random.nextInt(Gdx.graphics.getWidth()), random.nextInt(Gdx.graphics.getHeight()));
spriteg.setPosition(random.nextInt(Gdx.graphics.getWidth()), random.nextInt(Gdx.graphics.getHeight()));
}
}, delay, interval);
Put this code into your create() method and see if its working. Write if something still not working.
I am trying to be constructive here but I am having a hard time understanding what is being called where.
If I was you I would add in some sort of description on what is being called where, or the full code you wrote.
Now Straight to the point
in your render() method
boolean regeneratePosition;
count -= delta;
if(count<=0)
count = Time;
regeneratePosition = true;
}
if(regeneratePosition) {
//your regenerate position code goes here
}
The other code remain.
Hope this helped

Categories

Resources