贪吃蛇小游戏,基于Ts开发的,做着玩。
实物类
class Food{
element: HTMLElement
constructor() {
this.element = document.querySelector('#food')!;
}
get X() {
return this.element.offsetLeft
}
get Y() {
return this.element.offsetTop
}
change() {
let top = Math.round(Math.random() * 29) * 10;
let left = Math.round(Math.random() * 29) * 10;
this.element.style.top=top + 'px'
this.element.style.left=left + 'px'
}
}
export default Food;
游戏控制类
import Food from "./Food";
import ScorePanel from "./ScorePanel";
import Snake from "./Snake";
class GameControls{
snake: Snake
food: Food
scorePanel: ScorePanel
direction=''
isLive = true
constructor() {
this.snake = new Snake()
this.food = new Food()
this.scorePanel = new ScorePanel(10,2)
this.init()
}
init() {
document.addEventListener('keydown',this.keydownHandler.bind(this))
this.run()
}
keydownHandler(event: KeyboardEvent) {
this.direction = event.key;
}
run() {
let X = this.snake.X;
let Y = this.snake.Y
switch (this.direction) {
case 'ArrowUp':
Y -= 10;
break;
case 'ArrowDown':
Y += 10;
break;
case 'ArrowLeft':
X -= 10;
break;
case 'ArrowRight':
X += 10;
break;
}
this.checkEat(X, Y);
try{
this.snake.X = X;
this.snake.Y = Y;
}catch (e) {
alert('Your snake is died!')
this.isLive = false
}
this.isLive && setTimeout(this.run.bind(this),300-(this.scorePanel.level-1)*30)
}
checkEat(X: number, Y:number) {
if (X === this.food.X && Y === this.food.Y) {
this.food.change()
this.scorePanel.addScore()
this.snake.addBody()
}
}
}
export default GameControls
计分类
class ScorePanel{
score = 0;
level = 1;
scoreEle: HTMLElement
levelEle: HTMLElement
maxLevel: number
upScore:number
constructor(maxLevel:number=10,upScore:number=10) {
this.scoreEle = document.querySelector('#score')!;
this.levelEle = document.querySelector('#level')!;
this.maxLevel = maxLevel
this.upScore = upScore
}
addScore() {
this.scoreEle.innerHTML = ++this.score + '';
if (this.score % this.upScore === 0)
{
this.levelUp()
}
}
levelUp() {
if (this.level < this.maxLevel) {
this.levelEle.innerHTML = ++this.level + '';
}
}
}
export default ScorePanel;
蛇
class Snake{
element: HTMLElement
head: HTMLElement;
// 蛇的身体(包括蛇头)
bodies: HTMLCollection;
constructor() {
this.element = document.getElementById('snake')!
this.head = document.querySelector('#snake>div') as HTMLElement;
this.bodies = this.element.getElementsByTagName('div')
}
get X() {
return this.head.offsetLeft
}
get Y() {
return this.head.offsetTop
}
set X(value) {
if (value === this.X) {
return;
}
if (value < 0 || value > 290) {
throw new Error
}
if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
if (value > this.X) {
value = this.X - 10;
}
else {
value = this.X + 10;
}
}
this.moveBody()
this.head.style.left = value + 'px';
this.checkHeadBody()
}
set Y(value) {
if (value === this.Y) {
return;
}
if (value < 0 || value > 290) {
throw new Error
}
if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
if (value > this.Y) {
value = this.Y - 10;
}
else {
value = this.Y + 10;
}
}
this.moveBody()
this.head.style.top = value + 'px'
this.checkHeadBody()
}
addBody() {
this.element.insertAdjacentHTML("beforeend","<div></div>")
}
moveBody() {
for (let i = this.bodies.length - 1; i > 0; i--){
let X = (this.bodies[i - 1] as HTMLElement).offsetLeft;
let Y = (this.bodies[i - 1] as HTMLElement).offsetTop;
(this.bodies[i] as HTMLElement).style.left = X + 'px';
(this.bodies[i] as HTMLElement).style.top = Y + 'px';
}
}
checkHeadBody() {
for (let i = 1; i < this.bodies.length; i++){
if (this.X === (this.bodies[i] as HTMLElement).offsetLeft && this.Y === (this.bodies[i] as HTMLElement).offsetTop) {
throw new Error
}
}
}
}
export default Snake;
相关的包依赖
"@babel/core": "^7.13.15",
"@babel/preset-env": "^7.13.15",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^4.0.0-alpha.0",
"core-js": "^3.10.1",
"css-loader": "^5.2.1",
"html-webpack-plugin": "^5.3.1",
"less": "^4.1.1",
"less-loader": "^8.1.0",
"postcss": "^8.2.10",
"postcss-loader": "^5.2.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^2.0.0",
"ts-loader": "^8.1.0",
"typescript": "^4.2.4",
"webpack": "^5.32.0",
"webpack-cli": "^4.6.0",
"webpack-dev-server": "^3.11.2"
webback-config.js的配置
// 引入一个包
const path = require('path');
// 引入html插件
const HTMLWebpackPlugin = require('html-webpack-plugin');
//引入clean插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// npm init -y 初始化 创建package.json文件
// npm i -D webpack webpack-cli typescript ts-loader 安装四个依赖
// 编写webpack配置文件
// 编写tsconfig.json文件
// 修改package.json中加上build命令
// npm i -D html-webpack-plugin //自动生成html
// npm i -D webpack-dev-server //自动响应浏览器更新
// npm i -D clean-webpack-plugin //清楚dist目录旧文件
//webpack 中所有的配置信息都应该写在module.exports中
module.exports = {
// 指定入口文件
entry: './src/index.ts',
// 指定打包文件所在目录
output: {
//指定打包文件的目录
path: path.resolve(__dirname, 'dist'),
//打包后文件的名字
filename: 'bundle.js',
//告诉webpack不使用箭头函数
environment: {
arrowFunction: false,
const: false, //兼容ie10
},
},
//指定webpack打包时要使用的模块
module: {
// 指定要loader加载的规则
rules: [
// 设置ts文件的处理
{
// test指定的时规则生效的文件
test: /\.ts$/, //以ts结尾的文件
// 要使用的loader
use: [
// 配置babel
{
//指定加载器
loader: 'babel-loader',
// 设置babel
options: {
//设置预定义的环境
presets: [
[
//指定环境的插件
'@babel/preset-env',
// 配置信息
{
// 要兼容的目标浏览器及版本
targets: {
chrome: '58',
ie: '11',
},
//指定corejs的版本
corejs: '3',
//使用corejs的方式 "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 versions', //兼容每个浏览器最新的两个版本
},
],
],
},
},
},
'less-loader',
],
},
],
},
// mode: "development", //设置mode
//配置Webpack 插件
plugins: [
new CleanWebpackPlugin(),
new HTMLWebpackPlugin({
// title: "这是一个自定义的title"、
template: './src/index.html',
}),
],
// 用来设置引用模块,可以将这些文件识别为模块
resolve: {
extensions: ['.ts', '.js'],
},
};