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

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

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

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

大家好。我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei。近期博主发现博主的文章被非常多的站点(如游戏蛮牛)等非法转载,在转载的过程中博主原来的文章出处和链接均被去掉,更让博主认为生气的事情是某些人将博主的文章复制一部分以原创文章的形式发表在CSDN上,这样CSDN在依据Tag推荐相关文章的时候。就会将一部分文章连接到博主博客以外的地方,博主并非一个小气的人,仅仅是这些博客都是倾注了博主自己心血而写成的。如此作践难免让博主本人心寒。从今天起,博主全部的文章、配图都会加上链接,希望以此告诫那些非法转载博主文章的人懂得自重、懂得尊重博主的劳动成果。

好了。这些人我暂且不去理会,今天我们继续来研究Unity在Android平台上的扩展,通过昨天的学习,大家已经知道Unity和Android是能够互相调用的。但是相信大家从昨天的文章中能够看出。假设单纯地从调用Android接口的角度来看,我们已经能够实现这一目的。但是从实际开发的角度来看,我们仅仅是迈出了非常小的一步。为什么这么说呢。由于在实际的开发中可能我们不仅须要从接口上实现与Unity的对接,并且须要从界面上实现与Unity的对接。比方,如今主流的网游都会在游戏開始的时候给玩家一个选择创建角色的过程,通常界面上会显示各种类型的角色设定,玩家能够通过界面了解每种类型的角色的特点,从而选择合适自己的角色。从技术上来讲,这一部分我们能够全然使用Unity3D的GUI系统来实现。只是本文的目的在于探讨Unity和Android的对接问题,因此我们能够假定Android在整个对接过程中扮演着界面渲染的角色,而Unity则负责游戏逻辑的维护。

那么,这样就诞生了我们今天的问题,能不能将Unity作为Android界面的一部分嵌入到Android应用中呢?答案当然是肯定的。

一、为Unity编写Android插件

首先。我们来看Unity中为Android提供的类文件UnityPlayerNativeActivity.java,该文件位于例如以下位置:

D:\ProgramFiles\Unity\Editor\Data\PlaybackEngines\androidplayer\com\unity3d\player(在不同的计算机上可能会有所不同,大家灵活运用就可以)

package 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.View;
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); }
}

熟悉Android开发的朋友一定对这个类认为眼熟吧。NativeActivity是Google在Android3.0后推出的,其目的是为了让开发人员使用C/C++在NDK环境下管理Activity的生存周期。于是我们能够大胆的猜測Unity之所以能够和Android进行交互是由于NDK提供了方便之门,果然,博主在Unity的文件夹下找到了
libmain.so、libunity.so、libmono.so这三个文件,这证实我们的猜想是正确的。在这个类中。我们能够看到Unity做了大量的初始化工作。并且重写了NativeActvity的相关方法。

不知道大家还记不记得我们在前一篇文章中定义主Activity时,我们是让它继承自UnityPlayerActivity而不是Android的Activity。那么,这个UnityPlayerActivity是什么呢?我们打开它的文件:

package com.unity3d.player;

/**
* @deprecated Use UnityPlayerNativeActivity instead.
*/
public class UnityPlayerActivity extends UnityPlayerNativeActivity { }

这时候我相信大家和博主一样都有一种恍然大悟的感觉。原来它是继承自UnityPlayerNativeActivity的,换句话说Unity在Android这部分事实上做了两件事,即初始化Activity和重写相关的方法。我们注意到代码中的凝视提示这个类已经deprecated建议我们使用UnityPlayerNativeActivity。这点我们临时不用管。我们依旧使用UnityPlayerActivity,由于它和UnityPlayerNativeActivity本质上是一样的。好了。到眼下为止。假设大家已经理解了这里全部的内容。那么我们能够浩浩荡荡地冲向Eclipse開始编写Android项目了。

和昨天一样,我们创建一个Android项目并将其设为库,这里我们将其包名设为com.android.unityview4android。这个名称非常重要,我们在Unity中将继续使用这个名字。

首先我们来创建一个Android的布局文件activity_main.xml:

<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/BtnPre"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="@string/BtnPre" />
<LinearLayout
android:id="@+id/UnityView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/BtnNext"
android:layout_below="@+id/BtnPre"
android:orientation="vertical" >
</LinearLayout>
<Button
android:id="@+id/BtnNext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/BtnNext" />
</RelativeLayout>

这里我们放置了两个Buttonbutton,分别用来控制Unity向前、向后切换模型,在屏幕中间有一个叫做UnityView的线性布局,它将作为Unity视图的父控件,即我们会将Unity的视图放到这个控件里。

