---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei

转载请注明出处,本文作者:秦元培, 本文出处:http://blog.csdn.net/qinyuanpei/article/details/39717795

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

各位朋友大家好,我是秦元培。欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei。首先祝大家能够度过一个愉快的十一长假。

今天呢,博主将为大家送上Unity-Android系列的最后一篇文章《Unity3D游戏开发之从Unity3D到Eclipse》。通过前面的学习。大家已经知道通过在Eclipse中为Unity编写插件的方法,我们能够实如今Unity与Android API的通信。但是不幸的是,这样的方法并不能对全部的Android API奏效,在某些时候,我们须要反客为主,将Unity项目导出为Android项目,然后在Eclipse中继续改动游戏的内容。这样的方法在《Unity3D游戏开发之Unity与Android交互调用研究》这篇文章中已经提及,只是并没有真正地进行过研究。

之前有个叫@SHANlover的朋友问我,能不能写一篇Unity项目导出Eclipse的文章,因此博主便抽出时间研究了下这样的方法。从而有了今天的这篇文章。

首先,我们来创建一个简单地场景:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWlueXVhbnBlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

好了,创建完场景以后我们就能够直接编写一个脚本CubeScripts.cs来控制场景中的Cube:

using UnityEngine;
using System.Collections; public class CubeScripts : MonoBehaviour { /// <summary>
/// 定义旋转速度
/// </summary>
public float RotateSpeed=45; /// <summary>
/// 定义摄像机的近期距离
/// </summary>
private float mNear=2.5F; /// <summary>
/// 摄像机当前距离
/// </summary>
private float mDistance=5F; /// <summary>
/// 定义摄像机的最远距离
/// </summary>
private float mFar=7.5F; /// <summary>
/// 摄像机的缩放速率
/// </summary>
private float mZoomRate=0.5F; /// <summary>
/// 主摄像机
/// </summary>
private Transform mCamera; /// <summary>
/// 在Start()方法中我们设定了游戏体的名称,由于我们在
/// Android项目中须要用到这个名称,同一时候获取主相机对象
/// </summary>
void Start ()
{
this.name="Main Cube";
mCamera=Camera.main.transform;
} /// <summary>
/// 在Update()方法中我们让Cube依照一定的速度进行旋转
/// </summary>
void Update ()
{
transform.Rotate(Vector3.up * Time.deltaTime * RotateSpeed);
} /// <summary>
/// 定义一个放大的方法供外部调用
/// </summary>
public void ZoomIn()
{
mDistance-=mZoomRate;
mDistance=Mathf.Clamp(mDistance,mNear,mFar);
mCamera.position=mCamera.rotation * new Vector3(0,0,-mDistance)+transform.position;
} /// <summary>
/// 定义一个缩小的方法供外部调用
/// </summary>
public void ZoomOut()
{
mDistance+=mZoomRate;
mDistance=Mathf.Clamp(mDistance,mNear,mFar);
mCamera.position=mCamera.rotation * new Vector3(0,0,-mDistance)+transform.position;
}
}

这段脚本十分地简单。没有什么可说的,在这里我们定义了两个方法ZoomIn和ZoomOut。这两个方法我们将提供给Android来调用。

我们将这段脚本绑定到Main Cube这个对象上。接下来,我们将项目Build一下,这里我们将项目的PackageName设为com.android.unity2eclipse,然后将其导出为一个Android项目:

那么。这样我们就得到一个能够在Eclipse中打开的Android项目。

但是这个Android项目我们怎么样使用呢?在金曾玺老师《Unity3D手机游戏开发》一书中是将Unity导出的Android项目作为一个库,然后再用一个新的Android项目去调用这个库。这本书中所使用的Unity版本号是4.X,而博主所使用的Unity版本号是4.5.1。最初博主就是依照这样的思路去编写Android程序,但是在经历了无数次的失败后。博主開始怀疑这样的方法的正确性。带着尝试的念头,博主直接执行了由Unity导出的Android项目。结果程序成功地在手机上执行了。

如图:

那么。接下来我们最好还是冷静地分析下从Unity导出的这个Android项目,我们能够看到整个项目的目录结构是这样的:

