MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

32
MobAppDev Touch Driving Drawings & Sprites Vladimir Kulyukin www.vkedco.blogspot.com

Transcript of MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Page 1: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

MobAppDev

Touch Driving Drawings & Sprites

Vladimir Kulyukin

www.vkedco.blogspot.com

Page 2: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Outline● Review● Touch Driving Drawings● Touch Driving Sprites

Page 3: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Brief Review

Page 4: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

MotionEvent● On Android, digital data from touchscreens are captured as

MotionEvent objects● MotionEvent objects are created when the user touches the device's

touchscreen● Each MotionEvent object contains the x and y coordinates (and

some other stats) of the captured touch● MotionEvent objects are handled by the View.onTouchEvent()

method

Page 5: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

MotionEvent Sequences

● When user places his/her finger, moves it (without lifting it up), and then lifts it up, a sequence of MotionEvent objects is generated

● Such sequences can be captured and used in touch gesture recognition

● Each MotionEvent object contains information on: 1) type of action captured (e.g., MotionEvent.ACTION_DOWN, MotionEvent.ACTION_UP, etc); 2) pressure value; 3) x and y coordinates; 4) time of event

Page 6: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

MotionEvent.getAction()

● MotionEvent.getAction() can be used to retrieve the type of action● Examples:

MotionEvent.getAction() returns ACTION_DOWN when user touches screen

MotionEvent.getAction() returns ACTION_MOVE when user moves sideways

MotionEvent.getAction() returns ACTION_UP when user lifts his/her finger

Page 7: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Interface View.OnTouchListener

● Classes the receive touchscreen events must implement View.OnTouchListener

● Two main methods to handle MotionEvents are: onTouch(View, MotionEvent) onTouchEvent(MotionEvent)

● onTouch(View, MotionEvent) is used when one OnTouchListener handles MotionEvents from multiple views

Page 8: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Touch Driving Drawings

Page 9: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Definition of Touch Driving

Touch driving is a touchscreen technique that allows the user to drive drawings and/or images (sprites) with his/her finger.

Page 10: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Problem

Develop an application that draws a 3x3 Tic Tac Toe Board, 2 red circles, and 2 blue crosses. The user can touch drive circles and crosses on the screen.

Source code of DrawTouchDrive app here

Page 11: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Screenshots

Initial Screenshot Touch Driving a Circle Touch Driving a Cross

Page 12: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Solution Outline

● Define a custom View object that extends the View class● This custom View class (TicTacToeView.java) handles

all touch events and does all drawing● All basic board geometry is abstracted in a separate

class (BoardGeometry.java)

Page 14: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

X & Y Offsets of a Circle DrawingX

y

ME's X

ME's Y

X Offset

Y Offset

final float me_x = me.getX();

final float me_y = me.getY();

final int action = me.getAction();

c.setActionDownX(c.getCurrentX());

c.setActionDownY(c.getCurrentY());

c.setActionMoveOffsetX(me_x);

c.setActionMoveOffsetY(me_y);

final float me_x = me.getX();

final float me_y = me.getY();

final int action = me.getAction();

c.setActionDownX(c.getCurrentX());

c.setActionDownY(c.getCurrentY());

c.setActionMoveOffsetX(me_x);

c.setActionMoveOffsetY(me_y);

me is a MotionEvent

c is a Circle

Page 15: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Custom View: TicTacToeView<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent" >

<org.vkedco.mobappdev.draw_touch_drive_00001.TicTacToeView

android:id="@+id/pntr"

android:tag="Painter"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

</RelativeLayout>

Page 16: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

TicTacToeView.euclidDistance()

// TicTacToeView uses Euclidean Distance to find closest objects

private static float euclidDist(float x1, float y1, float x2, float y2)

{

return android.util.FloatMath.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));

}

Page 17: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

TicTacToeView: Member Variablespublic class TicTacToeView extends View {

// define background and foreground paints

final Paint mBackgroundPaint;

final Paint mForeCirclePaint;

final Paint mForeCrossPaint;

final Paint mForeBoardPaint;

// define a BoardGeometry object

final BoardGeometry mBoardGeometry;

// define arrays of circles and crosses

ArrayList<Circle> mCircles;

ArrayList<Cross> mCrosses;

}

Page 18: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

TicTacToeView: Construction of Circles & Crossespublic class TicTacToeView extends View {

// placing circles and crosses to their start x's & y's

private void createCircles() {

mCircles = new ArrayList<Circle>();

mCircles.add(new Circle(30, 30, 20));

mCircles.add(new Circle(120, 30, 20));

}

private void createCrosses() {

mCrosses = new ArrayList<Cross>();

mCrosses.add(new Cross(30, 350, 20));

mCrosses.add(new Cross(120, 350, 20));

}

}

public class TicTacToeView extends View {

// placing circles and crosses to their start x's & y's

private void createCircles() {

mCircles = new ArrayList<Circle>();

mCircles.add(new Circle(30, 30, 20));

mCircles.add(new Circle(120, 30, 20));

}

private void createCrosses() {

mCrosses = new ArrayList<Cross>();

mCrosses.add(new Cross(30, 350, 20));

mCrosses.add(new Cross(120, 350, 20));

}

}

Page 19: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Handling MotionEvents

● Get the x and y coordinates of a MotionEvent ME● Find a circle C closest to ME● Find a cross X closest to ME● If the Euclidean distance from ME to the closest circle C is smaller than

the Euclidean distance from ME to the closest cross X, then assume that the circle C was touched and handle it (redraw it at ME's x and y); otherwise, assume that the cross was touched and handle it

Page 20: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

TicTacToeView: Handling MotionEventspublic boolean onTouchEvent(MotionEvent event) {

// 1. get the x and y of MotionEvent

float x = event.getX(); float y = event.getY();

// 2. find circle closest to x and y

Circle cr = findCircleClosestToTouchEvent(x, y);

// 3. find cross closest to x and y

Cross cx = findCrossClosestToTouchEvent(x, y);

// 4. compute euclid distances to find which is

// closer - circle or cross

float dtcr = euclidDist(cr.getCurrentX(), cr.getCurrentY(), x, y);

float dtcx = euclidDist(cx.getMidX(), cx.getMidY(), x, y);

// 5. if distance to closest circle is smaller

// handle the circle; otherwise, handle the cross

if (dtcr < dtcx) { handleTouchedCircle(event, cr); }

else { handleTouchedCross(event, cx); }

return true;

}

Page 21: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Drawing the Canvas● Draw the background rectangle over the entire canvas● Draw the TicTacToe board (horizontal and vertical lines)● Draw the circles● Draw the crosses● Invalidate the canvas object to force it to redraw

Page 22: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

TicTacToeView: Canvas Drawing public void draw(Canvas canvas) {

if ( mDrawingEnabled ) {

final int width = canvas.getWidth(); final int height = canvas.getHeight();

// 1. draw background rectangle that covers the entire canvas

canvas.drawRect(0, 0, width, height, mBackgroundPaint);

// 2. draw board on the canvas

drawBoard(canvas);

// 3. draw red circles on canvas

drawCirclesOnCanvas(canvas);

// 4. draw blue crosses on canvas

drawCrossesOnCanvas(canvas);

// 5. force redraw

invalidate();

}

}

Page 23: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Touch Driving Sprites

Page 24: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Problem

Develop an application that displays 3 black chess pieces above and 3 white chess pieces below. The application allows the user to touch drive the black chess pieces down. If a black chess piece is driven close to a white chess piece, the white chess piece jumps on the black chess piece. The user's objective is to touch drive the black pieces down.

Source code of ImageTouchDrive is here

Page 25: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Screenshots

Initial Screen Piece Capture End Game

Page 26: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

Sprites

Black Bishop

Black King

Black Knight

White Bishop

White King

White Knight

I have taken these images from http://en.wikipedia.org/wiki/Chess

Page 27: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

ChessPiecepublic class ChessPiece {

final Bitmap mBitmap; // image of chess piece

float mStartX; // x of top left corner of bitmap

float mStartY; // y of top left corner of bitmap

float mCurrentX; // current x coordinate of ChessPiece

float mCurrentY; // current y coordinate of ChessPiece

float mActionDownX; // x coordinate of ChessPiece of an action down

float mActionDownY; // y coordinate of ChessPiece of an action down

float mActionMoveOffsetX; // x coordinate of a move action

float mActionMoveOffsetY; // y coordinate of a move action

float mEuclidDistThresh; // threshold to decide if motion event should be consumed

// rest of code

}

Page 28: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

ChessPiece Construction

public ChessPiece(Resources res, int res_id, float dthresh, float start_x, float start_y) {

mBitmap = BitmapFactory.decodeResource(res, res_id);

mStartX = start_x;

mStartY = start_y;

mCurrentX = start_x;

mCurrentY = start_y;

mEuclidDistThresh = dthresh;

}

Page 29: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

ChessPiece's Handling of Touch Events

void handleOnTouchEvent(MotionEvent me) {

final float me_x = me.getX(); final float me_y = me.getY();

final float left_x = mCurrentX; final float top_y = mCurrentY;

final float right_x = left_x + (float)mBitmap.getWidth();

final float bot_y = mCurrentY + (float)mBitmap.getHeight();

}

Page 30: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

ChessPiece's Handling of Touch Events

void handleOnTouchEvent(MotionEvent me) {

if ( euclidDist(left_x, top_y, me_x, me_y) > mEuclidDistThresh &&

euclidDist(right_x, top_y, me_x, me_y) > mEuclidDistThresh &&

euclidDist(left_x, bot_y, me_x, me_y) > mEuclidDistThresh &&

euclidDist(right_x, bot_y, me_x, me_y) > mEuclidDistThresh )

{ return; }

}

Page 31: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

ChessPiece's Handling of Touch Events

void handleOnTouchEvent(MotionEvent me) {

final int action = me.getAction();

switch ( action ) {

case MotionEvent.ACTION_DOWN:

this.setActionDownX(this.getCurrentX()); this.setActionDownY(this.getCurrentY());

this.setActionMoveOffsetX(me_x); this.setActionMoveOffsetY(me_y); break;

case MotionEvent.ACTION_MOVE:

case MotionEvent.ACTION_UP:

this.setCurrentX(this.getActionDownX() + me_x - this.getActionMoveOffsetX());

this.setCurrentY(this.getActionDownY() + me_y – this.getActionMoveOffsetY()); break;

case MotionEvent.ACTION_CANCEL: this.restoreInitialPosition(); break;}

}

Page 32: MobAppDev (Fall 2014): Touch Driving Drawings & Sprites

References ● en.wikipedia.org/wiki/Touchscreen

● http://developer.android.com/reference/android/view/MotionEvent.html

● http://developer.android.com/reference/android/view/View.OnTouchListener.html

● http://en.wikipedia.org/wiki/Chess