国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

基于控制臺(tái)實(shí)現(xiàn)貪吃蛇游戲

2019-11-14 13:51:32
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

1)、引言

  學(xué)習(xí)編程,我個(gè)人覺(jué)得最好的辦法就是根據(jù)自己的水平不斷的給自己設(shè)定一個(gè)小目標(biāo)。而這個(gè)小目標(biāo)就是一個(gè)有意思的項(xiàng)目,通過(guò)完成這個(gè)項(xiàng)目,對(duì)自己的成果(也包括失敗的)進(jìn)行分析總結(jié),從中提煉出對(duì)應(yīng)的技術(shù)并分享出來(lái),不斷的往復(fù),如此,為的就是讓我們永遠(yuǎn)保持編寫程序的興趣和熱情,完了,還提高我們的技術(shù)。而本文就是總結(jié)自己的一個(gè)小目標(biāo)(基于控制臺(tái)實(shí)現(xiàn)的貪吃蛇游戲而寫的總結(jié))

2)、技術(shù)實(shí)現(xiàn)

  大家小時(shí)候一定玩過(guò)貪吃蛇的游戲。貪吃蛇游戲的控制過(guò)程其實(shí)也不復(fù)雜。簡(jiǎn)單的可以概括為以下4個(gè)部分。

 1.1  、組成蛇的小塊以及食物(Block)

  在本程序中,食物以及蛇的組成都用一個(gè)對(duì)象表示,因?yàn)樗鼈兊淖饔枚际且粯樱瑑H僅只需要一個(gè)坐標(biāo)對(duì)。以及提供一個(gè)靜態(tài)方法,即可以通過(guò)在游戲的地圖內(nèi)生隨機(jī)產(chǎn)生一個(gè)坐標(biāo)對(duì)并返回Block對(duì)象。

 1.2、管理蛇的部分(Snake)

  程序的主體主要“蛇”這個(gè)對(duì)象的屬性以及方法的設(shè)計(jì)。現(xiàn)在我們想想在游戲中這個(gè)對(duì)象需要有哪些屬性以及行為,首先“蛇”有長(zhǎng)度以及“蛇”的組成,這就是蛇的屬性,可以由一個(gè)相鄰的Block類型的集合snakeList來(lái)表示;其次,蛇能移動(dòng)(上下左右),能吃食物,并且不能碰到邊框以及頭部不能觸碰自己的身體,這就可以抽象為蛇的三個(gè)行為,Move(),IsEatFood (),IsOver(),分別為移動(dòng),吃食物,檢測(cè)自身是否滿足游戲的規(guī)則。

  1、Move()

  //蛇移動(dòng)的關(guān)鍵代碼如下。

 public void Move(Direction dir)        {            Block head = this.snakeLIst[0];//獲取蛇頭            this.snakeLIst.RemoveAt(this.snakeLIst .Count -1);//移除末尾項(xiàng)            Block newBlock=null;            switch (dir)//獲取蛇當(dāng)前運(yùn)行的方向,然后把根據(jù)蛇頭的位置計(jì)算出新的蛇頭的位置。相當(dāng)于把蛇尾的坐標(biāo)進(jìn)行計(jì)算插入到蛇頭。            {                 case Direction.Top :                    newBlock = new Block(head.Row-1, head.Col);                    break;                case Direction .Bottom :                    newBlock = new Block(head.Row+1, head.Col);                    break;                case Direction .Left :                    newBlock = new Block(head.Row, head.Col-1);                    break;                case Direction .Right:                    newBlock = new Block(head.Row , head.Col+1);                    break;            }            this.snakeLIst.Insert(0, newBlock);//將新的位置插入到蛇頭        }

  蛇移動(dòng)的程序的動(dòng)態(tài)過(guò)程如下圖:(以向左走為例)

  

   2、IsEatFood ()

  //代碼如下

 /// <summary>        /// 判斷蛇是否達(dá)到食物的位置,如果到達(dá)這eat        /// </summary>        /// <param name="b">食物對(duì)象</param>        /// <returns>返回bool,好讓調(diào)用方知道是否需要產(chǎn)生新的食物</returns>        public bool IsEatFood(Block b)        {            Block head = this.snakeLIst[0];//獲取蛇頭            if (head.IsEqual(b))//是食物的位置一致            {                this.snakeLIst.Add(b);//添加一個(gè)block到蛇的集合中,并這下一次move中移動(dòng)到蛇頭,保證有序。                return true ;            }            return false ;        }

  3、IsOver()

  //代碼如下 

 public bool IsOver()        {            Block head = this.snakeLIst[0];            if (head.Row == 0 || head.Col == 0 || head.Row == 25 || head.Col == 80)//是否遇到邊界            {                return true;            }            for (int i = 1; i < this.snakeLIst.Count; i++)//是否遇到自身            {                if (head.IsEqual(this.snakeLIst[i]))                {                    return true ;                }            }            return false;        }

 

 1.3、管理游戲界面的類(MapManager)

  我們都知道游戲都是畫面不斷變化的一個(gè)過(guò)程,所以我們必須在極短的時(shí)間內(nèi)去更新游戲的畫面,所以就離不開(kāi)定時(shí)器。然后就可以實(shí)時(shí)的去繪制游戲的當(dāng)前的狀態(tài),那么一系列的狀態(tài)連起來(lái)就一個(gè)動(dòng)態(tài)的游戲畫面。

  • 1、我把整個(gè)游戲的地圖存儲(chǔ)在一個(gè)二位數(shù)組里面,如果其值為0則代表為空的,如果為1,則輸出“#”,因?yàn)檫@和在窗體中繪制游戲畫面不一樣,控制臺(tái)只能從左至右,從上至下的輸出。
  • 2、首先繪制邊界,實(shí)際上就是把二維數(shù)組(地圖)中的某一些值賦值為1.
  • 3、建立“對(duì)象”并初始化,遍歷組成蛇的Block集合,來(lái)獲取”蛇“在二維數(shù)組(地圖)的位置,并把對(duì)應(yīng)的位置賦值為1.
  • 4、初始化食物,也即是block對(duì)象,在二維數(shù)組(地圖)中找到他的位置,和第3步一樣將對(duì)應(yīng)的位置賦值為1。
  • 5、上面的4步已經(jīng)把“蛇”、食物以及游戲的邊界繪制出來(lái),接下來(lái)就是蛇的運(yùn)動(dòng)了。蛇的運(yùn)動(dòng)就是每次調(diào)用“蛇”的Move()行為,然后再蛇運(yùn)行之前都要判斷下面兩個(gè)條件,第一,當(dāng)前蛇頭的位置是不是在食物的位置,如果在則吃掉食物,生成新的食物,調(diào)用的方法為IsEatFood();第二,“蛇”是否滿足規(guī)則,如果不滿足則游戲結(jié)束,調(diào)用IsOver()。
  • 6、當(dāng)上面的步驟都完成之后,即二維數(shù)組(地圖)都賦值好了,然后再?gòu)纳现拢瑥淖笾劣乙来屋敵觯ㄆ鋵?shí)就是一長(zhǎng)串字符串)。最后一步才是真正的在界面輸出,其中前面的步驟都是游戲畫面的緩存。關(guān)于計(jì)時(shí)器是使

  其中System.Threading中的Timer類,具體的用戶可以查看其它資料,也可以看后面程序中是如何使用Timer類的

 1.4、與用戶交互的設(shè)計(jì)

  程序?qū)⒂脩艚换サ慕涌诜旁诹薓apManager,主要功能為,啟動(dòng)計(jì)時(shí)器去管理游戲的繪制與運(yùn)行,然后另外就是處理用戶的輸入去改變游戲運(yùn)行狀態(tài)。

 

     其中,需要注意的是,由于是基于控制臺(tái)的實(shí)現(xiàn),用戶的輸入肯定是不能按enter之后然后程序才能接受,而是實(shí)時(shí)的接受用戶的輸入且還不能將用戶的輸入顯示到控制中,還好c#提供了Console.Readkey(true),可以滿足程序的要求。

 1.5、下面是程序運(yùn)行的流程圖

   

  注意:

其中需要注意的是,最后輸出賦值好的二維數(shù)組(地圖)時(shí)候,不是遍歷二維數(shù)組(地圖)遍歷一項(xiàng)就輸出一項(xiàng),而是用StringBuilding對(duì)象去添加,直到遍歷完了,一次性輸出StringBuilding對(duì)象,達(dá)到雙緩存的效果,使得控制臺(tái)繪制不會(huì)閃爍。

3)程序編碼的實(shí)現(xiàn)

  本程序是基于c#控制臺(tái)實(shí)現(xiàn)的,開(kāi)發(fā)工具為2013

  1、Block類

  public class Block    {        PRivate int x;        private int y;               public Block()        {                     }        public Block(int x, int y)        {            this.x = x;            this.y = y;        }        public int Row        {            get { return this.x; }            set { this.x = value; }        }        public int Col        {            get { return this.y; }            set { this.y = value; }        }        public bool IsEqual(Block b)        {            if (this.x == b.Row&& this.y == b.Col)            {                return true;            }            return false;        }        public static Block ProvideFood()        {             Random r=new Random ();            Block b = new Block(r.Next(1, 25), r.Next(1, 80));            return b;        }    }

 

2、Snake類

public class Snake    {        List<Block> snakeLIst = new List<Block>();//存儲(chǔ)蛇的結(jié)構(gòu)        public List<Block> SnakeLIst        {            get { return snakeLIst; }        }        public Snake()        {            InitSnake();        }        private void InitSnake()        {            int rowStart = 2;            int colStart=5;            int lenth = 20+colStart ;            Block b;            for (int i = colStart; i < lenth; i++)            {                b = new Block(rowStart ,i);                this.snakeLIst.Insert(0, b);            }        }        /// <summary>        /// 判斷蛇是否達(dá)到食物的位置,如果到達(dá)這eat        /// </summary>        /// <param name="b">食物對(duì)象</param>        /// <returns>返回bool,好讓調(diào)用方知道是否需要產(chǎn)生新的食物</returns>        public bool IsEatFood(Block b)        {            Block head = this.snakeLIst[0];//獲取蛇頭            if (head.IsEqual(b))//是食物的位置一致            {                this.snakeLIst.Add(b);//添加一個(gè)block到蛇的集合中,并這下一次move中移動(dòng)到蛇頭,保證有序。                return true ;            }            return false ;        }        public void Move(Direction dir)        {            Block head = this.snakeLIst[0];//獲取蛇頭            this.snakeLIst.RemoveAt(this.snakeLIst .Count -1);//移除末尾項(xiàng)            Block newBlock=null;            switch (dir)//獲取蛇當(dāng)前運(yùn)行的方向,然后把根據(jù)蛇頭的位置計(jì)算出新的蛇頭的位置。相當(dāng)于把蛇尾的坐標(biāo)進(jìn)行計(jì)算插入到蛇頭。            {                 case Direction.Top :                    newBlock = new Block(head.Row-1, head.Col);                    break;                case Direction .Bottom :                    newBlock = new Block(head.Row+1, head.Col);                    break;                case Direction .Left :                    newBlock = new Block(head.Row, head.Col-1);                    break;                case Direction .Right:                    newBlock = new Block(head.Row , head.Col+1);                    break;            }            this.snakeLIst.Insert(0, newBlock);//將新的位置插入到蛇頭        }        public bool IsOver()        {            Block head = this.snakeLIst[0];            if (head.Row == 0 || head.Col == 0 || head.Row == 25 || head.Col == 80)//是否遇到邊界            {                return true;            }            for (int i = 1; i < this.snakeLIst.Count; i++)//是否遇到自身            {                if (head.IsEqual(this.snakeLIst[i]))                {                    return true ;                }            }            return false;        }    }

 

  3、MapManager類(包括與用戶的交互)

 public class MapManager    {        const int row = 25;        const int col = 80;        Snake snake;//        Block b;//食物        Timer t;//定時(shí)器        int[,] gameMap = new int[row, col];//地圖        int count=0;        StringBuilder mapBuffer;//緩存區(qū)        bool isNormal = true;        //初始化地圖+繪制邊界        private void InitMap()        {                        for (int i = 0; i < row; i++)            {                if (i == row - 1 || i == 0)                {                    for (int j = 0; j < col; j++)                    {                        this.gameMap[i, j] = 1;                    }                }                else                {                    for (int j = 0; j < col; j++)                    {                        if (j == col - 1 || j == 0)                        {                            this.gameMap[i, j] = 1;                        }                        else                        {                            this.gameMap[i, j] = 0;                        }                    }                }            }        }        //繪制蛇        private void InitSnake()        {            foreach (var s in snake.SnakeLIst)            {                gameMap[s.Row, s.Col] = 1;            }        }        //繪制食物        private void InitFood()        {            gameMap[this.b.Row, this.b.Col] = 1;        }        //輸出控制臺(tái)(游戲畫面)        private void DrawMap()        {                       mapBuffer.Clear();            Console.Clear();            for (int i = 0; i < row; i++)            {                for (int j = 0; j < col; j++)                {                    if (gameMap[i, j] == 1)                    {                        mapBuffer.Append("*");                    }                    else                    {                        mapBuffer.Append(" ");                    }                }                mapBuffer.Append("/n");            }            Console.WriteLine("/n-----------------------------當(dāng)前得分{0}------------------------/n", count);            Console .Write(mapBuffer .ToString ());//從緩存區(qū)中輸出整個(gè)游戲畫面        }        //游戲運(yùn)行管理        private void GameRun(object o)        {            InitMap();            InitSnake();            InitFood();            if (snake.IsEatFood(b))            {                b = Block.ProvideFood();//產(chǎn)生新的食物                count++;//得分            }            snake.Move(GlobalVar.dir);            if (snake.IsOver())            {                GameOver();            }            DrawMap();        }        private void GameOver()        {            Console.Clear();            Console.WriteLine("Game Over");            isNormal = false;            t.Dispose();        }        private void GameInit()        {            Console.WriteLine("按[w,s.a.d]作為上下左右,按[q]退出游戲!!!");            Console.WriteLine("按任何鍵進(jìn)入游戲");            Console.ReadKey(true);        }        //程序開(kāi)始,該方法包括啟動(dòng)定時(shí)器,以及與用戶的交互        public void Start()        {            GameInit();            snake = new Snake();            b = Block.ProvideFood();            mapBuffer = new StringBuilder();            //GameRun(null);            t = new Timer(GameRun, null, 200, 100);            char c;            while (isNormal)            {                c=Console .ReadKey(true ).KeyChar ;                switch (c)                {                     case 's':                        if (GlobalVar.dir != Direction.Top)                        {                            GlobalVar.dir = Direction.Bottom;                        }                        break;                    case 'w':                        if (GlobalVar.dir != Direction.Bottom)                        {                            GlobalVar.dir = Direction.Top;                        }                        break;                    case 'a':                        if (GlobalVar.dir != Direction.Right)                        {                            GlobalVar.dir = Direction.Left;                        }                        break;                    case 'd':                        if (GlobalVar.dir != Direction.Left)                        {                            GlobalVar.dir = Direction.Right;                        }                        break;                    case 'q':                        GameOver();                        break;                }            }            Console.ReadLine();        }    }

 

 

