项目要求:
1、使用C#控制台实现,
2、至少3个场景,且场景数据从文件中读取加载
3、玩家可以按键控制移动,碰到障碍物停止
3、UI显示玩家信息数据
4、怪物信息可以编辑,txt,xml或者json
5、有简单的框架支撑,且设计合理。使用封装、继承、多态。
6、可以战斗
C#快学完了,做一个魔塔的项目,今天开始记录下每天的进度,也是帮助自己回顾一下流程。
搭建框架(用到了观察者模式)
1、先把需要的几个类建好(目前就这么多)
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) { } } }
第一天项目就做到这里啦~未完待续。。。。。。