Category Archives: Code

hqdefault3

Unreal 4 + Oculus Rift 筆記

撞正Unreal 4 Free咗又接到個Oculus job 做,
就好快手咁玩咗一陣。
初步感覺Crash嘅情況係有但係唔多,
除咗load新project會有啲耐之外performance都算好好,
document好簡陋但有unreal answer補夠。
新engine多咗fancy嘢,又唔洗錢,
明顯係Unity做得太好,佢地要急起直追啦XD

Unreal / Oculus Notes

  • Unreal本身就support oculus,唔洗裝plugin,就咁run個app fullscreen就會自動開stereo mode
  • 我部mbp一開stereo就好鬼慢,暫時未知個bottleneck喺邊。不過做Oculus app就一定要搞好performance
  • Quality Settings: https://answers.unrealengine.com/questions/23023/trouble-configuring-game-settings.html
    P.S. sg.ResolutionQuality好似影響唔到Oculus
  • Disable smooth frame rate: Project Settings -> Engine -> General Settings -> Framerate -> turn off smooth frame rate. 啲人話呢個唔會影響framerate但我見會減咗少少,而且frame rate好低嘅時候唔需要control frame rate
  • Ambient Sound: 記住個聲音檔format要係wav,仲一定要係Mono,否則個engine會做唔到因應player位置嘅立體聲
  • 自動fullscreen: 建立 DefaultGameUserSettings.ini 放入去 project_folder/Config 入面:
    [/Script/Engine.GameUserSettings]
    bUseVSync=False
    ResolutionSizeX=1920
    ResolutionSizeY=1080
    LastUserConfirmedResolutionSizeX=1920
    LastUserConfirmedResolutionSizeY=1080
    WindowPosX=-1
    WindowPosY=-1
    bUseDesktopResolutionForFullscreen=False
    FullscreenMode=0
    LastConfirmedFullscreenMode=2
    Version=5

    P.S. bUseDesktopResolutionForFullscreen唔肯定係唔係False

  • Trick: 個scene冇光源,加ambient cubmap,用有illumination 嘅material做燈光效果,物件加reflection,就可以冇lighting 嘅情況下做到好似有lighting咁,Performace超高。P.S. Unreal 嘅reflection做得出奇地快

Post Process Volume

喺Modes入面search “Post Process Volume” 加入去個scene度,喺Details做settings(將個feature嘅intensity set做0就可以熄咗佢):

  • Post Process Volume – Unbound: turn on令佢影響整個scene,而唔理佢個brush settings
  • Bloom: 光暈。呢個效果出奇地重,較細啲會好啲,但係冇咗又差好遠。就算個scene冇光源,佢對illumination都有效
  • Ambient Cubmap: Unreal冇 “Ambient Light”,所以要用cubmap。Unreal 只係Support 32bits/Channel, 8.8.8.8 ARGB 32 bpp, unsigned。如果做咗個cubmap import唔到可能係因為未set 32 bpp https://docs.unrealengine.com/latest/INT/Engine/Content/Types/Textures/Cubemaps/CreatingCubemaps/index.html
  • Lens Flares: 都係熄咗佢好啲⋯⋯
  • Global Illumination: 可以一次過調整所有illumination。注意有illumination嘅物件唔會令周圍嘅嘢光咗,所以要加cubmap
  • Motion Blur: 喺Oculus Rift見到Motion Blur仲衰過見唔到,一定要熄咗佢

Animation Transition Blending

唔知點解網上面search到嘅blending都好鬼複雜,如果你只係想做個好簡單嘅transition blending,由一個animation blend去另一個animation,首先create個animation blueprint,係入面create個state machine:
https://docs.unrealengine.com/latest/INT/Engine/Animation/StateMachines/CreatingStateMachines/index.html

然後喺個transition rules度set高返 Blend Settings -> Transition Crossfade Sharing -> Duration 就OK了。

Matinee

識用真係幾好用,雖然又多bug又多唔方便嘢XD

首先我解釋下點用:

  • create一個matinee actor,然後select佢,喺details度click “Open Matinee” 就會開咗個Matinee Editor。
  • 喺個scene度㨂咗個actor之後係Matinee Editor -> Tracks -> 左邊個section度add new empty group就會出咗嗰個actor嘅group。
  • 再對個group right click -> Add New Movement Track就可以animation個action走黎走去
  • 㨂咗track同時間之後按enter開keyframe
  • 返去個scene度set position / rotation 等等
  • 見到有條線track住點郁就成功啦
  • 返去matinee editor可以調整個curve

不過好多唔方便嘢大家要記得:

  • 如果喺matinee editor select個keyframe就會select返相應嘅actor,但係一deselect咗個actor就會deselect個keyframe,再郁個actor都唔會edit個keyframe。你要返去matinee editor select返個keyframe再返黎個scene度改。
  • 有個UI bug係click details panel會click到個scene 啲嘢,令你deselect個actor -> deselect個keyframe :@ 解決方法係留意下個cursor over detail panel嘅時候有冇轉到cursor icon,如果仲係十字就select另一個application(Cmd+tab for Mac, 去另一個app例如Chrome)再返去Unreal。
  • 又有個UI bug係right click個group冇menu出,呢個時候right click下curve panel至有menu出,然後right click個group就有返menu
  • 記住唔好開住Matinee Editor,而又唔係改緊keyframe個陣改其他actor,因為一熄咗Matinee Editor就會冇曬。
  • Matinee嘅animation track係冇blending 嘅,所以我用咗個好迂迴嘅方法做⋯⋯有人知道好啲嘅方法請話我知⋯⋯首先做個animation blueprint (custom_animation_blueprint) -> state machine,個transition rule用public variable determine (anim_var)。喺Matinee event track set 個keyframe,然後去Level blueprint -> add matinee controller(去level blueprint之前喺個scene要select緊個matinee actor),個controller會有之前係matinee editor度加嘅event。再跟住令個event改個public variable: actor ref -> get anim instance -> cast to custom_animation_blueprint -> set  anim_var
  • 如果你睇Matinee 嘅tutorial會見到佢好容易就做都一個cut scene,因為佢加條track就會自動多咗個camera然後好易就郁到佢。不過如果做Oculus,嗰個camera就唔會跟個oculus郁。可能你會想加個script入去個camera度就得,或者唔同camera track,而係直接郁個player actor。不過我又唔知點解rotate個actor向下望嗰陣個cam又唔跟住rotate⋯⋯

Software Design – State Machine

For a class with different state, instead of using switch-case loop all the time, there should be a state system to manage the behavior for each state.

For example a monster with different attacking state, there should be a class for each state, and a list of the object with those classes to represent states. In this case, each state is an enemy behavior containing a list of enemy behaviors (see also: Software Design: Feature based design on class), which is a flexible pattern to receive enemy event and share behavior between different state. (p.s.: In the other word, a normal enemy is an enemy with one state.)

Fire Dragon: attack
-> Fire Ball State (current Enemy State): receive attack event, board-cast event to its behaviors
-> Fire Ball Behavior (the only behavior in Fire Ball State): receive attack event, generate a fire ball

Sudo code to construct the Fire Dragon like this:

class EnemyBehaviorList : EnemyBehavior {
    //take enemy behaviors in constructor
}

class FireBallState : EnemyBehaviorList {
    //to do something specific
}

Enemy fireDragon = new Enemy() {
    name = "FireDragon",
    behaviours = new List () {
        new FireBallState() {            //Fire Ball State
            new FireBallBehaviour(),     //Fire Ball Behavior
            new BehaviorA()
        },
        new BehaviorB()                 //Another State, can be a behavior
    },
    currentBehaviourIndex = 0
}


and the code to construct an enemy that will only generate fire ball:

Enemy fireDragon = new Enemy() {
    name = "FireDragon",
    behaviours = new List () {
        new FireBallBehaviour()
    },
    currentBehaviourIndex = 0
}

Software Design: Feature based design on class

This is about when to create a class: for a new feature instead of a new object concept
For example, an enemy for a combat game. Instead of making a class for an enemy, we should make a class for a feature/skill/behavior of enemy. Enemy should be a “data structure” instead of “controller”.

// Wrong practice:
class EnemyA : Enemy {
    ...
    public void throwFireBall() {...}  // it is hard to share this
                                       // with other enemy
}

// Correct practice:
class Enemy {
    string name; //name = "EnemyA"
    List<EnemyBehavior> behaviors;
}
class EBThrowFireBall : EnemyBehavior { //EB stands for EnemyBehavior
    public override void someEnemyMessage() {
        //throw fire ball
    }
}


Therefore different enemies can share same behavior with different settings and combination.

The key to make this decision is all about concept: enemy is a combination of behavior, and the behavior sharing between enemies are expected.

Android is plugin unfriendly

As I worked for mobile app almost 2 years, I conclude that Android is not a good platform for plugin development, comparing to iOS platform. I always feel painful to integrate any plugin for Android apps. Here are some reasons why.

Manifest.xml vs info.plist

Manifest file just does too much then a configuration file. Every activity/service and permission requirement in Android app have to register itself in it, which causes many plugins to modify this file. By the design pattern of Android SDK, many plugins cannot avoid to do so.

More than one plugins modifying the same file turns out the plugin users to do that manually, which increase the chance of careless mistake and the effort to manage them, or the users will do a template for several plugins, but it is still complicated if there are too many.

In my opinion, I don’t see any point for such registration on Manifest XML. To protect end-user? They won’t care about it. To protect app developer from third-party developer? No it can protect nothing. It would be perfect if Manifest XML does exactly what info.plist does. At least it should be application oriented, but not module oriented. There should be another automatic system to detect and conclude the combined activity/service and permission requirement.

Message in Activity

Such as onActivityResult, must be listened by an Activity, and there is only one active activity at the same time normally. It also causes different plugins trying to modify the only activity class.

Android View Parameter

All parameters of an Android View, such as position, width and height and etc, are stored in a ViewParam, which is an instance of one of the ViewParam classes, depending on the parent view of it. which causes a dependency of plugin component to external component.

Many plugins developer (mostly in iOS) implement a help method to create a view for users, so that the view could be added to the custom view made by the plugin users and it’s done. However, the view parameter cannot be pre-made as the plugin developer don’t know what is the parent view they are using. The plugin users have to hard code the parameters themselves, and have to update that if the view is updated.

May be it’s not fair to compare an old designed Cocoa Framework with a really new Java framework, and Google is so busy about catching up the visual design against iOS. For now a plugin management for Android should be a good idea to be invented.

Note on SplitViewController and Auto Reference Counting

SplitViewController is a easy tool to make a nice interface for iPad, but I have some negative comment on it:

- It is singleton, and it occupy the whole window. I cannot add something else on it. Of cause, it force a simpler design.

- It cause the work flow different between iPhone and iPad version, which cannot be solved by storyboard entirely.

There is a special case for auto reference counting that would produce error:

- make a weak property
@property (weak) UIView* myView

- alloc and assign an instance to it directly
self.myView = [[UIView alloc] init];

- the instance is released immediately!

It is because the reference counting is zero right after the assignment, and ARC don’t recognize that should be retained and auto-released. In order to solve this, change the code to:

- create a local variable to store the newly alloc-ed instance
UIView *view = [[UIView alloc] init];
The reference counting of the instance is 1 and being auto-released.

- assign that to the property
self.myView = view;

Java Native Interface – Java和C/C++的結合

很多情況下需要Java和C/C++結合一起來編程

例如本來用C/C++寫的lib/program
為了Multi-platform就用了Java Native Interface
外層的Java包著一個C/C++ shared lib
當轉換平台時就把shared lib轉了compilation setting重新compile
然後把shared lib file直接更換了就可以

又例如本來用Java時需要C/C++的lib
因為C/C++的效率較高
或者一個特別的情況:Cocos2D-X
用C/C++在Android和iOS兩個平台上執行
而在Android中用C/C++的方法就是Java Native Interface了

Ref: http://en.wikipedia.org/wiki/Java_Native_Interface

P.S. Wiki中用“export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.”確保shared lib linkage,但這不是必需的
在執行時以”java -classpath <path> …”也可以
以減低global variable的使用
減低global variable的原因請看: http://xahlee.info/UnixResource_dir/_/ldpath.html

Java

Note for compile Java on console

Common compilation command:
java -classpath bin:/path/a:/path/b/classes.jar -d bin -sourcepath src
/src/com/PackageNameA/*.java /src/com/PackageNameB/*.java
Explanation:
-classpath <paths>  -  a list of folders/JARs separated by “:”. All class file will be included for compilation. Usually, class path should include the destination of class file of the project to include other modules
-b <path>  -  the destination of class file to be produced
-sourcepath <path>  -  the source file folder. The java files there may be compiled by auto compilation
ended with a list of source files to be compiled, separated by space

Usually, class path should include Java Runtime library
Linux: ${JRE_PATH}/lib/rt.jar
MacOS: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar
Different version of Java may has different path of the library