日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从零开始做一个SLG游戏(三):用unity绘制图形

發布時間:2024/8/26 编程问答 63 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从零开始做一个SLG游戏(三):用unity绘制图形 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文主要是使用mesh制作一些簡單的模型資源。

一般而言,模型的制作最好還是使用專業的軟件來做,但是制作一些簡單的模型,unity還是可以勝任的。

unity自帶的模型只有立方體,圓柱,球,膠囊,方塊等有限的幾個,所以稍微復雜一些的東西就不好做了,比如最常用到的圓錐,棱柱,棱臺等,十分困難。

所以首先要做的是,將一些常用的基本模型,實現出來。

首先要做的是寫一個模型基類:
?

  • using System.Collections;
  • using System.Collections.Generic;
  • using UnityEngine;
  • [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider))]
  • public abstract class BasePoly : MonoBehaviour {
  • ? ? ? ? Mesh mesh;
  • ? ? ? ? private List<Vector3> vertices;
  • ? ? ? ? private List<int> triangles;
  • ? ? ? ? private List<Vector2> uvs;
  • ? ? ? ? private float length = 100f;
  • ? ? ? ? private void Awake()
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? mesh = GetComponent<MeshCollider>().sharedMesh = GetComponent<MeshFilter>().mesh = new Mesh();
  • ? ? ? ? ? ? ? ? mesh.name = "PolyMesh";
  • ? ? ? ? ? ? ? ? vertices = new List<Vector3>();
  • ? ? ? ? ? ? ? ? triangles = new List<int>();
  • ? ? ? ? ? ? ? ? uvs = new List<Vector2>();
  • ? ? ? ? }
  • ? ? ? ?
  • ? ? ? ? // Update is called once per frame
  • ? ? ? ? void Update ()
  • ? ?? ???{
  • ? ? ? ? ? ? ? ? DrawMesh();
  • ? ? ? ? }
  • ? ? ? ? private void DrawMesh()
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? Clear();
  • ? ? ? ? ? ? ? ? Draw();
  • ? ? ? ? ? ? ? ? UpdateMesh();
  • ? ? ? ? }
  • ? ? ? ? protected void AddTriangle(Vector3 v1, Vector3 v2, Vector3 v3)
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? AddConer(v1);
  • ? ? ? ? ? ? ? ? AddConer(v2);
  • ? ? ? ? ? ? ? ? AddConer(v3);
  • ? ? ? ? }
  • ? ? ? ? protected void AddSquare(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4)
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? AddTriangle(v1, v3, v2);
  • ? ? ? ? ? ? ? ? AddTriangle(v2, v3, v4);
  • ? ? ? ? }
  • ? ? ? ? private void AddConer(Vector3 point)
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? int count = vertices.Count;
  • ? ? ? ? ? ? ? ? vertices.Add(point);
  • ? ? ? ? ? ? ? ? triangles.Add(count);
  • ? ? ? ? ? ? ? ? uvs.Add(new Vector2(point.x / (2 * length), point.z / (2 * length)));
  • ? ? ? ? }
  • ? ? ? ? private void UpdateMesh()
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? mesh.vertices = vertices.ToArray();
  • ? ? ? ? ? ? ? ? mesh.triangles = triangles.ToArray();
  • ? ? ? ? ? ? ? ? mesh.uv = uvs.ToArray();
  • ? ? ? ? ? ? ? ? mesh.RecalculateNormals();
  • ? ? ? ? ? ? ? ? mesh.RecalculateBounds();
  • ? ? ? ? }
  • ? ? ? ? private void Clear()
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? mesh.Clear();
  • ? ? ? ? ? ? ? ? vertices.Clear();
  • ? ? ? ? ? ? ? ? triangles.Clear();
  • ? ? ? ? ? ? ? ? uvs.Clear();
  • ? ? ? ? }
  • ? ? ? ? public virtual void Draw()
  • ? ? ? ? {
  • ? ? ? ? }
  • }
  • 復制代碼



    具體實現的原理,在上一篇文章里大部分都有講過。現在將之封裝了起來。

    在子類中,重寫Draw()函數,調用下面兩個函數即可繪制各種想要的圖形。

    AddTriangle(Vector3v1,Vector3 v2,Vector3 v3);

    AddSquare(Vector3 v1,Vector3 v2,Vector3 v3,Vector3 v4);

    首先實現一下正多邊形:
    ?


    正多邊形其實和前面六邊形的制作方式類似,不過我們需要手動計算出正多邊形的各個頂點。

    將正n邊形的各個頂點和中心點連線,可以得到n個等腰三角形,而等腰三角形頂角的大小為(360°/n)。

    所以,如果知道一個頂點p的坐標,同時又知道原點坐標(0,0)的話,那下一個頂點p'的坐標可以通過p圍繞原點旋轉(360°/n)的角度獲得。

    那么我們復習一下高中的空間幾何知識:

    一個點圍繞原點逆時針旋轉θ角的時候,我們可以通過旋轉變換來獲得旋轉后的坐標。

    旋轉變換的矩陣為:
    ?


    具體用法為:

    對于(x,y)進行旋轉變換后,得到的(x',y')有

    x'=x*cosθ-y*sinθ

    y'=x*sinθ+y*cosθ

    所以寫一個函數來實現旋轉變換:
    ?

  • Vector3 RotationTranslate(Vector3 pos,float angle)
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? Vector3 Pos = pos;
  • ? ? ? ? ? ? ? ? float[,] transRect = {
  • ? ? ? ? ? ? ? ? ? ? ? ? { Mathf.Cos(angle),-Mathf.Sin(angle)},
  • ? ? ? ? ? ? ? ? ? ? ? ? { Mathf.Sin(angle),Mathf.Cos(angle)},
  • ? ? ? ? ? ? ? ? };
  • ? ? ? ? ? ? ? ? Pos.x = pos.x * transRect[0, 0] + pos.z * transRect[0, 1];
  • ? ? ? ? ? ? ? ? Pos.z = pos.x * transRect[1, 0] + pos.z * transRect[1, 1];
  • ? ? ? ? ? ? ? ? return Pos;
  • ? ? ? ? }
  • 復制代碼


    angle為旋轉的角度。

    正多邊形的各個點都有了,然后通過畫三角的方式,將正多邊形畫出來了。

    代碼如下:
    ?

  • public class Polygon : BasePoly {
  • ? ? ? ? public int edgeCount = 3;
  • ? ? ? ? private float angle = 0f;
  • ? ? ? ? private List<Vector3> coners = new List<Vector3>();
  • ? ? ? ? public override void Draw()
  • ? ? ? ? {
  • ? ?? ?? ?? ?? ? angle = 2f * Mathf.PI / count;
  • ? ? ? ? ? ? ? ? Vector3 pos = new Vector3(1f, 0f, 0f);
  • ? ? ? ? ? ? ? ? coners.Add(pos);
  • ? ? ? ? ? ? ? ? for (int i = 0; i < count; i++)
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? pos = RotationTranslate(pos);
  • ? ? ? ? ? ? ? ? ? ? ? ? coners.Add(pos);
  • ? ? ? ? ? ? ? ? }
  • ? ? ? ? ? ? ? ? for (int j = 0; j < count; j++)
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? AddTriangle(coners[j], Vector3.zero, coners[j + 1]);
  • ? ? ? ? ? ? ? ? }
  • ? ? ? ? ? ? ? ? coners.Clear();
  • ? ? ? ? }
  • ? ? ? ? Vector3 RotationTranslate(Vector3 pos)
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? Vector3 Pos = pos;
  • ? ? ? ? ? ? ? ? float[,] transRect = {
  • ? ? ? ? ? ? ? ? ? ? ? ? { Mathf.Cos(angle),-Mathf.Sin(angle)},
  • ? ? ? ? ? ? ? ? ? ? ? ? { Mathf.Sin(angle),Mathf.Cos(angle)},
  • ? ? ? ? ? ? ? ? };
  • ? ? ? ? ? ? ? ? Pos.x = pos.x * transRect[0, 0] + pos.z * transRect[0, 1];
  • ? ? ? ? ? ? ? ? Pos.z = pos.x * transRect[1, 0] + pos.z * transRect[1, 1];
  • ? ? ? ? ? ? ? ? return Pos;
  • ? ? ? ? }
  • }
  • 復制代碼


    實現后,會發現一個問題,那就是每幀都要繪制一次,會非常消耗功能,所以我們需要加一個函數,用于判斷是否需要再繪制一遍:
    ?

  • using System.Collections;
  • using System.Collections.Generic;
  • using UnityEngine;
  • [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider))]
  • public abstract class BasePoly : MonoBehaviour {
  • ……
  • ? ? ? ? private void DrawMesh()
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? if (NeedDraw())
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? Clear();
  • ? ? ? ? ? ? ? ? ? ? ? ? Draw();
  • ? ? ? ? ? ? ? ? ? ? ? ? UpdateMesh();
  • ? ? ? ? ? ? ? ? }
  • ? ? ? ? }
  • ? ? ? ? public virtual bool NeedDraw()
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? return true;
  • ? ? ? ? }
  • ……
  • }
  • 復制代碼


    然后再在子類中重寫NeedDraw()函數:
    ?

  • public class Polygon : BasePoly {
  • ? ? ? ? public int edgeCount = 3;
  • ? ? ? ? private int count = 0;
  • ? ? ? ? private float angle = 0f;
  • ? ? ? ? ……
  • ? ? ? ? public override bool NeedDraw()
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? if (edgeCount == count)
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? return false;
  • ? ? ? ? ? ? ? ? }
  • ? ? ? ? ? ? ? ? else if (edgeCount < 3)
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? return false;
  • ? ? ? ? ? ? ? ? }
  • ? ? ? ? ? ? ? ? else
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? count = edgeCount;
  • ? ? ? ? ? ? ? ? ? ? ? ? angle = 2f * Mathf.PI / count;
  • ? ? ? ? ? ? ? ? ? ? ? ? return true;
  • ? ? ? ? ? ? ? ? }
  • ? ? ? ? }
  • ? ? ? ? public override void Draw()
  • ? ? ? ? {
  • ? ?? ?? ?? ?? ? //angle = 2f * Mathf.PI / count;
  • ? ? ? ? ? ? ? ? ……
  • ? ? ? ? }
  • ? ?? ???……
  • }
  • 復制代碼


    其他圖形也可以通過類似的方法,一一繪制出來,并通過自己的賦值進行微調。

    比較麻煩的一點是,這么實現,需要先讓工程運行起來,繪制的圖形才能顯示出來。幸運的是,這并不影響搭建場景。

    接下來將介紹更多的基本圖形的畫法:

    1.正棱錐

    棱錐的畫法其實和前文制作六邊形網格的制作方法類似,將六邊形網格的中心點往上移動若干個單位,再加上底面,就是一個六棱錐了。

    處理方式和前文的正多邊形相同:按角度一次分割三角形
    ?

  • List<Vector3> conors = new List<Vector3>();
  • ? ? ? ? public override void Draw()
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? Vector3 pos = new Vector3(1f, 0f, 0f);
  • ? ? ? ? ? ? ? ? conors.Add(pos);
  • ? ? ? ? ? ? ? ? for (int i = 0; i < count; i++)
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? pos = RotationTranslate(pos);
  • ? ? ? ? ? ? ? ? ? ? ? ? conors.Add(pos);
  • ? ? ? ? ? ? ? ? }
  • ? ?? ?? ?}
  • 復制代碼



    和多邊形一樣,先把點加進去,手游賬號交易接下來和多邊形不同的是,我們需要畫2個三角形,如下圖:


    o為底面的中心點,o1為頂點,和前文一樣,底面中心的坐標默認為(0,0,0),即Vector3.zero。

    o1作為頂點,暫定高為1。于是o1的坐標為(0,1,0)。(0,1,0)也可以表示為Vector3.up。

    需要畫的三角形為底面的一部分(o,c<i>,c[i+1])以及側面(o1,c[i+1],c<i>)。

    完整代碼如下:
    ?

  • List<Vector3> conors = new List<Vector3>();
  • ? ? ? ? public override void Draw()
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? Vector3 pos = new Vector3(1f, 0f, 0f);
  • ? ? ? ? ? ? ? ? conors.Add(pos);
  • ? ? ? ? ? ? ? ? for (int i = 0; i < count; i++)
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? pos = RotationTranslate(pos);
  • ? ? ? ? ? ? ? ? ? ? ? ? conors.Add(pos);
  • ? ? ? ? ? ? ? ? }
  • ? ? ? ? ? ? ? ? for (int k = 0; k < count; k++)
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? AddTriangle(Vector3.zero, conors[k], conors[k + 1]);
  • ? ? ? ? ? ? ? ? ? ? ? ? AddTriangle(conors[k], Vector3.up, conors[k + 1]);
  • ? ? ? ? ? ? ? ? }
  • ? ? ? ? ? ? ? ? conors.Clear();
  • ? ? ? ? }
  • 復制代碼


    2.正棱臺

    正棱臺和正棱錐一樣,也是分割成多個方向,單個方向如圖:
    ?


    需要畫的是(o1,c1[i+1],c1<i>)(o,c<i>,c[i+1])兩個三角形底,以及(c<i>,c[1+1],c1<i>,c1[i+1])這個矩形的側面。

    上下兩個三角形的底是相似的,并且對應的邊也是相互平行的。

    o點坐標為Vector3.zero,即(0,0,0),o1的坐標為Vector3.up,即(0,1,0)。

    然后定義兩個三角形的縮放比例為zoom的話

    通過空間向量的換算,很容易得出:c1<i>=c<i>*zoom+Vector3.up

    所以我們定義兩個List用于存放上下底的點,并用一個函數來添加點:
    ?

  • List<Vector3> conors = new List<Vector3>();//下底的點
  • ? ? ? ? List<Vector3> _conors = new List<Vector3>();//上底的點
  • ? ?? ???public float zoom = 1f;
  • ? ?? ???void AddConors(Vector3 pos)
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? conors.Add(pos);
  • ? ? ? ? ? ? ? ? _conors.Add(pos * zoom + Vector3.up);
  • ? ? ? ? }
  • 復制代碼



    接下來的就很簡單了,點加好后,把三個面加上去就行了,函數都封裝好了的:
    ?

  • public override void Draw()
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? angle = 2f * Mathf.PI / count;
  • ? ? ? ? ? ? ? ? Vector3 pos = new Vector3(1f, 0f, 0f);
  • ? ? ? ? ? ? ? ? AddConors(pos);
  • ? ? ? ? ? ? ? ? for (int i = 0; i < count; i++)
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? pos = RotationTranslate(pos);
  • ? ? ? ? ? ? ? ? ? ? ? ? AddConors(pos);
  • ? ? ? ? ? ? ? ? }
  • ? ? ? ? ? ? ? ? for (int k = 0; k < count; k++)
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? AddTriangle(Vector3.zero, conors[k], conors[k + 1]);
  • ? ? ? ? ? ? ? ? ? ? ? ? AddTriangle(_conors[k], Vector3.up, _conors[k + 1]);
  • ? ? ? ? ? ? ? ? ? ? ? ? AddSquare(conors[k], conors[k + 1], _conors[k], _conors[k + 1]);
  • ? ? ? ? ? ? ? ? }
  • ? ? ? ? ? ? ? ? conors.Clear();
  • ? ? ? ? ? ? ? ? _conors.Clear();
  • ? ? ? ? }
  • 復制代碼


    有了自制的棱臺、棱柱,以及unity自帶的方塊,球,膠囊,圓柱之類的物體,就可以在unity中自己搭建各種需要的場景了。

    這樣做出來的場景物體,用于最終成品可能不達標,但是用于演示已經夠了。這最重要的是,暫時不用去學建模軟件了。


    ?

    總結

    以上是生活随笔為你收集整理的从零开始做一个SLG游戏(三):用unity绘制图形的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。