Cocos2d-x for WindowsPhone:開發一個打地鼠游戲(下)


上一篇中簡單的實現了打地鼠的游戲雛形,一個好的游戲需要很多次的調試和長時間打磨,才能成為有趣的產品,而不是一段段的代碼,前面一篇中使用了最簡單的方式生成了靜態界面,這次我們將整合動畫着重使用CCActionInterval派生出來的各種行為類做出有趣的游戲,那么現在開始吧。

 

  行為動畫

CCActionInterval是Cocos2d中常用的行為類,它的派生類分管各種不同對象,產生不同的結果,這個模式在一些游戲引擎中有的叫做腳本,有的叫做控制器,剛開始用的時候可能有點暈,但是隨着使用次數的增加就會越來越熟悉,今天我將使用到如下幾個行為來實現游戲的動畫效果:

CCDelayTime:延遲行為,它僅僅是一個定時器,設定好時間,行為會在指定的時間后結束

CCAnimate和CCAnimation:動畫行為類,它們組合在一起可以控制一個CCSprite的幀動畫

CCCallFunc:呼叫行為類,指定一個回調函數,執行的時候就會調用

CCSequence:行為隊列類,它可以將幾個行為組合起來,這樣就不需要定時的去判斷邏輯了,比如一個延遲行為加上回調行為,就會達到在延遲指定時間后回調指定函數的效果

除了這些還有很多有用的行為類,但是僅用這些就已經足夠了。

例如下面的代碼:

CCDelayTime delayTime = CCDelayTime.actionWithDuration(DelaySecond);
delayAction = CCSequence.actionOneTwo(delayTime, CCCallFunc.actionWithTarget(this, showCompled));
this.runAction(delayAction);

這個代碼換成圖片表示則是這樣的

image

如果仔細看過你會發現CCSequence也是一個CCActionInterval,它的作用就是將多個行為組合起來達到連貫,這是一個很有趣的方法,你能用它做很多有趣的行為,上面代碼中為延遲DelaySecond秒之后回調showCompled方法,在最后的代碼中你會發現這種方式被用了三次在不同的地方達到不同的效果。

那么,除了延遲,還有動畫也可以組合,這樣我們可以很准確的知道某個動畫結束后的事件,例如:

//鑽出動畫
CCAnimation marmotShowanimation = CCAnimation.animationWithFrames(frames,0.1f);
CCAnimate action = CCAnimate.actionWithAnimation(marmotShowanimation, false);
showAction = CCSequence.actionOneTwo(action, CCCallFunc.actionWithTarget(this, callback));
body.runAction(showAction);

這個代碼的意思是通過frames幀序列創建一個動畫行為,然后使用Animate嵌套使其播放,執行的目標是body這個CCSprite,當播放結束之后就會執行callback方法。

行為動畫在游戲當中舉足輕重,本例中使用的是最簡單的單個圖片序列的方式播放,其實,使用cocos2d的動畫plist更加簡便,但是單來說設計工具就比較繁瑣,因此我計划在后面篇章專門說動畫的制作和代碼。

 

  文字顯示

在現在cocos2dxna版本中還不能直接顯示文字和其他的平台狀況差不多,顯示英文和數字可以使用其他版本方法,這方面引擎提供了多個類來解決,其中最簡單的是CCLabelTTF,它不需要獨立載入文字序列,也不需要指定來源圖片,直接在屏幕的位置上顯示一行指定的英文和數字的字符,例如:

label_Score = CCLabelTTF.labelWithString("0", "Arial", 24);
label_Score.Color = new ccColor3B(255, 0, 0);
label_Score.anchorPoint = new CCPoint(1, 0.5f);
this.addChild(label_Score);
label_Score.position = new CCPoint(CCDirector.sharedDirector().getWinSize().width - 24, CCDirector.sharedDirector().getWinSize().height - 24);

這行的意思是在屏幕的右上角顯示了一個0的字符,更改的時候也很簡單,直接:

label_Score.setString(“999”);

我們用這個部分顯示打中地鼠時候的積分。

 

  聲音

聲音系統在cocos2dxna當中是一個獨立的類,在命名空間CocosDenshion當中SimpleAudioEngine可以播放音樂、聲效等,用法也很簡單:

//播放被打擊的聲音
SimpleAudioEngine.sharedEngine().playEffect(CCFileUtils.fullPathFromRelativePath("Sounds/sound43"));

在這之前需要將聲音添加到Hit_MoleContent即可

image

 

  完成

image

本工程源代碼在此下載

代碼其實非常的簡單,只有兩個cs文件,一個Mole一個Scene1,已經加入了注釋,期望大家看起來不會那么費勁。

第一個類:Mole

using cocos2d;
using System.Collections.Generic;
using CocosDenshion;

namespace Hit_Mole
{
    public class Mole : CCMenuItemSprite
    {
        CCSprite body;
        CCSprite hideimage;
        CCActionInterval showAction;
        CCActionInterval delayAction;
        //動畫序列幀
        static List frames ;
        public Mole(Scene1 root, SEL_MenuHandler selector)
        {
            //讀取一張“鼠洞”的圖片並添加到菜單項里,它將作為底背景
            CCSprite hole = CCSprite.spriteWithFile("Hole");
            hole.anchorPoint = new CCPoint(0, 0);
            this.addChild(hole);
            //讀取一張鼴鼠身體的圖片並設置為默認的圖像
            body = CCSprite.spriteWithFile("marmot_3");
            NormalImage = body;
            //讀取一張鼴鼠被選擇(點擊)時候顯示的圖像
            SelectedImage = CCSprite.spriteWithFile("marmot_4");
            //隱蔽時發生出現的圖像,在本篇中暫時無用,所以它是不可見的
            hideimage = CCSprite.spriteWithFile("marmot_5");
            hideimage.anchorPoint = new CCPoint(0, 0);
            hideimage.visible = false;
            this.addChild(hideimage);
            //初始化選擇器,Hit將發生與被點擊時候的狀態
            initWithTarget(root, selector);
            //設置內容的大小,用繼承類時,contentSize不會被刷新,需要自己指定
            contentSize = body.contentSize;
            body.visible = false;
            //創建靜態的幀列表,這樣做的目的是防止多次創建無用的CCSpriteFrame
            if (frames == null)
            {
                frames = new List();
                for (int i = 1; i < 4; i++)
                {
                    CCTexture2D texture = CCTextureCache.sharedTextureCache().addImage("marmot_" + i);
                    //這里存在一個引擎的bug,如果不設置的話,就會播放不出來動畫
                    texture.Name = (uint)i;
                    var frame = CCSpriteFrame.frameWithTexture(texture, new CCRect(0, 0, texture.ContentSizeInPixels.width, texture.ContentSizeInPixels.height));
                    frames.Add(frame);
                }
            }
            m_bIsEnabled = false;
        }
        //出現方法,調用此方法時,會創建鼴鼠鑽出動畫並執行
        public void Show()
        {
            IsShow = true;
            body.visible = true;
            //鑽出動畫
            CCAnimation marmotShowanimation = CCAnimation.animationWithFrames(frames,0.1f);
            CCAnimate action = CCAnimate.actionWithAnimation(marmotShowanimation, false);
            showAction = CCSequence.actionOneTwo(action, CCCallFunc.actionWithTarget(this, callback));
            //讓body身體執行鑽出動畫
            body.runAction(showAction);
            //延遲行為控制鑽回去的動作
            CCDelayTime delayTime = CCDelayTime.actionWithDuration(DelaySecond);
            delayAction = CCSequence.actionOneTwo(delayTime, CCCallFunc.actionWithTarget(this, showCompled));
            this.runAction(delayAction);
        }
        //延遲多久會鑽回去
        public float DelaySecond = 2;
        //鑽回去的方法
        public void Hide()
        {
            //立即停止各種行為
            stopAction(showAction);
            stopAction(delayAction);
            //現在是不可點擊
            IsShow = false;
            //執行一個延遲行為,鑽回動作完成后將動畫重置
            CCDelayTime delayTime = CCDelayTime.actionWithDuration(0.3f);
            var timespan = CCSequence.actionOneTwo(delayTime, CCCallFunc.actionWithTarget(this, hideCompled));
            body.visible = false;
            hideimage.visible = true;
            runAction(timespan);
        }
        private void callback()
        {
            
        }
        //鑽出完成時的回調
        private void showCompled()
        {
            SimpleAudioEngine.sharedEngine().playEffect(CCFileUtils.fullPathFromRelativePath("Sounds/sound63"));
            Hide();
        }
        //鑽入完成時的回調
        private void hideCompled()
        {
            hideimage.visible = false;
        }
        //使用一個屬性標識現在是否可點擊
        public bool IsShow
        {
            set { base.m_bIsEnabled = value; }
            get { return base.m_bIsEnabled; }
        }
        //用此屬性判定是否可點擊
        public override void selected()
        {
            if (IsShow)
                base.selected();
        }
    }
}

 

 

第二個類:Scene1

using cocos2d;
using System.Collections.Generic;
using System;
using CocosDenshion;

namespace Hit_Mole
{
    public class Scene1 : CCScene
    {
        Random _randome = new Random((int)DateTime.Now.Ticks);
        CCLabelTTF label_Score;
        List _molelist = new List();
        public Scene1()
        {
            //初始化
            initialize();
        }
        public bool initialize()
        {
            //L1
            //從Hit_MoleContent里面讀取scene.jpg的圖像成為游戲當中的一個精靈
            CCSprite background = CCSprite.spriteWithFile("scene");
            //將錨點設置到(0,0)處,單張圖片的讀取默認錨點在(0.5f,0.5f)處
            background.anchorPoint = new CCPoint(0, 0);
            //將背景添加到場景中
            this.addChild(background);

            //L2
            //取得當前窗口的寬
            var w = CCDirector.sharedDirector().getWinSize().width / 4;
            //取得高,並偏移80像素
            var h =( CCDirector.sharedDirector().getWinSize().height - 80) / 3;
            //聲明一個CCMenuItemSprite數組
            Mole[] moles = new Mole[4 * 3];
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    //建立一個地鼠的菜單(按鈕),並且按照4*3的方式排列
                    Mole mole = new Mole(this, onClick);
                    mole.position = new CCPoint(i * w + w / 2,j * h + h / 2);                    
                    moles[j * 4 + i] = mole;                    
                }
            }
            _molelist.AddRange(moles);
            //創建CCMenu
            var menus = CCMenu.menuWithItems(moles);
            //菜單項目默認position是在父節點容器的中間,所以要把他們移動到0,0處
            menus.position = new CCPoint(0, 0);
            this.addChild(menus);
            //L3
            //顯示一段文字
            label_Score = CCLabelTTF.labelWithString("0", "Arial", 24);
            label_Score.Color = new ccColor3B(255, 0, 0);
            label_Score.anchorPoint = new CCPoint(1, 0.5f);
            this.addChild(label_Score);
            label_Score.position = new CCPoint(CCDirector.sharedDirector().getWinSize().width - 24, CCDirector.sharedDirector().getWinSize().height - 24);

            beginTimeSpan(2);

            return base.init();
        }
        void beginTimeSpan(float second)
        {
            //延遲指定的循環回調,用來解決每段時間就會鑽出來鼴鼠的邏輯
            CCDelayTime delayTime = CCDelayTime.actionWithDuration(second);
            var action = CCSequence.actionOneTwo(delayTime, CCCallFunc.actionWithTarget(this, loopCallback));
            this.runAction(action);
        }
        //分數
        int _valuescore = 0;
        //分數屬性,同時刷新顯示的文字
        int valueScore
        {
            get { return _valuescore; }
            set
            {
                _valuescore = value;
                label_Score.setString(value.ToString());
            }
        }
        //被點擊的回調
        public void onClick(CCObject sender)
        {
            //分數+1
            valueScore += 1;
            if ((sender as Mole).IsShow)
            {
                (sender as Mole).Hide();
                //播放被打擊的聲音
                SimpleAudioEngine.sharedEngine().playEffect(CCFileUtils.fullPathFromRelativePath("Sounds/sound43"));
            }
        }
        //循環回調用的方法
        public void loopCallback()
        {
            //這里通過簡單計算使得鼴鼠出來的越來越快
            float sub = 1 - (float)valueScore / 20.0f;
            if (sub <= 0)
                sub = 0;
            beginTimeSpan(0.5f + sub);
            SetAllMoleDelaySecond(1.0f + sub);
            var t = getRandomMole();
            if (t != null)
                t.Show();
        }
        //獲得一個隨機老鼠
        private Mole getRandomMole()
        {
            for (int i = 0; i < _molelist.Count; i++)
            {
                Mole t = _molelist[_randome.Next() % _molelist.Count];
                _molelist.Remove(t);
                _molelist.Add(t);
            }
            foreach (var item in _molelist)
            {
                if (item.IsShow == false)
                    return item;
            }
            return null;
        }
        //重設所有的地鼠鑽回去的延遲時間
        private void SetAllMoleDelaySecond(float second)
        {
            foreach (var item in _molelist)
            {
                item.DelaySecond = second;
            }
        }
    }
}

一個好的游戲需要細致的推敲,本例子只是簡單的實現了邏輯,具體的規則可以依照自己需要更改,祝願在游戲的開發之路上風光無限。

推薦WindowsPhone和Silverlight游戲開發博客:深藍色右手


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM