游戲引擎學習第283天:“讓‘Standing-on’成為一個更嚴謹的概念

如果同時使用多個OpenGL上下文,并且它們都有工作負載,GPU或GPU驅動程序如何決定調度這些工作?我注意到Windows似乎優先處理活動窗口的OpenGL上下文(即活動窗口表現更好),挺有意思的……

當多個OpenGL上下文同時使用且都有工作負載時,GPU或GPU驅動程序如何決定調度這些工作負載實際上并不清楚。Windows似乎會優先處理當前活動窗口的OpenGL上下文,這點很有趣。

OpenGL在Windows環境中本身就存在一些復雜問題,因為微軟傾向于推動自己的標準,對OpenGL的支持并不充分。但驅動程序廠商希望支持OpenGL,因此通常會有自己的解決方案。

以NVIDIA為例,調度策略可能會依賴于使用的顯卡型號。高端顯卡的驅動程序甚至允許將不同的GPU單獨分配任務。理論上,如果有多個GPU,驅動可能會在它們之間平衡負載。

但具體如何平衡不同OpenGL上下文的工作負載,尤其是在多個應用同時運行時,比如三個應用都在用OpenGL,驅動如何切分資源分配,是個復雜問題,不同廠商的實現可能也不一樣。優先級是否會影響OpenGL上下文的執行資源分配,目前沒有明確的公開信息。

這方面的細節并不是很清楚,也很少有人深入研究,最好的方式是直接問顯卡驅動廠商。

你怎么看基于流程圖的編程?你覺得它們在游戲編程中有效嗎?

對于流程圖式編程的看法以及它在游戲編程中的效果,實際上并不太清楚“流程圖式編程”具體指什么。雖然對流程圖的概念很清楚,但并不確定將編程描述為“基于流程圖”的意思是什么。

如果指的是類似UML(統一建模語言)這樣的圖示,那個人并不認為這類圖示對編程有用,尤其是對任何類型的編程都不認為它們有實際幫助。但也可能這并不是“流程圖式編程”的真正含義,所以整體上并沒有明確的判斷或結論。

我更多是想說類似UE4用藍圖實現的那種

如果說流程圖式編程是指那種視覺編程語言,比如用來制作簡單效果或功能,通過拖拽節點來實現的系統,從所見過的情況來看,這類系統的價值并不大。它們主要幫助用戶做非常簡單的事情,不需要寫代碼,直接拖拽節點就能完成,但制作簡單東西對我們來說并不難,也不需要特別的工具輔助。

編程真正難的地方是做復雜的系統和功能,而這正是這些視覺編程系統的弱點。復雜起來的時候,節點之間關系混亂,界面變得雜亂無章,根本看不懂,也很難管理。到目前為止,沒有看到視覺編程語言能夠做出真正有趣且復雜的東西。

這并不意味著視覺編程沒有潛在價值,只是還沒有人成功利用它們的圖形特性,來讓編程變得更簡單、更高效。反而目前的做法往往讓復雜的東西更難管理,適得其反。理想狀態下,圖形化編程應該用圖形的優勢來簡化編程過程,而不是讓它更難。

你怎么看結構化編輯器?

我們對結構化編輯器的看法是:這個概念本身挺吸引人的,覺得它是一種不錯的發展方向,特別是它讓編輯的重點更聚焦在“編輯的內容本身”上,而不是僅僅作為一段普通文本來處理。這種思路比起傳統的純文本編輯方式更具針對性和結構性。

我們喜歡結構化編輯器的理念,認為它值得探索,是一種值得并行推進的工具演進方式。然而,雖然認可這種方向,但實際上我們并沒有真正使用過這類編輯器,因此對它的實際效果沒有太多經驗,不清楚是否已經有誰真正實現了一個好用、成熟、實用的結構化編輯器。

也就是說,理論上我們支持這種形式,但實踐中是否真的能帶來提升,還不確定。有待進一步觀察是否有人能真正將其做成一個好用的工具。

我覺得盒子和箭頭類型編程的主要用途是讓非程序員覺得自己沒在寫代碼

我們認為“盒子和箭頭”式的編程方式(即圖形化編程、節點式編程)主要的使用場景,其實是為了讓非程序員感覺自己沒有在“編程”。換句話說,它的核心作用并不是真正提高編程效率,而是降低編程的心理門檻——讓那些原本可能會被代碼嚇退的人,也能參與到邏輯構建中來。這種方式很適合向非技術用戶“偽裝”成一種非編程的操作方式。

雖然從技術角度來看,它并不一定有助于構建復雜系統,但在教育、演示、或低門檻應用開發場景中,它確實有其“說服性”作用。簡單直觀的圖形界面加上邏輯連接線,很容易給人一種“只是在搭建流程”的感覺,從而弱化了“寫代碼”的印象。

開始今天的內容

目前我們要做的是開啟模擬系統中的一個新方面,并讓它的更新機制更完善。之前我們已經修復了模擬相關的一些問題,現在正在逐步朝著更接近最終游戲代碼的方向前進。

我們需要著手處理一些更嚴肅的問題,特別是關于物理系統渲染系統的內容。之前我們使用的是一種臨時的、非常簡單的物理與移動邏輯,只是為了快速搭建基礎系統。但接下來我們要構建的是一種更“完整”的方式。

所謂“更完整”,并不意味著模擬真實世界的物理行為,而是要構建一種更加專業、結構清晰、設計簡潔的物理處理方式,讓這部分代碼的架構變得可靠且可維護。

今天我們需要做兩件事:

  1. 制定并實現新的物理系統,讓實體的移動和交互更合理,具備更清晰的狀態控制;
  2. 開始解決關于**多層深度(z軸多重疊層)**的渲染問題。昨天我們已經提出了目標,現在要正式著手編碼實現,使其在渲染中表現得更加高效、清晰。

運行游戲,設置當天場景

現在我們要開始今天的開發任務。

首先要明確一點:在著手構建新系統之前,應該先打下基礎,空著什么都不做是沒意義的。所以我們先運行一下當前的狀態,看看到哪一步了。

目前我們處理的是**多層高度(Multiple Heights)**的問題。我們之前在這部分做過一些嘗試,但現在可以看到存在明顯的排序錯誤。例如角色的位置排序不正確,角色的頭部顯示在了錯誤的位置。這是因為當前系統使用的是一種帶偏移的排序邏輯(bias sorting),而偏移值并不能正確表示實際的空間順序。

我們有很多地方需要修復,現在正是一個很好的時機來全面重新梳理物理系統Z軸高度(z)的處理機制,從而將當前這些零散不規范的系統整理成一個可靠、穩定的狀態,避免在將來的開發中不斷返工。

接下來我們計劃分兩步進行:

  1. 先處理世界空間中Z軸的表達方式:我們要先確保高度的表達結構合理、清晰、易維護,先不涉及渲染;
  2. 再將這一表達方式傳遞給渲染系統:這樣我們可以改善目前的排序錯誤,比如讓頭部總是顯示在身體上方等,這樣的規則渲染系統目前并不了解。

目前渲染器的排序能力是不錯的,但輸入數據太差,導致最終渲染效果不理想。比如渲染系統不知道“頭永遠在身體上方”這種邏輯,因此沒法正確處理繪制順序。這些邏輯我們現在開始要系統性地考慮和處理。

接下來,我們觀察到一個物理上的問題:比如角色無法往北移動。這是因為角色的頭部會撞到地形的碰撞體積(collision volume)。這些地磚(棕色小塊)雖然我們沒有在圖形上畫出來,但它們是有碰撞體積的。當頭部在物理模擬中“撞到”這些碰撞體積時,會阻止角色繼續移動。

這其實是合理的現象,因為我們希望有碰撞邏輯。但目前還沒有去精細設計這些體積的形狀、大小和放置方式。隨著我們對系統行為越來越清晰,現在正是時候去定義合理的碰撞體積結構,并且構建出更完整的碰撞檢測系統。

更進一步地,由于這款游戲的設計具有特定的機制:角色的頭部和身體是分開的兩個部分,控制的是“頭部”的移動,而“身體”會自動跳躍移動到特定的格子上。這種設計讓我們不能采用標準的物理模擬,而必須實現一種**具有明確二值判定(能不能跳過去)**的游戲邏輯。

如果我們采用現實物理模擬,跳躍和移動行為將變得連續而模糊,而這正違背了我們設計中那種“格子跳躍式”的清晰判定。比如是否能跳到下一個地塊,不應該依賴于“是否差一點點撞上”,而是要有明確的判定:可以或不可以

因此,我們將不采用真實物理引擎那種連續碰撞檢測方式,而是要開發一種非常特定的、服務于本游戲風格的離散跳躍判定機制

黑板講解:原子跳躍和浮動位置

我們希望傳達的核心思想是:這個游戲的移動和碰撞機制,不能依賴傳統物理模擬,而需要一套自定義、明確、原子化的判定規則系統

假設我們設計了兩個角色都試圖跳躍到同一個目標格子,我們必須定義一個機制來處理這種**“同時入場”沖突**。

我們設想了幾種解決方案:

  1. 雙方彈回:兩個角色在空中相撞,誰都無法落地,雙雙回到出發格子。
  2. 先到者得:誰先進入落點區域,誰就占據該格子,另一個回退。
  3. 共享位置:允許兩者共處一格(但這種方案一般不太可行)。

無論選擇哪種方案,都將引發更復雜的連鎖問題。例如,如果多個角色同時朝多個方向跳躍,某個角色原地不動但被其他跳入路徑阻斷,就會出現沒有落點可回退的問題,也就是角色“被困在空中”的狀態。

因此,需要設計一套規則,確保每個角色總是有一個明確、合法的落點,不可能懸而未決

一種解決思路是引入**“原子跳躍(Atomic Hop)”**的機制:

  • 每個角色從一個格子起跳,進入“目標格子”的中線邊界區時,會觸發一次原子性嘗試
  • 如果此時目標格子允許被占據(未被他人優先取得),則角色會原子性地釋放當前格子并成功占據目標格子
  • 如果目標格子無法占據,角色立即放棄跳躍并退回原位,此操作也是原子的,不會出現“懸空”狀態。

這種機制是和物理模擬完全不同的設計,強調的是空間控制權的原子判定,而不是連續運動和碰撞處理。

此外,還將引入另一類物體行為:**浮動類(Floating)或投射類(Projectile)**對象:

  • 它們不像角色那樣“占據格子”,而是可以在空間中自由移動、穿越,不會對格子產生“擁有權”;
  • 它們使用更常規的運動規則,比如速度、碰撞等,更偏向傳統物理模擬。

總結目前的物理系統劃分,我們將其分為兩類:

  1. 原子跳躍類型(Atomic Hop)

    • 用于角色行為,強調空間控制權,不能被物理模擬替代;
    • 如角色的身體(body),必須落在格子上,并決定是否成功跳躍;
  2. 浮動/投射類型(Floating / Projectile)

    • 用于頭部、飛行物、某些敵人或技能;
    • 在空間中自由移動,不持有格子,不參與原子跳躍邏輯。

這種劃分也符合當前游戲的特殊性:頭部和身體是分離的,身體必須精確落點,而頭部則在空間中“自由移動”,不與地面交互。

雖然這些規則聽上去清晰,但在實現上仍存在一些邊界情況的微妙問題,比如角色被擊退時穿越多個格子,該過程也需要特殊處理以保持一致性。因此,整個物理系統雖然不復雜于傳統物理模擬,但更具有規則性與特殊性,需要細致地構建與驗證。

我們目前面對的問題是關于游戲中角色移動與空間占用的設計邏輯,尤其是在存在擊退、沖突、投射物等復雜情況時,如何確保角色在跳躍和移動中始終擁有穩定的站立格子,避免“無處可落”的錯誤狀態。

一、空間占用必須是事務性的

我們明確了一點:角色從一個格子移動到另一個格子,這個動作必須是事務性的,即:

  • 只有在目標格子明確可占用的情況下,角色才會原子性地釋放當前格子并占據目標格子
  • 如果目標格子不可用(已被其他單位占用或其他限制),則角色必須保留當前格子并中止移動,不會進入“懸空”狀態;
  • 這個機制適用于所有關鍵單位,尤其是需要“落地”的角色身體部分。

這不再是簡單的跳躍邏輯,而是一種基于占格權的移動協議


二、擊退與滑動也必須遵循事務性原則

當一個角色被擊退時,他可能會在連續多個格子之間滑動。但這個滑動也必須建立在同樣的事務性邏輯上:

  • 每一次位移都必須檢查下一個格子是否可被占用;
  • 若下一格不可用,則滑動立即中止,角色停留在最后一個合法格子;
  • 項目符號移動仍然基于“占據點”的原子判斷,而不是簡單物理模擬。

三、投射物行為邏輯與主體不同

我們將投射物等單位與角色分開處理:

  • 投射物不擁有格子,不占據空間位置;
  • 它們可以自由飛行,只在命中檢測時產生交互;
  • 如果它與一個需要“歸位”的角色存在空間沖突,必須讓位,確保角色始終有地方可落;
  • 這是因為角色“落點”是一級優先權,不可被任何投射物阻斷。

四、極端情況舉例與規則適用

我們思考了一個情況:多個單位(如敵人與玩家)幾乎同時向同一格子移動,可能導致某方明明視覺上看到目標格子已被騰出,但在邏輯上卻因事務機制未釋放成功,導致被“擋住”。

我們承認這類情況在視覺表現上可能造成誤解,但為了系統一致性和無死鎖,我們仍要優先保證事務機制,而不是依賴時序精細對齊。

我們考慮的補充措施包括:

  1. 提前請求轉移權:如果一個單位要前往一個格子,而當前格子內單位正在嘗試離開,可以判斷該單位是否有下一個目標格子且可以立即移動,若可以則釋放當前格子,為后者讓路。

  2. 即時占用空格:一旦一個單位開始移動并目標格子空閑,即立刻標記為被占用,避免“后來的單位”誤以為它仍可進入。

無論采用何種具體規則,它們都必須構建在事務性占據模型之上,即:

  • 每次移動必須是“釋放當前 + 占據目標”的原子操作;
  • 永遠不允許處于“已離開當前格子但未成功進入下一個格子”的中間狀態。

五、系統構建方式與總結

我們強調:

  • 無論將來我們如何細化規則、調節體驗、做視覺反饋,只要底層是基于事務性占格模型構建的,就能避免“無法落地”或“站位沖突”等根本性Bug
  • 這樣一來,即便我們未來引入各種特殊敵人行為、復雜連擊、多人搶位、連鎖反應等系統,也都能在這一機制下良好運作;
  • 它是整個格子控制系統的根基

所以,我們當前所需做的,是在底層建立起一個清晰、嚴格、永遠可靠的事務性占格邏輯系統,并將所有移動、攻擊、滑動、投射等行為構建在這個框架之上。這樣我們才有信心面對游戲玩法擴展與未來所有復雜情況的挑戰。

黑板講解:旋轉木馬的問題和可能的斬首風險

我們在構建空間占用與物理行為系統時遇到了一些更復雜的場景和邊緣情況,這些都需要我們進行深入思考與處理,確保系統健壯且不影響玩家體驗。


一、旋轉平臺與跟隨問題

我們設想了一個旋轉的平臺,平臺上有若干個可站立點,一個實體(如玩家)站在上面時,平臺旋轉的同時實體也會跟著一起旋轉。這部分實現相對簡單,因為:

  • 每個可站立點都有相對于平臺中心的固定偏移;
  • 我們只需記錄該偏移,在平臺旋轉時重新計算實際世界坐標;
  • 實體的位置即可隨平臺自然更新。

這套機制本質是“父子坐標系”的變換,屬于常見的場景處理。


二、頭部與身體的分離問題

問題在于,如果實體具有高低不同的部分(如身體和頭部),而環境中存在只阻擋頭部的障礙物時,就會出現一種特殊情況:

  • 實體站在平臺上隨平臺旋轉;
  • 平臺將頭部旋轉進某個障礙物(例如橫梁)中;
  • 由于身體在低處未被阻擋,但頭部無法穿過障礙物,導致“頭部與身體分離”;
  • 若該邏輯成立,將相當于“砍頭”或“實體解體”,這在玩家角度顯然是極度不友好的。

我們意識到這種機制可能會造成以下問題:

  • 若平臺上只有一個站立點,且頭部被障礙阻擋,則無法將身體挪至其他位置;
  • 如果平臺周圍存在其他可行站點,但此時被怪物等占據,也同樣無法“回退”;
  • 即使空間設計合理,實際運行時也可能出現此類無法預判的失敗情況。

三、可能的解決策略

為解決上述問題,我們提出了幾種可行的策略:

1. 徹底禁止“頭部層級”的障礙物
  • 游戲中不再存在只對“高層”造成碰撞的障礙;
  • 所有障礙物都必須從上到下貫通,確保頭和身體共享同一碰撞判斷;
  • 這樣就不會再出現“身體能過頭不能過”的情況;
  • 這種方式簡單直接,能徹底避免邏輯混亂。
