C#学习-魔塔项目记录(2021.11.30)

项目要求:
1、使用C#控制台实现,
2、至少3个场景,且场景数据从文件中读取加载
3、玩家可以按键控制移动,碰到障碍物停止
3、UI显示玩家信息数据
4、怪物信息可以编辑,txt,xml或者json
5、有简单的框架支撑,且设计合理。使用封装、继承、多态。
6、可以战斗

C#快学完了,做一个魔塔的项目,今天开始记录下每天的进度,也是帮助自己回顾一下流程。

搭建框架(用到了观察者模式)

1、先把需要的几个类建好(目前就这么多) 

  • GameManager 管理游戏
  • GameMap 地图类
  • Player 玩家类
  • Program Mian函数入口
  • Singlton 单例泛型类,接入别的类,就可以实现单例的效果

2、看下各个类里有什么

首先是Singlton里,是一个带约束的泛型抽象类,功能是只要接入别的类就可以相应实现单例效果,项目里就不用反复写单例了。

    abstract class Singlton<T> where T : new()
    {
        private static T instance;
        public static T Instance 
        {
            get
            {
                if(instance == null)
                {
                    instance = new T();
                }
                return instance;
            }

        }
        
    }

然后是GameManager

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Mota
{
    class GameManager :Singlton<GameManager>
    {
        Player Player;
        GameMap gameMap;
        
        public void Init()
        {
            InputManager.Instance.Init();//输入管理的初始化


            gameMap = new GameMap("Map.txt");//实例化一个地图对象,把文件路径传进去
            gameMap.PrintMap();

            Player = new Player();
            Player.Init();


            while (true)
            {

                Update();
                Render();
                Thread.Sleep(1000 / 30);//游戏帧率控制
            }

        }

        public void Update()
        {
            InputManager.Instance.Update();
            Player.Update();

        }

        public void Render()
        {

        }
    }
}

简单的框架:

Init 方法初始化整个游戏

Update 方法更新数据

Render 方法渲染画面

在 Init 里用一个while循环调用Update和Render方法,

然后在框架里加上各种模块实现各种功能,目前只做了Player和GameaMap的几个简单功能

先看下Player

using Mota;
using System;
using System.Collections.Generic;
using System.Text;

namespace Mota
{
   enum Direction
    {
        None,
        Up,
        Down,
        left,
        right
    }//各个方向移动的枚举

    class Player :IKeyDown//这里是输入管理的接口
    {
        Direction dir = Direction.None;


        public void Init()
        {
            InputManager.Instance.AddObserverList(this);
        }//把自己加入观察者数组

        public void Update()
        
        {
            Move();
        }
        //player自己的Update,更新自己的各项数据,
        //最后GameManager里只要调用这个玩家的Update就可以实现玩家的功能了

        public void Move()
        {
            switch (dir)
            {
                case Direction.None:
                    break;
                case Direction.Up:
                    Console.WriteLine("向上走");//检测下功能
                    break;
                case Direction.Down:
                    break;
                case Direction.left:
                    break;
                case Direction.right:
                    break;
                default:
                    break;

                dir = Direction.None;
            }
        }//移动的逻辑

        public void ObserverOnKeyDown(ConsoleKey Key)
        {
            switch (Key)
            {
                case ConsoleKey.W:
                    dir = Direction.Up;                    
                    break;
                case ConsoleKey.S:
                    dir = Direction.Down;
                    break;
                case ConsoleKey.A:
                    dir = Direction.left;
                    break;
                case ConsoleKey.D:
                    dir = Direction.right;
                    break;
                
                default:
                    break;
            }
        }//玩家作为键盘输入的观察者,按 W A S D 控制玩家移动

    }

}

 然后是GameMap

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Mota
{
    class GameMap
    {
        int[,] mapDate;//定义一个二维数组接收地图数据
        int row;//地图的行数
        int col;//地图的列数
        
        public GameMap(string path)
        {
            string[] lines = File.ReadAllLines(path);
            //调用 File 类里的 ReadAllLines 方法,
            //读取文件里的内容传入一个string数组(文件路径以参数形式,后面 new 的时候传入)
            string[] line0 = lines[0].Split(",");//第零行按照“,”分隔,来读取地图行列
            row = int.Parse(line0[0]);
            col = int.Parse(line0[1]);

            mapDate = new int[row, col];

            for (int i = 0; i < row; i++)
            {
                string curLine = lines[i + 1];
                string[] datas = curLine.Split(",");
                //从第一行开始按照“,”分割来读取数据,一共有roe行
                //读取后把每一行的所有数据数据存入 datas 数组备用

                for (int j = 0; j < col; j++)
                {
                    mapDate[i, j] = int.Parse(datas[j]);
                    //把datas 数组里的数据返回给mapData
                }
            }
        }

       /* 
        public void Init()
        {
            InputManager.Instance.AddObserverList(this);
        }//把地图添加为观察者,暂时用不到
       */

        StringBuilder sb = new StringBuilder();
        //建一个 StringBuilder 打印地图(性能要比直接用 string 字符串打印好)

        public void PrintMap()
        {
            sb.Clear();
            for (int i = 0; i < mapDate.GetLength(0); i++)
            {
                for (int j = 0; j < mapDate.GetLength(1); j++)
                {
                    if (mapDate[i, j] == 0)
                    {
                        sb.Append("  ");
                    }
                    else if (mapDate[i, j] == 10)
                    {
                        sb.Append("■");
                    }
                    else if (mapDate[i, j] == 46)
                    {
                        sb.Append("◇");
                    }
                    else if (mapDate[i, j] == 38)
                    {
                        sb.Append("△");
                    }
                }
                sb.Append("\n");
            }
            Console.WriteLine(sb);
        }//根据mapDate里的数据,往sb里追加各种地图元素,现在地图还不完整

        public override string ToString()
        {
            return sb.ToString();
        }//改写 ToString 方法用于打印地图
    }
    
}

地图数据是这样的:(用Tiled软件画出来可以直接保存成txt文档)

 然后看下 InputManager 输入管理类

using System;
using System.Collections.Generic;
using System.Text;

namespace Mota
{
    class InputManager : Singlton<InputManager>//继承单例类,实现单例功能
    {
        //观察者的本质,就是维护一个容器,里面放了所有观察者的对象
        //当被观察的对象发生变化,那么会遍历这个容器,对所有观察者发出通知

        List<IKeyDown> ObserverKeyList; //新建一个List容器

        public void AddObserverList(IKeyDown Observer)
        {
            ObserverKeyList.Add(Observer);
        }//往容器里追加对象的方法

        public void RemoveObserverList(IKeyDown Observer)
        {
            ObserverKeyList.Remove(Observer);
        }//往容器里移除对象的方法

        public void Init()
        {
            ObserverKeyList = new List<IKeyDown>();
        }//InputManager 的初始化(比较low...只有实例化一个对象出来,哈哈)

        public void Update()
        {
            while (Console.KeyAvailable)//当按下按键时
            {
                ConsoleKey Key = Console.ReadKey(true).Key;//接收按键

                foreach (var item in ObserverKeyList)
                {
                    item.ObserverOnKeyDown(Key);
                }//foreach 循环,把按键通知给观察者数组里的所有观察者
            }

        }//InputManager的数据更新

    }

    interface IKeyDown //按键的接口
    {
        public void ObserverOnKeyDown(ConsoleKey Key)
        {
            
        }
    }
}

第一天项目就做到这里啦~未完待续。。。。。。

Supongo que te gusta

Origin blog.csdn.net/Erenlui/article/details/121644466
Recomendado
Clasificación