I have a problem with SurfaceView.
Function DrawWave is call by a timer Interval 5ms, BUT actually it needs more than 30ms between two calls, (I tried delete drawColor, drawPath).
I tried as "Mode 1" and "Mode 2", by using Dirty rect, hope it can run faster. The Interval is the same, both more than 30ms, (The width of this is 800px, and eScrX-sScrX<20px)
Question 1: Is it something I do wrong, using SurfaceView/SurfaceHolder?
Question 2: What can I do to improve the drawing speed? I hope that it can finish drawing in 10 ms.
My code:
public class VS_VChannel extends SurfaceView
{//Wave Show Class
//-------------------------------------------------------------------------------
private Paint paint = new Paint();
private SurfaceHolder sHolder = null;
private Canvas cvs = null;
private Path P = new Path();
//Data source of the wave point Y
protected VSChannel Channel = null;
private float drawY;
//-------------------------------------------------------------------------------
public VS_VChannel(Context context)
{
super(context);
}
//------------------------------------------------------------------------------
public VS_VChannel(Context context, AttributeSet attrs)
{
super(context, attrs);
//Bind the wave data source whith AttributeSet name:vs_wave
String vsName = attrs.getAttributeValue(null, "vs_wave");
Channel = (VSChannel)VS.GetItem(vsName);//Find the wave data source from collection with name
//
paint.setAntiAlias(true);
paint.setDither(true);
paint.setColor(Channel.getColor());
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
//
sHolder = this.getHolder();
this.setZOrderOnTop(true);
sHolder.setFormat(PixelFormat.TRANSPARENT);
}
//------------------------------------------------------------------------------
/** DrawWave is Call by a timer Interval 5ms,
* BUT actually it need more than 30ms between twice call,(tried delete drawColor, drawPath)
* I try as "Mode 1" and "Mode 2", by using Dirty rect, hope it can run faster
* The Interval is the same, both more than 30ms,
* (The width of this is 800px, and eScrX-sScrX<20px)
*/
protected void DrawWave(int sScrX, int eScrX)
{
Rect rect = new Rect(sScrX, 0, eScrX+8, getHeight()); //Mode 1
//Rect rect = new Rect(0, 0, getWidth(), getHeight()); //Mode 2
//
cvs = sHolder.lockCanvas(rect);
cvs.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
cvs.drawPath(P, paint);
sHolder.unlockCanvasAndPost(cvs);
}
//-------------------------------------------------------------------------------
protected void GetWaveY()
{
drawY = Channel.GetWaveY(getHeight());
}
//-------------------------------------------------------------------------------
protected void MoveTo(float x)
{
P.moveTo(x, drawY);
}
//-------------------------------------------------------------------------------
protected void LineTo(float x)
{
P.lineTo(x, drawY);
}
//-------------------------------------------------------------------------------
protected void DrawReturn()
{
P.reset();//Clear
P.moveTo(0, drawY);
}
//-------------------------------------------------------------------------------
}
//-------------------------------------------------------------------------------
If you are running on top of the display thread, you can only process and draw as fast as that thread allows. I might suggest drawing to a bitmap in another thread and then using the surface holder to unlock, draw the bitmap, and post.
Related
I'd like to have a path transition in such a way, that the path behaves relative to the window size, even when the size is changed during the animation. Furthermore, when the animation is completed, the animated element should use the stay at the relative destination location.
tileWidthProperty and tileHeightProperty are class members that I added for convinience and they simply divide the main pane's size in eights.
This is the code I have:
public void applyMove(final Ellipse toBeMoved, final int startCol, final int startRow, final int endCol, final int endRow)
{
Platform.runLater(() ->
{
final Path path = new Path();
final MoveTo startingPoint = new MoveTo();
final LineTo endPoint = new LineTo();
startingPoint.xProperty().bind(tileWidthProperty.multiply(startCol).add(tileWidthProperty.divide(2)));
startingPoint.yProperty().bind(tileHeightProperty.multiply(startRow).add(tileHeightProperty.divide(2)));
endPoint.xProperty().bind(tileWidthProperty.multiply(endCol).add(tileWidthProperty.divide(2)));
endPoint.yProperty().bind(tileHeightProperty.multiply(endRow).add(tileHeightProperty.divide(2)));
path.getElements().add(startingPoint);
path.getElements().add(endPoint);
toBeMoved.centerXProperty().unbind();
toBeMoved.centerYProperty().unbind();
PathTransition transition = new PathTransition(Duration.millis(10000), path, toBeMoved);
transition.setOrientation(PathTransition.OrientationType.NONE);
transition.setCycleCount(1);
transition.setAutoReverse(false);
//bind the node at the destination.
transition.setOnFinished(event ->
{
toBeMoved.centerXProperty().bind(tileWidthProperty.multiply(endCol).add(tileWidthProperty.divide(2)));
toBeMoved.centerYProperty().bind(tileHeightProperty.multiply(endRow).add(tileHeightProperty.divide(2)));
toBeMoved.setTranslateX(0.0);
toBeMoved.setTranslateY(0.0);
});
transition.play();
});
}
The col and row parameters are integers that are known to be 0 <= x < 8. They are the column and row of the tile position in the 8*8 grid.
The binding of the MoveTo and LineTo elements, however does not seem to have any effect.
First of all, once any standard Animation is started it does not change parameters.
So if anything changes, you have to stop the animation and start it again with new parameters.
I noticed you're trying to bind centerX and centerY after the transition is complete, which is wrong: PathTransition moves elements using translateX and translateY.
And for better debug you can actually add Path to the scene graph to see where your element will go.
Path path = new Path();
parent.getChildren().add(path);
I assume that tileWidthProperty and tileHeightProperty are bound to the actual parent size using something like this:
tileWidthProperty.bind(parent.widthProperty().divide(8));
tileHeightProperty.bind(parent.heightProperty().divide(8));
So I created example just to show how it might look like.
import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private Pane parent;
private final DoubleProperty
tileWidthProperty = new SimpleDoubleProperty(),
tileHeightProperty = new SimpleDoubleProperty();
private EllipseTransition ellipseTransition;
#Override
public void start(Stage primaryStage) {
this.parent = new Pane();
tileWidthProperty.bind(parent.widthProperty().divide(8));
tileHeightProperty.bind(parent.heightProperty().divide(8));
// create ellipse
final Ellipse ellipse = new Ellipse(25., 25.);
parent.getChildren().add(ellipse);
// show the stage
primaryStage.setScene(new Scene(parent, 800, 800));
primaryStage.show();
// create listeners that listen to size changes
InvalidationListener sizeChangeListener = l -> {
if(ellipseTransition != null) {
// refreshAndStart returns null if transition is completed
// let's call it delayed cleanup :)
ellipseTransition = ellipseTransition.refreshAndStart();
} else {
System.out.println("ellipseTransition cleaned up!");
}
};
// add listeners to the corresponding properties
tileWidthProperty.addListener(sizeChangeListener);
tileHeightProperty.addListener(sizeChangeListener);
// move ellipse 0,0 -> 7,7
applyMove(ellipse, 0, 0, 7, 7, Duration.millis(5000));
// interrupt transition at the middle, just for fun
/*new Thread(() -> {
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
return;
}
applyMove(ellipse, 2, 3, 4, 5, Duration.millis(1000));
}).start();*/
}
public void applyMove(final Ellipse toBeMoved, final int startCol, final int startRow, final int endCol, final int endRow, final Duration duration) {
Platform.runLater(() -> {
// if transition is still up, then stop it
if(ellipseTransition != null) {
ellipseTransition.finish();
}
// and create a new one
ellipseTransition = new EllipseTransition(toBeMoved, startCol, startRow, endCol, endRow, Duration.ZERO, duration, 0);
// then start it
ellipseTransition.start();
});
}
// I decided to write separate class for the transition to make it more convenient
private class EllipseTransition {
// these variables are the same you used in your code
private final Path path;
private final Ellipse ellipse; // this one was "toBeMoved"
private final int startCol, startRow, endCol, endRow;
private final Duration duration;
private final PathTransition transition;
// if we change parent size in the middle of the transition, this will give the new transition information about where we were.
private Duration startTime;
// we call System.currentTimeMillis() when we start
private long startTimestamp;
// if true, transition would not start again
private boolean finished;
public EllipseTransition(Ellipse ellipse, int startCol, int startRow, int endCol, int endRow, Duration startTime, Duration duration, long realStartTimestamp) {
this.path = new Path();
this.ellipse = ellipse;
this.startCol = startCol;
this.startRow = startRow;
this.endCol = endCol;
this.endRow = endRow;
this.startTime = startTime;
this.duration = duration;
this.transition = new PathTransition();
// applyMove passes 0, because we don't know our start time yet
this.startTimestamp = realStartTimestamp;
}
// this is called right before starting the transition
private void init() {
// show path for debugging
parent.getChildren().add(path);
// binding values here is useless, you can compute everything in old-fashioned way for better readability
final MoveTo startingPoint = new MoveTo();
startingPoint.setX(tileWidthProperty.get() * startCol + tileWidthProperty.get() / 2.);
startingPoint.setY(tileHeightProperty.get() * startRow + tileHeightProperty.get() / 2.);
final LineTo endPoint = new LineTo();
endPoint.setX(tileWidthProperty.get() * endCol + tileWidthProperty.get() / 2);
endPoint.setY(tileHeightProperty.get() * endRow + tileHeightProperty.get() / 2);
path.getElements().clear(); // clear paths from the last time
path.getElements().add(startingPoint);
path.getElements().add(endPoint);
ellipse.translateXProperty().unbind();
ellipse.translateYProperty().unbind();
transition.setNode(ellipse);
transition.setDuration(duration);
transition.setPath(path);
transition.setOrientation(PathTransition.OrientationType.NONE);
transition.setCycleCount(1);
transition.setAutoReverse(false);
transition.setOnFinished(event ->
{
// bind ellipse to the new location
ellipse.translateXProperty().bind(tileWidthProperty.multiply(endCol).add(tileWidthProperty.divide(2)));
ellipse.translateYProperty().bind(tileHeightProperty.multiply(endRow).add(tileHeightProperty.divide(2)));
// cleanup
stop();
// mark as finished
finished = true;
});
}
// stops the transition
private void stop() {
// remove debug path ( added it in init() )
parent.getChildren().remove(path);
transition.stop();
}
// starts the transition
public void start() {
if(finished) {
return;
}
init(); // initialize parameters
// start from the place where previous we stopped last time
// if we did not stop anywhere, then we start from beginning (applyMove passes Duration.ZERO)
this.transition.playFrom(startTime);
// applyMove passes 0, as it doesn't know when transition will start
// but now we know
if(this.startTimestamp == 0) {
this.startTimestamp = System.currentTimeMillis();
}
}
// stops the transition
public void finish() {
stop();
finished = true;
}
// stops and refreshes the transition.
// that will continue transition but for new values
private void refresh() {
// stop the transition
stop();
// determine how much time we spend after transition has started
long currentDuration = System.currentTimeMillis() - startTimestamp;
// update startTime to the current time.
// when we call start() next time, transition will continue, but with new parameters
this.startTime = Duration.millis(currentDuration);
}
// this method is called from change listener
public EllipseTransition refreshAndStart() {
if(finished) {
// return null to the listener
// we want to cleanup completely
return null;
}
// refresh new values and start
refresh(); start();
return this;
}
}
public static void main(String[] args) {
launch(args);
}
}
A little introduction: I've created a simple (for now) application which uses an AnimationTimer to update animations and draw objects to the Canvas. Everything runs smoothly and the timer adjusts its fps to the refresh-rate of my laptop (50/60Hz).
When I start the program however, there seems to be something wrong which causes my animations to appear 'jurky' or dropping frames, but the framerate stays a solid 60/50fps. Then when I resize the window for the first time (no difference how many), suddenly all the animations are super-smooth. After that, everything stays 'synced' no matter the resizes done.
What is the reason that the AnimationTimerstarts 'out-of-sync' until the window is resized and can it be prevented?
Update
Added a code example. The problem is mostly visible when on 50Hz, but also exist on 60Hz. Using Eclipse on Windows 10 (first code-share, may be to much/missing things).
public void start(Stage primaryStage) {
try {
pane = new Pane();
drawables = new ArrayList<>();
canvas = new Canvas(400,400);
canvas.widthProperty().bind(pane.widthProperty());
canvas.heightProperty().bind(pane.heightProperty());
GraphicsContext g = canvas.getGraphicsContext2D();
SimpleAnimatedCircle circle = new SimpleAnimatedCircle(20);
circle.setX(100);
circle.setY(50);
timer = new AnimationTimer() {
#Override
public void handle(long now) {
frameCount++;
if (System.currentTimeMillis() > frameStart + 500) {
System.out.println("FPS: " + frameCount*2);
frameStart = System.currentTimeMillis();
frameCount = 0;
}
for (Drawable drawable:drawables) {
drawable.update();
}
g.setFill(Color.DARKSLATEBLUE);
g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
circle.draw(g);
}
};
timer.start();
canvas.setOnMouseClicked((e) -> {
circle.start();
});
pane.getChildren().add(canvas);
Scene scene = new Scene(pane,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static class SimpleAnimatedCircle {
double diameter;
double x;
double y;
long startTime;
double diffY = 300; // Animated distance over y-axis.
double duration = 2000; // 2 second duration.
public SimpleAnimatedCircle(double diameter) {
this.diameter = diameter;
}
public void setX(double value) {
x = value;
}
public void setY(double value) {
y = value;
}
public void start() {
startTime = System.currentTimeMillis();
}
public void draw(GraphicsContext g) {
double animatedY = y;
// Update the animation.
if (System.currentTimeMillis() < startTime + duration) {
animatedY = y + (System.currentTimeMillis() - startTime) /
duration * diffY;
}
g.setFill(Color.ORANGE);
g.fillOval(x, animatedY, diameter, diameter);
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm developing a 2D car game for my University project.
I have developed it up to the point that user's car can move and traffic cars come from above. But I have no clue about how to destroy the user's car when it collied with a traffic car. Can anyone tell how to detect collision and after that how to destroy it.
public class MainActivity extends BaseGameActivity{
Scene scene; // declare a scene object
protected static final float CAMERA_WIDTH = 800; // define camera width
protected static final float CAMERA_HEIGHT = 520; //define camera height
/*----- background -----------*/
BitmapTextureAtlas backbitmapTextureAtlas; // declare a bitmap texture
ITextureRegion backiTextureRegion; // declare a i texture region to hold image
Sprite backsPlayer; // sprite to display the image
PhysicsWorld backpWorld;
SensorManager backsensor;
Vector2 backvec;
ITexture backparallax_background;
protected VertexBufferObjectManager backvbom;
org.andengine.engine.camera.Camera camera;
/*----- /background -----------*/
/*----user's car---------*/
BitmapTextureAtlas bitmapTextureAtlas;
ITextureRegion iTextureRegion;
Vector2 vec;
PhysicsWorld pWorld;
SensorManager sensor;
Sprite sPlayer;
/*----/user's car---------*/
/*------ traffic cars----------*/
BitmapTextureAtlas bitmapTextureAtlasTraffic1;
ITextureRegion iTextureRegionTraffic1;
Sprite sPlayerTraffic1;
BitmapTextureAtlas bitmapTextureAtlasTraffic2;
ITextureRegion iTextureRegionTraffic2;
Sprite sPlayerTraffic2;
BitmapTextureAtlas bitmapTextureAtlasTraffic3;
ITextureRegion iTextureRegionTraffic3;
Sprite sPlayerTraffic3;
BitmapTextureAtlas bitmapTextureAtlasTraffic4;
ITextureRegion iTextureRegionTraffic4;
Sprite sPlayerTraffic4;
MoveXModifier mod1;
MoveXModifier mod2;
MoveXModifier mod3;
MoveXModifier mod4;
/*------ /traffic cars----------*/
#Override
public EngineOptions onCreateEngineOptions() {
// TODO Auto-generated method stub
camera = new org.andengine.engine.camera.Camera(0,0,CAMERA_WIDTH,CAMERA_HEIGHT); // create camera
EngineOptions options= new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH,CAMERA_HEIGHT), camera); //create engine options
return options;
}
#Override
public void onCreateResources(
OnCreateResourcesCallback pOnCreateResourcesCallback)
throws Exception {
// TODO Auto-generated method stub
/* ---------------parallax back code------------------*/
backparallax_background = new AssetBitmapTexture(this.getTextureManager(), this.getAssets(), "gfx/back2.png");
backiTextureRegion = TextureRegionFactory.extractFromTexture(this.backparallax_background);
this.backparallax_background.load();
/* ---------------/parallax back code------------------*/
loadGfx(); // load user's car
loadTraffic();
pOnCreateResourcesCallback.onCreateResourcesFinished();
}
/*--------load traffic cars------------*/
private void loadTraffic() {
// TODO Auto-generated method stub
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/"); // give the path of image folder
bitmapTextureAtlasTraffic1 = new BitmapTextureAtlas(getTextureManager(), 256, 256);// create a bit map to hold the picture and give size according to the image
iTextureRegionTraffic1 = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bitmapTextureAtlasTraffic1, this, "traffic1.png", 0,0);
bitmapTextureAtlasTraffic1.load();
//----- traffic 2--------------
bitmapTextureAtlasTraffic2 = new BitmapTextureAtlas(getTextureManager(), 256, 256);// create a bit map to hold the picture and give size according to the image
iTextureRegionTraffic2 = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bitmapTextureAtlasTraffic2, this, "traffic2.png", 0,0);
bitmapTextureAtlasTraffic2.load();
//----- traffic 3--------------
bitmapTextureAtlasTraffic3 = new BitmapTextureAtlas(getTextureManager(), 256, 256);// create a bit map to hold the picture and give size according to the image
iTextureRegionTraffic3 = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bitmapTextureAtlasTraffic3, this, "traffic3.png", 0,0);
bitmapTextureAtlasTraffic3.load();
//----- traffic 4--------------
bitmapTextureAtlasTraffic4 = new BitmapTextureAtlas(getTextureManager(), 256, 256);// create a bit map to hold the picture and give size according to the image
iTextureRegionTraffic4 = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bitmapTextureAtlasTraffic4, this, "traffic4.png", 0,0);
bitmapTextureAtlasTraffic4.load();
}
/*--------load user's car------------*/
private void loadGfx() {
// TODO Auto-generated method stub
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/"); // give the path of image folder
bitmapTextureAtlas = new BitmapTextureAtlas(getTextureManager(), 256, 256);// create a bit map to hold the picture and give size according to the image
iTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bitmapTextureAtlas, this, "usercar.png", 0,0);
bitmapTextureAtlas.load();
}
/*--------load user's car------------*/
#Override
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
throws Exception {
// TODO Auto-generated method stub
scene = new Scene(); // create the object of scene
/*------ parallax background---------*/
final AutoParallaxBackground auto_background = new AutoParallaxBackground(0, 0, 0, 200);
final Sprite background_sprite = new Sprite(0,0, this.backiTextureRegion,backvbom);
auto_background.attachParallaxEntity(new ParallaxEntity(1.7f,background_sprite));
scene.setBackground(auto_background);
pOnCreateSceneCallback.onCreateSceneFinished(scene);
}
#Override
public void onPopulateScene(Scene pScene,
OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception {
// TODO Auto-generated method stub
// set traffic car1
sPlayerTraffic1 = new Sprite(10,350,iTextureRegionTraffic1,this.mEngine.getVertexBufferObjectManager());
sPlayerTraffic2 = new Sprite(300,280,iTextureRegionTraffic2,this.mEngine.getVertexBufferObjectManager());
sPlayerTraffic3 = new Sprite(400,190,iTextureRegionTraffic3,this.mEngine.getVertexBufferObjectManager());
sPlayerTraffic4 = new Sprite(50,70,iTextureRegionTraffic4,this.mEngine.getVertexBufferObjectManager());
mod1=new MoveXModifier(5,-600,800){
#Override
protected void onModifierFinished(IEntity pItem) {
// TODO Auto-generated method stub
Random r = new Random();
int y = r.nextInt(370-350)+350;// set y randomly
int speed = r.nextInt(3-2)+3; // set speed randomly
sPlayerTraffic1.setY(y); // set y
int x = r.nextInt(800-500)+200; // set x randomly
x = -x;
mod1.reset(speed, x, 800);
super.onModifierFinished(pItem);
}
};// moving down the traffic1 car
mod2=new MoveXModifier(4,200,800){
#Override
protected void onModifierFinished(IEntity pItem) {
// TODO Auto-generated method stub
Random r = new Random();
int y = r.nextInt(300-285)+285; // set y randomly
int speed = r.nextInt(5-3)+3; // set speed randomly
sPlayerTraffic2.setY(y); // set y
int x = r.nextInt(600-200)+200; // set x randomly
x = -x;
mod2.reset(speed, x, 800);
super.onModifierFinished(pItem);
}
};// moving down the traffic2 car
mod3=new MoveXModifier(3,-600,800){
#Override
protected void onModifierFinished(IEntity pItem) {
// TODO Auto-generated method stub
Random r = new Random();
int y = r.nextInt(190-150)+150;
int speed = r.nextInt(3-2)+2;
if(speed == 2){
y = 150;
}
sPlayerTraffic3.setY(y);
int x = r.nextInt(2000-800)+800;
x = -x;
mod3.reset(speed, x, 800);
super.onModifierFinished(pItem);
}
};// moving down the traffic3 car
mod4=new MoveXModifier(3,50,800){
#Override
protected void onModifierFinished(IEntity pItem) {
// TODO Auto-generated method stub
Random r = new Random();
int y = r.nextInt(100-70)+70;
int speed = r.nextInt(3-2)+2;
sPlayerTraffic4.setY(y);
int x = r.nextInt(600-200)+200;
x = -x;
mod4.reset(speed, x, 800);
super.onModifierFinished(pItem);
}
};// moving down the traffic4 car
sPlayerTraffic1.registerEntityModifier(mod1);
sPlayerTraffic2.registerEntityModifier(mod2);
sPlayerTraffic3.registerEntityModifier(mod3);
sPlayerTraffic4.registerEntityModifier(mod4);
//now set the x,y coordination of the image to display the right position we want
sPlayer = new Sprite(500,350,iTextureRegion,this.mEngine.getVertexBufferObjectManager()){ // user's car x,y
// touch event for user's car
#Override
public boolean onAreaTouched(org.andengine.input.touch.TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY)
{
this.setPosition(500 , pSceneTouchEvent.getY());
//website code
this.setPosition(pSceneTouchEvent.getX(),
this.getY());
//Detects if player is outside of bounds
final float width = this.getWidth();
final float height = this.getHeight();
float x = pSceneTouchEvent.getX() - width / 2 ;
float y = pSceneTouchEvent.getY() - height / 2;
if (x < 0)
x = 0;
if (y < 65) // right side of the road
y = 65;
if (x > (CAMERA_WIDTH - width))
x = CAMERA_WIDTH - width;
if (y > (CAMERA_HEIGHT - height-70)) // left side of the road
y = (CAMERA_HEIGHT - height-70);
this.setPosition(500, y);
return true;
}
};
//touch ----------------------------------------------------------
scene.registerTouchArea(sPlayer);
//-----------------------------------------------------------------
this.scene.attachChild(sPlayer);
this.scene.attachChild(sPlayerTraffic1);
this.scene.attachChild(sPlayerTraffic2);
this.scene.attachChild(sPlayerTraffic3);
this.scene.attachChild(sPlayerTraffic4);
pOnPopulateSceneCallback.onPopulateSceneFinished();
}
}
private ContactListener createContactListener()
{
ContactListener contactListener = new ContactListener()
{
#Override
public void beginContact(Contact contact)
{
final Fixture x1 = contact.getFixtureA();
final Fixture x2 = contact.getFixtureB();
if(x1==PlayerBody && x2==EnemyBody){
DestroyMethod();
}
}
};
return contactListener;
}
YourPhysicsWorld.setContactListener(createContactListener());
private void DestroyMethod(){
YourPhysicsWorld.destroyBody(EnemyBody);
}
I am developing a live wallpaper using Andengine GLES2 Anchor centre branch ,based on the Development Cookbook.Wallpaper works fine on mid range to high end devices but shows problem on low end devices.I have tested it on Samsung galaxy ace , Micromax Funbook tablet and the issue generator Samsung galaxy Y. Issue found only on Samsung galaxy Y the only low end device I have.
Issue
I got loosing textures of all sprites when unlocking screens sometimes,or when returning to homepage some times,Error is not generated in a predictable manner, some times it doesn't cause any issue at all, But when it occurs to make my work even in my preview mode I have to force close the application and start the app again.
These are the details of my live wallpaper,
Wallpaper have A background sprite,A main image sprite ,two BatchedSpriteParticleSystem with some initializers and modifiers
I have a sepretae folder in asset for lower end device (320*480) where I keep small images and load all images to a single texture atlas in that case other wise I am using two texture atlas one for background image,and one for my main image and the two particle images.I am using a resource manager calss as per the andengine cookbook to load textures
Please help me to sort out the issue,I dont know where iam going wrong on this
here is my code ...
LiveWallpaperExtensionService given below
LiveWallpaperExtensionService
#TargetApi(13)
public class LiveWallpaperExtensionService extends BaseLiveWallpaperService {
public Sprite bg_Sprite;
public Sprite main_image_sprite;
public SpriteBackground background;
public BatchedSpriteParticleSystem beamParticleSystem;
public BatchedSpriteParticleSystem starParticleSystem;
private Camera mCamera;
private Scene mScene;
#Override
public org.andengine.engine.Engine onCreateEngine(
final EngineOptions pEngineOptions) {
return new FixedStepEngine(pEngineOptions, 50);
}
public EngineOptions onCreateEngineOptions() {
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE))
.getDefaultDisplay();
Utils.setGlobalWidthandHeight(Utils.getDisplaySize(display));
mCamera = new Camera(0, 0, Global.Width, Global.Height);
EngineOptions engineOptions = new EngineOptions(true,
ScreenOrientation.PORTRAIT_SENSOR, new FillResolutionPolicy(),
mCamera);
engineOptions.getRenderOptions().setDithering(true);
return engineOptions;
}
public void onCreateResources(
OnCreateResourcesCallback pOnCreateResourcesCallback) {
System.out.println("On create resourses");
ResourceManager.getInstance().loadBlueTextures(mEngine, this);
pOnCreateResourcesCallback.onCreateResourcesFinished();
}
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback) {
System.out.println("On create scene");
mScene = new Scene();
pOnCreateSceneCallback.onCreateSceneFinished(mScene);
}
public void onPopulateScene(Scene arg0,
OnPopulateSceneCallback pOnPopulateSceneCallback) {
System.out.println("on populate ");
final float positionX = Global.Width * 0.5f;
final float positionY = Global.Height * 0.5f;
bg_Sprite = new Sprite(positionX, positionY,
ResourceManager.getInstance().mBackgroundTextureRegion,
this.getVertexBufferObjectManager());
main_image_sprite = new Sprite(positionX, positionY,
ResourceManager.getInstance().mJesusTextureRegion,
this.getVertexBufferObjectManager());
/*
* Define the center point of the particle system spawn location
*/
final int bparticleSpawnCenterX = (int) (Global.Width * 0.5f);
final int bparticleSpawnCenterY = (int) ((Global.Height * 0.5f) + ((Global.Height * 0.5f)) * 0.5f) - 25;
/* Define the radius of the circle for the particle emitter */
final float particleEmitterRadius = 50;
/* Create the particle emitter */
CircleOutlineParticleEmitter bparticleEmitter = new CircleOutlineParticleEmitter(
bparticleSpawnCenterX, bparticleSpawnCenterY,
particleEmitterRadius);
beamParticleSystem = new BatchedSpriteParticleSystem(bparticleEmitter,
10, 15, 50, ResourceManager.getInstance().mBeamTextureRegion,
mEngine.getVertexBufferObjectManager());
beamParticleSystem
.addParticleInitializer(new ExpireParticleInitializer<UncoloredSprite>(
3));
beamParticleSystem
.addParticleInitializer(new AccelerationParticleInitializer<UncoloredSprite>(
-150, 150, -150, 150));
RectangleParticleEmitter particleEmitter = new RectangleParticleEmitter(
((int) (Global.Width * 0.5f)), ((int) (Global.Height * 0.5f)),
Global.Width, Global.Height);
// Create a batched particle system for efficiency
starParticleSystem = new BatchedSpriteParticleSystem(particleEmitter,
1, 2, 20, ResourceManager.getInstance().mStarTextureRegion,
mEngine.getVertexBufferObjectManager());
/* Add an acceleration initializer to the particle system */
starParticleSystem
.addParticleInitializer(new ExpireParticleInitializer<UncoloredSprite>(
10));
starParticleSystem
.addParticleInitializer(new RotationParticleInitializer<UncoloredSprite>(
0, 160));
/* Define min/max values for the particle's scale */
starParticleSystem
.addParticleInitializer(new ScaleParticleInitializer<UncoloredSprite>(
0.3f, 1.5f));
/* Define the alpha modifier's properties */
starParticleSystem
.addParticleModifier(new AlphaParticleModifier<UncoloredSprite>(
0, 2, 0, 1));
/* Define the rotation modifier's properties */
starParticleSystem
.addParticleModifier(new RotationParticleModifier<UncoloredSprite>(
1, 9, 0, 180));
// Add alpha ('fade out') modifier
starParticleSystem
.addParticleModifier(new AlphaParticleModifier<UncoloredSprite>(
8, 10, 1, 0));
/*
* Create the SpriteBackground object, specifying the color values &
* Sprite object to display
*/
final float red = 0.7f;
final float green = 0.78f;
final float blue = 0.85f;
final float alpha = 1;
background = new SpriteBackground(red, green, blue, bg_Sprite);
mScene.setBackground(background);
mScene.setBackgroundEnabled(true);
// Attach our particle system to the scene
mScene.attachChild(starParticleSystem);
mScene.attachChild(beamParticleSystem);
mScene.attachChild(main_image_sprite);
bg_Sprite.setIgnoreUpdate(true);
main_image_sprite.setIgnoreUpdate(true);
pOnPopulateSceneCallback.onPopulateSceneFinished();
}
#Override
protected synchronized void onPause() {
System.out.println("On paused");
super.onPause();
if (starParticleSystem != null) {
starParticleSystem.setParticlesSpawnEnabled(false);
}
if (beamParticleSystem != null) {
beamParticleSystem.setParticlesSpawnEnabled(false);
}
}
#Override
protected synchronized void onResume() {
System.out.println("On resume");
super.onResume();
if (starParticleSystem != null) {
starParticleSystem.setParticlesSpawnEnabled(true);
}
if (beamParticleSystem != null) {
beamParticleSystem.setParticlesSpawnEnabled(true);
}
}
}
}
Please help me to sort out this issue ,I welcomes all ideas Suggestions, Any thing any thoughts of you to solve this issue ....
I've noticed that Galaxy Y has lots of issues, been getting lots of crash reports for a game of mine till I blocked them from downloading it and all reports stopped [it was the only device with issues]
I suggest you do the same
edit:
if you want to chose which devices to support, you can use this example
<supports-screens
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="false"
android:anyDensity="true" />
modify that as you see fit
I am trying to do something similar to this but in Android.
In Android I can extend the ProgressBar but I am doubting of how to add the TextViews on top. In iphone it was easy because I can use absolute positions, but not here.
Any ideas?
EDIT:
I decided to use SeekBar instead of ProgressBar to add the thumb drawable. I commented below. Some points to notice:
I am using hardcoded values, actually three but it can be more or less.
When the thumb is moved it moves to 50 but it should move to the different options.
I am using pixels instead of dpi. I should fix that.
I need to solve the lack of animation when the thumb moves.
My progress so far:
public class SliderFrameLayout extends FrameLayout implements OnSeekBarChangeListener {
private SeekBar mSlider;
private Context mContext;
private int mSize = 3;
private TextView[] mTextViews;
private String[] mTexts = {"Nafta", "Gas", "Gasoil"};
public SliderFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setWillNotDraw(false);
mTextViews = new TextView[mSize];
addSlider();
addTextViews();
}
private void addTextViews() {
for ( int i=0 ; i < mSize ; i++ ) {
TextView tv;
tv = new TextView(mContext);
tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
tv.setText(mTexts[i]);
mTextViews[i] = tv;
addView(tv);
}
}
private void addSlider() {
FrameLayout fl = new FrameLayout(mContext, null);
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
fl.setLayoutParams(params);
fl.setPadding(30, 30, 30, 0);
mSlider = new SeekBar(mContext, null);
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
//lp.setMargins(30, 30, 30, 0);
//mSlider.setPadding(30, 30, 30, 0);
mSlider.setLayoutParams(lp);
//mSlider.setMax(mSize-1);
mSlider.setThumbOffset(30);
//mSlider.setProgressDrawable(mContext.getResources().getDrawable(R.drawable.slider_track));
//mSlider.setThumb(mContext.getResources().getDrawable(R.drawable.slider_thumb));
mSlider.setOnSeekBarChangeListener(this);
//addView(mSlider);
fl.addView(mSlider);
addView(fl);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect rectf = new Rect();
mSlider.getLocalVisibleRect(rectf);
Log.d("WIDTH :",String.valueOf(rectf.width()));
Log.d("HEIGHT :",String.valueOf(rectf.height()));
Log.d("left :",String.valueOf(rectf.left));
Log.d("right :",String.valueOf(rectf.right));
Log.d("top :",String.valueOf(rectf.top));
Log.d("bottom :",String.valueOf(rectf.bottom));
int sliderWidth = mSlider.getWidth();
int padding = sliderWidth / (mSize-1);
for ( int i=0 ; i < mSize ; i++ ) {
TextView tv = mTextViews[i];
tv.setPadding(i* padding, 0, 0, 0);
}
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
Log.d("SEEK", "value: " + seekBar.getProgress());
seekBar.setProgress(50);
}
}
You're already overriding onDraw, why not just draw the text strings yourself? Rather than go through the overhead of adding TextViews and messing with the padding, just use canvas.drawText to physically draw the text strings in the right place.
You can specify the style and color of the text using a Paint object:
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(r.getColor(R.color.text_color));
textPaint.setFakeBoldText(true);
textPaint.setSubpixelText(true);
textPaint.setTextAlign(Align.LEFT);
And get the exact positioning by using the measureText method on that Paint object to find what width a particular string would be when drawn on a canvas:
textWidth = (int)textPaint.measureText(mTexts[i]);
Then you can iterate over your array of text strings and draw each string in the right place.
#Override
protected void onDraw(Canvas canvas) {
int myWidth = getMeasuredWidth()-LEFT_PADDING-RIGHT_PADDING;
int separation = myWidth / (mSize-1);
for (int i = 0; i++; i < mSize) {
int textWidth = (int)textPaint.measureText(mTexts[i]);
canvas.drawText(mTexts[i],
LEFT_PADDING+(i*separation)-(int)(textWidth/2),
TOP_PADDING,
textPaint);
}
}
You'll probably want to do the measurements in onMeasure instead of onDraw, and you should probably only measure the width of each string when you change the text or the paint, but I've put it all in one place to (hopefully) make it easier to follow.
Just a try. You could put your custom progressBar inside a FrameLayout then, inside this layout, you have to add three TextViews with fill_parent as width.
Then you can align the three texts in this way: left, center and right. Your texts shouldn't overwrite and you can adjust a little their position using margins.
You can use this... not exact what you looking for... but really easy to set up and customize...
You can set the TextViews to have:
android:layout_width="0dp"
android:layout_weight="1"
This will let the android framework take care of the placing of the TextViews and save you from manually calculating the padding of each one.