TypeScript实现一个贪吃蛇小游戏

游戏效果

文件目录

准备1:新建index.html,编写游戏静态页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<body>
    <div class="main">
        <div class="stage">
            <div id="snake">
                <div></div>
            </div>
            <div id="food">
                <div></div>
            </div>
        </div>
        <div class="score-panel">
            <div>
                SCORE: <span id="score">0</span>
            </div>
            <div>
                level: <span id="level">1</span>
            </div>
        </div>
    </div>
</body>
</html>

准备2:使用less,修改样式,编写CSS

//设置变量
@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: black;
                border: 1px solid @bg-color;
                //绝对定位
                position: absolute;
            }
            
        }
        #food{
            position: absolute;
            left: 40px;
            top: 100px;
            background-color: rebeccapurple;
            display: flex;
            flex-flow: row wrap;
            justify-content: space-between;
            align-content: space-between;
            &>div{
                width: 4px;
                height: 4px;
                background-color: black;
                transform: rotate(45deg);
            }
        }
    }
    //记分牌
    .score-panel {
        width: 300px;
        display: flex;
        justify-content: space-between;

    }
}

准备3:创建4个类:食物类-Food、记分牌等级类-ScorePanel、蛇类-Snake、操控类-GameControl

//食物类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(){
        //生成一个随机的位置
        let top = Math.round(Math.random()*29)*10
        let left = Math.round(Math.random()*29)*10

        //食物的位置最小的0,最大是290
        //蛇移动一次就是一格,一格的大小就是10,所以就要求食物的
        this.element.style.left = left + 'px'
        this.element.style.top = top + 'px'
    }
}
export default Food
//记分牌的类
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(){
        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:number){
        //如果新值和旧值相同,则直接返回不再修改
        if(this.X ===value){
            return
        }
        //X的值的合法范围在0-290之间
        if(value <0 || value >290){
            //进入判断说明蛇撞墙了
            throw new Error('蛇撞墙了')
        }
        //修改X时,是在修改水平坐标,蛇在左右移动,蛇向左移动时,不能向右移动,反之亦然
        if(this.bodies[1]&&(this.bodies[1] as HTMLElement).offsetLeft ===value){
            //如果发送了掉头,让蛇向反方向继续移动
            if(value >this.X){
                //如果新值value大于旧值X,则说明蛇在向右走,此时发送掉头,应该使蛇继续向左走
                value = this.X - 10;
            }else{
                //向左走
                value = this.X + 10
            }
        }
        //移动身体
        this.moveBody()
        this.head.style.left = value + 'px'
        this.checkHeadBody()
    }
    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){
            //如果发送了掉头,让蛇向反方向继续移动
            if(value >this.Y){
                //如果新值value大于旧值Y,则说明蛇在向下走,此时发送掉头,应该使蛇继续向上走
                value = this.Y - 10;
            }else{
                //向左走
                value = this.Y + 10
            }
        }
        this.moveBody()
        this.head.style.top = value + 'px'
        //检查有没有撞到自己
        this.checkHeadBody()
    }
    //蛇增加身体的方法
    addBody(){
        //向element中添加一个div
        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++){
            let bd = this.bodies[i] as HTMLElement
            if(this.X ===bd.offsetLeft && this.Y === bd.offsetTop){
                //进入判断说明蛇头撞到了身体,游戏结束
                throw new Error('撞到了自己!!!')
            }
        }
    }
}
export default Snake
//控制类
import Food from './Food'
import ScorePanel from './ScorePanel'
import Snake from './Snake'
//游戏控制器,控制其他的所有类
class GameControl{
    //定义一个属性
    //蛇
    snake :Snake
    //食物
    food:Food
    //记分牌
    scorePanel:ScorePanel
    //创建一个属性来存储蛇的移动方向(也就是按键的方向)
    direction :string = ''
    //创建一个属性用来记录游戏是否结束
    isLive = true
    constructor(){
        this.snake = new Snake()
        this.food = new Food()
        this.scorePanel = new ScorePanel()
        this.init()
    }
    //游戏的初始化方法,调用后游戏即开始
    init(){
        //绑定键盘按键按下的事件
        document.addEventListener('keydown',this.keydownHandler.bind(this))
        //调用run方法,使蛇移动
        this.run()
    }
    //创建一个键盘按下的响应函数
    keydownHandler(event:KeyboardEvent){
        //需要检查event.key的值是否合法(用户是否按了正确的按键)
        //修改direction属性
        this.direction = event.key
    }
    //创建一个控制蛇移动的方法
    run (){
        /*
         * 根据方向(this.direction)来使蛇的位置改变
         * 向上 top减少
         * 向下top增加
         * 向左 left减少
         * 向右left 增加 
         */
        //获取蛇现在的坐标
        let X  = this.snake.X
        let Y = this.snake.Y
        //根据按键方向
        switch(this.direction){
            case "ArrowUp":
            case 'Up':
                //向上移动top减少
                Y -=10;
                break;
            case 'ArrowDown':
            case 'Down':
                //向下移动top增加
                Y+=10;
                break;
            case 'ArrowLeft':
            case 'Left':
                //向左移动left 减少
                X-=10;
                break;
            case 'ArrowRight':
            case 'Right':
                //向右移动left 增加
                X+=10;
                break;
        }
        //检查蛇是否吃到食物
        this.checkEat(X,Y)
        //修改蛇的X、Y方向
        try {
            this.snake.X = X;
            this.snake.Y = Y ;           
        } catch (e:any) {
            //进入到catch,说明出现了异常,游戏结束,弹出一个提示信息
            alert(e.message + 'GAME OVER')
            //将isLive设置为false
            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 GameControl

准备4:创建index.ts文件,执行游戏

import './style/index.less'
import GameControl from './moduls/GameControl'

new GameControl()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/333006.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Java图书商城系统设计与实现(源码+部署文档)

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…

Windows连接Ubuntu桌面

平时Windows连接Ubuntu服务器都是使用Xshell、FinalShell等工具&#xff0c;但这些连接之后只能通过终端进行操作&#xff0c;无法用桌面方式与服务器交互。 本文介绍如何通过工具&#xff0c;实现Window连接远程Ubuntu服务器&#xff0c;并使用桌面方式交互。 系统版本&#x…

【leetcode】消失的数字

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家刷题&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 1.暴力求解法2.采用异或的方法&#xff08;同单身狗问题&#xff09;3.先求和再减去数组元素 点击查看…

基于ssm+vue的宠物医院系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

后面的输入框与前面的联动,输入框只能输入正数

概要 提示&#xff1a;这里可以描述概要 前面的输入框是发票金额&#xff0c;后面的输入框是累计发票金额&#xff08;含本次&#xff09;--含本次就代表后倾请求的接口的数据&#xff08;不是保存后返显的-因为保存后返显的是含本次&#xff09;是不含本次的所以在输入发票金…

四款免费、易用的Docker漏洞扫描工具

本文向您介绍四种既可以扫描Docker镜像中的漏洞&#xff0c;又能够被轻松地集成到CI/CD中的四种免费实用工具。 基本原理 所有这些工具的工作原理都比较类似。它们使用的是如下两步流程&#xff1a; 生成软件物料清单(Software Bill of Materials&#xff0c;SBOM)。将SBOM与…

虚拟线程探索与实践(JDK19)

优质博文&#xff1a;IT-BLOG-CN 一、简介 虚拟线程是轻量级线程&#xff0c;极大地减少了编写、维护和观察高吞吐量并发应用的工作量。虚拟线程是由JEP 425提出的预览功能&#xff0c;并在JDK 19中发布&#xff0c;JDK 21中最终确定虚拟线程&#xff0c;以下是根据开发者反馈…

解锁文字魔法:探索自然语言处理的秘密——从技术揭秘到应用实战!

目录 前言 关键技术——揭密自然语言处理的秘密武器&#xff01; 领域应用——自然语言处理技术在不同领域的奇妙表演&#xff01; 超越极限——自然语言处理技术面临的顽强挑战揭秘&#xff01; 科技VS伦理——自然语言处理技术的发展与伦理社会的纠结较量&#xff01; 开…

LINUX基础培训十一之日志管理

前言、本章学习目标 了解LINUX中日志文件及其功能掌握rsyslog服务及启动方法熟悉日志文件格式的分析 一、Linux日志常见文件及其功能 日志文件是重要的系统信息文件&#xff0c;其中记录了许多重要的系统事件&#xff0c;包括用户的登录信息、系统的启动信息、系统的安全信…

最长上升子序列模型(LIS)

最长上升子序列模型就像它的名字一样&#xff0c;用来从区间中找出最长上升的子序列。它主要用来处理区间中的挑选问题&#xff0c;可以处理上升序列也可以处理下降序列&#xff0c;原序列本身的顺序并不重要。 模型 895. 最长上升子序列&#xff08;活动 - AcWing&#xff0…

分享一个基于easyui前端框架开发的后台管理系统模板

这是博主自己在使用的一套easyui前端框架的后台管理系统模版&#xff0c;包含了后端的Java代码&#xff0c;已经实现了菜单控制、权限控制功能&#xff0c;可以直接拿来使用。 springboot mybatis mybatis-plus实现的增删查改完整项目&#xff0c;前端使用了easyui前端框架。…

怎么在桌面查看备忘录新的提醒事项?方法教程

在这个信息爆炸的时代&#xff0c;我们每天都面临着无数的任务和提醒。作为一名忙碌的职场人&#xff0c;我经常需要依赖备忘录来记录重要的待办事项&#xff0c;以免遗漏。备忘录&#xff0c;就像我生活中的小助手&#xff0c;帮我记下工作会议、生日提醒、购物清单等等&#…

基于 Hologres+Flink 的曹操出行实时数仓建设

本文整理自曹操出行实时计算负责人林震基于 HologresFlink 的曹操出行实时数仓建设的分享&#xff0c;内容主要分为以下六部分&#xff1a; 曹操出行业务背景介绍曹操出行业务痛点分析HologresFlink 构建企业级实时数仓曹操出行实时数仓实践曹操出行业务成果分析未来展望 一、曹…

基于Vue+Canvas实现的画板绘画以及保存功能,解决保存没有背景问题

基于VueCanvas实现的画板绘画以及保存功能 本文内容设计到的画板的js部分内容来源于灵感来源引用地址&#xff0c;然后我在此基础上&#xff0c;根据自己的需求做了修改&#xff0c;增加了其他功能。 下面展示了完整的前后端代码 这里写目录标题 基于VueCanvas实现的画板绘…

OpenAI GPT应用商城正式上线!超300万个GPT应用供选择

原创 | 文 BFT机器人 千呼万唤始出来&#xff0c;终于在北京时间1月11日凌晨&#xff0c;OpenAI在官网发布了令人振奋的消息&#xff1a;备受瞩目的GPT store正式上线&#xff01; 这个商店旨在让团体和企业用户轻松找到那些既实用又热门的GPT应用。在这里&#xff0c;用户可以…

python基础知识

python基础语法 python基础精讲 http://t.csdnimg.cn/HdKdi 本专栏主要针对python基础语法&#xff0c;帮助学习者快速接触并掌握python大部分最重要的语法特征。 1、基本数据类型和变量 2、分支结构与循环结构 3、函数与异常处理 4、类与模块 5、文件读写 通过本专栏可以快…

Unity 编辑器篇|(十)Handles (全面总结 | 建议收藏)

目录 1. 前言2 参数总览3 Handles两种使用方式3.1 基于Editor类的OnSceneGUI3.2 基于EditorWindow 4 Handles绘制4.1 Draw&#xff1a;绘制元几何体(点、线、面)4.1.1 抗锯齿&#xff1a; DrawAAPolyLine 、 DrawAAConvexPolygon4.1.2 绘制实线: DrawLine 、 DrawLines 、DrawP…

(2)(2.1) Andruav Android Cellular(一)

文章目录 前言 1 Andruav 是什么&#xff1f; 2 Andruav入门 3 Andruav FPV 4 Andruav GCS App​​​​​​​ 前言 Andruav 是一个基于安卓的互联系统&#xff0c;它将安卓手机作为公司计算机&#xff0c;为你的无人机和遥控车增添先进功能。 1 Andruav 是什么&#xff…

门禁监控如何提升安全系数?这个技术,学习一下!

随着社会的不断发展和科技的快速进步&#xff0c;安全管理成为各个领域至关重要的议题。在这一背景下&#xff0c;门禁监控系统逐渐崭露头角&#xff0c;成为保障建筑物和场所安全的关键工具。 门禁监控系统不仅在提高安全性方面发挥着积极作用&#xff0c;而且通过智能化的技术…

《模拟龙生》|500行Go代码写一个随机冒险游戏|巨龙修为挑战开启

一、前言 新年就要到了&#xff0c;祝大家新的一年&#xff1a;&#x1f432; 龙行龘龘&#xff0c;&#x1f525; 前程朤朤&#xff01; 白泽花了点时间&#xff0c;用 500行 Go 代码写了一个控制台的小游戏&#xff1a;《模拟龙生》&#xff0c;在游戏中你将模拟一条新生的…