游戏案例:泡泡龙

214 阅读2分钟

学习目标:泡泡龙核心玩法

泡泡龙(Puzzle Bobble)是一款经典的弹珠消除游戏,其实现思路通常涉及以下几个关键部分:

  1. 游戏界面:首先,创建一个包含泡泡和玩家操作区域的游戏窗口,泡泡通常以网格的形式排列。
  2. 游戏逻辑:玩家通过发射彩色气泡来消除相同颜色的泡泡。发射的气泡可能有不同的轨迹,可以通过计算角度和速度来决定。
  3. 碰撞检测:当发射的气泡碰到其他泡泡或者边框时,需要检测是否触发了消除效果。这通常涉及到使用矩形碰撞检测算法。
  4. 消除和得分系统:当三个或更多的相同颜色的泡泡相邻并被消除时,会扣除敌人的生命值或得分。消除后,剩余泡泡会下落填补空缺。
  5. 计时和难度递增:游戏通常设置时间限制,并随着进度增加游戏难度,比如减少发射气泡的机会、加快下落速度等。
  6. 敌人和道具:游戏中会有移动或固定的敌人,以及特殊道具如增加发射气泡数量或改变气泡轨迹的道具。
  7. 循环和游戏结束条件:游戏循环不断,直到玩家的生命值用完或达到特定目标(如消除所有泡泡)为止。

游戏画面

项目结构目录

部分核心代码

using UnityEngine;
using System.Collections;
using InitScriptName;


public enum GameState
{
    Playing,
    Highscore,
    GameOver,
    Pause,
    Win,
    WaitForPopup,
    WaitAfterClose,
    BlockedGame,
    Tutorial,
    PreTutorial,
    WaitForChicken
}


public class GamePlay : MonoBehaviour {
    public static GamePlay Instance;
    private GameState gameStatus;
    bool winStarted;
    public GameState GameStatus
    {
        get { return GamePlay.Instance.gameStatus; }
        set 
        {
            if( GamePlay.Instance.gameStatus != value )
            {
                if( value == GameState.Win )
                {
                    if( !winStarted )
                        StartCoroutine( WinAction ());
                }
                else if( value == GameState.GameOver )
                {
                    StartCoroutine( LoseAction() );
                }
                else if( value == GameState.Tutorial && gameStatus != GameState.Playing )
                {
                    value = GameState.Playing;
                    gameStatus = value;
                  //  ShowTutorial();
                }
                else if( value == GameState.PreTutorial && gameStatus != GameState.Playing )
                {
                    ShowPreTutorial();
                }

            }
            if( value == GameState.WaitAfterClose )
                StartCoroutine( WaitAfterClose() );

            if( value == GameState.Tutorial )
            {
                if( gameStatus != GameState.Playing )
                    GamePlay.Instance.gameStatus = value;

            }
          
                    GamePlay.Instance.gameStatus = value;

        }
    }

	// Use this for initialization
	void Start () {
        Instance = this;
	}

    void Update()
    {
        if(Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.OSXEditor)
        {
            if( Input.GetKey( KeyCode.W ) ) GamePlay.Instance.GameStatus = GameState.Win;
            if( Input.GetKey( KeyCode.L ) ) { LevelData.LimitAmount = 0; GamePlay.Instance.GameStatus = GameState.GameOver; }
            if( Input.GetKey( KeyCode.D ) ) mainscript.Instance.destroyAllballs() ;
            if( Input.GetKey( KeyCode.M ) ) LevelData.LimitAmount = 1;

        }
    }
	
	// Update is called once per frame
	IEnumerator WinAction () 
    {
        winStarted = true;
        InitScript.Instance.AddLife( 1 );
        GameObject.Find( "Canvas" ).transform.Find( "LevelCleared" ).gameObject.SetActive( true );
  //       yield return new WaitForSeconds( 1f );
        //if( GameObject.Find( "Music" ) != null)
        //    GameObject.Find( "Music" ).SetActive( false );
        //    GameObject.Find( "CanvasPots" ).transform.Find( "Black" ).gameObject.SetActive( true );
        SoundBase.Instance.GetComponent<AudioSource>().PlayOneShot( SoundBase.Instance.winSound );
         yield return new WaitForSeconds( 1f );
         if( LevelData.mode == ModeGame.Vertical )
         {
           //  SoundBase.Instance.audio.PlayOneShot( SoundBase.Instance.swish[0] );
           //  GameObject.Find( "Canvas" ).transform.Find( "PreComplete" ).gameObject.SetActive( true );
            yield return new WaitForSeconds( 1f );
            GameObject.Find( "CanvasPots" ).transform.Find( "Black" ).gameObject.SetActive( false );
            //     SoundBase.Instance.audio.PlayOneShot( SoundBase.Instance.swish[0] );
          //  yield return new WaitForSeconds( 1.5f );
            yield return new WaitForSeconds( 0.5f );
         }

        foreach( GameObject item in GameObject.FindGameObjectsWithTag("Ball") )
        {
            item.GetComponent<ball>().StartFall();
                                   
        }
       // StartCoroutine( PushRestBalls() );
        Transform b = GameObject.Find( "-Ball" ).transform;
        ball[] balls = GameObject.Find( "-Ball" ).GetComponentsInChildren<ball>();
        foreach( ball item in balls )
        {
            item.StartFall();
        }

        while( LevelData.LimitAmount > 0 )
        {
            if( mainscript.Instance.boxCatapult.GetComponent<Grid>().Busy != null )
            {
                LevelData.LimitAmount--;
                ball ball = mainscript.Instance.boxCatapult.GetComponent<Grid>().Busy.GetComponent<ball>();
                mainscript.Instance.boxCatapult.GetComponent<Grid>().Busy = null;
                ball.transform.parent = mainscript.Instance.Balls;
                ball.tag = "Ball";
                ball.PushBallAFterWin();

            }
            yield return new WaitForEndOfFrame();
        }
        foreach( ball item in balls )
        {
            if(item != null)
                item.StartFall();
        }
        yield return new WaitForSeconds( 2f );
        while( GameObject.FindGameObjectsWithTag( "Ball" ).Length > 0  )
        {
            yield return new WaitForSeconds( 0.1f );
        }
        SoundBase.Instance.GetComponent<AudioSource>().PlayOneShot( SoundBase.Instance.aplauds );
        if( PlayerPrefs.GetInt( string.Format( "Level.{0:000}.StarsCount", mainscript.Instance.currentLevel ),0 ) < mainscript.Instance.stars )
            PlayerPrefs.SetInt( string.Format( "Level.{0:000}.StarsCount", mainscript.Instance.currentLevel ), mainscript.Instance.stars );


        if( PlayerPrefs.GetInt( "Score" + mainscript.Instance.currentLevel ) < mainscript.Score )
        {
            PlayerPrefs.SetInt( "Score" + mainscript.Instance.currentLevel, mainscript.Score );

        }
        GameObject.Find( "Canvas" ).transform.Find( "LevelCleared" ).gameObject.SetActive( false );
        GameObject.Find( "Canvas" ).transform.Find( "MenuComplete" ).gameObject.SetActive( true );

    }

    //IEnumerator PushRestBalls()
    //{

    //    while( LevelData.limitAmount  > 0)
    //    {
    //        if( mainscript.Instance.boxCatapult.GetComponent<Grid>().Busy != null )
    //        {
    //            LevelData.limitAmount--;
    //            ball b = mainscript.Instance.boxCatapult.GetComponent<Grid>().Busy.GetComponent<ball>();
    //            mainscript.Instance.boxCatapult.GetComponent<Grid>().Busy = null;
    //            b.transform.parent = mainscript.Instance.Balls;
    //            b.tag = "Ball";
    //            b.PushBallAFterWin();

    //        }
    //        yield return new WaitForEndOfFrame();
    //    }

    //}

    void ShowTutorial()
    {
        //GameObject.Find( "Canvas" ).transform.Find( "Tutorial" ).gameObject.SetActive( true );
        

    }
    void ShowPreTutorial()
    {
        GameObject.Find( "Canvas" ).transform.Find( "PreTutorial" ).gameObject.SetActive( true );

    }

    IEnumerator LoseAction()
    {
        SoundBase.Instance.GetComponent<AudioSource>().PlayOneShot( SoundBase.Instance.OutOfMoves );
        GameObject.Find( "Canvas" ).transform.Find( "OutOfMoves" ).gameObject.SetActive( true );
        yield return new WaitForSeconds( 1.5f );
        GameObject.Find( "Canvas" ).transform.Find( "OutOfMoves" ).gameObject.SetActive( false );
        if(LevelData.LimitAmount <= 0)
            GameObject.Find( "Canvas" ).transform.Find( "MenuPreGameOver" ).gameObject.SetActive( true );
        yield return new WaitForSeconds( 0.1f );

    }

    IEnumerator WaitAfterClose()
    {
        yield return new WaitForSeconds( 1 );
        GameStatus = GameState.Playing;
    }
}

下载链接:gitee.com/unity_demo/…