使用TypeScript实现简单的HTML5贪吃蛇游戏
TypeScript是一种由微软开发的自由和开源的编程语言。它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。安德斯·海尔斯伯格,C#的首席架构师,已工作于TypeScript的开发。2012年十月份,微软发布了首个公开版本的TypeScript,2013年6月19日,在经历了一个预览版之后微软正式发布了正式版TypeScript
0.9,向未来的TypeScript 1.0版迈进了很大一步。——摘自百度百科
我个人感觉这个最大的优势就是建模比较方便了,因为它通过对JS的扩充实现了类、接口、枚举等(都是编译器在干活),感觉它把一些C#的语法加进去了,从而简化了大型JS应用程序的开发。
对于使用VS2012/2013的开发者来说,需要下载一个插件才行,地址如下:http://www.microsoft.com/en-us/download/details.aspx?id=34790
代码比较简单,直接上代码了,希望对typescript有兴趣的大牛给点建议吧。
下面是typescript源码,typescript源文件默认后缀为.ts,在HTML页面引用这个文件的时候需要使用后缀为.js,在请求该脚本文件时,编译器会把typescript代码编译为其等价的JavaScript代码,并保证其兼容性(官方说法,没有验证)。
1 //方向类,方向数值和键盘方向键一致 2 enum Direction { 3 Up= 38, 4 Down= 40, 5 Right= 39, 6 Left= 37 7 } 8 9 //贪吃蛇类 10 class Snake { 11 //当前运动方向 12 direction: Direction; 13 //蛇位置数组 14 body: number[] = []; 15 //在移动蛇 16 move() { 17 var i = 0; 18 for (; i < this.body.length - 1; i++) { 19 this.body[i] = this.body[i + 1]; 20 } 21 //根据方向计算蛇头位置 22 var cubeNumber = new Game().cubeNumber; 23 var y = parseInt(this.body[i] / cubeNumber + ""); 24 var x = this.body[i] - y * cubeNumber; 25 switch (this.direction) { 26 case Direction.Up: 27 this.body[i] = (y - 1) * cubeNumber + x; 28 break; 29 case Direction.Down: 30 this.body[i] = (y + 1) * cubeNumber + x; 31 break; 32 case Direction.Right: 33 this.body[i] = y * cubeNumber + x + 1; 34 break; 35 case Direction.Left: 36 this.body[i] = y * cubeNumber + x - 1; 37 break; 38 } 39 } 40 } 41 42 class Game { 43 canvas: HTMLCanvasElement; 44 Width: number = 602; 45 Height: number = 602; 46 cubeWidth: number = 30; 47 cubeNumber: number = 20; 48 wallNum: number = -1; 49 comNum: number = 0; 50 snakeNum: number = 1; 51 frogNum:number = 2; 52 boardArray: number[] = []; 53 snake: Snake; 54 wallColor: string = "#cccccc"; 55 snakeColor: string = "#000000"; 56 comColor: string = "#ffffff"; 57 frogColor: string = "#00cc33"; 58 59 snakeMoveInterval: number; 60 frogInterval: number; 61 moveInterval:number = 1000; 62 63 //初始化贪吃蛇界面(本贪吃蛇比较简单,只有一个canvas) 64 initialUI() { 65 //创建canvas并设置格式 66 this.canvas = document.createElement("canvas"); 67 this.canvas.height = this.Height; 68 this.canvas.width = this.Width; 69 this.canvas.style.margin = "30px auto auto auto"; 70 //this.canvas.style.border = "1px solid red"; 71 document.body.style.margin = "0px"; 72 document.body.style.textAlign = "center"; 73 document.body.appendChild(this.canvas); 74 } 75 //在(x,y)坐标处绘制一块墙 76 drawWall(x: number, y: number) { 77 var ctx = this.canvas.getContext("2d"); 78 ctx.fillStyle = this.wallColor; 79 //alert("(x,y)=>(" + (this.cubeWidth * x) + "," + (this.cubeWidth * y) + ")"); 80 //(x,y)各加0.5用来修正位置 81 ctx.fillRect(x * this.cubeWidth + 0.5, y * this.cubeWidth + 0.5, this.cubeWidth - 1, this.cubeWidth - 1); 82 } 83 84 //初始化一条蛇(此处简化处理了) 85 initialSnake() { 86 this.snake = new Snake(); 87 this.snake.direction = Direction.Right; 88 for (var i = 0; i < 4; i++) { 89 //从第二行开始位置设置一条向右运动的蛇 90 this.snake.body.push(this.cubeNumber + 1 + i); 91 } 92 } 93 94 //绘制蛇 95 drawSnake() { 96 //遍历蛇身 97 var ctx = this.canvas.getContext("2d"); 98 ctx.fillStyle = this.snakeColor; 99 for (var i = 0; i < this.snake.body.length; i++) { 100 //计算坐标 101 var y = parseInt(this.snake.body[i] / this.cubeNumber + ""); 102 var x = this.snake.body[i] - y * this.cubeNumber; 103 ctx.fillRect(x * this.cubeWidth + 0.5, y * this.cubeWidth + 0.5, this.cubeWidth - 1, this.cubeWidth - 1); 104 } 105 } 106 107 //清除蛇 108 eraseSnake() { 109 var ctx = this.canvas.getContext("2d"); 110 ctx.fillStyle = this.comColor; 111 for (var i = 0; i < this.snake.body.length; i++) { 112 var y = parseInt(this.snake.body[i] / this.cubeNumber + ""); 113 var x = this.snake.body[i] - y * this.cubeNumber; 114 ctx.fillRect(x * this.cubeWidth + 0.5, y * this.cubeWidth + 0.5, this.cubeWidth - 1, this.cubeWidth - 1); 115 } 116 } 117 118 //检查蛇的位置状态 119 checkSnake() { 120 121 var head = this.snake.body[this.snake.body.length - 1]; 122 //如果蛇头在墙上,则弹出蛇已经死亡的消息 123 if (this.boardArray[head] == this.wallNum) { 124 //停止蛇的移动 125 clearInterval(this.snakeMoveInterval); 126 alert("Your snake has gone !"); 127 } 128 //如果蛇头位置在蛇身上 129 for (var i = 0; i < this.snake.body.length - 2; i++) { 130 if (this.snake.body[i] == head) { 131 //停止蛇的移动 132 clearInterval(this.snakeMoveInterval); 133 alert("Your snake has gone !"); 134 } 135 } 136 137 //如果设的下一个位置是青蛙,则吃掉青蛙 138 //计算当前位置 139 var y = parseInt("" + head / this.cubeNumber); 140 var x = head - y * this.cubeNumber; 141 var next = 0; 142 //计算下一个位置 143 switch (this.snake.direction) { 144 case Direction.Up: 145 next = head - this.cubeNumber; 146 break; 147 case Direction.Down: 148 next = head + this.cubeNumber; 149 break; 150 case Direction.Right: 151 next = head +1; 152 break; 153 case Direction.Left: 154 next = head - 1; 155 break; 156 } 157 //如果是青蛙,吃掉青蛙 158 if (this.boardArray[next] == this.frogNum) { 159 this.boardArray[next] = this.comNum; 160 this.snake.body.push(next); 161 this.setFrog(); 162 } 163 } 164 //绘制面板 165 drawBoard() { 166 var ctx = this.canvas.getContext("2d"); 167 //画横线 168 ctx.beginPath(); 169 ctx.translate(0.5, 0.5); 170 for (var y = 0; y <= this.cubeNumber; y++) { 171 ctx.moveTo(0, y * this.cubeWidth); 172 ctx.lineTo(this.cubeNumber * this.cubeWidth, y * this.cubeWidth); 173 } 174 //画竖线 175 for (var x = 0; x <= this.cubeNumber; x++) { 176 ctx.moveTo(x * this.cubeWidth, 0); 177 ctx.lineTo(x * this.cubeWidth, this.cubeNumber * this.cubeWidth); 178 } 179 ctx.stroke(); 180 181 //数学化面板,以行序存储 182 for (var y = 0; y < this.cubeNumber; y++) { 183 for (var x = 0; x < this.cubeNumber; x++) { 184 //如果是四周,则设置值为墙的值 185 if (x == 0 || y == 0 || x == this.cubeNumber - 1 || y == this.cubeNumber - 1) { 186 this.boardArray.push(this.wallNum); 187 } else { 188 this.boardArray.push(this.comNum); 189 } 190 } 191 } 192 193 //遍历boardArray绘制其中表示墙的区域 194 for (var i = 0; i < this.boardArray.length; i++) { 195 if (this.boardArray[i] == this.wallNum) { 196 var y = parseInt(i / this.cubeNumber + ""); 197 var x = i - y * this.cubeNumber; 198 this.drawWall(x, y); 199 } 200 } 201 202 203 } 204 //随机设置一个位置为青蛙(保证青蛙不在墙上或蛇身上) 205 getRandomFrog() { 206 var position = parseInt(""+ Math.random() * this.boardArray.length); 207 if (this.boardArray[position] == this.wallNum) { 208 //递归 209 return this.getRandomFrog(); 210 } 211 //检查是否在蛇身上 212 if (this.snake.body.indexOf(position) > -1) { 213 return this.getRandomFrog(); 214 } 215 return position; 216 } 217 218 //绘制青蛙 219 drawFrog(position) { 220 //计算x,y 221 var y = parseInt(position / this.cubeNumber + ""); 222 var x = position - y * this.cubeNumber; 223 var ctx = this.canvas.getContext("2d"); 224 ctx.fillStyle = this.frogColor; 225 ctx.fillRect(x * this.cubeWidth+0.5, y * this.cubeWidth+0.5, this.cubeWidth - 1, this.cubeWidth - 1); 226 } 227 228 //声称青蛙 229 setFrog() { 230 var position = this.getRandomFrog(); 231 //设置该区域为青蛙 232 this.boardArray[position] = this.frogNum; 233 //绘制青蛙 234 this.drawFrog(position); 235 } 236 //绑定键盘事件 237 bindKeyBoard() { 238 window.onkeydown = (e) => { 239 //如果和当前方向相反,无操作 240 if (e.keyCode+2!=this.snake.direction&&e.keyCode-2!=this.snake.direction) { 241 //如果和当前方向相同 242 if (e.keyCode == this.snake.direction) { 243 if (this.moveInterval - 200 >= 200) { 244 this.moveInterval -= 200; 245 clearInterval(this.snakeMoveInterval); 246 this.setSnakeMoveInterval(); 247 } 248 } else { 249 if (this.moveInterval + 200 <= 1000) { 250 this.moveInterval += 200; 251 clearInterval(this.snakeMoveInterval); 252 this.setSnakeMoveInterval(); 253 } 254 } 255 this.snake.direction = e.keyCode; 256 //检查蛇状态,吃掉青蛙 257 this.checkSnake(); 258 this.drawSnake(); 259 } 260 }; 261 } 262 263 //移动蛇 264 moveSnake() { 265 this.eraseSnake(); 266 this.moveSnake(); 267 this.checkSnake(); 268 this.drawSnake(); 269 } 270 271 //设置贪吃蛇循环运动 272 setSnakeMoveInterval() { 273 clearInterval(this.snakeMoveInterval); 274 this.snakeMoveInterval = setInterval(() => { 275 this.eraseSnake(); 276 this.snake.move(); 277 this.checkSnake(); 278 this.drawSnake(); 279 },this.moveInterval); 280 } 281 282 //开始游戏 283 start() { 284 this.initialUI(); 285 this.drawBoard(); 286 this.initialSnake(); 287 this.drawSnake(); 288 this.bindKeyBoard(); 289 this.setSnakeMoveInterval(); 290 this.setFrog(); 291 } 292 } 293 294 //window加载时启动游戏 295 window.onload = () => { 296 var game = new Game(); 297 game.start(); 298 } 299
下面是其编译后的JavaScript代码。
1 //方向类,方向数值和键盘方向键一致 2 var Direction; 3 (function (Direction) { 4 Direction[Direction["Up"] = 38] = "Up"; 5 Direction[Direction["Down"] = 40] = "Down"; 6 Direction[Direction["Right"] = 39] = "Right"; 7 Direction[Direction["Left"] = 37] = "Left"; 8 })(Direction || (Direction = {})); 9 10 //贪吃蛇类 11 var Snake = (function () { 12 function Snake() { 13 //蛇位置数组 14 this.body = []; 15 } 16 //在移动蛇 17 Snake.prototype.move = function () { 18 var i = 0; 19 for (; i < this.body.length - 1; i++) { 20 this.body[i] = this.body[i + 1]; 21 } 22 23 //根据方向计算蛇头位置 24 var cubeNumber = new Game().cubeNumber; 25 var y = parseInt(this.body[i] / cubeNumber + ""); 26 var x = this.body[i] - y * cubeNumber; 27 switch (this.direction) { 28 case 38 /* Up */: 29 this.body[i] = (y - 1) * cubeNumber + x; 30 break; 31 case 40 /* Down */: 32 this.body[i] = (y + 1) * cubeNumber + x; 33 break; 34 case 39 /* Right */: 35 this.body[i] = y * cubeNumber + x + 1; 36 break; 37 case 37 /* Left */: 38 this.body[i] = y * cubeNumber + x - 1; 39 break; 40 } 41 }; 42 return Snake; 43 })(); 44 45 var Game = (function () { 46 function Game() { 47 this.Width = 602; 48 this.Height = 602; 49 this.cubeWidth = 30; 50 this.cubeNumber = 20; 51 this.wallNum = -1; 52 this.comNum = 0; 53 this.snakeNum = 1; 54 this.frogNum = 2; 55 this.boardArray = []; 56 this.wallColor = "#cccccc"; 57 this.snakeColor = "#000000"; 58 this.comColor = "#ffffff"; 59 this.frogColor = "#00cc33"; 60 this.moveInterval = 1000; 61 } 62 //初始化贪吃蛇界面(本贪吃蛇比较简单,只有一个canvas) 63 Game.prototype.initialUI = function () { 64 //创建canvas并设置格式 65 this.canvas = document.createElement("canvas"); 66 this.canvas.height = this.Height; 67 this.canvas.width = this.Width; 68 this.canvas.style.margin = "30px auto auto auto"; 69 70 //this.canvas.style.border = "1px solid red"; 71 document.body.style.margin = "0px"; 72 document.body.style.textAlign = "center"; 73 document.body.appendChild(this.canvas); 74 }; 75 76 //在(x,y)坐标处绘制一块墙 77 Game.prototype.drawWall = function (x, y) { 78 var ctx = this.canvas.getContext("2d"); 79 ctx.fillStyle = this.wallColor; 80 81 //alert("(x,y)=>(" + (this.cubeWidth * x) + "," + (this.cubeWidth * y) + ")"); 82 //(x,y)各加0.5用来修正位置 83 ctx.fillRect(x * this.cubeWidth + 0.5, y * this.cubeWidth + 0.5, this.cubeWidth - 1, this.cubeWidth - 1); 84 }; 85 86 //初始化一条蛇(此处简化处理了) 87 Game.prototype.initialSnake = function () { 88 this.snake = new Snake(); 89 this.snake.direction = 39 /* Right */; 90 for (var i = 0; i < 4; i++) { 91 //从第二行开始位置设置一条向右运动的蛇 92 this.snake.body.push(this.cubeNumber + 1 + i); 93 } 94 }; 95 96 //绘制蛇 97 Game.prototype.drawSnake = function () { 98 //遍历蛇身 99 var ctx = this.canvas.getContext("2d"); 100 ctx.fillStyle = this.snakeColor; 101 for (var i = 0; i < this.snake.body.length; i++) { 102 //计算坐标 103 var y = parseInt(this.snake.body[i] / this.cubeNumber + ""); 104 var x = this.snake.body[i] - y * this.cubeNumber; 105 ctx.fillRect(x * this.cubeWidth + 0.5, y * this.cubeWidth + 0.5, this.cubeWidth - 1, this.cubeWidth - 1); 106 } 107 }; 108 109 //清除蛇 110 Game.prototype.eraseSnake = function () { 111 var ctx = this.canvas.getContext("2d"); 112 ctx.fillStyle = this.comColor; 113 for (var i = 0; i < this.snake.body.length; i++) { 114 var y = parseInt(this.snake.body[i] / this.cubeNumber + ""); 115 var x = this.snake.body[i] - y * this.cubeNumber; 116 ctx.fillRect(x * this.cubeWidth + 0.5, y * this.cubeWidth + 0.5, this.cubeWidth - 1, this.cubeWidth - 1); 117 } 118 }; 119 120 //检查蛇的位置状态 121 Game.prototype.checkSnake = function () { 122 var head = this.snake.body[this.snake.body.length - 1]; 123 124 //如果蛇头在墙上,则弹出蛇已经死亡的消息 125 if (this.boardArray[head] == this.wallNum) { 126 //停止蛇的移动 127 clearInterval(this.snakeMoveInterval); 128 alert("Your snake has gone !"); 129 } 130 131 for (var i = 0; i < this.snake.body.length - 2; i++) { 132 if (this.snake.body[i] == head) { 133 //停止蛇的移动 134 clearInterval(this.snakeMoveInterval); 135 alert("Your snake has gone !"); 136 } 137 } 138 139 //如果设的下一个位置是青蛙,则吃掉青蛙 140 //计算当前位置 141 var y = parseInt("" + head / this.cubeNumber); 142 var x = head - y * this.cubeNumber; 143 var next = 0; 144 145 switch (this.snake.direction) { 146 case 38 /* Up */: 147 next = head - this.cubeNumber; 148 break; 149 case 40 /* Down */: 150 next = head + this.cubeNumber; 151 break; 152 case 39 /* Right */: 153 next = head + 1; 154 break; 155 case 37 /* Left */: 156 next = head - 1; 157 break; 158 } 159 160 //如果是青蛙,吃掉青蛙 161 if (this.boardArray[next] == this.frogNum) { 162 this.boardArray[next] = this.comNum; 163 this.snake.body.push(next); 164 this.setFrog(); 165 } 166 }; 167 168 //绘制面板 169 Game.prototype.drawBoard = function () { 170 var ctx = this.canvas.getContext("2d"); 171 172 //画横线 173 ctx.beginPath(); 174 ctx.translate(0.5, 0.5); 175 for (var y = 0; y <= this.cubeNumber; y++) { 176 ctx.moveTo(0, y * this.cubeWidth); 177 ctx.lineTo(this.cubeNumber * this.cubeWidth, y * this.cubeWidth); 178 } 179 180 for (var x = 0; x <= this.cubeNumber; x++) { 181 ctx.moveTo(x * this.cubeWidth, 0); 182 ctx.lineTo(x * this.cubeWidth, this.cubeNumber * this.cubeWidth); 183 } 184 ctx.stroke(); 185 186 for (var y = 0; y < this.cubeNumber; y++) { 187 for (var x = 0; x < this.cubeNumber; x++) { 188 //如果是四周,则设置值为墙的值 189 if (x == 0 || y == 0 || x == this.cubeNumber - 1 || y == this.cubeNumber - 1) { 190 this.boardArray.push(this.wallNum); 191 } else { 192 this.boardArray.push(this.comNum); 193 } 194 } 195 } 196 197 for (var i = 0; i < this.boardArray.length; i++) { 198 if (this.boardArray[i] == this.wallNum) { 199 var y = parseInt(i / this.cubeNumber + ""); 200 var x = i - y * this.cubeNumber; 201 this.drawWall(x, y); 202 } 203 } 204 }; 205 206 //随机设置一个位置为青蛙(保证青蛙不在墙上或蛇身上) 207 Game.prototype.getRandomFrog = function () { 208 var position = parseInt("" + Math.random() * this.boardArray.length); 209 if (this.boardArray[position] == this.wallNum) { 210 //递归 211 return this.getRandomFrog(); 212 } 213 214 //检查是否在蛇身上 215 if (this.snake.body.indexOf(position) > -1) { 216 return this.getRandomFrog(); 217 } 218 return position; 219 }; 220 221 //绘制青蛙 222 Game.prototype.drawFrog = function (position) { 223 //计算x,y 224 var y = parseInt(position / this.cubeNumber + ""); 225 var x = position - y * this.cubeNumber; 226 var ctx = this.canvas.getContext("2d"); 227 ctx.fillStyle = this.frogColor; 228 ctx.fillRect(x * this.cubeWidth + 0.5, y * this.cubeWidth + 0.5, this.cubeWidth - 1, this.cubeWidth - 1); 229 }; 230 231 //声称青蛙 232 Game.prototype.setFrog = function () { 233 var position = this.getRandomFrog(); 234 235 //设置该区域为青蛙 236 this.boardArray[position] = this.frogNum; 237 238 //绘制青蛙 239 this.drawFrog(position); 240 }; 241 242 //绑定键盘事件 243 Game.prototype.bindKeyBoard = function () { 244 var _this = this; 245 window.onkeydown = function (e) { 246 //如果和当前方向相反,无操作 247 if (e.keyCode + 2 != _this.snake.direction && e.keyCode - 2 != _this.snake.direction) { 248 //如果和当前方向相同 249 if (e.keyCode == _this.snake.direction) { 250 if (_this.moveInterval - 200 >= 200) { 251 _this.moveInterval -= 200; 252 clearInterval(_this.snakeMoveInterval); 253 _this.setSnakeMoveInterval(); 254 } 255 } else { 256 if (_this.moveInterval + 200 <= 1000) { 257 _this.moveInterval += 200; 258 clearInterval(_this.snakeMoveInterval); 259 _this.setSnakeMoveInterval(); 260 } 261 } 262 _this.snake.direction = e.keyCode; 263 264 //检查蛇状态,吃掉青蛙 265 _this.checkSnake(); 266 _this.drawSnake(); 267 } 268 }; 269 }; 270 271 //移动蛇 272 Game.prototype.moveSnake = function () { 273 this.eraseSnake(); 274 this.moveSnake(); 275 this.checkSnake(); 276 this.drawSnake(); 277 }; 278 279 //设置贪吃蛇循环运动 280 Game.prototype.setSnakeMoveInterval = function () { 281 var _this = this; 282 clearInterval(this.snakeMoveInterval); 283 this.snakeMoveInterval = setInterval(function () { 284 _this.eraseSnake(); 285 _this.snake.move(); 286 _this.checkSnake(); 287 _this.drawSnake(); 288 }, this.moveInterval); 289 }; 290 291 //开始游戏 292 Game.prototype.start = function () { 293 this.initialUI(); 294 this.drawBoard(); 295 this.initialSnake(); 296 this.drawSnake(); 297 this.bindKeyBoard(); 298 this.setSnakeMoveInterval(); 299 this.setFrog(); 300 }; 301 return Game; 302 })(); 303 304 //window加载时启动游戏 305 window.onload = function () { 306 var game = new Game(); 307 game.start(); 308 };
效果图: