基於Cocos2d-x-1.0.1的飛機大戰游戲開發實例(中)

来源:http://www.cnblogs.com/Raymond-Kwok/archive/2016/01/14/5131617.html
-Advertisement-
Play Games

接《基於Cocos2d-x-1.0.1的飛機大戰游戲開發實例(上)》三、代碼分析1.界面初始化 1 bool PlaneWarGame::init() 2 { 3 bool bRet = false; 4 do 5 { 6 CC_BREAK_IF(! CCL...


接《基於Cocos2d-x-1.0.1的飛機大戰游戲開發實例(上)》

三、代碼分析

1.界面初始化

 1 bool PlaneWarGame::init()
 2 {
 3     bool bRet = false;
 4     do 
 5     {
 6         CC_BREAK_IF(! CCLayer::init());
 7 
 8         _size = CCDirector::sharedDirector()->getWinSize();
 9 
10         // 設置觸摸可用
11         this->setIsTouchEnabled(true);
12         // 從視窗中取消息
13         CCDirector::sharedDirector()->getOpenGLView()->SetWin32KeyLayer( this );
14 
15         // 初始化游戲背景
16         CC_BREAK_IF(!initBackground());
17         // 菜單1(暫停/聲音/炸彈)
18         CC_BREAK_IF(!initMenu1());
19         // 菜單2(繼續/重新開始/返回)
20         CC_BREAK_IF(!initMenu2());
21         // 菜單3(重新開始/返回)
22         CC_BREAK_IF(!initMenu3());
23 
24         // 創建玩家飛機
25         _player = new PlaySprite;
26         _player->setPosition(CCPointZero);
27         addChild(_player);
28 
29         // 調度器:定時調用自定義的回掃函數
30         this->schedule( schedule_selector(PlaneWarGame::gameLoop));
31         this->schedule( schedule_selector(PlaneWarGame::shoot), 0.1 );
32         this->schedule( schedule_selector(PlaneWarGame::addEnemy), 0.3 );
33         this->schedule( schedule_selector(PlaneWarGame::addProp), 5 );
34 
35         // 初始化兩個數組
36         _enemys = CCArray::array();
37         _enemys->retain();
38         _bullets = CCArray::array();
39         _bullets->retain();
40         
41         // 背景音樂
42         CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic(
43             "planewar/game_music.wav", true);
44 
45         bRet = true;
46     } while (0);
47 
48     return bRet;
49 }

初始化的工作包括:

  • 設置觸摸可用
  •   設置可自定義處理消息
  •       初始化游戲背景
  •   初始化三個菜單(界面菜單/游戲暫停時的菜單/游戲結束時的菜單)
  •   初始化兩個CCArray類型的數組,分別用來存儲有效的敵機精靈對象和子彈對象
  •       設置需要定時調用函數的調度器
  •       設置背景音樂
  •       添加玩家角色

 

2.初始化游戲背景

 1 bool PlaneWarGame::initBackground()
 2 {
 3     // 顯示分數
 4     _label = CCLabelBMFont::labelWithString("0123456789","planewar/font.fnt");
 5     _label->setPosition(ccp(220,_size.height-20));
 6     _label->setColor(ccc3(0,0,0));
 7     this->addChild(_label, 1);
 8 
 9     // 顯示炸彈數量
10     CCLabelBMFont* bombcount = CCLabelBMFont::labelWithString("X09","planewar/font.fnt");
11     bombcount->setAnchorPoint(ccp(0,0));
12     bombcount->setPosition(ccp(73,10));
13     bombcount->setColor(ccc3(0,0,0));
14     addChild(bombcount, 10,111);
15 
16     // 添加背景
17     CCSprite* bg1 = CCSprite::spriteWithFile("planewar/bg1.png");
18     if (!bg1)return false;
19     bg1->setAnchorPoint(ccp(0,1));
20     bg1->setPosition( ccp(0, _size.height) );
21     this->addChild(bg1, 0, 11);
22 
23     bg1->runAction(
24         CCSequence::actions(
25         CCMoveBy::actionWithDuration(10,ccp(0,-720)),
26         CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg1roll)),NULL));
27 
28     CCSprite* bg2 = CCSprite::spriteWithFile("planewar/bg2.png");
29     if (!bg1)return false;
30     bg2->setAnchorPoint(ccp(0,1));
31     bg2->setPosition( ccp(0, _size.height*2) );
32     this->addChild(bg2, 0, 12);
33 
34     bg2->runAction(
35         CCSequence::actions(
36         CCMoveBy::actionWithDuration(20,ccp(0,-1440)),
37         CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg2roll)),NULL));
38     return true;
39 }
40 
41 void PlaneWarGame::bg1roll(){
42     //運動出屏幕重設位置,運動
43     CCSprite * bg = (CCSprite *)getChildByTag(11);
44     bg->setPosition(ccp(0,1440));
45     CCAction* seq = CCSequence::actions(
46         CCMoveBy::actionWithDuration(20,ccp(0,-1440)),
47         CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg1roll)),NULL);
48     bg->runAction(seq);
49 }
50 
51 void PlaneWarGame::bg2roll(){
52     //運動出屏幕重設位置,運動
53     CCSprite * bg = (CCSprite *)getChildByTag(12);
54     bg->setPosition(ccp(0,1440));
55     CCAction* seq = CCSequence::actions(
56         CCMoveBy::actionWithDuration(20,ccp(0,-1440)),
57         CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg2roll)),NULL);
58     bg->runAction(seq);
59 }

 初始化游戲背景時,需要註意的是:要做出飛機向上走的視覺效果,就要把背景向下滾動,這裡使用兩個背景bg1和bg2,大小分別為屏幕大小。初始bg1在屏幕內,bg2在屏幕上方,兩個同事向下運動;當bg1剛剛運動到屏幕外,bg2剛好蓋住屏幕,bg1挪到屏幕上方向下運動...迴圈操作,就能做出迴圈滾動的背景效果了。

 

3.子彈的處理

 1 // 確定子彈類型
 2 void PlaneWarGame::shoot(float dt)
 3 {
 4     if (_isOver)return;
 5     if(_player==NULL) return;
 6 
 7     if(_player->_bulletKind == BK_SINGLE)
 8     {
 9         CCSprite *bullet = CCSprite::spriteWithFile(
10             "planewar/plane.png", CCRectMake(112,2,9,17));
11         addBullet(bullet,_player->getPlayerPt());
12     }else if (_player->_bulletKind == BK_DOUBLE)
13     {
14         CCSprite *bullet = CCSprite::spriteWithFile(
15             "planewar/plane.png", CCRectMake(66,238,8,15));
16         addBullet(bullet,ccp(_player->getPlayerPt().x-20,_player->getPlayerPt().y));
17         CCSprite *bullet1 = CCSprite::spriteWithFile(
18             "planewar/plane.png", CCRectMake(66,238,8,15));
19         addBullet(bullet1,ccp(_player->getPlayerPt().x+20,_player->getPlayerPt().y));
20     }
21 }
22 // 添加子彈
23 void PlaneWarGame::addBullet(CCSprite* bullet, CCPoint pt)
24 {    
25     bullet->setPosition(pt);
26     this->addChild(bullet);
27 
28     bullet->runAction( CCSequence::actions(
29         CCMoveTo::actionWithDuration(0.5, ccp(pt.x,_size.height+bullet->getContentSize().height/2)),
30         CCCallFuncN::actionWithTarget(this,callfuncN_selector(PlaneWarGame::spriteMoveFinished)), 
31         NULL) );
32 
33     bullet->setTag(1);
34     _bullets->addObject(bullet);
35 }
36 // 回收
37 void PlaneWarGame::spriteMoveFinished(CCNode* sender)
38 {
39     CCSprite *sprite = (CCSprite *)sender;
40     this->removeChild(sprite, true);
41     if (sprite->getTag()==1)//子彈
42         _bullets->removeObject(sprite);
43 }

 吃道具可改變子彈類型。子彈的回收方式:從飛機坐標處出發,運動到屏幕外被回收。道具的處理類似。

 

4.設置觸摸/滑鼠點擊控制玩家角色的移動

 1 bool PlaneWarGame::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
 2 {
 3     if(_player==NULL) return false;
 4 
 5     CCPoint pt = CCDirector::sharedDirector()->convertToGL(
 6         pTouch->locationInView(pTouch->view()));
 7 
 8     CCRect rt = _player->getRect();
 9     if (CCRect::CCRectContainsPoint(rt,pt))
10         _player->_isDragEnabled = true;
11     return true;
12 }
13 
14 void PlaneWarGame::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
15 {
16     if(_player==NULL) return;
17 
18     CCSize size = CCDirector::sharedDirector()->getWinSize();
19     CCPoint pt = CCDirector::sharedDirector()->convertToGL(
20         pTouch->locationInView(pTouch->view()));
21     
22     CCRect rt = CCRect(0,0,size.width,size.height);
23 
24     if (_player->_isDragEnabled && CCRect::CCRectContainsPoint(rt,pt))
25         _player->setPlayerPt(pt);
26 }
27 
28 void PlaneWarGame::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
29 {
30     _player->_isDragEnabled = false;
31 }

這裡重寫3個虛函數。移動角色的方式:觸摸/滑鼠按下時,如果點擊位置在角色上,將角色可被拖拽狀態置為true;觸摸/滑鼠移動時,根據角色的可被拖拽狀態和屏幕範圍確定是否移動;觸摸/滑鼠彈起時,將角色的可被拖拽狀態恢復為false。

 

5.碰撞檢測

  1 void PlaneWarGame::updateGame(float dt)
  2 {
  3     CCArray *bulletsToDelete = CCArray::array();
  4     CCObject* it = NULL;
  5     CCObject* jt = NULL;
  6     
  7     if(_player==NULL) return;
  8 
  9     CCRect playerRect = _player->getRect();
 10     // 己方飛機和敵方飛機的碰撞
 11     CCARRAY_FOREACH(_enemys, jt)
 12     {
 13         EnemySprite *enemy = dynamic_cast<EnemySprite*>(jt);
 14         if (!enemy->isNull() && CCRect::CCRectIntersectsRect(playerRect, enemy->getRect()))
 15         {
 16             _player->die();
 17             gameover(false);
 18             return;
 19         }
 20     }
 21 
 22     //////////////////////////////////////////////////////////////////////////
 23         // 道具和角色的碰撞檢測
 24     CCSprite* prop = (CCSprite*)getChildByTag(8);//子彈
 25     if (NULL != prop)
 26     {
 27         CCRect propRect = CCRectMake(
 28             prop->getPosition().x - (prop->getContentSize().width/2),
 29             prop->getPosition().y - (prop->getContentSize().height/2),
 30             prop->getContentSize().width,
 31             prop->getContentSize().height);
 32         if (CCRect::CCRectIntersectsRect(playerRect, propRect))
 33         {
 34             _player->_bulletKind = BK_DOUBLE;
 35             removeChild(prop,true);
 36             CocosDenshion::SimpleAudioEngine::sharedEngine()->
 37                 playEffect("planewar/get_double_laser.wav",false);
 38         }
 39     }
 40     CCSprite* prop1 = (CCSprite*)getChildByTag(9);//炸彈
 41     if (NULL != prop1)
 42     {
 43         CCRect prop1Rect = CCRectMake(
 44             prop1->getPosition().x - (prop1->getContentSize().width/2),
 45             prop1->getPosition().y - (prop1->getContentSize().height/2),
 46             prop1->getContentSize().width,
 47             prop1->getContentSize().height);
 48         if (CCRect::CCRectIntersectsRect(playerRect, prop1Rect))
 49         {
 50             _player->_bombCount++;
 51             removeChild(prop1,true);
 52             CocosDenshion::SimpleAudioEngine::sharedEngine()->
 53                 playEffect("planewar/get_bomb.wav",false);
 54         }
 55     }
 56 
 57     //////////////////////////////////////////////////////////////////////////
 58         // 子彈和敵機的碰撞檢測
 59     CCARRAY_FOREACH(_bullets, it)
 60     for (int i=0; i<_bullets->count(); i++)
 61     {
 62         CCSprite *bullet = dynamic_cast<CCSprite*>(_bullets->objectAtIndex(i));
 63         CCRect bulletRect = CCRectMake(
 64             bullet->getPosition().x - (bullet->getContentSize().width/2),
 65             bullet->getPosition().y - (bullet->getContentSize().height/2),
 66             bullet->getContentSize().width,
 67             bullet->getContentSize().height);
 68 
 69         CCArray* enemysToDelete =CCArray::array();
 70 
 71         CCARRAY_FOREACH(_enemys, jt)
 72         {
 73             EnemySprite *enemy = dynamic_cast<EnemySprite*>(jt);
 74             if (!enemy->_die && CCRect::CCRectIntersectsRect(bulletRect, enemy->getRect()))
 75             {
 76                 if (enemy->_hp>0)
 77                 {
 78                     enemy->_hp--;
 79                     //bulletsToDelete->addObject(bullet);
 80                     _bullets->removeObject(bullet);
 81                     removeChild(bullet,true);
 82                 }
 83                 else if (enemy->_hp<=0)
 84                 {
 85                     //bulletsToDelete->addObject(bullet);
 86                     _bullets->removeObject(bullet);
 87                     removeChild(bullet,true);
 88                     enemysToDelete->addObject(enemy);
 89                 }
 90             }
 91         }
 92 
 93         CCARRAY_FOREACH(enemysToDelete, jt)
 94         {
 95             EnemySprite *enemy = dynamic_cast<EnemySprite*>(jt);
 96             enemy->_die = true;
 97             enemy->die();
 98             _bulletsDestroyed++;
 99         }
100 
101         enemysToDelete->release();
102     }
103 
104     // 釋放已死亡的子彈
105     CCARRAY_FOREACH(bulletsToDelete, it)
106     {
107         CCSprite* projectile = dynamic_cast<CCSprite*>(it);
108         _bullets->removeObject(projectile);
109         this->removeChild(projectile, true);
110     }
111     bulletsToDelete->release();
112 }          

 碰撞檢測使用最簡單的矩形檢測。

 

6.玩家角色的添加和操作

  1 void PlaySprite::onEnter()
  2 {
  3     CCNode::onEnter();
  4 
  5     CCSize size = CCDirector::sharedDirector()->getWinSize();
  6     _sprite = CCSprite::spriteWithFile("planewar/hero1.png");
  7     _sprite->setContentSize(CCSize(62,68));
  8     _sprite->setPosition( ccp(size.width/2,_sprite->getContentSize().height/2) );
  9     addChild(_sprite,10);
 10 
 11     CCAnimation * animation = CCAnimation::animation();
 12     animation->addFrameWithFileName("planewar/hero1.png");
 13     animation->addFrameWithFileName("planewar/hero2.png");
 14     CCAction* action = CCRepeatForever::actionWithAction(
 15         CCAnimate::actionWithDuration(0.1f, animation, false));
 16     action->setTag(11);
 17     _sprite->runAction(action);
 18 
 19     // 調度器
 20     schedule( schedule_selector(PlaySprite::move), 0.002 );
 21 }
 22 
 23 CCRect PlaySprite::getRect()
 24 {
 25     if (_sprite!=NULL)
 26         return CCRect(
 27         _sprite->getPosition().x - (_sprite->getContentSize().width/2),
 28         _sprite->getPosition().y - (_sprite->getContentSize().height/2),
 29         _sprite->getContentSize().width,
 30         _sprite->getContentSize().height);
 31 }    
 32 
 33 CCPoint PlaySprite::getPlayerPt()
 34 {
 35     if (_sprite!=NULL)
 36         return _sprite->getPosition();
 37 }
 38 
 39 void PlaySprite::setPlayerPt(CCPoint pt)
 40 {
 41     if (_sprite!=NULL)
 42         return _sprite->setPosition(pt);
 43 }
 44 
 45 void  PlaySprite::setMoveMode( UINT  message, WPARAM  wParam) 
 46 {
 47     if (message == WM_KEYDOWN)
 48     {// 控制飛機移動
 49         if (wParam == VK_UP)
 50             _mode = MM_UP;
 51         else if (wParam == VK_DOWN)
 52             _mode = MM_DOWN;
 53         else if (wParam == VK_LEFT)
 54             _mode = MM_LEFT;
 55         else if (wParam == VK_RIGHT)
 56             _mode = MM_RIGHT;
 57     }else if (message == WM_KEYUP)
 58     {
 59         if (wParam == VK_UP || wParam == VK_DOWN ||wParam == VK_LEFT||wParam == VK_RIGHT)
 60             _mode = MM_NONE;
 61     }
 62 }
 63 
 64 void PlaySprite::move(float dt)
 65 {
 66     CCSize winSize = CCDirector::sharedDirector()->getWinSize();
 67 
 68     switch(_mode)
 69     {
 70     case MM_NONE:
 71         break;
 72     case MM_UP:
 73         if (getPlayerPt().y<winSize.height)
 74             setPlayerPt(ccp(getPlayerPt().x,getPlayerPt().y+1));
 75         break;
 76     case MM_DOWN:
 77         if (getPlayerPt().y>0)
 78             setPlayerPt(ccp(getPlayerPt().x,getPlayerPt().y-1));
 79         break;
 80     case MM_LEFT:
 81         if (getPlayerPt().x>0)
 82             setPlayerPt(ccp(getPlayerPt().x-1,getPlayerPt().y));
 83         break;
 84     case  MM_RIGHT:
 85         if (getPlayerPt().x<winSize.width)
 86             setPlayerPt(ccp(getPlayerPt().x+1,getPlayerPt().y));
 87         break;
 88     }
 89 }
 90 
 91 void PlaySprite::die()
 92 {
 93     if (_sprite==NULL)return;
 94 
 95     _sprite->stopActionByTag(11);
 96     CCAnimation * animation = CCAnimation::animation();
 97     animation->addFrameWithFileName("planewar/hero_blowup_n1.png");
 98     animation->addFrameWithFileName("planewar/hero_blowup_n2.png");
 99     animation->addFrameWithFileName("planewar/hero_blowup_n3.png");
100     animation->addFrameWithFileName("planewar/hero_blowup_n4.png");
101     _sprite->runAction(CCSequence::actions(
102         CCAnimate::actionWithDuration(0.1f, animation, false),
103         CCCallFunc::actionWithTarget(this, callfunc_selector(PlaySprite::destroy)),NULL));
104 }
105 
106 void PlaySprite::destroy()
107 {
108     if (_sprite==NULL)return;
109     
110     removeChild(_sprite,true);
111     _sprite = NULL;
112 }
  • 玩家角色類是派生自CCNode類,用組合的方式包含一個CCSprite類的成員對象,在玩家角色類內部封裝對精靈的操作。
  • 重寫onEnter函數初始化_sprite成員,設置位置、大小、圖片和幀動畫等。
  • 玩家的方向鍵控制移動和滑鼠拖拽移動方式類似,在操作時設置移動狀態,在schedule定時調用的函數move中根據移動狀態來移動玩家角色。
  • 關於碰撞之後的動畫和銷毀,參照上面的die和destroy函數,對象被碰撞時調用die函數運行爆炸的幀動畫,動畫結束後自動調用destroy函數銷毀對象。
  • 敵機對象的操作和玩家角色類似。

 

四、完成效果圖

經過不到一周的時間,從什麼都沒有,到游戲正常運行、功能完整,體會了cocos2dx的調用機制。

下麵是運行效果圖:

 

如果實現中有什麼問題,歡迎大家在評論中指教!

 

基於Cocos2d-x-1.0.1的飛機大戰游戲開發實例(上)

基於Cocos2d-x-1.0.1的飛機大戰游戲開發實例(下)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Java使用jdbc連接Hive比較簡單,但是Hive的計算能力相對於其它資料庫的SQL而言較弱,要完成非常規的計算需要將數據取出後用Java進一步計算,編程比較麻煩。使用集算器配合Java編程,可以減少Java使用Hive時要進行複雜計算工作量。下麵我們通過例子來看一下具體作法:Hive中的or....
  • package com.pb;import java.io.UnsupportedEncodingException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import jav...
  • https://docs.spring.io/spring-security/site/docs/current/reference/html/headers.html#headers-frame-options
  • JS中 邏輯或 || 邏輯與 && 的使用方法總結 //1、在if判斷中 //if(1==1 || 2==3){}//->兩個條件中只要有一個條件為真,整體就為真 "或者" //if(1==1 && 2==3){}//->兩個條件中只有條件都為真,整體就為真 "並且" //...
  • 之前一直是斷斷續續地進行學習,學了好久之後發覺自己還只是入門水平,於是乎,今日下定決心,以後要系統地學習,並對每天的學習都作一總結。*args和**args的區別:意思就是1還是參數a的值,args表示剩餘的值,kwargs在args之後表示成對鍵值對。程式如下:1 def test(a,*args...
  • 一、面向對象1.1java鍵盤輸入 1.1.1這種方法我認為是最簡單,最強大的,就是用Scanner類import java.util.Scanner; public static void main(String [] args) { Scanner sc = new Scanner(Sys...
  • 這個是用Mac下的Network Utility工具實現ping命令,用Wireshark抓取的ICMP數據包:發送ICMP數據包內容接受ICMP數據包內容一.icmp結構要真正瞭解ping命令實現原理,就要瞭解ping命令所使用到的TCP/IP協議。ICMP(Internet Control Me...
  • 編譯打包 Spark支持Maven與SBT兩種編譯工具,這裡使用了Maven進行編譯打包; 在執行make distribution腳本時它會檢查本地是否已經存在Maven還有當前Spark所依賴的Scala版本,如果不存在它會自動幫你下載到build目錄中並解壓使用;Maven源最好...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...