  4、方向枚舉(Direction)

    public enum Direction    {         Left,Right,Top,Bottom    }

 

  5、main(程序入口)

static void Main(string[] args)        {            MapManager mm = new MapManager();            mm.Start();        }

  6、程序效果

   本來(lái)想插入視頻,但是不可以直接上傳,就截幾個(gè)圖吧。

  

4)結(jié)論

其實(shí)程序的最重要的部分是設(shè)計(jì)思路而不是編碼,就這個(gè)程序也可以使用c、python等語(yǔ)言實(shí)現(xiàn),都不是很那難。一旦程序的流程清晰了,編碼的過(guò)程自然也會(huì)浮現(xiàn)出來(lái)啦。

  源碼:http://download.csdn.net/detail/mingge38/9220243 。


上一篇:重構(gòu)

下一篇:C#字符串的不變性

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 咸宁市| 邹平县| 玛曲县| 黑山县| 昌江| 兖州市| 宝坻区| 岳西县| 平度市| 县级市| 隆化县| 昆明市| 西昌市| 周至县| 苍溪县| 农安县| 嘉黎县| 分宜县| 榆树市| 武陟县| 达孜县| 轮台县| 阿拉善左旗| 盖州市| 陈巴尔虎旗| 武汉市| 蒙山县| 九寨沟县| 青川县| 南京市| 玉山县| 武邑县| 易门县| 法库县| 雅安市| 望都县| 建平县| 石柱| 沾益县| 仁化县| 宜章县|