Mar 23, 2012

Gestures detection and canvas scale, translate and rotate.

Further works on previous SurfaceView Game step-by-step: react device movement/orientation using accelerometer; in this article we are going to implement GestureOverlayView to detect gestures input, and apply scale, translate and rotate on canvas accordingly.

Gestures detection and canvas scale, translate and rotate.

- In order to make it simple, disable Sensor function, comment the myAccelerometer related code in MyGameActivity.java.

- Create gestures of up/down/left/right, clockwise/anti-clockwise, enlarge/reduce, refer to the article Gestures Builder: create your gestures library. And copy the generated file to /res/raw folder.
(May be I build the Gestures too simple, the detection is not accurate. You are advised to create your own.)

Gestures Builder

- Modify main.xml to add android.gesture.GestureOverlayView.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

<com.MyGame.MyGameSurfaceView
android:id="@+id/myview1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<com.MyGame.MyForeground
android:id="@+id/myforeground"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

<android.gesture.GestureOverlayView
android:id="@+id/gestures"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gestureStrokeType="multiple"
android:eventsInterceptionEnabled="true"/>

</FrameLayout>
</LinearLayout>


- Modify MyGameActivity.java to handle Gesture.
package com.MyGame;

import java.util.ArrayList;

import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.gesture.Prediction;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.SurfaceView;
import android.widget.Toast;

public class MyGameActivity extends Activity {

MyGameSurfaceView myGameSurfaceView1;
MyForeground myForeground;

//MyAccelerometer myAccelerometer;

GestureLibrary gestureLibrary = null;
GestureOverlayView gestureOverlayView;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myGameSurfaceView1 = (MyGameSurfaceView)findViewById(R.id.myview1);
myForeground = (MyForeground)findViewById(R.id.myforeground);

//Set myForeground using transparent background
myForeground.setZOrderOnTop(true);
myForeground.getHolder().setFormat(PixelFormat.TRANSPARENT);

//myAccelerometer = new MyAccelerometer(this);

gestureOverlayView = (GestureOverlayView)findViewById(R.id.gestures);
gestureLibrary = GestureLibraries.fromRawResource(this, R.raw.gestures);
gestureLibrary.load();
gestureOverlayView.addOnGesturePerformedListener(gesturePerformedListener);

}

OnGesturePerformedListener gesturePerformedListener
= new OnGesturePerformedListener(){

@Override
public void onGesturePerformed(GestureOverlayView view, Gesture gesture) {
ArrayList<Prediction> prediction = gestureLibrary.recognize(gesture);

if(prediction.size() > 0){
String gesturePerformed = prediction.get(0).name;
if(gesturePerformed.equals("up")){
myForeground.canvasUp();
Toast.makeText(MyGameActivity.this,
"up", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("down")){
myForeground.canvasDown();
Toast.makeText(MyGameActivity.this,
"down", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("left")){
myForeground.canvasLeft();
Toast.makeText(MyGameActivity.this,
"left", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("right")){
myForeground.canvasRight();
Toast.makeText(MyGameActivity.this,
"right", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("clockwise")){
myForeground.canvasClockwise();
Toast.makeText(MyGameActivity.this,
"clockwise", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("anti-clockwise")){
myForeground.canvasAntiClockwise();
Toast.makeText(MyGameActivity.this,
"anti-clockwise", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("enlarge")){
myForeground.canvasEnlarge();
Toast.makeText(MyGameActivity.this,
"enlarge", Toast.LENGTH_LONG).show();
}else if(gesturePerformed.equals("reduce")){
myForeground.canvasReduce();
Toast.makeText(MyGameActivity.this,
"reduce", Toast.LENGTH_LONG).show();
}
}

}

};

@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
myGameSurfaceView1.MyGameSurfaceView_OnResume();
myForeground.MyGameSurfaceView_OnResume();

//myAccelerometer.registerListener();

}

@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
myGameSurfaceView1.MyGameSurfaceView_OnPause();
myForeground.MyGameSurfaceView_OnPause();

//myAccelerometer.unregisterListener();
}

void updateAccelerometer(float tx, float ty){
int w = myForeground.getWidth();
int h = myForeground.getHeight();

float x = ((w/2) * tx) + (w/2);
float y = ((h/2) * ty) + (h/2);
myForeground.updateAccelerometer(x, y);
}

}


- Modify MyForeground.java to handle canvas scale, translate and rotate.
package com.MyGame;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;

public class MyForeground extends MyGameSurfaceView {

Sprite mySprite;

float canvasScaleX = 1.0f;
float canvasScaleY = 1.0f;
float canvasTranslateX = 0.0f;
float canvasTranslateY = 0.0f;
float canvasRotate = 0.0f;

public MyForeground(Context context) {
super(context);
init();
}

public MyForeground(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public MyForeground(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

private void init(){
mySprite = new Sprite(
BitmapFactory.decodeResource(getResources(), R.drawable.icon_me),
100, 100);
}

@Override
protected void onDraw(Canvas canvas) {
//Clear Canvas with transparent background
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);

canvas.scale(canvasScaleX, canvasScaleY);
canvas.translate(canvasTranslateX, canvasTranslateY);
canvas.rotate(canvasRotate, mySprite.getX(), mySprite.getY());
mySprite.draw(canvas);

}

@Override
public void updateStates() {
// TODO Auto-generated method stub
mySprite.update();
}

void updateAccelerometer(float tx, float ty){
mySprite.setX((int)tx);
mySprite.setY((int)ty);
}

public void canvasUp(){
canvasTranslateY -= 10.0f;
}

public void canvasDown(){
canvasTranslateY += 10.0f;
}

public void canvasLeft(){
canvasTranslateX -= 10.0f;
}

public void canvasRight(){
canvasTranslateX += 10.0f;
}

public void canvasClockwise(){
canvasRotate += 10.0f;
}

public void canvasAntiClockwise(){
canvasRotate -= 10.0f;
}

public void canvasEnlarge(){
canvasScaleX *= 2.0f;
canvasScaleY *= 2.0f;
}

public void canvasReduce(){
canvasScaleX /= 2.0f;
canvasScaleY /= 2.0f;
}

}



The code can be download here:
https://sites.google.com/site/helloandroidingcoding/download/MyGame_20120324.zip?attredirects=0&d=1

2 comments:

  1. I downloaded the project files, added as a project to Eclipse, targeted Android 2.2 and the application always quits unexpectedly upon launch... Any ideas why it could be?

    ReplyDelete
  2. It is working, I used 4.1.2 API level.

    ReplyDelete

Infolinks In Text Ads