首页 > 其他分享 >【TypeScript教程】# 16:ts + webpack + less实现贪吃蛇小游戏

【TypeScript教程】# 16:ts + webpack + less实现贪吃蛇小游戏

时间:2022-10-16 16:06:59浏览次数:64  
标签:10 TypeScript 16 less value element snake HTMLElement bodies


项目搭建

我们以demo3的项目为基础,可以复制一份过来

【TypeScript教程】# 16:ts + webpack + less实现贪吃蛇小游戏_贪吃蛇

在这个基础上添加less相关的处理

npm i -D less

然后添加postcss处理兼容性问题

npm

最后配置webpack

// 设置less文件的处理
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{
browsers: "last 2 versions"
}
]
]
}
}
},
"less-loader"
]
}

能将我们写的less文件编译成css即可:

body {
background-color: #eee;
display: flex;
}

【TypeScript教程】# 16:ts + webpack + less实现贪吃蛇小游戏_webpack_02

项目界面

界面效果如下:

【TypeScript教程】# 16:ts + webpack + less实现贪吃蛇小游戏_webpack_03

html的代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>贪吃蛇</title>
</head>
<body>
<div id="app">
<div id="stage">
<div id="snake">
<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>

样式代码

@bg-color: #ebebeb;

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font: 20px bold "Courier";
}

#app {
display: flex;
flex-flow: column;
align-items: center;
justify-content: space-around;
width: 360px;
height: 420px;
background-color: @bg-color;
margin: 100px auto;
border-radius: 6px;
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.4);

#stage {
width: 304px;
height: 304px;
border: 2px solid #c9c9c9;
position: relative;
#snake {
&>div {
width: 10px;
height: 10px;
background-color: blueviolet;
border: 1px solid @bg-color;
position: absolute;
}
}
#food {
width: 10px;
height: 10px;
position: absolute;
top: 100px;
left: 40px;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-content: space-between;
&>div {
width: 4px;
height: 4px;
background-color: green;
transform: rotate(45deg);
}
}
}

#score-panel {
display: flex;
justify-content: space-between;
width: 304px;
}
}

完成Food类

class Food{
// 定义一个属性表示食物所对应的元素
element: HTMLElement;
constructor() {
// 变量后使用 !:表示类型推断排除null、undefined
this.element = document.getElementById("food")!;
}
// 定义一个获取食物的X轴坐标的方法
get X() {
return this.element.offsetLeft;
}
// 定义一个获取食物的Y轴坐标的方法
get Y() {
return this.element.offsetTop;
}
// 修改食物位置
change() {
// 生成一个随机的位置
// 食物的位置最小是0,最大是290,一格是10
let left = Math.round(Math.random() * 29) * 10;
let top = Math.round(Math.random() * 29) * 10;
this.element.style.left = `${left}px`;
this.element.style.top = `${top}px`;
}
}
export default Food;

每次调用change都可以修改到食物的位置,让其在stage里随机显示

【TypeScript教程】# 16:ts + webpack + less实现贪吃蛇小游戏_typescript_04

完成ScorePanel类

// 定义表示记分牌的类
class ScorePanel{
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.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;

完成Snake类

// 定义蛇类
class Snake{
// 表示蛇头所对应的元素
head: HTMLElement;
// 蛇的身体(包含蛇头)
bodies: HTMLCollection;
// 获取蛇的容器
element: HTMLElement;
constructor() {
// 变量后使用 !:表示类型推断排除null、undefined
this.element = document.querySelector("#snake")!;
this.head = document.querySelector("#snake > div") as HTMLElement;
this.bodies = this.element.getElementsByTagName("div");
}
// 获取蛇头的X轴坐标
get X() {
return this.head.offsetLeft;
}
// 获取蛇头的Y轴坐标
get Y() {
return this.head.offsetTop;
}
// 设置蛇头的X轴坐标
set X(value: number) {
if(this.X === value) {
return;
}
// 撞墙
if(value < 0 || value > 290) {
throw new Error("蛇撞墙了");
}

// 修改x时,是在修改水平坐标, 蛇在左右移动,蛇在向左移动时,不能向右掉头, 反之亦然
if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
console.log("水平方向发生了调头");
value = value > this.X ? this.X - 10 : this.X + 10;
}

// 移动身体
this.moveBody();
this.head.style.left = `${value}px`;
// 检查蛇头是否撞到身体
this.checkHeadBody();
}
// 设置蛇头的Y轴坐标
set Y(value: number) {
if(this.Y === value) {
return;
}
// 撞墙
if(value < 0 || value > 290) {
throw new Error("蛇撞墙了");
}
// 修改y时,是在修改垂直坐标, 蛇在上下移动,蛇在向上移动时,不能向下掉头, 反之亦然
if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
console.log("垂直方向发生了调头");
value = value > this.Y ? this.Y - 10 : this.Y + 10;
}

// 移动身体
this.moveBody();
this.head.style.top = `${value}px`;
// 检查蛇头是否撞到身体
this.checkHeadBody();
}
// 蛇增加身体的方法
addBody() {
// 向element添加一个div
// insertAdjacentElement 将一个给定的元素节点插入到相对于被调用的元素的给定的一个位置。
// beforeend 只在该元素当中,在该元素最后一个子孩子后面。
this.element.insertAdjacentElement("beforeend", document.createElement("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++) {
let bd = this.bodies[i] as HTMLElement;
if(this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
throw new Error("撞到自己了!");
}
}
}
}

