Hello I need to count pixels that are covered by each fingers in multi-touch.When fingers down one by one it should plus pixels in count and finger up it should subtract pixels of that finger.I have did this but it is not getting exact counts i don't know what's wrong with it.please help me i am stucked at it.
public class MainActivity extends AppCompatActivity {
private static final int INVALID_POINTER_ID = -1;
private float mLastTouchX;
private float mLastTouchY;
private int mActivePointerId = INVALID_POINTER_ID;
private float mPosX;
private float mPosY;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
float TouchMajor=0.0f;
float TouchMinor=0.0f;
//float Size = 0.0f;
Boolean IsRightSideActive = false;
Boolean IsLeftSideActive = false;
float RightPixSize=0.0f;
float LeftPixSize=0.0f;
float RightPixChange = 0.0f;
float LeftPixChange = 0.0f;
float Pressure = 0.0f;
String Orientaation = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Image img = new Image(getApplicationContext());
setContentView(R.layout.activity_main);
final ImageView MyimageView = (ImageView)findViewById(R.id.imageView);
final TextView LeftPixelView = (TextView)findViewById(R.id.LeftPixelView);
final TextView RightPixelView = (TextView)findViewById(R.id.RightPixelView);
final TextView PressureView = (TextView)findViewById(R.id.PressureView);
final TextView OrientationView = (TextView)findViewById(R.id.OrientationView);
final Display display = getWindowManager().getDefaultDisplay();
final int ScreenWidth = display.getWidth();
if (MyimageView != null) {
MyimageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
// get pointer index from the event object
// int pointerIndex = event.getActionIndex();
mScaleDetector.onTouchEvent(event);
// get pointer ID
// int pointerId = event.getPointerId(pointerIndex);
// get masked (not specific to a pointer) action
int maskedAction = event.getActionMasked();
switch (maskedAction) {
case MotionEvent.ACTION_DOWN: {
final float x = event.getX();
final float y = event.getY();
mLastTouchX = x;
mLastTouchY = y;
///Toast toast = Toast.makeText(getApplicationContext(), "Action down", Toast.LENGTH_SHORT);
//toast.show();
int pointerIndex = event.getActionIndex();
mActivePointerId = event.getPointerId(0);
TouchMajor = event.getTouchMajor(pointerIndex);
TouchMinor = event.getTouchMinor(pointerIndex);
Pressure = event.getPressure(pointerIndex);
PressureView.setText("Pressure :"+Float.toString(Pressure));
//Orientaation =Double.toString( event.getOrientation(mActivePointerId));
//left Side of scren
if(event.getX(mActivePointerId) < ScreenWidth/2)
{
LeftPixChange = (TouchMajor + TouchMinor) / 2;
LeftPixSize = LeftPixChange;
LeftPixelView.setText(Float.toString(LeftPixSize));
OrientationView.setText("Left Side Clicked");
}
else if(event.getX(mActivePointerId) > ScreenWidth/2)
{
RightPixChange = (TouchMajor + TouchMinor) / 2;
RightPixSize = RightPixChange;
RightPixelView.setText(Float.toString(RightPixSize));
OrientationView.setText("Right Side Clicked");
}
break;
}
case MotionEvent.ACTION_POINTER_DOWN: {
final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = event.getX(newPointerIndex);
mLastTouchY = event.getY(newPointerIndex);
mActivePointerId = event.getPointerId(newPointerIndex);
}
TouchMajor = event.getTouchMajor(pointerIndex);
TouchMinor = event.getTouchMinor(pointerIndex);
Pressure =Pressure + event.getPressure(pointerIndex);
PressureView.setText("Cummulative pressure :"+Float.toString(Pressure));
//Orientaation = Orientaation+","+ event.getOrientation(mActivePointerId);
// OrientationView.setText(Orientaation);
//we take pointerindex here because pointerId remains same but index will be increased
if(event.getX(pointerIndex) < ScreenWidth/2)
{
LeftPixChange = (TouchMajor + TouchMinor) / 2;
LeftPixSize =LeftPixSize + LeftPixChange;
LeftPixelView.setText(Float.toString(LeftPixSize));
OrientationView.setText("Multi Left side clicked");
IsLeftSideActive = true;
}
else if(event.getX(pointerIndex) > ScreenWidth/2)
{
RightPixChange = (TouchMajor + TouchMinor) / 2;
RightPixSize =RightPixSize + RightPixChange;
RightPixelView.setText(Float.toString(RightPixSize));
OrientationView.setText("Multi Right side clicked");
IsRightSideActive = true;
}
else
{
OrientationView.setText("Both Sidse Clicked simultaneously");
}
break;
}
case MotionEvent.ACTION_MOVE: { // a pointer was moved
// TODO use data
final int pointerIndex = event.findPointerIndex(mActivePointerId);
final float x = event.getX(pointerIndex);
final float y = event.getY(pointerIndex);
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
MyimageView.invalidate();
}
mLastTouchX = x;
mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP:{
mActivePointerId = INVALID_POINTER_ID;
//Toast toast = Toast.makeText(getContext(), "Action UP", Toast.LENGTH_SHORT);
//toast.show();
RightPixelView.setText(Float.toString(0.0f));
LeftPixelView.setText(Float.toString(0.0f));
PressureView.setText("Pressure : 0.0");
OrientationView.setText("");
break;
}
case MotionEvent.ACTION_POINTER_UP:{
final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = event.getX(newPointerIndex);
mLastTouchY = event.getY(newPointerIndex);
mActivePointerId = event.getPointerId(newPointerIndex);
}
if(event.getX(pointerIndex) > ScreenWidth/2)
{
RightPixSize = RightPixSize - RightPixChange;
RightPixelView.setText(Double.toString(RightPixSize));
}
else if(event.getX(pointerIndex) < ScreenWidth/2){
LeftPixSize = LeftPixSize - LeftPixChange;
LeftPixelView.setText(Double.toString(LeftPixSize));
IsRightSideActive = false;
}
Pressure = Pressure - event.getPressure(event.getActionIndex());
PressureView.setText("Pressure :"+ Double.toString(Pressure));
break;
}
case MotionEvent.ACTION_CANCEL: {
// TODO use data
mActivePointerId = INVALID_POINTER_ID;
MyimageView.invalidate();
break;
}
}
MyimageView.invalidate();
return true;
}});
}
Related
I am using a library for Image Editor. This library works well. I get whatever I want except the zooming functionality. This is my xml code:
<ja.burhanrashid52.photoeditor.PhotoEditorView
android:id="#+id/editorView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#id/toolbar"
app:layout_constraintBottom_toTopOf="#id/bottomView"
android:visibility="visible" />
I tried using this code but it only zooms the image view. Ie the source by doing getSource(). This is the code I tried:
// in my class
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
String savedItemClicked;
private String TAG = "ImageEditorActivity";
// in the onCreate
binding.editorView.getSource().setScaleType(ImageView.ScaleType.MATRIX);
binding.editorView.getSource().setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
ImageView view = (ImageView) v;
dumpEvent(event);
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG");
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
// ...
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY()
- start.y);
} else if (mode == ZOOM) {
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix);
return true;
}
private void dumpEvent(MotionEvent event) {
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",
"POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
sb.append("(pid ").append(
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++) {
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
Log.d(TAG, sb.toString());
}
/** Determine the space between the first two fingers */
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
});
this is my very first experience here on stackoverflow :). I hope i don't break any rule with my first question.
I want to get color from bitmap but i have a problem with converting Imageview to Bitmap. Wherever i put my ImageView on screen, it's moving to (0,0) screen position after converting it to Bitmap. The worst thing is that this is not visible on screen, but when i try to catch color from 'empty' position it gives me "color". Im attaching screens because im sure im not understandable now :D.
clicked on area where is invisible bitmap and catching color)
clicked on area where bitmap is located but it doesn't catch color
I really don't know what is wrong. sitting whole week on this case and i registered here to ask you...
It may be stupid thing because im newbie. Thanks for any help...
public class Game extends AppCompatActivity {
private boolean isTouch = false;
private ImageView imageOpponent;
private Bitmap bitmap1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
ImageView image = findViewById(R.id.imageView3);
ImageView imageAim = findViewById(R.id.imageAim);
ImageView imageMove = findViewById(R.id.imageView4);
ImageView imageShoot = findViewById(R.id.imageShoot);
ImageView imageBackground = findViewById(R.id.imageBackground);
//FrameLayout shootingFrame = findViewById(R.id.shootingFrame);
//Bitmap bitmap = imageBackground.getDrawingCache();
Bitmap bitmap = ((BitmapDrawable)imageBackground.getDrawable()).getBitmap();
imageOpponent = findViewById(R.id.imageOpponent);
imageOpponent.setDrawingCacheEnabled(true);
imageOpponent.buildDrawingCache(true);
TextView textX = findViewById(R.id.textView1);
TextView textY = findViewById(R.id.textView2);
//textX.setText(String.valueOf(xSize));
image.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
float xSize = image.getWidth();
float ySize = image.getHeight();
float xMaxShootingFrame = imageBackground.getWidth();
float yMaxShootingFrame = imageBackground.getHeight();
float xMoveSize = imageMove.getLayoutParams().width;
float yMoveSize = imageMove.getLayoutParams().height;
textY.setText(String.valueOf(xMaxShootingFrame));
float X = (float) event.getX() - (xMoveSize/2);
float Y = (float) event.getY() - (yMoveSize/2);
float xCalculated = 100 * event.getX() / xSize;
xCalculated = xCalculated/100;
float yCalculated = 100 * event.getY() / ySize;
yCalculated = yCalculated/100;
int eventaction = event.getAction();
//if ((X >= 0 && Y >= 0) || (X <= 100 && Y <= 100))
if ((X >= (0-(xMoveSize/2)) && X <= (xSize-(xMoveSize/2)) && (Y >= (0-(yMoveSize/2)) && Y <= (ySize-(yMoveSize/2))))) {
switch (eventaction) {
case MotionEvent.ACTION_DOWN:
//Toast.makeText(Game.this, "ACTION_DOWN AT COORDS "+"X: "+X+" Y: "+Y, Toast.LENGTH_SHORT).show();
imageMove.setX(X);
imageMove.setY(Y);
imageAim.setX(xMaxShootingFrame*xCalculated-xMoveSize/2);
imageAim.setY(yMaxShootingFrame*yCalculated-yMoveSize/2);
textX.setText(String.valueOf(xCalculated));
isTouch = true;
break;
case MotionEvent.ACTION_MOVE:
//Toast.makeText(Game.this, "MOVE "+"X: "+X+" Y: "+Y, Toast.LENGTH_SHORT).show();
imageMove.setX(X);
imageMove.setY(Y);
imageAim.setX(xMaxShootingFrame*xCalculated-xMoveSize/2);
imageAim.setY(yMaxShootingFrame*yCalculated-yMoveSize/2);
//textX.setText(String.valueOf(bitmap.getHeight()));
break;
case MotionEvent.ACTION_UP:
//Toast.makeText(Game.this, "ACTION_UP "+"X: "+X+" Y: "+Y, Toast.LENGTH_SHORT).show();
imageMove.setX(X);
imageMove.setY(Y);
imageAim.setX(xMaxShootingFrame*xCalculated-xMoveSize/2);
imageAim.setY(yMaxShootingFrame*yCalculated-yMoveSize/2);
//textX.setText(String.valueOf(bitmap.getHeight()));
break;
}
}
float xxx = imageAim.getX();
float yyy = imageAim.getY();
return true;
}
});
imageShoot.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event){
bitmap1 = imageOpponent.getDrawingCache();
Bitmap bitmapBackground = ((BitmapDrawable)imageBackground.getDrawable()).getBitmap();
float xMoveSizex = imageAim.getLayoutParams().width;
float yMoveSizey = imageAim.getLayoutParams().height;
int x = (int)imageAim.getX() + ((int)xMoveSizex/2);
int y = (int)imageAim.getY() + ((int)yMoveSizey/2);
//Bitmap bitmap69 = Bitmap.createScaledBitmap(bitmap1, imageOpponent.getWidth(), imageOpponent.getHeight(), false);
textX.setText(String.valueOf(bitmap1.getHeight()));
textY.setText(String.valueOf(bitmap1.getWidth()));
if (x <= bitmap1.getWidth() && y <= bitmap1.getHeight()) {
int pixel = bitmap1.getPixel(x, y);
int redValue = Color.red(pixel);
int blueValue = Color.blue(pixel);
int greenValue = Color.green(pixel);
//if (redValue == 0 && blueValue == 0 && greenValue == 0){
//imageBackground.setBackgroundColor(Color.rgb(redValue,greenValue,blueValue));
if (bitmap1.getPixel(x, y) == Color.TRANSPARENT) {
textY.setText("Black " + x + " " + y);
} else {
textY.setText("Any Color");
}
}
return true;
}
});
}
}
I am developing a joystick button. Everything is ok when moving it around circle, but when I want to move it up or down, it goes only around circle again from the right side. So, I want to have both options (to move up or down in circle like real joystick). Here is my code example. Thanks for any help
public class JoystickView extends FrameLayout implements View.OnTouchListener {
private Context context;
private ImageView backgroundImageView;
private ImageView buttonImageView;
private RelativeLayout relativeLayout;
private View rootView;
float xx = 0;
float yy = 0;
public JoystickView(Context context) {
super(context);
this.context = context;
setLayout(this);
buttonImageView.setOnTouchListener(this);
this.setClipChildren(false);
}
public void setLayout(ViewGroup view) {
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
View v = inflateControlerLayout();
view.addView(v, layoutParams);
}
protected View inflateControlerLayout() {
initSlider();
rootView = relativeLayout;
return rootView;
}
public void initSlider() {
if (relativeLayout == null) {
relativeLayout = new RelativeLayout(context);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
relativeLayout.setLayoutParams(layoutParams);
relativeLayout.setClipChildren(false);
}
if (backgroundImageView == null) {
backgroundImageView = new ImageView(context);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
backgroundImageView.setLayoutParams(layoutParams);
// load image
try {
// get input stream
InputStream ims = getContext().getAssets().open("joystick_background.png");
// load image as Drawable
Drawable d = Drawable.createFromStream(ims, null);
// set image to ImageView
backgroundImageView.setImageDrawable(d);
} catch (IOException ex) {
return;
}
}
if (buttonImageView == null) {
buttonImageView = new ImageView(context);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, Gravity.CENTER);
buttonImageView.setLayoutParams(layoutParams);
// load image
try {
// get input stream
InputStream ims2 = getContext().getAssets().open("jostick_button.png");
// load image as Drawable
Drawable d2 = Drawable.createFromStream(ims2, null);
// set image to ImageView
buttonImageView.setImageDrawable(d2);
buttonImageView.bringToFront();
} catch (IOException ex) {
return;
}
}
if (relativeLayout != null) {
relativeLayout.addView(backgroundImageView);
relativeLayout.addView(buttonImageView);
}
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
view.setX(xx);
view.setY(yy);
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
float cx = view.getWidth() / 2.f;
float cy = view.getHeight() / 2.f;
float x = motionEvent.getRawX();
float y = motionEvent.getRawY();
float w = buttonImageView.getWidth();
float h = buttonImageView.getHeight();
double r = Math.min(cx, cy) / 2.;
double dx = x - cx;
double dy = y - cy;
double hypot = Math.hypot(dx, dy);
double cos = dx / hypot;
double sin = dy / hypot;
double rdx = hypot < 1. ? 0. : r * cos;
double rdy = hypot < 1. ? 0. : r * sin;
buttonImageView.setTranslationX((float) (cx + rdx - w / 2.));
buttonImageView.setTranslationY((float) (cy + rdy - h / 2.));
break;
}
return true;
}
}
These lines constrain the coordinates to a circle (oval) path or center:
double rdx = hypot < 1. ? 0. : r * cos;
double rdy = hypot < 1. ? 0. : r * sin;
For hypot to be less than 1 (that's 1 pixel) you'd have to be dead center.
I changed it to only constrain the coordinates within the circle:
double rcos = r * cos;
double rsin = r * sin;
double rdx = Math.abs(dx) < Math.abs(rcos) ? dx : rcos;
double rdy = Math.abs(dy) < Math.abs(rsin) ? dy : rsin;
I think this might be what you want.
I have found a working solution if someone is looking for it
private Point calculate (float x, float y) {
float cx = buttonImageView.getWidth() / 2.f;
float cy = buttonImageView.getHeight() / 2.f;
double r = cx / 2.; // vrednost radius
double dx = x;
double dy = y;
double hypot = Math.hypot(dx, dy); // izracun hipotenuze
double cos = dx / hypot; // cos
double sin = dy / hypot; // sin
double rcos = r * cos;
double rsin = r * sin;
double rdx = Math.abs(dx) < Math.abs(rcos) ? dx : rcos; // if,else
double rdy = Math.abs(dy) < Math.abs(rsin) ? dy : rsin;
return new Point((int)rdx, (int)rdy);
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
final float x = motionEvent.getRawX(); // x točko
final float y = motionEvent.getRawY(); // y točka
//Log.d("VALUES", "RAW X:" + motionEvent.getRawX() + ", RAW Y:" + motionEvent.getRawY() + ", X:" + motionEvent.getX() + ", CX:" + cx + ", CY:" + cy + ", dx:" + dx + ", dy:" + dy + ", Hypo:" + hypot + ", cos:" + cos + ", sin" + sin);
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
xDelta = view.getX() - x;
yDelta = view.getY() - y;
break;
case MotionEvent.ACTION_UP:
doBounceAnimation(buttonImageView);
doVibration();
view.setX(xx);
view.setY(yy);
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
final float transX = (float) x;
final float transY = (float) y;
thread = new Thread() {
#Override
public void run() {
Point newPoint = calculate(transX+ xDelta,transY + yDelta);
buttonImageView.setX(newPoint.x);
buttonImageView.setY(newPoint.y);
}
};
thread.start();
Log.d(TRANSLATIONX,"X:" + transX + ", Y:" + transY);
break;
}
return true;
}
Enjoy coding!
I'm working in a spaceship first person view game. I have a joystick, and when i move the joystick i can move all the objects (asteroids) of the screen simulating that the spaceship is being moved with the joystick.
The game works fine, but now i have a problem. If you are pressing the joystick in the max left position and then you do ACTION_UP and then instantly ACTION_DOWN in the joystick again but in the max right position, the spaceship starts moving to the right at max speed. It is hard to explain it. For example, If you press the joystick in max left position the spaceship is moving -20px per frame to the left and if you press the joystick in the max right position, the spaceship moves to the right +20px per frame.
So, now, if i do a fast max left and max right touch on the joystick, the spaceship does this movement: -20....+20
It is not reallistic movement.
I want to get this movement: -20 -17 -14 -9 -5 0 +5 +9 +14 +17 +20.... I mean a more reallistic spaceship movement. But the problem is that i am not a math or physics expert, and i dont have any idea of how to get that kind of functionality in this joystick... any help will be very grateful.
Here you can find a demo project with the joystick: https://mega.co.nz/#!cp5FhYIT!dM88qx_xQdyhED9fX_4xeJ9ciQYJirUlNzEi-KOzU2k
This is the joystick code, i found it in google and works very well except for the non realistic movement that i described before:
public class Joystick extends View {
public static final int INVALID_POINTER = -1;
private JoystickMovedListener moveListener;
//# of pixels movement required between reporting to the listener
private float moveResolution;
//Max range of movement in user coordinate system
private float movementRange;
//Last touch point in view coordinates
private int pointerId = INVALID_POINTER;
private float touchX;
private float touchY;
private float touchXDelayedMovement;
private float touchYDelayedMovement;
//Handle center in view coordinates
private float handleX;
private float handleY;
//Last reported position in view coordinates (allows different reporting sensitivities)
private float reportX;
private float reportY;
//Center of the view in view coordinates
private int cX;
private int cY;
//Size of the view in view coordinates
private int dimX;
private int dimY;
private int innerPadding;
private int bgRadius;
private int handleRadius;
private int movementRadius;
private int handleInnerBoundaries;
//Cartesian coordinates of last touch point - joystick center is (0,0)
private int cartX;
private int cartY;
//User coordinates of last touch point
private int userX;
private int userY;
//Offset co-ordinates (used when touch events are received from parent's coordinate origin)
private int offsetX;
private int offsetY;
private Paint bgPaint;
private Paint handlePaint;
boolean disabled;
Handler handler;
Handler handlerDelayedMovement;
public Joystick(Context context) {
super(context);
initJoystickView();
}
private void initJoystickView() {
setFocusable(true);
handlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
handlePaint.setColor(Color.RED);
handlePaint.setStrokeWidth(1);
handlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bgPaint.setColor(Color.DKGRAY);
bgPaint.setStrokeWidth(1);
bgPaint.setStyle(Paint.Style.FILL_AND_STROKE);
this.moveResolution = 1.0f;
handler = new Handler();
handlerDelayedMovement = new Handler();
}
public void setMovementRange(float movementRange) {
this.movementRange = movementRange;
}
public void setOnJostickMovedListener(JoystickMovedListener listener) {
this.moveListener = listener;
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int d = Math.min(getMeasuredWidth(), getMeasuredHeight());
dimX = d;
dimY = d;
cX = d / 2;
cY = d / 2;
bgRadius = dimX/2 - innerPadding;
handleRadius = (int)(d * 0.2);
handleInnerBoundaries = handleRadius;
movementRadius = Math.min(cX, cY) - handleInnerBoundaries;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Here we make sure that we have a perfect circle
int measuredWidth = measure(widthMeasureSpec);
int measuredHeight = measure(heightMeasureSpec);
setMeasuredDimension(measuredWidth, measuredHeight);
}
private int measure(int measureSpec) {
int result = 0;
// Decode the measurement specifications.
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.UNSPECIFIED) {
result = 200; // Return a default size of 200 if no bounds are specified.
} else {
result = specSize; // As you want to fill the available space always return the full available bounds.
}
return result;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
// Draw the background
canvas.drawCircle(cX, cY, bgRadius, bgPaint);
// Draw the handle
handleX = touchX + cX;
handleY = touchY + cY;
canvas.drawCircle(handleX, handleY, handleRadius, handlePaint);
canvas.restore();
}
public void setPointerId(int id) {
this.pointerId = id;
}
public int getPointerId() {
return pointerId;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
if (disabled==true)
break;
return processMoveEvent(ev);
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
if ( pointerId != INVALID_POINTER ) {
returnHandleToCenter();
returnHandleToCenterDelayedMovement();
setPointerId(INVALID_POINTER);
}
break;
}
case MotionEvent.ACTION_POINTER_UP: {
if ( pointerId != INVALID_POINTER ) {
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if ( pointerId == this.pointerId ) {
returnHandleToCenter();
returnHandleToCenterDelayedMovement();
setPointerId(INVALID_POINTER);
return true;
}
}
break;
}
case MotionEvent.ACTION_DOWN: {
handlerDelayedMovement.removeCallbacksAndMessages(null);
if ( pointerId == INVALID_POINTER ) {
int x = (int) ev.getX();
if ( x >= offsetX && x < offsetX + dimX ) {
setPointerId(ev.getPointerId(0));
if (disabled==true){
return true;
}
return processMoveEvent(ev);
}
}
break;
}
case MotionEvent.ACTION_POINTER_DOWN: {
if ( pointerId == INVALID_POINTER ) {
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
int x = (int) ev.getX(pointerId);
if ( x >= offsetX && x < offsetX + dimX ) {
setPointerId(pointerId);
return true;
}
}
break;
}
}
return false;
}
private boolean processMoveEvent(MotionEvent ev) {
if ( pointerId != INVALID_POINTER ) {
final int pointerIndex = ev.findPointerIndex(pointerId);
// Translate touch position to center of view
float x = ev.getX(pointerIndex);
touchX = x - cX - offsetX;
float y = ev.getY(pointerIndex);
touchY = y - cY - offsetY;
reportOnMoved();
invalidate();
return true;
}
return false;
}
private void reportOnMoved() {
//constraint circle
float diffX = touchX;
float diffY = touchY;
double radial = Math.sqrt((diffX*diffX) + (diffY*diffY));
if ( radial > movementRadius ) {
touchX = (int)((diffX / radial) * movementRadius);
touchY = (int)((diffY / radial) * movementRadius);
}
//We calc user coordinates
//First convert to cartesian coordinates
cartX = (int)(touchX / movementRadius * movementRange);
cartY = (int)(touchY / movementRadius * movementRange);
//Cartesian Coordinates
userX = cartX;
userY = cartY;
if (moveListener != null) {
boolean rx = Math.abs(touchX - reportX) >= moveResolution;
boolean ry = Math.abs(touchY - reportY) >= moveResolution;
if (rx || ry) {
this.reportX = touchX;
this.reportY = touchY;
moveListener.OnMoved(userX, userY);
}
}
}
private void reportOnMovedDelayedMovement() {
//constraint circle
float diffX = touchXDelayedMovement;
float diffY = touchYDelayedMovement;
double radial = Math.sqrt((diffX*diffX) + (diffY*diffY));
if ( radial > movementRadius ) {
touchXDelayedMovement = (int)((diffX / radial) * movementRadius);
touchYDelayedMovement = (int)((diffY / radial) * movementRadius);
}
//We calc user coordinates
//First convert to cartesian coordinates
cartX = (int)(touchXDelayedMovement / movementRadius * movementRange);
cartY = (int)(touchYDelayedMovement / movementRadius * movementRange);
//Cartesian Coordinates
userX = cartX;
userY = cartY;
if (moveListener != null) {
boolean rx = Math.abs(touchXDelayedMovement - reportX) >= moveResolution;
boolean ry = Math.abs(touchYDelayedMovement - reportY) >= moveResolution;
if (rx || ry) {
this.reportX = touchXDelayedMovement;
this.reportY = touchYDelayedMovement;
moveListener.OnMoved(userX, userY);
}
}
}
private void returnHandleToCenter() {
final int numberOfFrames = 5;
final double intervalsX = (0 - touchX) / numberOfFrames;
final double intervalsY = (0 - touchY) / numberOfFrames;
handler.removeCallbacksAndMessages(null);
for (int i = 0; i < numberOfFrames; i++) {
final int j = i;
handler.postDelayed(new Runnable() {
#Override
public void run() {
touchX += intervalsX;
touchY += intervalsY;
//reportOnMoved();
invalidate();
if (moveListener != null && j == numberOfFrames - 1) {
moveListener.OnReturnedToCenter();
}
}
}, i * 10);
}
if (moveListener != null) {
moveListener.OnReleased();
}
}
private void returnHandleToCenterDelayedMovement() {
final int numberOfFrames = 25;
touchXDelayedMovement=touchX;
touchYDelayedMovement=touchY;
final double intervalsX = (0 - touchXDelayedMovement) / numberOfFrames;
final double intervalsY = (0 - touchYDelayedMovement) / numberOfFrames;
handlerDelayedMovement.removeCallbacksAndMessages(null);
for (int i = 0; i < numberOfFrames; i++) {
handlerDelayedMovement.postDelayed(new Runnable() {
#Override
public void run() {
touchXDelayedMovement += intervalsX;
touchYDelayedMovement += intervalsY;
reportOnMovedDelayedMovement();
}
}, i * 50);
}
}
public void setInnerPadding(int innerPadding){
this.innerPadding=innerPadding;
}
public void disable(){
disabled=true;
}
public void enable(){
disabled=false;
}
public interface JoystickMovedListener {
public void OnMoved(int pan, int tilt);
public void OnReleased();
public void OnReturnedToCenter();
}
}
You must do this in the class that will use the joystick:
private JoystickMovedListener joystickListener = new JoystickMovedListener() {
#Override
public void OnMoved(int pan, int tilt) {
//here i move the objects in the game
}
}
#Override
public void OnReleased() {}
public void OnReturnedToCenter() {};
};
joystickOnScreen = new Joystick(this);
joystickOnScreen.setMovementRange(screenHeight/50);
joystickOnScreen.setInnerPadding(screenHeight/30);
joystickOnScreen.setOnJostickMovedListener(joystickListener);
RelativeLayout.LayoutParams joystickParams = new RelativeLayout.LayoutParams(sh/3, sh/3);
joystickParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
joystickParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
joystickParams.setMargins(sh/100, 0, 0, sh/100);
joystickOnScreen.setLayoutParams(joystickParams);
joystickOnScreen.setAlpha(0.3f);
I will not implement the changes for you but hopefully this answer can help you towards implementing this on your own.
With your current implementation you are updating the object position (x, y) each frame. To get the more realistic physics that you want, you need to store and update velocity as well (vx, vy).
Add two new variables, vx and vy (with initial values of zero) in the objects that you are currently updating the position for. The joystick should control the change of the velocity instead of the position. Change the code that updates the positions x and y, to update the velocities vx and vy instead. When the joystick is max left, you can for example set vx = vx - 3.
After the velocity is updated, you need to update the position using the velocity variables. For example, set the position x = x + vx. Ideally you want this to happen in a different method that runs even if you don't move the joystick, but to keep it simple you can do this update right after the update of the velocity variables.
With this implementation you will get a more realistic game physics. As a next step you might want to add limits on the velocity to not move too fast. This can be done with an if-statement where you check that the value is not too big before adding more to it, or too smal before subtracting from it. Good luck!
I am implementing an app for getting the correct x and y location of the image-view and x and y coordinates of an image-view when I move the position of images on the screen. When I run the app and when I move my image-view it will get only 0 and 1. Is there a way for find out the x and y location?
Here is my Main-activity class:
public class MainActivity extends Activity{
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
int[] location = new int[4];
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView image = (ImageView) findViewById(R.id.ImageViewOne);
final Bitmap icon = BitmapFactory.decodeResource(this.getResources(),
R.drawable.yellowrose);
image.setImageBitmap(icon);
image.setOnTouchListener(new View.OnTouchListener()
{
public boolean onTouch(View v, MotionEvent event)
{
final ImageView view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
System.out.println("mode = drag");
RectF r = new RectF();
matrix.mapRect(r);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
System.out.println("mode = none = " + mode);
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
}
else if (mode == ZOOM)
{
float newDist = spacing(event);
if (newDist > 10f)
{
matrix.set(savedMatrix);
float scale = newDist / oldDist;
System.out.println("scale " + scale);
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f)
{
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
System.out.println("mode " + mode);
}
break;
}
// Perform the transformation
view.setImageMatrix(matrix);
return true;
}
});
}
private float spacing(MotionEvent event)
{
float x = event.getRawX() - event.getRawX();
System.out.println("spacing x" + x);
float y = event.getRawY() - event.getRawY();
System.out.println("spacing y" + y);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event)
{
float x = event.getRawX() + event.getRawX();
System.out.println("midpoint x" + x);
float y = event.getRawY() + event.getRawY();
System.out.println("midpoint y" + y);
point.set(x / 2, y / 2);
}
}
I am using View.getLocationOnScreen(int[]) to get X and Y of a view relative to its parent/screen:
int[] posXY = new int[2];
myView.getLocationOnScreen(posXY);
int x = posXY[0];
int y = posXY[1];