前天晚上睡前突然想起了當初接觸Python時的靈魂導師小甲魚,然后想到了他的一道經典課后題咆耿。
游戲編程:
按以下要求定義一個烏龜類和魚類并嘗試編寫游戲。
假設游戲場景為范圍(x, y)為0<=x<=10凯正,0<=y<=10
游戲生成1只烏龜和10條魚
它們的移動方向均隨機
烏龜的最大移動能力是2(Ta可以隨機選擇1還是2移動)拍埠,魚兒的最大移動能力是1
當移動到場景邊緣芯急,自動向反方向移動
烏龜初始化體力為100(上限)
烏龜每移動一次勺届,體力消耗1
當烏龜和魚坐標重疊,烏龜吃掉魚娶耍,烏龜體力增加20
魚暫不計算體力
當烏龜體力值為0(掛掉)或者魚兒的數量為0游戲結束涮因。
思路分析
首先可以確定的是這種需要過程遞推的方式在solver內進行。
那么在solver之前需要解決:
1.隨機分布
可以把烏龜和魚抽象成兩組點伺绽,用pointWangle在 0-10的范圍內撒點养泡。同時要注意坐標取整問題,可以借助floor()函數奈应。(如果有round()可以四舍五入就好了)
Solver內需要解決:
2.隨機移動
因為結果需要用關鍵幀遞推來實現澜掩,所以隨機移動的隨機seed也可以用當前幀數也就是@Frame茸炒,作為seed宇挫。
rand()返回的隨機數是[0,1] 的浮點值,借助fit01() 適配到 [-1,1] 或者[-2,2] 同時用floor()取整就可以模擬烏龜和魚的移動步長了氏捞。
3.體力值惩妇,移動消耗
可視化的體力值可以用pscale來表現株汉,暫定初始值為1,solver的每一次運算歌殃, pscale -= 0.01乔妈。
4.烏龜吃魚
只要判斷魚的點和烏龜的點坐標是否重合就可以了,如果相同:
- 烏龜的體力值pscale += 0.2 氓皱,
2.魚的點被去除路召,這里用到removepoint() 勃刨。
如果不相同則繼續(xù)進行下一輪推導。
Ok, let's dive into Houdini!
首先是在空白的集合體內撒點股淡,這里用到pointWrangle身隐。
float seed = chf('random_seed');
for(int i=0; i<10; i++){
int fishX = floor((rand(i+seed)*10));
int fishZ = floor((rand(i+134+seed)*10));
vector fishP = set(fishX,0,fishZ);
addpoint(0, fishP);
}
注:直接創(chuàng)建wrangle并用addpoint()理論上是不會出現點的,因為所有的wrangle都需要輸入端唯灵。
再注:同樣的seed返回的隨機數是相同的贾铝,這里用手動添加seed和增加常量的方法,目的是讓fishX和fishZ的值有所區(qū)別埠帕。
同樣的方法創(chuàng)建烏龜的點組忌傻,借助attribute create為烏龜組添加pscale屬性,默認更改為1搞监,同時為小魚組添加一個隨機0.2-0.4的pscale,主要是視覺上比較好看镰矿。
從這里可以發(fā)現琐驴,最后一個永遠都是烏龜,前面的是小魚秤标。那么只要通過npoint()來查找總點數-1 = 烏龜的點序列绝淡。
接下來進入solver開始推導,Solver主要解決三個問題苍姜,
1.魚的移動牢酵,每次在[-1,1]的整數值間選擇;
2.烏龜的移動衙猪,每次在[-2,2]的整數值間隨機選擇馍乙,且伴隨體力消耗-0.01;
3.烏龜吃魚垫释,當烏龜點和小魚點重合時丝格,小魚點被剔除,且烏龜體力 +0.2棵譬;
需要解決一個問題显蝌,魚和烏龜的移動是二維的,如何選定到底是在X軸還是在Z軸移動订咸?這里可以基于當前幀做隨機數曼尊,然后取整返回0或者1,定義一下0代表移動X脏嚷,1代表移動Z骆撇。
同時要注意,rand(@Frame) 返回的值是在[0,1]區(qū)間內的父叙,如果直接floor()取整艾船,獲得1的概率非常小葵腹,顯然不公平。所以這里需要將 [0,1]區(qū)間擴大到[0,2]屿岂,此時再用floor()践宴,返回0和1的概率就相同了。
首先是魚的游動問題爷怀,選定fish所在分組阻肩,分別將X軸和Z軸移動作為屬性捆綁到每個點,通過隨機數配合不同的seed來完成隨機篩選运授,這里額外定義了一個@first屬性烤惊,用來控制在X軸或Z軸移動。
然后需要判斷是否存在“碰壁”情況吁朦。如果在0位置且移動數值是-1柒室,則返回0-(-1) ,如果是在9位置且移動數值為1逗宜,則返回9-(1)雄右,在0和9之間,就直接簡單粗暴 P.x + stepX就好了纺讲。
小魚移動代碼如下
i@stepX = floor(fit01(rand(@Frame*(@ptnum+1)+1231235)*2,-1,1));
i@stepZ = floor(fit01(rand(@Frame*(@ptnum+1)+1235)*2,-1,1));
i@first = floor(fit01(rand(@Frame*(@ptnum+1)+12345)*2,0,1));
//first = 0 ---------------> moveX
if(@first == 0){
i@stepZ =0;
if(@P.x <= 0 && @stepX < 0){
@P.x -= @stepX;
}
if(@P.x >= 9 && @stepX > 0){
@P.x -= @stepX;
}
if( 0<@P.x<9){
@P.x += @stepX;
}
}
//first = 1 ---------------> moveZ
if(@first == 1){
i@stepX = 0;
if(@P.z <= 0 && @stepZ < 0){
@P.z -= @stepZ;
}
if(@P.z >= 9 && @stepZ > 0){
@P.z -= @stepZ;
}
if( 0 < @P.z < 9){
@P.z += @stepZ;
}
}
同樣的擂仍,烏龜移動的代碼也可以在小魚的基礎上更改,只需要把數值范圍擴大到[-2,2]就好了熬甚,這里記得更改一下隨機seed逢渔,以便減少魚和烏龜移動路徑的重復性。同時不要忘記勾選wrangle針對的烏龜組乡括。(此處更加明白了面向對象編程的重要性)
烏龜移動代碼如下
i@stepX = floor(fit01(rand(@Frame*(@ptnum+1)+123123565)*2,-1,1));
i@stepZ = floor(fit01(rand(@Frame*(@ptnum+1)+123235)*2,-1,1));
i@first = floor(fit01(rand(@Frame*(@ptnum+1)+12234345)*2,0,1));
//first = 0 ---------------> moveX
if(@first == 0){
i@stepZ =0;
if(@P.x <= 0 && @stepX < 0){
@P.x -= @stepX;
}
if(@P.x >= 9 && @stepX > 0){
@P.x -= @stepX;
}
if( 0<@P.x<9){
@P.x += @stepX;
}
}
//first = 1 ---------------> moveZ
if(@first == 1){
i@stepX = 0;
if(@P.z <= 0 && @stepZ < 0){
@P.z -= @stepZ;
}
if(@P.z >= 9 && @stepZ > 0){
@P.z -= @stepZ;
}
if( 0 < @P.z < 9){
@P.z += @stepZ;
}
}
//pscale ---------------> -0.01
f@pscale -= 0.01;
注:不要忘記烏龜是有體力值的肃廓!每次移動體力值-0.01。
接下來就是烏龜吃魚的部分了诲泌!
烏龜如果沒吃到魚自然不需要有什么運算亿昏,直接繼續(xù)解算繼續(xù)走就可以了。
如果烏龜吃到了魚档礁,首先烏龜體力值+0.2角钩,然后小魚被從幾何體中剔除。
因為是在烏龜和魚都存在的幾何體層面工作呻澜,分組篩選已經行不通了递礼,但是!之前我們說過烏龜肯定是最后一個點羹幸,所以求得的總點數-1 = 烏龜的點序號脊髓。借助npoints()可以返回當前幾何體的點數。
烏龜吃魚需要用到for循環(huán)栅受,循環(huán)的次數為魚的個數将硝,也就是總點數-1 恭朗。每次移動后用烏龜的坐標和每一條魚的坐標去對比,如果相同則魚被吃掉同時烏龜體力值+0.2依疼。
讀取烏龜和小魚的點坐標痰腮,可以借助point()。
借助setpointattrib()來修改烏龜的pscale律罢。
借助removepoint()來剔除被吃掉的點膀值。
注:這兩個函數內的point_num都可以用循環(huán)中的指針i來引導。
結構如下
代碼如下
int npt = npoints(0);
vector turtleP = point(0,'P', npt-1);
for( int i=0; i<npt-1; i++){
if( point(0, 'P', i) == turtleP){
float npscale = point(0, 'pscale', npt-1) + 0.2;
setpointattrib(0, 'pscale', npt-1, npscale);
removepoint(0, i);
}
}
至此主要程序架構就結束了误辑,通過copy to point 選擇不同的組來進行幾何體復制沧踏,這里用了Houdini自帶的烏賊和海龜玩具。
注:
勾選pack and instance是為了讓幾何體以內存指針形式存在巾钉,從而不需要復制詳細信息轉而以一個點來取代翘狱,也就是之前我們寫入的小魚和烏龜的點。
同時要檢查geometry spreadsheet中點的坐標是否正確砰苍,如果和輸入點的數值有差別潦匈,通常是因為沒有將Pivot Location 改為Origin。
如果深入還可以從以下幾點入手:
1.幾何體的移動方向伴隨轉動师骗;
2.幾何體移動從跳動變?yōu)榫€性移動;
有時間再回來迭代吧!先睡了讨惩!
Cheers !