首页 > 编程语言 >贪吃蛇游戏源码

贪吃蛇游戏源码

时间:2023-01-30 00:44:05浏览次数:44  
标签:10 游戏 value loader webpack 源码 snake 贪吃蛇 bodies

 

 

//定义食物类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() {
        // left:0-290,top:0-290 需要被10整除,蛇移动一次就是一格(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

  

//游戏控制器,控制其他所有类
import Snake from "./Snake";
import Food from "./Food";
import ScorePanel from "./ScorePanel";

class GameControl {
    //定义三个属性
    //蛇
    snake: Snake;
    food: Food;
    scorePanel: ScorePanel;
    //创建一个属性存储蛇的移动放心
    direction: string = '';
    //创建一个属性记录游戏是否结束
    isLive: boolean = true;
    constructor() {
        this.snake = new Snake();
        this.food = new Food();
        this.scorePanel = new ScorePanel(10,2);
        this.init()
    }
    //游戏初始化方法调用后游戏就开始
    init() {
        //绑定键盘按下的事件
        document.addEventListener('keydown', this.keydowHandler.bind(this))
        this.run()
    }
    //创建一个键盘按下的响应函数
    keydowHandler(e) {
        console.log(e.key);
        //需要检验key的值是否合法(用户是否按了正确的案件)
        this.direction = e.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':
                //向左移动x减小
                x -= 10;
                break;
            case 'ArrowRight':
            case 'Right':
                //向右移动x增加
                x += 10;
                break;
        }
         //检查蛇是否吃到了食物
          this.checkEat(x,y)
        //修改蛇的位置
        try {
            this.snake.X = x;
            this.snake.Y = y;
        } catch (e) {
            //进入catch,说明除了异常,游戏结束,弹出一个信息提示
            alert(e.message + 'GAME OVER !');//弹出提示
            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

  

//定义记分牌类
class ScorePanel {
    maxLevel:number//限制最大等级
    upScore:number//多少分升级 
    //score和level用来记录分数和等级
    private _score: number = 0;
    private _level: number = 1;
    //分数和等级所在元素
    scoreEle: HTMLElement;
    levelEle: HTMLElement;
    constructor(maxlevel:number = 10,upScore:number=10) {
        this.maxLevel = maxlevel;
        this.upScore = upScore
        this.scoreEle = document.getElementsByClassName('score')[0] as HTMLAreaElement;
        this.levelEle = document.getElementsByClassName('level')[0] as HTMLAreaElement;
    }
    get score() {
        return this._score
    }
    get level() {
        return this._level
    }
    //设置一个加分的方法
    addScore(){
       let score = ++this._score;
        this.scoreEle.innerHTML = `${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 {
    //表示蛇头的元素
    head: HTMLElement;
    //表示身体的元素
    bodies: HTMLCollection;
    //获取蛇的容器
    element: HTMLElement

    constructor() {
        this.head = document.querySelector('#snake > div')
        this.bodies = document.getElementById('snake').getElementsByTagName('div')
        this.element = document.getElementById('snake');
    }
    //获取蛇的坐标(蛇头坐标)
    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]) {
            //判断是否有第二截身体
            if (value === (this.bodies[1] as HTMLElement).offsetLeft) {
                //判断即将改变的蛇头的坐标是否和第二截身体的坐标相同,相同就发生了掉头
                //console.log('发生了掉头');
                //如果发生了掉头,让蛇向反方向继续移动
                if(value>this.X){
                    //如果value大于X,则说明蛇在向右走
                    value = this.X-10
                }else{
                    value = this.X+10
                }               
            }
        }

        //移动身体
        this.moveBody()

        this.head.style.left = `${value}px`;
        try {
            this.checkHeadBody()
        } catch (error) {
            alert(error.message+'GAME OVER !')
        }

    }
    set Y(value: number) {
        if (this.Y == value) {
            return;
        }
        if (value < 0 || value > 290) {
            //蛇撞墙的处理
            throw new Error('蛇撞墙了')
        }
         //修改Y时,是在修改蛇的垂直坐标,蛇在上下移动,蛇向上移动时,不能向下移动,反之亦然
         if (this.bodies[1]) {
            //判断是否有第二截身体
            if (value === (this.bodies[1] as HTMLElement).offsetTop) {
                //判断即将改变的蛇头的坐标是否和第二截身体的坐标相同,相同就发生了掉头
                //console.log('发生了掉头');
                //如果发生了掉头,让蛇向反方向继续移动
                if(value>this.Y){
                    //如果value大于Y,则说明蛇在向上走
                    value = this.Y-10
                }else{
                    value = this.Y+10
                }               
            }
        }
        //移动身体
        this.moveBody()
        this.head.style.top = `${value}px`;
        try {
            this.checkHeadBody()
        } catch (error) {
            alert(error.message+'GAME OVER !')
        }
    }
    //蛇增加身体的方法
    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

  

<!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 class="main">
        <!-- 舞台 -->
        <div class="stage">
            <!-- 蛇容器 -->
            <div id="snake">
                <!-- 蛇的各个部分 -->
                <div></div>
            </div>
            <div id="food">
                <!-- 添加4个div设置蛇的样式 -->
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                
            </div>
        </div>
        <!-- 计分板 -->
        <div class="score-panel">
            <div>
                SCORE:<span class="score">0</span>
            </div>
            <div>
                LEVEL:<span class="level">1</span>
            </div>
        </div>
    </div>
</body>
</html>

  

import './style/index.less'
import GameControl from './moduls/GameControl'
new GameControl();
   

  

@bgcl: #b7d4a8;

* {
    margin: 0;
    padding: 0;
    //改变盒子模型的计算方式
    box-sizing: border-box;
}

.main {
    width: 360px;
    height: 420px;
    background-color: @bgcl;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border: solid 10px #000000;
    border-radius: 5%;
}

.stage {
    width: 304px;
    height: 304px;
    border: 2px solid black;
    margin: 20px 18px;
    //开启相对定位
    position: relative;

    #snake>div {
        width: 10px;
        height: 10px;
        background-color: #000000;
        border: 1px solid @bgcl;
        //开启绝对定位
        position: absolute;
    }
 
}
#food{
    width: 10px;
    height: 10px;
    border: 1px solid @bgcl;
    position: absolute;
    left: 200px;
    top: 100px;
    display: flex;
    flex-flow: row wrap;
    justify-content: space-between;
    align-content: space-between;
    &>div{
        width: 3px;
        height: 3px;
        background-color: #000000;
        transform: rotate(45deg);
       
    }
}

.score-panel {
    display: flex;
    width: 85%;
    margin: 10px auto;
    justify-content: space-between;
}

  

{
  "name": "part3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --mode production",
    "dev": "webpack --mode development",
    "start": "webpack serve --open "
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.20.7",
    "@babel/preset-env": "^7.20.2",
    "babel-loader": "^9.1.0",
    "clean-webpack-plugin": "^4.0.0",
    "core-js": "^3.26.1",
    "css-loader": "^6.7.3",
    "html-webpack-plugin": "^5.5.0",
    "less": "^4.1.3",
    "less-loader": "^11.1.0",
    "style-loader": "^3.3.1",
    "ts-loader": "^9.4.2",
    "typescript": "^4.9.4",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.11.1"
  },
  "dependencies": {
    "-": "^0.0.1",
    "D": "^1.0.0",
    "postcss": "^8.4.21",
    "postcss-loader": "^7.0.2",
    "postcss-preset-env": "^7.8.3"
  }
}

  

{
    "compilerOptions": {
        "module": "ES2015",
        "target": "ES6",
        // "sourceMap": false,
        // "strict": true
    },
    "exclude": [
        "node_modules"
    ]
}

  

//引入path模块,管理路径
// import { Configuration } from 'webpack';//运行webpack时注释掉
/**
 * @type {Configuration}
 */
const path = require('path');
//引入html-webpack-plugin
const HTMLWEBPACKPLUGIN = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
//webpack中的所有配置信息都应写在module.exports中
module.exports = {
    //指定入口文件
    entry: './src/index.ts',
    //指定打包文件所在目录
    output: {
        //指定打包文件的目录
        // path:'./dist'
        path: path.resolve(__dirname, 'dist'),
        //打包后文件的文件名
        filename: "bundle.js",
        environment: {
            //配置打包的环境
            arrowFunction: false,//告诉webpack不使用箭头函数
            const:false,//告诉webpack不使用const
            
        }
    },
    //指定webpack打包时要使用的模块
    module: {
        //指定加载的规则
        rules: [
            {
                //指定规则生效的文件
                test: /\.ts$/,
                //要使用的loader,执行顺序从后往前
                use: [
                    {//配置babel
                        //指定加载器
                        loader: "babel-loader",
                        //设置babel
                        options: {
                            //设置预定义环境
                            presets: [
                                [
                                    //指定环境插件
                                    "@babel/preset-env",
                                    //配置信息
                                    {
                                        //要兼容的目标浏览器
                                        targets: {
                                            "chrome": "88",
                                            "ie": "11"
                                        },

                                        "corejs": "3",//指定core.js的版本
                                        // //使用core.js的方式
                                        "useBuiltIns": "usage",//"usage"表示按需加载

                                    },


                                ]
                            ]
                        }

                    },
                    "ts-loader"
                ],
                //指定要排除的文件
                exclude: /node_modules/,

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

                                ]
                            ]
                        }
                    }
                },
                    "less-loader"
                ]
            }
        ]
    },
    //配置webpack的插件
    plugins: [
        new CleanWebpackPlugin(),
        new HTMLWEBPACKPLUGIN({
            // title:'这是一个自定义的title'//用来配置自动生成的html文件的title
            template: "./src/index.html"//用来配置自动生成的html文件的模板
        })
    ],
    mode: 'development',
    resolve: {
        //设置引用模块
        extensions: ['.ts', '.js']//告诉webpack哪些后缀的文件可以被当做模块引用
    }

}

  

标签:10,游戏,value,loader,webpack,源码,snake,贪吃蛇,bodies
From: https://www.cnblogs.com/SadicZhou/p/17074178.html

相关文章

  • 快过年了,奉上好玩游戏“劲爆弹球3”
    快过牛年春节了,奉上好玩游戏“劲爆弹球3”,希望大家牛年玩的快乐!非常经典的小游戏系列,此部续作已时隔5年之久。游戏采用了目前主流的PhysX物理驱动引擎,动感真实,画面更显流畅......
  • USB摄像头驱动实现源码分析
    Spac5xx的实现是按照标准的USBVIDEO设备的驱动框架编写(其具体的驱动框架可参照/usr/src/linux/drivers/usb/usbvideo.c文件),整个源程序由四个主体部分组成:总结送免费学习......
  • Seata源码结构及事务模式介绍
    1.Seata是什么Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式......
  • eureka源码分析环境准备
    一、工具准备:eureka源码,下载地址:https://github.com/Netflix/eureka/tree/v1.7.2;gradle安装配置环境变量,自行百度;IDEA2018.1版本(其他版本不一定兼容)二、......
  • 如何成为游戏研发工程师
    如何成为游戏研发工程师想成为游戏研发工程师需要学习很多的内容,下面简答的说说,以下内容都来自广大网友。面试官考察方面:计算机基础、算法和代码能力、图形学基础和项目......
  • IdentityServer4源码解析_2_元数据接口
    1|0目录IdentityServer4源码解析_1_项目结构IdentityServer4源码解析_2_元数据接口IdentityServer4源码解析_3_认证接口IdentityServer4源码解析_4_令牌发放接口Id......
  • 游戏企业患上人才饥渴症
    50万年薪难聘高级游戏人才网络、手机游戏产业的超常发展,使得游戏人才供不应求。4月初,一知名游戏企业在网上开出一万元的月薪招聘游戏软件开发人才,另一网站日前更爆出消息称......
  • 数据访问层服务自动注册类封装和使用源码-AutoFac
    项目使用三层结构RepositoryIocFactoryusingSystem;usingSystem.Reflection;usingAutofac;namespaceCommonHelper.AutoInject.Repository{publicclassRe......
  • spring 源码浅析
    AliasRegistry:定义对alias的简单增删改查SimpleAliasRegistry:主要使用map作为alias的缓存,并对接口AliasRegistry进行实现SingletonBeanRegistry:定义对单例的注册及获取Bean......
  • Java安全 - RMI源码分析
    RMI远程服务创建流程分析1、远程对象创建过程首先步入对象的构造方法下一步这里步入了父类UnicastRemoteObject的构造函数,传入一个参数port,作用是将远程对象随即发......