I can't draw a straight line slowly!
when I slide slowly I have a wavy line instead a straight line.
I tried to use the tool "Pointer location" to check the points and I recived the same result.
But when I slide fastly, vertical, or horizontal, I recived straight line...
This is my code
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
String ms;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
int xDown = (int)event.getX();
int yDown = (int)event.getY();
ms = "down";
out.println(xDown);
out.println(yDown);
out.println(ms);
break;
case MotionEvent.ACTION_MOVE:
ms = "move";
int hsize = event.getHistorySize();
for(int i=0;i<hsize;i++)
{
int x = (int)event.getHistoricalX(i);
int y = (int)event.getHistoricalY(i);
int hx = x;
int hy = y;
out.println(hx);
out.println(hy);
out.println(ms);
}
/*
int xMove = (int)event.getX();
int yMove = (int)event.getY();
out.println(xMove);
out.println(yMove);
ms = "move";
out.println(ms);
*/
break;
case MotionEvent.ACTION_UP:
int xUp = (int)event.getX();
int yUp = (int)event.getY();
out.println(xUp);
out.println(yUp);
ms = "up";
out.println(ms);
break;
}
return false;
}
I can suggest you to save starting location and redraw line each time from the starting point to the point where you are touching the screen.
If you don't want a polygon made of straight lines you can draw it by tapping the screen where you want to place next point.
Related
I am new in OpenGl Devloper,i want to render 3d model in OpenGl android so i choose min3d framework library.
I want to Pan Zoom in zoom out functionality for my model ,like camera zoom in zoom out in min3d
like , i have 3dmodel of lady and i want to zoom out her face any solution without scale object?
You need to change the camera position. I suggest you define some additional parameters center and distance since you want to pan.
When you have a zoom gesture you simply apply zoom scale to distance distance *= scale (or distance = originalDistance*scale depending on the implementation).
On pan you simply move the center by distances center.x += (newXOnScreen-oldXOnScreen)*speedFactor and center.y += (newYOnScreen-oldYOnScreen)*speedFactor. The speed factor may be constant here (play around a bit with it) but it might be best to multiply it by a zoom scale as well so that if it is very close the center will move less.
Now that you have these 2 parameters you need to apply them to the camera. Assuming you have a model position at (0,0,0):
scene.camera.position = {center.x, center.y, center.z-distance}
scene.camera.target = {center.x, center.y, center.z}
scene.camera.up = {0, 1, 0}
The following code snippet worked for me. It is not the complete code, but I have just added the part which does the pinch zoom and drag of the 3d object in min3d framework. I put together the code by following online tutorials from here and modified according to the application
//import statements
public class threedviewActivity extends RendererActivity {
private Object3dContainer Object3D;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f,mLastTouchX,mLastTouchY,mPosX,mPosY;
private int mActivePointerId = INVALID_POINTER_ID,flag;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mScaleDetector = new ScaleGestureDetector(threedviewActivity.this, new ScaleListener());
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = MotionEventCompat.getActionMasked(ev);
switch (action) {
case MotionEvent.ACTION_DOWN: {
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
final float x = MotionEventCompat.getX(ev, pointerIndex);
final float y = MotionEventCompat.getY(ev, pointerIndex);
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
updateScene();
break;
}
case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
final float x = MotionEventCompat.getX(ev, pointerIndex);
final float y = MotionEventCompat.getY(ev, pointerIndex);
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
// Remember this touch position for the next move event
mLastTouchX = x;
mLastTouchY = y;
flag = 1;
updateScene();
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
final int pointerId = MotionEventCompat.getPointerId(ev, 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 = MotionEventCompat.getX(ev, newPointerIndex);
mLastTouchY = MotionEventCompat.getY(ev, newPointerIndex);
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
}
break;
}
}
return true;
}
#Override
public void initScene()
{
//this is where you initialize your 3d object. Check below for links for tutorials on that.
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
Object3D.scale().x = Object3D.scale().y = Object3D.scale().z = mScaleFactor*1.5f;
flag = 0;
updateScene();
return true;
}
}
#Override
public void updateScene()
{
if(flag == 1)
{
Object3D.position().x = mPosX/100;
Object3D.position().y = -mPosY/100;
}
}
}
For initalizing min3D, follow the tutorials here and here
I am trying to develop a simple game wherein I need to throw a bullet .
I would like the ball follows the touch, or swipe direction.
However, I have a small problem that I have not had success in solving.
I take coordinates on the ACTION_DOWN of MotionEvent, and the coordinates on the ACTION_UP of MotionEvent, then calculate the straight line equation in order to move the ball according to this straight line.
The problem is that when I swipe in a direction close to "up" or "forward" or "in front of", the ball moves at lightning speed while in the other direction of more skewed (right or left) or diagonal, the ball moves at a normal speed.
Where is the flaw in my calculation?
Help me please, I am not far from the result but need to you for solve this problem!
The onTouch method:
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction()) {
case(MotionEvent.ACTION_DOWN):
balle.setX(event.getX());
balle.setY(event.getY());
ya = event.getY();
xa = event.getX();
break;
case(MotionEvent.ACTION_UP):
xb = event.getX();
yb = event.getY();
balle.setMove(true);
break;
}
return true;
}
This is my moveDirection method:
public void moveDirection(float xa, float ya, float xb, float yb) {
if(!move) {
return;
}
else {
float m, b;
float dx = xb-xa;
m = (yb - ya) / (xb - xa);
b = ya - (m * xa);
if(dx > 0) {
this.x += speedX;
}
else {
this.x += -speedX;
}
this.y = (m * this.x + b);
}
}
Thank you in advance!
I see you are not capturing all the events so, maybe the code from the Android Documentation with de VelocityTracker api may help, in this example when you pull down your finger, a new tracker is created and when you move (in any direction) you capture the velocity of the event, i think you can move the ball according with the velocity and direction of touch.
public class MainActivity extends Activity {
private static final String DEBUG_TAG = "Velocity";
...
private VelocityTracker mVelocityTracker = null;
#Override
public boolean onTouchEvent(MotionEvent event) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch(action) {
case MotionEvent.ACTION_DOWN:
if(mVelocityTracker == null) {
// Retrieve a new VelocityTracker object to watch the velocity of a motion.
mVelocityTracker = VelocityTracker.obtain();
}
else {
// Reset the velocity tracker back to its initial state.
mVelocityTracker.clear();
}
// Add a user's movement to the tracker.
mVelocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
// When you want to determine the velocity, call
// computeCurrentVelocity(). Then call getXVelocity()
// and getYVelocity() to retrieve the velocity for each pointer ID.
mVelocityTracker.computeCurrentVelocity(1000);
// Log velocity of pixels per second
// Best practice to use VelocityTrackerCompat where possible.
Log.d("", "X velocity: " +
VelocityTrackerCompat.getXVelocity(mVelocityTracker,
pointerId));
Log.d("", "Y velocity: " +
VelocityTrackerCompat.getYVelocity(mVelocityTracker,
pointerId));
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// Return a VelocityTracker object back to be re-used by others.
mVelocityTracker.recycle();
break;
}
return true;
}
}
Link for doc.
A little problem for you but Break point for me during the development of an application.
I have a background image of Layout in which I have a Zip(Cloth zip) in the middle and at the top of image.
I want to do the following some things:
get coordinates of center-point(that is the starting point of Touch) of that image where that zip exists.
On moving the finger down, getting the changed coordinates.
X coordinate should be constant after getting the mid point, means the user can only drag on the middle of the screen vertically.
So badly waiting for an expert response.
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int width = displaymetrics.widthPixels;
int center1 = (width/2) - (aspected touchable area you need);
int center2 = (width/2) + (aspected touchable area you need);
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//Logic for Zip motion
case MotionEvent.ACTION_UP:
//Logic for Zip motion
}
return false;
}
ive been trying to change the color of specific rects in an array of rects when i touch the screen but it doesnt seem to be working, heres my code:
public Paint blue = new Paint();
RandomColorGen rc;
ArrayList<Integer> colors = RandomColorGen.ColorList(5);
Random rand = new Random();
int columns = 50;
int rows = 50;
Rect square[][] = new Rect[rows][columns];
public boolean isTouched;
public Canvas canvas;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
for (int x = 0; x < rows; x++) {
for (int y = 0; y < columns; y++) {
square[x][y] = new Rect();
blue.setColor(colors.get(rand.nextInt(colors.size())));
blue.setStyle(Paint.Style.FILL);
square[x][y].set(0, 0, (canvas.getWidth() - 10) / rows,
((canvas.getHeight() - 100) / columns));
square[x][y].offsetTo(x * ((canvas.getWidth() - 10) / rows), y
* ((canvas.getHeight() - 100) / columns));
canvas.drawRect(square[x][y], blue);
}
}
if(isTouched){
blue.setColor(colors.get(rand.nextInt(colors.size())));
blue.setStyle(Paint.Style.FILL);
canvas.save();
canvas.clipRect(square[1][1]);
canvas.drawRect(square[1][1], blue);
canvas.restore();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isTouched = true;
break;
}
return true;
}
the colors.get() thingy is an arraylist of colors. am i taking the wrong approach?
How you are calling the paint function after the onTouch action performed...
OnTouch action is the first action so how do you call Paint() function??
I just tested your code, it works but there are couple of notes worth mentioning:
Allocating objects during drawing is a very bad behavior ( specially when allocating 50*50 ) ! consider moving the allocation code to the constructor and change position of the rectangles at the onDraw() method if you want to achieve the same behavior you have now.
Your usage for onTouchEvent() is not complete, you need to have the isTouched true as long as the user didn't raise his hand, which can be done as the following :
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isTouched = true;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isTouched = false;
break;
}
invalidate();
return true;
}
Also request a layout every time you receive a TouchEvent by using invalidate()
I have a puzzle game where pieces are dragged around the screen but can not overlap. If they attempt to overlap, their position is changed back to where they were not overlapping and the UI is redrawn with invalidate(). This is working well except when the activity is destroyed and rebuilt like when closing the app and restarting it or when the orientation is changed.
What seems to happen is that the position variables that I use for collisions (x,y,right,bottom, etc.) are not reset to how they were initialized in the constructor. Pieces collide with invisible objects, snap to seemingly random positions, or move erratically.
The only ways to fix it are to manually kill the app (like with a task killer) or re-install it. Then it will work fine until the game activity is created a second time. What am I doing wrong? Any ideas? Here's how the piece are added in the onCreate() inside my GameView class:
Pieces redtiki = new Pieces(this,0,0,R.drawable.tikired);
...
board.addView(redtiki);
And this is a portion of my Pieces class:
public class Pieces extends View{
private int x;
private int y;
private int width;
private int height;
private int right;
private int bottom;
private int initialX;
private int initialY;
private Bitmap sizedBitmap;
private Bitmap sourceBitmap;
private int boardSize = 6;
public static ArrayList<Pieces> aPieces = new ArrayList<Pieces>();
//private final Paint mPaint = new Paint();
public Pieces(Context context, int x, int y, int img){
super(context);
this.x = x;
this.y = y;
sourceBitmap = BitmapFactory.decodeResource(getResources(), img);
aPieces.add(this);
initialX=x;
initialY=y;
}
private void sizePiece(){
int scaledWidth;
int scaledHeight;
int h = sourceBitmap.getHeight();
int w = sourceBitmap.getWidth();
if (h>w){
scaledWidth = 1;
}else if (w>h){
scaledWidth = w/h;
}else{
scaledWidth = 0;
}
if (h>w){
scaledHeight = h/w;
}else if (w>h){
scaledHeight = 1;
}else{
scaledHeight = 0;
}
int dstWidth = (((((View) getParent()).getWidth())*scaledWidth)/boardSize)-1;//TODO make sure that -1 is necessary for
int dstHeight = (((((View) getParent()).getHeight())*scaledHeight)/boardSize)-1;//fitting all pieces on the board
sizedBitmap = Bitmap.createScaledBitmap(sourceBitmap, dstWidth, dstHeight, true);
width = sizedBitmap.getWidth();
height = sizedBitmap.getHeight();
right = x+width;
bottom = y+height;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
sizePiece();
canvas.drawBitmap(sizedBitmap, x, y, null);
}
#Override
public boolean onTouchEvent(MotionEvent event){
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//check if touch is on piece
if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height)){
initialX=x;
initialY=y;
break;
}else{
return false;
}
case MotionEvent.ACTION_MOVE:
//determine if piece should move horizontally or vertically
if(width>height){
for (Pieces piece : aPieces) {
//if object equals itself in array, skip to next object
if(piece==this){
continue;
}
//check if there the possibility for a horizontal collision
if(this.isAllignedHorizontallyWith(piece)){
//check for and handle collisions while moving left
if(this.isRightOf(piece)){
if(eventX>piece.right+(width/2)){
x = (int)(eventX-(width/2)); //move normally
/*for(Pieces piece2 : aPieces){
if(this.isAllignedHorizontallyWith(piece2)){
if(this.isLeftOf(piece2)){
if(eventX<piece2.x-(width/2)){
x = (int)(eventX-(width/2));
continue;
}else{
x = piece2.x-width-1;
}
}
}
}*/
continue;
}else{
x = piece.right+1;
}
}
//check for and handle collisions while moving right
if(this.isLeftOf(piece)){
if(eventX<piece.x-(width/2)){
x = (int)(eventX-(width/2));
continue;
}else{
x = piece.x-width-1;
}
}
break;
}else{
x = (int)(eventX-(width/2));
}
}
}
if(height>width){
for (Pieces piece : aPieces) {
//if object equals itself in array, skip to next object
if(piece==this){
continue;
}
//check if there the possibility for a vertical collision
if(this.isAllignedVerticallyWith(piece)){
//check for and handle collisions while moving up
if(this.isBelow(piece)){
if(eventY>piece.bottom+(height/2)){
y = (int)(eventY-(height/2)); //move normally
continue;
}else{
y = piece.bottom+1;
}
}
//check for and handle collisions while moving down
if(this.isAbove(piece)){
if(eventY<piece.y-(height/2)){
y = (int)(eventY-(height/2));
continue;
}else{
y = piece.y-height-1;
}
}
break;
}else{
y = (int)(eventY-(height/2));
}
}
}
invalidate();
break;
case MotionEvent.ACTION_UP:
// end move
if(this.moves()){
GameView.counter++;
}
initialX=x;
initialY=y;
break;
}
// parse puzzle
invalidate();
return true;
}
In your Activity class, implement the methods OnPause(), OnResume().
Use log statements within the above mentioned methods to see whether the positions/coordinates are changed during the closing/opening of the app.
You can save the state of the various components when "OnPause()" is called. When "OnResume()" is invoked (i.e application comes to the foreground) read the saved state and draw the View with the coordinates you read recently.
Please not that "OnCreate()" will only be called once when the Activity is being created. Switching orientations will not invoked "OnCreate()"
You will find a flowchart explaining the Android API documentation.
http://developer.android.com/reference/android/app/Activity.html
I just realized what was wrong. Each time that I create a new Pieces object, it is added to my ArrayList, aPieces. So every time that the orientation changed, or I loaded a new level, it would load all my new pieces and display them, but my old pieces were still in the ArrayList and, therefore, still being checked for collisions. to solve this, before I load each new level (and all the pieces that make up the level), I clear the list with Pieces.aPieces.clear();. Now, it works perfectly.