1. 程式人生 > >min3d引擎使用指南(Android stdio)<一>

min3d引擎使用指南(Android stdio)<一>

嘗試著把min3d引擎移植到android stdio上開發,開始的時候遇到不少問題,所以在CSDN上開個帖。同時感謝美麗同事XY的幫忙。


第一個問題:一開始把min3d包匯入Android stdio後,在MainActivity中提示“improt unused imports statement”,然後聲明瞭物件,也同樣沒用。

後來上谷歌查了不少資料,在另一篇CSDN部落格上找到了一項設定:

然後點 ok,這樣 Android stdio就懂得自動匯入響應的包。import就不會報錯了。


第二個問題:在Android stdio上新建的空工程,public class MainActivity extends AppCompatActivity。而min3d要顯示跑起來,需要繼承的是RendererActivity。所以修改的程式碼如下:


package com.example.zk.min3d_demo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;

import min3d.animation.AnimationObject3d;
import min3d.core.Object3dContainer;
import min3d.core.RendererActivity;
import min3d.objectPrimitives.Box;
import min3d.parser.IParser;
import min3d.parser.Parser;
import min3d.vos.Light;

public class MainActivity extends RendererActivity {
//public class MainActivity extends AppCompatActivity {
    Object3dContainer faceObject3D;     //3D物件
    private AnimationObject3d ogre;
    private RockerView rockerView1;
    float modelx = 0;
    float modely = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        //frame3dView
        FrameLayout ll = (FrameLayout) this.findViewById(R.id.frame3dView);
        //在xml中,指定顯示的控制元件,這裡是一個FrameLayout。
        ll.addView(_glSurfaceView);//加入到_glSurfaceView中顯示。

        rockerView1 = (RockerView) findViewById(R.id.rockerView1);
        rockerView1.setRockerChangeListener(new RockerView.RockerChangeListener() {

            @Override
            public void report(float x, float y) {
                // TODO Auto-generated method stub
                modelx = x/1000;
                modely = y/1000;
            }
        });

    }

    public void initScene() {
        scene.lights().add(new Light());

        IParser parser = Parser.createParser(Parser.Type.MD2,
                getResources(), "com.example.zk.min3d_demo:raw/ogro", false);
        parser.parse();

        ogre = parser.getParsedAnimationObject();
        ogre.scale().x = ogre.scale().y = ogre.scale().z = .07f;
        ogre.rotation().z = -90;
        ogre.rotation().x = -90;
        scene.addChild(ogre);
        ogre.setFps(70);
        ogre.play();
    }

    public void updateScene() {
        //     faceObject3D.rotation().x++;//圍繞著X軸旋轉,正數為順時針,速度由X的數值變化決定
        ogre.rotation().x +=modelx;//設定初始位置,平截頭體中xyz的座標位置
        ogre.position().y +=modely;
    }
}
下面的xml檔案,就是美麗的同事幫我弄好的。
<?xml version="1.0" encoding="utf-8"?>
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.zk.min3d_demo.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/textView" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/textView"
        android:id="@+id/frame3dView"
        android:layout_alignParentStart="true">


    </FrameLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal|top">
        <com.example.zk.min3d_demo.RockerView
            android:id="@+id/rockerView1"
            android:layout_width="120dp"
            android:layout_height="120dp"
            android:layout_marginLeft="20dp"
            android:layout_alignParentTop="true"
            android:layout_alignParentEnd="true" />
    </RelativeLayout>
</RelativeLayout>

裡面的搖桿控制元件,要用到下面這個Java類

package com.example.zk.min3d_demo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;

/**
 * Created by zk on 2016/11/24.
 */
public class RockerView extends View {
    //固定搖桿背景圓形的X,Y座標以及半徑
    private float mRockerBg_X;
    private float mRockerBg_Y;
    private float mRockerBg_R;
    //搖桿的X,Y座標以及搖桿的半徑
    private float mRockerBtn_X;
    private float mRockerBtn_Y;
    private float mRockerBtn_R;
    private Bitmap mBmpRockerBg;
    private Bitmap mBmpRockerBtn;

    private PointF mCenterPoint;

    public RockerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        // 獲取bitmap
        mBmpRockerBg = BitmapFactory.decodeResource(context.getResources(), R.drawable.rocker_bg);
        mBmpRockerBtn = BitmapFactory.decodeResource(context.getResources(), R.drawable.rocker_btn);

        getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

            // 呼叫該方法時可以獲取view實際的寬getWidth()和高getHeight()
            @Override
            public boolean onPreDraw() {
                // TODO Auto-generated method stub
                getViewTreeObserver().removeOnPreDrawListener(this);

                Log.e("RockerView", getWidth() + "/" +  getHeight());
                mCenterPoint = new PointF(getWidth() / 2, getHeight() / 2);
                mRockerBg_X = mCenterPoint.x;
                mRockerBg_Y = mCenterPoint.y;

                mRockerBtn_X = mCenterPoint.x;
                mRockerBtn_Y = mCenterPoint.y;

                float tmp_f = mBmpRockerBg.getWidth() / (float)(mBmpRockerBg.getWidth() + mBmpRockerBtn.getWidth());
                mRockerBg_R = tmp_f * getWidth() / 2;
                mRockerBtn_R = (1.0f - tmp_f)* getWidth() / 2;

                return true;
            }
        });


        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                while(true){

                    //系統呼叫onDraw方法重新整理畫面
                    RockerView.this.postInvalidate();

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        canvas.drawBitmap(mBmpRockerBg, null,
                new Rect((int)(mRockerBg_X - mRockerBg_R),
                        (int)(mRockerBg_Y - mRockerBg_R),
                        (int)(mRockerBg_X + mRockerBg_R),
                        (int)(mRockerBg_Y + mRockerBg_R)),
                null);
        canvas.drawBitmap(mBmpRockerBtn, null,
                new Rect((int)(mRockerBtn_X - mRockerBtn_R),
                        (int)(mRockerBtn_Y - mRockerBtn_R),
                        (int)(mRockerBtn_X + mRockerBtn_R),
                        (int)(mRockerBtn_Y + mRockerBtn_R)),
                null);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {
            // 當觸屏區域不在活動範圍內
            if (Math.sqrt(Math.pow((mRockerBg_X - (int) event.getX()), 2) + Math.pow((mRockerBg_Y - (int) event.getY()), 2)) >= mRockerBg_R) {
                //得到搖桿與觸屏點所形成的角度
                double tempRad = getRad(mRockerBg_X, mRockerBg_Y, event.getX(), event.getY());
                //保證內部小圓運動的長度限制
                getXY(mRockerBg_X, mRockerBg_Y, mRockerBg_R, tempRad);
            } else {//如果小球中心點小於活動區域則隨著使用者觸屏點移動即可
                mRockerBtn_X = (int) event.getX();
                mRockerBtn_Y = (int) event.getY();
            }
            if(mRockerChangeListener != null) {
                mRockerChangeListener.report(mRockerBtn_X - mCenterPoint.x, mRockerBtn_Y - mCenterPoint.y);
            }
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            //當釋放按鍵時搖桿要恢復搖桿的位置為初始位置
            mRockerBtn_X = mCenterPoint.x;
            mRockerBtn_Y = mCenterPoint.y;
            if(mRockerChangeListener != null) {
                mRockerChangeListener.report(0, 0);
            }
        }
        return true;
    }

    /***
     * 得到兩點之間的弧度
     */
    public double getRad(float px1, float py1, float px2, float py2) {
        //得到兩點X的距離
        float x = px2 - px1;
        //得到兩點Y的距離
        float y = py1 - py2;
        //算出斜邊長
        float xie = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        //得到這個角度的餘弦值(通過三角函式中的定理 :鄰邊/斜邊=角度餘弦值)
        float cosAngle = x / xie;
        //通過反餘弦定理獲取到其角度的弧度
        float rad = (float) Math.acos(cosAngle);
        //注意:當觸屏的位置Y座標<搖桿的Y座標我們要取反值-0~-180
        if (py2 < py1) {
            rad = -rad;
        }
        return rad;
    }

    /**
     *
     * @param R  圓周運動的旋轉點
     * @param centerX 旋轉點X
     * @param centerY 旋轉點Y
     * @param rad 旋轉的弧度
     */
    public void getXY(float centerX, float centerY, float R, double rad) {
        //獲取圓周運動的X座標
        mRockerBtn_X = (float) (R * Math.cos(rad)) + centerX;
        //獲取圓周運動的Y座標
        mRockerBtn_Y = (float) (R * Math.sin(rad)) + centerY;
    }

    RockerChangeListener mRockerChangeListener = null;
    public void setRockerChangeListener(RockerChangeListener rockerChangeListener) {
        mRockerChangeListener = rockerChangeListener;
    }
    public interface RockerChangeListener {
        public void report(float x, float y);
    }
}


還有一些資原始檔,我已經把整個工程上傳到CSDN,無積分。但還在稽核,通過後會把連結貼到這裡:

http://download.csdn.net/detail/zhangkun35268/9692440


效果動態圖: