主頁 >  其他 > 用遺傳演算法優化垃圾收集策略

用遺傳演算法優化垃圾收集策略

2020-10-26 01:50:42 其他

作者|Andrew Kuo
編譯|VK
來源|Towards Data Science

遺傳演算法是一個優化技術,在本質上類似于進化程序,這可能是一個粗略的類比,但如果你瞇著眼睛看,達爾文的自然選擇確實大致上類似于一個優化任務,其目的是制造出完全適合在其環境中繁衍生息的有機體,

在本文中,我將展示如何在Python中實作一個遺傳演算法,在幾個小時內“進化”一個收集垃圾的機器人,

背景

我所遇到的遺傳演算法原理最好的教程來自Melanie Mitchell寫的一本關于復雜系統的好書《Complexity: A Guided Tour》,

在其中一個章節中,Mitchell介紹了一個名叫Robby的機器人,他在生活中的唯一目的是撿垃圾,并描述了如何使用GA優化Robby的控制策略,下面我將解釋我解決這個問題的方法,并展示如何在Python中實作該演算法,有一些很好的包可以用來構造這類演算法(比如DEAP),但是在本教程中,我將只使用基本Python、Numpy和TQDM(可選),

雖然這只是一個玩具的例子,但GAs在許多實際應用中都有使用,作為一個資料科學家,我經常用它們來進行超引數優化和模型選擇,雖然GAs的計算成本很高,但GAs允許我們并行地探索搜索空間的多個區域,并且在計算梯度時是一個很好的選擇,

問題描述

一個名為Robby的機器人生活在一個充滿垃圾的二維網格世界中,周圍有4堵墻(如下圖所示),這個專案的目標是發展一個最佳的控制策略,使他能夠有效地撿垃圾,而不是撞墻,

Robby只能看到他周圍上下左右四個方塊以及他所在的方塊,每個方塊有3個選擇,空的,有垃圾,或者是一面墻,因此,Robby有3?=243種不同的情況,Robby可以執行7種不同的動作:上下左右的移動(4種)、隨機移動、撿拾垃圾或靜止不動,

因此,Robby的控制策略可以編碼為一個“DNA”字串,由0到6之間的243位數字組成(對應于Robby在243種可能的情況下應該采取的行動),

方法

任何GA的優化步驟如下:

  1. 生成問題初始隨機解的“種群”

  2. 個體的“擬合度”是根據它解決問題的程度來評估的

  3. 最合適的解決方案進行“繁殖”并將“遺傳”物質傳遞給下一代的后代

  4. 重復第2步和第3步,直到我們得到一組優化的解決方案

在我們的任務中,你創建了第一代Robbys初始化為隨機DNA字串(對應于隨機控制策略),然后模擬讓這些機器人在隨機分配的網格世界中運行,并觀察它們的性能,

擬合度

機器人的擬合度取決于它在n次移動中撿到多少垃圾,以及它撞到墻上多少次,在我們的例子中,機器人每撿到一塊垃圾就給它10分,每次它撞到墻上就減去5分,然后,這些機器人以它們的擬合度相關的概率進行“交配”(即,撿起大量垃圾的機器人更有可能繁衍后代),新一代機器人誕生了,

交配

有幾種不同的方法可以實作“交配”,在Mitchell的版本中,她將父母的兩條DNA鏈隨機拼接,然后將它們連接在一起,為下一代創造一個孩子,在我的實作中,我從每一個親本中隨機分配每個基因(即,對于243個基因中的每一個,我擲硬幣決定遺傳誰的基因),

例如使用我的方法,在前10個基因里,父母和孩子可能的基因如下:

Parent 1: 1440623161
Parent 2: 2430661132
Child:    2440621161

突變

我們用這個演算法復制的另一個自然選擇的概念是“變異”,雖然一個孩子的絕大多數基因都是從父母那里遺傳下來的,但我也建立了基因突變的小可能性(即隨機分配),這種突變率使我們能夠探索新的可能,

Python實作

第一步是匯入所需的包并為此任務設定引數,我已經選擇了這些引數作為起點,但是它們可以調整,我鼓勵你可以嘗試調整,

"""
匯入包
"""
import numpy as np
from tqdm.notebook import tqdm

"""
設定引數
"""
# 仿真設定
pop_size = 200 # 每一代機器人的數量
num_breeders = 100 # 每一代能夠交配的機器人數量
num_gen = 400 # 總代數
iter_per_sim = 100 # 每個機器人垃圾收集模擬次數
moves_per_iter = 200 # 機器人每次模擬可以做的移動數

# 網格設定
rubbish_prob = 0.5 # 每個格子中垃圾的概率
grid_size = 10 # 0網格大小(墻除外)

# 進化設定
wall_penalty = -5 # 因撞到墻上而被扣除的擬合點
no_rub_penalty = -1 # 在空方塊撿垃圾被扣分
rubbish_score = 10 # 撿垃圾可獲得積分
mutation_rate = 0.01 # 變異的概率

