js吃豆人

window.cancelAnimationFrame =
    window.cancelAnimationFrame || window.mozCancelAnimationFrame;
window.requestAnimationFrame =
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.mzRequestAnimationFrame ||
    window.oRequestAnimationFrame;
// this.requestAnimationFrame = requestAnimationFrame(this.recursion_draw_circle)
// cancelAnimationFrame(this.requestAnimationFrame)
class cdr {
    constructor(option) {
        this.canvas = option.canvas;
        // 线的粗细
        this.lineHeight = 1.5;
        // 圆距离上下的间隙
        this.lineGap = 2;
        this.radius = 20;
        let bw = this.radius * 2 + this.lineHeight + this.lineGap * 2
        // x轴格数
        // this.XRowNumber = Math.floor(window.screen.width / bw);
        this.XRowNumber = 11;
        this.canvas.width = this.XRowNumber * bw - this.lineHeight;
        this.canvas.height = this.XRowNumber * bw - this.lineHeight;
        this.cxt = this.canvas.getContext('2d');
        this.moveSpeed = 1; // 移动速度
        this.mounthSpeed = 0.05;  // 嘴的速度
        this.ballColor = ["#c36f6f", "#d69347", "#81b91f", "#0fab11", "#0aa99e", "#0a4da9", "#de26d4"];
        // 球的位置
        this.ballDirection = ["top", "left", "right", "bottom"];
        // 球张嘴闭嘴 控制数据
        this.ballAngle = {
            top: {
                maxSAngle: 3 / 2 * Math.PI - 1 / 4 * Math.PI, // 起始角度
                maxEAngle: 1 / 4 * Math.PI + 3 / 2 * Math.PI, // 结束角度
                avgAngle: 3 / 2 * Math.PI,
                counterclockwise: true // 旋转方向
            },
            left: {
                maxSAngle: 3 / 4 * Math.PI,  // 起始角度
                maxEAngle: 3 / 2 * Math.PI - 1 / 4 * Math.PI, // 结束角度
                avgAngle: Math.PI,
                counterclockwise: true // 旋转方向
            },
            right: {
                maxSAngle: 1 / 4 * Math.PI, // 起始角度
                maxEAngle: 3 / 2 * Math.PI + 1 / 4 * Math.PI,  // 结束角度
                avgAngle: 0,
                counterclockwise: false // 旋转方向
            },
            bottom: {
                maxSAngle: 1 / 2 * Math.PI + 1 / 4 * Math.PI, // 起始角度
                maxEAngle: 1 / 2 * Math.PI - 1 / 4 * Math.PI, // 结束角度
                avgAngle: 1 / 2 * Math.PI,
                counterclockwise: false // 旋转方向
            }
        }
        this.PI2 = 2 * Math.PI
        this.ballArray = [];
        this.lineY = [];
        // 障碍物墙的坐标
        this.wallArray = [];
        // 绘制障碍物的数据 Obstacle
        this.obstacle = [];
        // 记录可以十字路口的坐标 数据
        this.crossingArray = []
        this.run();
    }
    run() { 
        this.drawColLine();
        this.initBallArray();
        this.initWallArray();
        this.initObstacleArray();
        this.drawBall()
    }
    setCounterclockwise(type) {
        // "top", "left", "right", "bottom"
        if (type == 'top' || type == 'left')
            return true
        else
            return false
    }
    initWallArray() {
        // direction 方向 top left  right bottom
        // 设置四周墙的坐标
        // 上
        this.wallArray.push({
            direction: "top",
            coordinate: {
                startX: 0,
                startY: 0,
                endX: this.canvas.width,
                endY: 0
            }
        })
        // 下
        this.wallArray.push({
            direction: "bottom",
            coordinate: {
                startX: 0,
                startY: this.canvas.height,
                endX: this.canvas.width,
                endY: this.canvas.height
            }
        })
        // 左
        this.wallArray.push({
            direction: "left",
            coordinate: {
                startX: 0,
                startY: 0,
                endX: 0,
                endY: this.canvas.height
            }
        })
        // 右
        this.wallArray.push({
            direction: "right",
            coordinate: {
                startX: this.canvas.width,
                startY: 0,
                endX: this.canvas.width,
                endY: this.canvas.height
            }
        })
    }
    initBallArray() {
        this.ballArray = new Array(this.random(22, 55))
        // this.ballArray = [4]
        for (let i = 0; i < this.ballArray.length; i++) {
            this.ballArray[i] = {
                // x: this.random(this.radius + 5, this.canvas.width - this.radius - 5),
                // y: this.setBallY(),
                x:this.radius + this.lineGap,
                y:this.radius + this.lineGap,
                direction: this.getDirection(),
                fillStyle: this.ballColor[this.random(0, 7)],
                directionType: 1, // 1 闭嘴 2 张嘴
                moveSpeed : this.random2(0.8,1.5)
            }
        }
    }
    initObstacleArray(){
           // 绘制障碍物
           let rctW = (this.canvas.width - (this.radius*2 + this.lineGap * 2) * 4) / 3
           let space = this.radius*2 + this.lineGap * 2
           let rctH = (this.canvas.width - (this.radius*2 + this.lineGap * 2) * 7) / 6
           for (let i = 0; i < 6; i++) {
               for(let j = 0 ; j < 3 ; j++){
                    this.obstacle.push({
                        x: space * (j+1) + rctW*j ,
                        y : space * (i + 1) + rctH * i,
                        width: rctW,
                        height:rctH,
                        radius:6,
                        color:"green",
                        type: "fill"
                    })
                    this.crossingArray.push({
                        x: Math.round( space * (j+1) + rctW*j  - this.radius - this.lineGap ),
                        y :Math.round( space * (i + 1) + rctH * i - this.radius - this.lineGap)
                    })
                    if( j == 2) {
                        this.crossingArray.push({
                            x: Math.round( space * (j+2) + rctW*(j + 1)  - this.radius  - this.lineGap),
                            y : Math.round( space * (i + 1) + rctH * i - this.radius - this.lineGap)
                        })
                    }
                    // this.wallArray.push({
                    //     direction: "top",
                    //     coordinate: {
                    //         startX: 0,
                    //         startY: 0,
                    //         endX: this.canvas.width,
                    //         endY: 0
                    //     }
                    // })
               }  
           } 
    
    }
    getDirection() {
        let direction = this.ballDirection[Math.floor(this.random(0, 4))]
        return {
            d: direction,
            sAngle: this.ballAngle[direction].maxSAngle,
            eAngle: this.ballAngle[direction].maxEAngle,
            counterclockwise: this.ballAngle[direction].counterclockwise,
        }
    }
    setBallY() {
        let y = this.random(this.radius, this.canvas.height);
        let min = 99999, newY = 0
        this.lineY.map(v => {
            if (Math.abs(y - v) < min) {
                min = Math.abs(y - v)
                newY = v
            }
        })
        return newY - this.radius - this.lineGap - this.lineHeight / 2
    }
    drawColLine() {
        this.lineY = []
        let OldHeight = 0
        for (let i = 1; i <= this.XRowNumber; i++) {
            if (i == 1) {
                OldHeight += this.radius * 2 + this.lineGap * 2
            } else {
                OldHeight += this.radius * 2 + this.lineGap * 2 + this.lineHeight
            }
            this.lineY.push(OldHeight)
        }
 
        this.lineY.push(this.radius * 2 + OldHeight + this.lineGap * 2 + this.lineHeight)
    }
    /**
         * @description {画直线}
         * @param {*开始位置对象} start 
         * @param {*结束位置对象} end 
         * @param {*线的宽度} width 
         * @param {*线的颜色} strokeStyle 
         */
    drawLine(start, end, width = 2, strokeStyle = "#000000") {
        this.cxt.beginPath();
        this.cxt.strokeStyle = strokeStyle;
        this.cxt.lineWidth = this.lineHeight; //线宽
        this.cxt.moveTo(start.x, start.y); // 线开始位置
        this.cxt.lineTo(end.x, end.y); // 线 结束位置
        this.cxt.stroke();
    }
    drawBall() {
        this.clearCanvas();
        this.drawColLine();
        this.ballArray.map(item => {
            this.cxt.fillStyle = item.fillStyle;
            this.cxt.beginPath();
            this.cxt.arc(item.x, item.y, this.radius, item.direction.sAngle, item.direction.eAngle, item.direction.counterclockwise);
            // 更改球的张嘴闭嘴数据
            this.updateBallDirection(item)
            // 更改球的坐标数据
            this.updateBall_X_OR_Y(item)
 
            this.cxt.lineTo(item.x, item.y);
            this.cxt.closePath();
            this.cxt.fill();
        })
        // 绘制障碍物
        this.obstacle.map(item =>{ 
            this.drawRectangle.apply(this,Object.values(item))
        })  
        requestAnimationFrame(this.drawBall.bind(this))
    }
    drawRectangle(x, y, width, height, radius, color, type) {
        let ctx = this.cxt
        ctx.beginPath();
        ctx.moveTo(x, y + radius);
        ctx.lineTo(x, y + height - radius);
        ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
        ctx.lineTo(x + width - radius, y + height);
        ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
        ctx.lineTo(x + width, y + radius);
        ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
        ctx.lineTo(x + radius, y);
        ctx.quadraticCurveTo(x, y, x, y + radius);
        ctx[type + 'Style'] = color || params.color;
        ctx.closePath();
        ctx[type]();
    }
    setBallDirection(item) {
        item.direction.d = this.ballDirection[Math.floor(this.random(0, 4))]
        item.direction.counterclockwise = this.setCounterclockwise(item.direction.d)  // 旋转方向 
        item.direction.sAngle = this.ballAngle[item.direction.d].maxSAngle
        item.direction.eAngle = this.ballAngle[item.direction.d].maxEAngle
    }
    /**
         * description {更改Ball数组中某个节点的张嘴闭嘴 数据}
         * @param {*} item 
         */
    updateBall_X_OR_Y(item) { 
        // 找到前方最近的障碍物 位置  
        this.wallArray.map(child => {
            if (child.direction == item.direction.d) {
                if (child.direction == "top") {
                    // 向上行走 
                    // 先确定前面没有障碍物
                    // 1 确定x轴某个范围
                    if ((item.x - this.radius) >= child.coordinate.startX && (item.x + this.radius) <= child.coordinate.endX) {
                        // 2. 过滤反方向的障碍物 
                        if ((item.y - this.radius - this.lineGap) > child.coordinate.startY) {
                            // 开始移动
                            item.y -= item.moveSpeed
                            if ((item.y - this.radius - this.lineGap) <= child.coordinate.startY) {
                                item.y = child.coordinate.startY + this.radius + this.lineGap
                            }
                        } else {
                            this.setBallDirection(item)
                        }
                    }
                }
 
                if (child.direction == "bottom") {
                    // 向下行走 
                    // 先确定前面没有障碍物
                    // 1 确定x轴某个范围
                    if ((item.x - this.radius) >= child.coordinate.startX && (item.x + this.radius) <= child.coordinate.endX) {
                        // 2. 过滤反方向的障碍物
                        if ((item.y + this.radius + this.lineGap) < child.coordinate.endY) {
                            // 开始移动
                            item.y += item.moveSpeed
                            if ((item.y - this.radius - this.lineGap) >= child.coordinate.endY) {
                                item.y = child.coordinate.startY - this.radius - this.lineGap
                            }
                        } else {
                            this.setBallDirection(item)
                        }
                    }
                }
 
                if (child.direction == "left") {
                    // 向左行走 
                    // 先确定前面没有障碍物
                    // 1 确定x轴某个范围
                    if ((item.y - this.radius) >= child.coordinate.startY && (item.y + this.radius) <= child.coordinate.endY) {
                        // 2. 过滤反方向的障碍物
                        if ((item.x - this.radius - this.lineGap) > child.coordinate.startX) {
                            // 开始移动
                            item.x -= item.moveSpeed
                            if ((item.x - this.radius - this.lineGap) <= child.coordinate.startX) {
                                item.x = child.coordinate.startX + this.radius + this.lineGap
                            }
                        } else {
                            this.setBallDirection(item)
                        }
                    }
                }
 
                if (child.direction == "right") {
                    // 向左行走 
                    // 先确定前面没有障碍物
                    // 1 确定x轴某个范围
                    if ((item.y - this.radius) >= child.coordinate.startY && (item.y + this.radius) <= child.coordinate.endY) {
                        // 2. 过滤反方向的障碍物
                        if ((item.x + this.radius + this.lineGap) < child.coordinate.endX) {
                            // 开始移动
                            item.x += item.moveSpeed
                            if ((item.x + this.radius + this.lineGap) >= child.coordinate.endX) {
                                item.x = child.coordinate.endX - this.radius - this.lineGap
                            }
                        } else {
                            this.setBallDirection(item)
                        }
                    }
                }
 
            }
        }) 
        // console.log(Math.floor(item.x),Math.floor(item.y))
        this.crossingArray.map(cd=>{
            if(Math.abs(item.x - cd.x) < 0.7 && Math.abs(item.y - cd.y) < 0.7 ){ 
                item.x = cd.x
                item.y =  cd.y
                this.setBallDirection(item)
            }
        })
    }
    /**
         * description {更改Ball数组中某个节点的张嘴闭嘴 数据}
         * @param {指定节点内容} item 
         */
    updateBallDirection(item) {
        let avgAngle = this.ballAngle[item.direction.d].avgAngle
        let maxSAngle = this.ballAngle[item.direction.d].maxSAngle
        let maxEAngle = this.ballAngle[item.direction.d].maxEAngle
 
        // 张嘴,闭嘴动画 , // 1 闭嘴 2 张嘴
        if (item.direction.d == 'bottom') {
            // this.PI2
            if (item.directionType == 1) {
                item.direction.sAngle -= this.mounthSpeed
                if (item.direction.sAngle < avgAngle + this.mounthSpeed) {
                    item.direction.sAngle = avgAngle + this.mounthSpeed
                    item.directionType = 2
                }
 
                item.direction.eAngle += this.mounthSpeed
                if (item.direction.eAngle > avgAngle - this.mounthSpeed) {
                    item.direction.eAngle = avgAngle - this.mounthSpeed
                    item.directionType = 2
                }
            }
            if (item.directionType == 2) {
                item.direction.sAngle += this.mounthSpeed
                if (item.direction.sAngle > maxSAngle) {
                    item.direction.sAngle = maxSAngle - this.mounthSpeed
                    item.directionType = 1
                }
 
 
                item.direction.eAngle -= this.mounthSpeed
                if (item.direction.eAngle < maxEAngle) {
                    item.direction.eAngle = maxEAngle + this.mounthSpeed
                    item.directionType = 1
                }
            }
        }
        if (item.direction.d == 'left' || item.direction.d == 'top') {
            // this.PI2
            if (item.directionType == 1) {
                item.direction.sAngle += this.mounthSpeed
                if (item.direction.sAngle > avgAngle - this.mounthSpeed) {
                    item.direction.sAngle = avgAngle - this.mounthSpeed
                    item.directionType = 2
                }
 
                item.direction.eAngle -= this.mounthSpeed
                if (item.direction.eAngle < avgAngle + this.mounthSpeed) {
                    item.direction.eAngle = avgAngle + this.mounthSpeed
                    item.directionType = 2
                }
            }
            if (item.directionType == 2) {
                item.direction.sAngle -= this.mounthSpeed
                if (item.direction.sAngle < maxSAngle) {
                    item.direction.sAngle = maxSAngle + this.mounthSpeed
                    item.directionType = 1
                }
 
 
                item.direction.eAngle += this.mounthSpeed
                if (item.direction.eAngle > maxEAngle) {
                    item.direction.eAngle = maxEAngle - this.mounthSpeed
                    item.directionType = 1
                }
            }
        }
        if (item.direction.d == 'right') {
            // maxSAngle =  this.PI2 
            if (item.directionType == 1) {
                // avgAngle = this.PI2
                avgAngle = 0
                item.direction.sAngle -= this.mounthSpeed
                if (item.direction.sAngle < avgAngle + 0.001) {
                    item.direction.sAngle = avgAngle + 0.001
                    item.directionType = 2
                }
 
                item.direction.eAngle += this.mounthSpeed
                avgAngle = this.PI2
                if (item.direction.eAngle > avgAngle - 0.001) {
                    item.direction.eAngle = avgAngle - 0.001
                    item.directionType = 2
                }
            }
            if (item.directionType == 2) {
                item.direction.sAngle += this.mounthSpeed
                if (item.direction.sAngle > maxSAngle) {
                    item.direction.sAngle = maxSAngle - + 0.001
                    item.directionType = 1
                }
 
                item.direction.eAngle -= this.mounthSpeed
                if (item.direction.eAngle < maxEAngle) {
                    item.direction.eAngle = maxEAngle + + 0.001
                    item.directionType = 1
                }
            }
        }
    }
    clearCanvas() {
        this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
    }
    /**
         * @description {生成随机整数}
         * @param {下限} lower 
         * @param {上限} upper 
         */
    random(lower, upper) {
        return Math.floor(Math.random() * (upper - lower)) + lower;
    }
    random2(lower, upper) {
        return Math.random() * (upper - lower) + lower;
    }
}
new cdr({
    canvas: document.getElementById("chidoudou")
})

