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

2019年3月31日 星期日

[筆記] Django - File Validator 上傳檔案與驗證

  Django 的表格 (Django.forms.Form) 能夠從設定的欄位產生對應的 html 表格,並幫助開發者從提交的資料中過濾有害的資訊,將資料轉換成 Python 物件供取用。還可以撰寫額外的程式碼以驗證提交的資料是否有效。
  撰寫驗證資料的方式有三種:在表格的定義中撰寫 clean_<field_name> 函式、繼承對應的欄位類別並提供 validate()、撰寫驗證類別並傳入到對應的欄位中。本篇網誌使用第三種方法來驗證使用者上傳的檔案,檢查檔案副檔名、MIME type、檔案大小。

2019年1月17日 星期四

[筆記] 矩形的碰撞偵測 (上篇)

  寫遊戲常常用 API 來幫忙處理碰撞偵測,當需要自己寫類似的功能時,發現內部的運作沒有想像中的簡單。最近因為專案的需求,撰寫打磚塊遊戲,原本想利用 pygame 的碰撞偵測,但是不適合這個專案,只好挽起袖子研究研究作作看。上篇介紹矩形碰撞偵測的原理,下篇則介紹在碰撞之後反彈的效果。

2018年12月3日 星期一

[筆記] Python - 應用 decorator 實作函式開關

  最近為了課程撰寫遊戲的 server 端 (專案於 Github),主要提供遊戲資訊跟進程控制的功能,client 端是一群擁有通訊功能的迷宮車,兩邊靠既定的指令溝通。在設計遊戲功能時,有些指令希望只在遊戲開始後才有作用,但又不可能讓 client 端乖乖在遊戲開始後才發送指令。最直觀的作法就是在每個處理指令的函式中檢查遊戲是否開始:
def game_command(...):
    if not game_is_started:
        return
    # Other jobs
但很快發現充滿重複的程式碼,而且影響程式碼的簡潔與維護的不方便。於是上網查找有無類似 C# 的 function attribute 的寫法,只要在函式的定義前加上像是 game_started 的 attribute,就可以控制該函式的行為。於是找到了 decorator (裝飾器)。

  本篇主要介紹我如何在專案中使用 decorator,先簡單介紹 decorator,接著是本篇主題 ─ 利用 decorator 來實作函式開關,與在類別中使用 decorator,最後是如何進一步強化 decorator 的能力。以下講解皆使用 python 3。

2018年3月4日 星期日

[桌遊/心得] 百鬼陰陽譚 與 棋幻爭霸

  介紹由硬盒子桌遊所設計的兩款募資桌遊。當初因為陰陽百鬼譚而知道硬盒子桌遊,個人頗喜歡百鬼譚的角色,再加上募資的組合中有奇幻爭霸,這位西洋棋控的手就忍不住了。(計畫通)

2018年2月19日 星期一

[桌遊/心得] 鋼鐵與火藥 ─ 文藝復興 與 歷史長流

  鋼鐵與火藥 ─ 文藝復興 與 歷史長流 這兩款桌遊都是由摩埃創意工作室設計出品的桌遊,這兩款桌遊的共同點為都是經營類型且擁有時代演進的概念。

2018年2月18日 星期日

[桌遊/心得] PANDEMIC 瘟疫危機 - 原版、The Cure (骰子板)、Contagion (病毒擴散)

  這次來介紹瘟疫危機系列的其中三款 ─ 原版、The Cure、Contagion。這是我第一款接觸到的合作遊戲,所有玩家共享勝利或失敗,有時候競爭類型玩多了,也可以嘗試每個人都是隊友的桌遊。
2018年2月17日 星期六

[桌遊/心得] RETREAT 系列 - 波波夫 popov

  身為一名喜好桌遊的傢伙,居然沒有想過要發一下自己的心得文(打頭)。因此趁著過年空閒的時間,打算整理出自己目前擁有的桌遊的心得文,也一起推廣桌遊與尋找同好。

  這系列的文章以項目式對每一款桌遊做介紹。「介紹」部分會簡述該桌遊的核心玩法與故事背景,並不會介紹詳細的玩法,方便直接了解這款桌遊。「心得」與「喜好程度」部分則是個人對於這款桌遊的感想,我喜歡策略類型的桌遊,因此心得這部分不會是客觀的。「類型」的策略量度是:輕度,局勢簡單,行動不會太繁雜;中度,局勢需要經過推理思考,行動稍微複雜;重度:就像權力遊戲桌遊那樣重吧。

2017年9月7日 星期四

[筆記] 多一點、少一點 ─ 雷切或 3D 列印卡榫時的預留空間

  個人在設計作品時,多多少少會加入螺絲孔,或是耍廚想要作一個純粹使用卡榫固定的作品。而當材料的製作是使用雷切或是 3D 列印時,在設計時就要考慮一些眉角,讓螺絲孔或是卡榫能夠符合預期的樣子使用。本篇文章介紹我在使用雷切與 3D 列印的這方面的心得(我也只用過這兩種)

2016年11月27日 星期日

[筆記] 深入了解 switch-case

  之前在課堂的作業中第一次看到神奇的 switch-case 用法,藉著機會研究一番;剛好朋友也詢問了類似的問題,也查看更多資料,完全顛覆我以前對 switch-case 的理解。因此藉著這篇文章來記錄我所查到的知識,也順便掃掃灰塵((汗。

  最初學到的 switch-case 用途是「多重選擇」,也就是說用來取代一連串的 if-else statement 對於一個變數的連續判斷,如以下的例子:
if (value == 0)
    printf("Grade S\n");
else if (value == 1)
    printf("Grade A\n");
else if (value == 2)
    printf("Grade B\n");
else if (value == 3)
    printf("Grade C\n");
else
    printf("Grade D\n");
可以用 switch-case 取代成:
switch (value) {
    case 0:
        printf("Grade S\n");
        break;
    case 1:
        printf("Grade A\n");
        break;
    case 2:
        printf("Grade B\n");
        break;
    case 3:
        printf("Grade C\n");
        break;
    default:
        printf("Grade D\n");
        break;
}
基礎複習完了,大家可以回家了。

以下會討論到:
  • 在 switch-case 中宣告變數
    • 在 switch 之下,case 之前
    • 在 case 中宣告變數
    • 不同 case 之間宣告相同名稱的變數
  • 不只是 if-else 的替代品 (對於一個變數的連續判斷)
而接下來的討論皆引用 C98/99 的規格書,需要一點 language syntax 的概念。
2016年8月21日 星期日

[DIY] OSU!mania 7K 控

  因為自己是個音 G 熱愛者,之前在網路上找到這篇 ─ [DIY 專區]自製 IIDX 控制器 Part1,於是也想要自幹一個 OSU!mania 7K 控 (差一個轉盤),還可以在家先練練識譜,不然之前四個人去打 IIDX 還比不過一個人((淚

設計


  基本上就是弄出一個箱子,然後挖幾個洞,放進按鈕,就完成了,你看很簡單吧。

設計草稿:大致上把設細想法規劃一下,因為我是用 5mm 雕刻版配合雷切去製作箱體,所以垂直接點的地方採用凹凸卡榫,這樣就不用膠去固定。整個箱體只有控制板是用螺絲固定,為了方便拆卸修理。

2015年5月9日 星期六

Unity3D - Circular Scrolling List - Part 2 - 顯示內容

了解 ListBox 的移動概念後,接下來就要顯示內容拉~

以下分成幾個部分:

  • ListBank
  • 初始化內容
  • 更換內容

2015年3月29日 星期日

[桌遊工具] 全手動給牌盒

當玩牌多的桌遊時,是否有這些困擾?
上了卡套之後,牌堆容易傾倒?



或是棄牌堆混亂不堪,難以整理?

2014年9月4日 星期四

Unity3D - Circular Scrolling List - Part 1 - 移動概念

實作影片:https://youtu.be/iZSN6CC--9Y

這個 Scrolling List 有幾個特色:
  • 使用固定數量的選單物件來代表無限數量的內容
  • 弧形移動效果
  • 慣性移動效果
將它分成幾的部分來教學:
  • 滑鼠動作
  • 慣性滑動
  • 多個物件同時移動
  • 邊界處理及環狀功能
  • 弧形移動