回顧并為今天的內容鋪墊背景
我們剛開始為游戲主角編寫一些程序邏輯,因為我們之前已經完成了大部分引擎方面的開發,現在可以專注在角色身上。這個角色的移動方式會有些特別,與大多數游戲角色的運動機制不太一樣。我們當前正在實現的控制方式在其它游戲中幾乎沒有見過,因此會顯得有些不尋常。我們也需要經過反復調試,才能讓這種方式看起來自然、操作起來順暢,但這正是游戲開發的樂趣所在。
現在角色的“頭部”和“身體”是分離的狀態,這種設計在視覺上看起來可能有些怪異,但這只是我們實現運動邏輯的一部分暫時手段。我們的設想是,讓角色的身體部分始終鎖定在屏幕上的某一個特定位置。雖然目前使用的是網格系統(grid),因為很多關卡場景會需要網格式布局,但實際上不強制使用網格,未來也可能會有非網格的設計。然而,不管布局如何變化,角色的身體都會始終鎖定在某一個固定的點位上。
我們已經畫出了一些橙黃色的參考方塊,角色的身體會貼合在這些方塊上。當前的目標是,讓身體總是處于這些點位之一,而當我們移動角色的頭部時,角色的身體并不會立即跟隨,而是會“傾斜”過去。只有當頭部的移動超過中點時,角色的身體才會真正地“跳躍”到下一個點位。這不是代碼中的瞬移,而是真正表現為角色用跳躍的方式跳過去。
頭部的移動是可以自由控制的,雖然最終控制方式會與現在略有不同,但整體感覺類似。我們還計劃加入一個邏輯:如果玩家停止移動,頭部會自動回到身體的原始位置,即“脖子”的位置。
接下來的開發任務包括:
- 編寫正式的代碼邏輯,確保身體始終鎖定在指定的點位上,而不是現在這種臨時的實現;
- 實現身體的拉伸與旋轉,使其在視覺上與頭部保持連接狀態,避免出現頭部像是懸浮的情況;
- 編寫“跳躍”動畫的邏輯,讓身體在從一個位置跳到另一個位置時看起來自然、連貫;
- 可能還需要幾天時間完成這些內容,因為我們每天只進行一個小時的開發;
- 由于這將是游戲中與玩家交互的核心機制,因此必須確保這一套移動方式手感良好、效果美觀。
雖然這不會是最終的版本,后期仍會根據整體設計不斷進行調整,但我們現在需要一個比較理想的第一版本,確保機制基本穩定,再繼續推進后續開發。移動機制如果做得不好,整個游戲的體驗就會受到嚴重影響。
每個人對角色操作手感都有自己的看法,有人可能覺得自己的偏好是“唯一正確”的,這其實是個誤區。不同的設計方向代表不同的游戲風格,我們只需要堅持讓自己滿意、合理的實現方向。
我們已經開始在 world_move.cpp
中編寫了基礎代碼,當前主要是讓身體根據頭部位置尋找最近的可站立點,并使用我們已有的通用移動代碼靠近這個點位。如果身體已經處于目標點上,就保持不動。這個邏輯目前只是原型實現,存在一些問題,尤其是它過于“模擬化”(analog),對于我們這種設計不太合適。
接下來,我們還會繼續調整,使其在邏輯和表現上都更加貼合我們對角色運動的最終構想。
黑板講解:站立模式與移動模式作為兩種獨立狀態
我們目前比較擔心的一個問題是角色的身體現在只是簡單地跟著頭部移動,并沒有明確區分角色的狀態階段。舉個例子,現在我們有一個頭部和一個身體,身體處在某個固定點位上。而我們現在的代碼邏輯僅僅是在不停地計算“我要去哪里”,然后讓身體往那個目標點移動。
目前這套邏輯只有一個階段:移動階段。也就是說,系統始終在考慮當前位置和目標位置,然后不停地嘗試靠近目標。如果目標點正好和當前位置一致,就沒有移動發生,看起來像是角色停住了,但其實只是碰巧目標和當前位置重合而已。
這種方式存在很多問題,比如移動不夠精準、存在過沖(overshoot)、缺乏平穩的停靠邏輯等。而且這套邏輯對“是否到達目的地”沒有概念,只是不斷追趕目標點。如果想實現“到達即停止”的效果,只能人為設定一個閾值(epsilon),例如靠近目標點到一定距離內就認為到達了,但這顯然不是理想的做法。
因此,我們現在打算將角色狀態明確分為兩個階段:
- 站立狀態(Stand):表示角色當前處于某個點位上,沒有發生跳躍或移動;
- 移動狀態(Movement):表示角色正在從當前位置跳躍或移動到另一個點位。
通過引入明確的狀態區分,我們可以讓代碼更加清晰地知道角色此刻處于哪種行為模式,從而更好地控制動作觸發和過渡邏輯。這也將為后續更復雜的動畫表現(如跳躍、蓄力等)打好基礎。接下來將會進行這方面的重構與完善。
黑板講解:有限狀態機(Finite State Machines)
有些人曾經問我們能不能解釋一下“有限狀態機”(Finite State Machine,FSM)。雖然我們之前沒來得及講,現在可以稍微談一下。我們認為“有限狀態機”這個詞本身被過度神化了,它聽起來像是一個很正式的理論結構,但實際上,在實際編程中,并沒有必要那么正式,甚至那種“形式化”的東西反而會成為負擔。
如果去讀編譯器相關的文獻,會看到非常嚴謹的“有限狀態機”的定義,比如確定性和非確定性狀態機等。這些在理論計算機科學里確實有它們的價值,適合做一些形式分析或模型驗證等用途。但在我們真正編寫代碼、實際開發中,它們并沒有太多直接的幫助。
原因在于,這種思維方式從問題的反方向出發。就像面向對象編程(OOP)一樣,把“狀態”這個概念看得過于核心、過于神圣,然后試圖讓一切邏輯都圍繞狀態展開,這是一種本末倒置的方式。狀態并不是代碼的出發點,也不是第一要務,我們認為更合理的方式是:在自然開發過程中,代碼中自然而然地會顯露出某些“狀態”的特性,我們再順勢而為去引入狀態控制。
而不是一開始就設計一個龐大的狀態機結構,把問題往一個固定框架里塞進去,那樣反而會限制靈活性,容易陷入類似面向對象設計那樣的誤區。所以我們認為,“狀態”應該是自然演化出來的,而不是一開始就強加的框架。
這并不意味著狀態機本身是錯的。事實上,任何稍復雜的程序最終都會有一些代碼段看起來像是狀態機,或者從定義上說就是一個狀態機。比如,在代碼中寫一個 enum
類型來代表幾種不同的狀態,再配一個 switch
語句來處理各種狀態間的跳轉邏輯,這種結構就是最標準的狀態機體現。這是計算的基本原理之一,因此自然會出現在各種程序中。
但我們強調的是:不要以“設計狀態機”的名義去限制思維,而是先解決問題,等問題演變出需要狀態的結構時,再用枚舉加切換邏輯去表達,這樣寫出來的代碼更自然、清晰、靈活。
因此,在當前角色控制系統中,我們希望通過引入一個簡單的狀態邏輯,讓角色的身體存在“靜止”和“移動”兩種模式。在“靜止”模式下,無論頭部如何移動,身體都保持不動;只有在滿足特定條件時,身體才切換到“移動”狀態,并跳躍到下一個位置。
這個思路實現起來也很簡單,我們已經在代碼的 sim_region
文件中開始實現它。后續會繼續擴展這一結構,逐步完善角色的行為系統。
查看 game_sim_region.h 和 game_world_mode.cpp:實現在兩種移動模式之間切換的能力
我們引入了一個“模擬運動模式”(sim movement mode)的概念,用于控制角色身體的行為。當前設置了兩種模式:
- Planted(扎根):表示身體固定在地面上,不移動。
- Hopping(跳躍):表示身體將從當前位置跳躍到另一個位置。
在角色邏輯中,當我們描述角色的身體(比如 Hiro Body
)時,可以根據當前的運動模式進行判斷和處理。在 Planted
模式下,身體不應該進行任何移動操作;而在 Hopping
模式下,身體則會執行跳躍動作。
為了實現這一邏輯,我們在初始化時將運動模式設為 Planted
,也就是說,一開始角色身體是靜止的。我們把之前實現的追蹤目標點的代碼(即朝目標點前進的邏輯)保留在 Hopping
模式下,在 Planted
模式下則完全不執行移動。
接著我們要思考:如何觸發從“靜止”模式到“跳躍”模式的切換?
為此,我們引入了一個條件判斷機制。在每一幀更新時,我們會計算當前“頭部”的位置所對應的最近地面點,并將其與“身體”當前的位置所對應的最近地面點進行比較。如果兩者不相同,意味著頭部和身體所處的位置不一致,說明角色可能想要移動,此時我們就可以切換到 Hopping
模式。
為了實現這個判斷,我們將原有的“最近點”計算邏輯從原位置中提取出來,使其在兩種模式下都能使用。但只有當處于 Hopping
模式時,才會真正觸發跳躍行為。
此外,我們也考慮了使用一個“最小距離閾值”的判斷方式來決定是否要跳躍。例如可以計算目標點與當前身體位置之間的距離(使用平方距離以避免不必要的開方運算),如果距離足夠遠就觸發跳躍。這個計算方式使用的是兩點之間的 Delta,然后對其求平方長度,用來避免昂貴的開方操作。雖然現在的處理器中平方根運算已經不再那么昂貴了,但由于舊習慣,我們仍然選擇避免頻繁使用。
總之,我們目前已經實現了基礎的兩態運動模式控制邏輯——通過距離判斷來切換模式,并根據模式決定是否進行跳躍,接下來將會進一步完善跳躍邏輯的細節。
length 才對
「現在已經沒人關心平方根了」α
我們現在繼續完善角色身體的運動模式切換機制。為了使系統能夠根據實際情況在“跳躍”(Hopping)和“靜止”(Planted)之間自由切換,我們引入了一個容差值(tolerance),用于判斷身體是否足夠接近目標點從而停止移動。
具體流程如下:
- 我們首先計算身體當前位置與目標點(通常是頭部所對應的地面點)之間的距離差,即“身體位移向量”(body delta)。
- 然后對該向量計算長度平方(body distance),目的是避免調用昂貴的平方根運算。雖然現代處理器已經足夠快,平方根的計算性能開銷很小,甚至 sin 和 cos 也不是太大問題,但比起內存訪問,這些運算已經不值得過度優化,因此這里只是沿用舊習慣。
接下來,根據這個距離平方值來控制狀態的轉變:
- 如果距離大于預設容差(例如一厘米),我們認為目標發生了偏移,角色應進入跳躍模式(Hopping),開始朝目標點移動;
- 如果在跳躍過程中,當前位置與目標點之間的距離小于容差,我們就認為已經“到達”,于是切換回靜止模式(Planted)。
這樣我們就完成了一個基本的自動往返狀態切換系統。
但是在實際運行中,發現角色進入跳躍模式后無法成功切換回靜止狀態。為了解決這個問題,我們開始調試代碼。
首先懷疑的問題是:角色的阻尼(drag)不足,導致移動過程不能自然減速到足夠接近目標點,從而距離始終大于容差,導致狀態無法切換回 Planted。
另一個問題是調試體驗不佳,我們注意到無法點擊選中某些實體(例如角色身體),這使得觀察狀態非常困難。這表明當前的選擇系統存在缺陷,很多實體不能被正確高亮和查看,這在后續需要重點修復。
繼續排查發現,代碼中還有一些殘留的邏輯,比如實體碰撞(entity collision)被錯誤地設置為“無碰撞”(null collision),這可能是導致實體狀態異常的原因之一。我們將這些無關或舊的邏輯清除,以避免影響行為判斷。
總結來說,我們實現了一個基于容差值的自動狀態切換系統,但在運行中發現狀態切換存在問題,目前初步推測可能是阻尼參數不足或其他系統邏輯干擾,后續將繼續調試以解決問題,同時也要改善實體調試系統,確保能夠可視化查看所有關鍵組件的狀態。
調試器:進入移動代碼并發現我們在兩個模式間來回震蕩
我們目前遇到的問題是角色在切換到“靜止(Planted)”模式后仍然無法真正停下來,會在“跳躍(Hopping)”和“靜止”模式之間不斷來回切換,形成**震蕩(oscillation)**狀態。
為了排查這個問題,我們給“進入跳躍”和“回到靜止”兩個邏輯分支都設置了斷點,觀察程序的實際運行流程。最終發現確實是在兩個狀態之間來回反復切換。推測原因是因為當前的容差判定機制太粗糙,沒有考慮到物理模擬帶來的實際運動慣性。
我們意識到角色的移動系統中啟用了物理模擬,也就是說,即使當前角色的位置已經足夠接近目標點(滿足容差條件),由于之前的加速度已經停止但仍然存在速度(velocity),在沒有任何阻力(drag 為 0)的情況下角色仍然會因為速度慣性向前滑動,從而滑出目標點,再次觸發進入跳躍模式,形成循環。
為了解決這個問題,我們想到了一種簡單且有效的方法:在進入“靜止”模式的瞬間,手動將速度歸零。這樣角色就會立即停止移動,不再依賴自然減速或者阻力拖拽,從而避免在邊緣位置震蕩。
總結當前的核心改動和優化思路:
- 問題核心:物理系統導致角色在接近目標點后仍繼續滑行,造成狀態反復切換。
- 臨時解決方法:在進入“靜止”狀態后,將速度強制設置為零。
- 原因分析:我們之前只判斷距離是否足夠接近,卻忘了處理角色當前仍具有速度的情況。
- 未來優化方向:可能需要引入更完善的狀態過渡系統,包括判斷速度、加速度等動態參數,或者調整 drag 系數以更真實地反映角色停止的意圖。
通過這一調整,角色應該就能在正確時機真正停下來,避免來回震蕩的問題。
運行游戲并發現游戲停下來了
經過調整后,問題基本解決了。現在角色在接近目標點時確實能夠停下來,雖然仍然存在因為過度推進(overshoot)而導致的位置微小偏差,但這種情況已經得到了顯著改善。我們可以看到,角色在達到目標后不會再像之前那樣持續滑動,已經有效地停止了移動。
目前的核心問題是,角色依然會有輕微的過度推進問題,這意味著即使停止了,角色的位置可能會偏離目標一點點,但整體已經避免了之前的震蕩問題。
接下來,計劃進一步解決這種“過度推進”現象,可能需要調整速度和加速度的計算,或者引入更精確的拖拽(drag)控制來確保角色完全停在目標位置。
總結:當前的改動解決了角色狀態反復切換的問題,角色可以停下來,但仍需進一步優化過度推進的現象。
黑板講解:跳躍與方向改變
目前的目標是將角色的移動方式轉變為更符合動畫風格的流暢運動,而不是使用之前那種基于加速度和速度的離散式控制方法。我們希望通過更程序化的方式來控制移動,而這種方式可能會帶來不同的感覺和效果,但也可能是一種錯誤的方向,因此還需要進一步的實驗和調整。
目前游戲設計的要求是,角色的移動要從一個站位跳到另一個站位,且頭部的控制由玩家操作,這一設計已經確定。所以,我們需要確保當角色的頭部移動到目標位置時,角色的身體能夠相應地進行跳躍,并且跳躍動作應該有好的手感。問題出在,如果玩家在跳躍過程中改變了頭部的位置,應該如何處理這一情況。
舉個例子,如果角色從站位A跳到站位B,但在跳躍過程中,玩家將頭部移到了其他方向(比如回到A或向C),那么在跳躍時,身體應該如何反應?我們有兩種可能的處理方式,這兩種方式會對游戲的操作體驗產生不同的影響:
-
嚴格控制跳躍:一旦跳躍開始,角色的身體必須完成跳躍,即使玩家將頭部移動到其他地方,跳躍仍會繼續,身體會按照最初的方向完成跳躍,這種方式類似于籃球的風格:一旦開始行動就無法停止,玩家可以通過移動頭部進行躲避或改變方向,但身體的移動必須完成。
-
允許空中控制:在跳躍過程中,玩家可以控制角色的頭部,進而影響身體的方向,使得角色可以在空中調整目標,甚至可以跳到其他位置。這種方式給玩家更多的控制自由度,允許他們在跳躍過程中對角色的運動路徑進行調整,可能會讓游戲感覺更加靈活,但也可能導致操作的感覺不夠有力。
這兩種方式有著深遠的游戲設計影響。嚴格控制跳躍可能讓游戲更加具有挑戰性,增加了玩家決策的重量(例如,跳到錯誤的地方可能導致踩到陷阱或踩到敵人)。但這種方式可能讓玩家感到游戲過于沉重,缺乏靈活性。相對而言,允許空中控制會讓玩家感覺控制更加自由,但可能會導致游戲失去一些挑戰性,特別是在跳躍帶來的后果方面。
因此,決定是否允許空中控制需要考慮游戲的整體節奏和難度設計。允許空中控制的同時,可能需要平衡這一機制帶來的靈活性和游戲的挑戰性,尤其是在設計跳躍失敗或跳躍懲罰的情況下。
黑板講解:重力軌跡與拋物線
現在的目標是實現一種拋物線插值方法來模擬跳躍動作,因為跳躍的軌跡在空中會受到重力的影響,而重力的作用產生的運動軌跡就是拋物線。為了簡單明了地說明這一點,假設我們在沒有空氣阻力的真空環境中,重力作用下物體的軌跡是拋物線形狀。這意味著,物體跳躍時的軌跡是與時間的平方成正比的,也就是一個拋物線方程。
從物理學的角度來看,這個拋物線是由重力產生的加速度所決定的。重力加速度是一個常量,通常在地球表面是9.8米每秒的平方。加速度是位移的二階導數,這意味著它是物體位置隨時間變化的速度變化的速率。由于重力是一個恒定加速度,因此物體的運動軌跡會遵循拋物線規律。
具體而言,物理學中的位移方程可以通過積分得到。位置是時間的二次函數,這是因為加速度是常數。通過兩次積分重力加速度得到的位置函數,就是一個二次方程,也就是拋物線的數學形式。因此,任何在重力作用下的物體,其運動軌跡都將呈現拋物線形狀。
在物理學中,描述拋物線運動的基本方程是通過加速度公式得到的。假設物體在垂直方向上受重力作用,忽略空氣阻力,那么其位移公式可以通過以下幾個步驟推導得出。
-
加速度:物體受重力作用時,垂直方向上的加速度是恒定的,即 a = ? g a = -g a=?g,其中 g g g 是重力加速度,通常取 g = 9.8 m/s 2 g = 9.8 \, \text{m/s}^2 g=9.8m/s2。
-
速度:速度是加速度的積分,表示物體位置隨時間變化的速率。由于加速度是常數,我們可以通過積分加速度得到速度:
v ( t ) = ∫ a d t = ? g t + v 0 v(t) = \int a \, dt = -gt + v_0 v(t)=∫adt=?gt+v0?
其中, v 0 v_0 v0? 是初始速度,通常在物體開始跳躍時為零。
-
位移:位移是速度的積分,表示物體的位置。通過對速度方程進行積分,可以得到物體的位置方程:
y ( t ) = ∫ v ( t ) d t = ? 1 2 g t 2 + v 0 t + y 0 y(t) = \int v(t) \, dt = -\frac{1}{2} g t^2 + v_0 t + y_0 y(t)=∫v(t)dt=?21?gt2+v0?t+y0?
其中, y 0 y_0 y0? 是初始位置,通常在跳躍開始時設為零。
這個方程 y ( t ) = ? 1 2 g t 2 + v 0 t + y 0 y(t) = -\frac{1}{2} g t^2 + v_0 t + y_0 y(t)=?21?gt2+v0?t+y0? 描述了物體在重力作用下的垂直運動軌跡,也就是拋物線形狀。
- t t t 是時間,表示物體運動的時間。
- g g g 是重力加速度。
- v 0 v_0 v0? 是物體的初始速度。
- y 0 y_0 y0? 是物體的初始位置。
運動軌跡的特點:
- 拋物線軌跡:在忽略空氣阻力的情況下,物體在重力作用下的運動軌跡是拋物線形狀。物體先上升達到最高點,然后開始下落。
- 時間的平方關系:位移與時間的平方成正比,這使得軌跡呈現典型的拋物線形態。
總結起來,重力作為恒定加速度的影響,使得物體的運動軌跡呈現出一個拋物線的形態,這也是為什么我們在模擬跳躍時,會使用拋物線插值方法的原因。
「這就是……數學」β
既然已知重力導致物體運動軌跡呈拋物線,那么就可以直接在角色的運動中加入一個拋物線軌跡,使角色從一個位置跳躍到另一個位置,進入其彈道階段。同時,跳躍的時間需要根據游戲設計來設定。這個設計的思路是,角色的運動不應該作為一個整體來控制,而是分成兩個部分:一個部分是以更典型的游戲方式進行移動,這種移動是較為自由且略顯隨意的;而另一個部分則是非常具體且無法直接控制的,它的運動路徑已經預設,并且玩家不能干預其移動方向。
因此,角色的運動機制就是這樣設計的,一個部分由玩家控制,另一個部分則會按照設定的軌跡(例如拋物線軌跡)進行移動,這樣的設計帶來了不同的控制感受。
編輯 game_world_mode.cpp:為角色添加拋物線跳躍動作
當前的目標是實現一個拋物線跳躍動作的模擬,通過修改角色的移動模式。首先,角色在“站立模式”下不會有任何變化,玩家不會進行任何移動。在玩家需要進行跳躍時,會切換到“跳躍模式”,并使用一個“tMovement”變量來控制跳躍過程。這個“tMovement”變量將從0到1變化,表示跳躍的進度。
在實現上,首先需要知道每幀的時間增量(delta time),這個值已經存在于代碼中(命名為DT
)。通過這個時間增量,可以控制跳躍進度的變化。當跳躍開始時,tMovement
變量會被初始化為0,表示跳躍剛開始。隨著時間推移,tMovement
逐漸增加,當其達到1時,跳躍完成,角色落地,切換回站立模式。
實現過程中,跳躍的過程使用了“從0到1”的參數化方法,這樣可以簡化跳躍過程的處理,并讓我們更容易控制。具體來說,在跳躍的過程中,角色會沿著一個拋物線軌跡從起始點移動到目標點。為了做到這一點,首先需要確定目標點的位置,這個位置是角色跳躍的終點。
然后,通過線性插值的方式,角色的當前位置會根據時間增量和tMovement
變量的變化,平滑地從起始點移動到目標點。在這段過程中,可以調整速度來控制跳躍的快慢。為了加快跳躍速度,可以在tMovement
代碼中加入一個倍速因子,這樣就能實現更快的跳躍。
然而,單純的線性插值并不能真正模擬跳躍的拋物線效果,這只是角色從起始點到目標點的平滑過渡。為了加入拋物線的效果,接下來需要引入物理上的拋物線運動。通過在運動過程中加入垂直方向的加速度,模擬重力的影響,使得角色的移動軌跡呈現出典型的拋物線形狀。
簡單來說,角色的移動將從最初的線性插值過渡到帶有拋物線效果的運動,以實現更加自然的跳躍動畫。這樣,角色的跳躍不再是簡單的直線跳躍,而是受重力影響的曲線跳躍,帶來更真實的游戲體驗。
黑板講解:用于計算跳躍拋物線的公式
我們的目標是模擬一個跳躍動作,使物體從起點以拋物線的軌跡移動到終點。我們已經有起點(from)和終點(to)兩個點,而為了構造出完整的拋物線軌跡,我們還需要一個額外的參數——跳躍的高度。這個高度決定了拋物線的弧度,也就是中間的最高點。
我們先從數學角度分析這個問題。由于我們想要的是一條拋物線軌跡,所以函數的基本形式應該是一個二次函數,即:
f ( t ) = a t 2 + b t + c f(t) = a t^2 + b t + c f(t)=at2+bt+c
其中 t t t 是一個從 0 到 1 的歸一化參數,表示從起點到終點的進程。
我們已經知道以下兩個條件:
- 當 t = 0 t = 0 t=0 時,位置應為起點 P from P_{\text{from}} Pfrom?
- 當 t = 1 t = 1 t=1 時,位置應為終點 P to P_{\text{to}} Pto?
將這些條件代入公式:
-
f ( 0 ) = a ? 0 2 + b ? 0 + c = c = P from f(0) = a \cdot 0^2 + b \cdot 0 + c = c = P_{\text{from}} f(0)=a?02+b?0+c=c=Pfrom?
??→ 因此我們知道 c = P from c = P_{\text{from}} c=Pfrom? -
f ( 1 ) = a ? 1 2 + b ? 1 + c = a + b + P from = P to f(1) = a \cdot 1^2 + b \cdot 1 + c = a + b + P_{\text{from}} = P_{\text{to}} f(1)=a?12+b?1+c=a+b+Pfrom?=Pto?
??→ 整理后得 a + b = Δ = P to ? P from a + b = \Delta = P_{\text{to}} - P_{\text{from}} a+b=Δ=Pto??Pfrom?
接下來,我們發現雖然只用了兩個條件,但由于公式中有三個未知數(a, b, c),我們實際上只剩下一個自由度可以調節(a 和 b 的組合必須滿足 a + b = Δ a + b = \Delta a+b=Δ)。這個自由度就可以用來控制跳躍的“彎曲程度”,也就是拋物線的弧高。
我們可以自由選取其中一個(比如 a),另一個就自動由差值決定(b = Δ - a)。這意味著我們可以根據希望的跳躍高度來調整 a 向量的方向和大小,從而間接地控制拋物線的形狀。
這種構造方式的意義在于:
- 起點和終點已經確定;
- 拋物線的中間形狀可以通過一個額外參數(如最大高度)來控制;
- 無需完全解析求解,只需要理解 a 和 b 向量之和等于 Δ(位移差)即可;
- 通過構造出任意兩個向量,只要它們的和等于目標位移,就能得到一條合法的跳躍軌跡。
總結來說,我們采用了一種將跳躍運動參數化的方法,從已知的起點、終點以及一個自由度(跳躍高度)出發,構建出一個滿足起點終點條件的拋物線插值函數。這個方法既直觀又靈活,非常適合在游戲開發中調試和控制角色跳躍的手感和視覺表現。
在 game_world_mode.cpp 中實現該跳躍公式
我們現在將跳躍動作的公式真正應用到實際代碼中。在這之前我們使用的是線性插值(lerp
)來實現跳躍位置的更新,但為了更真實地模擬物體在重力作用下的跳躍軌跡,我們用一個二次方程來替代線性插值。
我們把公式直接寫進代碼中。這個公式的基本形式是:
position ( t ) = a ? t 2 + b ? t + P from \text{position}(t) = a \cdot t^2 + b \cdot t + P_{\text{from}} position(t)=a?t2+b?t+Pfrom?
其中:
- t t t 是跳躍的歸一化時間值,范圍從 0 到 1;
- a a a 和 b b b 是控制跳躍軌跡形狀的兩個向量;
- P from P_{\text{from}} Pfrom? 是起跳點的位置。
在實現中,我們先定義了一個時間變量 t t t,然后代入到公式中去計算當前位置。這個公式清晰地表達了跳躍動作的軌跡。我們只需計算出當前的 t t t,就可以得到角色在跳躍過程中的位置。
接下來是關于 a a a 和 b b b 的設置。我們之前已經得出一個結論: a + b = Δ a + b = \Delta a+b=Δ,其中 Δ \Delta Δ 是從起點到終點的總位移。因此我們實際上只需要設置其中一個向量(例如 a a a),另一個向量 b b b 就可以通過:
b = Δ ? a b = \Delta - a b=Δ?a
來自動推導出來。這給我們帶來了極大的靈活性和調試的便利。
舉個例子,如果我們先不設置 a a a(也就是 a = 0 a = 0 a=0),那么整個跳躍就由 b ? t b \cdot t b?t 和 P from P_{\text{from}} Pfrom? 決定,效果類似線性插值。然后我們可以逐漸調整 a a a,也就是調整拋物線彎曲程度,從而控制跳躍的弧度——也就是跳多高。這可以用來“調跳躍手感”。
在調試中我們需要確保不要誤刪公式本身,否則計算會失敗。比如剛剛出現了一個失誤,把公式刪掉了導致結果出錯,一旦恢復公式后,跳躍軌跡便如預期運行。
這個實現方法簡潔直觀,適合在實際游戲中用來控制角色跳躍路徑和動畫。通過調節一個參數就能控制整個軌跡的弧度,非常適合做游戲體驗的細致調優。
運行游戲并查看當 A 為 0 時的運動效果
我們發現,如果將公式中的二次項(也就是 a ? t 2 a \cdot t^2 a?t2)的系數 a a a 設置為 0,那么整個公式就會退化為線性插值(lerp)形式。
我們原本的跳躍公式是:
position ( t ) = a ? t 2 + b ? t + P from \text{position}(t) = a \cdot t^2 + b \cdot t + P_{\text{from}} position(t)=a?t2+b?t+Pfrom?
當 a = 0 a = 0 a=0 時,公式簡化為:
position ( t ) = b ? t + P from \text{position}(t) = b \cdot t + P_{\text{from}} position(t)=b?t+Pfrom?
這個形式實際上就是標準的線性插值公式,表示從起點 P from P_{\text{from}} Pfrom? 沿著方向 b b b(也就是終點減去起點的位移)以線性方式前進, t t t 從 0 到 1 變化時,位置就從起點線性過渡到終點。
也就是說,如果我們不在跳躍軌跡中添加任何曲線(即沒有拋物線部分),那結果就是一個直線移動的軌跡,這也正是 lerp
的定義。因此,這個二次方程是一種更通用的方式——當我們不需要彎曲軌跡時,它退化為線性插值;而當我們想要創建一個弧形軌跡時,只需調整 a a a 的值,即可產生向上或向下彎曲的拋物線軌跡。
這個特性在實際游戲開發中非常實用。它說明我們可以通過簡單地調整一個參數( a a a)來在直線移動和跳躍軌跡之間切換,極大地方便了動畫調節與跳躍手感的微調。這樣一來,我們擁有了一個既統一又靈活的跳躍軌跡生成方式。
編輯 game_world_mode.cpp:使跳躍動作呈拋物線
我們決定要調節跳躍中的哪一部分呈現拋物線形狀。顯然,最希望呈現拋物線的部分就是跳躍的高度,也就是角色在空中上下起伏的部分。我們希望這個高度變化是平滑的、符合重力作用的自然軌跡,因此這個部分必須是拋物線曲線。
雖然我們目前尚未在代碼中處理 Z 軸(通常在 3D 空間中高度會使用 Z 軸表示),但由于還沒引入 Z,我們暫時把高度效果放在 Y 軸上,也就是用 Y 軸來代表跳躍中的垂直方向。
這樣可以看到,當我們在 Y 軸上引入一個二次項 a ? t 2 a \cdot t^2 a?t2 來控制高度的變化時,角色的跳躍軌跡就會在垂直方向上形成一個漂亮的弧線,從而看起來更自然。屏幕上的效果會表現為角色先向上移動,然后在跳躍到最高點后再下落,符合真實的物理行為。
總結來說:
- 我們希望控制跳躍“高度”部分呈現拋物線;
- 暫時將這個高度的拋物線作用在 Y 軸;
- 拋物線通過設置 Y 分量的二次項 a ? t 2 a \cdot t^2 a?t2 來實現;
- 軌跡在視覺上向上拱起,然后下降,模擬自然跳躍效果;
- 雖然最終可能需要使用 Z 軸處理真實高度,這里用 Y 是為了臨時展示軌跡效果。
這種設計思路使得我們可以非常靈活地調整跳躍的“弧度”,只需調整一個參數,就能控制跳躍高度和軌跡形狀,方便動畫表現和手感調試。
運行游戲并看到拋物線跳躍效果
我們將跳躍動作中的一部分運動分量放入了拋物線部分,這意味著角色現在的跳躍是沿著一個拋物線軌跡進行的。具體來說,我們將跳躍過程中的高度變化這一部分,用一個二次函數來表示,使其具有自然的拱形軌跡。這種方式讓跳躍看起來更像真實物理下的自由落體運動。
在當前實現中,水平運動(即角色從起點到終點的直線位移)仍然保持線性插值(linear interpolation),也就是線性運動。只有垂直方向的運動,也就是“跳的高度”,采用了拋物線插值。這種做法使得角色在跳躍時看起來既平滑又自然:路徑呈弧形,起跳后上升到頂點,然后再落下。
由于臨時關閉了碰撞檢測系統,所以角色的跳躍暫時不受任何障礙限制,這讓我們可以自由地測試拋物線軌跡,即使跳出正常區域也不會觸發阻擋或碰撞邏輯。雖然我們可能還沒完全理清一些底層邏輯,例如為什么某些跳躍會直接穿越邊界等,但目前的測試目的是驗證跳躍軌跡是否按照期望變成了拋物線。
因此,當前的實現邏輯如下:
- 起點和終點之間的水平運動依然使用線性插值計算,保持簡單;
- 跳躍的垂直高度則使用了一個二次函數,使其形成拋物線軌跡;
- 由于拋物線只作用于高度分量(目前是 Y 軸),角色的跳躍軌跡會在視覺上呈現拱形;
- 碰撞檢測被關閉,方便自由測試跳躍邏輯,不受物理阻擋影響;
- 整體跳躍路徑是“線性水平方向 + 拋物線垂直方向”的合成效果。
這個方式提供了一種簡潔且可調節的跳躍實現,我們只需調節拋物線高度參數即可獲得不同手感的跳躍效果,非常適合用于游戲中角色的跳躍動畫調試。
簡要講解如何將算法簡化為更少的變量
我們要記住一個非常實用的思路:在面對復雜的數學問題或游戲中動畫調節時,不一定非要一開始就解出完整的解析式。我們可以選擇先把問題拆解簡化,盡可能將方程中無法確定的部分縮減為少數幾個關鍵變量,然后通過手動調整這些變量的方式來完成調優。
這種思維方式的關鍵在于,不必執著于推導出一個完整封閉的數學解,而是更側重于實用、可控和可調性。例如我們剛才所做的,就是一個典型案例:我們沒有一開始就試圖完全解析一個跳躍軌跡的完整數學表達式,而是通過分析,明確哪些參數可以確定,哪些還不確定,然后通過實際測試和調整,把跳躍動作調成我們想要的樣子。
這個方法的核心思想可以總結如下:
- 問題先簡化:先解決已知條件對應的方程部分,比如起點、終點,以及常量項。
- 保留可調項:把無法精確求解或需要依據體驗微調的部分,作為參數保留下來。
- 變量調節控制行為:通過不斷嘗試和觀察結果,調整這些參數,直到得到想要的行為表現。
- 數學為工具而非束縛:即便沒有完整解方程的能力,也可以憑借理解和控制關鍵變量,達成目標。
在我們實現跳躍軌跡的例子中,這種思路就顯得尤為高效。我們將整個跳躍分解為線性移動加上一個拋物線的高度變化,并只保留一個主要參數(拋物線的“高度”)作為調節對象。剩下的部分可以自動平衡,確保最終的跳躍從起點準確到達終點。
這種方式非常適合游戲開發過程中那些需要兼顧數學合理性與可玩性、靈活性的問題。它鼓勵我們從實際出發,以調節為目的,利用數學表達式作為控制手段,而不是硬性約束。通過這種方法,我們可以更快速、更直觀地實現復雜運動或動畫系統,同時還能保持足夠的精度和物理合理性。
問答環節
那個跳躍動作太酷了,可以多演示一下嗎?
目前的跳躍效果還遠稱不上酷炫,整體看起來比較粗糙,比如角色的頭部甚至沒有正確地附著在身體上,導致視覺上顯得不協調,破壞了跳躍動作的整體觀感。
在交互方面也存在問題,例如當前居然可以選中頭部這部分,看起來并不合理。我們并不清楚為什么現在的系統允許我們去單獨選中頭部,很可能是選擇邏輯本身出現了問題,可能需要我們回過頭去檢查相關的選擇系統代碼。很有可能是之前做修改時對選擇機制影響較大,或者某些更新中破壞了實體結構之間的綁定和繼承關系。
從整體結構上看,這些問題反映出:
- 模型結構不完整:頭部沒有正確綁定到身體的骨骼或節點上,說明模型層級結構或動畫綁定存在問題。
- 選擇系統異常:允許用戶選中不應該直接操作的部分,例如角色的一部分獨立于整體被選中,反映出選擇邏輯未考慮層級歸屬或父子結構。
- 功能殘缺或丟失:例如碰撞檢測和物理系統可能被臨時關閉或禁用,導致當前測試跳躍功能時出現一些意料之外的行為,比如角色穿出地圖、跳出合法區域等。
- 調試狀態未清理:很多臨時關閉的系統可能沒有恢復到正常狀態,比如碰撞檢測未開啟,渲染層級沒修復,導致視覺效果不完整,邏輯行為不準確。
這些都說明當前系統仍處于一種實驗調試階段,功能未整合、狀態未統一,后續需要對各個系統進行逐一排查、重構與修復,特別是模型綁定和選擇邏輯,應該優先處理,以確保基本交互的完整性和一致性。整體而言,跳躍系統雖然數學邏輯和行為模型逐步清晰,但在具體實現細節層面仍需大量打磨和修正,才能最終達到理想效果。
你是如何將頭部分離出來的?
目前我們的角色模型實際上由兩個獨立的實體組成:一個是“頭部”實體,另一個是“身體”實體。它們在邏輯和物理上并沒有綁定在一起,因此在表現上看起來像是兩個分離的對象。
由于沒有建立父子層級關系或其他類型的綁定關系,這兩個實體在運動時是彼此獨立的,比如當身體進行跳躍時,頭部不會自動跟隨它移動。這種結構對于動畫、交互和物理模擬來說是非常不利的,會導致一系列的問題:
- 視覺不一致:角色在跳躍、移動時,頭部和身體的不同步會顯得非常奇怪,缺乏統一的動作表現,破壞了沉浸感。
- 物理行為分離:如果頭部和身體都參與物理模擬,它們可能會受到不同的力或發生穿插、碰撞等不一致的問題,進一步加劇表現上的不自然。
- 選擇與交互混亂:因為是兩個實體,用戶在選擇角色時可能只能選中其中之一,這會干擾正常的選擇邏輯,例如玩家點擊頭部時系統不認為是在操作角色本體。
- 動畫難以同步:動畫播放無法統一控制,頭部和身體的動作無法協調,從而導致角色動畫出現斷裂、不連貫等現象。
當前這種結構應該是臨時狀態,或是為調試某些功能而做的過渡性處理。為了解決這個問題,需要:
- 建立“頭部”與“身體”的綁定關系,例如通過骨骼系統將頭部附著到身體的某個節點。
- 在邏輯上將兩者合并為一個實體,或通過父子層級結構實現統一控制。
- 確保物理系統和渲染系統都能識別和處理這個統一的角色對象。
- 在選擇系統中屏蔽對子部件的單獨選擇,或者將選擇代理到整個角色對象。
總之,當前的實體分離狀態雖然可以用于原型測試和調試,但在正式功能中必須進行整合,才能實現一個完整、協調、自然的角色跳躍與交互系統。
你覺得為每次跳躍計算所需“力”和方向以達到某個高度是否值得?還是說這工作量太大而回報不明顯?
我們討論是否應該通過計算施加的力和方向,來使角色每次跳躍都能達到特定高度。結論是:在我們的場景中不值得這么做,原因如下:
我們承認,從理論上講,如果游戲系統以物理模擬為核心(例如基于真實力學的彈跳、反作用力、摩擦、剛體交互等),那么計算跳躍所需的力和方向是非常必要的。這種情況下,角色運動不能隨意通過代碼直接修改位置,必須通過施加合適的力,才能讓系統中的碰撞、推動、反彈等交互成立,保持物理一致性。
但在我們的游戲結構中,并不依賴物理模擬系統。我們采用的是基于邏輯控制的跳躍系統,即我們直接計算路徑、位置,通過插值函數(例如線性插值或二次曲線)來控制角色從起點跳到終點,中間模擬出一個拋物線。整個過程不需要真實的重力或力的計算。因此我們不需要去反推出“為了達到某個高度,應該施加多大向上的力”這種信息。
換句話說,我們不是用物理系統來“推動”角色跳躍,而是直接告訴角色“你現在該在這個位置”。在這種邏輯驅動的系統中,如果去引入額外的力學計算,不僅工程量大,系統復雜度高,而且對我們實際的表現幾乎沒有提升,甚至還可能導致更多的調試和維護問題。
總結如下:
- 如果是純物理驅動的系統,必須通過力來控制跳躍,那樣可以帶來系統上的一致性和物理交互能力。
- 我們當前系統是邏輯驅動、不依賴真實物理模擬,直接計算跳躍路徑就可以滿足視覺和功能需求。
- 所以,我們選擇更簡潔的邏輯路徑控制,而不是求解施力方向與大小。這在當前框架下更加高效實用。
我猜寵物和敵人也需要以類似方式移動?是否還有很多工作需要完成才能適配它們?
我們考慮將相同的跳躍移動系統應用到其他實體,例如跟隨者(familiar)和敵人。因為這些實體需要以與主角類似的方式進行移動,所以還需要進行以下工作才能讓系統兼容:
-
路徑規劃邏輯的開發
我們需要設計路徑規劃系統,使其能夠識別跳躍只能發生在特定方格(如合法跳躍平臺或路徑)之間。換句話說,這個系統需要明白不是任何兩點之間都能跳躍,跳躍只能在滿足特定規則的格子之間進行。 -
跳躍路徑限制
對于每一個目標跳躍格子,系統需要判斷是否存在一個有效的跳躍路徑(例如,有沒有可以落腳的平臺,有沒有空間進行上升和下降等),避免生成非法路徑。 -
運動系統的通用化
當前的跳躍系統是為主角構建的,接下來需要將其抽象成通用模塊,使得敵人和跟隨者也能復用這一跳躍邏輯。包括拋物線參數的配置、起點終點的選擇、狀態控制等,都需要從主角專用變為可配置和通用。 -
行為系統的協調
對于敵人或跟隨者的AI邏輯,需要支持根據路徑規劃結果發起跳躍動作。例如,敵人看到目標在另一平臺時,應能自動判斷出跳躍路徑并發起跳躍,而不是單純走直線。 -
狀態同步與動畫系統適配
敵人與跟隨者在跳躍時需要切換到跳躍狀態,這涉及動畫播放、行為凍結(如不能攻擊或轉向)等。需要確保他們跳躍的動畫和行為表現與主角保持一致或根據角色差異做適當調整。 -
多實體控制與同步
同一時間可能會有多個實體跳躍,因此系統還需處理好多跳躍實例之間的調度、防止穿插重疊、狀態沖突等問題。
最后提到的“清理額外的頭部”,說明當前在系統中可能因為調試或實體管理問題,存在重復或多余的角色頭部對象。這部分也需要通過清理多余實體或修復實體系統中的BUG來完成。
總結:
- 需要為敵人和跟隨者添加專屬的路徑規劃系統,并確保它們理解跳躍限制;
- 把跳躍行為從主角專用轉為通用;
- 處理AI控制、動畫切換、多實體狀態同步;
- 修復現有實體系統中殘留的臨時或錯誤對象(如多余的頭部)。
這一整套流程,是將系統從“主角跳躍功能”擴展為“通用跳躍邏輯”的關鍵步驟。
可以清理屏幕上多余的頭部和身體圖像嗎?還是說之后還會用到?
在當前的開發狀態中,屏幕上的“頭部”和“身體”仍然是實際存在的實體,雖然它們的功能和用途可能還沒有完全確定。具體來說:
-
頭部與身體的用途
- 頭部實體可能會跟隨主角,作為游戲中的某種輔助對象。這意味著它不僅是一個視覺元素,可能還會參與到一些游戲機制或動畫中。
- 至于另一個實體(可能是目標或其他互動對象),它的確切用途尚不明確,但有可能是某種目標指示物或者類似的功能,之后可能會被去除或重構。
-
其他不必要的元素
- 當前屏幕上還顯示了一些看似沒有實際用途的小“板塊”,這些板塊可能是某種可以發射的物品,盡管現在沒有明顯的目的。這些可能是在開發過程中臨時添加的元素,未來有可能被去除或重新設計。
-
頭部與身體的連接問題
- 目前,頭部并沒有固定在身體上,可能是由于程序設計的問題。為了確保更自然的表現,理想情況下,頭部應該始終保持在身體的頂部。這個問題可能是由于碰撞檢測、實體綁定或其他物理處理上的疏忽,之后需要進行修復或調整,以便實現更符合預期的視覺效果。
總結:
目前屏幕上的頭部和身體仍是實際存在的對象,但它們的具體作用和連接方式可能還需要進一步的調整。某些不必要的物品或功能(如可以發射的小板塊)會根據后續需求進行刪減或優化。
為什么頭部沒有一直待在身體上方?這是 bug 嗎?
目前,頭部和身體是兩個不同的實體,它們各自獨立移動。頭部和身體的分離并不是一個BUG,而是設計上的選擇。身體會跟隨頭部的運動,但兩者依然是分開的實體。未來是否將它們合并為一個實體,將根據實際構建的實體系統來決定。開發過程中,實體系統的設計會影響最終的決策。
現在的目標是讓身體根據頭部的位置進行跟隨,使得兩者之間的連接能夠隨著頭部的移動而延伸,但依然保持它們獨立控制的狀態。這個設計的思路是讓它們在獨立控制的同時,保持一種連貫的運動表現,而不是將它們完全合并成一個單一的實體。
在寫過程式代碼時,我常常寫出很深的嵌套結構。應該避免這種情況嗎?有沒有方法能簡化?
深度嵌套的代碼確實在編輯器中的處理可能會有些困難,因為編輯器通常不太擅長有效地幫助管理這類代碼,可能會導致閱讀和修改變得更加麻煩。雖然嵌套代碼本身沒有本質上的問題,但如果它對開發造成了不便,那么最好的做法是將一些嵌套的邏輯提取到獨立的函數中。通過這種方式,代碼不僅變得更加清晰,而且可以提升可維護性。因此,如果嵌套代碼讓你感覺麻煩,簡單地將它分解成函數并不會有什么大問題。
這開始有點像《節奏地牢》(Crypt of the Necrodancer)了
這款游戲的設計與《Crypt of the NecroDancer》并沒有太多相似之處。雖然只是簡短地玩過《Crypt of the NecroDancer》,但就目前的了解而言,這兩者在設計理念和玩法上沒有太多的關聯。至于“Trap Master”游戲,雖然沒有具體描述,但看起來它的設計與前述游戲并不相同。
我錯過了很多。你是在為這個游戲制作引擎嗎?還是這些東西只是目前給你/我們用的?
這款游戲的引擎是從零開始開發的,包括渲染器,甚至可以使用軟件渲染,這挺酷的。不過,目前編譯模式是調試模式,且在軟件渲染時似乎沒有清除操作,這可能是一個問題。盡管在軟件渲染中沒有清除應該也不算嚴重問題,因為本不應該有空白區域,但還是不確定為什么沒有進行清除操作。通過查看 render.cpp
文件,發現清除操作被寫入,但它可能并沒有正確地清理屏幕的背景,這可能導致渲染問題。因此,雖然系統目前在這種狀態下可以運行,但仍有一些細節上的問題需要進一步調試和修復。
調試器:進入 RenderCommandsToBitmap 并查看 Clear 的處理過程
在調試過程中,發現屏幕沒有正確清除,經過分析后發現問題出在清除顏色的 alpha 值上。原本應該清除屏幕的顏色是透明的(alpha 為 0),而這個值導致了屏幕沒有完全清除。因此,這個問題看起來是由于設置了錯誤的清除顏色導致的,這樣的錯誤顯然會影響屏幕的渲染效果。為了修復這個問題,需要將 alpha 值設置為正確的值,而不是 0,這樣屏幕清除操作才能正常執行。
軟件渲染模式clear 之前已經清理過了
編輯 game_render.cpp:設置傳遞給 Clear 的透明度參數
經過進一步分析,發現將 alpha 值設置為 0 是合適的,因為在清除操作時,目標的 alpha 值需要設置為某個特定值。因此,雖然這并不完美,但從技術角度來看,這種設置是正確的。為了確保清除操作正常進行,可以將顏色值設置為一個臨時的有效值,而這正是導致問題的根源。
運行游戲并看到軟件渲染器成功清屏
通過進一步檢查性能,發現硬件渲染通過 OpenGL 運行非常流暢,而軟件渲染的表現也相當不錯。實際上,如果 Windows 不存在延遲,軟件渲染的幀率應該能夠達到每秒 60 幀。然而,部分性能瓶頸來自于 Windows 系統本身的處理延遲,此外,可能還需要使用 P 緩沖區(P Buffer)來優化屏幕的傳輸過程,進而提升 OpenGL 提交的效率。
Z 軸被定義后,跳躍的上下運動會有所不同嗎?
目前需要解決的問題是 Z 軸的處理一直存在一些問題,現在已經意識到它應該如何調整。接下來需要對 Z 軸進行一些調整,以確保它能夠按照預期工作。
C#開發游戲的限制有哪些?你整體上喜歡 C
使用 C# 開發游戲存在許多限制。首先,C# 是一種垃圾回收語言,這意味著內存管理由系統自動處理,而開發者無法直接控制。其次,C# 是通過解釋器運行的,雖然它可以通過即時編譯來優化,但依然比低級語言如 C 或 C++ 在性能上有差距。C# 是一種高級語言,存在許多抽象層,這使得開發者無法直接控制 CPU 的操作,背后有很多復雜的中間層。
開發者普遍不喜歡這種語言,因為它在開發過程中增加了額外的抽象層,減少了對硬件的直接控制。
如果不是面向對象風格,你用了 C++ 的哪些部分?
如果不使用面向對象編程(OOP)風格,我們主要使用函數重載、運算符重載以及在某些情況下使用構造函數和析構函數對進行塊作用域管理。這些是主要用到的功能。
我現在用的是 Microsoft Natural Ergonomic 4000 鍵盤,想換成非人體工學的機械鍵盤,有什么建議?
對于微軟自然系列的鍵盤,特別是微軟自然4000型號,它的空間鍵確實有一些難以操作的問題,很多人對此表示困擾。個人來說,雖然我更傾向于使用非人體工學的機械鍵盤,因為設計上更符合我的打字習慣,但如果有人能夠設計一款真正合理的人體工學鍵盤,我會考慮嘗試。不過,普遍感覺是,設計這些自然或者人體工學鍵盤的設計者似乎并不經常打字,至少從我的經驗來看是這樣。
這游戲做完時會有多少個 A?(注:疑為玩梗)
在這段內容中,提到了游戲完成后的目標并沒有明確指出是否指向像 AAA 游戲那樣的規模。至于游戲的規模,似乎并沒有特別強調要達到 AAA 游戲的標準,更多的是關注實際的開發過程和當前所面對的挑戰。
此外,關于底部一排的樹被裁剪的部分,提出了當前圖形顯示的問題,可能是由于視角或渲染設置的問題,導致樹的頂部被裁剪掉。這可能需要調整渲染設置或視角來解決。
總的來說,開發中的關注點不僅僅是實現大規模的游戲內容,而是處理一些細節上的問題,如圖形顯示和游戲邏輯的調整。
的確是會被編譯的
討論了 C# 編譯和運行時的特點。C# 雖然可以進行即時編譯(JIT,Just-In-Time Compilation),但它并不直接編譯成機器碼,而是編譯成字節碼。這個字節碼在運行時由 .NET 虛擬機(CLR)執行,而不是生成直接的機器碼。因此,開發者無法像在低級語言中那樣完全控制生成的機器代碼,也無法準確預測垃圾回收器的運行時機和方式,因為垃圾回收是由系統自動管理的。
此外,C# 編譯器和垃圾回收機制都由運行環境控制,開發者無法干預這些內部機制的具體實現。這意味著,開發者的控制力受到限制,而這些機制的表現可能會因不同的 C# 實現版本而有所不同。因此,雖然 C# 可以被編譯并優化,但仍存在許多抽象層,開發者無法直接控制程序的底層行為。
你對 Apple 的 Swift 看法如何?現在它已經開源了,你怎么看?
這段內容提到沒有看到 Swift,可能是在討論一種編程語言或開發環境,并表達了對 Swift 語言的不了解或缺乏接觸。這里沒有深入討論 Swift 具體的特點或應用,而是僅提到自己并未接觸過它。
為什么我要投總統初選時還要聲明一個政黨?
在華盛頓州,之所以必須聲明一個政黨才能參加總統初選,原因是根據華盛頓州最高法院的判決(如果不是聯邦法院的話)。這項判決要求選民在參與初選時聲明政黨,以便確定選民所能投票的黨派。
查看資源:查看樹的位圖,發現樹像是被裁剪的原因是缺少一個 1 像素的邊緣區域
至于原先的問題,關于圖像資產的問題,之所以看起來像是被裁剪了,是因為圖像的實際結束位置就在這個地方,而這一部分正好位于一個像素的邊緣區域,這部分不會被渲染。如果這些圖像資產按照最終游戲中所要求的格式進行打包(即加上這個一像素的邊緣區域),那么就不會出現裁剪的情況。