i am making an app to detect 91 categories with help of tensorflow api. I want to show the size of the detected object ie. height* width for that i made following changes in my detectoractivity.java
i added,
float width = location.width();
float height = location.height();
float area = width * height;
String s = Float.toString(area);
TextView editText = (TextView) findViewById(R.id.tv);
editText.setText(s);
at line 322.
but it gives an error saying
Only the original thread that created a view hierarchy can touch its views.*
full code,
dtetctoractivity.java
public class DetectorActivity extends CameraActivity implements OnImageAvailableListener {
private static final Logger LOGGER = new Logger();
// Configuration values for the prepackaged multibox model.
private static final int MB_INPUT_SIZE = 224;
private static final int MB_IMAGE_MEAN = 128;
private static final float MB_IMAGE_STD = 128;
private static final String MB_INPUT_NAME = "ResizeBilinear";
private static final String MB_OUTPUT_LOCATIONS_NAME = "
output_locations/Reshape";
private static final String MB_OUTPUT_SCORES_NAME =
"output_scores/Reshape";
private static final String MB_MODEL_FILE =
"file:///android_asset/multibox_model.pb";
private static final String MB_LOCATION_FILE =
"file:///android_asset/multibox_location_priors.txt";
private static final int TF_OD_API_INPUT_SIZE = 300;
private static final String TF_OD_API_MODEL_FILE =
"file:///android_asset/ssd_mobilenet_v1_android_export.pb";
private static final String TF_OD_API_LABELS_FILE =
"file:///android_asset/coco_labels_list.txt";
// Configuration values for tiny-yolo-voc. Note that the graph is not included with TensorFlow and
// must be manually placed in the assets/ directory by the user.
// Graphs and models downloaded from http://pjreddie.com/darknet/yolo/ may be converted e.g. via
// DarkFlow (https://github.com/thtrieu/darkflow). Sample command:
// ./flow --model cfg/tiny-yolo-voc.cfg --load bin/tiny-yolo-voc.weights -
-savepb --verbalise
private static final String YOLO_MODEL_FILE = "file:///android_asset/graph-
tiny-yolo-voc.pb";
private static final int YOLO_INPUT_SIZE = 416;
private static final String YOLO_INPUT_NAME = "input";
private static final String YOLO_OUTPUT_NAMES = "output";
private static final int YOLO_BLOCK_SIZE = 32;
// Which detection model to use: by default uses Tensorflow Object Detection API frozen
// checkpoints. Optionally use legacy Multibox (trained using an older
version of the API)
// or YOLO.
private enum DetectorMode {
TF_OD_API, MULTIBOX, YOLO;
}
private static final DetectorMode MODE = DetectorMode.TF_OD_API;
// Minimum detection confidence to track a detection.
private static final float MINIMUM_CONFIDENCE_TF_OD_API = 0.6f;
private static final float MINIMUM_CONFIDENCE_MULTIBOX = 0.1f;
private static final float MINIMUM_CONFIDENCE_YOLO = 0.25f;
private static final boolean MAINTAIN_ASPECT = MODE == DetectorMode.YOLO;
private static final Size DESIRED_PREVIEW_SIZE = new Size(640, 480);
private static final boolean SAVE_PREVIEW_BITMAP = false;
private static final float TEXT_SIZE_DIP = 10;
private Integer sensorOrientation;
private Classifier detector;
private long lastProcessingTimeMs;
private Bitmap rgbFrameBitmap = null;
private Bitmap croppedBitmap = null;
private Bitmap cropCopyBitmap = null;
private boolean computingDetection = false;
private long timestamp = 0;
private Matrix frameToCropTransform;
private Matrix cropToFrameTransform;
private MultiBoxTracker tracker;
private byte[] luminanceCopy;
private BorderedText borderedText;
#Override
public void onPreviewSizeChosen(final Size size, final int rotation) {
final float textSizePx =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, TEXT_SIZE_DIP,
getResources().getDisplayMetrics());
borderedText = new BorderedText(textSizePx);
borderedText.setTypeface(Typeface.MONOSPACE);
tracker = new MultiBoxTracker(this);
int cropSize = TF_OD_API_INPUT_SIZE;
if (MODE == DetectorMode.YOLO) {
detector =
TensorFlowYoloDetector.create(
getAssets(),
YOLO_MODEL_FILE,
YOLO_INPUT_SIZE,
YOLO_INPUT_NAME,
YOLO_OUTPUT_NAMES,
YOLO_BLOCK_SIZE);
cropSize = YOLO_INPUT_SIZE;
} else if (MODE == DetectorMode.MULTIBOX) {
detector =
TensorFlowMultiBoxDetector.create(
getAssets(),
MB_MODEL_FILE,
MB_LOCATION_FILE,
MB_IMAGE_MEAN,
MB_IMAGE_STD,
MB_INPUT_NAME,
MB_OUTPUT_LOCATIONS_NAME,
MB_OUTPUT_SCORES_NAME);
cropSize = MB_INPUT_SIZE;
} else {
try {
detector = TensorFlowObjectDetectionAPIModel.create(
getAssets(), TF_OD_API_MODEL_FILE, TF_OD_API_LABELS_FILE, TF_OD_API_INPUT_SIZE);
cropSize = TF_OD_API_INPUT_SIZE;
} catch (final IOException e) {
LOGGER.e("Exception initializing classifier!", e);
Toast toast =
Toast.makeText(
getApplicationContext(), "Classifier could not be initialized", Toast.LENGTH_SHORT);
toast.show();
finish();
}
}
previewWidth = size.getWidth();
previewHeight = size.getHeight();
sensorOrientation = rotation - getScreenOrientation();
LOGGER.i("Camera orientation relative to screen canvas: %d", sensorOrientation);
LOGGER.i("Initializing at size %dx%d", previewWidth, previewHeight);
rgbFrameBitmap = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888);
croppedBitmap = Bitmap.createBitmap(cropSize, cropSize, Config.ARGB_8888);
frameToCropTransform =
ImageUtils.getTransformationMatrix(
previewWidth, previewHeight,
cropSize, cropSize,
sensorOrientation, MAINTAIN_ASPECT);
cropToFrameTransform = new Matrix();
frameToCropTransform.invert(cropToFrameTransform);
trackingOverlay = (OverlayView) findViewById(R.id.tracking_overlay);
trackingOverlay.addCallback(
new DrawCallback() {
#Override
public void drawCallback(final Canvas canvas) {
tracker.draw(canvas);
if (isDebug()) {
tracker.drawDebug(canvas);
}
}
});
addCallback(
new DrawCallback() {
#Override
public void drawCallback(final Canvas canvas) {
if (!isDebug()) {
return;
}
final Bitmap copy = cropCopyBitmap;
if (copy == null) {
return;
}
final int backgroundColor = Color.argb(100, 0, 0, 0);
canvas.drawColor(backgroundColor);
final Matrix matrix = new Matrix();
final float scaleFactor = 2;
matrix.postScale(scaleFactor, scaleFactor);
matrix.postTranslate(
canvas.getWidth() - copy.getWidth() * scaleFactor,
canvas.getHeight() - copy.getHeight() * scaleFactor);
canvas.drawBitmap(copy, matrix, new Paint());
final Vector<String> lines = new Vector<String>();
if (detector != null) {
final String statString = detector.getStatString();
final String[] statLines = statString.split("\n");
for (final String line : statLines) {
lines.add(line);
}
}
lines.add("");
lines.add("Frame: " + previewWidth + "x" + previewHeight);
lines.add("Crop: " + copy.getWidth() + "x" + copy.getHeight());
lines.add("View: " + canvas.getWidth() + "x" + canvas.getHeight());
lines.add("Rotation: " + sensorOrientation);
lines.add("Inference time: " + lastProcessingTimeMs + "ms");
borderedText.drawLines(canvas, 10, canvas.getHeight() - 10, lines);
}
});
}
OverlayView trackingOverlay;
#Override
protected void processImage() {
++timestamp;
final long currTimestamp = timestamp;
byte[] originalLuminance = getLuminance();
tracker.onFrame(
previewWidth,
previewHeight,
getLuminanceStride(),
sensorOrientation,
originalLuminance,
timestamp);
trackingOverlay.postInvalidate();
// No mutex needed as this method is not reentrant.
if (computingDetection) {
readyForNextImage();
return;
}
computingDetection = true;
LOGGER.i("Preparing image " + currTimestamp + " for detection in bg thread.");
rgbFrameBitmap.setPixels(getRgbBytes(), 0, previewWidth, 0, 0, previewWidth, previewHeight);
if (luminanceCopy == null) {
luminanceCopy = new byte[originalLuminance.length];
}
System.arraycopy(originalLuminance, 0, luminanceCopy, 0, originalLuminance.length);
readyForNextImage();
final Canvas canvas = new Canvas(croppedBitmap);
canvas.drawBitmap(rgbFrameBitmap, frameToCropTransform, null);
// For examining the actual TF input.
if (SAVE_PREVIEW_BITMAP) {
ImageUtils.saveBitmap(croppedBitmap);
}
runInBackground(
new Runnable() {
#Override
public void run() {
LOGGER.i("Running detection on image " + currTimestamp);
final long startTime = SystemClock.uptimeMillis();
final List<Classifier.Recognition> results = detector.recognizeImage(croppedBitmap);
lastProcessingTimeMs = SystemClock.uptimeMillis() - startTime;
cropCopyBitmap = Bitmap.createBitmap(croppedBitmap);
final Canvas canvas = new Canvas(cropCopyBitmap);
final Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(2.0f);
float minimumConfidence = MINIMUM_CONFIDENCE_TF_OD_API;
switch (MODE) {
case TF_OD_API:
minimumConfidence = MINIMUM_CONFIDENCE_TF_OD_API;
break;
case MULTIBOX:
minimumConfidence = MINIMUM_CONFIDENCE_MULTIBOX;
break;
case YOLO:
minimumConfidence = MINIMUM_CONFIDENCE_YOLO;
break;
}
final List<Classifier.Recognition> mappedRecognitions =
new LinkedList<Classifier.Recognition>();
for (final Classifier.Recognition result : results) {
final RectF location = result.getLocation();
if (location != null && result.getConfidence() >= minimumConfidence) {
canvas.drawRect(location, paint);
float width = location.width();
float height = location.height();
float area = width * height;
String s = Float.toString(area);
TextView editText = (TextView) findViewById(R.id.tv);
editText.setText(s);
cropToFrameTransform.mapRect(location);
result.setLocation(location);
mappedRecognitions.add(result);
}
}
tracker.trackResults(mappedRecognitions, luminanceCopy, currTimestamp);
trackingOverlay.postInvalidate();
requestRender();
computingDetection = false;
}
});
}
#Override
protected int getLayoutId() {
return R.layout.camera_connection_fragment_tracking;
}
#Override
protected Size getDesiredPreviewFrameSize() {
return DESIRED_PREVIEW_SIZE;
}
#Override
public void onSetDebug(final boolean debug) {
detector.enableStatLogging(debug);
}
}
The problem here is that you initiated the textview inside the wrong place.Beside that, you should never put this line :
TextView editText = (TextView) findViewById(R.id.tv);
inside a loop. Make your variables global : editText and width then you can implement a button and in the onClick method a toast will be shown with the last value given from the for loop.
Related
I'm writing a javafx image generator for .STL files. I'm using StlMeshImporter to import the STL file. However, when I import files in my javafx scene and try to take a snapshot, I get different result for each file because they are not center in the scene.
I would like to be able to scale it or center it, in the scene dynamically to take a snapshot. Is there a way to get the width and height of the object so I could set a scale factor, and offset automatically?
Here is my class:
public class STLImageGenerator extends Application {
private static final String MESH_FILENAME
= "./9sk02_flex_r02.stl";
private static final int VIEWPORT_SIZE = 800;
private static final double MODEL_SCALE_FACTOR = 3;
private static final double MODEL_X_OFFSET = 0;
private static final double MODEL_Y_OFFSET = 0;
private static final double MODEL_Z_OFFSET =0 ;
// private static final int VIEWPORT_SIZE = 4096;
private static final Color lightColor = Color.rgb(204, 204, 204);
private static final Color jewelColor = Color.rgb(0, 100, 204);
final static int CANVAS_WIDTH = 512;
final static int CANVAS_HEIGHT = 512;
private Group root;
private PointLight pointLight;
Canvas canvas = null;
PerspectiveCamera perspectiveCamera = null;
static MeshView[] loadMeshViews() {
File file = new File(MESH_FILENAME);
StlMeshImporter importer = new StlMeshImporter();
importer.read(file);
Mesh mesh = importer.getImport();
return new MeshView[]{new MeshView(mesh)};
}
private Group buildScene() {
MeshView[] meshViews = loadMeshViews();
System.out.println("MESHVIEWS: " + meshViews.length);
for (int i = 0; i < meshViews.length; i++) {
System.out.println("meshViews[i].getLayoutX():"+meshViews[i].getLayoutX());
meshViews[i].setScaleX(MODEL_SCALE_FACTOR);
meshViews[i].setScaleY(MODEL_SCALE_FACTOR);
meshViews[i].setScaleZ(MODEL_SCALE_FACTOR);
meshViews[i].setTranslateX((VIEWPORT_SIZE / 2) + MODEL_X_OFFSET-MODEL_SCALE_FACTOR);
meshViews[i].setTranslateY((VIEWPORT_SIZE / 2) + MODEL_Y_OFFSET-MODEL_SCALE_FACTOR);
meshViews[i].setTranslateZ((VIEWPORT_SIZE / 2) + MODEL_Z_OFFSET);
PhongMaterial sample = new PhongMaterial(jewelColor);
sample.setSpecularColor(lightColor);
sample.setSpecularPower(16);
meshViews[i].setMaterial(sample);
//meshViews[i].getTransforms().setAll(new Rotate(38, Rotate.Z_AXIS), new Rotate(20, Rotate.X_AXIS));
}
pointLight = new PointLight(lightColor);
pointLight.setTranslateX(VIEWPORT_SIZE * 3 / 4);
pointLight.setTranslateY(VIEWPORT_SIZE / 2);
pointLight.setTranslateZ(VIEWPORT_SIZE / 2);
PointLight pointLight2 = new PointLight(lightColor);
pointLight2.setTranslateX(VIEWPORT_SIZE * 1 / 4);
pointLight2.setTranslateY(VIEWPORT_SIZE * 3 / 4);
pointLight2.setTranslateZ(VIEWPORT_SIZE * 3 / 4);
PointLight pointLight3 = new PointLight(lightColor);
pointLight3.setTranslateX(VIEWPORT_SIZE * 5 / 8);
pointLight3.setTranslateY(VIEWPORT_SIZE / 2);
pointLight3.setTranslateZ(0);
Color ambientColor = Color.rgb(80, 80, 80, 0);
AmbientLight ambient = new AmbientLight(ambientColor);
root = new Group(meshViews);
root.getChildren().add(pointLight);
root.getChildren().add(pointLight2);
root.getChildren().add(pointLight3);
root.getChildren().add(ambient);
//root.setAutoSizeChildren(true);
return root;
}
private PerspectiveCamera addCamera(Scene scene) {
perspectiveCamera = new PerspectiveCamera();
System.out.println("Near Clip: " + perspectiveCamera.getNearClip());
System.out.println("Far Clip: " + perspectiveCamera.getFarClip());
System.out.println("FOV: " + perspectiveCamera.getFieldOfView());
perspectiveCamera.setFieldOfView(5);
scene.setCamera(perspectiveCamera);
return perspectiveCamera;
}
#Override
public void start(Stage primaryStage) {
//canvas = new Canvas(VIEWPORT_SIZE, VIEWPORT_SIZE);
Group group = buildScene();
Scene scene = new Scene(group, VIEWPORT_SIZE, VIEWPORT_SIZE, true, SceneAntialiasing.BALANCED);
scene.setFill(Color.rgb(255, 255, 255));
group.setAutoSizeChildren(true);
addCamera(scene);
//root.getChildren().add(canvas);
primaryStage.setMaxHeight(CANVAS_HEIGHT);
primaryStage.setMaxWidth(CANVAS_WIDTH);
String fname = MESH_FILENAME.substring(0, MESH_FILENAME.length() - 3) + "png";
File file = new File(fname);
primaryStage.setTitle("Jewel Viewer");
primaryStage.setScene(scene);
primaryStage.show();
try {
SnapshotParameters s = new SnapshotParameters();
// s.setCamera(perspectiveCamera);
// s.setViewport(Rectangle2D.EMPTY);
WritableImage wim = new WritableImage(1024, 1024);
scene.snapshot(wim);
// WritableImage writableImage = root.snapshot(new SnapshotParameters(), null);
RenderedImage renderedImage = SwingFXUtils.fromFXImage(wim, null);
ImageIO.write(renderedImage, "png", file);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.setProperty("prism.dirtyopts", "false");
Platform.setImplicitExit(false);
launch(args);
}
Hi I've implemented a toggle button for sound on my SettingsMenu, it works within this screen however when I go back to my main menu the functionality is lost and it resets back to its initial state. Any ideas how I can make it so that once it is clicked, it keeps this selection throughout every screen. I will show you the toggle button class and the settings class in which it is implemented. Thanks.
package uk.ac.qub.eeecs.game.cardDemo;
public class ToggleButtonSound extends GameObject {
protected enum ButtonState {
ON, OFF
}
private ButtonState mButtonState = ButtonState.OFF;
private SoundManager sm;
protected Bitmap mOffBitmap;
protected Bitmap mOnBitmap;
protected Bitmap mOnHoverBitmap;
protected Bitmap mOffHoverBitmap;
private Game mGame;
public boolean mMusicMuted = false;
public boolean mSoundMuted = false;
private MusicManager mMusicManager;
public ToggleButtonSound(float x, float y, float width, float height,
String offBitmap,
String onBitmap,
// String OffHoverBitmap,
//String OnHoverBitmap,
GameScreen gameScreen,
Game game) {
super(x, y, width, height,
gameScreen.getGame().getAssetManager().getBitmap(offBitmap), gameScreen);
mGame = game;
AssetStore assetStore = gameScreen.getGame().getAssetManager();
mOffBitmap = assetStore.getBitmap(offBitmap);
// mOffHoverBitmap = assetStore.getBitmap(offBitmap);
mOnBitmap = assetStore.getBitmap(onBitmap);
//mOnHoverBitmap = assetStore.getBitmap(onBitmap);
sm = new SoundManager(mGame);
mMusicManager = new MusicManager(mGame);
}
private boolean mPushTriggered;
private boolean mIsPushed;
/**
* Update the button
*
* #param elapsedTime Elapsed time information
*/
public void update(ElapsedTime elapsedTime) {
// Consider any touch events occurring in this update
Input input = mGame.getInput();
BoundingBox bound = getBound();
// Check for a press release on this button
for (TouchEvent touchEvent : input.getTouchEvents()) {
if (touchEvent.type == TouchEvent.TOUCH_UP
&& bound.contains(touchEvent.x, touchEvent.y)) {
// A touch up has occured in this control
if (mButtonState == ButtonState.OFF) {
setToggled(true);
} else {
setToggled(false);
}
return;
}
}
for (int idx = 0; idx < TouchHandler.MAX_TOUCHPOINTS; idx++) {
if (input.existsTouch(idx)) {
if (bound.contains(input.getTouchX(idx), input.getTouchY(idx))) {
if (!mIsPushed) {
mPushTriggered = true;
if (mOnHoverBitmap != null && mOffHoverBitmap != null)
mBitmap = mButtonState == ButtonState.ON ? mOnHoverBitmap : mOffHoverBitmap;
mIsPushed = true;
}
return;
}
}
}
if (mIsPushed) {
mBitmap = mButtonState == ButtonState.ON ? mOnBitmap : mOffBitmap;
mIsPushed = false;
mPushTriggered = false;
}
}
public boolean isToggledOn() {
return mButtonState == ButtonState.ON;
}
public void setToggled(boolean on) {
if (on) {
mButtonState = ButtonState.ON;
mBitmap = mOnBitmap;
} else {
mButtonState = ButtonState.OFF;
mBitmap = mOffBitmap;
}
}
#Override
public void draw(ElapsedTime elapsedTime, IGraphics2D graphics2D,
LayerViewport layerViewport, ScreenViewport screenViewport) {
// Assumed to be in screen space so just draw the whole thing
drawScreenRect.set((int) (position.x - mBound.halfWidth),
(int) (position.y - mBound.halfWidth),
(int) (position.x + mBound.halfWidth),
(int) (position.y + mBound.halfHeight));
graphics2D.drawBitmap(mBitmap, null, drawScreenRect, null);
}
}
Settings menu
public class SettingsMenu extends GameScreen {
private ToggleButtonSound mToggleButtonSound;
public SettingsMenu(Game game) {
super("Settings Menu", game);
mSoundManager = new SoundManager(game);
mMenuScreen = new MenuScreen(game);
music = new MusicManager(game);
AssetStore assetManager = mGame.getAssetManager();
assetManager.loadAndAddBitmap("offswitch", "img/offswitch.png");
assetManager.loadAndAddBitmap("onswitch", "img/onswitch.png");
assetManager.loadAndAddBitmap("SoundOn", "img/Soundon.png");
assetManager.loadAndAddBitmap("SoundOff", "img/Soundoff.png");
assetManager.loadAndAddBitmap("SettingsBackground", "img/settingsbackground.png");
//Load in sound
assetManager.loadAndAddSound("mouseClick", "Sounds/clicksound.wav");
assetManager.loadAndAddMusic("BackgroundMusic", "Sounds/MenuScreenBackgroundMusic.mp3");
//initialise sound
int spacingX = mGame.getScreenWidth() / 3;
int spacingY = mGame.getScreenHeight() / 9;
mPlayButtonBound = new Rect(spacingX, 3 * spacingY, 2 * spacingX, 4 * spacingY);
mInventoryButtonBound = new Rect(spacingX, 5 * spacingY, 2 * spacingX, 6 * spacingY);
soundButtonBound = new Rect(game.getScreenWidth() / 100, game.getScreenWidth() / 100, game.getScreenWidth() / 10, game.getScreenWidth() / 10);
mSettingsBackground = new Rect(1, 1, game.getScreenWidth(), game.getScreenHeight());
mLayerViewport = new LayerViewport(0, 0, game.getScreenWidth(), game.getScreenHeight());
mScreenViewport = new ScreenViewport(0, 0, game.getScreenWidth(), game.getScreenHeight());
int toggleHeight = mGame.getScreenHeight()/3;
mToggleButtonMusic = new ToggleButtonMusic(game.getScreenWidth() / 100, game.getScreenWidth() / 200, game.getScreenWidth() / 10, game.getScreenWidth() / 20, "onswitch","offswitch","onswitch","offswitch", this, mGame);
mToggleButtonSound = new ToggleButtonSound(game.getScreenWidth() / 100, game.getScreenWidth() / 200, game.getScreenWidth() / 10, game.getScreenWidth() / 20, "onswitch","offswitch", this, mGame);
mToggleButtonMusic.setPosition(game.getScreenWidth()/2,game.getScreenHeight()/3);
mToggleButtonSound.setPosition(game.getScreenWidth()/2, toggleHeight*2);
//toggleB.getBitmap();
//toggleB.getBound();
}
private boolean mIsPushed;
#Override
public void update(ElapsedTime elapsedTime) {
music.isPlaying1();
//mToggleButtonSound.setToggled(soundMuted);
mToggleButtonMusic.update(elapsedTime);
mToggleButtonSound.update(elapsedTime);
Input input = mGame.getInput();
List<TouchEvent> touchEvents = input.getTouchEvents();
if (touchEvents.size() > 0) {
TouchEvent touchEvent = touchEvents.get(0);
if (touchEvent.type == TouchEvent.TOUCH_UP) {
if ((soundButtonBound.contains((int) touchEvent.x, (int) touchEvent.y))) {
mGame.getScreenManager().removeScreen("Settings Menu");
mMenuScreen = new MenuScreen(mGame);
mGame.getScreenManager().addScreen(mMenuScreen);
}
}
}
}
#Override
public void draw(ElapsedTime elapsedTime, IGraphics2D graphics2D) {
graphics2D.drawBitmap(mGame.getAssetManager().getBitmap("SettingsBackground"), null, mSettingsBackground, null);
mToggleButtonMusic.draw(elapsedTime,graphics2D,mLayerViewport, mScreenViewport);
mToggleButtonSound.draw(elapsedTime,graphics2D,mLayerViewport, mScreenViewport);
graphics2D.drawBitmap(mGame.getAssetManager().getBitmap("SoundOn"), null, soundButtonBound, null);
}
#Override
public boolean onBackPressed() {
return true;
}
}
I recently got into LibGDX using the book "LibGDX Game Development By Example" (Pretty good one btw) and have been playing around with the tutorial projects for the last month.
One of these games is a FlappyBird-clone (of course it is) and I decided to add features, change sprites etc.
Now the problem is that the normal obstacle graphics (flowers) don't fit the new theme and need to be exchanged.
Doing so results in jiggering graphics for the new sprites.
I should point out that the code used to visualize these obstacles has not changed at all, simply exchanging the sprites causes this problem.
I tried a lot of different sprites and all that are not identical to the flowers seem to have this problem.
So whatever is the cause, the old flower sprites are unaffected, every other sprite is.
On to the code (Removed some Getters/Setters and other unrelated methods)
The Flower/Obstacle Class:
public class Flower
{
private static final float COLLISION_RECTANGLE_WIDTH = 13f;
private static final float COLLISION_RECTANGLE_HEIGHT = 447f;
private static final float COLLISION_CIRCLE_RADIUS = 33f;
private float x = 0;
private float y = 0;
private static final float MAX_SPEED_PER_SECOND = 100f;
public static final float WIDTH = COLLISION_CIRCLE_RADIUS * 2;
private static final float HEIGHT_OFFSET = -400.0f;
private static final float DISTANCE_BETWEEN_FLOOR_AND_CEILING = 225.0f;
private final Circle floorCollisionCircle;
private final Rectangle floorCollisionRectangle;
private final Circle ceilingCollisionCircle;
private final Rectangle ceilingCollisionRectangle;
private boolean pointClaimed = false;
private final TextureRegion floorTexture;
private final TextureRegion ceilingTexture;
float textureX,textureY;
public Flower(TextureRegion floorTexture, TextureRegion ceilingTexture)
{
this.floorTexture = floorTexture;
this.ceilingTexture = ceilingTexture;
this.y = MathUtils.random(HEIGHT_OFFSET);
this.floorCollisionRectangle = new Rectangle(x,y,COLLISION_RECTANGLE_WIDTH,COLLISION_RECTANGLE_HEIGHT);
this.floorCollisionCircle = new Circle(x + floorCollisionRectangle.width / 2, y + floorCollisionRectangle.height, COLLISION_CIRCLE_RADIUS);
this.ceilingCollisionRectangle = new Rectangle(x,floorCollisionCircle.y + DISTANCE_BETWEEN_FLOOR_AND_CEILING,COLLISION_RECTANGLE_WIDTH,
COLLISION_RECTANGLE_HEIGHT);
this.ceilingCollisionCircle = new Circle(x + ceilingCollisionRectangle.width / 2, ceilingCollisionRectangle.y, COLLISION_CIRCLE_RADIUS);
}
public void update(float delta)
{
setPosition(x - (MAX_SPEED_PER_SECOND * delta));
}
public void setPosition(float x)
{
this.x = x;
updateCollisionCircle();
updateCollisionRectangle();
}
private void updateCollisionCircle()
{
floorCollisionCircle.setX(x + floorCollisionRectangle.width / 2);
ceilingCollisionCircle.setX(x + ceilingCollisionRectangle.width / 2);
}
private void updateCollisionRectangle()
{
floorCollisionRectangle.setX(x);
ceilingCollisionRectangle.setX(x);
}
public void draw(SpriteBatch batch)
{
drawFloorFlower(batch);
drawCeilingFlower(batch);
}
private void drawFloorFlower(SpriteBatch batch)
{
textureX = floorCollisionCircle.x - floorTexture.getRegionWidth() / 2;
textureY = floorCollisionRectangle.getY() + COLLISION_CIRCLE_RADIUS;
batch.draw(floorTexture,textureX,textureY);
}
private void drawCeilingFlower(SpriteBatch batch)
{
textureX = ceilingCollisionCircle.x - ceilingTexture.getRegionWidth() / 2;
textureY = ceilingCollisionRectangle.getY() - COLLISION_CIRCLE_RADIUS;
batch.draw(ceilingTexture,textureX, textureY);
}
}
And the GameScreen/Main Class:
public class GameScreen extends ScreenAdapter
{
private static final float WORLD_WIDTH = 480;
private static final float WORLD_HEIGHT = 640;
private java.util.prefs.Preferences prefs;
private int highscore;
FlappeeBeeGame flappeeBeeGame;
private ShapeRenderer shapeRenderer;
private Viewport viewport;
private Camera camera;
private SpriteBatch batch;
private Flappee flappee;
private Flower flower;
private Array<Flower> flowers = new Array<Flower>();
private static final float GAP_BETWEEN_FLOWERS = 200.0f;
private boolean gameOver = false;
int score = 0;
BitmapFont bitmapFont;
GlyphLayout glyphLayout;
private TextureRegion background;
private TextureRegion flowerBottom;
private TextureRegion flowerTop;
private TextureRegion bee;
private TextureRegion smallCloud;
private TextureRegion lowCloud;
private Music music_background;
TextureAtlas textureAtlas;
List<Cloud> activeClouds = new ArrayList<Cloud>();
List<Cloud> cloudBarriers = new ArrayList<Cloud>();
private float cloud_minScale = 0.6f;
private float cloud_maxScale = 1.0f;
private float cloud_minY, cloud_maxY;
private float cloud_minDis, cloud_maxDis;
private float cloud_minSpeed = 17.0f;
private float cloud_maxSpeed = 27.0f;
private final float barrierCloud_speed = 150.0f;
private boolean inputBlocked = false;
private float blockTime = 0.5f;
private float remainingblockTime = blockTime;
public GameScreen(FlappeeBeeGame fpg)
{
flappeeBeeGame = fpg;
flappeeBeeGame.getAssetManager().load("assets/flappee_bee_assets.atlas",TextureAtlas.class);
flappeeBeeGame.getAssetManager().finishLoading();
textureAtlas = flappeeBeeGame.getAssetManager().get("assets/flappee_bee_assets.atlas");
prefs = java.util.prefs.Preferences.userRoot().node(this.getClass().getName());
highscore = prefs.getInt("highscore",0);
music_background = Gdx.audio.newMusic(Gdx.files.internal("assets/backgroundmusic.ogg"));
music_background.setLooping(true);
music_background.setVolume(0.5f);
music_background.play();
}
private void createNewFlower()
{
Flower newFlower = new Flower(flowerBottom,flowerTop);
newFlower.setPosition(WORLD_WIDTH + Flower.WIDTH);
flowers.add(newFlower);
}
private void checkIfNewFlowerIsNeeded()
{
if(flowers.size == 0)
{
createNewFlower();
}
else
{
Flower flower = flowers.peek();
if(flower.getX() < WORLD_WIDTH - GAP_BETWEEN_FLOWERS)
{
createNewFlower();
}
}
}
private void drawFlowers()
{
for(Flower flower : flowers)
{
flower.draw(batch);
}
}
private void removeFlowersIfPassed()
{
if(flowers.size > 0)
{
Flower firstFlower = flowers.first();
if(firstFlower.getX() < -Flower.WIDTH)
{
flowers.removeValue(firstFlower,true);
}
}
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
viewport.update(width,height);
}
#Override
public void show() {
super.show();
camera = new OrthographicCamera();
camera.position.set(WORLD_WIDTH / 2, WORLD_HEIGHT / 2, 0);
camera.update();
viewport = new FitViewport(WORLD_WIDTH,WORLD_HEIGHT, camera);
shapeRenderer = new ShapeRenderer();
batch = new SpriteBatch();
bitmapFont = new BitmapFont(Gdx.files.internal("assets/score_new.fnt"));
glyphLayout = new GlyphLayout();
background = textureAtlas.findRegion("bg");
flowerBottom = textureAtlas.findRegion("pipeBottom");
flowerTop = textureAtlas.findRegion("flowerTop");
bee = textureAtlas.findRegion("bee");
smallCloud = textureAtlas.findRegion("smallCloud");
lowCloud = textureAtlas.findRegion("lowerCloud");
flower = new Flower(flowerBottom,flowerTop);
flappee = new Flappee(bee,textureAtlas);
flappee.setPosition(WORLD_WIDTH/4,WORLD_HEIGHT/2);
cloud_minDis = smallCloud.getRegionWidth() / 4;
cloud_maxDis = smallCloud.getRegionWidth();
cloud_maxY = viewport.getWorldHeight() - smallCloud.getRegionHeight()/2;
cloud_minY = viewport.getWorldHeight() - smallCloud.getRegionHeight() * 2;
Cloud a = generateCloud(null);
Cloud b = generateCloud(a);
Cloud c = generateCloud(b);
Cloud d = generateCloud(c);
Cloud e = generateCloud(d);
activeClouds.add(a);
activeClouds.add(b);
activeClouds.add(c);
activeClouds.add(d);
activeClouds.add(e);
a = new Cloud(lowCloud,batch,0,0 - lowCloud.getRegionHeight()/4,barrierCloud_speed,1.0f);
b = new Cloud(lowCloud,batch,lowCloud.getRegionWidth(),0 - lowCloud.getRegionHeight()/4,barrierCloud_speed,1.0f);
c = new Cloud(lowCloud,batch,lowCloud.getRegionWidth()*2,0 - lowCloud.getRegionHeight()/4,barrierCloud_speed,1.0f);
cloudBarriers.add(a);
cloudBarriers.add(b);
cloudBarriers.add(c);
}
public Cloud generateCloud(Cloud formerCloud)
{
Cloud d;
if(formerCloud == null)
{
float randomVal = (float)Math.random();
d = new Cloud(smallCloud,batch,viewport.getWorldWidth(),
(float)Math.random() * (cloud_maxY - cloud_minY) + cloud_minY,
randomVal * (cloud_maxSpeed-cloud_minSpeed) + cloud_minSpeed,
randomVal * (cloud_maxScale-cloud_minScale) + cloud_minScale);
return d;
}
float randomVal = (float)Math.random();
d = new Cloud(smallCloud,batch,formerCloud.getPosX() + ((float)
Math.random() * (cloud_maxDis - cloud_minDis) + cloud_minDis),(float)Math.random() * (cloud_maxY - cloud_minY) + cloud_minY,
randomVal * (cloud_maxSpeed-cloud_minSpeed) + cloud_minSpeed,
randomVal * (cloud_maxScale-cloud_minScale) + cloud_minScale);
return d;
}
#Override
public void render(float delta) {
super.render(delta);
clearScreen();
shapeRenderer.setProjectionMatrix(camera.projection);
shapeRenderer.setTransformMatrix(camera.view);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.end();
draw(delta);
update(delta);
}
private void draw(float delta)
{
batch.setProjectionMatrix(camera.projection);
batch.setTransformMatrix(camera.view);
batch.begin();
batch.draw(background,0,0);
drawClouds(delta);
drawScore();
drawFlowers();
//drawDebug();
if(!gameOver)
{
flappee.draw(batch,delta);
}
drawBarrierClouds(delta);
batch.end();
}
private void updateClouds(float delta)
{
boolean move = false;
Cloud tmp = null;
for(Cloud c : cloudBarriers)
{
c.update(delta);
if(c.getPosX() <= -lowCloud.getRegionWidth())
{
tmp = c;
move = true;
}
}
if(move)
{
float positionX = cloudBarriers.get(cloudBarriers.size()-1).getPosX() + lowCloud.getRegionWidth();
if(positionX < viewport.getWorldWidth())
{
positionX = viewport.getWorldWidth();
}
tmp.setPos(positionX,0 - lowCloud.getRegionHeight()/4);
cloudBarriers.remove(tmp);
cloudBarriers.add(tmp);
tmp = null;
move = false;
}
for(Cloud c : activeClouds)
{
c.update(delta);
if(c.getPosX() <= -smallCloud.getRegionWidth())
{
tmp = c;
move = true;
}
}
if(move)
{
float randomVal = (float)Math.random();
float positionX = activeClouds.get(activeClouds.size()-1).getPosX() + ((float)
Math.random() * (cloud_maxDis - cloud_minDis) + cloud_minDis);
if(positionX < viewport.getWorldWidth())
{
positionX = viewport.getWorldWidth();
}
tmp.setPos(positionX,(float)Math.random() * (cloud_maxY - cloud_minY) + cloud_minY);
tmp.setSpeed(randomVal * (cloud_maxSpeed - cloud_minSpeed) + cloud_minSpeed);
tmp.setScale(randomVal * (cloud_maxScale - cloud_minScale) + cloud_minScale);
activeClouds.remove(tmp);
activeClouds.add(tmp);
move = false;
tmp = null;
}
}
private void drawBarrierClouds(float delta)
{
for(Cloud c : cloudBarriers)
{
c.render();
}
}
private void drawClouds(float delta)
{
for(Cloud c : activeClouds)
{
c.render();
}
}
private void clearScreen()
{
Gdx.gl.glClearColor(Color.BLACK.r,Color.BLACK.g,Color.BLACK.b, Color.BLACK.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
private void blockFlappeeLeavingTheWorld()
{
flappee.setPosition(flappee.getX(), MathUtils.clamp(flappee.getY(),0,WORLD_HEIGHT));
}
private void updateFlowers(float delta)
{
for(Flower flower : flowers)
{
flower.update(delta);
}
checkIfNewFlowerIsNeeded();
removeFlowersIfPassed();
}
private void update(float delta)
{
updateClouds(delta);
if(!gameOver) {
updateFlappee(delta);
updateFlowers(delta);
updateScore();
if (checkForCollision())
{
gameOver = true;
inputBlocked = true;
remainingblockTime = blockTime;
restart();
}
}
else
{
if((Gdx.input.isKeyJustPressed(Input.Keys.SPACE) || Gdx.input.isButtonPressed(Input.Buttons.LEFT)) && !inputBlocked)
{
gameOver = false;
score = 0;
}
if(inputBlocked)
{
if(remainingblockTime > 0)
{
remainingblockTime -= delta;
}
else
{
inputBlocked = false;
remainingblockTime = blockTime;
}
}
}
}
private void restart()
{
flappee.setPosition(WORLD_WIDTH / 4, WORLD_HEIGHT / 2);
flowers.clear();
}
#Override
public void dispose() {
super.dispose();
}
private boolean checkForCollision()
{
for(Flower flower : flowers)
{
if(flower.isFlappeeColliding(flappee))
{
if(score > highscore)
{
highscore = score;
prefs.putInt("highscore",highscore);
inputBlocked = true;
remainingblockTime = blockTime;
}
return true;
}
}
return false;
}
}
I'd love to give you a runnable jar but I've got some problems building a working version. Let's just say a jar is out of the question for now.
What I can give you are screenshots:
Jiggering Sprite View
Functional Flower Sprite View
The first image shows the problem: The new sprites (which are just debug) become edgy like the top of the sprite can't compete with the speed of its lower half.
The second image shows the old sprites for comparison: They don't show any of this behaviour, even if they are longer than the one on the screenshot.
So what do you people think?
What causes this behaviour and how should I fix it?
Thanks in advance for any help, I appreciate it :)
Greetz!
EDIT:
I kind of fixed it.
When switching to another computer and running the game the issue didn't come up anymore.
Specifically I went from Debian to Windows 10 and from NVIDIA Optimus to a standard desktop AMD-Card.
If you should encounter this problem try another PC with a different OS and/or GPU.
Sadly (if you were to google this question) I can't tell you how to solve it on the first machine or what exactly caused it, but at least it shouldn't come up on anyone else's computer when you send them your project.
I have a GameScene in which I used ZoomCamera, a background and a few "viruses".
The problem is that when I pinchzoom in or out the background also scales, I do not want that, please help.
http://puu.sh/9XPUl/c6725806ae.png
http://puu.sh/9XQ5g/609d77e962.png
public class GameScene extends BaseScene implements IScrollDetectorListener, IPinchZoomDetectorListener, IOnSceneTouchListener {
private static final String TAG_ENTITY = "entity";
private static final String TAG_ENTITY_ATTRIBUTE_X = "x";
private static final String TAG_ENTITY_ATTRIBUTE_Y = "y";
private static final String TAG_ENTITY_ATTRIBUTE_TYPE = "type";
private ZoomCamera mZoomCamera = GameActivity.mZoomCamera;
private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_CELL = "cell";
//private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM1 = "platform1";
//private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM2 = "platform2";
//private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM3 = "platform3";
//private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_COIN = "coin";
private SurfaceScrollDetector mScrollDetector;
private PinchZoomDetector mPinchZoomDetector;
private float mPinchZoomStartedCameraZoomFactor;
#Override
public void createScene() {
this.mScrollDetector = new SurfaceScrollDetector(this);
this.mPinchZoomDetector = new PinchZoomDetector(this);
this.setOnSceneTouchListener(this);
this.setTouchAreaBindingOnActionDownEnabled(true);
this.setOnAreaTouchTraversalFrontToBack();
createBackground();
createHUD();
createPhysics();
loadLevel(1);
}
#Override
public void onBackKeyPressed() {
SceneManager.getInstance().loadMenuScene(engine);
}
private void createBackground()
{ Sprite bg=new Sprite(400, 240, resourcesManager.menu_background_region, vbom);
attachChild(bg);
/*attachChild(new Sprite(400, 240, resourcesManager.menu_background_region, vbom)
{
#Override
protected void preDraw(GLState pGLState, Camera pCamera)
{
super.preDraw(pGLState, pCamera);
pGLState.enableDither();
}
});*/
}
#Override
public SceneType getSceneType() {
// TODO Auto-generated method stub
return null;
}
#Override
public void disposeScene()
{
camera.setHUD(null);
camera.setCenter(400, 240);
mZoomCamera.setZoomFactor(1.0f);
// TODO code responsible for disposing scene
// removing all game scene objects.
}
private HUD gameHUD;
private Text scoreText;
private void createHUD()
{
gameHUD = new HUD();
// CREATE SCORE TEXT
scoreText = new Text(20, 420, resourcesManager.font, "Score: 0123456789", new TextOptions(HorizontalAlign.LEFT), vbom);
scoreText.setAnchorCenter(0, 0);
scoreText.setText("Score: 0");
gameHUD.attachChild(scoreText);
camera.setHUD(gameHUD);
}
private int score = 0;
private void addToScore(int i)
{
score += i;
scoreText.setText("Score: " + score);
}
private PhysicsWorld physicsWorld;
private void createPhysics()
{
physicsWorld = new FixedStepPhysicsWorld(60, new Vector2(0, -17), false);
registerUpdateHandler(physicsWorld);
}
private void loadLevel(int levelID)
{
final SimpleLevelLoader levelLoader = new SimpleLevelLoader(vbom);
final FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(0, 0.01f, 0.5f);
levelLoader.registerEntityLoader(new EntityLoader<SimpleLevelEntityLoaderData>(LevelConstants.TAG_LEVEL)
{
public IEntity onLoadEntity(final String pEntityName, final IEntity pParent, final Attributes pAttributes, final SimpleLevelEntityLoaderData pSimpleLevelEntityLoaderData) throws IOException
{
SAXUtils.getIntAttributeOrThrow(pAttributes, LevelConstants.TAG_LEVEL_ATTRIBUTE_WIDTH);
SAXUtils.getIntAttributeOrThrow(pAttributes, LevelConstants.TAG_LEVEL_ATTRIBUTE_HEIGHT);
// TODO later we will specify camera BOUNDS and create invisible walls
// on the beginning and on the end of the level.
return GameScene.this;
}
});
levelLoader.registerEntityLoader(new EntityLoader<SimpleLevelEntityLoaderData>(TAG_ENTITY)
{
public IEntity onLoadEntity(final String pEntityName, final IEntity pParent, final Attributes pAttributes, final SimpleLevelEntityLoaderData pSimpleLevelEntityLoaderData) throws IOException
{
final int x = SAXUtils.getIntAttributeOrThrow(pAttributes, TAG_ENTITY_ATTRIBUTE_X);
final int y = SAXUtils.getIntAttributeOrThrow(pAttributes, TAG_ENTITY_ATTRIBUTE_Y);
final String type = SAXUtils.getAttributeOrThrow(pAttributes, TAG_ENTITY_ATTRIBUTE_TYPE);
final Sprite levelObject;
/* if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM1))
{
levelObject = new Sprite(x, y, resourcesManager.platform1_region, vbom);
PhysicsFactory.createBoxBody(physicsWorld, levelObject, BodyType.StaticBody, FIXTURE_DEF).setUserData("platform1");
}
else if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM2))
{
levelObject = new Sprite(x, y, resourcesManager.platform2_region, vbom);
final Body body = PhysicsFactory.createBoxBody(physicsWorld, levelObject, BodyType.StaticBody, FIXTURE_DEF);
body.setUserData("platform2");
physicsWorld.registerPhysicsConnector(new PhysicsConnector(levelObject, body, true, false));
}
else if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM3))
{
levelObject = new Sprite(x, y, resourcesManager.platform3_region, vbom);
final Body body = PhysicsFactory.createBoxBody(physicsWorld, levelObject, BodyType.StaticBody, FIXTURE_DEF);
body.setUserData("platform3");
physicsWorld.registerPhysicsConnector(new PhysicsConnector(levelObject, body, true, false));
}
else*/ if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_CELL))
{
levelObject = new Sprite(x, y, resourcesManager.cell_region, vbom);
final Body body = PhysicsFactory.createBoxBody(physicsWorld, levelObject, BodyType.StaticBody, FIXTURE_DEF);
body.setUserData("cell");
physicsWorld.registerPhysicsConnector(new PhysicsConnector(levelObject, body, true, false));
}
/*else if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_COIN))
{
levelObject = new Sprite(x, y, resourcesManager.coin_region, vbom)
{
#Override
protected void onManagedUpdate(float pSecondsElapsed)
{
super.onManagedUpdate(pSecondsElapsed);
/**
* TODO
* we will later check if player collide with this (coin)
* and if it does, we will increase score and hide coin
* it will be completed in next articles (after creating player code)
}
};
levelObject.registerEntityModifier(new LoopEntityModifier(new ScaleModifier(1, 1, 1.3f)));
} */
else
{
throw new IllegalArgumentException();
}
levelObject.setCullingEnabled(true);
return levelObject;
}
});
levelLoader.loadLevelFromAsset(activity.getAssets(), "level/" + levelID + ".lvl");
}
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
this.mPinchZoomDetector.onTouchEvent(pSceneTouchEvent);
if(this.mPinchZoomDetector.isZooming()) {
this.mScrollDetector.setEnabled(false);
} else {
if(pSceneTouchEvent.isActionDown()) {
this.mScrollDetector.setEnabled(true);
}
this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
}
return true;
}
#Override
public void onPinchZoomStarted(PinchZoomDetector pPinchZoomDetector,
TouchEvent pSceneTouchEvent) {
this.mPinchZoomStartedCameraZoomFactor = this.mZoomCamera.getZoomFactor();
}
#Override
public void onPinchZoom(PinchZoomDetector pPinchZoomDetector,
TouchEvent pTouchEvent, float pZoomFactor) {
this.mZoomCamera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
}
#Override
public void onPinchZoomFinished(PinchZoomDetector pPinchZoomDetector,
TouchEvent pTouchEvent, float pZoomFactor) {
this.mZoomCamera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
}
#Override
public void onScrollStarted(ScrollDetector pScollDetector, int pPointerID,
float pDistanceX, float pDistanceY) {
final float zoomFactor = mZoomCamera.getZoomFactor();
mZoomCamera.offsetCenter(-pDistanceX / zoomFactor, pDistanceY / zoomFactor);
}
#Override
public void onScroll(ScrollDetector pScollDetector, int pPointerID,
float pDistanceX, float pDistanceY) {
final float zoomFactor = mZoomCamera.getZoomFactor();
mZoomCamera.offsetCenter(-pDistanceX / zoomFactor, pDistanceY / zoomFactor);
}
#Override
public void onScrollFinished(ScrollDetector pScollDetector, int pPointerID,
float pDistanceX, float pDistanceY) {
final float zoomFactor = mZoomCamera.getZoomFactor();
mZoomCamera.offsetCenter(-pDistanceX / zoomFactor, pDistanceY / zoomFactor);
}
}
You're attaching your background as Entity using attachChild() method. You have to use setBackground() method instead.
setBackground(new SpriteBackground(bg));
Im trying to use the technique shown here, but unfortunately I have one problem. Whenever the color fades into the next colour the screen flashes/blinks a white colour. The problem seems to be coming from this class:
public class ColorAnimationDrawable extends Drawable implements Animatable {
private static final long FRAME_DURATION = 1000 / 60;
private static final long ANIMATION_DURATION = 1500;
private static final int ACCCENT_COLOR = 0x33FFFFFF;
private static final int DIM_COLOR = 0x33000000;
private static final Random mRandom = new Random();
private final Paint mPaint = new Paint();
private boolean mIsRunning;
private int mStartColor;
private int mEndColor;
private int mCurrentColor;
private long mStartTime;
#Override
public void draw(Canvas canvas) {
final Rect bounds = getBounds();
mPaint.setColor(mCurrentColor);
canvas.drawRect(bounds, mPaint);
mPaint.setColor(ACCCENT_COLOR);
canvas.drawRect(bounds.left, bounds.top, bounds.right, bounds.top + 1, mPaint);
mPaint.setColor(DIM_COLOR);
canvas.drawRect(bounds.left, bounds.bottom - 2, bounds.right, bounds.bottom, mPaint);
}
#Override
public void setAlpha(int alpha) {
oops("setAlpha(int)");
}
#Override
public void setColorFilter(ColorFilter cf) {
oops("setColorFilter(ColorFilter)");
}
#Override
public int getOpacity() {
return PixelFormat.TRANSPARENT;
}
#Override
public void start() {
if (!isRunning()) {
mIsRunning = true;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartColor = randomColor();
mEndColor = randomColor();
scheduleSelf(mUpdater, SystemClock.uptimeMillis() + FRAME_DURATION);
invalidateSelf();
}
}
#Override
public void stop() {
if (isRunning()) {
unscheduleSelf(mUpdater);
mIsRunning = false;
}
}
#Override
public boolean isRunning() {
return mIsRunning;
}
private void oops(String message) {
throw new UnsupportedOperationException("ColorAnimationDrawable doesn't support " + message);
}
private static int randomColor() {
return mRandom.nextInt() & 0x00FFFFFF;
}
private static int evaluate(float fraction, int startValue, int endValue) {
return (int) (startValue + fraction * (endValue - startValue));
}
private final Runnable mUpdater = new Runnable() {
#Override
public void run() {
long now = AnimationUtils.currentAnimationTimeMillis();
long duration = now - mStartTime;
if (duration >= ANIMATION_DURATION) {
mStartColor = mEndColor;
mEndColor = randomColor();
mStartTime = now;
mCurrentColor = mStartColor;
} else {
float fraction = duration / (float) ANIMATION_DURATION;
//#formatter:off
mCurrentColor = Color.rgb(
evaluate(fraction, Color.red(mStartColor), Color.red(mEndColor)), // red
evaluate(fraction, Color.green(mStartColor), Color.green(mEndColor)), // green
evaluate(fraction, Color.blue(mStartColor), Color.blue(mEndColor))); // blue
//#formatter:on
}
scheduleSelf(mUpdater, SystemClock.uptimeMillis() + FRAME_DURATION);
invalidateSelf();
}
};
}
Ive noticed that if I change ANIMATION_DURATION to something longer the delay in between the flashing is also longer. Does anyone know what the issue is and how I can get rid of the blinking?