export default Snake;

GameControl键盘事件以及使蛇移动

import Food from "./Food";
import Snake from "./Snake";
import ScorePanel from "./ScorePanel";

// 游戏控制器,控制其他的所有类
class GameControl {
food: Food;
snake: Snake;
scorePanel: ScorePanel;
// 方向
direction: String = "";
// 是否结束
isLive = true;
constructor() {
this.food = new Food();
this.snake = new Snake();
this.scorePanel = new ScorePanel(10, 1);

this.init();
}

// 游戏初始化
init() {
document.addEventListener("keydown", this.keydownHandler.bind(this));
this.run();
}
/**
* 按下事件
* ArrowUp Up
* ArrowRight Right
* ArrowDown Down
* ArrowLeft Left
*/
keydownHandler(event: KeyboardEvent) {
console.log(event);
// 检查是否合法
this.direction = event.key;
}
// 控制蛇移动,根据方向移动
run() {
/**
* ArrowUp Up:top -
* ArrowRight Right:left +
* ArrowDown Down:top +
* ArrowLeft Left:left -
*/

// 蛇现在的坐标
let X = this.snake.X;
let Y = this.snake.Y;

switch(this.direction){
case "ArrowUp":
case "Up":
Y -= 10;
break;
case "ArrowRight":
case "Right":
X += 10;
break;
case "ArrowDown":
case "Down":
Y += 10;
break;
case "ArrowLeft":
case "Left":
X -= 10;
break;
}

// 检查是否吃到食物
this.checkEat(X, Y);

// 修改XY
try {
this.snake.X = X;
this.snake.Y = Y;
} catch (e) {
alert(e);
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) {
console.log("吃到食物了!");
// 食物重置
this.food.change();
// 分数增加
this.scorePanel.addScore();
// 蛇增加一节
this.snake.addBody();
}
}
}

export default GameControl;

实例化GameControl

最后引入控制器实例化即可。

import "./style/index.less";

import GameControl from "./modules/GameControl";

new GameControl();

蛇撞墙和吃食检测效果

【TypeScript教程】# 16:ts + webpack + less实现贪吃蛇小游戏_贪吃蛇_05

【TypeScript教程】# 16:ts + webpack + less实现贪吃蛇小游戏_html_06

目录结构

整体的目录结构如下:

【TypeScript教程】# 16:ts + webpack + less实现贪吃蛇小游戏_贪吃蛇_07


标签:10,TypeScript,16,less,value,element,snake,HTMLElement,bodies
From: https://blog.51cto.com/kaimo313/5760337

相关文章

  • 【luogu P5161】WD与数列(SA)(单调栈)
    WD与数列题目链接:luoguP5161题目大意给你一个序列,问你有多少对区间,长度相同,没有相交部分,而且一个区间里面所有数同时加上某个数可以变成另一个区间。思路首先发现它......
  • TypeScript笔记
    TS(就是JS的超集)是静态类型是弱类型(允许隐式转化)下载Ts编译器:npmi-gtypescript查看Ts:tsc使用编译器将Ts文件编译成为js文件使用:tsc文件名.ts指定路径输出:tsc--......
  • 2022.10.16小记
    今天心情好差,不想计算倒计时了,感觉又开始迷茫了今天小姐妹结婚,可惜我不能去参加婚礼关于一件浪漫的事,分扣太多就不要了吧,到此为止明天要学仰泳了周日了,抓紧时间弥......
  • 10.16
       第一次报错   报错语句   第二次报错   执行语句   第三次报错   执行语句   并且除了第一次报错外,每次运行都成功生......
  • TypeScript Type Manipulation All In One
    TypeScriptTypeManipulationAllInOneCreatingTypesfromTypesGenericsKeyofTypeOperatorTypeofTypeOperatorIndexedAccessTypesConditionalTypesMa......
  • Typescript助力项目开发:JS切换TS、TS类型定制与思考
    TS已经成为可以帮助项目顺利开发的存在了。在上半年笔者就被要求采用TS开发新的项目,并在一些老项目中用TS去改造(因为沟通原因我以为某个远程组件只有TS版本)。在其中也有了一......
  • [Typescript] 51. Medium - Mutable
    Implementthegeneric Mutable<T> whichmakesallpropertiesin T mutable(notreadonly).ForexampleinterfaceTodo{readonlytitle:stringreadonlyd......
  • 116. 填充每个节点的下一个右侧节点指针
    题目描述给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:structNode{intval;Node*left;Node*right;Node*n......
  • TypeScript中Never类型和类型断言
    Never类型never类型表示:那些永不存在的值的类型。例如:never类型是那些总是会【抛出异常】或根本就【不会有返回值的函数表达式】或【箭头函数表达式的返回值类型】ne......
  • 116. 填充每个节点的下一个右侧节点指针
    /*//DefinitionforaNode.classNode{public:intval;Node*left;Node*right;Node*next;Node():val(0),left(NULL),right(NULL),n......