用cocos2d-x做一個簡單的windows phone 7遊戲:旋轉炮塔(二)

本教程基於子龍山人翻譯的cocos2dIPHONE教程,用cocos2d-x for XNA引擎重寫,加上我一些加工製作。教程中大多數文字圖片都是原作者和翻譯作者子龍山人,還有不少是我自己的理解和加工。感謝原作者的教程和子龍山人的翻譯。本教程僅供學習交流之用,切勿進行商業傳播。

子龍山人翻譯的Iphone教程地址:http://www.cnblogs.com/andyque/articles/1997820.html

Iphone教程原文地址:http://www.raywenderlich.com/692/rotating-turrets


旋轉炮塔來改變射擊的方向。許多遊戲都有這個功能,

在這個教程中,將會詳細地講解如何實現這個功能,即如何把旋轉炮塔的功能添加到一個遊戲當中去。

準備工作

  如果你看完並實踐了上一個教程,你可以繼續使用那個工程。如果沒有的話,那麼下載這個鏈接的代碼吧。

  接下來,下載新的 player sprite projectile sprite圖片,然後把它們加到Content工程的images目錄裏面。並修改原來的精靈初始化代碼。

// In the init method
CCSprite player = CCSprite.spriteWithFile(@"images/player2");
// In the ccTouchesEnded method
CCSprite projectile = CCSprite.spriteWithFile(@"images/Projectile2");
編譯並運行你的工程,如果一切順利的話,你將會看到一個炮塔正在發射子彈。然後,這並不是很好,因爲炮塔在射擊的時候並沒有面朝那個方向。因此,接下來讓我們來解決這個問題。

旋轉並射擊

  在我們旋轉炮塔之前,首先,我們需要保存Player精靈的引用,以便後面旋轉它的時候使用。把Player精靈的聲明提到類當中去:

CCSprite player;

修改init中的代碼爲:

player = CCSprite.spriteWithFile(@"images/player2");
好了,現在讓我們取出player對象的引用並且旋轉它吧!爲了旋轉它,我們首先需要計算出旋轉的角度。爲了解決這個問題,想想我們在高中時候學過的三角代數吧。還記得sin cos tan嗎?爲了便於理解,下面使用一張圖來解釋一下:tan = 對面/鄰邊。

  如上所示,我們想要旋轉的角度是arctangent(angle),即對offY/offX求arctangent運算。

  然而,這裏還有兩件事情,我們需要放在心上。首先,當我們計算actangent(offY/offX)的時候,這個結果是弧度,但是cocos2d使用的卻是角度。還好,cocosd2d提供了一個非常方便的宏,可以使得角度和弧度之間方便轉化。

  第二點,我們假定上面的圖中angle的偏轉是正20度,但是,cocos2d裏面順時針方向爲正(而不是上圖所示的逆時針爲正)。讓我們看到下面這個圖:

  因此,爲了得到正確的方向,我們把運算結果乘以一個-1就可以了。比如,如果我們把上面那幅圖片裏的角度乘以-1的話,我們就得夠得到-20度,這個角度其實就是逆時針方向的20度。(感覺老外說話好囉嗦啊,聰明的讀者恐怕早就明白了吧!:)

  好了,講得夠多了!讓我們來寫一點代碼吧。在ccTouchesEnded裏面加入以下代碼,添加位置在你的projectile runAction之前。

            //Determine angle to face
            float angleRadians = (float)Math.Atan(offRealY / offRealX);
            float angleDegrees = MathHelper.ToDegrees(angleRadians);
            float cocosAngle = -1 * angleDegrees;
			player.rotation = cocosAngle;

  編譯並運行工程,現在我們的炮塔在射擊的時候可以改變方向了。

旋轉之後再射擊

  目前來說還不錯,但是有一點點怪。因爲,這個炮塔好像突然一下跳到一個方向射擊,有點不夠流暢。我們可以解決這個問題,但是在這之前,我們需要重構一下代碼。

  首先,打開GamePlayLayer類,然後在你的類裏添加如下成員變量:

CCSprite nextProjectile = null;

然後,修改你的ccTouchesEnded方法,並且添加一個新的方法,叫做finishShoot,如下所示:

 

        public override void ccTouchesEnded(List<CCTouch> touches, CCEvent event_)
        {
            if (nextProjectile != null)
                return;

            CCTouch touch = touches.FirstOrDefault();
            CCPoint location = touch.locationInView(touch.view());
            location = CCDirector.sharedDirector().convertToGL(location);

            //set up initial location of projectile
            CCSize winSize = CCDirector.sharedDirector().getWinSize();
            //CCSprite projectile = CCSprite.spriteWithFile(@"images/Projectile");
            nextProjectile = CCSprite.spriteWithFile(@"images/Projectile2");
            nextProjectile.position = new CCPoint(20, winSize.height / 2);

            //Determine offset of location to projectile

            float offX = location.x - nextProjectile.position.x;
            float offY = location.y - nextProjectile.position.y;

            //Bail out if we are shooting or backwards
            if (offX <= 0)
            {
                return;
            }



            //Determine where we wish to shoot the projectile to
            float realX = winSize.width + nextProjectile.contentSize.width / 2;
            float ratio = offY / offX;
            float realY = realX * ratio + nextProjectile.position.y;
            CCPoint realDest = new CCPoint(realX, realY);

            //Determine the length of how far we're shooting
            float offRealX = realX - nextProjectile.position.x;
            float offRealY = realY - nextProjectile.position.y;
            float length = (float)Math.Sqrt(offRealX * offRealX + offRealY * offRealY);
            float velocity = 480 / 1;//480pixls/lsec
            float realMoveDuration = length / velocity;


            //Determine angle to face
            float angleRadians = (float)Math.Atan(offRealY / offRealX);
            float angleDegrees = MathHelper.ToDegrees(angleRadians);
            float cocosAngle = -1 * angleDegrees;

            float rotateSpeed = (float)(0.5 / Math.PI);//Would take 0.5 seconds to rotate 0.5 radians ,or half a circle
            float rotateDuration = Math.Abs(angleRadians * rotateSpeed);
            player.runAction(CCSequence.actions(CCRotateTo.actionWithDuration(rotateDuration,cocosAngle), CCCallFunc.actionWithTarget(this, finishShoot)));
            //Move projectile to actual endpoint
            nextProjectile.runAction(CCSequence.actions(CCMoveTo.actionWithDuration(realMoveDuration, realDest),
                CCCallFuncN.actionWithTarget(this,spriteMoveFinished)));
            nextProjectile.tag = 2;
            
            //SimpleAudioEngine.sharedEngine().playEffect(@"resource/pew-pew-lei");
        }

        void finishShoot()
        { 
            // Ok to add now , we are finished rotation
            this.addChild(nextProjectile);
            _projectiles.Add(nextProjectile);
            nextProjectile = null;
        }


        看上去好像有許多代碼,但是,實際上我們改動的並不多--大部分只是做一些小小的重構。下面是我們所修改的內容的一個列表: 

  1.  在函數開頭檢查nextProjectile的值是否爲nil。這意味着我們當前的touch事件正發生在射擊過程之中。也就是說,炮塔已經發射出一個子彈了。 .
  2. 之前,我們使用一個projectile的局部變量,並把它加入到了當前的場景中。在這個版本中,我們增加了一個nextProjectile的成員變量,但是並沒有馬上加到當前場景中。因爲後要還要使用。
  3.  .定義炮塔旋轉的角度,半秒鐘旋轉半個圓。記住,一個圓有2 PI個弧度。 .
  4. 計算旋轉特定的角度需要多長時間,這裏是拿弧度乘以速度。 .
  5. 接下來,我們使用一個sequence action來旋轉我們的炮塔。最後,調用一個函數,把projectile加入到當前場景當中去。  

好,大功告成!編譯並運行工程,現在炮塔可以旋轉,並且很流暢地射擊了!本次工程下載:http://dl.dbank.com/c0cvo9f1gc    

 繼續學習:用cocos2d-x做一個簡單的windows phone 7遊戲:更猛的怪獸和更多的關卡(三)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章