无论是在迷宫还是类似于地牢的游戏地图中,利用程序来生成每次都不一样的地图是一件叫人兴奋不已的事。

这时我们需要解决两个非常重要的随机事件:

1.在一定范围内随机出各不相同但又不能互相重叠的房间

2.优美生成连接这些房间的通道

基本的UML思路图:

这次我们先讨论如何快速生成符合各种随机要求的房间。

一般来说,一个房间的高度是一个相对固定的值,可以根据面板上的参数进行必要的调整,而真正参与随机的应该是房间的长,宽和位置。

建立房间的数据结构,根据需求可以随时补充和添加:

 using System.Collections.Generic;
using UnityEngine; public class RoomData
{
public int Id;
//房间的Transform等属性
public RoomTran RoomTran;
//该房间的战斗类型
public RoomBattleType BattleType;
//该房间与哪些其余房间互相连接
public List<RoomData> CrossRooms;
//房间内的怪物列表
public List<GameObject> Monsters;
//是否是端点房间
public bool bEndRoom;
//是否是主路径房间
public bool bMainCrossRoom;
} public class RoomTran
{
public int Length;
public int Width;
//长宽中心点
public Vector2Int CenterPos;
//高度位置
public float PosY;
} public enum RoomBattleType
{
Rest,
NormalBattle,
BossBattle
}

RoonBuilder属性和控制参数:

     //建筑单位方块
public GameObject BuildUnit; //房间高度值
public int FixedUnitHeight;
//生成的房间层数
public int LayerCount;
//长宽随机范围
public Vector2Int GenRange; //随机类型
public RoomRandType RandType;
//随机的房间形状类型
public RoomShapeType Shape; //房间大小的随机列表,用于枚举随机
public List<Vector2Int> RoomRandSizes = new List<Vector2Int>(); //随机的房间最大面积
public int MaxRoomArea;
//最大随机数量(随机试验次数)
public int MaxRoomCount; //最小边长度
private int MinRoomEdge;
//最大长宽比
public int MaxLengthWidthScale = ; //标准方向
Vector3Int Dx = new Vector3Int(, , );
Vector3Int Dy = new Vector3Int(, , );
Vector3Int Dz = new Vector3Int(, , ); //建筑单位标签
const string S_TAG = "Unit"; private MapSystem MapManager;

单房间轮廓生成:

     /// <summary>
/// 生成单一房间的轮廓
/// </summary>
/// <param name="centerPos">房间中点位置</param>
/// <param name="length">长</param>
/// <param name="width">宽</param>
/// <param name="parent">父物体</param>
void GenOneRoom(Vector3 centerPos, int length, int width, Transform parent = null)
{
var to = new Vector3(length - , FixedUnitHeight - , width - ) * .5f; //顶点
var ned = centerPos - to;
var fod = centerPos + to; var v3 = new Vector3(ned.x, fod.y, ned.z);
var v4 = new Vector3(ned.x, fod.y, fod.z);
var v5 = new Vector3(ned.x, ned.y, fod.z); var v6 = new Vector3(fod.x, ned.y, ned.z);
var v7 = new Vector3(fod.x, ned.y, fod.z);
var v8 = new Vector3(fod.x, fod.y, ned.z); //顶点位置(8个)
InsSetPos(ned, parent);
InsSetPos(fod, parent);
InsSetPos(v3, parent);
InsSetPos(v4, parent);
InsSetPos(v5, parent);
InsSetPos(v6, parent);
InsSetPos(v7, parent);
InsSetPos(v8, parent); //12条棱(4*3)
//长
InsOneEdge(length, ned, Dx, parent);
InsOneEdge(length, v3, Dx, parent);
InsOneEdge(length, v4, Dx, parent);
InsOneEdge(length, v5, Dx, parent);
//高
InsOneEdge(FixedUnitHeight, ned, Dy, parent);
InsOneEdge(FixedUnitHeight, v5, Dy, parent);
InsOneEdge(FixedUnitHeight, v6, Dy, parent);
InsOneEdge(FixedUnitHeight, v7, Dy, parent);
//宽
InsOneEdge(width, ned, Dz, parent);
InsOneEdge(width, v3, Dz, parent);
InsOneEdge(width, v6, Dz, parent);
InsOneEdge(width, v8, Dz, parent);
} //生成一条边上的建筑单位但不包含顶点位置
void InsOneEdge(int edge, Vector3 v, Vector3 dir, Transform parent = null)
{
//忽略首尾单位
for (int i = ; i < edge - ; i++)
{
InsSetPos(v + i * dir, parent);
}
} void InsSetPos(Vector3 pos, Transform parent = null)
{
var ins = Instantiate(BuildUnit);
ins.transform.position = pos;
ins.transform.parent = parent;
}

