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

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

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. 在没有APP的125年前 印度的外卖小哥是这样送餐

    说到印度,你想到的是什么?咖喱.歌舞剧.开挂的火车?通通不是,我今天要说的是他们的外卖小哥,在印度如同"神"一般的存在.其实印度人不叫这批人为外卖小哥,而称他们为dabbawala ...

  2. linux-深度学习环境配置-Centos

    下载Centos 7安装镜像,制作启动优盘. Install CentOS 7 安装CentOS 7. 第一步,配置日期.语言和键盘. 第二步,选择-系统-安装位置,进入磁盘分区界面.选择-其它存储选 ...

  3. Leetcode 142题 环形链表 II(Linked List Cycle II) Java语言求解

    题目描述: 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 p ...

  4. python爬虫之浅析验证码

    一.什么是验证码? 验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”( ...

  5. 从输入URL到页面展示

    当我们输入 URL 并按回车后,浏览器会对 URL 进行检查,首先判断URL格式,比如是ftp http ed2k等等,我们这里假设这个URL是http://hellocassie.cn,那么浏览器会 ...

  6. XML学习笔记--背诵版

    前言 一直想系统性的学XML,就没时间学,今晚抽出几个小时时间学完了XML.过几天再过来看看,背一背应该就差不多,记得东西较多,没什么难理解的. XML数据传输格式 第一章 XML概述 1.1 引入 ...

  7. ysoserial源码结构分析

    1.前言 之前也花了几天晚上熟悉了一下commonscollections系列的构造,那么学习一下这个项目是如何设计的也挺重要,多学习大佬如何写代码应该也能对自己的代码能力有提升吧~2333 2.项目 ...

  8. Serializable详解(1):代码验证Java序列化与反序列化

    说明:本文为Serializable详解(1),最后两段内容在翻译上出现歧义(暂时未翻译),将在后续的Serializable(2)文中补充. 介绍:本文根据JDK英文文档翻译而成,本译文并非完全按照 ...

  9. 量子计算机编程(二)——QPU基础函数

    第二部分主要是QPU的基础功能,第一部分就像是我们有了哪些基本的语句,第二部分就是我们能写一些简单基础的函数,一些小模块,第三部分就是他的应用了. 先来看一下一个简单量子应用的结构: 第一步,将量子态 ...

  10. 使用 ALSAlib 播放 wav

    在 ARM 2440 开发板上正常播放 16bit  44100 采样率的wav , 为了程序简单,没有判断返回值. 补充,在 ubunto 上也能正常播放. 编译方法: arm-linux-gcc ...