2. 遇障即停止平臺旋轉
  • 如果平臺旋轉時將導致實體部分(如頭部)與障礙物發生沖突;
  • 則平臺旋轉動作會被立即中止;
  • 相當于“自動制動”,防止沖突導致穿模或破壞角色完整性;
  • 缺點是可能影響旋轉機制的自由度,但穩定性更高。
3. 允許被動推開、尋求退路
  • 若頭部發生碰撞,而身體未被阻擋;
  • 嘗試將實體整體“推開”,退至周圍可站立的備選點;
  • 若存在空格子則移動,若無可用空間(如被怪物占據),則中止;
  • 但如果連退路都不存在,會面臨“無法保命”的情況,因此風險依然存在。

四、對頭部獨立存在的重新思考

我們也進一步分析了“頭部與身體分離”機制是否真的必要:

  • 目前我們暫未發現明確的游戲機制需要頭部能單獨繞開路徑障礙;
  • 即使未來加入相關能力(如頭部漂浮、魔法探路等),仍可用“完整體積”代替,僅在表現層分離;
  • 所以,沒有必要強行支持頭部單獨遇阻的復雜情況。

五、系統化重構的方向

當前系統中,只有主角的代碼實現了“事務性站點切換”的邏輯。為了系統統一性和可拓展性,我們計劃將其改造為普遍適用于所有實體的通用機制:

  • 所有單位(包括敵人、NPC、平臺上的物件等)都要接入事務性站點機制;
  • 每個單位都需要有明確的“我占據了哪個點”這一狀態;
  • 移動必須基于“釋放舊格子 + 占據新格子”的原子操作,確保邏輯安全;
  • 這一機制將作為物理交互和空間占用的底層基礎設施,服務于所有游戲實體。

六、總結與原則

為構建一個健壯且不易出錯的游戲系統,我們明確以下核心原則:

  1. 事務性格子占用:任何實體移動必須是原子操作,確保占用狀態一致;
  2. 避免頭部與身體解耦:不允許只對某個身體部分產生碰撞,防止脫節邏輯;
  3. 優先保護玩家體驗:系統設計不能因技術邏輯導致玩家突然失敗或死亡;
  4. 平臺交互可控性:旋轉、推動等機制必須能中止、回退或自我修正;
  5. 通用機制統一入口:所有實體應接入統一占點與移動系統,避免特例代碼。

我們將優先完成這一底層系統的搭建,然后再通過規則層進行玩法擴展與特性調整。在此基礎上,所有復雜行為都可穩定運行而不會產生結構性Bug。

game_entity.h:引入 traversable_reference,并添加兩個到實體

我們當前在處理實體(如主角)移動邏輯時,仍然采用一種臨時且重復計算的方式。每一幀都會重新計算主角頭部和身體所處的位置,也就是每次循環都對空間中最近的“移動點”進行一次實時搜索。這種方式雖然在早期開發中勉強可用,但效率不高、結構混亂,也不具備擴展性。因此我們計劃對這部分邏輯進行系統性的改造,使其變得更加正式、統一和高效。


一、引入正式的“站點”概念

我們決定將“主角當前站在哪個點”這個信息進行顯式記錄:

  • 不再每幀實時計算當前位置;
  • 而是在明確進入某個區域時,就記錄下當前所站的那個移動點;
  • 系統化地提供一個查詢函數,用來獲取“當前位置的最近可站點”;
  • 并將其抽象為一個統一的數據結構,方便所有實體通用使用。

二、結構抽象:可通行引用(traversable reference)

為描述實體“從哪里移動到哪里”,我們引入一種新的引用結構:

  • 類似于以往的“實體引用”(entity reference);
  • 但“可通行引用”不僅包括了實體自身的引用,還會記錄其下的“移動點索引”;
  • 即這個引用告訴我們:實體X下的第N個站點,是某個角色實際站立的位置。

我們將“移動起點(movement from)”與“移動終點(movement to)”都改寫為這種形式:

  • 每個移動行為都表示為:從某個實體的某個可通行點出發,到另一個實體的某個可通行點;
  • 這種結構更具語義性,并且為系統提供更大的靈活性和拓展空間。

三、處理邏輯的延遲更新機制

由于在模擬過程中實體可能會發生移動,因此我們采取一種“延遲更新”策略,確保在正確的時機處理這些移動信息:

  • 我們不會在添加數據的同時立即解析“可通行引用”;
  • 而是在主循環中,模擬系統進行到合適階段之后再進行處理;
  • 這樣可以避免在實體移動時引用失效或錯誤指向,確保數據一致性。

例如,在添加實體進入模擬區域時(通過類似 add 操作),以前是直接用 chunk delta 偏移量來快速還原實體位置:

  • 而現在我們不再通過 chunk delta 來計算偏移;
  • 而是根據“可通行引用”去準確獲取目標站點信息。

四、進一步優化方向

當前結構仍處于過渡階段,未來還有進一步優化的空間,例如:

  • 將實體引用和通行點索引完全拆分,支持更細致的動態移動;
  • 對所有敵人、物體等擴展相同機制,實現統一的空間行為模型;
  • 可能還會在更高層封裝出更簡潔的行為接口,方便邏輯系統調用。

此外,當前用于處理的函數名(如 add)并不直觀,后續也需要命名重構,使其更準確地表達功能語義。


五、總結

我們正在進行一項核心架構的調整與系統化設計,目標是:

  1. 避免重復查詢,顯式記錄實體所站點;
  2. 引入統一的數據結構“可通行引用”來表示實體移動路徑;
  3. 利用延遲處理機制,保證模擬過程中的數據一致;
  4. 準備將主角的特殊邏輯,推廣為所有實體通用的標準接口;
  5. 為后續構建穩定、可拓展的物理與行為系統打好基礎。

這一系統將成為所有空間相關邏輯的通用底層,確保行為、狀態與物理結構三者統一,提升整體效率與可維護性。
在這里插入圖片描述

game_sim_region.cpp:引入 LoadTraversableReference 和 StoreTraversableReference

我們將會把某些對象變成可以加載的可遍歷引用(traversable reference)。具體來說,會把“movement from”和“movement to”這兩個動作都作為可遍歷引用進行加載。加載的過程會在“load entity reference groups”里實現,當我們在哈希表中查找時,邏輯是一樣的,只是變成了對可遍歷引用的處理。

在流程中,首先是有一個已經降低(lowered)的可遍歷引用,我們通過這個引用嘗試加載實體引用(entity reference)。這里的關鍵步驟是嘗試獲取“enmity”(敵意)部分,如果成功就不需要從其他地方拉取額外數據,因為這里不需要再去拿“to be three”之類的內容,所以只要加載敵意部分就完成了。

關于反向引用(reverse),同樣需要存儲對應的可遍歷記錄。反向存儲目前只是一個簡單的函數調用(thunk),因為暫時不需要做額外的處理。它的功能主要是調用“store entity reference”方法,作用對象是這個可遍歷引用中敵意部分的反向引用。

編譯時發現“sim regan”并不存在,所以需要修正代碼。接下來,在存儲任何引用時,也需要同樣處理可遍歷引用的存儲,流程和加載時是對稱的,只不過是進行翻譯轉換。

在處理“movement from”和“movement to”的相關代碼時,應該不會太復雜。因為已有的“get closest traversable”功能已經包含了必要的信息,所以只需基于它進行擴展即可。

總結來說,主要工作包括:

  • 將“movement from”和“movement to”作為可遍歷引用加載和存儲。
  • 加載時通過哈希表查找,嘗試獲取敵意部分,完成實體引用加載。
  • 反向引用存儲時調用已有的存儲方法,暫時沒有復雜操作。
  • 存儲時同樣轉換處理為可遍歷引用,保持和加載對稱。
  • 通過已有的“get closest traversable”功能,簡化“movement from/to”的實現。
  • 編譯過程中修正不存在的符號,保證代碼正確性。

接下來就是根據以上思路實現相應代碼。整體流程結構清晰,核心就是對可遍歷引用的統一加載和存儲管理。
在這里插入圖片描述

在這里插入圖片描述

game_sim_region.cpp:從 game_world_mode.cpp 移動 GetClosestTraversable 并讓它記錄索引

首先,我們準備對“get closest traversable”(獲取最近的可遍歷對象)這部分進行改造。目前這個功能可能是在代碼的某個較高層次,但現在認為它應該限制在同一區域內處理,并且需要加速處理過程。

我們打算把這個函數放到合適的位置,暫時放在代碼的底部,以便后續調整。調用這個函數時,不再傳遞一個簡單的三維坐標點(position vector),而是傳遞一個“可逆引用”(reversible reference)。這樣在執行過程中就能知道是否成功找到對應的可遍歷對象。

在調用該函數時,會先清空結果,如果沒有找到合適的可遍歷對象,就將結果置零,表示無效。搜索的過程是在體積組(volume group)里遍歷每個可遍歷對象,找到最靠近的那個。關鍵改變是:我們不再存儲該對象的位置,而是直接存儲實體指針(entity pointer)和用于找到它的可遍歷索引(traversable index,也稱p index),語義上表示實體“站立”的那個對象是什么。

因此,這樣就改變了原本基于空間點的表示方法,改為直接通過可遍歷實體來表達位置關系。當調用“get closest traversable”時,返回的不再是一個空間點,而是我們實際應該站立的那個“東西”。

為了適應這個變化,需要提供一種方式將該可遍歷引用轉換為具體的空間點。具體實現上,會調用類似“get sim space traversable”這樣的函數,把可遍歷引用轉換成世界空間坐標(world space position)。這里可能還涉及一些實現細節,比如傳遞參數、inline優化等。

在這個過程中,為了減少重復輸入“traversable”相關代碼,會定義一些輔助函數或變量,簡化調用。

總體流程是:給“get sim space traversable”傳遞一個可遍歷引用,得到對應的空間點,這樣現有的代碼邏輯可以在不大改動的情況下繼續使用。

接下來,處理遍歷引用時,提取其中的P值(位置索引)進行操作。這個引用當前只有一個值,未來可能擴展其他信息。

我們通過可遍歷引用找到最近的對象后,將其存儲下來。接著,在執行移動操作(movement from 和 movement to)時,直接記錄當前實體所“站立”的那個可遍歷對象作為起點和終點。

這樣,原先代碼中用實際位置(point)表示的“from”和“to”,現在被可遍歷引用所替代,改成基于實體站立對象的邏輯。

但在實現時會遇到一個問題:目前并沒有跟蹤實體當前到底站在哪個可遍歷對象上。這需要做額外處理,特別是對于“hopping”類型的實體,必須知道當前站立的位置,從而保證后續邏輯的準確執行。

具體來說,在任何需要用到“movement from”或“movement to”時,都會先通過實體調用“get sim space traversable”得到對應的空間位置,從而完成位置相關的計算。

總結關鍵點:

  • “get closest traversable”函數改為傳遞可遍歷引用,返回的是實體站立的對象,而非純空間點。
  • 通過輔助函數,將可遍歷引用轉換成具體的世界空間位置,保持兼容性。
  • 在體積組中搜索最近可遍歷對象時,存儲實體指針和索引,而非空間位置。
  • 移動操作中使用可遍歷引用表示起點和終點,語義更明確。
  • 解決目前沒有跟蹤實體當前所在可遍歷對象的問題,特別是“hopping”實體必須知道自己站在哪。
  • 對代碼進行了簡化封裝,減少重復輸入,優化函數調用。
  • 目前整體結構仍需調試和完善,但思路清晰,核心是以“實體當前站立的可遍歷對象”為核心來替代單純的位置點邏輯。

這是整個過程的詳細邏輯梳理,后續工作是完成具體代碼實現和調試,確保上述設計正確無誤地落地。

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

game_entity.h:讓實體跟蹤當前所在的 traversable

在處理實體的移動邏輯時,特別是對于“hopping”(跳躍)類的行為,我們將移動的概念從傳統的“movement from”和“movement to”改為更語義化的“站立在某處”(standing on)和“移動到某處”(moving to)。
具體來說:

  • 原先的“movement from”和“movement to”會被替換為“standing on”和“moving to”這兩個可遍歷引用。
  • 這里的“standing on”表示實體當前所站立的那個可遍歷對象,而“moving to”表示實體即將移動到的目標可遍歷對象。
  • 在跳躍或者移動過程中,不需要頻繁更新“standing on”,因為它始終是被追蹤和維護的。每次移動時,只需要更新“moving to”即可。
  • 當設置實體的位置引用時,比如實體指針(entity p),不僅會設置“moving to”,還會同時更新“standing on”,確保兩個引用都保持同步且準確。
  • 這種設計是為了為后續實現更復雜的事務性處理(transactional process)做準備,目的是能以更嚴謹和安全的方式管理實體的移動和狀態轉換。
  • 當前還不能完全保證“standing on”引用隨時有效,因此暫時還不能直接依賴它來進行所有操作,但整體思路是逐步將這套系統搭建起來,最終形成一個中心化的事務系統來統一管理。
  • 通過將“movement from/to”抽象為“standing on/moving to”,代碼結構和邏輯變得更清晰,語義更加貼合實體移動的真實含義。
  • 未來在處理移動時,會以這兩個引用為核心,相關的分組和邏輯也圍繞它們展開。

總結而言,我們正在將實體移動的底層表示從位置點向基于可遍歷引用的“站立點”和“目標點”轉變,為實現事務性移動管理打基礎,并逐步建立更安全、集中管理的移動狀態體系。
在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

game_world_mode.cpp:讓 AddPlayer 接受一個 traversable_reference 并在最近的 traversable 上創建玩家

我們目前雖然編譯沒有錯誤了,但仍然存在一個邏輯上的問題:

問題在于,當我們初始化一個實體時,并沒有為其分配具體的位置,也就是說,實體在創建后并沒有被放置在任何一個明確的“格子”或可遍歷位置上。現在我們系統假設所有實體在任意時刻都必須處于某個明確的“格子”中,這種初始化方式就會造成問題。

因此,我們必須改變實體創建的流程,確保每個實體在被創建的那一刻起,就已經明確地被放置在某個有效的位置上。不能再任意地把實體“扔”到某個位置上然后再依賴系統去推導其站立點或可遍歷引用。

我們有兩個方向可以處理這個問題:

  1. 創建時自動修正:如果實體被創建時沒有指定明確位置,可以在初始化階段“自動吸附”到最近的合法位置上,即自動尋找一個最近的可遍歷格子并將實體放置上去。這是個“容錯”方案,適合臨時處理。

  2. 強制指定位置(推薦):

    • 明確要求:所有實體在創建時必須提供其初始“站立位置”(即一個有效的可遍歷引用)。
    • 這樣可以保證后續所有系統運行時對實體狀態的假設都能成立,也更符合我們正在構建的事務性移動系統的設計原則。
    • 如果初始沒有提供合法位置,系統就拒絕創建該實體,或者拋出錯誤。

我們傾向于采用第二種方式,因為這是一個更清晰、更一致的設計方向,更符合“事務性”系統的原則——每個狀態都必須明確、合法、可追蹤。

總結要點:

  • 系統假設所有實體都必須在任意時刻處于一個明確的、合法的可遍歷格子中。

  • 當前實體初始化時沒有自動設置該狀態,導致潛在邏輯錯誤。

  • 解決方案是:

    • 優先采用強制要求初始化時指定合法站立點。
    • 可選采用自動修正機制,將未設置位置的實體吸附到最近的合法格子中。
  • 此調整為后續事務性系統打基礎,確保每個狀態都完整合法,避免系統出現不一致或非法狀態。

“我不想讓它們一開始就無效”β

我們目前已經實現了錯誤消除,但仍然存在一個關鍵問題:我們在初始化實體時,并沒有為其設置一個合法的初始位置。由于現在系統設定所有支持跳躍的實體必須處于一個明確的“可遍歷位置”(traversable reference)上,所以我們不能再隨意初始化實體,而不指定它的站立點。我們必須確保所有實體一開始就處于有效狀態,而不是默認處于非法狀態。

所以我們必須修改當前的實體創建邏輯,使得:

  1. 每個可以跳躍的實體都必須在初始化時被賦予一個合法的 traversable reference,這就意味著它一開始就必須站在某個格子上,而不是漂浮在空中或處于無效狀態。
  2. 即使邏輯上這個實體目前沒有“腿”或不能移動,但它的位置在語義上必須是有效的格子。
  3. 實體的“世界坐標” p 值也可能需要從其所在的可遍歷格子推導出來,或者相對于該格子進行偏移,但這部分細節可以稍后再討論。

我們在創建玩家時進行調整:

  • 玩家有一個身體部分(body),這是實體中真正“落地”的部分。
  • 我們會將玩家身體的 standing_on 字段設置為一個明確的 traversable reference,表示實體當前所處的位置。
  • 在處理“添加玩家”的操作時,我們需要先找到一個合法的格子來安放該玩家。

我們做了如下幾個關鍵性調整:

  1. 控制器輸入處理順序優化
    為了確保在嘗試放置玩家之前能夠訪問到當前的 sim_region(模擬區域),我們將控制器輸入處理邏輯移動到了 open_sim_region 之后。這樣我們就可以在同一幀中正確地基于場景信息進行決策。

  2. 通過攝像機位置尋找最近可遍歷點
    臨時方案中,我們通過 get_closest_traversable 函數,以攝像機位置作為參考點,尋找最近的合法格子,并將玩家放置在該格子上。

  3. 未來的更優方案規劃
    當前這種方式只是權宜之計。正式的做法應該是:

    • 第一位玩家會被放置在預定義的初始位置上。
    • 后續玩家加入時,應只選擇可從當前已有玩家位置連通到的可遍歷格子,避免玩家出生在無法逃脫的“孤島”區域。
    • 如果暫時無法找到合適的出生點,可以顯示 UI 提示告知“無法找到合適位置”,并在后續幀中繼續嘗試尋找。

通過這些設計,我們確保了所有支持移動的實體在創建時就是“合法”的,符合整個系統關于空間邏輯的要求,也為后續引入事務性移動系統打下了良好的基礎。系統狀態將從一開始就完整一致,不再存在“虛空中漂浮”的未初始化狀態。
在這里插入圖片描述

運行游戲查看效果,觸發 GetSimSpaceTraversable 的斷言

我們當前已經成功地添加了玩家,并嘗試將其放置在一個合理的可遍歷位置上,理論上這一步是完成了的,但在進行跳躍操作(hop)時卻出現了問題。

經過分析,我們發現:

  1. 玩家已經被添加成功
    這說明我們確實找到了一個有效的 traversable,并將其賦值給了玩家的 standing_on 字段,同時也設置了 movement_to 字段。這兩個字段都應該是有效的引用。因為如果找不到可遍歷位置,玩家根本就不會被創建,所以這一步邏輯上沒問題。

  2. 斷言失敗出現在跳躍邏輯中
    在執行跳躍時觸發了一個斷言,提示我們嘗試訪問了一個不存在的 traversable,這意味著 movement_to 字段的值在某一時刻是不合法的。

  3. 初步懷疑是字段順序混淆
    檢查代碼后發現 standing_onmovement_to 的賦值順序搞反了,在設置時不小心交換了它們。這種混淆導致了跳躍處理時邏輯錯誤,因為系統在嘗試查找 movement_to 時卻找到了錯誤的值,進而觸發斷言。

  4. 修正順序是當務之急
    首先必須修復這兩個字段的賦值順序,確保 movement_tostanding_on 分別設置為它們各自正確的 traversable 引用。修正后才能繼續排查跳躍過程中其他可能存在的邏輯問題。

  5. 材質顯示問題暫不處理
    雖然當前還有一些與材質顯示相關的問題(如紋理錯誤),但這并不是當前的優先級,可以在后續再處理。

總體而言,我們已經建立起了一個初步的、可落地的實體初始化機制,但還需要仔細驗證跳躍操作鏈路中的所有狀態傳遞是否一致、字段是否在所有路徑中都被正確設置。這是構建一個健壯的實體空間管理系統所必須跨過的階段。
在這里插入圖片描述

調試器:觸發斷言,發現 Head->StandingOn 是 NULL

我們當前的問題出在 standing_on 字段,它在某些情況下并沒有被正確設置,這導致在后續邏輯中訪問這個字段時發生了錯誤。

我們逐步排查了整個流程,并得出了以下詳細結論:


1. 初始狀態下 standing_on 應該是有效的

  • 在添加玩家的過程中,我們確實在 add_player 的邏輯里為玩家的 body 設置了 standing_onmovement_to
  • 設置的位置處,standing_onmovement_to 都被賦值為一個有效的 traversable,看上去一切正常。

2. 進入跳躍邏輯時字段卻變為 null

  • 當我們進入跳躍邏輯查看實體狀態時,卻發現 standing_onmovement_to 都是 null
  • 這說明在某個環節中,原本賦值成功的這兩個字段信息丟失了。

3. 排查字段丟失的原因

  • 我們跟蹤到了實體被加入世界的那一刻,即調用 enter_into_world 和相關的 chunk 打包邏輯。
  • 發現這里的實現是不完整的,在進行實體打包處理時,相關的狀態字段(比如 standing_on)并沒有被正確地保存或者拷貝到世界數據結構中。
  • 也就是說,雖然在邏輯層面上我們設置了字段,但在實體真正被寫入世界內存時這些字段被丟掉了。

4. 問題本質:打包/寫入邏輯缺失關鍵字段

  • 實體被加入到 world/chunk 的過程中遺漏了對 standing_onmovement_to 字段的寫入操作。
  • 這導致實際在游戲世界中的實體是“空的”,沒有這些關鍵字段的引用,于是后續邏輯讀取這些字段時就發生了斷言失敗或錯誤行為。

5. 解決思路

  • 必須修復 enter_into_world 或相應的打包寫入邏輯,確保將實體的所有關鍵字段(特別是 standing_onmovement_to)一并寫入。
  • 不僅僅要賦值,還要確認其在寫入結構中確實被序列化、傳遞和還原。
  • 此外可以考慮添加調試斷言,確保所有進入世界的實體在關鍵字段上都是非空的。

補充說明

  • 這個問題暴露了系統中實體數據生命周期管理上的一個結構性漏洞:邏輯賦值與數據落地脫節,容易造成表面上“設置成功”,實際卻“無效”的錯誤。
  • 需要系統性檢查所有實體創建與加入世界的路徑,避免類似遺漏。

總結來說,我們發現實體的 standing_on 字段雖然在邏輯上被賦值,但在真正加入游戲世界的過程中,這個值被遺漏,導致后續訪問時為空。需要立即修復實體寫入邏輯,確保所有關鍵字段都能正確存儲和傳遞。

在這里插入圖片描述

game_world.cpp:在 PackEntityIntoChunk 中完成所有修改

我們發現之前的實體數據寫入邏輯存在嚴重問題,核心在于打包(pack)實體進入世界時沒有涵蓋所有關鍵字段的處理,尤其是 standing_onmovement_to 等關鍵引用字段未被正確存儲,導致整個實體的狀態是不完整的。這是個根本性的錯誤,導致實體看似創建成功,實際上卻是無效的。

以下是我們對這一過程的詳細分析與修復思路:


1. 原因分析:打包邏輯不完整

  • 原本實體進入世界時的打包流程 pack_entity_into_world 只處理了一部分內容,沒有將所有必要的數據(如位置信息、狀態引用等)正確寫入。
  • 由于這些關鍵字段未被打包,所以實體在世界中是處于“未初始化”狀態的,訪問這些字段時就會出錯。

2. 修復方式:補全打包流程

  • 我們應當將所有字段的處理(包括邏輯狀態和位置引用)全部集中在 pack_entity_into_world 中統一處理,不能遺漏。
  • 尤其在打包進入 chunk 后,必須馬上處理相關字段的賦值,確保實體的完整性。
  • 因此新增了一個類似 entity_store_data 的結構或邏輯步驟,用于在存儲時執行這些打包行為。

3. 理念統一:創建時即應打包

  • 實體的所有“正確性”操作必須發生在打包階段,而不是在創建階段零散設置。
  • 創建實體本身不應直接設置任何 “索引” 或特定 chunk 數據,而是設置邏輯引用,最終由打包過程統一轉換為實際的世界數據。

4. 問題延伸:add_player 的實現不合理

  • 當前的 add_player 實現也存在相同的問題:在創建階段直接對實體結構設置了字段(如索引),這是不合理的。
  • 正確方式是:在 add_player 時僅設置邏輯引用或初步狀態,真正的 index/id/指針等應由世界系統在打包階段分配。

5. 后續優化建議

  • 考慮合并 same_regionstorage 系統。這兩個系統目前職責過于重疊,操作緊密耦合,合并有利于簡化邏輯和維護。
  • 合并后可形成一個更統一、更健壯的實體存儲與生命周期管理系統。

總結

我們之前的做法漏掉了實體生命周期中關鍵的存儲與狀態轉移環節,打包過程未覆蓋所有所需字段,導致實體行為不一致、邏輯斷裂。現在我們已將打包階段定義為狀態“落地”的唯一入口點,確保所有字段在進入世界之前都通過統一機制處理,從而保證實體行為的正確性和穩定性。接下來也將修復 add_player 的流程,確保它只負責邏輯創建,而不承擔狀態設定,統一交由打包系統處理。

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

