Laya连线小游戏
游戏规则
- 通过连接不同颜色的方块来实现连一连
- 连线不可重复,就是一条线不能和另外一条线撞一起
- 最后所有连线要占据整个空间
游戏资源
创建Item
线条可以分为上左下右,通过显示和隐藏达到画线的效果。
譬如item1到item2,通过判断两者posX,posY,item1调用方法showLine(3)显示line3,item2调用方法showLine(1)显示line1。
Item.ts。
import { ui } from "../ui/layaMaxUI"; export class Item extends ui.view.ItemUI{ public colorType:number = 1;//定义线条颜色 public type:number = 0;//类型 public posX:number = 1;//位置x public posY:number = 1;//位置y public isLinkList:boolean = false;//是否已经连过了 /* 创建item */ public static createItem():Item{ let item:Item = new Item(); item.line1.visible = false; item.line2.visible = false; item.line3.visible = false; item.line4.visible = false; return item; } /* 设置线条颜色 */ public setLineColor(value:number):void{ this.isLinkList = true; this.colorType = value; for(let i:number = 1; i <= 4; i++){ this["line" + i].skin = "res/ui/icon/line_line" + value + ".png"; } } /* 设置icon */ public setIcon(value:number):void{ this.type = value; if(value > 0){ this.icon.skin = "res/ui/icon/line_icon" + value + ".png"; }else{ this.icon.skin = ""; } } /* 显示上或下或左或右线条 */ public showLine(value:number):void{ switch(value){ case 1: this.line1.visible = true;break; case 2: this.line2.visible = true;break; case 3: this.line3.visible = true;break; case 4: this.line4.visible = true;break; default: this.line1.visible = false; this.line2.visible = false; this.line3.visible = false; this.line4.visible = false; this.isLinkList = false; break; } } }
游戏界面创建
创建GameView.ts,类GameView继承自该界面
import { LinkList } from "../script/LinkList"; import { ui } from "../ui/layaMaxUI"; import { Item } from "./Item"; export class GameView extends ui.dialog.GameUI { private row:number = 5;//行数 private column:number = 5;//列数 private itemArr:Array<Item> = [];//存放item的数组 private dataArr:Array<number> = [1,0,0,0,3,0,0,2,0,0,1,0,0,3,0,4,0,0,4,2,5,0,0,0,5]; private ITEM_WIDTH:number = 120;//定义item宽 private ITEM_HEIGHT:number = 120;//定义item高 private canDraw:boolean = false;//是否能画线 private tempPoint:Laya.Point = new Laya.Point(); private list1:LinkList = new LinkList();//链表1 private list2:LinkList = new LinkList();//链表2 private list3:LinkList = new LinkList();//链表3 private list4:LinkList = new LinkList();//链表4 private list5:LinkList = new LinkList();//链表5 private currentList:LinkList; constructor() { super(); this.init(); } private init():void{ this.addEvent(); this.initDrawLinePanel(); } private addEvent():void{ Laya.stage.on(Laya.Event.RESIZE,this,this.onResize); this.panelNode.on(Laya.Event.MOUSE_DOWN,this,this.onMouseDown); this.panelNode.on(Laya.Event.MOUSE_MOVE,this,this.onMouseMove); this.panelNode.on(Laya.Event.MOUSE_OUT,this,this.onMouseOut); this.panelNode.on(Laya.Event.MOUSE_UP,this,this.onMouseOut); } /* 初始化画线面板 */ private initDrawLinePanel():void{ let item:Item; for(let i:number = 0; i < this.row; i++){ for(let j:number = 0; j < this.column; j++){ item = Item.createItem(); item.pos(j * this.ITEM_WIDTH,i * this.ITEM_HEIGHT); item.posX = j; item.posY = i; item.setIcon(this.dataArr.shift()); this.panelNode.addChild(item); this.itemArr.push(item); } } let panelWidth:number = this.ITEM_WIDTH * this.column; let panelHeight:number = this.ITEM_HEIGHT * this.row; this.panelNode.size(panelWidth,panelHeight); this.panelNode.x = -0.5 * panelWidth; this.panelNode.y = -0.5 * panelHeight; } /* 鼠标按下 */ private onm ouseDown():void{ //全局坐标转为panelNode局部坐标 this.tempPoint.setTo(Laya.MouseManager.instance.mouseX,Laya.MouseManager.instance.mouseY); let point:Laya.Point = this.panelNode.globalToLocal((this.tempPoint)); let posX:number = Math.floor(point.x / this.ITEM_WIDTH); let posY:number = Math.floor(point.y / this.ITEM_HEIGHT); let index:number = posY * this.column + posX; let item:Item = this.itemArr[index];//拿到对应的item if(item.type > 0){//点击到有颜色的item this.canDraw = true; this.currentList = this["list" + item.type]; this.currentList.clear(); this.currentList.append(item); }else{//点击到没有颜色的item if(item.isLinkList){//连过了 this.currentList = this["list" + item.colorType]; let tail:Item = this.currentList.getTail().item; if(item == item){//判断该item是否属于链表尾节点 this.canDraw = true; } } } } /* 鼠标滑动 */ private onm ouseMove():void{ if(!this.canDraw) return; //全局坐标转为panelNode局部坐标 this.tempPoint.setTo(Laya.MouseManager.instance.mouseX,Laya.MouseManager.instance.mouseY); let point:Laya.Point = this.panelNode.globalToLocal((this.tempPoint)); let posX:number = Math.floor(point.x / this.ITEM_WIDTH); let posY:number = Math.floor(point.y / this.ITEM_HEIGHT); let index:number = posY * this.column + posX; let item:Item = this.itemArr[index];//拿到对应的item let tail:Item = this.currentList.getTail().item;//链表尾 if((posX == tail.posX && Math.abs(posY - tail.posY) == 1) || (posY == tail.posY && Math.abs(posX - tail.posX) == 1)){//必须与链表尾相邻(上下左右) if(item.type <= 0 || item.type == tail.colorType){//滑动到没有颜色的节点或者是颜色一样 let position:number = this.currentList.positionOf(item); if(position < 0){ if(item.isLinkList){//已经在其它链表里了 let list:LinkList = this["list" + item.colorType] list.slice(list.positionOf(item) - 1); } this.currentList.append(item);//添加到链表 this.isGetVictory();//是否通关 if(item.type > 0){ this.canDraw = false; } }else{ this.currentList.slice(position);//切割链表 } }else{ this.canDraw = false; } }else{ if(item != this.currentList.getTail().item){//此时滑动到的点不是链表尾,才不能画线(在当前的点滑来滑去还是能画线) this.canDraw = false; } } } /* 鼠标松开 */ private onm ouseOut():void{ this.canDraw = false; } /* 是否通过 */ private isGetVictory():boolean{ let count:number = 0 for(let i:number = 1; i <= 5;i ++){//遍历所有链表,判断链表长度是否等于面板上的方格总数 count += this["list" + i].size() } if(count == this.row * this.column){ return true; } return false; } private onResize():void{ this.height = Laya.stage.height; this.width = Laya.stage.width; } }
通过行数5,列数5创建item,添加到panelNode节点上,初始化画线面板。
/* 初始化画线面板 */ private initDrawLinePanel():void{ let item:Item; for(let i:number = 0; i < this.row; i++){ for(let j:number = 0; j < this.column; j++){ item = Item.createItem(); item.pos(j * this.ITEM_WIDTH,i * this.ITEM_HEIGHT); item.posX = j; item.posY = i; item.setIcon(this.dataArr.shift()); this.panelNode.addChild(item); this.itemArr.push(item); } } let panelWidth:number = this.ITEM_WIDTH * this.column; let panelHeight:number = this.ITEM_HEIGHT * this.row; this.panelNode.size(panelWidth,panelHeight); this.panelNode.x = -0.5 * panelWidth; this.panelNode.y = -0.5 * panelHeight; }
通过鼠标位置,计算出posX,posY,拿到对应的item
鼠标全局位置转为panelNode局部位置,计算出posX,posY,再从itemArr拿到对应的item
this.tempPoint.setTo(Laya.MouseManager.instance.mouseX,Laya.MouseManager.instance.mouseY); let point:Laya.Point = this.panelNode.globalToLocal((this.tempPoint)); let posX:number = Math.floor(point.x / this.ITEM_WIDTH); let posY:number = Math.floor(point.y / this.ITEM_HEIGHT); let index:number = posY * this.column + posX; let item:Item = this.itemArr[index];
鼠标按下
鼠标点击时,有俩种情况,才可以画线
第一种情况,点击到颜色方块
第二种情况,不是点击到 颜色方块,但是点击到连线的末端,这时可以继续连线
/* 鼠标按下 */ private onm ouseDown():void{ //全局坐标转为panelNode局部坐标 this.tempPoint.setTo(Laya.MouseManager.instance.mouseX,Laya.MouseManager.instance.mouseY); let point:Laya.Point = this.panelNode.globalToLocal((this.tempPoint)); let posX:number = Math.floor(point.x / this.ITEM_WIDTH); let posY:number = Math.floor(point.y / this.ITEM_HEIGHT); let index:number = posY * this.column + posX; let item:Item = this.itemArr[index];//拿到对应的item if(item.type > 0){//点击到有颜色的item this.canDraw = true; this.currentList = this["list" + item.type]; this.currentList.clear(); this.currentList.append(item); }else{//点击到没有颜色的item if(item.isLinkList){//连过了 this.currentList = this["list" + item.colorType]; let tail:Item = this.currentList.getTail().item; if(item == item){//判断该item是否属于链表尾节点 this.canDraw = true; } } } }
鼠标滑动,连线
连线时,只有跟该线线尾相邻才可以连接
滑到不同颜色节点时断开连接
如果滑动到的已经连接过了,就切割该链表
如果滑动到的节点已经被其它节点连接过了,就切割连接过的链表
/* 鼠标滑动 */ private onm ouseMove():void{ if(!this.canDraw) return; //全局坐标转为panelNode局部坐标 this.tempPoint.setTo(Laya.MouseManager.instance.mouseX,Laya.MouseManager.instance.mouseY); let point:Laya.Point = this.panelNode.globalToLocal((this.tempPoint)); let posX:number = Math.floor(point.x / this.ITEM_WIDTH); let posY:number = Math.floor(point.y / this.ITEM_HEIGHT); let index:number = posY * this.column + posX; let item:Item = this.itemArr[index];//拿到对应的item let tail:Item = this.currentList.getTail().item;//链表尾 if((posX == tail.posX && Math.abs(posY - tail.posY) == 1) || (posY == tail.posY && Math.abs(posX - tail.posX) == 1)){//必须与链表尾相邻(上下左右) if(item.type <= 0 || item.type == tail.colorType){//滑动到没有颜色的节点或者是颜色一样 let position:number = this.currentList.positionOf(item); if(position < 0){ if(item.isLinkList){//已经在其它链表里了 let list:LinkList = this["list" + item.colorType] list.slice(list.positionOf(item) - 1); } this.currentList.append(item);//添加到链表 this.isGetVictory();//是否通关 if(item.type > 0){ this.canDraw = false; } }else{ this.currentList.slice(position);//切割链表 } }else{ this.canDraw = false; } }else{ if(item != this.currentList.getTail().item){//此时滑动到的点不是链表尾,才不能画线(在当前的点滑来滑去还是能画线) this.canDraw = false; } } }
判断是否连接完成
只需要遍历所有链表,判断链表长度是否等于面板上的方格总数
/* 是否通过 */ private isGetVictory():boolean{ let count:number = 0 for(let i:number = 1; i <= 5;i ++){//遍历所有链表,判断链表长度是否等于面板上的方格总数 count += this["list" + i].size() } if(count == this.row * this.column){ return true; } return false; }
item链表
LinkList.ts
import { Item } from "../view/Item"; export class Node{ public item:Item;//节点数据 public next:Node = null;//指向下一个节点 constructor(item:Item){ this.item = item; } } export class LinkList{ private head:Node = null;//链表头 private tail:Node = null;//链表尾 private length:number = 0;//链表长度 /* 向链表添加新节点 */ public append(item:Item):void{ let node:Node = new Node(item); if(this.length <= 0){//如果当前链表为空,则将head,tail指向node item.setLineColor(item.type); this.head = node; this.tail = node; }else{//否则在链表尾添加新元素 item.setLineColor(this.head.item.colorType); let prevItem:Item = this.tail.item; this.tail.next = node; this.tail = node; this.setLine(prevItem,this.tail.item); } this.length++;//链表长度+1 } /* 截取链表,包含position */ public slice(position:number):boolean{ if(position < 1 || position > this.length){ return false; } console.log(position); let currentNode:Node = this.head; let currentPosition:number = 1; let sliceNode:Node; let prevNode:Node; while(currentNode){ if(currentPosition == position - 1){ prevNode = currentNode; } else if(currentPosition == position){ this.length = position; sliceNode = currentNode; currentNode.item.showLine(0); currentNode.item.isLinkList = true; }else if(currentPosition > position){ currentNode.item.showLine(0); } currentNode = currentNode.next; currentPosition++; } sliceNode.next = null; if(prevNode){ this.setLine(prevNode.item,sliceNode.item); } this.tail = sliceNode; } /* 设置线条 */ private setLine(item1:Item,item2:Item):void{ let prevX:number = item1.posX; let prevY:number = item1.posY; let nextX:number = item2.posX; let nextY:number = item2.posY; if(prevX == nextX){ if(prevY > nextY){ item1.showLine(1); item2.showLine(3); }else{ item1.showLine(3); item2.showLine(1); } } if(prevY == nextY){ if(prevX > nextX){ item1.showLine(4); item2.showLine(2); }else{ item1.showLine(2); item2.showLine(4); } } } /* 查找某个元素所在的节点位置 */ public positionOf(item:Item):number{ let currentNode:Node = this.head; let currentPosition:number = 1; while(currentNode){ if(currentNode.item == item){ return currentPosition; } currentPosition++; currentNode = currentNode.next; } return -1; } /* 返回某位置的节点*/ public getNodeAt(position:number):Node{ if(position < 1 || position > this.length){//越界 return null; } let currentNode:Node = this.head; let currentPositon:number = 1; while(currentPositon < position){//遍历链表,找到节点 currentNode = currentNode.next; currentPositon++; } return currentNode; } /* 链表是否为空 */ public isEmpty():boolean{ return this.length == 0; } /* 返回链表长度 */ public size():number{ return this.length; } /* 返回链表头 */ public getHead():Node{ return this.head; } /* 返回链表尾 */ public getTail():Node{ return this.tail; } /* 清空链表 */ public clear():void{ let currentNode:Node = this.head; while(currentNode){ currentNode.item.showLine(0); currentNode = currentNode.next; } this.head = null; this.tail = null; this.length = 0; } }
设置线条
通过比较链表前后节点的item,显示对应的线条
/* 设置线条 */ private setLine(item1:Item,item2:Item):void{ let prevX:number = item1.posX; let prevY:number = item1.posY; let nextX:number = item2.posX; let nextY:number = item2.posY; if(prevX == nextX){ if(prevY > nextY){ item1.showLine(1); item2.showLine(3); }else{ item1.showLine(3); item2.showLine(1); } } if(prevY == nextY){ if(prevX > nextX){ item1.showLine(4); item2.showLine(2); }else{ item1.showLine(2); item2.showLine(4); } } }
item链表添加节点
需要设置一下当前节点跟上一个节点的线条
/* 向链表添加新节点 */ public append(item:Item):void{ let node:Node = new Node(item); if(this.length <= 0){//如果当前链表为空,则将head,tail指向node item.setLineColor(item.type); this.head = node; this.tail = node; }else{//否则在链表尾添加新元素 item.setLineColor(this.head.item.colorType); let prevItem:Item = this.tail.item; this.tail.next = node; this.tail = node; this.setLine(prevItem,this.tail.item); } this.length++;//链表长度+1 }
item链表截取节点
/* 截取链表,包含position */
public slice(position:number):boolean{ if(position < 1 || position > this.length){ return false; } console.log(position); let currentNode:Node = this.head; let currentPosition:number = 1; let sliceNode:Node; let prevNode:Node; while(currentNode){ if(currentPosition == position - 1){ prevNode = currentNode; } else if(currentPosition == position){ this.length = position; sliceNode = currentNode; currentNode.item.showLine(0); currentNode.item.isLinkList = true; }else if(currentPosition > position){ currentNode.item.showLine(0); } currentNode = currentNode.next; currentPosition++; } sliceNode.next = null; if(prevNode){ this.setLine(prevNode.item,sliceNode.item); } this.tail = sliceNode; }
清空item链表
将链表清空,item线条全部隐藏
/* 清空链表 */ public clear():void{ let currentNode:Node = this.head; while(currentNode){ currentNode.item.showLine(0); currentNode = currentNode.next; } this.head = null; this.tail = null; this.length = 0; }