在这个目录结构中,我们能够看到它是一个标准的Android项目。在libs中的unity-class.jar就是我们在前面的文章中所使用过的jar库文件。而在assets目录中我们能够看到Unity所依赖的dll文件。在com.android.unity2eclipse这个Package中。我们会发现一个名为UnityPlayerNativeActivity.class的类,该类定义例如以下:

package com.android.unity2ecplise;

import com.unity3d.player.*;
import android.app.NativeActivity;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Window;
import android.view.WindowManager; public class UnityPlayerNativeActivity extends NativeActivity
{
protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code // Setup activity layout
@Override protected void onCreate (Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState); getWindow().takeSurface(null);
setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);
getWindow().setFormat(PixelFormat.RGB_565); mUnityPlayer = new UnityPlayer(this);
if (mUnityPlayer.getSettings ().getBoolean ("hide_status_bar", true))
getWindow ().setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(mUnityPlayer);
mUnityPlayer.requestFocus();
} // Quit Unity
@Override protected void onDestroy ()
{
mUnityPlayer.quit();
super.onDestroy();
} // Pause Unity
@Override protected void onPause()
{
super.onPause();
mUnityPlayer.pause();
} // Resume Unity
@Override protected void onResume()
{
super.onResume();
mUnityPlayer.resume();
} // This ensures the layout will be correct.
@Override public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
mUnityPlayer.configurationChanged(newConfig);
} // Notify Unity of the focus change.
@Override public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
mUnityPlayer.windowFocusChanged(hasFocus);
} // For some reason the multiple keyevent type is not supported by the ndk.
// Force event injection by overriding dispatchKeyEvent().
@Override public boolean dispatchKeyEvent(KeyEvent event)
{
if (event.getAction() == KeyEvent.ACTION_MULTIPLE)
return mUnityPlayer.injectEvent(event);
return super.dispatchKeyEvent(event);
} // Pass any events not handled by (unfocused) views straight to UnityPlayer
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); }
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); }
@Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); }
/*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); }
}

相信大多数看过我博客的人都会认为这个类有点眼熟吧。不错,在之前的《Unity3D游戏开发之在Android视图中嵌入Unity视图》这篇文章中,我们就是利用这个类实现了在Android视图中嵌入Unity视图,仅仅只是当时这个类是定义在Unity的unity-class.jar这个库中的,而更为确切地位置是在com.unity3d.player这个包以下的UnityPlayerNativeActivity类,我们注意到此时这个类是继承自NativeActivity的,在前面的文章中博主以前提及这个类,它是Android提供给C/C++开发人员的接口。

换句话说。Unity项目在Android平台上内部依靠的实际上就是NativeActivity接口,仅仅只是Unity自己使用的接口是封装过的。而我们这里使用的接口是直接继承自父类。那么,我们在这一刻就会产生疑问。从这个类从详细实现上来讲基本的功能就是对Activity进行初始化,那么我们在Activity中能够看到什么由谁来决定呢?大家注意到这里有一个SetContentView()的方法。它传入了UnityPlayer类型的參数作为Activity显示的内容。相信从如今開始,大家对Unity提供的Android接口的认识会越来越清晰吧。

为了验证我们的想法,接下来。我们来创建一个布局文件activity_main。它的代码定义例如以下:

<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:orientation="vertical"
tools:context=".MainActivity" >
<Button
android:id="@+id/BtnZoomIn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="@string/ZoomIn" />
<LinearLayout
android:id="@+id/UnityView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/BtnZoomOut"
android:layout_below="@+id/BtnZoomIn"
android:orientation="vertical" >
</LinearLayout>
<Button
android:id="@+id/BtnZoomOut"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/ZoomOut" />
</RelativeLayout>

接下来,我们创建与之相应的Java类文件MainActivity.class:

package com.android.unity2ecplise;

import com.android.unity2ecplise.R;
import com.unity3d.player.UnityPlayer; import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout; /*我们这里让我们定义的MainActivity继承自Unity导出项目中的UnityPlayerNativeActivity*/
public class MainActivity extends UnityPlayerNativeActivity
{
private Button BtnZoomIn,BtnZoomOut; @Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取显示Unity视图的父控件
LinearLayout mParent=(LinearLayout)findViewById(R.id.UnityView);
//获取Unity视图
View mView=mUnityPlayer.getView();
//将Unity视图加入到Android视图中
mParent.addView(mView); //放大
BtnZoomIn=(Button)findViewById(R.id.BtnZoomIn);
BtnZoomIn.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
UnityPlayer.UnitySendMessage("Main Cube","ZoomIn","");
}
});
//缩小
BtnZoomOut=(Button)findViewById(R.id.BtnZoomOut);
BtnZoomOut.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
UnityPlayer.UnitySendMessage("Main Cube","ZoomOut","");
}
});
}
}