html

<!DOCTYPE html>
<html lang="en">
 
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>吃豆人</title>
    <style>
html,body{
margin: 0;
padding: 0;
}
canvas{
display: block;
background: #ffd;
}
</style>
</head>
 
<body>
<div class="example-box">
<canvas id="chidoudou"></canvas>
</div>
</body>
<script src="../js/cdr.js"></script>
  
 
</html>

gulpfile.js

var gulp = require('gulp');
// 在命令行设置为生产环境或者开发环境
//开发环境不要使用压缩,会影响找错
// windows: set NODE_ENV = development 或 production  
//(可能会有问题, 建议使用 :var environment = process.env.NODE_ENV || 'development';)
// mac  linux : export NODE_ENV = development 或 production
var environment = process.env.NODE_ENV || 'development';
//根据自己开发的实际需求自行设置, src放开发文件, dist是打包压缩后的导出目录
const folder = {
src: "canvas/",
dist: 'dist/'
}
// 压缩html代码
const htmlClean = require('gulp-htmlclean');
// 图片类: 压缩PNG, JPEG, GIF and SVG
const imageMin = require('gulp-imagemin');
// uglify 不支持压缩 es6 , 需要先使用babel降级才行 */
const uglifyJS = require('gulp-uglify')
//es6 降级到es5    请使用  "gulp-babel": "^7.0.1", 
//切记不要用 8版本, 会出现无法输出的情况
const babel = require('gulp-babel');
//去除掉 注释, console 和 debugger
const removeComments = require('gulp-strip-debug')
//less 转 css
const less = require('gulp-less');
//css3 兼容各类浏览器脚本
const postCss = require('gulp-postcss');
const autoPrefixer = require('autoprefixer');
//css代码压缩
const cleanCss = require('gulp-clean-css');
//创建服务器环境插件 支持热更新
const connect = require("gulp-connect");
gulp.task('html', function () {
const step = gulp.src(folder.src + "html/*")
.pipe(connect.reload())
if (environment == 'production') {
step.pipe(htmlClean())
}
step.pipe(gulp.dest(folder.dist + "html/"))
})
gulp.task('img', function () {
gulp.src(folder.src + "img/*")
.pipe(imageMin())
.pipe(gulp.dest(folder.dist + "img/"))
})
gulp.task('css', function () {
var step = gulp.src(folder.src + "css/*")
.pipe(connect.reload())
.pipe(less())
.pipe(postCss([autoPrefixer()]))
if (environment == 'production') {
step.pipe(cleanCss())
}
step.pipe(gulp.dest(folder.dist + "css/"))
})
gulp.task('js', function () {
var step = gulp.src(folder.src + "js/*")
.pipe(connect.reload())
.pipe(babel({
presets: ['es2015']
}))
if (environment == 'production') {
step.pipe(removeComments())
.pipe(uglifyJS())
}
step.pipe(gulp.dest(folder.dist + "js/"))
})
gulp.task('server', function () {
    //设置默认服务器接口, livereload: true 是否监视文件变化
connect.server({
port: 8888,
livereload: true
})
})
//自动刷新页面
gulp.task('watch', () => {
gulp.watch(folder.src + "html/*", ['html']);
gulp.watch(folder.src + "css/*", ['css']);
gulp.watch(folder.src + "js/*", ['js'])
})
gulp.task("default", ["html", "img", "css", "js", "server", "watch"]);
// default任务一定要写,不然会报警告: Task 'default' is not in your gulpfile
// 数组中写哪一个执行哪一个任务, 从左到右执行

package.json

{
"name": "gulp_es6",
"version": "1.0.0",
"description": "",
"main": "gulpfile.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"autoprefixer": "^9.5.1",
"babel-core": "^6.26.3",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.24.1",
"gulp": "^3.9.1",
"gulp-babel": "^7.0.1",
"gulp-clean-css": "^4.2.0",
"gulp-connect": "^5.7.0",
"gulp-connect-reproxy": "^0.0.98",
"gulp-htmlclean": "^2.7.22",
"gulp-imagemin": "^5.0.3",
"gulp-less": "^4.0.1",
"gulp-postcss": "^8.0.0",
"gulp-strip-debug": "^3.0.0",
"gulp-uglify": "^3.0.2"
},
"author": "",
"license": "ISC"
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值