LibGdx `ShapeRenderer` on Android does not honor alpha channel - android

I have a program where I am drawing some lines on each frame using ShapeRenderer. On each frame I want to draw on top the previous, faded by a amount, frame.
So what I am doing is first draw a black rectangle with an alpha less than 1 and then draw the current frame. On desktop it works well and the result is something like this
But on Android it does not work. It renders like this.
I tried enabling blending before drawing rectangle
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Also tried seting the alpha channel to 8 bits in AndroidApplicationConfiguration (config.a = 8)
Nothing of these worked. What else can I try?
Also is there a better way to achieve what I want?
Screen code
package com.waterpaw.trochoids.screen;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.utils.viewport.ScreenViewport;
import com.waterpaw.trochoids.Trochoid;
import com.waterpaw.trochoids.Trochoids;
public class GameScreen extends BaseScreen {
private ShapeRenderer sr;
private ScreenViewport viewport;
private List<Trochoid> trochoids = new ArrayList<Trochoid>();
public GameScreen(Trochoids game) {
super(game);
viewport = new ScreenViewport();
Gdx.input.setInputProcessor(this);
sr = new ShapeRenderer();
}
private int resized;
#Override
public void resize(int width, int height) {
viewport.update(width, height);
trochoids.clear();
trochoids.add(new Trochoid(viewport.getWorldWidth(), viewport.getWorldHeight()));
resized = 2;
}
#Override
public void render(float delta) {
if(resized-- > 0) {
Gdx.gl.glClearColor(0f, 0f, 0f, 0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
processInput();
if(!trochoids.get(0).isPaused()) {
updateTrochoids();
renderTrochoids();
}
}
private void processInput() {
if(Gdx.input.isKeyJustPressed(Keys.P)) {
if(trochoids.get(0).isPaused()) {
trochoids.get(0).unpause();
} else {
trochoids.get(0).pause();
}
} else if(Gdx.input.isKeyJustPressed(Keys.SPACE)) {
touchDown(0, 0, 0, 0);
}
}
#Override
public void dispose() {
sr.dispose();
}
#Override
public boolean touchDown(int x, int y, int pointer, int button) {
trochoids.get(0).initialize();
return true;
}
public void renderTrochoids() {
sr.setProjectionMatrix(viewport.getCamera().combined);
float w = viewport.getWorldWidth();
float h = viewport.getWorldHeight();
sr.setColor(0, 0, 0, 0.1f);
sr.begin(ShapeRenderer.ShapeType.Filled);
sr.rect(-w / 2, -h / 2, w, h);
sr.end();
sr.begin(ShapeRenderer.ShapeType.Line);
for(int i = 0; i < trochoids.size(); i++) {
trochoids.get(i).render(sr);
}
sr.end();
}
private void updateTrochoids() {
for(int i = 0; i < trochoids.size(); i++) {
trochoids.get(i).update();
}
}
}

LibGDX uses double buffering on Android, so your technique won't work. Draw to a FrameBuffer so you can ensure your previous drawing is not cleared every other frame. Then draw the FrameBuffer's color texture to the screen on every frame.

Related

Lbgdx: Repeating and scrolling background image

Hi I am developing the game, where i need scrolling and repeating background. Following are my code:
Main Game Class:
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
BitmapFont font;
float bgX =0f;
Texture background,background2;
On Create:
public void create () {
batch = new SpriteBatch();
background = new Texture("background.png");
background2 = new Texture("background.png");
On Render:
public void render () {
batch.begin();
bgX -=1;
batch.draw(background,bgX,0,background.getWidth(),Gdx.graphics.getHeight());
batch.draw(background2,background.getWidth() + bgX,0,background.getWidth(),Gdx.graphics.getHeight());
if(bgX <- background.getWidth())
{
bgX = 0;
}
On Dispose:
public void dispose () {
batch.dispose();
background.dispose();
However i get my desired result, but after mins, the scrolling becomes really slow.
Is there any other better option?
I need, background repeating scroll from right to left and background height is equal to Gdx.graphics.getHeight()
Thank you! in advance :)
you can simply achieve this by using "translate" method in libgdx. which will give you stable and constant output. please try this example.
public class myGame extends ApplicationAdapter{
public static Sprite sprite,sprite2;
public static texture;
public spriteBatch batch;
public myGame () {
}
#Override
public void create() {
texture = new Texture(Gdx.files.internal("background.png"));
texture2 = new Texture(Gdx.files.internal("background.png"));
sprite = new Sprite(texture, 0, 0, texture.getWidth(), texture.getHeight());
sprite2 = new Sprite(texture2, 0, 0, texture.getWidth(), texture.getHeight());
sprite.setPosition(0, 0);
sprite2.setPosition(1280, 0);
batch=new spriteBatch(sprite);
}
public void bckgroundMovment()
{
sprite.translate(-1.5f, 0);
// here 1280 is the screen width
sprite2.translate(-1.5f, 0);
if (sprite.getX() < -1280) {
sprite.setPosition(1280, 0);
}
if (sprite2.getX() < -1280) {
sprite2.setPosition(1280, 0);
}
}
#Override
public void render(float delta) {
bckgroundMovment()
batch.begin()
sprite.draw(batch);
sprite2.draw(batch);
batch.end();
}
#Override
public void draw(SpriteBatch batch, float deltaTime) {
settingUp(Gdx.graphics.getDeltaTime());
sprite.draw(batch);
sprite2.draw(batch);
}
}
// it will defenitly work ..good luck
One thing that I haven't noticed in your code, or you may have neglected to add, is to call batch.end(), which should always be called after batch.begin().
I've implemented vertical/horizontal parallax backgrounds using Actors, but this should work for your approach:
public void render () {
batch.begin();
float left = bgX - 1;
float backgroundWidth = background.getWidth();
if (left <= -backgroundWidth) { // right side is now off the screen to the left
bgX += backgroundWidth; // smoothly reset position
}
bgX -= 1; // continue scrolling
batch.draw(background, bgX, 0, backgroundWidth, Gdx.graphics.getHeight());
batch.draw(background2, backgroundWidth + bgX, 0, backgroundWidth, Gdx.graphics.getHeight());
batch.end();
}

Camera does not follow player

I use libgdx have one player which moves in x direction from left to right. Now I want the camera to follow it (like in Flappy Bird for example).
What happen is that the player go out off screen when it reaches the right border of screen and the camera don't follow him.
I have tried following options but none of them worked:
camera.position.set(player.getX(), camera.position.y, 0);
camera.position.set(player.getX(), 0, 0);
Vector3 vector3= camera.unproject(new Vector3(player.getX(), 0f, 0f));
player.setX(vector3.x);
I know that this question already exists on SO but none answer works in this case. Maybe I miss something important that i don't know.
The code:
Game.java class
public class Game extends com.badlogic.gdx.Game implements ApplicationListener {
public static Vector2 VIEWPORT = new Vector2(320, 480);
public static int WIDTH;
public static int HEIGHT;
#Override
public void create() {
WIDTH = Gdx.graphics.getWidth();
HEIGHT = Gdx.graphics.getHeight();
// VIEWPORT = new Vector2(WIDTH/2, HEIGHT/2);
VIEWPORT = new Vector2(WIDTH, HEIGHT);
setScreen(new GameScreen(this));
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
super.resize(width, height);
}
#Override
public void resume() {
}
#Override
public void pause() {
}
}
GameScreen.java class
import android.util.Log;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.viewport.FitViewport;
import java.util.Collections;
public class GameScreen implements Screen {
private OrthographicCamera camera;
private Player player;
private PlayerInputHandler inputHandler1, inputHandler2;
private Sound sound;
FitViewport viewp;
public static int WIDTH;
public static int HEIGHT;
int width_spacing = 0;
int height_spacing = 0;
Stage stage;
Skin skin;
public GameScreen(Game game) {
stage = new Stage(new FitViewport(Game.WIDTH, Game.HEIGHT));
camera = (OrthographicCamera) stage.getCamera();
Gdx.input.setInputProcessor(stage);
}
#Override
public void show() {
resetGame();
}
public void resetGame() {
WIDTH = Gdx.graphics.getWidth();
HEIGHT = Gdx.graphics.getHeight();
width_spacing = Game.WIDTH / 24;
height_spacing = Game.HEIGHT / 14;
stage.clear();
skin = new Skin(Gdx.files.internal("data2/uiskin.json"));
prepareInputHandlers();
prepare_stage();
}
public void addPlayer() {
Texture texture = new Texture("player.png");
player = new Player(texture);
player.setPosition(Game.WIDTH / 2, Game.HEIGHT * 2 / 3);
stage.addActor(player);
}
#Override
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (delta > 1 / 60f) {
player.setX(player.getX() + (4 * delta));
camera.position.set(player.getX(), camera.position.y, 0);
}
update();
stage.act(delta);
stage.draw();
}
private void update() {
camera.update();
}
private void prepareInputHandlers() {
inputHandler2 = new PlayerInputHandler(player, Input.Keys.LEFT, Input.Keys.RIGHT, Input.Keys.UP, Input.Keys.DOWN);
}
#Override
public void dispose() {
sound.dispose();
player.getTexture().dispose();
}
public void prepare_stage() {
addPlayer();
player.setWidth(64);
player.setHeight(64);
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
}
Player.java class
import com.badlogic.gdx.graphics.Texture;
public class Player extends com.badlogic.gdx.scenes.scene2d.ui.Image{
private Texture texture;
public Player(Texture texture) {
super(texture);
}
public Texture getTexture() {
return texture;
}
#Override
public void act(float delta) {
super.act(delta);
}
}
try to use stage's camera instead of creating your own. Change your GameScreen constructor like this:
public GameScreen(Game game)
{
stage = new Stage(new FitViewport(Game.WIDTH, Game.HEIGHT));
camera = (OrthographicCamera) stage.getCamera();
Gdx.input.setInputProcessor(stage);
}
then in the render method set the camera position just like
camera.position.set(player.getX(), camera.position.y, 0);
before camera.update() call
There is also something strange in your code - why you have camera.position.set() and setting player x in this condition:
if (delta > 1 / 60f) //??
{
player.setX(player.getX() + (4 * delta));
camera.position.set(player.getX(), camera.position.y, 0);
}
I'm pretty sure you don't need this - but even if you need the
camera.position.set(player.getX(), camera.position.y, 0);
should be out of if statement because what is happening now is that even if you are changing your player position (using keybord through PlayerInputHandler object) you **don't update camera position. Try to remove if statement or at least do something like
public void render(float delta)
{
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (delta > 1 / 60f)
{
player.setX(player.getX() + (100 * delta));
}
camera.position.set(player.getX(), camera.position.y, 0);
update();
stage.act(delta);
stage.draw();
}
last thing is that if your stage is empty (excluding player) when camera will start to follow player - you will see as player not moving at all :) Add someting more to stage

Box2D body lags/jumps when a camera is centered on it

I'm trying to set the camera position to the position of a body, but when I do this, the body will jump very noticeably. You can see this with the debug renderer but I have a sprite attached in my code. The jump is always in the direction that the sprite is headed. I've got a fixed time step with interpolation, and I update the sprites position to an interpolated value of the current and last position of a box2d body every frame. Then set the camera to the interpolated position.
import java.util.Random;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Input.Orientation;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.JointEdge;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.viewport.FitViewport;
public class GameScreen implements Screen {
private static learnGame game;
private static OrthographicCamera camera;
private static FitViewport viewport;
private static Random rand;
private static BitmapFont font;
private static Vector3 touch;
private static double frameTime;
private static double accumulator;
private static float animTime = 0f;
private static float step = 1f / 60f;
private static boolean killBody;
private static Buttons buttons;
public static Player tom;
public static InputMultiplexer multiplexer;
public static Bodies world;
public static boolean paused;
private static Sprite tomSprite = new Sprite(new Texture(Gdx.files.internal("chars/bob.png")));
public GameScreen(learnGame learngame) {
GameScreen.game = learngame;
multiplexer = new InputMultiplexer();
Gdx.input.setInputProcessor(multiplexer);
camera = new OrthographicCamera();
viewport = new FitViewport(40, 22.5f, camera);
buttons = new Buttons(game, multiplexer, viewport); //HUD stuff
world = new Bodies(viewport, multiplexer); //creates a box2d world
tom = new Player(world.box2d, 10, 15, 1f, multiplexer); //creates a body with a CircleShape with a radius of 1. Catches user input to apply forces to the body
Assets.loadSprites();
world.box2d.getBodies(world.bodies);
font = new BitmapFont();
touch = new Vector3();
rand = new Random();
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
learnGame.batch.setProjectionMatrix(camera.combined);
frameTime = 0;
if (!paused) {
frameTime = Math.min(Gdx.graphics.getRawDeltaTime(), 0.25);
accumulator += frameTime;
tom.update(); //here I apply forces to the body that I attach a camera to
generalUpdate(delta, touch, camera);
updatePositions(); //get previous positions for interpolation
while (accumulator >= step) {
world.box2d.step(step, 6, 2);
accumulator -= step;
interpolate((float) (accumulator / step));
}
world.box2d.clearForces();
learnGame.batch.begin();
if (tom.getBody().isActive()) {
tomSprite.setSize(tom.getHeight(), tom.getHeight());
tomSprite.setOriginCenter();
tomSprite.setRotation(Assets.tom.angle);//this doesn't work right but not the point.
tomSprite.setPosition(Assets.tom.pos.x, Assets.tom.pos.y);
tomSprite.draw(learnGame.batch);
}
learnGame.batch.end();
cameraUpdate(); //update the camera to the same position as the sprite
} else { //else pause the game
learnGame.batch.begin();
learnGame.batch.draw(Assets.pauset, viewport.getCamera().position.x
- (viewport.getCamera().viewportWidth / 2), viewport.getCamera().position.y
- (viewport.getCamera().viewportHeight / 2), viewport.getWorldWidth(), viewport.getWorldHeight());
learnGame.batch.end();
if (Gdx.input.isKeyJustPressed(Keys.SPACE) || Gdx.input.justTouched()) {
paused = false;
}
}
//destroy fixtures and bodies outside of the world step
for (Fixture fixture : Bodies.fixturesToDestroy) {
if (Bodies.destroyJoint == true) {
world.box2d.destroyJoint(Bodies.joint);
Bodies.joint = null;
Bodies.destroyJoint = false;
}
fixture.getBody().destroyFixture(fixture);
Bodies.fixturesToDestroy.removeValue(fixture, true);
}
for (Body body : Bodies.bodiesToDestroy) {
world.box2d.destroyBody(body);
body.setActive(false);
Bodies.bodiesToDestroy.removeValue(body, true);
}
}
#Override
public void show() {
Assets.firstSound.play();
}
#Override
public void resize(int width, int height) {
viewport.update(width, height, true);
Assets.reloadFont();
}
#Override
public void pause() {
paused = true;
}
#Override
public void resume() {
}
#Override
public void hide() {
paused = true;
}
#Override
public void dispose() {
Bodies.box2d.dispose();
Bodies.debugRenderer.dispose();
Buttons.stage.dispose();
Assets.cFrame.getTexture().dispose();
Assets.firstSound.dispose();
System.out.println("disposed");
}
public void generalUpdate(float delta, Vector3 touch, OrthographicCamera camera) {
if (Gdx.input.isKeyPressed(Keys.PAGE_UP)) {
camera.zoom -= 2f * Gdx.graphics.getDeltaTime();
;
} else if (Gdx.input.isKeyPressed(Keys.PAGE_DOWN)) {
camera.zoom += 2f * Gdx.graphics.getDeltaTime();
}
}
public static void cameraUpdate() {
camera.position.set(Assets.tom.pos, 0);
System.out.println("cam:" + Assets.tom.pos.x);
camera.update();
}
public static void kill() {
world.box2d.dispose();
world.debugRenderer.dispose();
Assets.cFrame.getTexture().dispose();
}
public void updatePositions() {
for (MySprite name : Assets.spriteList) {
name.prevPos = name.body.getTransform().getPosition();
name.prevAngle = name.body.getTransform().getRotation();
}
}
public void interpolate(float alpha) {
for (MySprite name : Assets.spriteList) {
name.pos.x = (name.body.getTransform().getPosition().x) * alpha + name.prevPos.x * (1.0f - alpha);
name.pos.y = (name.body.getTransform().getPosition().y) * alpha + name.prevPos.y * (1.0f - alpha);
name.angle = (name.body.getTransform().getRotation() * alpha + name.prevAngle * (1.0f - alpha));
}
}
}
I have tested my interpolation implementation without the camera moving and it appears to work fine. I've been able to test this on my desktop and on my android. The sprite "jumps" a lot more on my android but it happens on both devices. Not sure where I went wrong here, would really appreciate some input!
It's an old question, I know, but I just solved my Problem today.
I have implemented a fixed Timestep and interpolation, but my body lagged and jittered and jumped like there would be no tomorrow.
Please do following things to your camera Movement:
Use the interpolated Position from the body, NOT the original body position.
Use camera.position.slerp(x, y, z, alpha) to do a smooth movement. (You need to play a bit with the variables.
A really simple Example:
static Vector3 desiredPosition;
static {
desiredPosition = new Vector3(0, 0, 0);
}
public static moveCam(Player player, Camera camera){
desiredPosition.x = player.interpolatedPos.x;
desiredPosition.y = player.interpolatedPos.y;
camera.slerp(desiredPosition, Gdx.graphics.getDeltaTime * 5);
camera.update();
}
and in your render do the following
render(float delta){
moveCam(player, camera);
}
(Instant position setting caused jitter for my moving Object)
I wanted to give up my project, because of this bug. But I managed to do it. I hope it'll help people out there.
€dit: A guess why the jumping body is happening:
The interpolated position is not synchron with the camera (set Position then update world(now interpolated pos is offset with camera), then draw)
But I'm not sure with this.

LibGDX: A screen with 20 Rectangles that can be scrolled

I need to create a menu with 20 vertical Rectangles in LibGdx.
The height of the rectangles is the entire height of the device.
The width of the rectangles is a set 20.0f
I have: private Stage stage; to which I intend to add on to my Rectangles.
The class is called LevelSelectScreen and implements Screen.
This is what I have so far:
public class LevelSelectScreen implements Screen {
private Stage stage;
private int stageNumber = 20;
Array<Rectangle> stageRectangles;
ShapeRenderer shapeRenderer;
public LevelSelectScreen(){
stage = new Stage();
stageRectangles = new Array<Rectangle>(stageNumber);
for(int i = 0;i<stageNumber;i++){
stageRectangles.get(i).setWidth(20f);
stageRectangles.get(i).setHeight(Gdx.graphics.getHeight());
stageRectangles.get(i).setPosition(new Vector2(20*i,0));
}
Gdx.graphics.getWidth();
shapeRenderer = new ShapeRenderer();
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
//shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(0, 1, 0, 1);
for(int i = 0;i<stageNumber;i++){
Rectangle r = stageRectangles.get(i);
shapeRenderer.rect(r.x, r.y, r.getWidth(), r.getHeight());
}
shapeRenderer.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void show() {
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
}
}
Nothing appears and I don't think I'm using the Shape Renderer correctly.
How do I properly set up my scrollable rectangles?
Edit
Also, found this helpful link.
Varible class:
private Stage stage;
private int stageNumber = 20;
Array<Rectangle> stageRectangles;
ShapeRenderer shapeRenderer;
//new, for no magic number, but not required
private float w = 20f;
private float h = Gdx.graphics.getHeight();
private float space = 5;
private float xPos = w + space;
private float yPos = 0;
In your code:
public LevelSelectScreen(){
stage = new Stage();
stageRectangles = new Array<Rectangle>(stageNumber);
for(int i = 0; i<stageNumber; i++){
stageRectangles.add(new Rectangle(xPos * i,
yPos,
w,
h));
Gdx.app.log("Rectangle add", ""+i);
}
shapeRenderer = new ShapeRenderer();
}
you say that does not work or that I understand, but you're not having a Nullpointer or BoundsException ? anyway grabbing a few adjustments to your code this is what I have, it's what you wanted.
PS: do not would be more comfortable using a scroll and a table for when you have to use the listener, pictures ect, but it's just an idea, I hope you have understood what you were saying
in your code:
for(int i = 0; i<stageNumber; i++){
stageRectangles.get(i).setWidth(20f);
stageRectangles.get(i).setHeight(Gdx.graphics.getHeight());
stageRectangles.get(i).setPosition(new Vector2(25*i,0));
}
.
in this point stageRectangles.get(i).setWidth(20f);
the size is 0, then the array has an initial capacity
of 20 but is empty.
not getting something like this?
IndexOutOfBoundsException: index can't be >= size 0 >= 0

Android draw using SurfaceView and Thread

I am trying to draw a ball to my screen using 3 classes. I have read a little about this and I found a code snippet that works using the 3 classes on one page, Playing with graphics in Android
I altered the code so that I have a ball that is moving and shifts direction when hitting the wall like the picture below (this is using the code in the link).
Now I like to separate the classes into 3 different pages for not making everything so crowded, everything is set up the same way.
Here are the 3 classes I have.
BallActivity.java
Ball.java
BallThread.java
package com.brick.breaker;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class BallActivity extends Activity {
private Ball ball;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
ball = new Ball(this);
setContentView(ball);
}
#Override
protected void onPause() {
super.onPause();
setContentView(null);
ball = null;
finish();
}
}
package com.brick.breaker;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class Ball extends SurfaceView implements SurfaceHolder.Callback {
private BallThread ballThread = null;
private Bitmap bitmap;
private float x, y;
private float vx, vy;
public Ball(Context context) {
super(context);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ball);
x = 50.0f;
y = 50.0f;
vx = 10.0f;
vy = 10.0f;
getHolder().addCallback(this);
ballThread = new BallThread(getHolder(), this);
}
protected void onDraw(Canvas canvas) {
update(canvas);
canvas.drawBitmap(bitmap, x, y, null);
}
public void update(Canvas canvas) {
checkCollisions(canvas);
x += vx;
y += vy;
}
public void checkCollisions(Canvas canvas) {
if(x - vx < 0) {
vx = Math.abs(vx);
} else if(x + vx > canvas.getWidth() - getBitmapWidth()) {
vx = -Math.abs(vx);
}
if(y - vy < 0) {
vy = Math.abs(vy);
} else if(y + vy > canvas.getHeight() - getBitmapHeight()) {
vy = -Math.abs(vy);
}
}
public int getBitmapWidth() {
if(bitmap != null) {
return bitmap.getWidth();
} else {
return 0;
}
}
public int getBitmapHeight() {
if(bitmap != null) {
return bitmap.getHeight();
} else {
return 0;
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
ballThread.setRunnable(true);
ballThread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
ballThread.setRunnable(false);
while(retry) {
try {
ballThread.join();
retry = false;
} catch(InterruptedException ie) {
//Try again and again and again
}
break;
}
ballThread = null;
}
}
package com.brick.breaker;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class BallThread extends Thread {
private SurfaceHolder sh;
private Ball ball;
private Canvas canvas;
private boolean run = false;
public BallThread(SurfaceHolder _holder,Ball _ball) {
sh = _holder;
ball = _ball;
}
public void setRunnable(boolean _run) {
run = _run;
}
public void run() {
while(run) {
canvas = null;
try {
canvas = sh.lockCanvas(null);
synchronized(sh) {
ball.onDraw(canvas);
}
} finally {
if(canvas != null) {
sh.unlockCanvasAndPost(canvas);
}
}
}
}
public Canvas getCanvas() {
if(canvas != null) {
return canvas;
} else {
return null;
}
}
}
Here is a picture that shows the outcome of these classes.
I've tried to figure this out but since I am pretty new to Android development I thought I could ask for help.
Does any one know what is causing the ball to be draw like that?
The code is pretty much the same as the one in the link and I have tried to experiment to find a solution but no luck.
well , as you can see on the image , you only drew the ball . instead , you need to re-drew a black background (or whatever that you wish) before each time you draw the ball.
alternatively , you can draw a black area only on the previous position , but you might have problems with it later , when you use more objects.
here's a nice sample, similar to what you do
A quick look and I would have to say you are just drawing on the same surface and never requesting your surfaceview to redraw itself. at the end of the finally block, in the IF Statement use: postInvalidate(); That should cause the surface view to redraw itself.
put this
public void onDraw(Canvas canvas){
canvas.drawColor(Color.BLACK);
.....
}
See how i have done the pendulum simulation at
http://som-itsolutions.blogspot.in/2012/06/android-graphics-and-animation-pendulum.html
You can clone the source code of this project from
https://github.com/sommukhopadhyay/pendulumsimulation
[edit]The answer was wrong, but the comment was helpful so I'll leave this answer up:
Not the question you asked, but there is a problem in your code. In Android you are only allowed to write to the screen in the UI thread. This is the thread that runs all the Activity callbacks, etc. By writing to the screen from BallThread you are risking many odd failures in your program.

Categories

Resources