这里唯一值得注意的地方是房间顶点位置的单位不要重复生成。(因为想偷懒的话真的很容易重复Orz)。

随机RoomTran结构:

     RoomTran RanRoomTran(Vector3 centerPos)
{
var rt = new RoomTran(); switch (RandType)
{
case RoomRandType.AllRand:
int temp;
var oe = MaxRoomArea / MinRoomEdge;
switch (Shape)
{
case RoomShapeType.LengthMain:
rt.Length = Random.Range(MinRoomEdge + , oe + );
temp = MaxRoomArea / rt.Length;
if (temp >= rt.Length)
rt.Width = Random.Range(MinRoomEdge, rt.Length);
else
rt.Width = Random.Range(MinRoomEdge, temp + );
break;
case RoomShapeType.WidthMain:
rt.Width = Random.Range(MinRoomEdge + , oe + );
temp = MaxRoomArea / rt.Width;
if (temp >= rt.Width)
rt.Length = Random.Range(MinRoomEdge, rt.Width);
else
rt.Length = Random.Range(MinRoomEdge, temp + );
break;
case RoomShapeType.Coustom:
rt.Length = Random.Range(MinRoomEdge, oe + );
temp = MaxRoomArea / rt.Length;
rt.Width = Random.Range(MinRoomEdge, temp + );
break;
}
break;
case RoomRandType.EnumRand:
var rc = RoomRandSizes.Count;
if (rc == )
{
//未填写时设定随机默认值
rt.Length = ;
rt.Width = ;
}
else
{
var ridx = Random.Range(,rc);
var t = RoomRandSizes[ridx];
if (t.x < || t.y < )
{
//填写错误时设定随机默认值
rt.Length = ;
rt.Width = ;
}
else
{
switch (Shape)
{
case RoomShapeType.LengthMain:
rt.Length = t.x > t.y ? t.x : t.y;
rt.Width = t.x < t.y ? t.x : t.y;
break;
case RoomShapeType.WidthMain:
rt.Width = t.x > t.y ? t.x : t.y;
rt.Length = t.x < t.y ? t.x : t.y;
break;
case RoomShapeType.Coustom:
rt.Length = Random.value < .5f ? t.x : t.y;
rt.Width = t.y == rt.Length ? t.x : t.y;
break;
}
}
}
break;
} rt.CenterPos = new Vector2Int(Random.Range((int)(centerPos.x - GenRange.x * .5f), (int)(centerPos.x + GenRange.x * .5f)),
Random.Range((int)(centerPos.z - GenRange.y * .5f), (int)(centerPos.z + GenRange.y * .5f))); rt.PosY = centerPos.y; var roomCenter = new Vector3(rt.CenterPos.x, rt.PosY, rt.CenterPos.y); //射线检测重叠
if (RayRoomCheck(roomCenter, rt.Length, rt.Width))
{
return null;
}
return rt;
}

用的是射线检测重叠,生成了重叠的房间就会被视作是一次失败的随机试验,之前尝试过直接用物理系统推开失败了,可能是使用有误,如果有知道原因的欢迎与笔者分享,共同进步;

当然了,你也可以用Unity自带的Bounds.Intersects(Bounds other)方法来判断两个生成的房间盒子是否重叠,但缺点是没有办法控制两个房间边缘的间隔的最小距离,用纯粹的数学方法判断三个轴向的边缘值大小同样也是可行的:

     //生成房间前射线检测下范围内有无其他房间
bool RayRoomCheck(Vector3 cp, int length, int width)
{
bool result = false;
//长宽至少留一格间隙,高度与地板格对齐
var to = new Vector3(length + , FixedUnitHeight - , width + ) * .5f;
var ned = cp - to; var vx2 = ned + new Vector3(, , width + ) * .5f;
var vx3 = ned + new Vector3(, , width + ); var vx4 = ned + new Vector3(length + , , width * .5f + .5f);
var vx5 = ned + new Vector3(length + , , width + ); var vz2 = ned + new Vector3(length + , , ) * .5f;
var vz3 = ned + new Vector3(length + , , ); var vz4 = ned + new Vector3(length * .5f + .5f, , width + );
var vz5 = ned + new Vector3(length + , , width + ); result =
//4组射线,每组3条
RayCast(ned, Dx, length + , S_TAG) ||
RayCast(vx2, Dx, length + , S_TAG) ||
RayCast(vx3, Dx, length + , S_TAG) || RayCast(vx4, Dx * -, length + , S_TAG) ||
RayCast(vx5, Dx * -, length + , S_TAG) ||
RayCast(vz3, Dx * -, length + , S_TAG) || RayCast(ned, Dz, width + , S_TAG) ||
RayCast(vz2, Dz, width + , S_TAG) ||
RayCast(vz3, Dz, width + , S_TAG) || RayCast(vz4, Dz * -, width + , S_TAG) ||
RayCast(vz5, Dz * -, width + , S_TAG) ||
RayCast(vx3, Dz * -, width + , S_TAG); return result;
}

这里将射线的起点和终点都延长了一格,是为了避免两个生成的房间贴得太紧,这样至少每个房间与其它房间间隔一个单位格或以上。

完整的房间结构生成脚本:

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events; public enum RoomRandType
{
//全随机
AllRand,
//枚举大小随机
EnumRand
} public enum RoomShapeType
{
//宽>=长
WidthMain,
//长>=宽
LengthMain,
//自定义,无形状要求
Coustom
}
//x-length z-width y-height public class RoomBuilder : MonoBehaviour
{
//建筑单位方块
public GameObject BuildUnit; //房间高度值
public int FixedUnitHeight;
//生成的房间层数
public int LayerCount;
//长宽随机范围
public Vector2Int GenRange; //随机类型
public RoomRandType RandType;
//随机的房间形状类型
public RoomShapeType Shape; //房间大小的随机列表,用于枚举随机
public List<Vector2Int> RoomRandSizes = new List<Vector2Int>(); //随机的房间最大面积
public int MaxRoomArea;
//最大随机数量(随机试验次数)
public int MaxRoomCount; //最小边长度
private int MinRoomEdge;
//最大长宽比
public int MaxLengthWidthScale = ; //标准方向
Vector3Int Dx = new Vector3Int(, , );
Vector3Int Dy = new Vector3Int(, , );
Vector3Int Dz = new Vector3Int(, , ); //建筑单位标签
const string S_TAG = "Unit"; private MapSystem MapManager; void Awake()
{
MapManager = GetComponent<MapSystem>();
} public IEnumerator GenRooms(Vector3Int centerPos,UnityAction complete)
{
var temp = (int)Mathf.Sqrt(MaxRoomArea * 1.0f / MaxLengthWidthScale);
MinRoomEdge = temp > ? temp : ; //每层至少1
for (int i = ; i <= LayerCount; i++)
{
SetGenOneRoom(centerPos, i);
yield return new WaitForSeconds(.1f);
} //超过的随机布置
var oc = MaxRoomCount - LayerCount;
if (oc > )
{
for (int i = ; i <= oc; i++)
{
var r = Random.Range(, LayerCount + );
SetGenOneRoom(centerPos, r);
yield return new WaitForSeconds(.1f);
}
} //所有房间生成完成后发送一个委托信号,以便后续创建房间数据和计算必要连接
complete();
} void SetGenOneRoom(Vector3Int cp, int r)
{
var layerCenter = cp - new Vector3(, (LayerCount - * r + ) * .5f * FixedUnitHeight, ); var rt = RanRoomTran(layerCenter);
if (rt != null)
{
var roomCenter = new Vector3(rt.CenterPos.x, rt.PosY, rt.CenterPos.y); GameObject temp = new GameObject(r.ToString());
temp.transform.position = roomCenter;
temp.tag = S_TAG; //给生成的房间添加碰撞盒子并设置大小
GenOneRoom(roomCenter, rt.Length, rt.Width, temp.transform);
var bc = temp.AddComponent<BoxCollider>();
bc.size = new Vector3(rt.Length, FixedUnitHeight, rt.Width); //目前用物理方式似乎难以推开重叠的房间,可能是哪里使用方法有误,改为用用射线检测解决...
//var rb = temp.AddComponent<Rigidbody>();
//rb.useGravity = false;
//rb.drag = Mathf.Infinity;
//rb.constraints = RigidbodyConstraints.FreezePositionY;
//rb.freezeRotation = true; //将房间数据存入临时列表
MapManager.GenRooms.Add(rt);
MapManager.UnCrossRooms.Add(rt);
}
} RoomTran RanRoomTran(Vector3 centerPos)
{
var rt = new RoomTran(); switch (RandType)
{
case RoomRandType.AllRand:
int temp;
var oe = MaxRoomArea / MinRoomEdge;
switch (Shape)
{
case RoomShapeType.LengthMain:
rt.Length = Random.Range(MinRoomEdge + , oe + );
temp = MaxRoomArea / rt.Length;
if (temp >= rt.Length)
rt.Width = Random.Range(MinRoomEdge, rt.Length);
else
rt.Width = Random.Range(MinRoomEdge, temp + );
break;
case RoomShapeType.WidthMain:
rt.Width = Random.Range(MinRoomEdge + , oe + );
temp = MaxRoomArea / rt.Width;
if (temp >= rt.Width)
rt.Length = Random.Range(MinRoomEdge, rt.Width);
else
rt.Length = Random.Range(MinRoomEdge, temp + );
break;
case RoomShapeType.Coustom:
rt.Length = Random.Range(MinRoomEdge, oe + );
temp = MaxRoomArea / rt.Length;
rt.Width = Random.Range(MinRoomEdge, temp + );
break;
}
break;
case RoomRandType.EnumRand:
var rc = RoomRandSizes.Count;
if (rc == )
{
//未填写时设定随机默认值
rt.Length = ;
rt.Width = ;
}
else
{
var ridx = Random.Range(,rc);
var t = RoomRandSizes[ridx];
if (t.x < || t.y < )
{
//填写错误时设定随机默认值
rt.Length = ;
rt.Width = ;
}
else
{
switch (Shape)
{
case RoomShapeType.LengthMain:
rt.Length = t.x > t.y ? t.x : t.y;
rt.Width = t.x < t.y ? t.x : t.y;
break;
case RoomShapeType.WidthMain:
rt.Width = t.x > t.y ? t.x : t.y;
rt.Length = t.x < t.y ? t.x : t.y;
break;
case RoomShapeType.Coustom:
rt.Length = Random.value < .5f ? t.x : t.y;
rt.Width = t.y == rt.Length ? t.x : t.y;
break;
}
}
}
break;
} rt.CenterPos = new Vector2Int(Random.Range((int)(centerPos.x - GenRange.x * .5f), (int)(centerPos.x + GenRange.x * .5f)),
Random.Range((int)(centerPos.z - GenRange.y * .5f), (int)(centerPos.z + GenRange.y * .5f))); rt.PosY = centerPos.y; var roomCenter = new Vector3(rt.CenterPos.x, rt.PosY, rt.CenterPos.y); //射线检测重叠
if (RayRoomCheck(roomCenter, rt.Length, rt.Width))
{
return null;
}
return rt;
} //生成房间前射线检测下范围内有无其他房间
bool RayRoomCheck(Vector3 cp, int length, int width)
{
bool result = false;
//长宽至少留一格间隙,高度与地板格对齐
var to = new Vector3(length + , FixedUnitHeight - , width + ) * .5f;
var ned = cp - to; var vx2 = ned + new Vector3(, , width + ) * .5f;
var vx3 = ned + new Vector3(, , width + ); var vx4 = ned + new Vector3(length + , , width * .5f + .5f);
var vx5 = ned + new Vector3(length + , , width + ); var vz2 = ned + new Vector3(length + , , ) * .5f;
var vz3 = ned + new Vector3(length + , , ); var vz4 = ned + new Vector3(length * .5f + .5f, , width + );
var vz5 = ned + new Vector3(length + , , width + ); result =
//4组射线,每组3条
RayCast(ned, Dx, length + , S_TAG) ||
RayCast(vx2, Dx, length + , S_TAG) ||
RayCast(vx3, Dx, length + , S_TAG) || RayCast(vx4, Dx * -, length + , S_TAG) ||
RayCast(vx5, Dx * -, length + , S_TAG) ||
RayCast(vz3, Dx * -, length + , S_TAG) || RayCast(ned, Dz, width + , S_TAG) ||
RayCast(vz2, Dz, width + , S_TAG) ||
RayCast(vz3, Dz, width + , S_TAG) || RayCast(vz4, Dz * -, width + , S_TAG) ||
RayCast(vz5, Dz * -, width + , S_TAG) ||
RayCast(vx3, Dz * -, width + , S_TAG); return result;
} bool RayCast(Vector3 ori, Vector3 dir, float mD, string tag)
{
Ray ray = new Ray(ori, dir);
RaycastHit info;
if (Physics.Raycast(ray, out info, mD))
{
if (info.transform.tag == tag)
return true;
}
return false;
} /// <summary>
/// 生成单一房间的轮廓
/// </summary>
/// <param name="centerPos">房间中点位置</param>
/// <param name="length">长</param>
/// <param name="width">宽</param>
/// <param name="parent">父物体</param>
void GenOneRoom(Vector3 centerPos, int length, int width, Transform parent = null)
{
var to = new Vector3(length - , FixedUnitHeight - , width - ) * .5f; //顶点
var ned = centerPos - to;
var fod = centerPos + to; var v3 = new Vector3(ned.x, fod.y, ned.z);
var v4 = new Vector3(ned.x, fod.y, fod.z);
var v5 = new Vector3(ned.x, ned.y, fod.z); var v6 = new Vector3(fod.x, ned.y, ned.z);
var v7 = new Vector3(fod.x, ned.y, fod.z);
var v8 = new Vector3(fod.x, fod.y, ned.z); //顶点位置(8个)
InsSetPos(ned, parent);
InsSetPos(fod, parent);
InsSetPos(v3, parent);
InsSetPos(v4, parent);
InsSetPos(v5, parent);
InsSetPos(v6, parent);
InsSetPos(v7, parent);
InsSetPos(v8, parent); //12条棱(4*3)
//长
InsOneEdge(length, ned, Dx, parent);
InsOneEdge(length, v3, Dx, parent);
InsOneEdge(length, v4, Dx, parent);
InsOneEdge(length, v5, Dx, parent);
//高
InsOneEdge(FixedUnitHeight, ned, Dy, parent);
InsOneEdge(FixedUnitHeight, v5, Dy, parent);
InsOneEdge(FixedUnitHeight, v6, Dy, parent);
InsOneEdge(FixedUnitHeight, v7, Dy, parent);
//宽
InsOneEdge(width, ned, Dz, parent);
InsOneEdge(width, v3, Dz, parent);
InsOneEdge(width, v6, Dz, parent);
InsOneEdge(width, v8, Dz, parent);
} //生成一条边上的建筑单位但不包含顶点位置
void InsOneEdge(int edge, Vector3 v, Vector3 dir, Transform parent = null)
{
//忽略首尾单位
for (int i = ; i < edge - ; i++)
{
InsSetPos(v + i * dir, parent);
}
} void InsSetPos(Vector3 pos, Transform parent = null)
{
var ins = Instantiate(BuildUnit);
ins.transform.position = pos;
ins.transform.parent = parent;
}
}

在MapSystem中可以在房间结构生成完后创建一个默认的数据结构:

     public void RandRoomDatas()
{
if (RoomBuilder == null||MapData ==null)
return; RoomBuilder.StartCoroutine(RoomBuilder.GenRooms(MapData.MapCenter,()=>
{
CreatRoomData();
RandRoomCrosses();
}));
} void CreatRoomData()
{
for (int i = ; i < GenRooms.Count + ; i++)
{
var rd = new RoomData();
rd.Id = i;
rd.RoomTran = GenRooms[i - ];
rd.BattleType = RoomBattleType.NormalBattle;
if (rd.Id == )
rd.BattleType = RoomBattleType.Rest;
rd.CrossRooms = new List<RoomData>();
rd.Monsters = new List<GameObject>();
rd.bEndRoom = false;
rd.bMainCrossRoom = false; MapData.RoomDataDic.Add(rd.Id, rd);
}
}

效果图:(单层-枚举列表随机)

单层(全随机-长条形房间随机):

多层(层数5)(自定义-全随机):

参考资料:

https://indienova.com/indie-game-development/rooms-and-mazes-a-procedural-dungeon-generator/?tdsourcetag=s_pctim_aiomsg

https://mp.weixin.qq.com/s/3yM-mAAXq_fX5tcy82s0uQ

Unity 随机房间地图生成的更多相关文章

  1. Unity 随机地图房间通道生成

    之前的博客中已经说了随机房间生成: https://www.cnblogs.com/koshio0219/p/12604383.html 但实现房间生成只是整个地图生成最初最简单的一步.下面讨论如何随 ...

  2. Unity与Android交互-Unity接入高德地图实现定位以及搜索周边的功能(使用Android Studio)详细操作

    刚进公司给安排的任务就是Unity接入高德地图,算是踩了不少坑总算做出来了,抽点时间写个博客记录一下 废话不多说 先上效果图 获取定位并根据手机朝向显示周边信息            使用的Unity ...

  3. GJM:Unity导入百度地图SDK [转载]

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  4. Web 开发人员必备的随机 JSON 数据生成工具

    在 Web 开发中,经常会需要一些测试数据来测试接口或者功能时候正确.JSON Generator 就是这样一款生成随机 JSON 数据的在线工具,Web 开发人员必备,记得收藏和分享啊. 您可能感兴 ...

  5. Python 中的POST/GET包构建以及随机字符串的生成-乾颐堂

    现在,我们来用Python,创建GET包和POST包. 至于有什么用处,大家慢慢体会. Python 中包含了大量的库,作为一门新兴的语言,Python 对HTTP有足够强大的支持. 现在,我们引入新 ...

  6. Unity3d 随机地图生成

    2D解析图: 3D地形: 嘿嘿.

  7. unity3d WorldComposer1 卫星地图生成地形

    http://blog.csdn.net/myarrow/article/details/42709113 1. 简介 1.1 TerrainComposer(TC) 一个Unity扩展工具,可用于创 ...

  8. RaceWeb介绍(7):由500强公司数据高速生成百度地图——生成坐标字段及坐标数据

    接上篇. 一.生成X坐标.Y坐标两个字段. 我们须要为每一个公司建立X坐标和Y坐标字段,用来保存XY坐标. 既然为了突出"快",这一步就有程序来完毕吧. 右键单击"世界5 ...

  9. 【转】有关Oracle随机字符串的生成方法及具体应用

    Oracle生成随机字符串的方法是通过dbms_random.string实现的. 1.dbms_random.string用法Oracle官方文档参考链接:http://download.oracl ...

随机推荐

  1. golang实现chunk方式的查询

    有一个需求,是把表里面所有的数据都查询出来,并且生成json文件.因为一张表里面的数据很多,所以不可能一次性全部查询出来,所以需要用到chunk.之前用的gorm,但是发现gorm没有chunk方式的 ...

  2. Louis的「每周语文」

    说明:此专栏为Louis收录的经典语录及书影音标记,每周一更新. 成长的本质是变得复杂.当你的主观世界遇到客观世界,之间的那条沟,你掉进去,叫挫折,爬出来,叫成长. -- 语出罗振宇在奇葩说第四季的结 ...

  3. C++走向远洋——21(项目一,三角形,类)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:sanjiaoxing.cpp * 作者:常轩 * 微信公众号: ...

  4. 7-43 jmu-python-字符串异常处理 (20 分)

    输入一行字符串及下标,能取出相应字符.程序能对不合法数据做相应异常处理. 输入格式: 行1:输入一字符串 行2:输入字符下标 输出格式: 下标非数值异常,输出下标要整数 下标越界,输出下标越界 数据正 ...

  5. 7-5 jmu-python-分段函数1 (10 分)

    本题目要求计算下列分段函数f(x)的值(x为从键盘输入的一个任意实数): 输入格式: 直接输入一个实数给 x,没有其他任何附加字符. 输出格式: 在一行中按“f(x)=result”的格式输出,其中x ...

  6. czC#01

    1. .net简介: .net分为.net平台及.net Framework 2..NET作用 2.转义与@ 3.类型转换 1) 隐式转换 2)显式类型转换 (待转换的目标类型)原始值

  7. 绕过Referer和Host检查

    1.我们在尝试抓取其他网站的数据接口时,某些接口需要经过请求头中的Host和Referer的检查,不是指定的host或referer将不予返回数据,且前端无法绕过这种检查 此时通过后端代理解决 在vu ...

  8. 前端ps中常用的操作

    昨天,ui给了个psd图,让写成网页.额,要自己切图.很久之前,操作的还凑乎.但是,好久了,都忘了.所以,打算自己记个笔记,方便以后查看. 首先,打开ps就先来设置一下ps的单位啦点击最上面的一行的编 ...

  9. .netCore下的jwt的梳理-->借鉴于“老张的哲学”

    之前在公司的项目中有用到jwt进行token验证,但是公司里用的框架已经集成好了jwt,所以对jwt的的了解不够清晰,感觉还是隔着一层.在看了“老张的哲学”的jwt部分后对jwt的认识才更加深刻了一些 ...

  10. 玩转 .NET Core 3.0:逐浪CMS新版发布,建站更简单、网站更安全

    2019年11月11日,在大家都忙于网上体会“双11 ”的热闹气氛的时候,逐浪CMS开发者团队正在做着新版本发布的最后工作.此次更新是基本于 .NET Core 3.0开发,也是全国首个基于 .NET ...