基于typescript下的贪吃蛇练习项目(内含源码)
Posted 是小橙鸭丶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于typescript下的贪吃蛇练习项目(内含源码)相关的知识,希望对你有一定的参考价值。
各位铁汁们,这个是我练习typescript时根据资料做的一个练习项目(用babel配置了浏览器的兼容,以及用postcss兼容各个浏览器的css3(IE))
这个贪吃蛇的规则:最高等级是十级,每吃三个食物升一级,(最高等级和吃几个食物升级可以自己自定义的)贪吃蛇移动速度加快,撞到墙撞到自己身体都会显示游戏GAME OVER! 以及贪吃蛇不可以自己掉头移动等
首先先将我们的项目进行一些简单配置(这里就不详细描述了),小伙伴们要是不理解可以去之前写过的webpack打包ts的配置可以看看,(依然送上我们的截图和代码)
1.package.json
{
"name": "part5",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \\"Error: no test specified\\" && exit 1",
"build": "webpack",
"start": "webpack serve --open chrome.exe"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/preset-env": "^7.14.2",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^4.0.0-alpha.0",
"core-js": "^3.12.1",
"css-loader": "^5.2.5",
"html-webpack-plugin": "^5.3.1",
"less": "^4.1.1",
"less-loader": "^9.0.0",
"postcss": "^8.3.0",
"postcss-loader": "^5.3.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^2.0.0",
"ts-loader": "^8.3.0",
"typescript": "^4.2.4",
"webpack": "^5.37.1",
"webpack-cli": "^4.7.0",
"webpack-dev-server": "^3.11.2"
}
}
2.tsconfig.json
{
"compilerOptions":{
"module": "ES2015",
"target": "ES2015",
"strict": false,
"noEmitOnError": true
}
}
3.webpack.config.js(直接上代码)
webpack配置css3兼容浏览器的
npm i -D postcss postcss-loader postcss-preset-env
// 引入一个包
const path = require('path')
// 引入html插件
let HtmlWebpackPlugin = require('html-webpack-plugin');
// 引入clean插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// webpack中的所有的配置信息都应该写在module.exports中
module.exports = {
//指定入口文件 通常放在src 源码目录
entry: "./src/index.ts",
// 指定打包文件所在目录
output:{
//指定打包文件的目录
path:path.resolve(__dirname, 'dist'),
// 打包后的文件
filename: "bundle.js",
//告诉webpack不要使用箭头函数以及const 我要兼容IE
environment:{
arrowFunction:false,
const:false
}
},
// 指定webpack打包时要使用的模块
module:{
//指定要加载的规则
rules:[
{
// test指定的是规则生效的文件//去匹配所有以ts结尾的文件
test:/\\.ts$/,
// 要使用对应的loader //从后往前执行 先执行ts-loader
use: [
//配置babel
{
//指定加载器
loader:"babel-loader",
//设置babel
options:{
// 设置预定义的环境
presets:[
[
//指定环境的插件
"@babel/preset-env",
//配置信息
{
//要兼容的目标浏览器
targets:{
//"chrome":"88" //兼容到chrome88版本最新的 语法都能识别
"chrome":"58",
"ie":"11" //要兼容ie 11 不支持const语法的
},
//指定corejs的版本
"corejs": "3", //比如我们用了promise ie11是没有promise语法的 此时corejs就起作用了
//使用core js的方式 "usage"表示按需加载
"useBuiltIns":"usage"
}
]
]
}
},
//'babel-loader' 配置选项少的时候直接用就行了 多的就像上面那样配置
'ts-loader'
],
// 要排除的文件
exclude:/node_modules/
},
//设置less文件的处理
{
test:/\\.less$/,
use:[
"style-loader",
"css-loader",
// 引入postcss
{
loader:"postcss-loader",
options:{
postcssOptions:{
plugins:[
[
"postcss-preset-env",
{
browsers:'last 2 version' //兼容两个最新的浏览器
}
]
]
}
}
},
"less-loader"
]
}
]
},
//配置webpack插件
plugins:[
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
//title:"这是一个自定义的title"
template:"./src/index.html" //引入你自己定义的模板
}),
],
// 用来设置引用模块
resolve:{
extensions: ['.ts', '.js']
}
}
4.我们在src目录下创建index.html和index.ts写上我们的基础页面,以及创建css目录下的index.less(这里引入less也已经在webpack配置好了, 以及我们引入postcss来兼容浏览器中的css3,兼容ie等,设置了兼容浏览器最新的两个版本)
index.html
<!DOCTYPE html>
<html land="zh">
<head>
<meta charset="UTF-8">
<title>贪吃蛇</title>
</head>
<body>
<!--创建游戏的主容器-->
<div id="main">
<!--设置游戏的舞台-->
<div id="stage">
<!--设置蛇-->
<div id="snake">
<!--snake内部的div 表示🐍的各个部位-->
<div>
</div>
</div>
<!--设置食物-->
<div id="food">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<!--设置游戏的记分牌-->
<div id="score-panel">
<div>
SCORE:<span id="score">0</span>
</div>
<div>
level:<span id="level">1</span>
</div>
</div>
</div>
</body>
</html>
index.less
//设置变量
@bg-color:#b7d4a8;
//清除默认样式
*{
margin: 0;
padding: 0;
// 改变盒子模型的计算方式
box-sizing: border-box;
}
body{
font:bold 20px "Courier";
}
//设置主窗口
#main{
width: 360px;
height: 420px;
background-color: @bg-color;
margin:100px auto;
border:10px solid black;
border-radius: 40px;
// 开启弹性盒模型
display: flex;
//设置主轴的方向
flex-flow:column;//纵向
//设置辅轴的对齐方式
align-items:center;
//设置主轴的对齐方式
justify-content: space-around;
#stage{
width: 304px;
height: 304px;
border:2px solid black;
//开启相对定位
position: relative;
//设置蛇的样式
#snake{
&>div{
width: 10px;
height: 10px;
background-color: #000;
border:1px solid @bg-color; //间隔缝隙
//开启绝对定位
position: absolute;
}
}
//设置食物样式
&>#food{
width: 10px;
height: 10px;
position: absolute;
left: 40px;
top:100px;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-content: space-between;
&>div{
width: 4px;
height: 4px;
background-color: red;
transform: rotate(45deg);
}
}
}
#score-panel{
width: 300px;
display: flex;
justify-content: space-between;
}
}
现在基本的页面样式都搭好了。
重点编写我们的ts内容,我们要将各个功能分成一个个类实现
主要的index.ts
//引入样式
import './css/index.less'
//引入各个类
import Food from './moduls/Food';
import ScorePanel from './moduls/ScorePanel';
const food = new Food()
food.change()
console.log(food.X, food.Y);
const scorePanel = new ScorePanel();
for(let i=0;i<210 ;i++){
scorePanel.addScore()
}
定义食物类Food.ts
//定义食物类Food
class Food{
// 定义一个属性表示食物所对应的元素
element:HTMLElement;
constructor(){
// 获取页面中的food元素并将其复制给element
this.element = document.getElementById('food')!;//!表示这东西不会为空
}
//定义一个获取食物X轴坐标的方法
get X(){
return this.element.offsetLeft;
}
//定义一个获取食物Y轴坐标的方法
get Y(){
return this.element.offsetTop;
}
//修改食物的位置
change(){
//生成一个随机的位置
//食物的位置 最小是0 最大是290(300-10 食物本身是10)
// 蛇移动一次就说一格,一格的大小就是10 所以就要求食物的坐标必须是整10
let top = Math.round(Math.random() * 29) * 10; //里面那个是取0-29的随机数 后面×10
let left = Math.round(Math.random() * 29) * 10;
this.element.style.left = left + 'px';
this.element.style.top = top + 'px';
}
}
//测试代码
// const food = new Food()
// food.change()
// console.log(food.X, food.Y);
export default Food;
效果如下图所示
也能获取到食物的位置
定义表示记分牌的类ScorePanel.ts(默认最高等级是10级,每一级升级分数需要10分(可以根据自己的传入的值而改变))
//定义表示记分牌的类
class ScorePanel{
//score 和level 用来记录分数和等级
score = 0;
level = 1;
// 分数和等级所在的元素,在构造函数中进行初始化
scoreEle:HTMLElement;
levelEle:HTMLElement;
//设置一个变量限制等级
maxLevel:number;
//设置一个变量表示升级所需要的分数
upScore:number
constructor(maxLevel:number = 10, upScore:number = 10){
this.scoreEle = document.getElementById('score')!;
this.levelEle = document.getElementById('level')!;
this.maxLevel = maxLevel
this.upScore = upScore
}
//设置一个加分的方法
addScore(){
this.score++;
this.scoreEle.innerHTML = this.score + ''; //把分数赋给页面
//判断分数是多少 能够整除10的时候就升一级
if(this.score % this.upScore === 0){
this.levelUp();
}
}
//设置一个升级的方法
levelUp(){
//小于我的最大等级在给你升级
if(this.level < this.maxLevel){
this.levelEle.innerHTML = ++this.level + '';
}
}
}
// //测试代码
// const scorePanel = new ScorePanel();
// for(let i=0;i<210 ;i++){
// scorePanel.addScore()
// }
export default ScorePanel
初步定义一个蛇的类Snake.ts
class Snake{
// 表示蛇头的元素
head:HTMLElement;
// 表示蛇的身体的元素(包括蛇头)
bodies:HTMLCollection; //会实时更新的
// 获取蛇的容器
element:HTMLElement;
constructor(){
this.element = document.getElementById('snake')!
this.head = document.querySelector('#snake > div')! as HTMLElement;//只取一个 所以表示蛇头
this.bodies = this.element.getElementsByTagName('div'); //获取snake里面所有的div
}
//获取蛇X轴的坐标(蛇头坐标)
get X(){
return this.head.offsetLeft;
}
// 获取蛇的Y轴坐标(蛇头坐标)
get Y(){
return this.head.offsetTop;
}
//设置蛇头的坐标
set X(value:number){
this.head.style.left = value + 'px';
}
set Y(value:number){
this.head.style.top = value + 'px';
}
//设置蛇增加身体的方法
addBody(){
//向element添加身体(添加div)
this.element.insertAdjacentHTML("beforeend","<div></div>")
}
}
接下来就是定义我们最重要的一个类GameControl.ts
1.首先是要定义键盘事件
注意: keydownHandler函数里面的this指向问题,下面提供了两种方法 ,一是使用bind(this)
二是使用了箭头函数,大家可以了解一下
//引入其他的类
import Snake from './Snake'
import Food from './Food'
import ScorePanel from './ScorePanel'
// 游戏控制器, 控制其他的所有类
class GameControl{
//定义三个属性
//蛇
snake:Snake;
//食物
food:Food;
//记分牌
scorePanel:ScorePanel;
//创建属性来存储蛇的移动方向(也就是我们按键的方向)
direction:string = '';
constructor() {
this.snake = new Snake();
this.food = new Food();
this.scorePanel = new ScorePanel();
this.init()
}
//游戏的初始化方法,调用后游戏即开始
init(){
// 绑定键盘按键按下的事件
//document.addEventListener('keydown', this.keydownHandler.bind(this)) //第一种解决方案-----调用bind(this) 创建一个新函数然后把(this)绑定成this.keydownHandler.bind(this)这个函数的this,所以(this)表示当前的对象 就不会有问题了
document.addEventListener('keydown', this.keydownHandler)
}
/**
*
* ArrowUp 上 Up(IE)
* ArrowDown 下 Down(IE)
* ArrowLeft 左 Left(IE)
* ArrowRight 右 Right(IE)
*/
//创建一个键盘按下的响应函数
// keydownHandler(event:KeyboardEvent){
// // 修改direction属性
// this.direction = event.key;
// }
//创建一个键盘按下的响应函数 //第二种解决方法改为箭头函数 解决this指向问题
keydownHandler = (event:KeyboardEvent) =>{
// 需要检查event.key的值是否合法(用户是否按了正确的按键)
// 修改direction属性
this.direction = event.key;
}
}
export default GameControl
我们在index.ts进行测试
//引入样式
import './css/index.less'
//引入各个类
import GameControl from './moduls/GameControl'
const gameControl = new GameControl()
setInterval(()=>{
console.log(gameControl.direction);
},1000)
结果如图所示
2.让蛇移动起来—重点看run的方法
//引入其他的类
import Snake from './Snake'
import Food from './Food'
import ScorePanel from 以上是关于基于typescript下的贪吃蛇练习项目(内含源码)的主要内容,如果未能解决你的问题,请参考以下文章