Unity记录5.6-地图-天空地面及地底的地形
汇总:Unity 记录
摘要:天空,平原,地底的不同地形的生成。
地形-2023/9/11
- 这部分代码断断续续写了好几天,不好计时,所以只标记最后的时间。
- 三类测试地形,天空,平原,矿洞。
- 地形有生成区域判断。
- 地形周围,同类地形生成概率增加。
- 地形的地势走向具有独特性。例如平原,绝大部分是东西走向,极小几率生成其它走向,并且没有悬空地形。
- 地形决定了当前的主要方块是哪些。
- 目前的判断条件
- 生成高度影响当前地形。
- 周围地形影响当前地形。
- 当前地形决定当前地势。
- 周围地势影响当前地势。
- 当前地形决定当前的方块。
实现代码-2023/9/11
- 核心部分,还有一个影响部分是direction的地势走向,但不重要。
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using MathNet.Numerics.LinearAlgebra;
/*
* ---------- type of terrain ----------
* ---------- direction fluctuation
* flat: 2
* undulating: 1 3 7 9
* steep: 4 6 14 16
* suspended: 11 12 13 17 19
* full: 5
* empty: 0
* ---------- ground
* | tag | flat | undulating | steep | suspended | full | empty |
* |------------|--------|--------------|---------|-------------|--------|---------|
* | flat | most | few | no | no | some | no |
* | undulating | some | some | few | no | some | no |
* | steep | some | some | some | few | some | no |
* | suspended | few | some | some | some | some | no |
*
* ---------- underground
* | tag | flat | undulating | steep | suspended | full | empty |
* |------------|--------|--------------|---------|-------------|--------|---------|
* | spacious | most | few | some | few | few | some |
* | roomy | some | some | some | some | some | some |
* | narrow | few | some | few | some | most | few |
*
* ---------- sky
* | tag | flat | undulating | steep | suspended | full | empty |
* |------------|--------|--------------|---------|-------------|--------|---------|
* | sky | no | no | no | no | no | most |
*
*/
public struct TerrainType{
public string[] tags;
public string name;
public float scale;
public string[] dirs_avail; // available directions
public float[] dirs_prob; // probability of each available directions
}
public struct TerrainInfo{
public string ID;
public string name;
public string[] tags;
public int[] h_avail; // where can it generating, height means block offset, left close right open interval
public string tile_surface; // ID, surface tile
public string tile_transition; // ID, transition from terr1 to terr2, trans_tile is the surface_tile of terr2
public string[] tiles_mineral; // ID, which mineral can be generated
}
public class TilemapTerrain{
List<TerrainType> _terrains_type = new();
List<TerrainInfo> _terrains_info = new();
public Dictionary<string, TerrainInfo> ID2TerrainInfo = new();
public Dictionary<string[], TerrainType> tags2TerrainType = new();
public TilemapTerrain() {
_init_terrainsType();
_init_terrainsInfo();
_init_ID2TerrainInfo();
_init_tags2TerrainType();
}
public TilemapBlock set_terrain_random(TilemapBlock block, TilemapAroundBlock around_blocks){
List<string> terrains_avail = _get_available_terrains(block);
float[] terrains_prob = _get_terrains_prob(terrains_avail, around_blocks);
string terrain_ID = terrains_avail[_random_by_prob(terrains_prob)];
block.terrain_ID = terrain_ID;
return block;
}
public TilemapBlock set_terrainType_random(TilemapBlock block, TilemapAroundBlock around_blocks){
List<TerrainType> terrainTypes_avail = _get_available_terrainTypes(block.terrain_ID);
float[] terrainTypes_prob = _get_terrainTypes_prob(terrainTypes_avail, around_blocks);
string[] terrainTypes_tags = terrainTypes_avail[_random_by_prob(terrainTypes_prob)].tags;
block.terrainType_tags = terrainTypes_tags;
return block;
}
List<TerrainType> _get_available_terrainTypes(string terrain_ID){
TerrainInfo terrain = ID2TerrainInfo[terrain_ID];
List<TerrainType> types = new();
for (int i = 0; i < _terrains_type.Count; i++){
if (_check_tagsIsSubset(terrain.tags, _terrains_type[i].tags))
types.Add(_terrains_type[i]);
}
return types;
}
float[] _get_terrainTypes_prob(List<TerrainType> types, TilemapAroundBlock around_blocks){
// init
float[] probs = new float[types.Count];
for(int i = 0; i < types.Count; i++){
probs[i] = 1;
// increase the prob of exist tags
if(around_blocks.up.isExist && _check_tagsIsSubset(around_blocks.up.terrainType_tags, types[i].tags)) probs[i] += types.Count;
if(around_blocks.down.isExist && _check_tagsIsSubset(around_blocks.down.terrainType_tags, types[i].tags)) probs[i] += types.Count;
if(around_blocks.left.isExist && _check_tagsIsSubset(around_blocks.left.terrainType_tags, types[i].tags)) probs[i] += types.Count;
if(around_blocks.right.isExist && _check_tagsIsSubset(around_blocks.right.terrainType_tags, types[i].tags)) probs[i] += types.Count;
}
return probs;
}
bool _check_tagsIsSubset(string[] tags_sub, string[] tags_super){
return tags_sub.All(item => tags_super.Contains(item));
}
bool _check_terrainAvailable(TilemapBlock block, TerrainInfo terrain){
// height condition
if (block.offsets.y < terrain.h_avail[0] && terrain.h_avail[0] != -999999999) return false;
if (block.offsets.y >= terrain.h_avail[1] && terrain.h_avail[1] != 999999999) return false;
// all pass
return true;
}
List<string> _get_available_terrains(TilemapBlock block){
List<string> availables = new ();
for(int i = 0; i < _terrains_info.Count; i++)
if (_check_terrainAvailable(block, _terrains_info[i]))
availables.Add(_terrains_info[i].ID);
return availables;
}
float[] _get_terrains_prob(List<string> terrains, TilemapAroundBlock around_blocks){
// init
float[] probs = new float[terrains.Count];
for(int i = 0; i < terrains.Count; i++){
probs[i] = 1;
// increase the prob of exist terrain
if(around_blocks.up.isExist && terrains[i]==around_blocks.up.terrain_ID) probs[i] += terrains.Count;
if(around_blocks.down.isExist && terrains[i]==around_blocks.down.terrain_ID) probs[i] += terrains.Count;
if(around_blocks.left.isExist && terrains[i]==around_blocks.left.terrain_ID) probs[i] += terrains.Count;
if(around_blocks.right.isExist && terrains[i]==around_blocks.right.terrain_ID) probs[i] += terrains.Count;
}
return probs;
}
// ---------- other ----------
int _random_by_prob(float[] probs){
float sum = probs.Sum();
float target = Random.Range(0f, sum);
for(int i = 0; i < probs.Length; i++){
target -= probs[i];
if(target <= 0) return i;
}
return probs.Length - 1;
}
// ---------- init ----------
void _init_ID2TerrainInfo(){
for(int i = 0; i < _terrains_info.Count; i++){
ID2TerrainInfo.Add(_terrains_info[i].ID, _terrains_info[i]);
}
}
void _init_tags2TerrainType(){
for(int i = 0; i < _terrains_type.Count; i++){
tags2TerrainType.Add(_terrains_type[i].tags, _terrains_type[i]);
}
}
void _init_terrainsInfo(){
_terrains_info.Add(new TerrainInfo{
ID = "0", name = "plain", tags = new string[]{"flat", "ground"},
h_avail = new int[]{-999999999, 999999999},
tile_surface = "1",
});
_terrains_info.Add(new TerrainInfo{
ID = "1", name = "sky", tags = new string[]{"sky"},
h_avail = new int[]{-999999999, 999999999},
tile_surface = "0",
});
_terrains_info.Add(new TerrainInfo{
ID = "2", name = "underground gravel", tags = new string[]{"underground"},
h_avail = new int[]{-999999999, 999999999},
tile_surface = "3",
});
}
void _init_terrainsType(){
_terrains_type.Add(new TerrainType {
tags = new string[] {"flat", "ground"},
name = "flat ground", scale = 1f,
dirs_avail = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "9", "11", "12", "13", "14", "16", "17", "19" },
dirs_prob = new float[] { 0.1f, 1, 50, 1, 0.1f, 5, 0.1f, 1, 1, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f},
});
_terrains_type.Add(new TerrainType {
tags = new string[] {"undulating", "ground"},
name = "undulating ground", scale = 2f,
dirs_avail = new string[] {"0", "1", "2", "3", "4", "5", "6", "7", "9", "11", "12", "13", "14", "16", "17", "19" },
dirs_prob = new float[] {0.1f, 10, 10, 10, 1, 10, 1, 10, 10, 0.1f, 0.1f, 0.1f, 1, 1, 0.1f, 0.1f },
});
_terrains_type.Add(new TerrainType {
tags = new string[] {"steep", "ground"},
name = "steep ground", scale = 4f,
dirs_avail = new string[] {"0", "1", "2", "3", "4", "5", "6", "7", "9", "11", "12", "13", "14", "16", "17", "19" },
dirs_prob = new float[] {0.1f, 10, 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, 10, 10, 1, 1 },
});
_terrains_type.Add(new TerrainType {
tags = new string[] {"suspended", "ground"},
name = "suspended ground", scale = 8f,
dirs_avail = new string[] {"0", "1", "2", "3", "4", "5", "6", "7", "9", "11", "12", "13", "14", "16", "17", "19" },
dirs_prob = new float[] {0.1f, 10, 1, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 },
});
_terrains_type.Add(new TerrainType {
tags = new string[] {"spacious", "underground"},
name = "spacious underground",
dirs_avail = new string[] {"0", "1", "2", "3", "4", "5", "6", "7", "9", "11", "12", "13", "14", "16", "17", "19" },
dirs_prob = new float[] { 10, 1, 50, 1, 10, 1, 10, 1, 1, 1, 1, 1, 10, 10, 1, 1 },
});
_terrains_type.Add(new TerrainType {
tags = new string[] {"roomy", "underground"},
name = "roomy underground",
dirs_avail = new string[] {"0", "1", "2", "3", "4", "5", "6", "7", "9", "11", "12", "13", "14", "16", "17", "19" },
dirs_prob = new float[] { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 },
});
_terrains_type.Add(new TerrainType {
tags = new string[] {"narrow", "underground"},
name = "narrow underground",
dirs_avail = new string[] {"0", "1", "2", "3", "4", "5", "6", "7", "9", "11", "12", "13", "14", "16", "17", "19" },
dirs_prob = new float[] { 1, 10, 1, 10, 1, 50, 1, 10, 10, 10, 10, 10, 1, 1, 10, 10 },
});
_terrains_type.Add(new TerrainType {
tags = new string[] {"sky"},
name = "sky", scale = 1f,
dirs_avail = new string[] {"0", "1", "2", "3", "4", "5", "6", "7", "9", "11", "12", "13", "14", "16", "17", "19"},
dirs_prob = new float[] {50, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f},
});
}
}
文章目录
关闭
共有 0 条评论