【cocos2dx】【iOS工程】如何保存用戶在游戲內的繪畫數據,并將數據以圖像形式展示在預覽界面

【cocos2dx】【iOS工程】如何保存用戶在應用內的操作數據,并將數據以圖像形式展示在預覽界面

設備/引擎:Mac(11.6)/Mac Mini

開發工具:Xcode(15.0.1)

開發需求:如何保存用戶在應用內的操作數據,并將數據以圖像形式展示在預覽界面

又到了總結的時候了,之前做過一個涂色類的項目,其中有個技術難點就是怎么保存用戶每次的繪畫數據,并在預覽界面展示用戶之前的繪畫內容。這幾天閑下來就整理整理。

思路:
將用戶的繪畫數據存儲到動態數組中——>每次結束游戲時,遍歷動態數組中的數據并將數據存儲為一個二進制文件——>用戶重新開始游戲時,從保存的二進制文件中加載圖像,再用該圖像初始化一個CCTexture2D對象,再用該紋理對象創建一個新的精靈,最后將精靈顯示在場景中。

簡單說就是兩步,首先保存好數據,最后將數據提出再展示出來
《獲取用戶的涂畫數據》
根據項目的要求,用戶只能在場景內的指定區域來涂色,比如畫板上、動物的各部位色塊上,為了實現只在指定的區域進行涂色,我們使用了自定義的裁剪節點ColoringClippingNode(CCClippingNode類型)。具體如下:
1.創建背景畫布

CCSprite* stencilCanvas = CCSprite::create("DinoColor/canvas.png");
stencilCanvas->setAnchorPoint(ccp(0.0, 0.0));
stencilCanvas->setPosition(CCPointZero);

用來展示用戶將要涂色的圖像或場景,這個也是基礎的背景畫布。
2.創建裁剪節點

ColoringClippingNode* clip = ColoringClippingNode::create(stencilCanvas);
clip->setContentSize(CCSizeMake(stencilCanvas->getContentSize().width, stencilCanvas->getContentSize().height));
clip->setAlphaThreshold(0.0f);
clip->setAnchorPoint(ccp(0.5, 0.5));
clip->setPosition(ccp(stencilCanvas->getContentSize().width/2, stencilCanvas->getContentSize().height/2));

以 stencilCanvas 為裁剪模板,設置裁剪節點的大小,設置裁剪的透明度閾值,設置裁剪節點的錨點和位置。
3.用戶實際的涂色操作
whiteCanvas為自定義的CCSprite類型的ColorSprite類的實例化對象

whiteCanvas = ColorSprite::CreateColor("DinoColor/canvas.png", ccp(stencilCanvas->getContentSize().width/2, stencilCanvas->getContentSize().height/2), this, m_DrawArray->count());
whiteCanvas->curSprName = "ColoringType_"+std::to_string(ColorManager::shared()->curColorTheme+1)+"_"+std::to_string(ColorManager::shared()->colorAniIndex)+"canvas";
whiteCanvas->showLastSceneImage();
whiteCanvas->initBrushNode();
whiteCanvas->setTag(20);

上述代碼依次為:創建畫布->設置當前涂色畫布的名稱(方便后續保存提取對應的數據)->根據保存的涂色數據顯示上次的涂色數據->初始化涂色使用的畫筆節點->設置一個tag值,方便后續獲取。
4.將節點添加到場景中

this->addChild(clip);
m_ClipDrawArray->addObject(clip);
clip->addChild(whiteCanvas);

將裁剪節點添加到當前場景中,將裁剪節點添加到管理裁剪節點的動態數組中,將用戶實際的涂色畫布作為裁剪節點的子節點,確保涂色操作被裁剪到stencilCanvas指定的區域內。
以上通過使用背景畫布、涂色畫布和裁剪節點,就可以實現一個用戶在指定區域內進行涂色操作的功能。

《保存數據》
我們查了一些iOS工程保存數據內容的方法,最后還是決定用二進制形式(.bin格式)來保存用戶的繪畫數據。先看保存部分的代碼

1.創建渲染對象

CCSize sprSize = _colorSpr->getContentSize();
CCRenderTexture* saverenderTexture = CCRenderTexture::create(sprSize.width, sprSize.height, kCCTexture2DPixelFormat_RGBA8888);

_colorSpr就是傳進來的用戶繪畫內容對象,為什么要將該精靈渲染到CCRenderTexture中,簡單說就是為了將用戶繪畫內容繪制到一個紋理上,以便后續將其保存為圖像數據。這個過程類似于在一個虛擬的畫布上繪制 _colorSpr,而不是直接在屏幕上顯示。具體原因如下:
1)離屏渲染:CCRenderTexture允許在內存中創建一個虛擬的渲染目標,而不是直接顯示在屏幕上。通過離屏渲染,可以在不影響屏幕顯示的情況下,捕捉和處理精靈的圖像內容,更隱蔽更安全更方便。
2)捕捉精靈狀態:在游戲中,當我們需要保存當前精靈的狀態,就像現在要保存用戶的繪畫、涂色數據等操作時,將精靈渲染到 CCRenderTexture 中,可以將當前獲取的數據內容保存為一個完整的圖像數據,方便后續使用和存儲。
3)保存為圖像文件:一旦將 _colorSpr 的渲染結果存儲在 CCRenderTexture 中,接下來就可以將其保存為圖像文件(.bin 文件)。這種方式可以將精靈的圖像數據永久化存儲到文件系統中,以便將來讀取、恢復或分享給其他用戶。

2.開始渲染并繪制內容

saverenderTexture->begin();	//開始將渲染目標
_colorSpr->visit();			//調用_colorSpr的visit()方法,用于渲染精靈對象到saverenderTexture上
saverenderTexture->end();	//結束渲染

這部分比較簡單不再贅述。

3.保存為圖像文件

std::string localPath = CCFileUtils::sharedFileUtils()->getWritablePath() + _fileName + ".bin";
CCImage* saveImage = saverenderTexture->newCCImage();
saveImage->saveToFile(localPath.c_str());
saveImage->release();

localPath 是保存文件的本地路徑,使用可寫入路徑加上_fileName(前面自定義的文件名稱)加上.bin 擴展名;
saverenderTexture->newCCImage(); 將 saverenderTexture 轉換為CCImage對象;
saveImage->saveToFile(localPath.c_str()); 將CCImage對象保存為二進制文件;
saveImage->release(); 釋放CCImage對象,避免內存泄漏。
整段內容總結為:將 _colorSpr的渲染內容捕捉并保存為二進制文件
1)為什么要保存為.bin格式
.bin 格式通常是為了將數據以二進制形式存儲到文件中,他也不是指定格式,你可以用它來存儲圖像、音頻、視頻、數據結構、存檔或配置文件、數據庫文件、自定義的一些數據格式等等。
2)以此方式存儲數據的好處
二進制存儲:.bin 文件以二進制形式存儲數據,相比文本文件,可以更有效地存儲和讀取數據。對于像素數據、圖像數據等大量的二進制信息,使用二進制格式可以更節省存儲空間和提高讀寫效率。
數據完整性:二進制文件保存數據時,可以直接以字節流形式寫入數據,不需要轉換為可打印字符(如文本文件)。這樣就可以確保數據在存儲和讀取過程中的完整性,特別是對于圖像、音頻等復雜數據結構。
適合圖像數據:在游戲開發中,如保存精靈的圖像狀態或游戲中的地圖數據或者是繪畫內容數據等等,二進制格式通常更為適合。這些數據通常是復雜的結構化數據,直接以二進制形式存儲可以減少數據解析和轉換的復雜性。

《獲取保存的數據》
獲取數據簡單說就是從指定的**.bin**文件中加載圖像數據,并返回一個CCImage對象,然后再在游戲中進一步處理CCImage對象并顯示出來。
1.從指定的.bin文件中加載圖像數據
1)構建文件路徑:

std::string fullPath = CCFileUtils::sharedFileUtils()->getWritablePath() + _fileName + ".bin";

不再贅述
2)打開文件

FILE* file = fopen(fullPath.c_str(), "rb");
if (!file) {// Handle errorreturn nullptr;
}

使用fopen函數以二進制只讀模式 (“rb”) 打開文件。如果文件打開失敗 (file為nullptr),則返回 nullptr,表示加載失敗。
3)獲取文件大小

fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);

使用fseek和ftell函數來獲取文件大小。首先將文件指針移動到文件末尾 (SEEK_END),然后使用 ftell 獲取當前文件指針的位置,即文件大小。 一旦獲取了文件大小,通常需要將文件指針重新定位到文件的開頭,以便進一步讀取文件內容或者其他操作,也就是最后一行將文件指針移回文件開頭 (SEEK_SET)。
注:獲取文件大小是為了在讀取文件內容之前,知道文件有多大,以便分配足夠大小的內存緩沖區來存儲文件內容
4)分配內存并讀取文件內容

char* buffer = new char[fileSize];
size_t bytesRead = fread(buffer, 1, fileSize, file);

根據文件大小fileSize分配一個足夠大的緩沖區buffer,用于存儲文件內容。使用fread函數從打開的文件中讀取數據,將文件內容讀取到buffer中。
5)創建 CCImage 對象

CCImage* image = new CCImage();
if (!image->initWithImageData(buffer, static_cast<int>(bytesRead))) {// Handle errordelete[] buffer;delete image;return nullptr;
}

使用 CCImage 對象的 initWithImageData 方法,將 buffer 中的二進制數據初始化為 CCImage 對象。如果初始化失敗,釋放buffer和image對象,然后返回nullptr,表示加載圖像數據失敗。
6)清理資源

delete[] buffer;
fclose(file);

成功加載圖像后,釋放 buffer 內存,并關閉文件。
7)返回圖像數據

return image;

2.將獲取到的圖像顯示在游戲內
1)構建文件名

std::string canvasFileName = "ColoringType_"+std::to_string(ColorManager::shared()->curColorTheme+1)+"_"+std::to_string(i+1)+"canvas";

目的是為了獲取到你保存數據時對應的文件名稱,以便加載對應的數據圖像。
2)加載二進制圖像文件

CCImage* canvasImage = ColorManager::shared()->loadImageFromBinaryFile(canvasFileName);

loadImageFromBinaryFile方法內容就是上面所提到的如何提取數據位圖像的內容,不再贅述。
3)初始化紋理對象

if (canvasImage != NULL) {CCTexture2D* canvasTexture = new CCTexture2D();if (canvasTexture && canvasTexture->initWithImage(canvasImage)) {// 創建和設置精靈對象// ...}
}

如果成功加載了 canvasImage,則創建一個 CCTexture2D 對象 canvasTexture,并使用 canvasImage 初始化它。這個步驟是為了將圖像數據轉換為紋理對象,以便后續在精靈中顯示。
4)創建和設置精靈對象

CCSprite* stencilSpr = CCSprite::createWithTexture(CCTextureCache::sharedTextureCache()->addImage("DinoColor/canvas.png"), CCRect(0, 0, 739, 640));
stencilSpr->setAnchorPoint(ccp(0.0, 0.0));
stencilSpr->setPosition(CCPointZero);CCSprite* canvasSpr = CCSprite::createWithTexture(canvasTexture);
canvasSpr->setPosition(ccp(lastscenePos.x+x_x, canvasSpr->getContentSize().height/2));

canvasSpr是加載了從二進制文件中讀取的紋理數據的精靈,設置它的位置,這個精靈將顯示用戶之前涂色的內容。
5)創建裁剪節點并添加精靈

CCClippingNode* clip = CCClippingNode::create(stencilSpr);
clip->addChild(canvasSpr);

CCClippingNode 是一個用于裁剪其子節點顯示區域的節點。用stencilSpr也就是畫板作為裁剪模板,將canvasSpr作為子節點添加到裁剪節點中。這樣做可以確保canvasSpr只在stencilSpr指定的區域內顯示。
PS:除了畫板之外,游戲內還有各動物的各部位也可以涂畫,所以也需要創建他們的精靈對象,方法與上面創建畫板的基本一致,不再贅述。

內容有點多,希望能給大家帶來幫助!!!有什么問題需要討論的可以評論私信歡迎討論~

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

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

相關文章

富格林:抓住正規穩健出金思路

富格林指出&#xff0c;凡事要學會抓住正規思路避繁就簡&#xff0c;才會順利達到終點。在現貨黃金市場中&#xff0c;投資者必須學會抓對正規趨勢&#xff0c;才是走向盈利出金的根本保障。以下是富格林投資總結的幾個觀點和建議&#xff0c;希望能幫助投資者實現穩健出金。 …

算法基礎之分治法

算法原理 對于一個規模為 n n n 的子問題&#xff0c;若該問題可以容易地解決則直接解決&#xff0c;否則將其分解為 k k k 個規模較小的子問題&#xff0c;這些子問題相互獨立且與原問題形式相同。遞歸地解決這些子問題&#xff0c;然后將各子問題的解合并得到原問題的解&a…

單鏈表詳解(2)

三、函數定義 查找節點 //查找結點 SLTNode* SLTNodeFind(SLTNode* phead, SLTDataType x) {assert(phead);SLTNode* pcur phead;while (pcur){if (pcur->data x){return pcur;}pcur pcur->next;}return NULL; } 查找節點我們是通過看數據域來查找的&#xff0c;查…

Arm64 基礎指令集介紹

按照字母排序順序&#xff1a; ● ADC&#xff1a;帶進位加法。 ● ADCS&#xff1a;帶進位加法&#xff0c;設置標志位。 ● ADD (extended register)&#xff1a;擴展寄存器加法。 ● ADD (immediate)&#xff1a;立即數加法。 ● ADD (shifted register)&#xff1a;移位寄存…

【MySQL05】【 undo 日志】

文章目錄 一、前言二、undo 日志&#xff08;回滾日志&#xff09;1. 事務 id2. undo 日志格式2.1 INSERT 對應的 undo 日志2.2 DELETE 對應的 undo 日志2.3 UPDATE 對應的 undo 日志2.3.1 不更新主鍵2.3.2 更新主鍵 2.3 增刪改操作對二級索引的影響2.4 roll_pointer 3. FIL_PA…

Windows 網絡重置

netsh int ip reset 命令是用于重置 Windows 操作系統中的網絡設置和配置的命令。 在網絡故障排除、修復網絡連接問題以及清除可能存在的網絡配置沖突時非常有用。 命令詳解&#xff1a; netsh: 用于配置各種網絡設置 int: 用于管理網絡接口 ip: 用于管理網絡接口的 IP 配…

layui項目中的layui.define、layui.config以及layui.use的使用

第一步:創建一個layuiTest項目&#xff0c;結構如下 第二步&#xff1a;新建一個test.js,利用layui.define定義一個模塊test,并向外暴露該模塊&#xff0c;該模塊里面有兩個方法method1和method2. 第三步&#xff1a;新建一個test.html&#xff0c;在該頁面引入layui.js&#x…

基于FPGA的LDPC編譯碼算法設計基礎知識

基于FPGA的LDPC編譯碼算法設計基礎知識 數字電路&#xff08;數電&#xff09;知識模擬電路&#xff08;模電&#xff09;知識1. 放大器1.1. 晶體管放大器1.2. 運算放大器1.3. 管子放大器&#xff08;真空管放大器&#xff09;微處理器/單片機知識其他相關知識 基于FPGA的算法設…

neo4j 圖數據庫:Cypher 查詢語言、醫學知識圖譜

neo4j 圖數據庫&#xff1a;Cypher 查詢語言、醫學知識圖譜 Cypher 查詢語言創建數據查詢數據查詢并返回所有節點查詢并返回所有帶有特定標簽的節點查詢特定屬性的節點及其所有關系和關系的另一端節點查詢從名為“小明”的節點到名為“小紅”的節點的路徑 更新數據更新一個節點…

python爬蟲和用騰訊云API接口進行翻譯并存入excel,通過本機的Windows任務計劃程序定時運行Python腳本!

項目場景&#xff1a; 提示&#xff1a;這里簡述項目相關背景&#xff1a;定時爬取外網的某個頁面&#xff0c;并將需要的部分翻譯為中文存入excel 接下了的&#xff0c;沒學過的最好看一下 基本爬蟲的學習 【爬蟲】requests 結合 BeautifulSoup抓取網頁數據_requests beauti…

Vue CoreVideoPlayer 一款基于 vue.js 的輕量級、優秀的視頻播放器組件

大家好,我是程序視點的小二哥!今天小二哥給大家推薦一款非常優秀的視頻播放組件 效果欣賞 介紹 Vue-CoreVideoPlayer 一款基于vue.js的輕量級的視頻播放器插件。 采用Adobd XD進行UI設計&#xff0c;支持移動端適配,不僅功能強大&#xff0c;顏值也是超一流&#xff01; Vue-…

第一次構建一個對話機器人流程解析(二)

1. 問答機器人的組成-基于知識圖譜的搜索 在教育場景下&#xff0c;若學生有關于學習內容的提問&#xff0c;或業務層面的提問&#xff0c;則要求問答機器人的回答必須精準&#xff0c;來滿足業務的要求因此需要通過知識圖譜來快速檢索&#xff0c;所提內容的相關信息&#xf…

數字系統與進制轉換

數字系統 數字邏輯是計算機科學的基礎&#xff0c;它研究的是如何通過邏輯門電路&#xff08;與門、或門、非門等&#xff09;實現各種邏輯功能。數字系統則是由數字邏輯電路組成的系統&#xff0c;可以實現各種復雜的運算和控制功能。在計算機科學中&#xff0c;數字邏輯和數…

C++ 假設今天是星期日,那么過a^b天之后是星期幾?

題目 假設今天是星期日&#xff0c;那么過a^b天之后是星期幾&#xff1f; 【輸入】 兩個正整數a&#xff0c;b&#xff0c;中間用單個空格隔開。0<a≤100,0<b≤10000。 【輸出】 一個字符串&#xff0c;代表過a^b天之后是星期幾。 其中&#xff0c;Monday是星期一&…

自定義波形圖View,LayoutInflater動態加載控件保存為本地圖片

效果圖: 頁面布局: <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="…

C#多線程并行計算實例

在C#中實現多線程并行計算可以通過使用 Task 和 Parallel 類來實現。這里給出兩個簡單的示例&#xff0c;一個是使用 Task&#xff0c;另一個是使用 Parallel.ForEach。 使用 Task 進行多線程并行計算 using System; using System.Threading.Tasks;class Program {static voi…

Kubernetes基于helm部署jenkins

Kubernetes基于helm安裝jenkins jenkins支持war包、docker鏡像、系統安裝包、helm安裝等。在Kubernetes上使用Helm安裝Jenkins可以簡化安裝和管理Jenkins的過程。同時借助Kubernetes&#xff0c;jenkins可以實現工作節點的動態調用伸縮&#xff0c;更好的提高資源利用率。通過…

MySQL Innodb存儲引擎中,當頁默認的大小是16K時,頁中最多存放多少行的記錄?

1、題目引入 Innodb存儲引擎是面向行的(row-oriented)&#xff0c;也就是說數據的存放按行進行&#xff0c;每頁存放的行記錄是有硬性定義的&#xff0c;當頁默認的大小是16K時&#xff0c;頁中最多存放多少行的記錄&#xff1f; A、1600 行B、8192 行C、16383 行D、7992 行 …

基于Python協同過濾的旅游景點推薦系統,采用Django框架,MySQL數據存儲,Bootstrap前端,echarts可視化實現

隨著旅游業的迅速發展&#xff0c;個性化旅游推薦系統成為提升用戶體驗和促進旅游市場增長的重要工具。本研究旨在設計并實現一種基于Python協同過濾的旅游景點推薦系統&#xff0c;結合Django框架、MySQL數據庫存儲、Bootstrap前端框架以及echarts數據可視化技術&#xff0c;為…

Flask發布一個及時止損(止盈)服務(二)

生成可視化的止盈止損結果&#xff08;圖片&#xff09; 媽的&#xff0c;還是得用 akshare&#xff0c;還需要指定python版本3.9以上 conda remove -n fonxsys --all conda search pythonconda create -n fonxsys python3.9 conda activate fonxsys python.exe -m pip insta…