我在网上搜索了类似的问题,虽然我发现了几个类似的问题,但没有一个有可靠的答案,这就是我在这里发帖的原因。
当为Android编译Unity3D项目时,它基本上只是将场景作为活动开始/结束/等。我想将此Activity更改为Fragment,以便将其显示为导航抽屉内的选项卡,并将其显示为另一个片段/活动内的子视图。
所以基本上我有一个MainActivity
打开按钮,UnityPlayerNativeActivity
是实际的Unity3D项目。
我搜索了如何将一般活动更改为片段,并将UnityPlayerNativeActivity
更改为匹配。例如,在下面新标题的UnityPlayerNativeFragment
中(评论反映了之前确切的变化):
import com.unity3d.player.UnityPlayer;
// Other imports available in full code linked to below
public class UnityPlayerNativeFragment extends Fragment
{
// Changes in this class:
// 1- 'this' references changed to "getActivity()"
// 2- onCreate -> onCreateView
// 3- protected -> public in function names
// 4- @Override added before function calls
// 5- newInstance and onAttach added
protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code
private static final String ARG_SECTION_NUMBER = "section_number";
public static UnityPlayerNativeFragment newInstance(int sectionNumber) {
UnityPlayerNativeFragment fragment = new UnityPlayerNativeFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((HomeActivity) activity).onSectionAttached(
getArguments().getInt(ARG_SECTION_NUMBER));
}
// UnityPlayer.init() should be called before attaching the view to a layout - it will load the native code.
// UnityPlayer.quit() should be the last thing called - it will unload the native code.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
//below line removed because it was causing errors
//getActivity().requestWindowFeature(Window.FEATURE_NO_TITLE);
getActivity().getWindow().takeSurface(null);
getActivity().setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);
getActivity().getWindow().setFormat(PixelFormat.RGB_565);
mUnityPlayer = new UnityPlayer(getActivity());
if (mUnityPlayer.getSettings ().getBoolean ("hide_status_bar", true))
getActivity().getWindow ().setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
int glesMode = mUnityPlayer.getSettings().getInt("gles_mode", 1);
boolean trueColor8888 = false;
mUnityPlayer.init(glesMode, trueColor8888);
View playerView = mUnityPlayer.getView();
return playerView;
}
@Override
public void onDestroy ()
{
mUnityPlayer.quit();
super.onDestroy();
}
// onPause()/onResume() must be sent to UnityPlayer to enable pause and resource recreation on resume.
@Override
public void onPause()
{
super.onPause();
mUnityPlayer.pause();
}
@Override
public void onResume()
{
super.onResume();
mUnityPlayer.resume();
}
@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
mUnityPlayer.configurationChanged(newConfig);
}
}
AndroidManifest.xml
:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.SamerBekhazi.Test" 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:theme="@style/AppTheme" android:icon="@drawable/app_icon" android:label="@string/app_name">
<activity android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="portrait" android:name=".HomeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
</activity>
</application>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-feature android:glEsVersion="0x00020000" />
</manifest>
我在这里只包含了这两个文件,因为我认为问题来自其中一个。完整代码可下载here。提取/导入到Android Studio中 - 您可能需要按Sync Project with Gradle Files
一次才能生效。
项目的其余部分基于Android Studio在创建新项目时自动为您创建的Navigation Drawer Activity
项目。我基本上只是在newInstance
中按下相应的图标时调用上述UnityPlayerNativeFragment
NavigationDrawer
。
当我按下场景标签时会出现什么结果:黑屏,操作栏显示静止,但没有别的。右上角的“设置”按钮仍然是可按下的,导航抽屉按钮也是如此,但是当按下导航抽屉上的另一个选项卡时,整个应用程序会冻结,您必须强制退出。我认为后一个问题是因为你无法关闭一个没有正确打开的UnityPlayer
,所以主要的问题是实际上在UnityPlayer
内部正确地打开了AndroidManifest.xml
。应用程序的其余部分(其他选项卡)工作正常。我在上面的代码和11-11 21:22:19.681 29280-29280/com.Bekhazi.Bouncy_Ball W/linker﹕ libmain.so has text relocations. This is wasting memory and is a security risk. Please fix.
11-11 21:22:19.681 29280-29280/com.Bekhazi.Bouncy_Ball D/dalvikvm﹕ Added shared lib /data/app-lib/com.Bekhazi.Bouncy_Ball-2/libmain.so 0x42d64cd8
11-11 21:22:19.691 29280-29280/com.Bekhazi.Bouncy_Ball W/linker﹕ libmono.so has text relocations. This is wasting memory and is a security risk. Please fix.
11-11 21:22:19.691 29280-29280/com.Bekhazi.Bouncy_Ball W/linker﹕ libunity.so has text relocations. This is wasting memory and is a security risk. Please fix.
文件中尝试了几种变体(我能想到的一切),但没有任何效果。
Logcat没有显示任何错误,只是说:
{{1}}
这到底出了什么问题?目标版本适用于Android 5.0,我使用的是Android Studio 0.8.14。 值得注意的是:当它是一个活动时,我能够成功地将场景加载到我的Nexus 5上。
答案 0 :(得分:1)
尝试这种方式,它可以在我这边工作。
1.在活动中创建UnityPlayer
private UnityPlayer mUnityPlayer;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mUnityPlayer = new UnityPlayer(this);
2.On Fragment
private MyActivity mUnityMainActivity;
private UnityPlayer mUnityPlayer;
View playerView;
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// TODO Auto-generated method stub
mUnityMainActivity = (MyActivity) getActivity();
mUnityPlayer = mUnityMainActivity.GetUnityPlayer();
playerView = mUnityPlayer.getView();
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
playerView.setLayoutParams(lp);
if(playerView.getParent() != null){
((ViewGroup)playerView.getParent()).removeAllViews();
}
return playerView;
}
答案 1 :(得分:0)
借助上面提供的帮助以及以下链接,我设法将其集成到一个片段中:https://forum.unity.com/threads/unity3d-in-fragment.327303/。
必须在活动中使用标准方法。
下面详细说明:
在保存片段的活动中(“ MyActivity”):
//区域生命周期方法 @Override 受保护的void onCreate(@Nullable Bundle savedInstanceState){ super.onCreate(savedInstanceState); mUnityPlayer =新的UnityPlayer(this); }
/ **团结** / @Override 受保护的void onPause(){ super.onPause(); mUnityPlayer.pause(); }
//恢复团结 @Override受保护的void onResume() { super.onResume(); mUnityPlayer.resume(); }
//低内存统一 @Override public void onLowMemory() { super.onLowMemory(); mUnityPlayer.lowMemory(); }
//修剪内存统一 @Override public void onTrimMemory(int level) { super.onTrimMemory(级别); 如果(级别== TRIM_MEMORY_RUNNING_CRITICAL) { mUnityPlayer.lowMemory(); } }
//这样可以确保布局正确。 @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mUnityPlayer.configurationChanged(newConfig); }
///将焦点更改通知Unity。 @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); mUnityPlayer.windowFocusChanged(hasFocus); }
//由于某种原因,ndk不支持多键事件类型。 //通过重写dispatchKeyEvent()强制事件注入。 @Override public boolean dispatchKeyEvent(KeyEvent event) { 如果(event.getAction()== KeyEvent.ACTION_MULTIPLE) 返回mUnityPlayer.injectEvent(event); 返回super.dispatchKeyEvent(event); }
///直接将未由(未聚焦的)视图处理的任何事件直接传递给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); }
@Override 受保护的void onDestroy(){ super.onDestroy(); mUnityPlayer.quit(); }
在片段中:
@可为空 @Override 公共视图onCreateView(@NonNull LayoutInflater充气机,@ Nullable ViewGroup容器,@ Nullable捆绑包saveInstanceState){ myActivity =(MyActivity)getActivity(); 查看unityPlayViewer = calibActivity.mUnityPlayer.getView(); 新的Handler()。postDelayed(()-> initialize(),5000); 返回unityPlayViewer; }
private void initialize(){ calibActivity.mUnityPlayer.UnitySendMessage(“您对Unity的命令开始播放”); }