01
项目背景
地图展示作为游戏 LBS 社交的基础能力,是王者荣耀地图技术落地中需要突破和解决的事情。
地图能力是地图开放平台的核心能力,在经过第一次沟通后,明确了几个核心需求:王者地图UI的展示 、POI 点省市县排行、热门街区排行 、定位能力的输出。
并且也明确了由地图团队提供 Unity 上的地图展示方案,由王者团队、阿波罗团队以及地图团队共同开发该项目。
接下来就进入了技术方案的调研和设计阶段。
02
技术方案演进
2.1 地图方案选型地图展示作为游戏 LBS 社交的基础能力,是当前方案中最需要突破和解决的事情。按照《王者荣耀》的整体计划,留给调研设计、研发和联调也就只有 1 个月的时间,在技术选型上更多的是结合当前已有的地图能力对外输出。
从现状出发,地图开放平台对外输出移动端地图 sdk,使用平台分为 Android 端和 ios 端,在效果上可以分为两类,2D 版本和 3D 版本。区别如下:
2D 版本的地图提供了基础的地图展示能力,3D 版本的地图可以支持更酷炫的建筑物拔起效果以及无极缩放等,在体验上更酷炫,但所占用的包大小更大。
android:
包大小 | 包增量 | |
栅格1.2.8 | 221K | 115K |
矢量4.0.1 | jar包2.3M(包括资源文件1.1M),so库1.3M(armV7a) | 2.2M(armv7a) |
ios:
代码段 | |
栅格1.2.7 | 321K(arm64) |
矢量4.0.0 | 1490K (arm64) |
从王者系统的第一期需求效果图来看,2D 版本的地图是完全可以满足的。而王者对于包大小也有严格的要求。
基于此,我们把地图支持的项目目标定义为:为王者荣耀提供基于 2D 效果的轻量级游戏解决方案。
2.2 技术方案选型2.2.1 第一阶段 原生View挂载可行性分析明确了使用 2D 地图 sdk 对外输出后,需要解决的是如何将两个平台 ( Android 和ios )的原生 View 和 Unity 的 View 结合在一起。
Unity 与原生的 andorid 和 ios 相互调用,在技术上是可行的。之前王者内部是有一些页面由各个团队提供的原生 view 支持(主要是一些独立的 webview 页面,如英雄故事,王者规则等)。
2.2.1.1 Android可行性分析Android一般情况有三种方式实现地图:
1)启动新的 Activty,展示一个全新的页面;
2)使用 WindowManager,在游戏 Activity 之上显示一个新页面;
3)加载原生 View,需要将原始View挂载到游戏 Activity 之上。
第一种方案一开始就被pass了。由于已明确了 Unity 业务逻辑,上层负责 UI 展示,而展示地图时,Unity 侧还需要进行一些逻辑处理。新起一个 Activity, 在体验上和逻辑上都行不通。
第二个方案和第三个方案原则上都行得通,两种方案也都做了验证。本文介绍的是第三种方案。
原理如下:
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();
}
..............................
}
这个是 Android 中 Unity 中 Activity 的基类,而 mUnityPlayer 也是通过 setContentView 加载的,也就是加载到 DecorView 上。所以只需要再将 Native 的View 加载上去就可以了:
ViewGroup rootView = (ViewGroup)activity.getWindow().getDecorView();
ViewGroup.LayoutParams param = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
rootView.addView(mView, param);
2.2.1.2 ios可行性分析
ios 侧可以通过将原生View挂载在地图的 Window 上。
/**
* 获取场景挂载点 (keyWindow)
* @return 挂载点
*/
(UIView *)getMountPoint{
UIWindow *window = [UIApplication sharedApplication].keyWindow;
NSAssert(window != nil, @"window must not be nil");
return window;
}
/**
* 挂载到 keywindow.
*/
- (void)mount{
UIView *mountPoint = [[self class] getMountPoint];
NSAssert([self underlyingView].superview == nil , @"scene super view must be nil");
[mountPoint addSubview:[self underlyingView]];
}
以上方案均在 Unity 侧验证通过。
2.2.2 第二阶段 View层级关系从整体需求来看,上层不仅仅是一个单独的地图,还要有很多的 UI 元素: