Qt -DFS可視化

博客主頁:【夜泉_ly】
本文專欄:【暫無】
歡迎點贊👍收藏?關注??

在這里插入圖片描述

目錄

      • 前言
      • 關于如何sleep
      • 實現思路
      • Pixmaps
        • pixmaps.h
        • pixmaps.cpp
      • MapSquare
        • mapsquare.h
        • mapsquare.cpp
      • dfsthread
        • dfsthread.h
        • dfsthread.cpp
          • run dfs
          • 其他
        • Widget
          • Unit
          • 其他

Qt -DFS算法可視化

完整代碼:https://gitee.com/Ye_Quan/my-cpp-project/tree/master/Qt-experiments/dfs-visualizer

前言

本來,我是在搞我的戰棋小游戲的,
如果大家玩過戰棋應該知道,
當我們點擊一個單位時,
一般會顯示出一片區域,
表示這個單位的移動范圍(以及可攻擊目標等等)。

我當時就想到了用DFS和BFS,
然后就寫了。

之后我想,
既然已經在游戲中實現了DFS,
那能不能以現有代碼為基礎,
寫一個DFS算法可視化呢?
感覺很有意思,
所以有了本文。

當然,雖然標題叫做DFS可視化,
但是代碼部分大多是在對戰棋游戲的實現進行試驗,
因此存在很多‘多余’的設計,大家看看就行。

關于如何sleep

既然是可視化,
那必定不能等DFS完了再更新地圖狀態,
因此我決定在每次更新了一個格子的狀態后,
就暫停一會兒再繼續DFS。

結果問題來了,
怎么做到每次都暫停一會兒?

我本來想直接在DFS中直接加sleep就好了:
在這里插入圖片描述
然后程序卡了,
DFS完了才更新界面。
我以為是沒用信號觸發的問題,
改成用信號觸發地格更新:
在這里插入圖片描述
結果還是不行。
為什么?
最開始我以為和Linux中多線程競爭鎖的問題類似,
大概描述一下就是:
搶鎖 - 我搶到了! - 我釋放 - 欸我離得近,我再搶!
然后發現了一個本質的區別:
這里只有一個線程啊🤣!

問題出在事件隊列
當前這個DFS就是事件隊列的一個事件,
而DFS發送的信號所觸發的事件,
不過是去事件隊列后面排隊罷了,
那現在執行的是誰?
還是DFS!
我DFS沒跑完,
你們后面的事件都別想跑!

所以用QTimer?
我這是DFS。。。
如果用QTimer,那得搞個stack,
然后用類似非遞歸版的DFS來做吧?

我最終的解決方案是,
使用子線程跑DFS,
這樣就不會阻塞主線程的事件隊列了。

實現思路

那么大致分為幾個模塊

首先是圖片模塊,
這里搞的單例模式,
用于加載圖片給所有人用。
為什么提前加載?
因為不這樣做會很卡。。。

然后是地圖格模塊,
我感覺地圖格在戰棋游戲中還挺重要的,
所以把很多屬性存進去了,
這里只是個DFS可視化,
所有只保留關鍵的一些屬性。

然后是子線程模塊,
主要作用是進行DFS和發送信號。

最后就是widget主窗口,
進行初始化地圖,處理用戶交互等工作。

Pixmaps

比較簡單,比較作用就是加載和存儲圖片。
注意這里不能用餓漢模式,
圖片的加載必須放在QApplication對象創建之后。

pixmaps.h
#ifndef PIXMAPS_H
#define PIXMAPS_H
#include <QPixmap>
class Pixmaps {static Pixmaps *getInstance();
private:Pixmaps();Pixmaps(const Pixmaps&) = delete;static void* _instance;
public:QPixmap map0, map1, map2, map3, dst, src;const int map_width = 100, map_height = 100,unit_width = 80, unit_height = 80;
};
#endif // PIXMAPS_H
pixmaps.cpp
#include "pixmaps.h"
void* Pixmaps::_instance = nullptr; // 這個不能放.h   --  會造成重定義問題// 報錯會提示在其他包含了這個.h文件中, 重定義了_instance
Pixmaps* Pixmaps::getInstance(){if(_instance == nullptr){// 加鎖。。。懶得加了if(_instance == nullptr){_instance = new Pixmaps;}}return (Pixmaps*)_instance;
}Pixmaps::Pixmaps(): map0("://image/map0.png"), map1("://image/map1.png"), map2("://image/map2.png"), map3("://image/map3.png"), map_src("://image/map_src.png"), map_dst("://image/map_dst.png")
{map0 = map0.scaled(map_width, map_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);map1 = map1.scaled(map_width, map_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);map2 = map2.scaled(map_width, map_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);map3 = map3.scaled(map_width, map_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);map_dst = map_dst.scaled(map_width, map_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);map_src = map_src.scaled(map_width, map_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}

單例,只是為了讓別人更方便的用圖片罷了,
所以不用搞太復雜 - - 至少這里不用。

MapSquare

地格類

mapsquare.h
#ifndef MAPSQUARE_H
#define MAPSQUARE_H
#include <QLabel>
#include "pixmaps.h"class MapSquare : public QLabel
{Q_OBJECT
public:MapSquare(QWidget *parent = nullptr);enum UNIT_TYPE{UNIT_TYPE_EMPTY = 0,UNIT_TYPE_PLAYER1 = 1,UNIT_TYPE_PLAYER2 = 2};enum STATUS{STATUS_UNCHECKABLE = -1,STATUS_EMPTY = 0,STATUS_MOVE = 1,STATUS_ATTACK = 2,};void setStatus(STATUS new_status, bool update_pixmap = true);void setUnitType(UNIT_TYPE new_type);void setIndex(int r, int c);void setSrc(int r = -1, int c = -1);void setUnit(void* unit = nullptr);STATUS status(){return _status;}UNIT_TYPE unit_type(){return _unit_type;}int r(){return index_r;}int c(){return index_c;}int src_r() {return _src_r;}int src_c() {return _src_c;}void* unit() {return _unit;}
private:UNIT_TYPE _unit_type;STATUS _status;int index_r, index_c;int _src_r = -1, _src_c = -1;void* _unit = nullptr;
};
#endif // MAPSQUARE_H

嗯,基本是直接cv過來的,enum都沒改,
畢竟要改的話太麻煩了。

這里保留了我們需要用的,
_unit_type,即地格上面有什么,
無、陣營1(這里就是起點)、陣營2(這里就是終點)。

_status,即地格的狀態,
不可達請添加圖片描述、空請添加圖片描述、可抵達 請添加圖片描述、可攻擊請添加圖片描述(這里用來表示DFS找到的路徑)。

r和c,表示地格在地圖中的坐標。

_src_r、_src_c、_unit,這里不用管。

mapsquare.cpp
#include "mapsquare.h"MapSquare::MapSquare(QWidget *parent): QLabel(parent) {int w = Pixmaps::getInstance()->map_width,h = Pixmaps::getInstance()->map_height;setGeometry(-w, -h, w, h);setStatus(STATUS_EMPTY);_unit_type = UNIT_TYPE_EMPTY;
}void MapSquare::setStatus(STATUS new_status, bool update_pixmap){_status = new_status;if(update_pixmap){if(_status == STATUS_UNCHECKABLE){setPixmap(Pixmaps::getInstance()->map0);} else if(_status == STATUS_EMPTY){setPixmap(Pixmaps::getInstance()->map1);} else if(_status == STATUS_MOVE){setPixmap(Pixmaps::getInstance()->map2);} else if(_status == STATUS_ATTACK){setPixmap(Pixmaps::getInstance()->map3);}}
}void MapSquare::setUnitType(UNIT_TYPE new_type) {_unit_type = new_type;
}void MapSquare::setIndex(int r, int c) {index_r = r;index_c = c;
}void MapSquare::setSrc(int r, int c) {_src_r = r;_src_c = c;
}void MapSquare::setUnit(void *unit) {_unit = unit;
}

都是簡單的賦值,應該不必多說吧。

dfsthread

用于DFS的線程,本篇的核心。

dfsthread.h
#ifndef DFSTHREAD_H
#define DFSTHREAD_H#include "mapsquare.h"
#include <QObject>
#include <QWidget>
#include <QThread>
#include <QWaitCondition>
#include <QMutex>class DfsThread : public QThread
{Q_OBJECT
public:explicit DfsThread(QWidget *parent = nullptr);void init(QVector<QVector<MapSquare*>>& _map, int _r, int _c, int _max_step);public:void pause();void resume();void oneStep(bool);protected:void run() override;bool dfs(int r, int c, int step, int max_step);signals:void updateSquare(int r, int c, MapSquare::STATUS status);void dstNotFound();private:QVector<QVector<MapSquare*>>* map; // 這里要不斷更改指向, 所以不能用引用QVector<QVector<bool>> visited;int src_r, src_c, max_step;int r_map, c_map;static const int dx[4];static const int dy[4];
private:bool one_step = false;bool paused = false;QMutex mutex;QWaitCondition pauseCond;
};#endif // DFSTHREAD_H

講講成員變量:
map用來存地圖。
visited用來標記當前走過的路徑。
src_r, src_c 就是起點坐標。
max_step 是最多走多少步。
r_map, c_map 是地圖行、列的數量。
dx,dy 用于控制方向。

嗯,后面幾個是用來控制線程的,
為了達到暫停、單步執行的效果,
用到了鎖和條件變量。

dfsthread.cpp
run dfs
void DfsThread::run()
{{QMutexLocker locker(&mutex);while (paused) {pauseCond.wait(&mutex);}}if (!map) return;if (false == dfs(src_r, src_c, 0, max_step)){emit dstNotFound();}
}

先檢查被暫停沒有,然后開始DFS。

bool DfsThread::dfs(int r, int c, int step, int max_step)
{{QMutexLocker locker(&mutex);while (paused) {pauseCond.wait(&mutex);}}

同樣,每次DFS前檢查一下被暫停沒有。

    if (step > max_step) return false;if (r < 0 || r >= r_map || c < 0 || c >= c_map) return false;if (visited[r][c]) return false;const QVector<QVector<MapSquare*>>& mapRef = *map;if (mapRef[r][c]->status() == MapSquare::STATUS_UNCHECKABLE) return false;visited[r][c] = true; // 標記為已訪問

對當前地格是否可走進行判定,
如果可走,在visited中標記。
接下來的地格將不包括:請添加圖片描述

    // 檢查是否找到目標 (不同陣營)if (mapRef[r][c]->unit_type() != MapSquare::UNIT_TYPE_EMPTY &&mapRef[r][c]->unit_type() != mapRef[src_r][src_c]->unit_type()) {// 找到目標!emit updateSquare(r, c, MapSquare::STATUS_ATTACK);mapRef[r][c]->setSrc(src_r, src_c);QThread::msleep(300);return true;  // 成功找到路徑}

如果找到目標,
發出信號將地格 請添加圖片描述 標記為STATUS_ATTACK 請添加圖片描述
并開始返回。

    if(mapRef[r][c]->status() != MapSquare::STATUS_MOVE){emit updateSquare(r, c, MapSquare::STATUS_MOVE);mapRef[r][c]->setSrc(src_r, src_c);if(one_step) {pause();} else {QThread::msleep(50); // 暫停一段時間}}

如果沒找到,
發出信號將地格 請添加圖片描述 標記為STATUS_MOVE 請添加圖片描述
并判斷是否是單步執行,
如果是,直接暫停線程,
如果不是,那么休眠50ms,
展現出地格是一步步被改變的,
而不是一下就dfs完了。

    for (int i = 0; i < 4; i++) {int x = dx[i] + r;int y = dy[i] + c;if (dfs(x, y, step + 1, max_step)) {// 到了這里, 說明找到了// 那么接著修改地格狀態, 并返回 trueemit updateSquare(r, c, MapSquare::STATUS_ATTACK);QThread::msleep(300);return true;}}// 恢復狀態visited[r][c] = 0;return false;
}
其他
#include "dfsthread.h"
#include <QDebug>const int DfsThread::dx[4] = {0, 0, 1, -1};
const int DfsThread::dy[4] = {1, -1, 0, 0};DfsThread::DfsThread(QWidget *parent): QThread(parent), map(nullptr)
{
}void DfsThread::init(QVector<QVector<MapSquare*>>& _map, int _r, int _c, int _max_step){map = &_map;src_r = _r;src_c = _c;max_step = _max_step;r_map = _map.size();c_map = _map[0].size();// 這里每次都得重新設置一下visited = QVector<QVector<bool>>(r_map, QVector<bool>(c_map, false));
}void DfsThread::pause(){QMutexLocker locker(&mutex);paused = true;
}void DfsThread::resume(){QMutexLocker locker(&mutex);paused = false;pauseCond.wakeAll();
}void DfsThread::oneStep(bool o){one_step = o;
}

我試了一下,
似乎不加鎖和條件變量也行,
不過為了安全還是加上吧。

Widget

UI界面史中史,設計得就是依托。

完整的可以去我的代碼倉庫看,
這里就不列出來了。

Unit
struct Unit : public QPushButton{Unit(QWidget *parent=nullptr): QPushButton(parent){}int r = -1, c = -1;int move_range = 5;MapSquare::UNIT_TYPE unit_type;
};

這個類本來單獨在一個文件里的,被我合過來了。

關于這個類,我寫了幾個函數:

void initUnit(Unit* unit, MapSquare::UNIT_TYPE unit_type);
void moveUnit(Unit* unit, int r, int c);
void connectUnit(Unit* &unit);

一個是初始化,
一個是移動,
一個是連接信號和槽(繼承自按鈕,可點擊)。

initUnit :

void Widget::initUnit(Widget::Unit *unit, MapSquare::UNIT_TYPE unit_type)
{if(unit_type == MapSquare::UNIT_TYPE_PLAYER1)unit->setIcon(Pixmaps::getInstance()->map_src);else if(unit_type == MapSquare::UNIT_TYPE_PLAYER2)unit->setIcon(Pixmaps::getInstance()->map_dst);elseqDebug() << "初始化單位為未定義類型";unit->setIconSize(QSize(80, 80));unit->setStyleSheet("border : transparent;");unit->unit_type = unit_type;
}

傳入一個Unit*,和單位類型,
就能初始化一個單位。

moveUnit

void Widget::moveUnit(Widget::Unit *unit, int r, int c)
{if(unit->r != -1 && unit->c != -1) {map[unit->r][unit->c]->setUnitType(MapSquare::UNIT_TYPE_EMPTY);map[unit->r][unit->c]->setUnit();}unit->setGeometry(map[r][c]->geometry());unit->r = r;unit->c = c;unit->raise();map[r][c]->setUnitType(unit->unit_type);map[r][c]->setUnit(unit);
}

首先得判斷是否剛初始化,
如果已經設置過坐標,
那么得先把原地格的狀態清空,
(感覺還能封裝,地格可以提供一個狀態清空函數)
然后才能移動單位,
并重新設置相關屬性。

connectUnit

void Widget::connectUnit(Widget::Unit* &unit)
{connect(unit, &QPushButton::clicked, this, [&](){qDebug() << "unit clicked ...";if(dfsThreadIsRunning()) return;MapSquare::STATUS _status = map[unit->r][unit->c]->status();if(_status == MapSquare::STATUS_EMPTY) {resetMap(); // 重置地圖dfsThread.init(map, unit->r, unit->c, unit->move_range); // 每次都要初始化dfsThread.start(); // 不能用run, 會阻塞主線程} else {resetMap(); // 重置地圖}});
}

單位被點擊,
如果當前地格狀態為空,
則開始DFS。
如果地格狀態為其他的,
暫時不做處理。

其他
connect(&dfsThread, &DfsThread::updateSquare, this, [this](int r, int c, MapSquare::STATUS status) {qDebug() << "子線程來信號了!" << status;map[r][c]->setStatus(status);
});

這個放在構造函數里,
子線程發來信號,
主線程進行地格的狀態更新。

在這里插入圖片描述


希望本篇文章對你有所幫助!并激發你進一步探索編程的興趣!
本人僅是個C語言初學者,如果你有任何疑問或建議,歡迎隨時留言討論!讓我們一起學習,共同進步!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/77878.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/77878.shtml
英文地址,請注明出處:http://en.pswp.cn/web/77878.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

RHCSA Linux 系統 文件系統權限

1. 文件的一般權限 &#xff08;1&#xff09;文件權限標識解讀 drwxr - xr - x. 12 root root 144 Feb 17 16:51 usr ?d&#xff1a;文件類型&#xff08;d 表示目錄&#xff09; ?rwx&#xff1a;文件所有者權限&#xff08;讀 r&#xff0c;寫 w&#xff0c;執行 x&am…

華為云IoT平臺與MicroPython實戰:從MQTT協議到物聯網設備開發

目錄 前言 1. 華為云 1.1. 創建實例 1.2. 創建產品 1.3. 編輯服務模型 1.4. 注冊設備 1.4.1. 復制設備連接參數 1.5. 連接參考代碼 2. micropython版-物聯網 2.1. 環境搭建 2.2. 實現步驟 2.3. 示例代碼 結語 前言 物聯網&#xff08;IoT&#xff09;技術的快速發…

2025-04-30 AIGC-如何做短片視頻

摘要: 2025-04-30 AIGC-如何做短片視頻 如何做短片視頻: 一、畫圖修圖 1.保存視頻&#xff08;無水保存&#xff09; 2.文案提取&#xff08;提取文案&#xff09; 3. DeepSeek(提示詞&#xff09; 4.小夢Ai&#xff08;圖片視頻&#xff09; 5.修圖Ai 6.擴圖Ai 7.養生…

硬件工程師面試常見問題(10)

第四十六問&#xff1a;鎖存器&#xff0c;觸發器&#xff0c;寄存器三者的區別 觸發器&#xff1a;能夠存儲一位二值信號的基本單元電路統稱為 "觸發器"。&#xff08;單位&#xff09; 鎖存器&#xff1a;一位觸發器只能傳送或存儲一位數據&#xff0c;而在實際工…

外部訪問 Kubernetes 集群中 MQ 服務的方案

外部訪問 Kubernetes 集群中 MQ 服務的方案 當您在 Kubernetes 集群中部署了消息隊列服務&#xff08;如 RabbitMQ、Kafka、ActiveMQ 等&#xff09;后&#xff0c;以下是外部客戶端訪問這些服務的幾種可靠方法&#xff1a; 一、基礎訪問方案 1. NodePort 方式暴露服務 # M…

論文筆記(八十二)Transformers without Normalization

Transformers without Normalization 文章概括Abstract1 引言2 背景&#xff1a;歸一化層3 歸一化層做什么&#xff1f;4 動態 Tanh &#xff08;Dynamic Tanh (DyT)&#xff09;5 實驗6 分析6.1 DyT \text{DyT} DyT 的效率6.2 tanh \text{tanh} tanh 和 α α α 的消融實驗…

軟考中級-軟件設計師 操作系統(手寫筆記)

第一章&#xff1a;基礎知識 第二章&#xff1a;進程管理 狀態轉換圖 進程同步機制 信號量機制 信號量題 死鎖 第三章&#xff1a;存儲管理 基礎知識 分頁存儲管理 分段存儲管理 段頁式存儲管理 頁面置換算法 第四章&#xff1a;文件管理 基礎知識 索引分配 空閑存儲空間的管…

ubuntu 部署moodle

通過地址https://download.moodle.org/releases/latest/選擇下載&#xff0c;下載兩種壓縮包都特別慢&#xff08;有可能無法下載&#xff09;。 可以使用下面git下載項目 注意圖中php、mysql等版本要求&#xff0c;本次采用Ubuntu22.04下 nginxphp8.2mysql8.4部署 mkdir /var…

python實戰項目67:空氣質量在線檢測平臺js逆向

python實戰項目67:空氣質量在線檢測平臺js逆向 一、需求介紹二、完整代碼一、需求介紹 項目需求是獲取某個城市(以北京市為例)歷年(2013年12月至2025年4月)的空氣質量數據,字段包括日期、AQI、質量等級、PM2.5、PM10、NO2、CO、SO2等。改網站的網址是“https://www.aqis…

【Linux】記錄一個有用PS1

PS1 是用來定義shell提示符的環境變量 下面是一個帶有顏色和豐富信息的 Linux PS1 配置示例&#xff0c;包含用戶名、主機名、路徑、時間、Git 分支和退出狀態提示&#xff1a; # 添加到 ~/.bashrc 文件末尾 PS1\[\e[1;32m\]\u\[\e[m\] # 綠色粗體用戶名 PS…

Python PyTorch庫【機器學習框架】全面深入講解與實踐

一、PyTorch 核心概念 1. 定義與發展背景 PyTorch 是由 Facebook AI Research (FAIR) 開發的開源機器學習框架&#xff0c;2016 年首次發布。其核心特性包括&#xff1a; 動態計算圖&#xff08;Define-by-Run&#xff09;GPU 加速張量計算自動微分系統豐富的神經網絡模塊 …

呼叫中心座席管理系統:智能升級,高效服務

在數字化轉型加速的今天&#xff0c;客戶服務體驗已成為企業競爭力的核心要素。傳統 呼叫中心系統 依賴硬件設備、人工操作的模式已無法滿足高效、智能、靈活的現代企業需求。暢信達呼叫中心 座席管理系統 V5.0應運而生&#xff0c;以WEBRTC軟電話接入、智能座席輔助、知識庫管…

時態--00--總述

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 時態句子結構時態標志詞 時態 句子結構 時態標志詞

算法每日一題 | 入門-順序結構-字母轉換

字母轉換 題目描述 輸入一個小寫字母&#xff0c;輸出其對應的大寫字母。例如輸入 q[回車] 時&#xff0c;會輸出 Q。 輸入格式 無 輸出格式 無 輸入輸出樣例 #1 輸入 #1 q輸出 #1 QC 首先我們要知道&#xff0c;C字符的所有轉換形式都是依照ASCII碼來的。 所以&…

晶振:從消費電子到航天領域的時間精度定義者

從手表到衛星&#xff1a;晶振如何在不同領域定義時間精度 在時間的長河中&#xff0c;人類對時間精度的追求永無止境。從古老的日晷到如今精密的計時儀器&#xff0c;每一次進步都離不開技術的革新。而晶振&#xff0c;作為現代計時的核心元件&#xff0c;在不同領域發揮著至…

短視頻矩陣系統貼牌開發實戰:批量剪輯文件夾功能設計與實現

摘要&#xff1a;在短視頻矩陣系統的開發中&#xff0c;批量處理功能是提升運營效率的關鍵。本文將深入探討如何實現基于文件夾的短視頻批量剪輯功能&#xff0c;涵蓋技術選型、核心功能實現及代碼示例。 一、需求背景與場景價值 在短視頻矩陣運營場景中&#xff0c;運營者常面…

讀書筆記--華為從偶然到必然之創新與技術開發閱讀有感

最近繼續閱讀一本講述華為研發投資與管理實踐方面的書籍&#xff0c;分享給大家。華為在創新與技術研發方面有體系化、系統化和延續性。創新是企業的生命線&#xff0c;是企業發展的不竭動力&#xff0c;同時將企業文化與創新精神進行了融合&#xff0c;華為的企業文化強調以客…

基于DeepSeek與HTML的可視化圖表創新研究

一、研究背景 在當今數字化時代&#xff0c;數據呈指數級增長&#xff0c;廣泛滲透于社會各個領域。無論是商業運營、科學研究&#xff0c;還是公共管理等方面&#xff0c;海量數據蘊含著豐富的潛在價值&#xff0c;成為驅動決策優化、推動業務發展、促進科學創新的關鍵要素。數…

K8S - 命名空間實戰 - 從資源隔離到多環境管理

引言 在傳統的物理機或虛擬機環境中&#xff0c;不同業務應用共享資源&#xff0c;容易導致權限沖突、資源爭用和管理混亂。Kubernetes 通過 命名空間&#xff08;Namespace&#xff09;實現資源邏輯隔離&#xff0c;將集群劃分為多個虛擬子集群&#xff0c;從而解決以下問題&…

Unity3D仿星露谷物語開發40之割草動畫

1、目標 當Player選擇Scythe后&#xff0c;鼠標懸浮在草上&#xff0c;會顯示綠色光標。鼠標左擊&#xff0c;會觸發割草的動畫。 2、優化Settings.cs腳本 添加以下兩行代碼&#xff1a; // Reaping&#xff08;收割&#xff09; public const int maxCollidersToTestPerRe…