在这段代码中。我们通过UnitySendMessage调用了Unity中定义的两个方法ZoomIn、ZoomOut。好了,接下来。我们改动配置文件,使主Activity相应于MainActivity类,打开
AndroidManifest.xml文件:

<?

xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.unity2ecplise"
android:theme="@android:style/Theme.NoTitleBar"
android:versionName="1.0" android:versionCode="1"
android:installLocation="preferExternal">
<supports-screens android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true" />
<application android:icon="@drawable/app_icon"
android:label="@string/app_name"
android:debuggable="false">
<activity android:label="@string/app_name"
android:screenOrientation="fullSensor"
android:launchMode="singleTask"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
android:name="com.android.unity2ecplise.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
<meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
</activity>
</application>
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17" />
<uses-feature android:glEsVersion="0x00020000" />
</manifest>

如我们所推測的那样。acivity节点的name属性相应于com.android.unity2ecplise.UnityPlayerNativeActivity。这说明在此之前,Android是以这个类作为主Acivity。

如今我们将其改为我们自定义的类。这样我们就能使用自定义的布局。同一时候大家会注意到以下这两行:

      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
<meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />

之前我们在讲Unity视图嵌入Android视图时以前碰到过Android视图无法取得焦点的问题,当时就是在配置文件里加入了这样两行代码,此时此刻,大家是不是和博主一样有种大彻大悟的感觉呢。我们执行程序,会发现界面像我们所希望看到的那样被改变了。并且我们能够通过两个button来改变视图中立方体的大小:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWlueXVhbnBlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

这样我们就能够认识到从Unity中导出的就是Android项目。我们能够直接将其改动来达到满足我们要求的目的。至于金曾玺老师的这样的方法。在官方API文档中的确有提到过这样的方法,只是博主尝试了好久,这样的方法都失败了,不知道是不是由于Unity在新版本号中已经攻克了这个问题,从而能够直接导出可执行的Android项目。

最后来说说网络上流传的一种方法。据说在Unity中将项目Build下就会在project目录下的Temp目录下生成一个名为StagingArea目录。我们将这个目录在导入到Eclipse中并将其设为一个库,然后在新建的Android项目中引用这个库。并将这个项目中的assets目录覆盖新建项目中的assets目录,然后我们仅仅要让主Acitivity继承Unity提供的Android接口中的UnityPlayerActivity就可以。这样的方法博主并没有去尝试,只是在Build的时候确实会产生这样一个目录。只是博主认为这样是不是有点麻烦了啊,既然Unity导出的Android项目直接就能用。我们何必要再去用这样的复杂的方法呢,只是我认为大致的思路就是这样的,UnityPlayerActivity负责Acivity生命周期的维护。UnityPlayer负责渲染Unity场景中的内容,而我们在Unity中使用的资源都被Unity的引擎在内部进行了处理,总之把握了这些,Unity和Android的交互就基本没什么问题了。好了,谢谢大家关注我的博客,今天的内容就是这样了,希望大家喜欢。

每日箴言:有些路看起来非常近,但是走下去却非常远的。缺少耐心的人永远走不到头。人生,一半是现实,一半是梦想。 ——顾城

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

喜欢我的博客请记住我的名字:秦元培。我的博客地址是blog.csdn.net/qinyuanpei

转载请注明出处。本文作者:秦元培, 本文出处:http://blog.csdn.net/qinyuanpei/article/details/39717795

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

本文源码下载:Unity项目 Android项目

