Does anyone know the double-tap-zoom function on normal Android application (like web view or image view) is accomplished by zoom animation or by dividing the zoom into small steps and perform them one by one?
If using zoom animation, since animation is cached drawing, is there any problem when I do zoom in like this?
mView.zoomTo(newScale);
mView.startAnimation(zoomInAnimation);
Should I only set the new scale after animation finished?
And if using multiple steps of zooming, is this really a good approach? How to perform each step? Send messages multiple times?
What is exactly the best way of doing smooth zoom in/out when double tapping?
extend Animation class and override applyTransformarion method, use interpolatedTime parameter to compute the current zoom level
EDIT
as simple as it can be, works with really ancient droids:
public class ZoomAnimation extends Animation {
private float mFrom;
private float mTo;
public ZoomAnimation(float from, float to) {
mFrom = from;
mTo = to;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float currentZoom = mFrom + ((mTo - mFrom) * interpolatedTime);
// do something with currentZoom
}
}
While waiting for the best answer, I tried "multiple-step-zooming" by myself, and it turns out charming.
If anyone could give out a better answer, I will accept yours.
The multiple-step-zooming is performed by posting the nested Runnable instance, the mCanvasScale is the field used to control the drawing of the view. setZoomValue() is setting the mCanvasScale and call invalidate().
public void smoothScaleTo(final float targetScale) {
if(targetScale != mCanvasScale) {
post(new SmoothScaleExecutor(mCanvasScale, targetScale));
}
}
private class SmoothScaleExecutor implements Runnable {
public static final int SMOOTH_SCALE_STEPS = 4;
private float mStartingScale;
private float mTargetScale;
private float mScaleStep;
public SmoothScaleExecutor(float startingScale, float targetScale) {
mStartingScale = startingScale;
mTargetScale = targetScale;
mScaleStep = (targetScale - startingScale) / SMOOTH_SCALE_STEPS;
}
#Override
public void run() {
if(mStartingScale < mTargetScale) {
if(mCanvasScale < mTargetScale) {
float f = mCanvasScale + mScaleStep;
if(f > mTargetScale) f = mTargetScale;
setZoomValue(f);
post(this);
}
} else {
if(mCanvasScale > mTargetScale) {
float f = mCanvasScale + mScaleStep;
if(f < mTargetScale) f = mTargetScale;
setZoomValue(f);
post(this);
}
}
}
}
Related
I need to remove blur from the image wherever user touch on screen from an image and save it's state. I have been using the following library.
https://github.com/cats-oss/android-gpuimage
I have used the following example which is using android-gpuimage
https://github.com/ufo22940268/Android-Blur
It removes blur from image wherever I touch but when I touch other parts of the image the later touch point become blur again.
public void onTouch(MotionEvent event){
float y = event.getY(mActionIndex);
float x = event.getX(mActionIndex);
focus(x, y);
requestRender();
}
private void focus(float x, float y) {
GPUImageFilter filter = getFilter();
if (filter != null && filter instanceof GPUImageBoxBlurFilter) {
GPUImageBoxBlurFilter blurFilter = (GPUImageBoxBlurFilter) filter;
blurFilter.focus(x, y);
}
}
public void focus(final float x, final float y) {
runOnDraw(new Runnable() {
#Override
public void run() {
float[] focusLocation = new float[]{normalize(x, mOutputWidth), -normalize(y, mOutputHeight)};
GPUImageFilter filter = mFilters.get(0);
int screenRatioLocation = GLES20.glGetUniformLocation(filter.getProgram(), "focusLocation");
filter.setFloatVec2(screenRatioLocation, focusLocation);
filter = mFilters.get(1);
screenRatioLocation = GLES20.glGetUniformLocation(filter.getProgram(), "focusLocation");
filter.setFloatVec2(screenRatioLocation, focusLocation);
initTexelOffsets();
}
});
}
private float normalize(float x, int outputWidth) {
return x / outputWidth * 2 - 1;
}
protected void initTexelOffsets() {
float ratio = getHorizontalTexelOffsetRatio();
GPUImageFilter filter = mFilters.get(0);
int texelWidthOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), "texelWidthOffset");
int texelHeightOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), "texelHeightOffset");
filter.setFloat(texelWidthOffsetLocation, ratio / mOutputWidth);
filter.setFloat(texelHeightOffsetLocation, 0);
ratio = getVerticalTexelOffsetRatio();
filter = mFilters.get(1);
texelWidthOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), "texelWidthOffset");
texelHeightOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), "texelHeightOffset");
filter.setFloat(texelWidthOffsetLocation, 0);
filter.setFloat(texelHeightOffsetLocation, ratio / mOutputHeight);
}
Whenever user select unblur then touching on image should remove blur from that point and save image so that when user touch another point both or more points should be unblured.
Need vice versa of this as well, if user select blur it should blur that point.
As I am pretty noob in opengl any help will be greately appreciated.
So I am using the libgdx framework and am new to android games development. I have an array of yellow circle objects stored in each index which are shown on the game screen when I run them, all the circle objects are in different x positions but on the same y axis. I want to basically set the visibility of each circle for a given amount of time before the next one becomes visible for say 1000 ms per circle. So for example circle 1 will be visible for 1000 ms then it will become invisible and circle 2 will then become visible for 1000ms so on and so forth, till I reach the end of the list.
public class Spot {
private float x;
private float y;
private float radius;
private Circle spot;
private Circle spotList[];
public Spot(float x, float y, float radius, int amount){
this.x = x;
this.y = y;
this.radius = radius;
spot = new Circle(x,y,radius);
spotList = new Circle[amount];
for(int i = 0; i < spotList.length; i++){
spotList[i] = new Circle(this.x+(i*15), this.y, this.radius);
}
}
public void update(float delta){
}
public Float getX(){
return x;
}
public Float getY(){
return y;
}
public float getRadius(){
return radius;
}
public Circle[] getSpots(){
return spotList;
}
public Circle getSpot(){
return spot;
}
}
The rendering of the shape has been outsourced to a different class I want to be able to handle the visibility of the circles etc in the update method.
Since you're not using Actors (https://github.com/libgdx/libgdx/wiki/Scene2d), you need to keep track of time yourself and make the circles visible/not visible.
You will want to add
private float elapsedTime = 0.0f;
private float currentCircle = 0;
two fields, one for keeping track of elapsed time and one for the currently visible circle.
public void update(float delta){
elapsedTime += delta;
if (elapsedTime >= 1.0f) { // more than one second passed
spot[currentCircle].setVisible(false);
if (currentCircle + 1 < spotList.size()) {
currentCircle++;
spot[currentCircle].setVisible(true);
elapsedTime -= 1.0f; // reset timer (don't just set to 0.0f to avoid time shifts)
}
}
}
In the update method, count elapsedTime and if more then one seconds passed, make old circle not visible and new circle visible. Also make sure that initially the first circle is visible and that the timer is 0.
A possible solution is to use the Universal Tween Engine which works well with the libGDX framework. Visit the link to see how to include it in your project and for documentation.
As a quick demonstration on how to use it:-
Create and instantiate a TweenManager and your array of Spots in your class responsible for rendering.
protected TweenManager tweenManager = new TweenManager();
Spot spots[] = new Spot[...];
...
Create your timer by implementing the TweenCallback()
final int numberOfSpots = 5;
int spotArrayIndex = 0;
float timeDelay = 1000f; /*1000 milliseconds*/
Tween.call(new TweenCallback() {
#Override
public void onEvent(int type, BaseTween<?> source) {
/*set or unset the visibility of your Spot objects here i.e. */
spots[spotArrayIndex++].setVisible(false); /*Set current spot invisible*/
spots[spotArrayIndex].setVisible(true); /*Set next spot to be visible*/
}
}).repeat(numberOfSpots, timeDelay).start(tweenManager);
Update the tweenManager in your render method
public void render(float delta) {
...
tweenManger.update(delta);
...
}
Please check the code for errors if you use it, as I am not sure of the rest of your code.
I'm making a game with Andengine and i'm stuck for 2 days on shooting from a rotating sprite. I'm not a hero at geometry and already ask a teacher but he could also not provide me the correct answer. So who is a mathematics hero and help me out :).
The problem is that i cannot figure out where the bullet has to spawn in front of the turret. Rotating and finding the destination where the bullet has to go is no problem. It only about the spawn point.
I removed a lot of not-interesting-code for this question.
Okay so here is the rotating code from the turret-rotation:
public class AlienShip extends Ship {
public static final float BASE_ROTATION_SPEED = 0.25f;
public static final int DEFAULT_IMAGE_ROTATION = 90; //90 degrees
protected PlayerShip ship;
public AlienShip(float pX, float pY, TextureRegion pTextureRegion,
VertexBufferObjectManager pVertexBufferObject,FixedStepPhysicsWorld pw, int baseDurability) {
super(pX, pY, pTextureRegion, pVertexBufferObject, pw, baseDurability);
}
public void rotateToPlayer()
{
if (ship != null) {
float dX = this.getX() - ship.getX();
float dY = this.getY() - ship.getY();
float angle = (float) Math.atan2(-dY, dX);
float rotation = MathUtils.radToDeg(angle) + DEFAULT_IMAGE_ROTATION;
RotationModifier rotMod = new RotationModifier(BASE_ROTATION_SPEED, this.getRotation(), rotation);
this.registerEntityModifier(rotMod);
}
}
public void rotateToInitPos() {
RotationModifier rotMod = new RotationModifier(BASE_ROTATION_SPEED, this.getRotation(), 0);
this.registerEntityModifier(rotMod);
}
}
The code above is working fine.
Here is the code from the laser that the ship is shooting.
Read the comments to find out witch part is not working.
public class GameScene extends Scene {
protected PlayerShip playerShip;
private SpawnCallback createShootCallback(boolean player) {
return new SpawnCallback() {
#Override
public void spawn(SpawnTimer spawnTimer) {
PhysicsSprite laser = null;
AlienShip alienShip = (AlienShip) spawnTimer.getPhysicsSprite();
// laser = alienMissilePool.getMissileFromPool(x,y)
//spawn the laser in front of the rotating ship [Not working :( ]
laser = alienMissilePool.getMissileFromPool( ( alienShip.getX() * FloatMath.cos(MathUtils.degToRad(rotation)) - ((1280 - alienShip.getY() - alienShip.getY()/2) * FloatMath.sin(MathUtils.degToRad(rotation)) ) ) ,
( alienShip.getX() * FloatMath.sin(MathUtils.degToRad(rotation)) + ((1280 - alienShip.getY() - alienShip.getY()/2) * FloatMath.cos(MathUtils.degToRad(rotation)) ) ) );
//Set the rotation from the laser same to the ship rotation [Is working perfectly].
float rotation = alienShip.getRotation();
laser.setRotation(rotation);
//Set laser speed and direction [Is working perfectly]
float pX = 0.01f * (playerShip.getX() - laser.getX());
float pY = 0.01f * (playerShip.getY() - laser.getY());
laser.getSpriteBody().setLinearVelocity(pX, pY);
spawnPhysicsSprite(laser);
}
};
}
}
Here is a link to a drawing that shows the x-axis and y-axis values.
http://s24.postimg.org/citz29339/gamescene.png
Thank you!
Instead of getting into maths, why don't you put an object (Entity) positioned on the place of the turret and use it's position as the spawn point for the laser ?
so your turret would have an Entity attached to it on the place of the gun.
tell me if you need an example code
I made a panorama app that scrolls the image automatically, from left to right to left and so on. It works nicely, except for the fact that it doesn't quite scrolls as smoothly (meaning constant velocity) as I would like. It sometimes 'jumps' a bit. It shouldn't be in a device with a core of 1.4 GHz...
I implemented this just by translating the image, then waiting a bit with a Thread.sleep(panoanimspeed); (where 1/1000s <= panoanimspeed <= 1/50s), and so on. Probably not the smartest thing to do...?
Do you know how can I make this smoother? Below is the code of the relevant AsyncTask.
Thanks!
class AnimatePanorama extends AsyncTask<Void, Integer, Void> {
private float scale = foto.getCropScale() * foto.getBaseScale();
private Matrix m = foto.matrix;
#Override
protected void onProgressUpdate(Integer... values) {
if (values[0] == 0) {
m.setScale(scale, scale);
m.postTranslate(values[1], 0);
foto.setImageMatrix(m);
}
}
#Override
protected Void doInBackground(Void... arg) {
dir = -dir;
int l, ini = 0;
float lim = foto.getImageWidth()*scale - foto.getViewWidth();
float[] mm = new float[9];
foto.matrix.getValues(mm);
if (foto.getScale() == foto.getCropScale())
ini = (int) (dir*(lim*(dir+1)/2 + mm[2]));
while (true) {
if(isCancelled()) break;
l = (int) (lim*(dir+1)/2);
for (int i = ini; i < lim; i++) {
if(isCancelled()) break;
try {
Thread.sleep(panoanimspeed);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(0, dir * i - l);
}
ini = 0;
dir = -dir;
}
return null;
}
}
Create an animation by extending Animation class (http://developer.android.com/reference/android/view/animation/Animation.html)
and override the applyTransformation(float interpolatedTime, Transformation t) method.
Base your image translation on a "real time" based translation, like X pixels per second.
On the first cycle, save the system time as a base time stamp.
On future loop cycles, calculate the new location based on the time since the base time stamp.
This will avoid the unreliability of the Thread.sleep "real world" timing.
I am trying to check collisions between lines and a circle, if the circle hits the line, it would work change a boolean to true and once its not touched, it would change it back to false. I am using canvas and surface view.
Here is my code for checking collision which didn't work and ended up in error:
#Override
public void run() {
while(runnable)
{
if(!holder.getSurface().isValid()){
continue;
}
Canvas mCanvas = holder.lockCanvas();
update(mCanvas);
values = new Values(mCanvas);
createPaints();
drawBackground(mCanvas);
drawObjects(mCanvas);
holder.unlockCanvasAndPost(mCanvas);
}
}
Now the collision is processed in the update:
private void update(Canvas c) {
ball.update(c, checkLinesCollision(values.level1, ball.getX(), ball.getY()));
//takes a canvas, and a boolean
}
boolean checkLinesCollision(float[] f,float x,float y){
int c = 0;
for(int i = 0; i < f.length; i+=4){
float x1 = f[i];
float y1 = f[i+1];
float x2 = f[i+2];
float y2 = f[i+3];
if (x> x1 && x<x2 && y>y1 && y>y2){
c++;
}
}
if(c>0){return true;}else{return false;}
}
the values for the level
float yLow = c.getHeight()-c.getHeight()/4;
level1 = new float[]{0,yLow,c.getWidth(),yLow,
40,c.getHeight()/2,300,c.getHeight()/2};
ball update function:
public void update(Canvas c, boolean b) {
if(b){
dy=-dy;
b = false;
}
y -= dy;
dy--;
}
Now according to the logcat the problem is in the main update function.
I think that I am using the wrong function, what can I do to fix it?
Thanks!
I have found the solution. Apparently the problem was with the float array; in my app, i declared the float array in a constructor. After a long time of researching on the web and rechecking my logcat, i found that you cannot declare an array in the constructor. all i did was moving the float array outside of the constructor and everything was alright, even though i found the solution, i am not sure why you cannot declare it in the constructor..