我们注意到在UnityPlayerNativeActivity.java类中有一个UnityPlayer类型的变量mUnityPlayer,该类型博主眼下没有找到官方的相关说明。博主猜測它应该是负责Unity界面渲染的一个类吧,在这个类中有一个getView()方法,它将返回一个View类型的值。我们便能够通过这样的方法将其加入到Android视图里,由于我们已经准备好了一个UnityView的父控件,所以这一切实现起来变得相当地easy:

package com.android.unityview4android;

/*导入Unity提供的类*/
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity; import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout; public class MainActivity extends UnityPlayerActivity { private Button BtnPre,BtnNext;
@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); //上一个
BtnPre=(Button)findViewById(R.id.BtnPre);
BtnPre.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
UnityPlayer.UnitySendMessage("GameObject", "ShowPrevious", "");
}
}); //下一个
BtnNext=(Button)findViewById(R.id.BtnNext);
BtnNext.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
UnityPlayer.UnitySendMessage("GameObject", "ShowNext", "");
}
});
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} }

好了,这样我们就完毕了Jar库的编写,我们仅仅要将Jar库导入到Unity中,并且依照上一篇文章中所述的方法构建Android插件文件夹组织相关资源就能够了。最后我们给出AndroidManifest.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.unityview4android"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="17" /> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.android.unityview4android.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>

二、创建Unity项目
     好了。如今我们来创建Unity项目,我们这里创建一个简单地场景,场景中仅仅有一个空游戏体和摄像机。我们将通过脚本的形式来控制Unity渲染,基本的脚本代码例如以下:

using UnityEngine;
using System.Collections; public class ModelManager : MonoBehaviour { //模型
public GameObject[] Models;
//当前索引
private int index=0;
//当前对象
private GameObject mObject; void Start ()
{
this.name="GameObject";
//生成第一个物体
mObject=(GameObject)Instantiate(Models[index]);
} public void ShowNext()
{
//使索引添加
index+=1;
//范围控制
if(index>Models.Length-1){
index=0;
}
//销毁原来物体
Destroy(mObject);
//生成新物体
mObject=(GameObject)Instantiate(Models[index]);
} public void ShowPrevious()
{
//使索引降低
index-=1;
//范围控制
if(index<0){
index=Models.Length-1;
}
//销毁原来物体
Destroy(mObject);
//生成新物体
mObject=(GameObject)Instantiate(Models[index]);
}
}

这段脚本我们绑定到这个空的游戏体上,脚本的两个方法ShowNext()和ShowPrevious()相相应,通过UnitySendMessage()实现通信。好了。我们来执行项目,如图所看到的:

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

我们能够注意到当程序打开的那一瞬间,是Android视图先载入、然后Unity视图才载入的,给人总体的感觉就是在Activity里面嵌套了一个Activity。

但是博主立即就发现了一个问题,这Android视图中的button无法取得焦点啊,点击事件无效。

这是为什么呢?后来博主找到的解决方法是在AndroidManifest.xml文件里的activity子节点下添加例如以下两行代码:

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

这样问题是攻克了。但是我们得搞懂为什么吧,在Unity官方文档中,我们找到了答案:

请注意,NativeActivity在Android2.3以后被引入并且不支持该版本号下面的设备。由于触摸/运动事件处理在本机代码,Java视图通常不会看到这些事件。然而,在统一转发机制同意将事件传播到DalvikVM。为了使用这个机制,您须要改动manifest文件例如以下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product">
<application android:icon="@drawable/app_icon" android:label="@string/app_name">
<activity android:name=".OverrideExampleNative"
android:label="@string/app_name">
<meta-data android:name="android.app.lib_name" android:value="unity" />
<meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

这段话的意思就是说Android的事件是执行在本机代码中的。Java视图是看不到这些事件的,然而我们能够通过Unity提供的统一转发机制将这些事件发送到Android虚拟机。为了使用这个机制。我们必须改动Android的AndroidManifest.xml文件。博主感觉Android插件这块官方眼下做得不是非常好,总是给人一种云里雾里的感觉。并且通过各种语言相互调用添加了调试的难度,关于Android很多其它的内容。大家能够參考官方的文档:点击这里.好了,今天的内容就是这样啦,希望大家喜欢。

最后再来看看程序执行的效果吧

每日箴言:这年头连梦想都是有期限的。有想法就去做,即使失败了都比没做来得好,由于失败至少给了你经验。没做仅仅会带给你后悔。

——朱德庸

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

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

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

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

为方便大家研究这篇文章。最后给出源码:

Unity项目源码下载

Android项目源码下载

版权声明:本文博主原创文章,博客,未经同意不得转载。转载请注明作者和出处,谢谢。

[Unity3D]Unity3D游戏开发Android内嵌视图Unity查看的更多相关文章

  1. Unity3D手机游戏开发

    <Unity3D手机游戏开发> 基本信息 作者: 金玺曾 出版社:清华大学出版社 ISBN:9787302325550 上架时间:2013-8-7 出版日期:2013 年8月 开本:16开 ...

  2. 《Unity3D/2D游戏开发从0到1(第二版本)》 书稿完结总结

    前几天,个人著作<Unity3D/2D游戏开发从0到1(第二版)>经过七八个月的技术准备以及近3个月的日夜编写,在十一长假后终于完稿.今天抽出一点时间来,给广大热心小伙伴们汇报一下书籍概况 ...

  3. 《Unity3D/2D游戏开发从0到1》正式出版发行

    <Unity3D/2D游戏开发从0到1>正式出版发行 去年个人编写的Unity书籍正式在2015年7月正式发行,现在补充介绍一下个人著作.书籍信息:      书籍的名称: <Uni ...

  4. Unity3D 入门 游戏开发 Unity3D portal game development

    Unity3D 入门 游戏开发 Unity3D portal game development 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com ...

  5. 关于《Unity3D/2D游戏开发从0到1》书籍再版说明

    关于<Unity3D/2D游戏开发从0到1>第一版本在2015年7月1日全国发行,累计得到不少国内高校教师.培训机构的好评.但是由于Unity官方对于技术不断的升级与版本的快速迭代,基于U ...

  6. cocos2d-x调用android内嵌浏览器打开网页

    cocos2d-x调用android内嵌浏览器打开网页,能够从入口传入网址,C++调用android 的api就可以实现. 方法也非常easy 1. 改动"cocos2dx\platform ...

  7. Angular 内嵌视图、宿主视图

    解析视图: 内嵌视图 - 连接到模板的嵌入视图,在组件模板元素中添加模板(DOM元素.DOM元素组) 宿主视图 - 连接到组件的嵌入视图,在组件元素中添加别的组件 使用类说明: ElementRef ...

  8. Unity3D独立游戏开发日记(二):摆放建筑物

    在沙盒游戏里,能自由建造是很重要的特点,比如说风靡全球的<我的世界>,用一个个方块就能搭建出规模宏大的世界.甚至有偏激的人说,没有自由建造,就不是一个真正的沙盒游戏.的确,沙盒游戏的魅力有 ...

  9. Unity3D独立游戏开发日记(一):动态生成树木

    目前写的独立游戏是一个沙盒类型的游戏.游戏DEMO视频如下: 提到沙盒类型的游戏,就有人给出了这样的定义: 游戏世界离现实世界越近,自由度.随机度越高才叫沙盒游戏.所谓自由度,就是你在游戏里想干啥就干 ...

随机推荐

  1. URAL - 1966 - Cycling Roads(并检查集合 + 判刑线相交)

    意甲冠军:n 积分,m 边缘(1 ≤ m < n ≤ 200),问:是否所有的点连接(两个边相交.该 4 点连接). 主题链接:http://acm.timus.ru/problem.aspx? ...

  2. Cocos2d-x 3.x plist+png 做动画

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...

  3. ExtJS4 表格的嵌套 rowExpander

    今天做一个grid,里面的数据须要带明细,思来想去还是搞个表格嵌套吧!看下图 对于grid中每一条记录点击左边的+号能展开一个明细的子表格 全部数据包含列名均从后台获得,子表格的数据临时在本地以做測试 ...

  4. MemoryBarrier,Volatile

    使用MemoryBarrier,Volatile进行同步 上一节介绍了使用信号量进行同步,本节主要介绍一些非阻塞同步的方法.本节主要介绍MemoryBarrier,volatile,Interlock ...

  5. spring多数据源的配置(转)

    C3P0和DBCP的区别 C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展.目前使用它的开源项目有Hibernate,Spring等.   d ...

  6. Codeforces Round #267 (Div. 2) A

    题目: A. George and Accommodation time limit per test 1 second memory limit per test 256 megabytes inp ...

  7. 页面中插入百度地图(使用百度地图API)

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWF5dW4wNTE2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...

  8. JAVA多线程两个实用的辅助类(CountDownLatch和AtomicBoolean)

    AtomicBoolean它允许一个线程等待一个线程完成任务,然后运行: A boolean value that may be updated atomically. See the java.ut ...

  9. Android 源代码结构(转)

    简介 在使用Andriod SDK进行应用程序开发的时候,我们需要对源代码进行调试,有可能需要进入到某个Android API函数内部进行跟踪调试.但是,如果目标版本的SDK没有关联对应版本的源代码的 ...

  10. Oracle to_char,to_date

    一.在oracle中,当想把字符串为‘2011-09-20 08:30:45’的格式转化为日期格式,我们可以使用oracle提供的to_date函数. sql语句为: SELECT to_date(' ...