運行游戲,成功跳躍

現在我們已經修復了之前的邏輯問題,整體流程終于能夠走通,并且角色能夠正常地進行跳躍了,說明整個實體初始化與動作系統的流程已經進入正軌。以下是這一階段的詳細總結:


1. 修復后的行為驗證成功

  • 之前存在的問題是實體創建后狀態不完整,尤其是沒有正確設置 standing_onmovement_to,導致動作邏輯異常。
  • 修復后我們確保了所有關鍵狀態字段在實體被打包到世界時統一設置,從而保證了邏輯的一致性和完整性。
  • 現在跳躍操作已經可以順利執行,說明移動相關的狀態引用邏輯已成功生效。

2. 修復的核心改動

  • 實體從創建到存入世界時的路徑完全走通,打包過程中確保了數據結構被正確賦值。
  • 所有需要落地的邏輯都集中到了統一的打包處理函數中進行,不再在其他流程中單獨設置,避免了重復和遺漏。
  • 這些修復讓角色創建后立即處于一個“合法”的狀態,也為后續所有交互行為提供了正確的起點。

3. 狀態字段工作機制已穩定

  • 現在系統能夠在實體創建并進入世界的過程中,正確設置:

    • 當前站立的位置(standing_on
    • 當前目標位置(movement_to
  • 這兩個字段已經成為實體行為驅動的基礎,在跳躍等行為觸發時起到了核心作用。

  • 避免了無效或未定義狀態導致的斷言失敗。


4. 當前成果與下一步方向

  • 跳躍功能運行正常,初步驗證了整體移動機制是可靠的。
  • 這也為后續更復雜的系統(如路徑查找、動態碰撞處理等)提供了良好基礎。
  • 下一階段可以考慮對更多交互行為做統一測試,并評估是否需要擴展或重構與實體行為相關的其它邏輯模塊。

總結

我們成功通過修復實體初始化與打包流程中的漏洞,實現了跳躍等行為的正確執行。所有關鍵數據字段都已在正確的生命周期階段進行賦值,角色行為也已回歸正常。系統整體的行為驅動模型已經初具雛形,后續可以在此基礎上構建更豐富、更可靠的實體交互機制。
在這里插入圖片描述

game_world_mode.cpp:讓 HeroBody 恢復位置,引入 AddFloatyThing

當前階段我們開始探索實體與“可站立物體”之間的交互機制,主要思路是通過創建類似“浮動平臺”的新實體類型,讓角色能夠在這些平臺上“站立”和“被移動”。以下是對這部分邏輯的詳細總結:


1. 在“站立”狀態下重設實體位置的概念

  • 我們設想:當實體處于“站立”狀態時,應始終將其位置設置為所依附對象的位置,即“站立在哪,就在那里”。
  • 雖然當前系統中這段代碼沒有實際功能,但這個邏輯為未來實現“移動載具”或“移動平臺”等交互打下了基礎。
  • 比如玩家站在一艘船或平臺上,這個平臺移動時,玩家的 entity.p 位置也應隨之更新。

2. 引入“浮動物體”作為新實體類型

  • 我們引入了 floaty_thing 類型的實體,作為測試使用的一種“浮動地面”。
  • 它和普通地面類似,都可以被“站立”,但未來可能會有特殊的移動邏輯或交互功能。
  • 創建方式類似于其他地面對象,暫時不涉及額外碰撞邏輯(即不做特殊的碰撞處理)。

3. 渲染和邏輯系統的集成

  • 在渲染邏輯中增加了對 floaty_thing 類型的支持,使其可以在世界中可見。
  • 暫時復用了地面渲染邏輯,因此可視效果與地板相似,但這僅作為占位設計。
  • 實體類型的系統未來將逐步淘汰,可能會過渡到更通用的組件系統。

4. 場景構建中的使用實例

  • 在標準房間構建邏輯(如 add_standard_room)中,我們測試性地添加了一個 floaty_thing
  • 具體位置在某個指定 tile 坐標(例如 tile x=7, y=7)。
  • 用這種方式測試浮動平臺的存在、渲染及是否能被實體“站立”。

5. 系統結構與未來擴展方向

  • 當前系統仍有很多臨時代碼,如位置判斷、硬編碼坐標等,僅作為功能驗證使用。
  • 隨著邏輯成熟,將逐步移除硬編碼內容,引入更健壯的空間管理與交互檢測機制。
  • 未來還會探索讓平臺移動,并同步移動其上的角色,實現動態載具系統或浮動平臺關卡。

總結

我們為實體系統引入了“站立依附”的機制,允許角色在特定平臺上移動,同時保證其空間狀態與依附物保持同步。新添加的 floaty_thing 為后續更復雜的物體交互打下了基礎。通過初步集成渲染和實體邏輯,我們驗證了這一機制的基本可行性,未來可以進一步拓展為完整的移動平臺、載具交互或移動環境機制。

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

game_world_mode.cpp:讓 FloatyThingForNow 上下移動

我們在這個階段實現了“浮動物體”(floaty thing)的基本運動邏輯,并嘗試通過對其垂直坐標(Z軸)的動態修改,實現一個周期性上下浮動的效果。具體內容如下:


1. 浮動物體已經添加成功

  • 雖然一開始看不到浮動物體,但經過確認它確實已經被添加進了世界中。
  • 后續在畫面中可以看到它和地面重疊地堆疊在一起,說明其確實被正確渲染和放置。

2. 添加浮動物體的移動邏輯

  • 與普通地面(floor)不同,浮動物體被賦予了“主動移動”的能力。
  • 通過在邏輯處理中添加對 floaty_thing 類型的判斷,我們為這類物體添加了動態更新的邏輯。
  • 主要是控制其 entity.p.z 值,讓其上下浮動。

3. 使用時間函數實現上下浮動

  • 通過正弦函數(sine)控制其 Z 坐標值,實現自然的周期性浮動。

  • 使用了 tBob 或類似變量表示當前幀的時間偏移量。

  • 更新邏輯類似于:

    entity.p.z = sin(tBob * 0.5f) * 2.0f;
    

    表示以一定頻率和幅度(比如 ±2)做垂直方向的震蕩。


4. 浮動行為的意義

  • 雖然目前浮動物體只是在 Z 軸方向做簡單的上下運動,但這已經為后續更多交互場景打下了基礎:

    • 玩家或其他實體可以“站在”浮動物體上,跟隨其上下移動;
    • 可以模擬諸如升降臺、電梯、浮橋等功能;
    • 若與碰撞檢測結合,可擴展為更復雜的游戲機制,比如動態地形、移動謎題等。

5. 后續可擴展內容

  • 當前上下浮動是純視覺與位移效果,還未影響“站在其上”的實體位置,需要進一步擴展同步邏輯;
  • 可以添加橫向位移,形成更復雜的運動軌跡;
  • 支持多個浮動物體、不同頻率與相位、更多參數可調的浮動方式;
  • 最終可能將這類浮動物體設計為一種獨立的“可騎乘”或“可承載”組件,供其他實體掛載。

總結

我們已實現浮動物體的基礎動態行為,通過在邏輯更新中修改其 Z 軸位置,實現周期性浮動效果。這個機制可廣泛用于游戲中的動態交互場景,如浮橋、移動平臺等,并可進一步擴展為支持實體掛載、平臺聯動等高級系統。這個步驟標志著實體系統朝動態環境與物理交互方向邁出了關鍵一步。
在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

站上面抖動的厲害

運行游戲,嘗試站在 FloatyThingForNow 上

當前我們實現了一個上下浮動的浮動物體,并試圖讓玩家實體站在其上,但出現了一些問題與不符合預期的行為。我們對這些現象進行了分析,并對系統進行了微調,具體過程和結論如下:


1. 浮動物體上下浮動邏輯生效

  • 浮動物體已經能夠周期性上下浮動。
  • 浮動是通過改變實體的 z 坐標實現的,采用的是類似 sin 函數控制的平滑運動。

2. 玩家實體無法穩定站立在浮動物體上

  • 理論上實體應該可以站在浮動物體上,并隨著其一起上下移動。
  • 實際上實體不斷地“彈跳”(hop),無法保持穩定。
  • 出現了反復跳起然后落下的異常行為,表現出“劇烈晃動”或“持續彈跳”的效果。

3. 異常行為原因分析

  • 異常的根本原因是:玩家的頭部系統(head)在每一幀都在尋找最近的可行走表面(traversable)
  • 浮動物體因為上下移動,其位置在時間軸上不斷變化,導致玩家頭部每一幀都認為“腳下不是最近的 traversable”。
  • 因此每幀都在嘗試跳躍或重新校準位置,從而形成了這種不穩定的“彈跳”行為。

4. 跳躍終止邏輯問題

  • 原先以為跳躍是純時間驅動的,但現在可以確認:跳躍的終止條件還涉及當前位置是否仍然在可行走表面上
  • 由于浮動物體不斷變動,導致系統判斷為“不再有效”,從而不斷重啟跳躍動作。

5. 臨時緩解方案

  • 為了避免這種劇烈彈跳現象,我們暫時降低了浮動物體的浮動幅度,使得其在玩家頭部邏輯判斷中更加“穩定”。
  • 此舉減輕了由于坐標浮動造成的邏輯擾動,使得站立更接近于“靜止狀態”。

6. 后續需要處理的問題

  • 頭部邏輯與實體跟隨機制的脫節:頭部依賴“最近 traversable”的判斷方式并不適用于動態平臺,應該考慮“綁定”當前站立表面。
  • 站立狀態與移動平臺同步:當玩家站在移動平臺上時,應有專門的跟隨邏輯,而不是每幀重新計算位置。
  • 跳躍邏輯中斷機制改進:需要添加對動態平臺的適配機制,比如標記“當前站立平臺仍在可用范圍內”,避免誤判導致跳躍。
  • 未來可擴展為完整的掛載系統:例如平臺可以通知其承載實體做同步更新,而非依賴實體自身去追蹤平臺狀態。

總結

當前系統成功讓浮動物體實現了浮動行為,但在玩家實體站立其上時出現了彈跳異常。問題的根源在于頭部系統對“最近 traversable”的判斷方式不適用于動態表面。我們通過降低浮動幅度臨時緩解了現象,但后續需從邏輯架構上調整平臺與實體的綁定方式,以支持更復雜的動態交互系統。

game_world_mode.cpp:讓 AddStandardRoom 只在位置添加 FloatyThingForNow

我們對房間(standard room)的地面生成邏輯進行了調整,目標是使房間中某個特定坐標位置不再生成普通地面,而是生成一個可以上下浮動的“浮動物體”,用于測試實體在動態平臺上的行為。具體操作和推理如下:


1. 修改地面生成邏輯

  • 原始的地面生成方式是統一調用添加地板(ground)并賦予碰撞屬性(floor collision)。
  • 為了在特定位置替換為浮動物體,加入了一個條件判斷結構。

2. 加入條件判斷

  • 判斷依據是 tile 坐標的偏移值 axay

    • ax == 2 && ay == 2 時,不再添加普通地面。
    • 而是添加一個浮動物體(floaty thing)作為替代。
  • 其余坐標位置仍照常生成地面。


3. 設計目的

  • 這種做法可以確保在特定坐標處創建一個特殊的平臺(浮動物體),其余部分不變,便于對比和測試。
  • 由于位置明確,避免了控制邏輯(如玩家移動判斷)因不確定性而出錯。

4. 浮動物體顯示問題

  • 出現了浮動物體未能正確渲染的問題,因此臨時放棄了浮動物體渲染的獨立邏輯。
  • 改為簡單地使用已有的邏輯結構直接繪制(“does that it this way”)以保證視覺上能看到該實體。

5. 總體目標

  • 利用這種靜態房間結構內的條件判斷方式,實現在指定區域插入一個動態平臺。
  • 為后續實現如“站在移動平臺上并隨之移動”等更復雜的玩法機制提供驗證基礎。

后續方向

  • 優化浮動物體的渲染與實體綁定機制,使其行為在動態更新中更加一致。
  • 進一步探索玩家與動態平臺之間的相互作用方式,如自動同步、乘坐邏輯、跳躍過渡等。

總結

我們通過修改標準房間地面生成邏輯,在特定坐標位置生成一個浮動物體,替代普通地面,從而為后續動態平臺的交互測試打下基礎。同時對浮動物體的顯示做了調整,確保可以看到效果。整套邏輯在不影響其他控制系統的情況下實現了定點插入特殊實體的功能。
在這里插入圖片描述

運行游戲,再次嘗試站在 FloatyThingForNow 上

當前發現了一個奇怪的問題,具體表現為角色的“跳躍”(hop)行為異常頻繁和不合理。分析后發現原因可能是跳躍的觸發條件設計有誤,現有的跳躍代碼并不是基于角色頭部與目標點之間的合理距離判斷,而是每次都嘗試跳到最近的點,這導致角色會在兩個點之間不斷地反復跳躍,非常不自然。


具體問題點:

  • 跳躍代碼缺少判斷條件,沒有排除“跳躍到相同點”的情況。
  • 控制邏輯是每次都根據頭部當前位置尋找最近點,但沒有考慮當前的運動模式和頭部與身體的位置差異。
  • 導致角色頭部位置稍微移動,就會反復觸發跳躍,出現不穩定的跳躍抖動。

解決思路:

  • 在跳躍動作執行前,需要先檢查實體的運動模式是否為“planted”(即已站穩狀態)。
  • 如果是站穩狀態,需要先更新相關狀態,再進行最近點的搜索和跳躍。
  • 只有當頭部距離身體足夠遠,才允許觸發跳躍,避免無意義的頻繁跳躍。
  • 這要求重寫控制器代碼,使其基于頭部與身體距離的判斷,控制跳躍觸發時機。

當前狀態和后續工作:

  • 修正運動模式更新的順序,確保跳躍判斷邏輯前狀態正確。
  • 仍然存在問題,因為頭部持續尋找最近點,跳躍動作反復出現。
  • 計劃對控制器邏輯進行重新設計,加入“只有距離超過閾值時才跳躍”的限制。
  • 這一問題暫定為后續重點調試和修復的“明日任務”。

總結:

當前跳躍機制缺少合理的觸發判斷,導致角色在頭部位置變化時反復跳躍。需要先根據運動模式和頭部與身體的距離進行判斷,避免無意義跳躍。解決方案是調整跳躍前狀態更新順序并重寫控制器邏輯,確保跳躍行為自然合理。
在這里插入圖片描述

在這里插入圖片描述

問答環節

如果我理解沒錯,這聽起來像是用滯后機制解決的問題

目前的控制邏輯是在沒有考慮“不可通行區域”的情況下編寫的,導致每次都簡單地選擇距離最近的點進行跳躍,這樣的設計不夠合理。現在需要改進控制器邏輯,使其能夠識別哪些區域是可通行的,避免角色跳到無法通過的位置。


改進之后,代碼會更智能地考慮角色意圖和環境限制,從而提升頭部的行為表現,使其跳躍選擇更加合理和自然。這個改動相對簡單,但會大幅優化整體的動作邏輯和角色移動體驗。


總結來說,現有控制邏輯過于簡單,沒有過濾不可通行區域。通過增加對可通行性的判斷和角色意圖的考慮,控制邏輯將變得更健壯,頭部跳躍行為也會更加合理和有效。

他們為Greenfoot實現了結構化編輯器

Greenfoot 是一個面向初學者的交互式編程環境,主要用于教學和學習面向對象編程,特別是Java語言。它通過一個圖形化界面和簡單的結構化編輯器,讓用戶可以創建基于二維圖形的游戲和模擬。Greenfoot 讓編程更直觀,能夠直觀看到代碼對游戲世界的影響,適合入門級別的編程學習。雖然界面看起來不夠美觀,但它的重點是教學和簡化編程過程,而不是視覺設計。

所以,我們打算讓頭永遠是脫離狀態嗎?

我們計劃讓頭部永遠與身體分離。這意味著頭部始終獨立移動,身體則跟隨頭部移動。雖然在圖形表現上,我們會盡力繪制得讓頭部和身體看起來像是物理上連接在一起,但實際上它們是分開控制的,頭部的運動先行,身體的運動緊隨其后。這樣做的目的是讓視覺效果保持連貫,但在邏輯和運動上實現分離控制。

手套在哪里?你會編寫自定義手套動作吧?

Abner戴上手套后,會為手套編寫自定義的移動程序。手套實際上是用來攻擊的工具,所以手套的移動不是自由移動,而是根據攻擊動作來控制。也就是說,手套不會像普通肢體那樣隨意移動,而是在執行攻擊時才會做出相應的動作。

你計劃什么時候加入正確透視的美術,讓英雄看起來不那么奇怪?

關于何時添加正確的透視圖,我們還沒有具體計劃。英雄的畫面看起來有些奇怪,因為藝術資源的準備進度有所耽擱,主要是獲取藝術素材方面的問題,目前還沒有完成,所以這方面的工作還在等待中。

理論上你可以用第二個英雄和Xbox手柄測試,確保他們不會站在同一個格子上?

理論上,可以通過添加第二個英雄來測試,主要是為了確保它們不會處于相同的狀態或位置。但由于事務處理機制還沒有實現,這意味著兩個英雄可能會同時站在同一個地方,這種情況目前并沒有被阻止或檢測到。同時,當前也沒有將它們的狀態打印出來進行監控。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/81162.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/81162.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/81162.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深度學習讓魚與熊掌兼得

通常,一個大的復雜的模型的loss會低,但是擬合方面不夠,小的模型在擬合方面更好,但是loss高,我們可以通過深度學習來得到一個有著低loss的小模型 我們之前學過,peacewise linear可以用常數加上一堆這個階梯型函數得到,然后因為peacewise linear可以逼近任何function,所以理論上…

如何在 AWS 上構建支持 AVIF 的前端圖片優化方案

一、為什么使用 AVIF 圖片格式? 優勢點 說明 高壓縮率 在相似質量下,AVIF 文件比 JPEG/PNG/WebP 更小,能有效節省帶寬和存儲空間。 更高畫質 即使在低碼率下也能保持清晰細節,減少壓縮帶來的馬賽克或模糊問題。 支持透明度 …

C++中的std::allocator

C中的std::allocator 文章目錄 C中的std::allocator1.std::allocator1.1C中的placement new 和operator new1.2一個custom allocator的實現1.3使用std::allocator_traits實現allocator 1.std::allocator C中的std::allocator默默工作在CSTL中的所有容器的內存分配上&#xff0…

CodeBuddy編程新范式

不會寫?不想寫? 騰訊推出的CodeBuddy徹底解放雙手。 示例 以下是我對CodeBuddy的一個小體驗。 我只用一行文字對CodeBuddy說明了一下我的需求,剩下的全部就交給了CodeBuddy,我需要做的就是驗收結果即可。 1.首先CodeBuddy會對任…

QML學習01(設置寬度、高度、坐標點、標題,信號與槽,鍵盤事件)

QML學習 1、前言2、QML3、QML和QWidget的區別3、QtQuick下的Windows應用4、總結 1、前言 記錄一下QML學習的過程,方便自己日后回顧,也可以給有需要的人提供幫助。 2、QML QML是 Qt 框架中的一種聲明式編程語言,專門用于快速設計和開發用戶…

在VSCode中接入DeepSeek的指南

本文將介紹三種主流接入方式,涵蓋本地模型調用和云端API接入方案。 一、環境準備 1.1 基礎要求 VSCode 1.80+Node.js 16.x+Python 3.8+(本地部署場景)已部署的DeepSeek服務(本地或云端)1.2 安裝必備插件 # 打開VSCode插件面板(Ctrl+Shift+X) 搜索并安裝: - DeepSeek Of…

機器學習-計量經濟學

機器學習 不要事前決定變量關系,關鍵是誰也不知道啊,機器學習學習的模型(那也不是真實的關系啊) 這就是自然學科的好處:只要不斷的優化這個未知的東西(函數),然后在數據上&#xff…

五、Linux賬號與權限管理

1、管理用戶和組賬號 1.1、用戶 1.1.1、用戶的概念及作用 在Linux系統中,用戶(User)指的是可以訪問系統資源的個體實體。每個用戶都有一個唯一的用戶賬號,用于標識和管理其在系統中的活動和訪問權限。 用戶的重要性和功能: 身份認證和訪問控制: 用戶賬號用于身份認證,確…

精益數據分析(61/126):移情階段評分體系構建與實戰案例解析

精益數據分析(61/126):移情階段評分體系構建與實戰案例解析 在創業的移情階段,如何科學評估用戶需求的真實性與緊迫性,是決定后續產品方向的關鍵。今天,我們結合《精益數據分析》中的評分框架,…

完成反射宇宙的最后一塊拼圖:泛型集合

反射,c#的黑科技,一手打造漂亮的,專屬于自己的屬性框 之前分享的: 如何寫一個自定義屬性控件的功能,但是只是對基礎的類型,比如String,bool,int等,但是對list<T>,Vector<T>這種泛型集合類型支持的不是很好,剛好最近重新研究了一下,將這個非常重要的功能完成了. 效…

Redis--基礎知識點--26--過期刪除策略 與 淘汰策略

Redis 的過期策略和淘汰策略是內存管理的核心機制&#xff0c;分別用于處理鍵的自動失效和內存不足時的數據清理。以下是詳細說明&#xff1a; 1 、過期刪除策略&#xff08;Expiration Policy&#xff09; 處理已設置過期時間&#xff08;EXPIRE&#xff09;的鍵&#xff0c;…

第六天——貪心算法——字符串分隔

1. 題目 給定一個字符串 s&#xff0c;我們需要將其劃分為盡可能多的部分&#xff0c;使得同一字母最多出現在一個部分中。 例如&#xff1a;字符串 "ababcc" 可以劃分為 ["abab", "cc"]&#xff0c;但要避免 ["aba", "bcc&quo…

[原創](現代Delphi 12指南):[macOS 64bit App開發]: 注意“回車換行“的跨平臺使用.

[作者] 常用網名: 豬頭三 出生日期: 1981.XX.XX 企鵝交流: 643439947 個人網站: 80x86匯編小站 編程生涯: 2001年~至今[共24年] 職業生涯: 22年 開發語言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 開發工具: Visual Studio、Delphi、XCode、…

Maven 插件參數注入與Mojo開發詳解

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家&#xff0c;歷代文學網&#xff08;PC端可以訪問&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移動端可微信小程序搜索“歷代文學”&#xff09;總架構師&#xff0c;15年工作經驗&#xff0c;精通Java編…

擴增子分析|R分析之微生物生態網絡穩定性評估之節點和連接的恒常性、節點持久性以及組成穩定性指數計算

一、引言 周集中老師團隊于2021年在Nature climate change發表的文章&#xff0c;闡述了網絡穩定性評估的原理算法&#xff0c;并提供了完整的代碼。自此對微生物生態網絡的評估具有更全面的指標&#xff0c;自此網絡穩定性的評估廣受大家歡迎。本文將介紹網絡穩定性之節點和連…

人體肢體渲染-一步幾個腳印從頭設計數字生命——仙盟創夢IDE

人體肢體動作數據集-太極拳 渲染代碼 # 初始化Pygame pygame.init()# 設置窗口尺寸 WINDOW_WIDTH 800 WINDOW_HEIGHT 600 window pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) pygame.display.set_caption("動作回放")# 設置幀率 FPS 30 clock pyg…

強化學習入門:馬爾科夫獎勵過程

文章目錄 前言1、組成部分2、應用例子3、馬爾科夫獎勵過程總結 前言 最近想開一個關于強化學習專欄&#xff0c;因為DeepSeek-R1很火&#xff0c;但本人對于LLM連門都沒入。因此&#xff0c;只是記錄一些類似的讀書筆記&#xff0c;內容不深&#xff0c;大多數只是一些概念的東…

騰訊開源實時語音大模型VITA-audio,92mstoken極速響應,支持多語言~

簡介 VITA-Audio 是一個由騰訊優圖實驗室&#xff08;Tencent Youtu Lab&#xff09;、南京大學和廈門大學的研究人員共同開發的項目&#xff0c;旨在解決現有語音模型在流式生成&#xff08;streaming&#xff09;場景下生成第一個音頻令牌&#xff08;token&#xff09;時的高…

測序的原理

Sanger 測序原理 https://v.qq.com/x/page/d0124c0k44t.html illumina 測序原理&#xff1a; https://v.qq.com/x/page/i0770fd7r9i.html PacBio 第三代 SMRT 單分子測序 https://v.qq.com/x/page/r03534cry7u.html Ion torrent 測序原理 https://v.qq.com/x/page/v01754s6r82.…

高項-邏輯數據模型

邏輯數據模型的核心理解 1. 定義與特點 邏輯數據模型&#xff08;Logical Data Model, LDM&#xff09;&#xff1a; 是一種抽象的數據結構設計&#xff0c;用于描述業務實體&#xff08;如客戶、訂單&#xff09;及其關系&#xff08;如“客戶下單”&#xff09;&#xff0c…