2D獵寶行動(類掃雷小遊戲)DAY 5
阿新 • • 發佈:2018-11-06
1.製作金光閃閃的特效
2.設計金幣元素類
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GoldElement : DoubleCoveredElement { public GoldType goldType; public override void Awake() { base.Awake(); elementContent = ElementContent.Gold; } public override void OnUnCovered() { Transform goldEffect = transform.Find("GoldEffect"); if (goldEffect != null) { Destroy(goldEffect.gameObject); } //TODO 獲得金幣 Debug.Log("Get a Gold"); base.OnUnCovered(); } public override void ConfirmSprite() { Transform goldEffect = transform.Find("GoldEffect"); if (goldEffect == null) { Instantiate(GameManager._instance.goldEffect,transform).name = "GoldEffect"; } LoadSprite(GameManager._instance.goldSprites[(int)goldType]); } }
3.設計剩餘的所有不可翻開的元素類
建立五個類,分別為BigWall,SmallWall,Door,Enemy
using System.Collections; using System.Collections.Generic; using UnityEngine; public class BigWallElement : CantCoveredElement { public override void Awake() { base.Awake(); elementContent = ElementContent.BigWall; LoadSprite(GameManager._instance.bigwallSprites[Random.Range(0, GameManager._instance.bigwallSprites.Length)]); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SmallWallElement : CantCoveredElement { public override void Awake() { base.Awake(); elementContent = ElementContent.SmallWall; ClearShadow(); LoadSprite(GameManager._instance.smallwallSprites[Random.Range(0, GameManager._instance.smallwallSprites.Length)]); } }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DoorElement : CantCoveredElement {
public override void Awake()
{
base.Awake();
elementContent = ElementContent.Door;
LoadSprite(GameManager._instance.doorSprite);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyElement : CantCoveredElement {
public override void Awake()
{
base.Awake();
elementContent = ElementContent.Enemy;
ClearShadow();
LoadSprite(GameManager._instance.enemySprites[Random.Range(0, GameManager._instance.enemySprites.Length)]);
}
}
4.關卡出口的生成
建立關卡出口的類
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExitElement : CantCoveredElement
{
public override void Awake()
{
base.Awake();
elementContent = ElementContent.Exit;
ClearShadow();
name = "Exit";
LoadSprite(GameManager._instance.exitSprite);
}
}
在GameManager中寫生成出口的方法
/// <summary>
/// 生成出口
/// </summary>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值</param>
private void GenerateExit(List<int> availableIndex)
{
float x = w - 1.5f;
float y = Random.Range(1, h) - 0.5f;
BaseElement exit = SetElement(GetIndex((int)(x + 0.5), (int)(y - 0.5)), ElementContent.Exit);
exit.transform.position = new Vector3(x, y, 0);
Destroy(exit.GetComponent<BoxCollider2D>());
exit.gameObject.AddComponent<BoxCollider2D>();
availableIndex.Remove(GetIndex((int)(x + 0.5), (int)(y - 0.5)));
availableIndex.Remove(GetIndex((int)(x + 0.5), (int)(y + 0.5)));
availableIndex.Remove(GetIndex((int)(x - 0.5), (int)(y - 0.5)));
availableIndex.Remove(GetIndex((int)(x - 0.5), (int)(y + 0.5)));
Destroy(mapArray[(int)(x + 0.5), (int)(y + 0.5)].gameObject);
Destroy(mapArray[(int)(x - 0.5), (int)(y - 0.5)].gameObject);
Destroy(mapArray[(int)(x - 0.5), (int)(y + 0.5)].gameObject);
mapArray[(int)(x + 0.5), (int)(y + 0.5)] = exit;
mapArray[(int)(x - 0.5), (int)(y - 0.5)] = exit;
mapArray[(int)(x - 0.5), (int)(y + 0.5)] = exit;
}
執行程式,結果如下:
5.障礙物生成策略簡介
6.設計閉合區域資訊結構體
/// <summary>
/// 生成障礙物區
/// </summary>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值</param>
private void GenerateObstacleArea(List<int> availableIndex)
{
for(int i = 0; i < obstacleAreaNum; i++)
{
if (Random.value < 0.5f)
{
CreateCloseArea(i, availableIndex);
}
else
{
CreateRandomWall(i, availableIndex);
}
}
}
private struct CloseAreaInfo
{
int x, y, sx, ex, sy, ey;
public int doorType;
public Vector2 doorPos;
public int tx, ty;
public ToolElement t;
public int gx, gy;
public GoldElement g;
public int innerCount, goldNum;
}
/// <summary>
/// 生成閉合障礙物區域
/// </summary>
/// <param name="nowArea">當前障礙物區域的索引值</param>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值列表</param>
private void CreateCloseArea(int nowArea, List<int> availableIndex)
{
int shape = Random.Range(0, 2);
switch (shape)
{
case 0:
break;
case 1:
break;
}
}
/// <summary>
/// 生成隨機障礙物區域
/// </summary>
/// <param name="nowArea">當前障礙物區域的索引值</param>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值列表</param>
private void CreateRandomWall(int nowArea, List<int> availableIndex)
{
}
7.生成閉合區域資訊
/// <summary>
/// 生成閉合區域資訊
/// </summary>
/// <param name="type">閉合區域型別,0:與邊界閉合;1:自閉和</param>
/// <param name="nowArea">閉合區域索引值</param>
/// <param name="info">要生成的閉合區域資訊結構體</param>
private void GenerateCloseAreaInfo(int type,int nowArea,ref CloseAreaInfo info)
{
switch (type)
{
case 0:
info.x = Random.Range(3, obstacleAreaW - 2);
info.y = Random.Range(3, h - 3);
info.sx = standAreaW + nowArea * obstacleAreaW + 1;
info.ex = info.sx + info.x;
info.doorType = Random.Range(4, 8);
break;
case 1:
break;
}
}
/// <summary>
/// 生成閉合障礙物區域
/// </summary>
/// <param name="nowArea">當前障礙物區域的索引值</param>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值列表</param>
private void CreateCloseArea(int nowArea, List<int> availableIndex)
{
int shape = Random.Range(0, 2);
CloseAreaInfo info = new CloseAreaInfo();
switch (shape)
{
case 0:
GenerateCloseAreaInfo(0, nowArea, ref info);
int dir = Random.Range(0, 4);
switch (dir)//四種樣子的障礙物區域
{
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
}
break;
case 1:
break;
}
}
8.生成閉合區域的門和牆
/// <summary>
/// 生成閉合障礙物區域
/// </summary>
/// <param name="nowArea">當前障礙物區域的索引值</param>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值列表</param>
private void CreateCloseArea(int nowArea, List<int> availableIndex)
{
int shape = Random.Range(0, 2);
CloseAreaInfo info = new CloseAreaInfo();
switch (shape)
{
case 0:
GenerateCloseAreaInfo(0, nowArea, ref info);
int dir = Random.Range(0, 4);
switch (dir)
{
case 0:
info.doorPos = Random.value < 0.5f ? new Vector2(Random.Range(info.sx + 1, info.ex), info.y) : new Vector2(Random.value < 0.5f ? info.sx : info.ex, Random.Range(info.y, h));
CreateULShapeAreaDoor(info, availableIndex);
for(int i = h - 1; i > info.y; i--)
{
if (availableIndex.Contains(GetIndex(info.sx, i)))
{
availableIndex.Remove(GetIndex(info.sx, i));
SetElement(GetIndex(info.sx, i), ElementContent.BigWall);
}
}
for (int i = info.sx; i < info.ex; i++)
{
if (availableIndex.Contains(GetIndex(i, info.y)))
{
availableIndex.Remove(GetIndex(i, info.y));
SetElement(GetIndex(i, info.y), ElementContent.BigWall);
}
}
for (int i = h-1; i >= info.y; i--)
{
if (availableIndex.Contains(GetIndex(info.ex, i)))
{
availableIndex.Remove(GetIndex(info.ex, i));
SetElement(GetIndex(info.ex, i), ElementContent.BigWall);
}
}
break;
case 1:
break;
case 2:
break;
case 3:
break;
}
break;
case 1:
break;
}
}
/// <summary>
/// 生成U或L閉合障礙物區域的門
/// </summary>
/// <param name="info">閉合區域資訊</param>
/// <param name="availableIndex">要生成的閉合區域資訊結構體</param>
private void CreateULShapeAreaDoor(CloseAreaInfo info,List<int> availableIndex)
{
availableIndex.Remove(GetIndex((int)info.doorPos.x, (int)info.doorPos.y));
SetElement(GetIndex((int)info.doorPos.x, (int)info.doorPos.y), (ElementContent)info.doorType);
}
/// <summary>
/// 生成U或L閉合障礙物區域的獎勵物品
/// </summary>
/// <param name="info">閉合區域資訊</param>
/// <param name="availableIndex">要生成的閉合區域資訊結構體</param>
private void CreateCloseAreaRewards(CloseAreaInfo info, List<int> availableIndex)
{
info.innerCount = info.x * info.y;
info.goldNum = Random.Range(1, Random.value < 0.5 ? info.innerCount + 1 : info.innerCount / 2);
for(int i = 0; i < info.goldNum; i++)
{
}
}
9.生成閉合區域的獎勵
/// <summary>
/// 生成閉合障礙物區域
/// </summary>
/// <param name="nowArea">當前障礙物區域的索引值</param>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值列表</param>
private void CreateCloseArea(int nowArea, List<int> availableIndex)
{
int shape = Random.Range(0, 2);
CloseAreaInfo info = new CloseAreaInfo();
switch (shape)
{
case 0:
GenerateCloseAreaInfo(0, nowArea, ref info);
int dir = Random.Range(0, 4);
switch (dir)
{
case 0:
info.doorPos = Random.value < 0.5f ? new Vector2(Random.Range(info.sx + 1, info.ex), info.y) : new Vector2(Random.value < 0.5f ? info.sx : info.ex, Random.Range(info.y, h));
CreateULShapeAreaDoor(info, availableIndex);
for(int i = h - 1; i > info.y; i--)
{
if (availableIndex.Contains(GetIndex(info.sx, i)))
{
availableIndex.Remove(GetIndex(info.sx, i));
SetElement(GetIndex(info.sx, i), ElementContent.BigWall);
}
}
for (int i = info.sx; i < info.ex; i++)
{
if (availableIndex.Contains(GetIndex(i, info.y)))
{
availableIndex.Remove(GetIndex(i, info.y));
SetElement(GetIndex(i, info.y), ElementContent.BigWall);
}
}
for (int i = h-1; i >= info.y; i--)
{
if (availableIndex.Contains(GetIndex(info.ex, i)))
{
availableIndex.Remove(GetIndex(info.ex, i));
SetElement(GetIndex(info.ex, i), ElementContent.BigWall);
}
}
info.sy = info.y;
info.ey = h - 1;
info.y = h - 1 - info.y;
CreateCloseAreaRewards(info, availableIndex);
break;
case 1:
info.doorPos = Random.value < 0.5f ? new Vector2(Random.Range(info.sx + 1, info.ex), info.y) : new Vector2(Random.value < 0.5f ? info.sx : info.ex, Random.Range(0, info.y));
CreateULShapeAreaDoor(info, availableIndex);
for (int i = 0; i < info.y; i++)
{
if (availableIndex.Contains(GetIndex(info.sx, i)))
{
availableIndex.Remove(GetIndex(info.sx, i));
SetElement(GetIndex(info.sx, i), ElementContent.BigWall);
}
}
for (int i = info.sx; i < info.ex; i++)
{
if (availableIndex.Contains(GetIndex(i, info.y)))
{
availableIndex.Remove(GetIndex(i, info.y));
SetElement(GetIndex(i, info.y), ElementContent.BigWall);
}
}
for (int i = 0; i <= info.y; i++)
{
if (availableIndex.Contains(GetIndex(info.ex, i)))
{
availableIndex.Remove(GetIndex(info.ex, i));
SetElement(GetIndex(info.ex, i), ElementContent.BigWall);
}
}
info.sy = 0;
info.ey = info.y;
CreateCloseAreaRewards(info, availableIndex);
break;
case 2:
info.doorPos = Random.value < 0.5f ? new Vector2(Random.Range(info.sx + 1, info.ex), info.y) : new Vector2(info.sx , Random.Range(info.y, h));
CreateULShapeAreaDoor(info, availableIndex);
for (int i = h - 1; i > info.y; i--)
{
if (availableIndex.Contains(GetIndex(info.sx, i)))
{
availableIndex.Remove(GetIndex(info.sx, i));
SetElement(GetIndex(info.sx, i), ElementContent.BigWall);
}
}
for (int i = info.sx; i < info.ex; i++)
{
if (availableIndex.Contains(GetIndex(i, info.y)))
{
availableIndex.Remove(GetIndex(i, info.y));
SetElement(GetIndex(i, info.y), ElementContent.BigWall);
}
}
for (int i = 0; i <= info.y; i++)
{
if (availableIndex.Contains(GetIndex(info.ex, i)))
{
availableIndex.Remove(GetIndex(info.ex, i));
SetElement(GetIndex(info.ex, i), ElementContent.BigWall);
}
}
break;
case 3:
info.doorPos = Random.value < 0.5f ? new Vector2(Random.Range(info.sx + 1, info.ex), info.y) : new Vector2(info.sx, Random.Range(0, info.y));
CreateULShapeAreaDoor(info, availableIndex);
for (int i = 0; i < info.y; i++)
{
if (availableIndex.Contains(GetIndex(info.sx, i)))
{
availableIndex.Remove(GetIndex(info.sx, i));
SetElement(GetIndex(info.sx, i), ElementContent.BigWall);
}
}
for (int i = info.sx; i < info.ex; i++)
{
if (availableIndex.Contains(GetIndex(i, info.y)))
{
availableIndex.Remove(GetIndex(i, info.y));
SetElement(GetIndex(i, info.y), ElementContent.BigWall);
}
}
for (int i = h - 1; i >= info.y; i--)
{
if (availableIndex.Contains(GetIndex(info.ex, i)))
{
availableIndex.Remove(GetIndex(info.ex, i));
SetElement(GetIndex(info.ex, i), ElementContent.BigWall);
}
}
break;
}
break;
case 1:
break;
}
}
10.完成閉合區域的生成
新增自閉和區域的結構體和生成程式碼
/// <summary>
/// 生成閉合區域資訊
/// </summary>
/// <param name="type">閉合區域型別,0:與邊界閉合;1:自閉和</param>
/// <param name="nowArea">閉合區域索引值</param>
/// <param name="info">要生成的閉合區域資訊結構體</param>
private void GenerateCloseAreaInfo(int type,int nowArea,ref CloseAreaInfo info)
{
switch (type)
{
case 0:
info.x = Random.Range(3, obstacleAreaW - 2);
info.y = Random.Range(3, h - 3);
info.sx = standAreaW + nowArea * obstacleAreaW + 1;
info.ex = info.sx + info.x;
info.doorType = Random.Range(4, 8);
break;
case 1:
info.x = Random.Range(3, obstacleAreaW - 2);
info.y = Random.Range(3, info.x + 1);
info.sx = standAreaW + nowArea * obstacleAreaW + 1;
info.ex = info.sx + info.x;
info.sy = Random.Range(3, h - info.y - 1);
info.ey = info.sy + info.y;
info.doorType = (int)ElementContent.BigWall;
break;
}
}
/// <summary>
/// 生成閉合障礙物區域
/// </summary>
/// <param name="nowArea">當前障礙物區域的索引值</param>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值列表</param>
private void CreateCloseArea(int nowArea, List<int> availableIndex)
{
int shape = Random.Range(0, 2);
CloseAreaInfo info = new CloseAreaInfo();
switch (shape)
{
case 0:
GenerateCloseAreaInfo(0, nowArea, ref info);
int dir = Random.Range(0, 4);
switch (dir)
{
case 0:
info.doorPos = Random.value < 0.5f ? new Vector2(Random.Range(info.sx + 1, info.ex), info.y) : new Vector2(Random.value < 0.5f ? info.sx : info.ex, Random.Range(info.y, h));
CreateULShapeAreaDoor(info, availableIndex);
for(int i = h - 1; i > info.y; i--)
{
if (availableIndex.Contains(GetIndex(info.sx, i)))
{
availableIndex.Remove(GetIndex(info.sx, i));
SetElement(GetIndex(info.sx, i), ElementContent.BigWall);
}
}
for (int i = info.sx; i < info.ex; i++)
{
if (availableIndex.Contains(GetIndex(i, info.y)))
{
availableIndex.Remove(GetIndex(i, info.y));
SetElement(GetIndex(i, info.y), ElementContent.BigWall);
}
}
for (int i = h-1; i >= info.y; i--)
{
if (availableIndex.Contains(GetIndex(info.ex, i)))
{
availableIndex.Remove(GetIndex(info.ex, i));
SetElement(GetIndex(info.ex, i), ElementContent.BigWall);
}
}
info.sy = info.y;
info.ey = h - 1;
info.y = h - 1 - info.y;
CreateCloseAreaRewards(info, availableIndex);
break;
case 1:
info.doorPos = Random.value < 0.5f ? new Vector2(Random.Range(info.sx + 1, info.ex), info.y) : new Vector2(Random.value < 0.5f ? info.sx : info.ex, Random.Range(0, info.y));
CreateULShapeAreaDoor(info, availableIndex);
for (int i = 0; i < info.y; i++)
{
if (availableIndex.Contains(GetIndex(info.sx, i)))
{
availableIndex.Remove(GetIndex(info.sx, i));
SetElement(GetIndex(info.sx, i), ElementContent.BigWall);
}
}
for (int i = info.sx; i < info.ex; i++)
{
if (availableIndex.Contains(GetIndex(i, info.y)))
{
availableIndex.Remove(GetIndex(i, info.y));
SetElement(GetIndex(i, info.y), ElementContent.BigWall);
}
}
for (int i = 0; i <= info.y; i++)
{
if (availableIndex.Contains(GetIndex(info.ex, i)))
{
availableIndex.Remove(GetIndex(info.ex, i));
SetElement(GetIndex(info.ex, i), ElementContent.BigWall);
}
}
info.sy = 0;
info.ey = info.y;
CreateCloseAreaRewards(info, availableIndex);
break;
case 2:
info.doorPos = Random.value < 0.5f ? new Vector2(Random.Range(info.sx + 1, info.ex), info.y) : new Vector2(info.sx , Random.Range(info.y, h));
CreateULShapeAreaDoor(info, availableIndex);
for (int i = h - 1; i > info.y; i--)
{
if (availableIndex.Contains(GetIndex(info.sx, i)))
{
availableIndex.Remove(GetIndex(info.sx, i));
SetElement(GetIndex(info.sx, i), ElementContent.BigWall);
}
}
for (int i = info.sx; i < info.ex; i++)
{
if (availableIndex.Contains(GetIndex(i, info.y)))
{
availableIndex.Remove(GetIndex(i, info.y));
SetElement(GetIndex(i, info.y), ElementContent.BigWall);
}
}
for (int i = 0; i <= info.y; i++)
{
if (availableIndex.Contains(GetIndex(info.ex, i)))
{
availableIndex.Remove(GetIndex(info.ex, i));
SetElement(GetIndex(info.ex, i), ElementContent.BigWall);
}
}
break;
case 3:
info.doorPos = Random.value < 0.5f ? new Vector2(Random.Range(info.sx + 1, info.ex), info.y) : new Vector2(info.sx, Random.Range(0, info.y));
CreateULShapeAreaDoor(info, availableIndex);
for (int i = 0; i < info.y; i++)
{
if (availableIndex.Contains(GetIndex(info.sx, i)))
{
availableIndex.Remove(GetIndex(info.sx, i));
SetElement(GetIndex(info.sx, i), ElementContent.BigWall);
}
}
for (int i = info.sx; i < info.ex; i++)
{
if (availableIndex.Contains(GetIndex(i, info.y)))
{
availableIndex.Remove(GetIndex(i, info.y));
SetElement(GetIndex(i, info.y), ElementContent.BigWall);
}
}
for (int i = h - 1; i >= info.y; i--)
{
if (availableIndex.Contains(GetIndex(info.ex, i)))
{
availableIndex.Remove(GetIndex(info.ex, i));
SetElement(GetIndex(info.ex, i), ElementContent.BigWall);
}
}
break;
}
CreateCloseAreaTool(info, availableIndex);
break;
case 1:
GenerateCloseAreaInfo(1, nowArea, ref info);
for(int i = info.sx; i<= info.ex; i++)
{
if (availableIndex.Contains(GetIndex(i, info.sy)))
{
availableIndex.Remove(GetIndex(i, info.sy));
SetElement(GetIndex(i, info.sy), ElementContent.BigWall);
}
if (availableIndex.Contains(GetIndex(i, info.ey)))
{
availableIndex.Remove(GetIndex(i, info.ey));
SetElement(GetIndex(i, info.ey), ElementContent.BigWall);
}
}
for (int i = info.sy + 1; i < info.ey; i++)
{
if (availableIndex.Contains(GetIndex(info.sx,i)))
{
availableIndex.Remove(GetIndex(info.sx, i));
SetElement(GetIndex(info.sx, i), ElementContent.BigWall);
}
if (availableIndex.Contains(GetIndex(info.ex, i)))
{
availableIndex.Remove(GetIndex(info.ex, i));
SetElement(GetIndex(info.ex, i), ElementContent.BigWall);
}
}
CreateCloseAreaRewards(info,availableIndex);
CreateCloseAreaTool(info, availableIndex);
break;
}
}
11.完成地圖的建立
完成生成道具和生成金幣的方法
/// <summary>
/// 生成道具
/// </summary>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值</param>
private void GenerateTool(List<int> availableIndex)
{
for (int i = 0; i < 3; i++)
{
int tempIndex = availableIndex[Random.Range(0, availableIndex.Count)];
availableIndex.Remove(tempIndex);
ToolElement t = (ToolElement)SetElement(tempIndex, ElementContent.Tool);
t.toolType = (ToolType)Random.Range(0, 9);
if (t.isHide == false)
{
t.ConfirmSprite();
}
}
}
/// <summary>
/// 生成金幣
/// </summary>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值</param>
private void GenerateGold(List<int> availableIndex)
{
for (int i = 0; i < obstacleAreaNum * 3; i++)
{
int tempIndex = availableIndex[Random.Range(0, availableIndex.Count)];
availableIndex.Remove(tempIndex);
GoldElement g = (GoldElement)SetElement(tempIndex, ElementContent.Gold);
g.goldType = (GoldType)Random.Range(0, 7);
if (g.isHide == false)
{
g.ConfirmSprite();
}
}
}
執行程式,結果如下:
12.為玩家建立站立區域
在生成陷阱的方法中新增一條語句,使初始的地方沒有陷阱
/// <summary>
/// 生成陷阱
/// </summary>
/// <param name="standAreaY">站立區域的y座標</param>
/// <param name="availableIndex">尚未初始化的地圖元素的索引值</param>
private void GenerateTrap(int standAreaY, List<int> availableIndex)
{
float trapProbability = Random.Range(minTrapProbability, maxTrapProbability);
int trapNum = (int)(availableIndex.Count * trapProbability);
for (int i = 0; i < trapNum; i++)
{
int tempIndex = availableIndex[Random.Range(0, availableIndex.Count)];
int x, y;
GetPosition(tempIndex, out x, out y);
if (x >= 0 && x < standAreaW && y >= standAreaY - 1 && y <= standAreaY + 1) continue;
availableIndex.Remove(tempIndex);
SetElement(tempIndex, ElementContent.Trap);
}
}
新增生成初始空位的方法
/// <summary>
/// 生成站立區域
/// </summary>
/// <param name="y">站立區域中心y座標</param>
private void GenerateStandArea(int y)
{
for(int i = 0; i < standAreaW; i++)
{
for(int j = y - 1; j <= y + 1; j++)
{
((SingleCoveredElement)mapArray[i, j]).UncoverElementSingle();
}
}
}
執行程式,結果如下: