控件(1)-使用URL創(chuàng)建的Sprite

你可以使用圖片名創(chuàng)建一個(gè)Sprite,可以使用預(yù)加載好的紋理創(chuàng)建一個(gè)Sprite,但是引擎沒(méi)有提供一個(gè)使用url來(lái)創(chuàng)建Sprite的方法。

在游戲中每次遇到需要從服務(wù)端獲取一個(gè)玩家的頭像url,然后通過(guò)這個(gè)url獲取玩家頭像并顯示的時(shí)候,我就會(huì)想,如果能直接用url創(chuàng)建Sprite該多好。
需要顯示配置在服務(wù)端的推廣圖片時(shí)。。。
需要顯示配置在服務(wù)端的商品列表時(shí)。。。


其實(shí)很早就想寫(xiě)這樣一個(gè)控件了,只是一直想在其之上附加各種功能(預(yù)加載? 默認(rèn)紋理? 使用本地緩存?等),導(dǎo)致自己一直想不明白要做什么,也就是需求不明確。今天終于沉下心來(lái)實(shí)現(xiàn)了一下這個(gè)URLSprite。

需求

1.使用url創(chuàng)建Sprite
2.可以設(shè)置默認(rèn)texture
3.下載好的資源保存在本地,并且可以指定文件名
4.可以使用已下載好的本地資源

大致思路

1.URLSprite繼承自Sprite
2.使用一個(gè)Texture2D指針保存默認(rèn)紋理
3.使用cocos2d引擎提供的HttpClient來(lái)下載圖片
4.使用FILE將圖片保存在本地
5.使用cocos2d引擎的FileUtils來(lái)查找本地資源


URLSprite

先來(lái)看看URLSprite的頭文件:

//
//  QFLURLSprite.hpp
//  MyTemplet
//
//  Created by QuFangliu on 2017/1/4.
//  Copyright ? 2017年 qufangliu. All rights reserved.
//
//  使用URL創(chuàng)建一個(gè)Sprite,可以設(shè)置默認(rèn)texture,對(duì)象可以自動(dòng)使用HttpClient來(lái)下載圖片資源

#ifndef QFLURLSprite_hpp
#define QFLURLSprite_hpp

#include <stdio.h>
#include "cocos2d.h"
#include "network/HttpClient.h"

/*
 QFLURLSprite的狀態(tài)
 */
enum QFLURLSprite_State{
    URLSprite_State_NoTexture = 0,  //無(wú)紋理
    URLSprite_State_Default = 1,    //默認(rèn)紋理
    URLSprite_State_Loaded = 2,     //下載好的紋理(或者使用指定的本地文件)
};

/*
 URLSprite
 */
class QFLURLSprite : public cocos2d::Sprite
{
CC_CONSTRUCTOR_ACCESS:
    QFLURLSprite();
    virtual ~QFLURLSprite();
    
public:
    
    /*
        Create
     */
    static QFLURLSprite* create();
    static QFLURLSprite* create(const std::string &strURL);
    //指定(已)下載好的文件名,并且選擇是否直接使用本地資源
    static QFLURLSprite* create(const std::string &strURL, const std::string &strFileName, bool bForceRefresh);
    
    /*
        Init
     */
    virtual bool init();
    virtual bool initWithURL(const std::string &strURL);
    virtual bool initWithConfig(const std::string &strURL, const std::string &strFileName, bool bForceRefresh);
    
    /*
        Refresh
     */
    void refresh(bool bShowDefault = false);
    
    void loadImage();
    void loadImageCallback(cocos2d::network::HttpClient* pClient, cocos2d::network::HttpResponse* pResponse);
    
    /*
        Default Texture
     */
    void setDefaultTexture(cocos2d::Texture2D* pTexture);
    cocos2d::Texture2D* getDefaultTexture() { return m_pDefaultTexture; }
    
    /*
        Config
     */
    CC_SYNTHESIZE(std::string, m_strURL, SpriteURL);        //圖片的下載地址
    CC_SYNTHESIZE(std::string, m_strName, FileName);        //下載好后或者指定的文件名
    CC_SYNTHESIZE(bool, m_bForceRefresh, ForceRefresh);     //是否強(qiáng)制刷新,false則找到本地文件就不刷新
    
private:
    /*
        tools
     */
    std::string getFileNameByURL(const std::string &strURL);
    std::string checkNativeFile(const std::string &strName);
    
    cocos2d::Texture2D* m_pDefaultTexture;  //默認(rèn)紋理
    QFLURLSprite_State m_eState;            //狀態(tài)
};

#endif /* QFLURLSprite_hpp */

創(chuàng)建方式模仿了Cocos2d引擎的Sprite的二段構(gòu)建方法,即重載不同的create方法,在create中去找對(duì)應(yīng)的init方法,真正進(jìn)行Sprite的初始化。

然后使用了一個(gè)枚舉來(lái)標(biāo)志URLSprite的狀態(tài),在setDefaultTexture時(shí),如果當(dāng)前不是使用的url指定的圖片,則顯示默認(rèn)紋理。

另外還提供了refresh方法,以供控件的重用。

上面代碼比較簡(jiǎn)單,基本都有說(shuō)明了,這里就不贅述了。

下面把cpp文件也粘貼出來(lái),懶得去看Github的童鞋可以用這個(gè),但不保證此處是最新版本。

//
//  QFLURLSprite.cpp
//  MyTemplet
//
//  Created by QuFangliu on 2017/1/4.
//  Copyright ? 2017年 qufangliu. All rights reserved.
//

#include "QFLURLSprite.hpp"

USING_NS_CC;
using namespace network;

QFLURLSprite::QFLURLSprite()
{
    m_strURL = "";
    m_strName = "";
    m_bForceRefresh = true;
    m_pDefaultTexture = nullptr;
    m_eState = QFLURLSprite_State::URLSprite_State_NoTexture;
}

QFLURLSprite::~QFLURLSprite()
{
    
}

QFLURLSprite* QFLURLSprite::create()
{
    QFLURLSprite* pSprite = new (std::nothrow) QFLURLSprite();
    
    if (pSprite && pSprite->init()) {
        pSprite->autorelease();
        return pSprite;
    }
    else {
        CC_SAFE_DELETE(pSprite);
        return nullptr;
    }
}

QFLURLSprite* QFLURLSprite::create(const std::string &strURL)
{
    QFLURLSprite* pSprite = new (std::nothrow) QFLURLSprite();
    
    if (pSprite && pSprite->initWithURL(strURL)) {
        pSprite->autorelease();
        return pSprite;
    }
    else {
        CC_SAFE_DELETE(pSprite);
        return nullptr;
    }
}

QFLURLSprite* QFLURLSprite::create(const std::string &strURL, const std::string &strFileName, bool bForceRefresh)
{
    QFLURLSprite* pSprite = new (std::nothrow) QFLURLSprite();
    
    if (pSprite && pSprite->initWithConfig(strURL, strFileName, bForceRefresh)) {
        pSprite->autorelease();
        return pSprite;
    }
    else {
        CC_SAFE_DELETE(pSprite);
        return nullptr;
    }
}

bool QFLURLSprite::init()
{
    if (Sprite::init()) {
        return true;
    }
    else {
        return false;
    }
}

bool QFLURLSprite::initWithURL(const std::string &strURL)
{
    if (Sprite::init()) {
        m_strURL = strURL;
        m_strName = this->getFileNameByURL(m_strURL);
        
        //下載圖片
        this->refresh();
        return true;
    }
    else {
        return false;
    }
}

bool QFLURLSprite::initWithConfig(const std::string &strURL, const std::string &strFileName, bool bForceRefresh)
{
    if (Sprite::init()) {
        m_strURL = strURL;
        m_strName = strFileName;
        m_bForceRefresh = bForceRefresh;
        
        if (m_bForceRefresh) {
            this->refresh();
        }
        else {
            //查找紋理
            auto pTexture = Director::getInstance()->getTextureCache()->getTextureForKey(strFileName);
            if (pTexture) {
                m_eState = QFLURLSprite_State::URLSprite_State_Loaded;
                this->initWithTexture(pTexture);
            }
            else {
                //查找本地文件
                std::string strNative = this->checkNativeFile(m_strName);
                if (strNative != "") {
                    m_eState = QFLURLSprite_State::URLSprite_State_Loaded;
                    this->initWithFile(strNative);
                }
                else {
                    //下載圖片
                    this->refresh();
                }
            }
        }
        return true;
    }
    else {
        return false;
    }
}

//下載圖片的邏輯
void QFLURLSprite::refresh(bool bShowDefault)
{
    if (bShowDefault && m_pDefaultTexture) {
        m_eState = QFLURLSprite_State::URLSprite_State_Default;
        this->setTexture(m_pDefaultTexture);
    }
    else {}
    
    if (m_strURL.empty()) {
        CCLOG("Invalid url!");
        return;
    }
    else {}
    
    if (m_strName.empty()) {
        m_strName = this->getFileNameByURL(m_strURL);
    }
    else {}
    
    this->loadImage();
}

void QFLURLSprite::loadImage()
{
    HttpRequest* pRequest = new (std::nothrow) HttpRequest();
    if (pRequest) {
        pRequest->setUrl(m_strURL.c_str());
        pRequest->setRequestType(cocos2d::network::HttpRequest::Type::GET);
        pRequest->setTag("LoadImage");
        pRequest->setResponseCallback(CC_CALLBACK_2(QFLURLSprite::loadImageCallback, this));
        
        HttpClient::getInstance()->send(pRequest);
        
        pRequest->release();
        
        //防止被刪除
        CC_SAFE_RETAIN(this);
    }
    else {
        CC_SAFE_DELETE(pRequest);
        CCLOG("Can not create HttpRequest!");
    }
}

void QFLURLSprite::loadImageCallback(cocos2d::network::HttpClient *pClient, cocos2d::network::HttpResponse *pResponse)
{
    //和load對(duì)應(yīng)
    CC_SAFE_RELEASE(this);
    
    if (this->getReferenceCount() == 0) {
        return;
    }
    else {}
    
    if (pResponse) {
        if (pResponse->isSucceed()) {
            //保存請(qǐng)求的圖片數(shù)據(jù)
            std::vector<char>* pBuffer = pResponse->getResponseData();
            std::string strBuffer = std::string(pBuffer->begin(), pBuffer->end());
            std::string strPath = FileUtils::getInstance()->getWritablePath() + m_strName;
            
            //圖片保存到本地
            FILE *pFile = fopen(strPath.c_str(), "wb+");
            fwrite(strBuffer.c_str(), 1, strBuffer.size(), pFile);
            fclose(pFile);
            
            //使用下載的圖片
            m_eState = QFLURLSprite_State::URLSprite_State_Loaded;
            this->setTexture(strPath);
        }
        else {
            CCLOG("Request error:%s", pResponse->getErrorBuffer());
        }
    }
    else {
        CCLOG("Request failed!");
    }
}

void QFLURLSprite::setDefaultTexture(cocos2d::Texture2D *pTexture)
{
    m_pDefaultTexture = pTexture;
    
    if (m_eState != QFLURLSprite_State::URLSprite_State_Loaded) {
        m_eState = QFLURLSprite_State::URLSprite_State_Default;
        this->initWithTexture(m_pDefaultTexture);
    }
    else {}
}

std::string QFLURLSprite::getFileNameByURL(const std::string &strURL)
{
    return strURL.substr(strURL.find_last_of("/") + 1);
}

std::string QFLURLSprite::checkNativeFile(const std::string &strName)
{
    std::string strPath = "";
    
    //查找項(xiàng)目資源
    strPath = FileUtils::getInstance()->fullPathForFilename(strName);
    if (FileUtils::getInstance()->isFileExist(strPath)) {
        return strPath;
    }
    else {}
    
    //查找讀寫(xiě)路徑下的資源
    strPath = FileUtils::getInstance()->getWritablePath() + strName;
    if (FileUtils::getInstance()->isFileExist(strPath)) {
        return strPath;
    }
    else {}
    
    return "";
}

代碼比較簡(jiǎn)單,也沒(méi)有周詳?shù)娜ハ朊恳粋€(gè)細(xì)節(jié)。例如如果url指向的不是一個(gè)可用的圖片,而是一個(gè)mp3文件,要如何處理?寫(xiě)文件很慢要不要另外啟動(dòng)一個(gè)異步線程來(lái)做?
這些需要的時(shí)候再優(yōu)化啦~


如果小伙伴們發(fā)現(xiàn)有問(wèn)題,或者有更好的實(shí)現(xiàn)方式,或者其他建議,歡迎聯(lián)系噢~

下一個(gè)UI就做個(gè)道具列表吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 我選擇開(kāi)發(fā)一個(gè)游戲有很多原因。我覺(jué)得自己是“核心”玩家,過(guò)去的大部分時(shí)間我都花在玩游戲,自己制作、閱讀和游戲...
    月影檀香閱讀 12,458評(píng)論 1 27
  • 在開(kāi)發(fā)iOS應(yīng)用程序時(shí),讓程序具有良好的性能是非常關(guān)鍵的。這也是用戶所期望的,如果你的程序運(yùn)行遲鈍或緩慢,會(huì)招致用...
    imkakaxi閱讀 1,126評(píng)論 0 0
  • v3.0 亮點(diǎn) @來(lái)自官網(wǎng) 使用 C++(C++11) 的特性取代了 Objective-C 的特性優(yōu)化了 Lab...
    光明程輝閱讀 1,179評(píng)論 0 1
  • 本文由子龍山人原創(chuàng),原文鏈接:http://www.zilongshanren.com/cocos2d-x-des...
    光明程輝閱讀 3,019評(píng)論 0 2
  • 物質(zhì)身體是我的嗎?物質(zhì)身體是我嗎? 手機(jī)是我的,手機(jī)受我的控制,但是我的物質(zhì)身體不受我控制。 這個(gè)邏輯是什么?怎么...
    大杜915閱讀 1,029評(píng)論 0 1

友情鏈接更多精彩內(nèi)容