Depth-sort upright world planes; mod documentation

This commit is contained in:
cthangover committed 2026-10-29 09:26:18 +01:00
1 parent f332570294
commit 2dc6769cb1
30 files changed
+406

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
# Line endings: LF everywhere, on every OS, whatever core.autocrlf says.
* text=auto eol=lf
# cmd.exe misreads labels and goto in LF batch files, so they stay CRLF.
*.bat text eol=crlf
*.cmd text eol=crlf
# Binaries: never converted, never diffed as text.
*.png binary
*.jpg binary
*.jpeg binary
*.webp binary
*.svg text
*.ogg binary
*.wav binary
*.mp3 binary
*.ttf binary
*.otf binary
*.woff binary
*.woff2 binary
*.dll binary
*.so binary
*.dylib binary
*.pdb binary
*.exe binary
*.zip binary
*.pck binary
*.moc3 binary
*.res binary
*.scn binary
+9
View File
@@ -0,0 +1,9 @@
{
"options": [
{
"key": "tile.renderer",
"value": "isometric",
"name": "collection_settings/isometric"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

+37
View File
@@ -0,0 +1,37 @@
# Isometric Tiles — the diamond map view
Isometric Tiles draws tile maps at an angle, as a grid of 2:1 diamonds, so buildings and trees stand up out of the ground. It is one of two map views for the shared Tile Rendering engine; the other is Top-down Tiles. The same maps, events and saves work in both.
![The village of RPG Plus at noon in the isometric view: the square, lamps, houses, villagers and the hero on the path; past the map's edge the background is empty.](assets/village-isometric.jpg)
## What is different from the top-down view
- **Diamond cells.** Each map cell is drawn as a diamond twice as wide as it is tall. The logical grid is still square: a cell has the same four neighbours as before.
- **Standing objects.** Buildings and other multi-cell objects that a tileset marks for it are drawn as upright pictures or as several flat faces, instead of flat tiles.
- **Characters** pick the sprite row that matches their direction on the diamond grid.
- **Clicking** on the map selects the diamond under the pointer; the RPG map editor uses the same rule.
![The same village map drawn in both views: top-down on the left, isometric on the right.](assets/same-map-two-projections.jpg)
What does not change: walking rules, collisions, events, battles, saves, lighting and time of day are owned by the RPG mod and Tile Rendering and behave the same in both views.
## Limitations
- **Keys follow the grid, not the screen.** Up and down (W/S, arrows) move along one diagonal of the screen, left and right along the other, because they move the hero one cell on the square grid.
- **The edges of a map show.** Near a corner of the map you see the empty background beyond the diamond's edge, as in the picture above.
- **Tilesets must be prepared.** Objects look upright only when the tileset describes them as groups; ordinary tiles are laid flat on the diamonds.
## Turn it on
In the game's scheme (**Mods & Collections → Collections → the game → Edit scheme**), include this mod and set **Map projection** to **Isometric**. The value of the `tile.renderer` setting is `isometric`:
```json
"settings": { "tile.renderer": "isometric" }
```
To try it once without changing the game, start it with `--tile-renderer=isometric` on the command line. RPG Plus already includes both renderers, so only the setting needs to change.
## If something goes wrong
1. **The map is empty.** The game's **Map projection** asks for a renderer that is not included; include this mod or choose another projection.
2. **The hero walks diagonally.** That is how the keys work in this view (see Limitations).
+37
View File
@@ -0,0 +1,37 @@
# Isometric Tiles — la vista en rombos del mapa
Isometric Tiles dibuja los mapas de tiles en ángulo, como una cuadrícula de rombos 2:1, de modo que los edificios y los árboles se levantan del suelo. Es una de las dos vistas de mapa del motor común Tile Rendering; la otra es Top-down Tiles. Los mismos mapas, eventos y partidas guardadas funcionan en ambas.
![La aldea de RPG Plus al mediodía en la vista isométrica: la plaza, las farolas, las casas, los aldeanos y el héroe en el camino; tras el borde del mapa, el fondo queda vacío.](assets/village-isometric.jpg)
## Qué cambia respecto a la vista superior
- **Casillas de rombo.** Cada casilla del mapa se dibuja como un rombo el doble de ancho que de alto. La cuadrícula lógica sigue siendo cuadrada: una casilla tiene los mismos cuatro vecinos que antes.
- **Objetos de pie.** Los edificios y demás objetos de varias casillas que el tileset marca como tales se dibujan como imágenes verticales o como varias caras planas, en lugar de tiles planos.
- **Los personajes** eligen la fila de sprites que corresponde a su dirección sobre la cuadrícula de rombos.
- **Al hacer clic** en el mapa se selecciona el rombo bajo el puntero; el editor de mapas RPG usa la misma regla.
![El mismo mapa de la aldea en ambas vistas: vista superior a la izquierda, isométrica a la derecha.](assets/same-map-two-projections.jpg)
Lo que no cambia: las reglas de caminar, las colisiones, los eventos, los combates, el guardado, la iluminación y la hora del día pertenecen al mod RPG y a Tile Rendering, y se comportan igual en ambas vistas.
## Limitaciones
- **Las teclas siguen la cuadrícula, no la pantalla.** Arriba y abajo (W/S, flechas) avanzan por una diagonal de la pantalla, izquierda y derecha por la otra, porque mueven al héroe una casilla de la cuadrícula cuadrada.
- **Se notan los bordes del mapa.** Cerca de una esquina se ve el fondo vacío más allá del borde del rombo, como en la imagen de arriba.
- **Los tilesets deben estar preparados.** Los objetos solo se ven de pie cuando el tileset los describe como grupos; los tiles normales se colocan planos sobre los rombos.
## Actívalo
En el esquema del juego (**Mods → Colecciones → el juego → Editar esquema**), incluye este mod y pon **Proyección del mapa** en **Isométrica**. El valor del ajuste `tile.renderer` es `isometric`:
```json
"settings": { "tile.renderer": "isometric" }
```
Para probarlo una vez sin cambiar el juego, arráncalo con `--tile-renderer=isometric` en la línea de comandos. RPG Plus ya incluye los dos renderizadores, así que basta con cambiar el ajuste.
## Si algo falla
1. **El mapa está vacío.** La **Proyección del mapa** del juego pide un renderizador que no está incluido; incluye este mod o elige otra proyección.
2. **El héroe camina en diagonal.** Así funcionan las teclas en esta vista (ver Limitaciones).
+37
View File
@@ -0,0 +1,37 @@
# Isometric Tiles — ひし形のマップビュー
Isometric Tiles はタイルマップを 2:1 のひし形の格子で斜めから描き、建物や木を地面から立ち上がらせます。共通エンジン Tile Rendering の 2 つのマップビューの 1 つで、もう 1 つは Top-down Tiles です。同じマップ、イベント、セーブがどちらでもそのまま動きます。
![アイソメトリックビューの正午の RPG Plus の村: 広場、灯り、家、村人、道を行く主人公。マップの外は背景が空いている。](assets/village-isometric.jpg)
## 見下ろしビューとの違い
- **ひし形のマス。** 各マスは、高さの 2 倍の幅を持つひし形として描かれます。論理グリッドは相変わらず正方形で、マスの 4 つの隣接は昔のままです。
- **立つ物体。** タイルセットがそのように印をつけた建物などの複数マスの物体は、平たいタイルの代わりに、立ち上がった絵やいくつかの平面として描かれます。
- **キャラクター**は、ひし形グリッド上での向きに合うスプライトの列を選びます。
- **クリック**すると、ポインターの下のひし形が選ばれます。RPG マップエディターも同じ規則を使います。
![同じ村のマップを両方のビューで: 左が見下ろし、右がアイソメトリック。](assets/same-map-two-projections.jpg)
変わらないもの: 歩行の規則、衝突、イベント、バトル、セーブ、照明、時間の流れは RPG Mod と Tile Rendering の持ち物で、両方のビューで同じように振る舞います。
## 制限
- **キーはグリッドに従い、画面には従いません。** 上と下(W/S、矢印)は画面の片方の対角線に沿って、左と右はもう片方に沿って動きます。正方形グリッドの 1 マスを動かすためです。
- **マップの縁が見えます。** マップの角の近くでは、ひし形の縁の向こうの空の背景が見えます。上の画像のとおりです。
- **タイルセットの準備が必要。** 物体が立って見えるのは、タイルセットがそれらをグループとして記述しているときだけです。普通のタイルはひし形の上に平たく置かれます。
## 有効にする
ゲームの構成(**MOD とコレクション → コレクション → ゲーム → 構成を編集**)でこの Mod を含め、**マップの投影**を **アイソメトリック** にします。設定 `tile.renderer` の値は `isometric` です。
```json
"settings": { "tile.renderer": "isometric" }
```
ゲームを変えずに 1 回だけ試すには、コマンドラインで `--tile-renderer=isometric` を付けて起動します。RPG Plus には両方のレンダラーが入っているので、設定だけ変えれば十分です。
## うまくいかないとき
1. **マップが空です。** ゲームの **マップの投影** が、含まれていないレンダラーを求めています。この Mod を含めるか、別の投影を選んでください。
2. **主人公が斜めに歩く。** このビューではキーがそう動く仕組みです(「制限」を参照)。
+37
View File
@@ -0,0 +1,37 @@
# Isometric Tiles — 마름모 맵 보기
Isometric Tiles는 타일 맵을 2:1 마름모 격자로 비스듬히 그려서 건물과 나무가 땅에서 솟아 보이게 합니다. 공유 엔진 Tile Rendering의 두 맵 보기 중 하나이며, 다른 하나는 Top-down Tiles입니다. 같은 맵, 이벤트, 저장이 양쪽에서 모두 작동합니다.
![아이소메트릭 보기의 정오 무렵 RPG Plus 마을: 광장, 가로등, 집들, 마을 사람들, 길 위의 주인공. 맵 가장자리 너머로 배경이 비어 있다.](assets/village-isometric.jpg)
## 탑다운 보기와 다른 점
- **마름모 칸.** 맵의 각 칸은 높이의 두 배 폭을 가진 마름모로 그려집니다. 논리 격자는 여전히 정사각형이라 칸의 네 이웃도 예전과 같습니다.
- **서 있는 물체.** 타일셋이 표시해 둔 건물 같은 여러 칸짜리 물체는 평평한 타일 대신 곧게 선 그림이나 여러 평면으로 그려집니다.
- **캐릭터**는 마름모 격자에서 자기 방향에 맞는 스프라이트 줄을 고릅니다.
- **클릭**하면 포인터 아래의 마름모가 선택됩니다. RPG 맵 에디터도 같은 규칙을 씁니다.
![같은 마을 맵의 두 보기: 왼쪽 탑다운, 오른쪽 아이소메트릭.](assets/same-map-two-projections.jpg)
바뀌지 않는 것: 걷기 규칙, 충돌, 이벤트, 전투, 저장, 조명, 시간대는 RPG 모드와 Tile Rendering의 소유이며 두 보기에서 똑같이 작동합니다.
## 한계
- **키는 화면이 아니라 격자를 따릅니다.** 위·아래(W/S, 방향키)는 화면의 한 대각선을 따라, 왼쪽·오른쪽은 다른 대각선을 따라 움직입니다. 정사각형 격자에서 한 칸을 움직이기 때문입니다.
- **맵 가장자리가 드러납니다.** 맵 구석 근처에서는 마름모 경계 너머의 빈 배경이 보입니다. 위 사진과 같습니다.
- **타일셋을 준비해야 합니다.** 물체가 서 있는 것처럼 보이려면 타일셋이 그것들을 그룹으로 기술해야 합니다. 보통 타일은 마름모 위에 평평하게 놓입니다.
## 켜는 법
게임 구성(**모드 및 컬렉션 → 컬렉션 → 게임 → 구성 편집**)에 이 모드를 넣고 **지도 투영**을 **아이소메트릭**으로 정하세요. 설정 `tile.renderer`의 값은 `isometric`입니다.
```json
"settings": { "tile.renderer": "isometric" }
```
게임을 바꾸지 않고 한 번만 시도하려면 명령줄에서 `--tile-renderer=isometric`을 붙여 시작하세요. RPG Plus에는 두 렌더러가 이미 들어 있으므로 설정만 바꾸면 됩니다.
## 문제가 생겼을 때
1. **맵이 비어 있습니다.** 게임의 **지도 투영**이 포함되지 않은 렌더러를 요청합니다. 이 모드를 넣거나 다른 투영을 고르세요.
2. **주인공이 비스듬히 걷는다.** 이 보기에서는 키가 그렇게 작동합니다(한계 참조).
+37
View File
@@ -0,0 +1,37 @@
# Isometric Tiles — ромбовидный вид карты
Isometric Tiles рисует тайловые карты под углом, сеткой ромбов 2:1, так что дома и деревья поднимаются из земли. Это один из двух видов карты общего движка Tile Rendering; второй — Top-down Tiles. Те же карты, события и сохранения работают в обоих.
![Деревня RPG Plus в полдень в изометрии: площадь, фонари, дома, жители и герой на дорожке; за краем карты виден пустой фон.](assets/village-isometric.jpg)
## Чем изометрия отличается от вида сверху
- **Ромбовидные клетки.** Каждая клетка карты рисуется ромбом, вдвое более широким, чем высоким. Логическая сетка остаётся квадратной: у клетки те же четыре соседа, что и раньше.
- **Стоящие объекты.** Дома и другие много-клеточные объекты, которые тайлсет пометил особым образом, рисуются стоящими картинками или несколькими плоскими гранями — а не плоскими тайлами.
- **Персонажи** выбирают строку спрайта, отвечающую их направлению на ромбовидной сетке.
- **Щелчок** по карте выбирает ромб под указателем; редактор RPG-карт пользуется тем же правилом.
![Та же карта деревни в обоих видах: слева вид сверху, справа изометрия.](assets/same-map-two-projections.jpg)
Не меняется следующее: правила ходьбы, коллизии, события, бои, сохранения, освещение и время суток принадлежат моду RPG и Tile Rendering и ведут себя одинаково в обоих видах.
## Ограничения
- **Клавиши следуют за сеткой, а не за экраном.** Вверх и вниз (W/S, стрелки) двигают по одной диагонали экрана, влево и вправо — по другой: они смещают героя ровно на одну клетку квадратной сетки.
- **Края карты видны.** Возле угла карты виден пустой фон за пределами ромба — как на картинке выше.
- **Тайлсеты нужно готовить.** Объекты выглядят стоящими, только если тайлсет описывает их группами; обычные тайлы кладутся плашмя на ромбы.
## Как включить
В схеме игры (**Моды и коллекции → Коллекции → игра → Изменить схему**) подключите этот мод и установите **Проекцию карты** в **Изометрия**. Значение настройки `tile.renderer` — `isometric`:
```json
"settings": { "tile.renderer": "isometric" }
```
Чтобы попробовать один раз, не меняя игру, запустите её с ключом `--tile-renderer=isometric` в командной строке. RPG Plus уже включает оба рендерера, так что достаточно поменять настройку.
## Если что-то пошло не так
1. **Карта пуста.** **Проекция карты** игры просит рендерер, которого нет в составе; подключите этот мод или выберите другую проекцию.
2. **Герой ходит наискосок.** Так работают клавиши в этом виде (см. «Ограничения»).
+37
View File
@@ -0,0 +1,37 @@
# Isometric Tiles — chế độ xem ô hình thoi
Isometric Tiles vẽ các bản đồ ô ở một góc nghiêng, thành lưới hình thoi 2:1, khiến nhà cửa và cây cối đứng dậy khỏi mặt đất. Đây là một trong hai chế độ xem bản đồ của nền chung Tile Rendering; chế độ kia là Top-down Tiles. Cùng các bản đồ, sự kiện và save đều chạy ở cả hai.
![Làng RPG Plus lúc trưa trong chế độ đẳng cự: quảng trường, đèn đường, nhà cửa, dân làng và nhân vật chính trên con đường; ngoài rìa bản đồ là nền trống.](assets/village-isometric.jpg)
## Khác gì so với chế độ nhìn từ trên
- **Ô hình thoi.** Mỗi ô được vẽ thành hình thoi rộng gấp đôi chiều cao. Lưới logic vẫn vuông: một ô vẫn có bốn ô kề như trước.
- **Vật thể đứng.** Nhà cửa và các vật thể nhiều ô mà tileset đánh dấu sẽ được vẽ như tranh dựng đứng hoặc vài mặt phẳng, thay vì ô phẳng.
- **Nhân vật** chọn hàng sprite khớp với hướng của mình trên lưới hình thoi.
- **Nhấp chuột** vào bản đồ sẽ chọn hình thoi dưới con trỏ; trình sửa bản đồ RPG dùng cùng luật đó.
![Cùng bản đồ làng ở hai chế độ: nhìn từ trên bên trái, đẳng cự bên phải.](assets/same-map-two-projections.jpg)
Không đổi: luật đi lại, va chạm, sự kiện, chiến đấu, save, chiếu sáng và thời gian trong ngày thuộc về mod RPG và Tile Rendering, hoạt động y hệt ở cả hai chế độ.
## Giới hạn
- **Phím theo lưới, không theo màn hình.** Lên và xuống (W/S, mũi tên) đi theo một đường chéo của màn hình, trái và phải theo đường chéo kia, vì chúng dịch nhân vật đúng một ô trên lưới vuông.
- **Rìa bản đồ bị lộ.** Gần góc bản đồ, bạn thấy nền trống ngoài mép hình thoi, như trong hình trên.
- **Tileset phải được chuẩn bị.** Vật thể chỉ đứng thẳng khi tileset mô tả chúng thành nhóm; ô thường được đặt phẳng trên các hình thoi.
## Cách bật
Trong sơ đồ game (**Mod & Bộ sưu tập → Bộ sưu tập → game → Sửa sơ đồ**), đưa mod này vào và đặt **Phép chiếu bản đồ** thành **Đẳng cự**. Giá trị của cài đặt `tile.renderer` là `isometric`:
```json
"settings": { "tile.renderer": "isometric" }
```
Muốn thử một lần mà không đổi game, hãy khởi động với `--tile-renderer=isometric` trên dòng lệnh. RPG Plus đã có sẵn cả hai trình kết xuất, nên chỉ cần đổi cài đặt.
## Khi có trục trặc
1. **Bản đồ trống trơn.** **Phép chiếu bản đồ** của game yêu cầu một trình kết xuất không có trong game; hãy đưa mod này vào hoặc chọn phép chiếu khác.
2. **Nhân vật đi chéo.** Phím hoạt động như vậy trong chế độ này (xem Giới hạn).
+37
View File
@@ -0,0 +1,37 @@
# Isometric Tiles — 菱形地图视图
Isometric Tiles 以一定角度绘制图块地图,呈 2:1 的菱形网格,让建筑和树木从地面里"立"起来。它是共享引擎 Tile Rendering 的两种地图视图之一;另一种是 Top-down Tiles。同一批地图、事件和存档在两种视图下都能使用。
![等距视角下的正午 RPG Plus 村庄:广场、路灯、房屋、村民和走在小路上的主角;地图边缘之外是空的背景。](assets/village-isometric.jpg)
## 与俯视视图的不同
- **菱形格子。** 每格画成一个宽是高两倍的菱形。逻辑网格仍是方的:一格的四个邻居和原来相同。
- **立起来的物件。** 图块集标记出的建筑等多格物件,会画成竖立的图像或若干个平面,而不是平铺的图块。
- **角色**会根据自己在菱形网格上的朝向挑选对应的精灵行。
- **点击**地图时选中指针下的菱形;RPG 地图编辑器使用同样的规则。
![同一张村庄地图的两种视图:左边俯视,右边等距。](assets/same-map-two-projections.jpg)
不变的是:行走规则、碰撞、事件、战斗、存档、光照和昼夜都归 RPG 模组和 Tile Rendering 所有,在两种视图中的表现完全一致。
## 局限
- **按键跟随网格,而不是屏幕。** 上和下(W/S、方向键)沿屏幕的一条对角线移动,左和右沿另一条,因为它们是在方格网格上把主角移动一格。
- **地图边缘会露出来。** 靠近地图角落时,能看到菱形边界之外的空背景,如上图所示。
- **图块集需要预先准备。** 只有当图块集把物件描述成组合时,它们看起来才是立着的;普通图块平铺在菱形上。
## 如何启用
在游戏的方案(**模组与合集 → 合集 → 对应游戏 → 编辑结构**)中加入这个模组,并把**地图投影**设为**等距**。设置 `tile.renderer` 的值为 `isometric`:
```json
"settings": { "tile.renderer": "isometric" }
```
不想改游戏、只想试一次的话,在命令行用 `--tile-renderer=isometric` 启动。RPG Plus 已经包含两个渲染器,所以只需改设置。
## 如果遇到问题
1. **地图是空的。** 游戏的**地图投影**要求一个未包含的渲染器;请加入这个模组,或选择其他投影。
2. **主角斜着走。** 这种视图下按键就是这样工作的(见"局限")。
+1
View File
@@ -0,0 +1 @@
collection_settings/isometric = Isometric
+1
View File
@@ -0,0 +1 @@
collection_settings/isometric = Isométrica
+1
View File
@@ -0,0 +1 @@
collection_settings/isometric = アイソメトリック
+1
View File
@@ -0,0 +1 @@
collection_settings/isometric = 등각
+1
View File
@@ -0,0 +1 @@
collection_settings/isometric = Изометрия
+1
View File
@@ -0,0 +1 @@
collection_settings/isometric = Đẳng cự
+1
View File
@@ -0,0 +1 @@
collection_settings/isometric = 等距
+2
View File
@@ -0,0 +1,2 @@
mod_tile_isometric_base_name = Isometric Tiles
mod_tile_isometric_base_desc = Draws tile maps at an angle, a grid of 2:1 diamonds, so buildings and trees stand up out of the ground. One of the two views of Tile Rendering.
+2
View File
@@ -0,0 +1,2 @@
mod_tile_isometric_base_name=Casillas isométricas
mod_tile_isometric_base_desc=Dibuja los mapas de tiles en ángulo, como una cuadrícula de rombos 2:1, de modo que los edificios y los árboles se levantan del suelo. Una de las dos vistas de Tile Rendering.
+2
View File
@@ -0,0 +1,2 @@
mod_tile_isometric_base_name=アイソメトリックタイル
mod_tile_isometric_base_desc=タイルマップを 2:1 のひし形の格子で斜めから描き、建物や木を地面から立ち上がらせます。Tile Rendering の 2 つのビューの 1 つです。
+2
View File
@@ -0,0 +1,2 @@
mod_tile_isometric_base_name=아이소메트릭 타일
mod_tile_isometric_base_desc=타일 맵을 2:1 마름모 격자로 비스듬히 그려서 건물과 나무가 땅에서 솟아 보이게 합니다. Tile Rendering의 두 보기 중 하나입니다.
+2
View File
@@ -0,0 +1,2 @@
mod_tile_isometric_base_name=Изометрические тайлы
mod_tile_isometric_base_desc=Рисует тайловые карты под углом, сеткой ромбов 2:1, так что дома и деревья поднимаются из земли. Один из двух видов Tile Rendering.
+2
View File
@@ -0,0 +1,2 @@
mod_tile_isometric_base_name=Ô đẳng cự
mod_tile_isometric_base_desc=Vẽ các bản đồ ô ở một góc nghiêng, thành lưới hình thoi 2:1, khiến nhà cửa và cây cối đứng dậy khỏi mặt đất. Một trong hai chế độ xem của Tile Rendering.
+2
View File
@@ -0,0 +1,2 @@
mod_tile_isometric_base_name=等距图块
mod_tile_isometric_base_desc=以一定角度绘制图块地图,呈 2:1 的菱形网格,让建筑和树木从地面里立起来。Tile Rendering 的两种视图之一。
+17
View File
@@ -0,0 +1,17 @@
{
"id": "tile_isometric_base",
"name": "Isometric Tiles",
"version": "1.0.0",
"author": "ct",
"description": "Draws tile maps at an angle, a grid of 2:1 diamonds, so buildings and trees stand up out of the ground. One of the two views of Tile Rendering.",
"category": "visual, engine",
"sources": [
"src/**/*.cs"
],
"test_sources": [
"tests/*.cs"
],
"depends": [
"tile_render_base>=1"
]
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

+11
View File
@@ -0,0 +1,11 @@
namespace Cthangover.Mods.TileIsometric
{
using Cthangover.Mods.TileRender;
/// <summary>Textured ground polygons and upright whole-object sprites share the same source atlases.</summary>
public class IsometricRendererFactory : ITileRendererFactory
{
public string Id => "isometric";
public ITileProjection Projection(int size) => new IsometricTileProjection(size);
public ITileWorldPresentation Create() => new TileCanvasPresentation(this);
}
}
+32
View File
@@ -0,0 +1,32 @@
namespace Cthangover.Mods.TileIsometric
{
using Cthangover.Mods.TileRender;
using Godot;
/// <summary>2:1 diamond projection. Triangles are drawing geometry; the logical four-neighbour grid stays square.</summary>
public class IsometricTileProjection : ITileProjection
{
public float Unit { get; }
public IsometricTileProjection(int size) { Unit = size > 0 ? size : throw new System.ArgumentOutOfRangeException(nameof(size)); }
public Vector2 Project(Vector3 p) => new((p.X - p.Y) * Unit, (p.X + p.Y) * Unit * 0.5f - p.Z * Unit);
public Vector2 Unproject(Vector2 p) => new((p.X * 0.5f + p.Y) / Unit, (p.Y - p.X * 0.5f) / Unit);
public int CharsetRow(int facing) => facing switch { 0 => 1, 1 => 3, 2 => 0, _ => 2 };
public TileVisualPlacement Place(TileVisual visual)
{
var anchor = TileDrawing.Project(this, visual.Anchor);
if (visual.WorldQuad is { Length: 4 })
{
var points = new Vector2[4];
for (var i = 0; i < 4; i++) points[i] = Project(visual.WorldQuad[i]);
return TileVisualPlacement.FromQuad(points, anchor, visual.Upright);
}
if (visual.Upright)
{
var rect = new Rect2(anchor + (visual.Bounds.Position - visual.Anchor) * Unit, visual.Bounds.Size * Unit);
var points = new[] { rect.Position, rect.Position + new Vector2(rect.Size.X, 0), rect.End,
rect.Position + new Vector2(0, rect.Size.Y) };
return TileVisualPlacement.FromQuad(points, anchor, true);
}
return TileVisualPlacement.FromQuad(TileDrawing.CellPolygon(this, visual.Bounds), anchor, false);
}
}
}
+27
View File
@@ -0,0 +1,27 @@
namespace Cthangover.Mods.TileIsometric.Tests
{
using Cthangover.Core.Mods.Testing;
using Godot;
/// <summary>Ground projection is invertible in every quadrant, before rounding to cells.</summary>
public class ProjectionTests
{
[ModTest("projection/ground_roundtrip_and_elevation")]
static void GroundRoundtrip(ModTestContext ctx)
{
var projection = new IsometricTileProjection(32);
for (var y = -4; y <= 4; y++)
for (var x = -4; x <= 4; x++)
{
var point = new Vector2(x + 0.25f, y + 0.75f);
var pixel = projection.Project(new Vector3(point.X, point.Y, 0));
ModAssert.True(projection.Unproject(pixel).IsEqualApprox(point), "ground inverse including negative coordinates");
}
var ground = projection.Project(new Vector3(2, 3, 0));
var above = projection.Project(new Vector3(2, 3, 1));
ModAssert.CloseTo(32, ground.Y - above.Y, what: "one cell elevation");
ModAssert.CloseTo(32, projection.Unit, what: "projection pixel scale");
for (var direction = 0; direction < 4; direction++)
ModAssert.True(projection.CharsetRow(direction) >= 0 && projection.CharsetRow(direction) < 4, "valid facing row");
}
}
}