接下來,我們為網格世界環境定義一個類,我們用標記“o”、“x”和“w”來表示每個單元,分別對應一個空單元、一個帶有垃圾的單元和一個墻,

class Environment:
    """
    類,用于表示充滿垃圾的網格環境,每個單元格可以表示為:
    'o': 空
    'x': 垃圾
    'w': 墻
    """
    def __init__(self, p=rubbish_prob, g_size=grid_size):
        self.p = p # 單元格是垃圾的概率
        self.g_size = g_size # 不包括墻

        # 初始化網格并隨機分配垃圾
        self.grid = np.random.choice(['o','x'], size=(self.g_size+2,self.g_size+2), p=(1 - self.p, self.p))
        
        # 設定外部正方形為墻壁
        self.grid[:,[0,self.g_size+1]] = 'w'
        self.grid[[0,self.g_size+1], :] = 'w'

    def show_grid(self):
        # 以當前狀態列印網格
        print(self.grid)

    def remove_rubbish(self,i,j):
        # 從指定的單元格(i,j)清除垃圾
        if self.grid[i,j] == 'o': # 單元格已經是空
            return False
        else:
            self.grid[i,j] = 'o'
            return True

    def get_pos_string(self,i,j):
        # 回傳一個字串,表示單元格(i,j)中機器人“可見”的單元格
        return self.grid[i-1,j] + self.grid[i,j+1] + self.grid[i+1,j] + self.grid[i,j-1] + self.grid[i,j]

接下來,我們創建一個類來表示我們的機器人,這個類包括執行動作、計算擬合度和從一對父機器人生成新DNA的方法,

class Robot:
    """
    用于表示垃圾收集機器人
    """
    def __init__(self, p1_dna=None, p2_dna=None, m_rate=mutation_rate, w_pen=wall_penalty, nr_pen=no_rub_penalty, r_score=rubbish_score):
        self.m_rate = m_rate # 突變率
        self.wall_penalty = w_pen # 因撞到墻上而受罰
        self.no_rub_penalty = nr_pen # 在空方塊撿垃圾的處罰
        self.rubbish_score = r_score # 撿垃圾的獎勵
        self.p1_dna = p1_dna # 父母2的DNA
        self.p2_dna = p2_dna # 父母2的DNA
        
        # 生成字典來從場景字串中查找基因索引
        con = ['w','o','x'] # 墻,空,垃圾
        self.situ_dict = dict()
        count = 0
        for up in con:
            for right in con:
                for down in con:
                    for left in con:
                        for pos in con:
                            self.situ_dict[up+right+down+left+pos] = count
                            count += 1
        
        # 初始化DNA
        self.get_dna()

    def get_dna(self):
        # 初始化機器人的dna字串
        if self.p1_dna is None:
            # 沒有父母的時候隨機生成DNA
            self.dna = ''.join([str(x) for x in np.random.randint(7,size=243)])
        else:
            self.dna = self.mix_dna()

    def mix_dna(self):
        # 從父母的DNA生成機器人的DNA
        mix_dna = ''.join([np.random.choice([self.p1_dna,self.p2_dna])[i] for i in range(243)])

        #添加變異
        for i in range(243):
            if np.random.rand() > 1 - self.m_rate:
                mix_dna = mix_dna[:i] + str(np.random.randint(7)) + mix_dna[i+1:]

        return mix_dna

    def simulate(self, n_iterations, n_moves, debug=False):
        # 仿真垃圾收集
        tot_score = 0
        for it in range(n_iterations):
            self.score = 0 # 擬合度分數
            self.envir = Environment()
            self.i, self.j = np.random.randint(1,self.envir.g_size+1, size=2) # 隨機分配初始位置
            if debug:
                print('before')
                print('start position:',self.i, self.j)
                self.envir.show_grid()
            for move in range(n_moves):
                self.act()
            tot_score += self.score
            if debug:
                print('after')
                print('end position:',self.i, self.j)
                self.envir.show_grid()
                print('score:',self.score)
        return tot_score / n_iterations # n次迭代的平均得分

    def act(self):
        # 根據DNA和機器人位置執行動作
        post_str = self.envir.get_pos_string(self.i, self.j) # 機器人當前位置
        gene_idx = self.situ_dict[post_str] # 當前位置DNA的相關索引
        act_key = self.dna[gene_idx] # 從DNA中讀取行動
        if act_key == '5':
            # 隨機移動
            act_key = np.random.choice(['0','1','2','3'])

        if act_key == '0':
            self.mv_up()
        elif act_key == '1':
            self.mv_right()
        elif act_key == '2':
            self.mv_down()
        elif act_key == '3':
            self.mv_left()
        elif act_key == '6':
            self.pickup()

    def mv_up(self):
        # 向上移動
        if self.i == 1:
            self.score += self.wall_penalty
        else:
            self.i -= 1

    def mv_right(self):
        # 向右移動
        if self.j == self.envir.g_size:
            self.score += self.wall_penalty
        else:
            self.j += 1

    def mv_down(self):
        # 向下移動
        if self.i == self.envir.g_size:
            self.score += self.wall_penalty
        else:
            self.i += 1

    def mv_left(self):
        # 向左移動
        if self.j == 1:
            self.score += self.wall_penalty
        else:
            self.j -= 1

    def pickup(self):
        # 撿垃圾
        success = self.envir.remove_rubbish(self.i, self.j)
        if success:
            # 成功撿到垃圾
            self.score += self.rubbish_score
        else:
            # 當前方塊沒有撿到垃圾
            self.score += self.no_rub_penalty

最后是運行遺傳演算法的時候了,在下面的代碼中,我們生成一個初始的機器人種群,讓自然選擇來運行它的程序,我應該提到的是,當然有更快的方法來實作這個演算法(例如利用并行化),但是為了本教程的目的,我犧牲了速度來實作清晰,

# 初始種群
pop = [Robot() for x in range(pop_size)]
results = []

# 執行進化
for i in tqdm(range(num_gen)):
    scores = np.zeros(pop_size)
    
    # 遍歷所有機器人
    for idx, rob in enumerate(pop):
        # 運行垃圾收集模擬并計算擬合度
        score = rob.simulate(iter_per_sim, moves_per_iter)
        scores[idx] = score

    results.append([scores.mean(),scores.max()]) # 保存每一代的平均值和最大值

    best_robot = pop[scores.argmax()] # 保存最好的機器人

    # 限制那些能夠交配的機器人的數量
    inds = np.argpartition(scores, -num_breeders)[-num_breeders:] # 基于擬合度得到頂級機器人的索引
    subpop = []
    for idx in inds:
        subpop.append(pop[idx])
    scores = scores[inds]

    # 平方并標準化
    norm_scores = (scores - scores.min()) ** 2 
    norm_scores = norm_scores / norm_scores.sum()

    # 創造下一代機器人
    new_pop = []
    for child in range(pop_size):
        # 選擇擬合度優秀的父母
        p1, p2 = np.random.choice(subpop, p=norm_scores, size=2, replace=False)
        new_pop.append(Robot(p1.dna, p2.dna))

    pop = new_pop

雖然最初大多數機器人不撿垃圾,總是撞到墻上,但幾代人之后,我們開始看到一些簡單的策略(例如“如果與垃圾在一起,就撿起來”和“如果挨著墻,就不要移到墻里”),經過幾百次的反復,我們只剩下一代不可思議的垃圾收集天才!

結果

下面的圖表表明,我們能夠在400代機器人種群中“進化”出一種成功的垃圾收集策略,

為了評估進化控制策略的質量,我手動創建了一個基準策略,其中包含一些直觀合理的規則:

  • 如果垃圾在當前方塊,撿起來

  • 如果在相鄰的方塊上可以看到垃圾,移到那個方塊

  • 如果靠近墻,則向相反方向移動

  • 否則,隨意移動

平均而言,這一基準策略達到了426.9的擬合度,但我們最終的“進化”機器人的平均擬合度為475.9,

戰略分析

這種優化方法最酷的一點是,你可以找到反直覺的解決方案,機器人不僅能夠學習人類可能設計的合理規則,而且還自發地想出了人類可能永遠不會考慮的策略,一種先進的技術出現了,就是使用“標記物”來克服近視和記憶不足,

例如,如果一個機器人現在在一個有垃圾的方塊上,并且可以看到東西方方塊上的垃圾,那么一個天真的方法就是立即撿起當前方塊上的垃圾,然后移動到那個有垃圾的方塊,這種策略的問題是,一旦機器人移動(比如向西),他就無法記住東邊還有1個垃圾,為了克服這個問題,我們觀察了我們的進化機器人執行以下步驟:

  1. 向西移動(在當前方塊留下垃圾作為標記)

  2. 撿起垃圾往東走(它可以看到垃圾作為標記)

  3. 把垃圾撿起來,搬到東邊去

  4. 撿起最后一塊垃圾

從這種優化中產生的另一個反直覺策略的例子如下所示,OpenAI使用強化學習(一種更復雜的優化方法)教代理玩捉迷藏,我們看到,這些代理一開始學習“人類”策略,但最終學會了新的解決方案,

結論

遺傳演算法以一種獨特的方式將生物學和計算機科學結合在一起,雖然不一定是最快的演算法,但在我看來,它們是最美麗的演算法之一,

本文中介紹的所有代碼都可以在我的Github上找到,還有一個演示Notebook:https://github.com/andrewjkuo/robby-robot-genetic-algorithm,謝謝你的閱讀!

原文鏈接:https://towardsdatascience.com/optimising-a-rubbish-collection-strategy-with-genetic-algorithms-ccf1f4d56c4f

歡迎關注磐創AI博客站:
http://panchuang.net/

sklearn機器學習中文官方檔案:
http://sklearn123.com/

歡迎關注磐創博客資源匯總站:
http://docs.panchuang.net/

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/191163.html

標籤:其他

上一篇:使用Detectron2分6步進行目標檢測

下一篇:NLP:不要重新造輪子

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more