Android M Runtime Permission Issue in Unity Game Development

关于有史以来遇见过的最麻烦的游戏bug: Android M Permission

问题描述:

Android M 允许玩家在游戏安装后,修改游戏访问设备的权限。当玩家禁止游戏访问设备摄像头之后,游戏中的AR scene 依旧可以照常运行并不显示任何提示信息。

具体权限访问改变参考此处:https://blog.xamarin.com/requesting-runtime-permissions-in-android-marshmallow/

经过调查,游戏AR scene 的错误监控系统来自 Vufornia 的自带错误监控系统。然而,糟糕的是,Vufoirnia 并没有兼容 Android 的最新版本。每次AR scene 初始化时,访问的 Init 信息为 success。 这意味着,我必须自创一种检测方式,来检测游戏是否有权限访问设备的摄像头。

最开始,我尝试了两种方法:WebCamTexture (http://docs.unity3d.com/ScriptReference/WebCamTexture.html) 和 CameraDevice( https://developer.vuforia.com/library/sites/default/api/unity/classVuforia_1_1CameraDevice.html)。

前者是 Unity 提供的 api,后者是 Vuforinia 提供的对象。我本以为,如果摄像头访问权限受限后,api 返回的 active device 数目应该为 0。但是,实际返回对象数目依旧是 2 (前置和后置摄像头)。其次,我试图通过摄像头的各种参数,来区分权限访问情况。但是,无论是检测 Camera 的 buffer 是否在上一帧有更新,或者是检查 Camera 的 field of view,即使 permission 被禁止了,这些信息依旧可以被访问。

于是,我不得不把方向转向 Android M 的常规解决办法。http://jijiaxin89.com/2015/08/30/Android-s-Runtime-Permission/ 和 https://developer.android.com/training/permissions/requesting.html

这里的关键 api 是 checkSelfPermission。要调用该 api,最直接的办法是,创建自己的 jar,并添加到项目中。之后再用 C# 代码调用。但是,还有一种更简单的办法,即用 Unity 提供的 api 直接调用 Android 函数。方法在此:http://docs.unity3d.com/ScriptReference/AndroidJavaClass.html

我们既可以通过 AndrpidJavaClass 调用 static 函数,可以通过 AndroidJavaObject 调用 non-static 函数。以下是我的测试代码:

  1.             AndroidJavaClass jc = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”);
  2.             AndroidJavaObject activity = jc.GetStatic<AndroidJavaObject>(“currentActivity”);
  3.             AndroidJavaObject context = activity.Call<AndroidJavaObject>(“getApplicationContext”);
  4.             AndroidJavaObject ContextCompat = new AndroidJavaObject(“android.support.v4.content.ContextCompat”);
  5.             AndroidJavaClass ActivityCompatClass = new AndroidJavaClass(“android.support.v4.app.ActivityCompat”);
  6.             int hasCameraPermission = context.Call<int>(“checkSelfPermission”, “android.permission.CAMERA” );
  7.             ActivityCompatClass.CallStatic(“requestPermissions”, context, “android.permission.CAMERA”, 1000 );
  8.             //int hasCameraPermission = ContextCompat.Call<int>(“checkSelfPermission”, context, “android.permission.CAMERA” );

但是糟糕的是,如果我用 ContextCompat.checkSelfPermission 调用 static 函数,程序将会报错显示无法找到该 static 函数。如果我使用 context.checkSelfPermission 调用 non-static 函数,虽然 method 会被调用,但是返回的值永远都是 0 (granted)。

后来经过再三检查,发现其问题在于我们使用的 library 不是最新版本,无法支持 Android api 23 及以上的版本。如果更新 lib 的话,会花费相当多的时间去清理和调整。

最后,我们尝试更改 Manifest 中的 targetVersion 来禁止用户修改游戏的访问权限。但是,这种方法也失败了。原因在于 targetVersion 的具体意思是指告知设备该程序已经在通过 targetVersion 的目标版本测试。然而我们的游戏实际并不满足目标版本,但是设备依然会按照应有的方式处理我们的程序。详细见此:

http://www.cnblogs.com/popapa/p/android_uses-sdk-element.html
http://developer.android.com/guide/topics/manifest/uses-sdk-element.html

最后是网上另外两名用户的解决办法: http://blog.trsquarelab.com/2015/11/  和 http://stackoverflow.com/questions/35027043/implementing-android-6-0-permissions-in-unity3d/

 

Unity: Gimbal Lock Again

I have to say, I have heard the word “gimbal lock” tons of time before. But recently a gimbal lock bug in Unity definitely reminded me of how naive I was about this problem. Actually, gimbal lock problem should not be seen in Unity. However, this is not always true.

What is gimbal lock?

Gimbal lock is the loss of one degree of freedom in a three-dimensional, three-gimbal mechanism that occurs when the axes of two of the three gimbals are driven into a parallel configuration, “locking” the system into rotation in a degenerate two-dimensional space.

This problem is frequently seen when we use euler angle for game object’s rotation, as one axis is set to 90 (in Unity axis order, this axis is x), then we lost one dimension. You could easily reproduce this problem in Unity Editor by set one game object’s rotation as (90, 0, 0). Then no matter how you change the value for y or z, the game object would only rotate in one dimension.

Detailed Information about Gimabl Lock

How Unity deals with euler?

Later, I checked the source code of Unity API. Here is what I found:

For transform.eulerAngles

public Vector3 eulerAngles
{
      get
      {
        return this.rotation.eulerAngles;
      }
      set
      {
        this.rotation = Quaternion.Euler(value);
      }
}

For transform.Rotate

public void Rotate(Vector3 eulerAngles, [DefaultValue("Space.Self")] Space relativeTo)
    {
      Quaternion quaternion = Quaternion.Euler(eulerAngles.x, eulerAngles.y, eulerAngles.z);
      if (relativeTo == Space.Self)
        this.localRotation = this.localRotation * quaternion;
      else
        this.rotation = this.rotation * Quaternion.Inverse(this.rotation) * quaternion * this.rotation;
    }

It is obvious that Unity internally uses quaternion instead of euler. In fact, euler is just the data showing to users. According to resources online, people believe gimbal lock could be solved by using quaternion. But now, I have doubt about it.

We could make a simple experiment like what two bloggers did here:

Candycat1992 made this test:

transform.rotation = Quaternion.Identity;
transform.Rotate(new Vector3(0, 0, 40));  
transform.Rotate(new Vector3(0, 90, 0));  
transform.Rotate(new Vector3(80, 0, 0)); 

And Scott did this:

void Start () { 
		     newDirection = new Quaternion();
		     newDirection  = Quaternion.Euler(-90, 45, 0);
     //newDirection  = Quaternion.Euler(-90, 0, 45);
	}
 
	void Update () { 
		     transform.rotation = Quaternion.Lerp(transform.rotation, newDirection, Time.deltaTime);
}

And gimbal lock appeared! But wait, how could quaternion fail to avoid gimbal lock?

Then I made my own test:

  • Set the rotation of the target object as (90, 0, 0)
  • Call transform.Rotate( 0, rate, 0 )
  • Call transform.Rotate( 0, 0, rate )

Gimbal lock never happens.

So what actually happened?

There are two concepts I misunderstood:

  1. Unity rotation order: In Unity, the order of rotation is ZXY. So if I set the original rotation of the object as (90, 0, 0), and then transform.Rotate(0, rate, 0) and transform.Rotate(0, 0, rate). It would not generate the gimbal lock. Because here it rotates in the order of XYZ, as rotation in X would not make any affect. But, if we call transform.Rotate( 90, y, z) directly, Unity would rotate in order of ZXY. In this way, it would generate gimbal lock.
  2. The way to use Quaternion: Quaternion could avoid gimbal lock, which is true. But remember, “could avoid” doesn’t mean always avoid. We could consider Quaternion as four dimension, comparing to three dimension of Euler, it has an extra dimension to avoid gimbal lock. However, if you rotate it the same as Euler axes, Quaternion does the same as Euler.  Therefore, we should be very careful about the way we use Quaternion.

Quaternion and gimbal lock is not easy to understand. So far I only know what went wrong, and I need to do more research about Quaternion and gimbal lock.

Unity UI adjustment based on different screen resolution

There are three ways which we could use to adjust UI elements based on different screen resolution:

  1. Surrounding fill out
  2. Relative size and fixed size
  3. Two patterns

Surrounding fill out

For surrounding fill out, it means that all game elements are placed in the center of the screen, and fill out rest of the screen space by using other elements, like merely black color. Here is the example from “Fallout:Shelter”:

16:9 ( for iphone5)

Screen Shot 2015-08-17 at 11.29.16 AM.png

4:3 ( for ipad)

Screen Shot 2015-08-17 at 11.28.19 AM.png

You can see, all UI elements are places in the center square. No matter what screen resolution it is, each UI element stays in the same position, and rest of space whether be cut (4:3) or filled in black (16:9). It is obviously a smart solution. Meanwhile, it presents a clean style for users. Personally I like this solution the most.

Pros:

  • Easy to implement
  • Clean style, looks perfect.

Cons:

  • All UI elements must be in the center
  • All UI elements’ size could not be adjusted

Summary

If there are a few interactive UI elements in the game scene, and each element’s size is not so small (like button), I suggest you use this method to solve UI adjustment issue.

Relative size and fixed size

For relative size and fixed size, UI element’s size and position are set as relative or fixed. Usually, the size is set as relative, and position is set as fixed. In Unity, we could use NGUI stretch and NGUI anchor to achieve it. In general, we want UI element’s size would be automatically adjusted according to screen size, and UI element’s position stays the same as resolution changes in order to make layout unchanged. Here is the example from Dead Trigger 2:

16:9 (iphone 5)

Screen Shot 2015-08-17 at 11.29.34 AM.png

4:3 ( ipad)

Screen Shot 2015-08-17 at 11.28.39 AM.png

It is clear that all buttons stay in the same position, as they use the same anchor target. If you look at green button on the right, you could notice that the distance between it and screen border is the same for 16:9 resolution and 4:3 resolution. Moreover, the iphone version has relatively bigger buttons as  we want player are able to tap them easily on iphone device. And it could be achieved by using NGUI stretch to set button’s relative size.

Pros:

  • Keep UI layout unchanged
  • UI elements would be not places in a certain place of the screen

Cons:

  • It might be generated unexpected result like buttons overlap with each other

Summary

If you want to have UI elements adjust their size based on device screen resolution, especially you want player on iphone could have relatively bigger UI elements, you could use this method. But you should be careful when elements are very close to each other. Because they might overlap with each other if their size keep increasing but they stay in the same position.

Two patterns

For two patterns, it is easy to understand. The game would use two different pattern of UI based on screen resolution. Here is the example from Hearthstone:

16:9 (iphone5)

Screen Shot 2015-08-17 at 11.28.57 AM.png

4 : 3 (ipad)

Screen Shot 2015-08-17 at 11.27.57 AM.png

Pros:

  • Provide the best interaction experience by choosing the appropriate pattern according to screen resolution

Cons:

  • You need to do everything twice

Summary

If you have enough resources and time, just do it!

All is Dust Thesis Game – Week_1_Work:Level Night 1 Design and Narrative Work

This is a fictional book called “Witches’ Feast” in the player’s house. Player could read some part of this book and also found some broken pages in the farm.

Book “Witches’ Feast”

Pages Player could read from the book.

Page 38:

Witches’ Sabbath is the feast of witches. European records indicate case of persons being accused or tried for taking part in Sabbat gatherings. According to Hans Baldung Grien, the Sabbats that many Wiccans and Neo-Pagans follow are: Beltane (May 1), Litha (Summer Solstice) and Lammas (August 1). The salt, bread and oil were prohibited during the Sabbath because Devil hated them. And human flesh, especially… (The page is broken)

 

Page 122:

Witch trials were a period of witch hunts that took place across early modern Europe and the European colonies in North America between the fifteenth and eighteenth centuries. Over these three centuries, an estimated total of 40,000 people were executed, usually by burning.

 

Page 156:

After 1750, it was very rare for an accused witch to undergo a judicial process and be threatened with execution, but there was still a danger from popular justice and lynch mobs.

 

Page: 158

During 1750 to 1920, there were 569 recorded lynchings of witches in Southern United States, including Georgia, Texas, Oklahoman, Mississippi and Alabama.

 

Newspaper: Old woman arrested for abusing child

May 1, 1928

A woman from Oklahoma was arrested on child abuse charges after a 9-year-old girl told authorities she had been burned and tortured while the woman was dressed in a witch costume.

 

Time: Senator Joseph Robinson

June 25, 1928

The cover is the photo of the senator Joseph Robinson,

 

Pages Player could find in the farm.

Page 39:

Human bones and children would be stewed in a special way during the Sabbath.

Page 216:

In order to go to hell after death, witches hold Witches’ Sabbath more frequently to please the Devil.

It was believed that the end of the world would soon come, and the Devil began to develop into a more threatening form, more souls of the witches were back to the world as the servant of the Devil.

Some pictures providing inspiration:

 Night One Design

Night_1_Desgin

GameEngineering_2: Final Game – “Lost Rabbits in Silence”

Game Description

“Lost Rabbits in Silence” is a third-person view horror game where the player needs to find his five lost friends in a mystic small town fulled of fog. This game is made for showing the respect and love for the classical horror game “Silent Hill”.

Download Link

Debug Build: https://drive.google.com/file/d/0B6aorYphcJ5INW0tMmllZHJRU3M/view?usp=sharing

Release Build: https://drive.google.com/file/d/0B6aorYphcJ5Ib0hvNHltQWlqQms/view?usp=sharing

If you met the error “MSVCP120d.dll is missing” when you run the demo, please download vs2013 visual C++ redistributable package x86 (32bit version), here is the link: http://www.microsoft.com/en-us/download/details.aspx?id=40784

Game Screenshots

Game_1 Game_2 Game_3

Game Controls

Arrow Keys for Player Movement

WASD Keys for Camera Movement

Esc for exit

When game begins, you need to control the character to move around in this small town to find his five lost friends. Some are abandoned outside, and some are hided inside the house.  You have to move forward and go through the fog beyond your vision to find your friends.

In debug build, press P to enable the debug lines, which all point to the positions of five rabbits, and press O to disable the debug lines.

Game_4

 

Game Technical Detailed

This game is made by Hui engine, which is created by myself. The engine is developed in C++, using DirectX 9 and lua.

What I learned from the class really helps me a lot for creating this game. The knowledge and lua programming skills about the graphics like mesh, material and texture, help me organize the game art assets. Now the game art assets are well-organized and flexible to change and edit. Here is my game’s art assets folders.

Game_5

 

Meanwhile, what I learn about the shader in class contribute to my game’s final effect a lot. As I have fully understand the function of vertex shader and pixel shader, it is easy for me to add more image effect for my game. Here I have added the fog effect for my game. In general, adding fog effect is pretty simple. All you need is to calculate the fog factor and then use the fog formulas to add the fog color to each pixel at last.

Here is the fog formulas I use for the game:

Linear Fog = (FogEnd – ViewpointDistance) / (FogEnd – FogStart)

Fog Color = FogFactor * TextureColor + (1.0 – FogFactor) * FogColor

And here is my final pixel shader of my game:

Game_6

The fog effect part is here:

Game_7

 

Also I take advantage of  DirecX sound code to add the background music into my game.

At Last

I want to extend my gratitude to our class teacher John Paul and class TA Jamie. This class is great! I really learn a lot about the game graphics and also get experience of the game industry project development. These sleepless nights of working on this project would be the sweetest and most unforgettable memory of my EAE MGS time.

All is Dust Thesis Game – Week_14_Work: Before the EAE Open House

Final Gameplay Process

1. Player awakes in the first room of the house, and two of the doors are closed, only the one that leads to the outside is opened.

2. After the player moves out of the house, the ghost will lead the player to the position of the lantern.

3. It is fine if the player could not find the lantern, but he has to face the dark corn field without any light except the lighting in the sky.

4. Player will go through two scarecrows wave attack. And if he could find three items of four in the game level and return to the house, then he will survive.

Game End Scene Bug fixed

When we built the game, we found that the game could not enter the end scene as it worked well in Unity Editor.  This bug took us a long time to fix and finally we found that after player’s health point is below 0, the Application.LoadLevel function had not been executed. So we changed the level load condition, and when the player health point is below 0.3f, execute the level load function. This time, the end scene could be loaded well for the build version of our game.

Game Player Height Adjust and Scarecrow Size Adjust

As some players gave us feedback before about the problem of the player’s height. This time I changed the player’s height to make it more comfortable. Relatively I also adjust the size of the scarecrows as we found why the scarecrow is not creepy enough is because it is too small.

13_1

Now you can see the height of the player is reasonable.

 

 

Category Archives: All is Dust Thesis Game – Week_13_Work:

Lighting Effect Improvement

John has achieved the lighting script and we added the glow effect to the camera. So when the lighting comes, the script would enable the glow effect script, which makes the lighting more sacred.

13_5

 

Lantern Light Redesign

After I analyzed the night scene of the horror game “The Forest”, I found that the light of the lantern should not be point light. And also the light effect of the current game is not so good.Here is “The Forest” light effect:

13_3

So I adjust the setting of our lantern and here is the final result:

13_2

Scarecrow Wave Attack Process Design

1. The fog begins, enable the fog of the game scene.

FARMHOUSE

2. Rain stops falling down and all sounds would be mute.

3. The siren begins to ring.

4. Scarecrows appear and begin to attack.

13_4

5. After a certain of time, scarecrows disappear in the form of dust.

GameEngineering_2: Sprite rendering

Description

  • Draw a 2D “sprite” overlay
  • Draw a sprite that uses a texture “atlas”

Reading Time: 1.0 hours

Coding Time: 5.5 hours

Write-up Time: 1 hours

Total Time: 7.5 hours

Download Link: http://blogs.eae.utah.edu/jdong/wp-content/uploads/sites/13/2014/12/game.zip

Achievement

1. Create the new Sprite class to draw a 2D overlay

In general, sprite is a 2D object which is similar to actor game object, but they are different in following:

Sprite only has vertex buffer while actor has vertex buffer and index buffer. The reason is that sprite only needs four vertexes.

Sprite vertex only needs the information of position and uv coordination, although it could still share the vertex format with actor class.

Sprite draw function is DrawPrimitive rather than DrawIndexPrimitive.

Based on those differences, here is my sprite class:

11.01

And in my World and Graphics component, before each component has Vector<Actor> list to store all actors in the game. Now I need to add Vector<Sprite> list to store the sprites game objects.

11.02

And for DrawPrimitive, we used the draw type D3DPT_TRIANGLESTRIP. The reason is that if we used D3DPT_TRIANGLELIST, we must use index buffer. But now we only need to draw a few triangles, so we could use D3DPT_TRIANGLESTRIP. In order to use D3DPT_TRIANGLESTRIP, we must define the order of the vertex in a different way, like the following:

11.03

Now the order is like in the shape of Z.

Final Effects:

11.04

11.05

2. Create the new Sprite “atlas”

By using atlas, we could make a sprite with shared texture, and even we could achieve a kind of simple animation by taking advantage of the atlas.

In my project, you could change the atlas by pressing the key from 0 – 9.

11.06 11.07

To achieve this, the UV of the atlas sprite should be changed according to the keyboard input.

Pixel Debugging:

11.08 11.09

 

11.10

Problems I met

1. Use a new vertex format

At first, I thought the sprite vertex only has two information: position and uv, so I created a new vertex format called sVertex. Then I learned from class e-mail that there is no need to create a new vertex format for just a simple sprite. So at last my sprite vertex shares the same vertex format with actor’s vertex format.

2. Mysterious bug fixing

Remember in previous I mentioned that my camera movement is not so smooth. I have asked JP and Jamie and tried several solutions but it did not work. And tonight I found that my program only update camera’s position when there is new input. Once I added the camera position update function to the branch  where there is no message sent from the window, the problem has been fixed. I still don’t know why this problem has been fixed in this way.  I guess it would take a while to check whether there is new message from the window or not. So when there is new input, the camera update function will not be called immediately.

11.11

Thesis Game – Week_12_Work: New game level map built and hanged scarecrows trigger

This week we have the new game map level and also I added the hanged scarecrow trigger to the new map:

1. New game map level

10_1

 

 

Elements:

1. House

  • Function: A warm and safe place. Player will get the information and clues here.

2. Barn

  • Function: Creepy and weird place. Current design is that barn contains a machine which player needs to interact with.

3. Silo

Function: Not decided yet.

4.Well

  • Function: A place with a puzzle. Probably it will be a hidden place for player in the last level of the game.

5. Windmill

  • Function: A place surrounded with the crows. Also it could be the alarm for the dust storm.

6. Dry Lake

  • Function: Create the atmosphere of the death.

7. Sheds

  • Function: Player could get the item (some useful tools ).

8. Corn

  • Function: Create the obstacle for player’s vision; it is also the place where the scarecrows could hide.

9. Animals Platform

  • Functions: Full of dead animals body, gross and dirty.

2. Hanged Scarecrows Trigger

8_1 10.5

When the player triggers the hanged scarecrow trigger, the scarecrow will fall down ( from the tree, the roof…). This is inspired from the SH3 ghost house  design and we want to create the jump scare for the player.

10_6