2020年9月20日 星期日

[筆記] Round() 不一定是四捨五入

  使用程式語言函式庫提供的 `Round()` 之類的函式對數值做四捨五入時,要小心它的捨入結果可能不是所預期的四捨五入,因而踩到雷。
來看看 Python 的:

來看看 JavaScript 的:

最後看看 C# 的:

可以發現,對 1.5 跟 3.5 都是四捨五入到 2 與 4,可是在 Python 與 C# 中,對 2.5 的結果卻是 2。

2020年9月16日 星期三

[筆記] Unity3D - 繼承類別不要有與基礎類別同名的屬性

  最近在寫遊戲時遭遇一點困難:在繼承基礎類別時,需要將其附屬的資料類別一併繼承,而在建立繼承類別的實體後,遇到初始化基礎類別的資料類別的問題,原因只是因為兩者的欄位 (field) 同名。有問題的程式碼像這樣:
class Character : MonoBehaviour
{
    protected CharacterData data;

    ...
}

class CharacterData : ScriptableObject
{
    public float movingVelocity = 10.0f;
    public float rotatingVelocity = 10.0f;
}

class Player : Character
{
    public new PlayerData data;

    private void Start()
    {
        base.data = data;
    }

    ...
}

[CreateAssetMenu(fileName = "PlayerData",
    menuName = "Scriptable Object/PlayerData", order = 1)]
class PlayerData : CharacterData
{
    public float firingPeriod = 0.1f;
}
Unity 在編譯後會出現錯誤訊息,"The same field name is serialized multiple times in the class or its parent class. This is not supported: Base(Player) data":

即使可以忽略錯誤訊息將 PlayerData 的 scriptable object 設給 data 欄位:
但只要重新編譯後,該欄位還是會變回 None,即使為基礎類別的 data 加上 [HideInInspector] 的性質。因為 Unity 無法為一個物件同名的欄位初始化多次(一次是 Player 裡的 data,一次是繼承的 Character 裡的 data)。
2020年7月12日 星期日

[筆記] API 設計概念 — 下篇

  下篇整理演講後半的內容,主要更進一步探討類別跟函式的設計概念。

類別設計


減少易變性(mutability)

  • 除非有好理由,不然類別應該要 immutable:好處是單純、thread-safe、可重複使用;缺點是每個不同的值都是獨立的物件,也就是為了改一個值,就要放棄現在的物件取得新的物件。
  以 python 為例,int 是 immutable 的,所以使用 '1' 的值,它只要產生一次對應的物件,後續只要使用到 '1' 的值,就使用同一個物件即可。
>>> id(1)
10914496
>>> x = 1
>>> id(x)
10914496
2020年7月11日 星期六

[筆記] API 設計概念 — 上篇

  當初在設計 MLGame 專案時,為了能夠讓遊戲開發者和玩家能夠使用 MLGame 架構,於是嘗試查了關於 API 設計的概念。本篇整理一場 Google 的技術演講,演講標題為「How to Design a Good API and Why it Matters」,演講雖然是在講 API 的設計概念,但我認為這些概念在平常撰寫程式上也很受用。演講以 Java 為舉例語言,文章中會引用演講中的例子,我也會盡量舉在專案中(以 Python 撰寫)遇到的情況。
上篇整理演講前半段的部分,主要是 API 設計的通用概念。

為何 API 設計重要?


  • 好的 API 可以是公司最重要的資產之一:客戶會使用 API 來製作產品,同時也會學習使用 API。而放棄一個 API 去學習另一個全新的 API 的成本太高,所以一個好的 API 會吸引客戶來使用
  • 壞的 API 就會是公司的負債:客戶會佔滿客服線路。公司要修改 API 也會困難重重,造成技術負債
  • 發布的 API 就發布了:修改 API 可能會造成客戶的程式崩潰。

為何 API 設計對你重要?


  • 平常寫程式也是在做 API 設計:好程式是模組化的,而模組之間的界線就是 API。而且好的模組應該要能夠一再被重複使用
  • 以 API 設計的方式去寫程式可以增進程式品質

2020年3月18日 星期三

[筆記] 矩形的碰撞偵測 (下篇) - 沒被偵測到的碰撞

  有時就是天不從人願,當覺得碰撞 OK,反彈 OK 的時候,就會出現不 OK 的情況。做了一個球速會漸漸加快的 pixel game,然後遊戲就逐漸毋湯。當球移動的速度很快的時候,球會穿越平台,連碰撞都沒有被偵測到,然後就蹦蹦了。

問題點


如圖所示,當球一次移動的距離大於板子的厚度時,板子可是一點感覺都沒有呢。因為球的移動並非連續移動,而是在這個影格是 A 地點,下一個影格就直接出現在 B 地點(直接加上要移動的距離)。可以想像做碰撞偵測時,是看當下每個物件的位子來判斷有沒有碰撞的,所以當球直接「掠過」板子時,就不會被偵測到碰撞。如此一來就會出現穿板的現象,原本應該繼續的遊戲,就 Game Over 了。

2019年7月10日 星期三

[筆記] 矩形的碰撞偵測 (中篇) - 反彈

  處理完碰撞後,接著就要來處理碰撞後的反彈。因為做的是打磚塊這類 pixel game,所以呈現的是簡單反彈,也就是反彈物體速度的 xy 分量的正負號變換(呈現出來是入射角 = 反射角,反彈後速率維持不變)。
  這個功能困擾的我很久,困難點在於如何判斷是哪個面發生碰撞。期間一直無法做出理想中的反彈效果。後來拋出問題向朋友求救,討論後終於得到解答,雖然想出來的演算法不盡完美,但大部分的情況下都能有預想中的反彈行為。

2019年6月16日 星期日

[筆記] Unity3D 設置 Android apk 建置環境 - 不安裝 Android Studio

  以前可以直接單獨下載 Android SDK manager 來管理 Android apk 開發環境,但後來必需安裝 Android Studio 才可以使用 SDK manager。Android Studio 需要大量空間與資源,對於只需要 Android SDK 的我來說顯得多餘,此外要使用 manager 還必須先等待 Android Studio 啟動,相當不方便。幸好還是可以透過 command line tools 來管理 SDK 套件。

  本篇文章要建立 Android apk 建置環境所需要的套件如下,示範的作業系統為 Windows:
  • Java SE Development Kit (JDK) 8
  • Android SDK Tools 25.2.3 (也就是 SDK manager)
  • Android platform 27 (Android 8.1,要選擇其他 API level 可以查看對照表)
  • Android build-tools 27.0.3 (Android 8.1)
  • Android platform-tools