本節書摘來自異步社群《android 應用案例開發大全(第3版)》一書中的第2章,第2.7節線程相關類,作者 吳亞峰 , 蘇亞光 , 于複興,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視
2.7 線程相關類
上一節已為讀者詳細介紹了繪制相關類,在讀者進一步了解本案例的基礎上,在這一節将對線程相關類的開發進行詳細的介紹。前面已經完成了對水族館背景及水族館中的魚、魚群、魚食和氣泡的繪制開發,隻繪制出模型是不夠的,還需要讓它們動起來,進而産生更加真實的效果。
該桌面開發中開啟了多個線程,使得本案例中的場景更加活靈活現,更加逼真。線程相關類主要包括氣泡移動線程類、群魚遊動線程類、魚群遊動線程類、魚食移動線程類和吸引力線程類,下面将對線程相關類的開發進行詳細的介紹。
2.7.1 氣泡移動線程類——bubblethread
前面已經完成了對3d水族館中氣泡的開發,但隻開發出一個模型是遠遠不夠的,這就需要讓氣泡移動起來,并可以讓多處位置連續不斷地冒出氣泡來,這樣場景才會更加逼真。這就是本類的作用,本類開啟了一個線程定時移動氣泡,并在不同位置冒出。其具體代碼如下。
第1~10行為聲明相關成員變量,通過構造器,擷取bubblecontrol的引用,為後面線程中調用bubblecontrol類中的bubblemove方法做準備。其中省略了部分類和包的引入代碼,請讀者自行查閱随書CD光牒中的源代碼
第11~32行為該類中氣泡移動線程方法,在該方法中周遊氣泡清單bubblesingle。為了能夠在場景中出現3處氣泡,是以将氣泡隊列切分成3隊,并根據每個隊列中氣泡的奇偶性來給出y的值,以作為氣泡x、z軸移動的擾動變量,并調用氣泡移動方法bubblemove,然後休眠10ms。
2.7.2 群魚遊動線程類——fishgothread
上小節介紹了氣泡移動的線程bubblethread,本小節将為讀者介紹群魚遊動的線程。線上程中有關于群魚之間的受力算法,以防止兩條魚互穿;還有關于群魚碰到魚群的受力變化,以及群魚和牆壁碰撞時群魚的受力如何變化。其具體代碼如下所示。
第3~24行首先周遊魚群、群魚清單,并計算單條魚所受到的其他魚的力和魚群對該魚的力。當魚與其他單條魚或群魚之間的距離小于阙值後會産生力的作用,這樣計算群魚中的魚一直遊動,并不會與魚群發生碰撞。
第25~47行是對碰壁檢測處理的代碼,這裡計算了魚與上、下、左、右、前、後牆壁的檢測,然後判斷魚某個方向的位置是否超過了牆壁的範圍,如果超過,則牆壁給一個相反方向的力,然後将魚所受到的力與牆壁給魚的力相加求出魚所受到的合力。
第49~50行周遊所有魚的速度與位移。周遊所有群魚中的魚,調用fishmove方法使之動态地修改魚的速度與位移,并讓線程睡眠後重新整理群魚,這樣,群魚在場景中就會一直的由來遊去,非常酷炫。
2.7.3 魚群遊動線程類——fishschoolthread
上一小節為讀者介紹了群魚遊動的線程類,本小節将着重介紹魚群遊動的線程類——fishschoolthread,其中計算了魚群與群魚之間的受力,使之不會碰撞,還計算了魚群中魚受到從該位置指向相對位置的力,以及魚群與牆壁碰撞時的受力情況。
(1)首先給出了fishschoolthread類的整體架構。魚群中單條魚受到的向心力以及群魚碰壁檢測等其他算法代碼過多,将在後面詳細介紹。接下來詳細介紹魚群之間的受力算法,主要是群魚對魚群的作用力情況等。具體代碼如下所示。
第4~9行是本類中一些變量的聲明還有構造器的初始化。将線程是否開始的标志位設定為true,并獲得魚群控制類對象fishschoolcontrol,為下面的算法調用控制類對象中的方法,以及聲明兩條魚之間的距離。
第14~35行當魚群中的某條魚與魚群中的距離小于阙值後便對該魚産生作用力。第一條魚隻受牆壁的力。魚群中其他3條魚互相沒有力的作用,也沒有第一條魚的力。它們受到從該位置指向相對位置(以魚群中第一條魚的位置為中心,以定半徑确定的球面上的一個點)的力,并受群魚的力。
第36~45行為修改魚群裡面所有魚的速度和位移。調用每條魚的fishschoolmove方法定時修改魚群裡面魚的速度和位移。進行異常處理,如果出現異常,則列印出異常。并讓線程睡眠50ms後重新重新整理魚群。
(2)上面詳細介紹了魚群碰見群魚之間的受力算法與魚群中魚的受力情況算法。下面将為讀者詳細介紹(1)中省略的魚離開魚群的受到恒力的算法,以及魚群和牆壁碰撞時的魚群受力變化的算法。這樣魚群一直是魚群,不會被沖散。其具體代碼如下所示。
第1~26行給離開魚群的魚賦予一個恒力。一旦這條魚相對脫離了魚群之後就會受到一個恒力使這條魚遊回魚群,該條魚遊的距離魚群越遠這個恒力就會越大,進而使魚群裡面的魚能夠快速地回到魚群,使魚群一直是魚群,不會被沖散。
第27~35行是魚群裡面第一條魚與水族館中的上牆壁、下牆壁、左牆壁、右牆壁、前牆壁及後牆壁的碰撞檢測,碰撞時牆壁會對魚群裡面的第一條魚産生力的作用,這樣魚群就會一直在魚缸中遊來遊去。
2.7.4 魚食移動線程類——foodthread
上一小節詳細介紹了對魚群的移動線程控制類,讀者已經了解了魚群的移動方法。本小節将為讀者詳細介紹魚食的移動線程類foodthread,本小節中将着重為讀者介紹魚食的移動方法,以及對魚食标志位的設定等,具體代碼如下。
第4~11行是本類中一些标志位的初始化與本類中的構造。其中一些标志位的初始化有助于讀者更加容易地了解本類中的邏輯關系,其構造器是拿到singlefood類的引用,為後面調用其中魚食的坐标做準備。
第12~31行是本類中魚食移動的線程方法,本案例中的魚食從上到下勻速運動,并且每次計算失誤y軸所在的位置之前,會通過增加或減少食物的x、z坐标來使食物産生輕微的晃動效果,進而增加食物的真實感,讓線程休眠100ms後重新整理魚食。
2.7.5 吸引力線程類——attractthread
上一小節中介紹了食物的移動線程。本小節着重介紹魚食對群魚的吸引力線程類attractthread,本案例中群魚是可以看到魚食的,但是魚群看不到魚食,是以魚群不會受到食物吸引力的影響。本節将詳細介紹這是如何操作的。
(1)下面将為讀者重點介紹本類中魚食對群魚的吸引力的算法,并定時對每條魚的吸引力進行重新整理。每當魚食落下的時候,如果某條魚看到了魚食,這條魚就會朝魚食遊去,将魚食吃掉,這樣使百納水族館桌面更加地真實逼真。具體代碼如下。
第4行為省略掉的部分變量與構造方法代碼。此代碼中部分變量主要是設定線程标志位、設定清空标志位(每次喂食之前會清空清單f1)、是否計算食物吸引力的标志位。并建立受到食物吸引力的魚清單。
第5~24行首先判斷是否需要喂食。開啟喂食後尋找能看到魚食的魚,每喂食一次清空受到吸引力的魚清單f1,然後在喂食的時候重新尋找滿足條件的魚,如果滿足條件把該條魚添加到受到吸引力的魚清單f1中。
第25~45行是開始喂食後,計算f1裡面魚受到食物吸引力的算法。能看到魚食的魚受到一個由該條魚目前位置指向食物的吸引力的作用。這樣當開始喂食時,一條魚看到魚食會自動地向魚食遊去,并将魚食吃掉。
(2)上面介紹了當開始喂食時,如何尋找能夠看到魚食的魚的算法,并介紹了如何操作當魚看到魚食後的遊動問題。下面将為讀者介紹如果魚食被吃掉或者魚食位置超過地面後,如何對魚食進行操作的方法stopallthread()。
第1~8行為stopallthread方法,若魚食位置超過地面,或者魚食被魚吃掉後,就會調用此方法,把魚食移動線程裡面的計算标志位和計算群魚是否受到的食物吸引力标志位變為false,同時點選喂食的标志位設定為true,進而能點選螢幕在此喂食。