אחרי שהכרנו כיצד לבנות ולצבוע אובייקטים השלב הבא הוא תנועה במרחב של המנוע אבל לפני שניכנס לכפתורים ולממשק המשתמש נתחיל דווקא עם החיישנים שנמצאים בכל מכשיר מתקדם, אבל חשוב לזכור שהם משתנים ממכשיר למכשיר ולא זמינים בכולם.
שימו לב! - המאמר מתבסס על Samsung Galaxy S3 שבו יש Gyroscope מובנה.
Gyroscope
מכשיר מדידה שמאפשר לחשב את זווית הסטייה כאשר הגוף לא במצב אופקי, כלומר כל הטיה של המכשיר תשנה את המיקום על 3 הצירים התלת מימדיים (X,Y,Z), על מנת להפעיל אותו ב Android עלינו להשתמש במספר מחלקות שיעשנו לנו את העבודה עבור כל החיישנים שנראה במאמרים הבאים:
private Sensor mSensor;
אובייקטים שמייצגים את החיישנים.
mSensorManager = (SensorManager)con.getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
מבקשים את השירות של החיישנים במערכת, מתחברים לחיישן ספציפי שבמקרה שלנו הוא ה Gyroscope אבל ניתן לקבל חיישנים נוספים כמו: Accelerometer, Ambient Temperature,Gravity ועוד (לרשימה המלאה).
לאחר מכן מתחברים ל Event של החיישן בעזרת SensorEventListener ודוגמים אותו, השתמשתי בהגדרה קיימת במערכת שמתאימה למשחקים ודוגמת את החיישן כל 20 ms.
mSensorManager.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
}, mSensor, SensorManager.SENSOR_DELAY_GAME);
OpenGL
אחד השינויים הוא בפונקציה Draw של האובייקט שמוכרת מהמאמרים האחרונים בנושא, נוספו 3 פרמטרים עבור X,Y,Z שאותם נשלח ל OpenGL בעזרת הפונקציה glTranslatef.
public void draw(float x,float y,float z)
{
//set gl focus to cube
gl.glLoadIdentity();
gl.glTranslatef(x, y, z);
//...
}
קוד
דגימת החיישן מתבצעת ה GLSurfaceView.Renderer בעזרת EventListener שממתין לאירוע מהחיישן ומעדכן פרמטרים גלובלים במחלקה שנשלחים אח"כ לפונקציה Draw של האובייקט.
package com.example.openglgyroscope;
import java.text.DecimalFormat;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
public class OpenGLSensorRender implements GLSurfaceView.Renderer {
private CubeNaked mCube;
//remember the last values of the Axis
private float mLastX = 0, mLastY = 0, mLastZ = 0;
Context con;
private SensorManager mSensorManager;
private Sensor mSensor;
public OpenGLSensorRender(Context _con)
{
con = _con;
mSensorManager = (SensorManager)con.getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
mSensorManager.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
//taking sample from the sensor
DecimalFormat _fp = new DecimalFormat("#.#");
float x = Float.valueOf( _fp.format(event.values[0]));
float y = Float.valueOf( _fp.format(event.values[1]));
float z = Float.valueOf( _fp.format(event.values[2]));
mLastX = mLastX + x;
mLastY = mLastY+ y;
//not in use for now
//mLastZ = z;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}, mSensor, SensorManager.SENSOR_DELAY_GAME);
}
@Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
//draw the cube ,sending the new axis
mCube.draw(mLastX,mLastY,mLastZ);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
//enter to Perspective Projection Mode Settings
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f,
100.0f);
gl.glViewport(0, 0, width, height);
//enter to ModelView Projection Mode Settings
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
// TODO Auto-generated method stub
//clear the suraface color to black
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
gl.glClearDepthf(1.0f);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
mCube = new CubeNaked(gl);
}
}
סרט הדגמה
קבצי מקור
סיכום:
עבודה עם חיישנים נפוצה מאוד במיוחד במשחקים, הם מאפשרים לנו לשלוט על האובייקטים במשחק מבלי שנצטרך לגעת במסך שגם ככה יחסית קטן וחוסכים לנו ממשק משתמש שמתלבש על המסך שעלול להסתיר חלקים מהמשחק, אבל צריך להתרגל לצורת המשחק החדשה ולא תמיד זה נוח למי שרגיל לכפתורים הסטנדרטים.
שחק איתו!
אין תגובות:
הוסף רשומת תגובה