[Unity3D]Unity3D游戏开发之从Unity3D到Eclipse的更多相关文章

  1. Unity3D游戏开发之在Unity3D中视频播放功能的实现

    版权声明:欢迎订阅公众号[5厘米的理想],愿生命里的每个小理想,都能成为生命里的小确幸.本文地址为: https://blog.csdn.net/qinyuanpei/article/details/ ...

  2. [整理]Unity3D游戏开发之Lua

    原文1:[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(上) 各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我地博客地址是blog.csdn.net/qinyuanpei.如果 ...

  3. [Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘终结篇:UniLua热更新全然解读

    ---------------------------------------------------------------------------------------------------- ...

  4. [Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(下)

    ---------------------------------------------------------------------------------------------------- ...

  5. Cocos2d-x 3.x游戏开发之旅

    Cocos2d-x 3.x游戏开发之旅 钟迪龙 著   ISBN 978-7-121-24276-2 2014年10月出版 定价:79.00元 516页 16开 内容提要 <Cocos2d-x ...

  6. 【转载】浅谈游戏开发之2D手游工具

    浅谈游戏开发之2D手游工具 来源:http://www.gameres.com/459713.html 游戏程序 平台类型: iOS Android  程序设计: 其它  编程语言:   引擎/SDK ...

  7. Cocos2d—X游戏开发之CCToggle(菜单标签切换)CCControlSwitch(开关切换)

    Cocos2d—X游戏开发之CCToggle(菜单标签切换) 首先继承子CCMenu,是菜单标签中的一种.‘ class CC_DLL CCMenuItemToggle : public CCMenu ...

  8. iOS游戏开发之UIDynamic

    iOS游戏开发之UIDynamic 简介 什么是UIDynamic UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架 可以认为是一种物理引擎,能模拟和仿真现实生活中的物理现象 ...

  9. Unity3D游戏开发之Unity与Android交互调用研究

    各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.在前一篇文章中,我们研究了Android平台上Unity3D的手势操作并在之前的基础 ...

随机推荐

  1. node.js入门之三

    Node.js REPL(交互式解释器) Node.js REPL(Read Eval Print Loop:交互式解释器) 表示一个电脑的环境,类似 Window 系统的终端或 Unix/Linux ...

  2. 洛谷 P2341 [HAOI2006]受欢迎的牛

    题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所有奶 牛都是自恋狂,每头奶牛总是喜欢自己的.奶牛之间的“喜欢”是可以传递的——如果A喜 欢B,B喜欢C,那么A也喜欢C ...

  3. 自定义对话框(jDialog)

    [配置项]jDialog options点击收起 一.接口功能 jDialog的默认配置项,本组件提供的所有对话框,都可以通过修改这些配置项来实现不同的效果. 二.详细配置项 /** * 对话框的默认 ...

  4. 由于未清除缓存引发的bug

    在写页面的时候,首先引入了本地react.js和react-dom.js 16版本(cjs)的文件,出现如下错误 发现bug后,将本地的react.js和react-dom.js文件改成16.2(um ...

  5. PHP 中 include() 与 require() 的区别说明

    引用文件的方法有两种:require 及 include.两种方式提供不同的使用弹性. require 的使用方法如 require("MyRequireFile.php"); . ...

  6. 简单说一下 TCP打洞和UDP打洞

    1, TCP协议通信: 现在有两台电脑A和B.在 假设A的地址为 192.168.0.100 假设B的地址为 192.168.0.102 A想给B发送一个字符串Hello,  如果A,B之间采用TCP ...

  7. 时钟周期 VS 机器周期

    时钟周期vs机器周期 Clock cycle The speed of a computer processor, or CPU, is determined by the clock cycle, ...

  8. JavaScript:JSON 和 JS 对象

    区别 JSON(JavaScript Object Notation)仅仅是一种数据格式(或者叫数据形式).数据格式其实就是一种规范,按照这种规范来存诸和交换数据.就好像 XML 格式一样. 区别 J ...

  9. js中5中继承方式分析

    //1.借用式继承   把sup的构造函数里的属性方法克隆一份sub实例对象     function Super(){       this.val = 1;       this.fun1 = f ...

  10. CSU1008: Horcrux

    Description A Horcrux is an object in which a Dark wizard or witch has hidden a fragment of his or h ...