制作五子棋小游戏单机/在线联网对弈手把手精致设计含游戏服务器源码5

接上期。传送门:

http://liuxinyumo.cn/index.php?s=/Home/Index/content/id/6.html

项目仓库地址:https://github.com/liuxinyumocn/LittleGame

 

现在已经实现了辅助器跟随鼠标移动、给出落点等基本功能,接下来需要独立建设五子棋逻辑模块,注意,在设计逻辑模块时需脱离视图部分,将游戏逻辑独立出来,至于将来从视图上所展现是需要在两者中间增加接口(MVC)。

现在我们脱离Canvas坐标单独研究游戏逻辑(GameCore),该部分我们目前采用Javascript语言完成,而实际上为保证游戏公平性,在未来服务器端也需要有相同的判断逻辑,这里是为了满足制作非联网五子棋的小伙伴。

五子棋游戏逻辑非常简单,建立15*15大小二维数组用于代表每一个落子点,默认元素值为0,1为黑子,2为白子。Javascript中并没有直接定义二维数组方式,因此我们采用分步法创建一个默认值为0的15*15二维数组。

var GameCore = function(){ //游戏逻辑核心
		this.Data = null;
		this.Init(); 
	}
	GameCore.fn = GameCore.prototype = {
		Init:function(){	//	两层循环初始化15*15长度的二维数组
			this.Data = new Array();
			for(var i = 0;i<15;i++){
				this.Data[i] = new Array();
				for(var n=0;n<15;n++){
					this.Data[i][n] = 0;
				}
			}
		}
	}

之后是2个基本功能,落子以及胜负判断,我一并给出完整代码,其中注释很清晰:

var GameCore = function(){ //游戏逻辑核心
		this.Data = null;
		this.Init(); 
		this.CurrentPlayer = 1; //执黑先手
		this.Winner = 0;
		this.Steps = new Array(); //步骤记录 用于悔棋
		this.StepsNum = 0;
	}
	GameCore.fn = GameCore.prototype = {
		Init:function(){	//	两层循环初始化15*15长度的二维数组
			this.Data = new Array();
			for(var i = 0;i<15;i++){
				this.Data[i] = new Array();
				for(var n=0;n<15;n++){
					this.Data[i][n] = 0;
				}
			}
		},
		Action:function(x,y){ //落子动作 玩家由系统自动判断 提供的落点是棋盘编号
			//判断合法性
			if(Winner != 0)
				return false; //游戏已经结束
			if(x<1||x>15||y<1||y>15)
				return false;
			if(this.Data[x-1][y-1] != 0)
				return false; //已经有落子
			this.Data[x-1][y-1] = this.CurrentPlayer;
			this.AddSteps(x,y);
			this.CurrentPlayer = this.CurrentPlayer == 1 ? 2:1;//交换选手

			return true;
		},
		Check:function(){	//判断胜负
			//return true 胜者为 this.winner false 无胜者
			//扫描是否存在5子连要从4个方向判断 右上(或左下) 右(或左) 右下(或左上) 下(或上)
			for(var y=0;y<15;y++){
				for(var x=0;x<15;x++){
					if(this.Data[x][y] == 0)
						continue; //未落子不扫描
					var count = 0; //连子数目
					//右上扫描
					for(var i=1;i<=5;i++){
						if(x+i > 14 || y-i<0)
							break;
						if(this.Data[x+i][y-i] == this.Data[x][y]){
							count++;
						}else{
							break;
						}
					}
					if(count >= 5){
						this.Winner = this.Data[x][y];
						return true;
					}
					//右扫描
					for(var i=1;i<=5;i++){
						if(x+i > 14)
							break;
						if(this.Data[x+i][y] == this.Data[x][y]){
							count++;
						}else{
							break;
						}
					}
					if(count >= 5){
						this.Winner = this.Data[x][y];
						return true;
					}
					//右下扫描
					for(var i=1;i<=5;i++){
						if(x+i > 14 || y+i > 14)
							break;
						if(this.Data[x+i][y+i] == this.Data[x][y]){
							count++;
						}else{
							break;
						}
					}
					if(count >= 5){
						this.Winner = this.Data[x][y];
						return true;
					}
					//下扫描
					for(var i=1;i<=5;i++){
						if(y+i > 14)
							break;
						if(this.Data[x][y+i] == this.Data[x][y]){
							count++;
						}else{
							break;
						}
					}
					if(count >= 5){
						this.Winner = this.Data[x][y];
						return true;
					}

				}
			}
			return false;
		},
		AddSteps:function(x,y){
			var p = this.CurrentPlayer;
			this.Steps[this.StepsNum++] = {x:x,y:y,p:p};
		}
	}

接下来是视图控制器,用于将游戏核心逻辑部分,与游戏界面(视图)部分联系起来(GameControl)。

视图控制器并不是要控制视图中的所有元素,而是要控制和管理活跃元素,诸如棋子,记分板,玩家等等,并负责在游戏开局以及另开一局时的资源初始化。那么有了视图控制器之后,我们在Gobang的类内所产生的临时测试棋子的部分则应注释掉,完全交由GameControl负责。下面开始定义GameControl:

var GameControl = function(MainPage){
		this.MainPage = MainPage;
		this.GameCore = null;

		this.Pieces = new Array();
		this.PiecesNum = 0;

		this.WinnerPNG = this.MainPage.AddElement("WinnerPNG");
		this.WinnerPNG.Left(330);
		this.WinnerPNG.Top(170);

	}
	GameControl.fn = GameControl.prototype = {
		Start:function(){	//开始游戏 或者 重新一局
			this.GameCore = new GameCore(); //创建游戏核心
			this.Show();	//映射核心 该函数会被反复使用 有可能用于重连载入
			this.WinnerPNG.Visible(false);
		},
		Show:function(){
			//该函数用于将场景完全恢复后映射GameCore中所存数据
			//棋盘数据
			this.HidePiece();
			for(var x=0;x<15;x++){
				for(var y=0;y<15;y++){
					if(this.GameCore.Data[x][y] != 0){
						this.SetPositon(this.GetPiece(this.GameCore.Data[x][y]),x+1,y+1);
					}
				}
			}
		},
		HidePiece:function(){
			for(var i = 0;i<this.PiecesNum;i++){
				this.Pieces[i].Visible(false);
			}
		},
		SetPositon:function(piece,x,y){	//设置位置并显示
			var p = PiecePostionKit.BoardPostion(x,y);
			piece.Left(p.x);
			piece.Top(p.y);
			piece.Visible(true);
		},
		GetPiece:function(Color){	//获取一个空闲棋子 并设置颜色
			for(var i=0;i<this.PiecesNum;i++){
				if(this.Pieces[i].Visible() == false){
					if(Color == 1){
						this.Pieces[i].Action("SetBlack()");
					}else{
						this.Pieces[i].Action("SetWhite()");
					}
					return this.Pieces[i];
				}
			}
			var p = this.MainPage.AddElement("Piece");
			this.Pieces[this.PiecesNum++] = p;
			if(Color == 2)
				p.Action("SetWhite()");
			return p;
		},
		Down:function(x,y){
			var ps = PiecePostionKit.ScreenPostion(x,y);
			if(ps.x != -1){//说明有落点
				this.GameCore.Action(ps.x,ps.y);
				this.Show();
				var re = this.GameCore.Check();
				if(re){
					this.WinnerPNG.Action("SetColor()",this.GameCore.Winner);
					this.MainPage.SetPosition(this.WinnerPNG,-1);
					this.WinnerPNG.Visible(true);
				}
			}
		}
	}

再此期间我定义了几个新的场景元素,获胜提示等。直接参阅新增部分即可,不再陈述。

看下效果:



还算完美,

本篇完毕。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值