狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

JS簡單貪吃蛇邏輯

freeflydom
2024年8月15日 9:26 本文熱度 883

 

實現(xiàn)步驟

1、屏幕刷新

利用瀏覽器的 requestAnimationFrame 方法進(jìn)行刷新重置

2、對象封裝

//位置類 

class Rect

//身體類 

class Body

// 食物類 

class Food

// 蛇類 

class Snake

// 搖桿控制類 

class EleOption class BallOption

// 啟動 

let snake = new Snake() 

snake.begin()

3、源碼

css

body {

position: relative;

width: 100vw;

height: 100vh;

}


.snake_body {

position: absolute;

background-color: rgb(234, 12, 101);

border-radius: 50%;

}


.food_body_1 {

position: absolute;

background-color: rgb(170, 192, 170);

border-radius: 50%;

}


.food_body_2 {

position: absolute;

background-color: rgb(169, 214, 169);

border-radius: 50%;

}


.food_body_3 {

position: absolute;

background-color: rgb(18, 139, 18);

border-radius: 50%;

}


.food_body_4 {

position: absolute;

background-color: rgb(207, 15, 197);

border-radius: 50%;

}


.food_body_5 {

position: absolute;

background-color: rgb(222, 27, 53);

border-radius: 50%;

}


#optionDiv{

width: 100px;

height: 100px;

position: absolute;

right: 40px;

bottom: 40px;

  z-index: 99;

}


#resultWarningDiv{

position: relative;

width: 100%;

height: 100%;

display: flex;

justify-content: center;

align-items: center;

background-color: rgba(0, 0, 0, 0.5);

z-index: 999;

}


.hideResultWarningDiv{

visibility: hidden !important;

}


.warningContent{

width: 40%;

height: 40%;

display: flex;

flex-direction: column;

justify-content: center;

align-items: center;

background-color: white;

border-radius: 10px;

}


#warningContentDiv{

margin-bottom: 20px;

}


#resumeGameDiv{

background-color: rgb(209, 126, 17);

color: white;

padding: 10px 40px;

border-radius: 4px;

}

js

class Rect {


x = 0

y = 0

width = 0

height = 0


constructor({ x, y, width = 10, height = 10 }){

this.x = x

this.y = y

this.width = width

this.height = height

}

}


class Body {


rect = null

div = null

constructor(rect){

this.render(rect)

}


render(rect){

this.createBody()

this.setRect(rect)

}


// 創(chuàng)建舍身

createBody(){

this.div = document.createElement('div');

this.div.setAttribute('class', 'snake_body');

document.body.appendChild(this.div);

}


// 位置設(shè)置

setRect(rect){

this.rect = rect

this.div.style.top = rect.y + 'px'

this.div.style.left = rect.x + 'px'

this.div.style.width = rect.width + 'px'

this.div.style.height = rect.height + 'px'

}

}


class Food {


rect = null

div = null

size = null


constructor(){

this.render()

}


// 類方法,創(chuàng)建隨機(jī)食物

static scatterFoods(){

let foods = []

let count = 0;

while(count < 100) {

// 要執(zhí)行的操作

foods.push(new Food())

count++;

}

return foods;

}


// 渲染

render(){

this.size = (Math.floor(Math.random() * 5) + 1);

this.createFood(this.size)

this.setRect(this.size)

}


// 創(chuàng)建食物

createFood(size){

this.div = document.createElement('div');

this.div.setAttribute('class', 'food_body_' + size);

document.body.appendChild(this.div);

}


// 位置設(shè)定

setRect(size){


let screenWidth = document.body.offsetWidth

let screenHeight = document.body.offsetHeight


let width = size * 5

let height = size * 5


let x = Math.floor(Math.random() * (screenWidth - 4 * width)) + width

let y = Math.floor(Math.random() * (screenHeight - 4 * height)) + height


this.rect = new Rect({ x, y, width, height })

this.div.style.top = this.rect.y + 'px'

this.div.style.left = this.rect.x + 'px'

this.div.style.width = this.rect.width + 'px'

this.div.style.height = this.rect.height + 'px'

}


// 銷毀

destroy(){

this.div.remove()

}

}


class Snake {


bodys = []

foods = []

ballOption = null

angle = null

isPause = false


constructor(){


}


// 開始

begin(){

        this.clearAll()

        this.createHeader()

this.foods = Food.scatterFoods()

this.createBall()

        return this

}


    // 清除全部元素、再次繪制

    clearAll(){

        this.angle = null

        this.ballOption = null

        this.bodys = []

        this.foods = []

        this.isPause = false

        document.body.innerHTML = `

            <div id="optionDiv"></div>

            <div id="resultWarningDiv" class="hideResultWarningDiv">

                <div class="warningContent">

                    <span id="warningContentDiv">22</span>

                    <span id="resumeGameDiv"> 繼續(xù) </span>

                </div>

            </div>

        `

    }


// 創(chuàng)建搖桿

createBall(){

this.ballOption = new BallOption('optionDiv',(angle)=>{

angle = 270 + angle

if(angle > 360){

angle = angle - 360

}

this.angle = angle * (Math.PI / 180)

})

this.ballOption.createOptionView()

}


// 創(chuàng)建蛇頭

createHeader(){

let x = document.body.offsetWidth / 2.0

let y = document.body.offsetHeight / 2.0

let header = new Body(new Rect({ x, y }))

this.bodys.push(header)

}


// 吃

eat(foodItem){

let lastBody = this.getTailer()

let body = new Body(lastBody)

this.bodys.push(body)

// 移除食物

foodItem.destroy()

}


// 移動

move(){

requestAnimationFrame(() => {

            if(!this.isPause){

              this.setNewHeaderDirection()

              this.collisionDetection()

              this.checkIsSucceeded()

            }

            this.move()

});

}


// 轉(zhuǎn)向

setNewHeaderDirection(){

for(let i = this.bodys.length - 1; i >= 0;i--){

let item = this.bodys[i]

if(i == 0){

item.setRect(this.nextStepRect())

} else {

item.setRect(this.bodys[i - 1].rect)

}

}

}


// 獲取蛇頭

getHeader(){

return this.bodys[0]

}


// 獲取蛇尾

getTailer(){

return this.bodys[this.bodys.length - 1]

}


// 蛇頭下一步的位置計算

nextStepRect(){

let header = this.getHeader()

let step = 1.5

let addX = 0

let addY = 0

addX = this.angle ? step * Math.cos(this.angle) : step

addY = this.angle ? step * Math.sin(this.angle) : 0

let x = header.rect.x + addX

let y = header.rect.y + addY

return new Rect({x, y })

}


// 吃到食物檢測

collisionDetection(){

let headerRect = this.getHeader().rect

this.foods = this.foods.filter((foodItem)=>{

let foodRect = foodItem.rect

let isDetection = this.checkRectOverlap(headerRect,foodRect)

if(isDetection){

//根據(jù)size大小成長

for(let i = 0; i < foodItem.size; i ++){

this.eat(foodItem)

}

}

return !isDetection

})

}


// 蛇頭與食物區(qū)域是否重疊判斷

checkRectOverlap(rect1, rect2) {

// 提取矩形的坐標(biāo)和尺寸

let x1 = rect1.x;

let y1 = rect1.y;

let width1 = rect1.width;

let height1 = rect1.height;

  

let x2 = rect2.x;

let y2 = rect2.y;

let width2 = rect2.width;

let height2 = rect2.height;

  

// 檢查是否有重疊

return (x1 < x2 + width2 &&

x1 + width1 > x2 &&

y1 < y2 + height2 &&

y1 + height1 > y2)

}


// 游戲結(jié)果計算

checkIsSucceeded(){

let screenWidth = document.body.offsetWidth

let screenHeight = document.body.offsetHeight

let { x, y } = this.getHeader().rect

if(x >= screenWidth || x <= 0 || y >= screenHeight || y <= 0){

this.isPause = true

            this.resultWarning('游戲結(jié)束')

}

if(this.foods.length == 0){

this.isPause = true

this.resultWarning('厲害!')

}

}


    // 結(jié)果提醒

    resultWarning(content = '游戲結(jié)束'){

        document.getElementById('resultWarningDiv').classList.remove('hideResultWarningDiv')

        document.getElementById('warningContentDiv').innerText = content

        document.getElementById('resumeGameDiv').onclick = ()=>{

            document.body.innerHTML = ''

            this.begin()

        }

    }

}


class EleOption{

    //添加操作dom ID

    eleId


    constructor(eleId){

        this.eleId = eleId

    }


    //獲取當(dāng)前關(guān)聯(lián)的el

    getCurrentEle(){

        return document.getElementById(this.eleId)

    }


    //獲取el寬度

    getEleWidth(el){

        return el.offsetWidth

    }


    //獲取el高度

    getEleHeight(el){

        return el.offsetHeight

    }


    //設(shè)置背景顏色

    setBackgroundColor(el,color){

        el.style.backgroundColor = color

    }


    //設(shè)置寬度

    setWidth(el,w){

        el.style.width = w + 'px'

    }


    //設(shè)置高度

    setHeight(el,h){

        el.style.height = h + 'px'

    }


    //設(shè)置圓角

    setCircle(el){

        el.style.borderRadius = (this.getEleWidth(el) / 2.0 )+ 'px'

    }


    //設(shè)置絕對定位

    setAbsolutePosition(el){

        el.style.position = 'absolute'

    }


    //設(shè)置透明度

    setTransparency(el,alpha){

        el.style.opacity = alpha / 100

    }


    //設(shè)置為父el中心位置

    setSupCenter(el){

        if(el.style.position != 'absolute'){

            this.setAbsolutePosition(el)

            let superElWidth = this.getEleWidth(this.getSuperEl(el))

            let superElHeight = this.getEleHeight(this.getSuperEl(el))


            let width = this.getEleWidth(el)

            let height = this.getEleHeight(el)


            el.style.left = ((superElWidth - width) / 2.0) + 'px'

            el.style.top = ((superElHeight - height) / 2.0) + 'px'

        }

    }


    //設(shè)置中心位置

    setCenter(el,point){

        if(el.style.position != 'absolute'){

            this.setAbsolutePosition(el)

        }

        el.style.left = point.x + 'px'

        el.style.top = point.y + 'px'

    }


    //獲取父類el

    getSuperEl(el){

        return el.parentNode

    }


    //獲取el

    getElById(elId){

        return document.getElementById(elId)

    }


    //創(chuàng)建el

    createEl(elId){

        let el = document.createElement('div')

        if(elId){

            el.setAttribute('id',elId)

        }

        return el

    }


    //添加子el

    addSubEl(superEl,subEl){

        superEl.appendChild(subEl);

    }


    //取消交互

    cancleUserInreface(el){

        el.style.pointerEvents = 'none'

    }



    //添加move事件

    addMoveEvent(el,ballOption,mcb,emcb){

        el.onmousemove = (event)=>{

            mcb(this.getMoveEventPoint(event,el),ballOption)

        }

        el.onmouseout = (_)=>{

            emcb(ballOption)

        }

    }


    //move事件監(jiān)聽

    getMoveEventPoint(event,el){

        let x = event.clientX - this.getSuperEl(el).offsetLeft

        let y = event.clientY - this.getSuperEl(el).offsetTop

        return {x,y}

    }


    //獲取中心點

    getCenterPoint(off){

        let x = this.getSuperEl(this.getCurrentEle()).offsetLeft + (this.getEleWidth(this.getCurrentEle()) / 2.0) - off.offX

        let y = this.getSuperEl(this.getCurrentEle()).offsetTop + (this.getEleHeight(this.getCurrentEle()) / 2.0) - off.offY

        return {x,y}

    }

}


class BallOption{

    //添加操作dom ID

    eleId

    //el操作對象

    eleOption


    //控制球?qū)ο?/span>

    ball

    //控制球尺寸

    ballWidth

    ballHeight

    ballOffX

    ballOffY

    //是否觸碰過控制球

    isTouchedBall = false

    

    //控制區(qū)域

    optionRangeView

    optionRangeViewCenterPoint


    //上一次角度

    lastDeg


    //角度回調(diào)

    angleCallBack


    constructor(eleId,angleCallBack){

        this.eleId = eleId

        this.angleCallBack = angleCallBack

        this.eleOption = new EleOption(eleId)

    }


    //創(chuàng)建操作框

    createOptionView(){

        if(this.eleId != undefined){

            this.createOptionRangeView()

            this.createOptionBallView()

        }

    }


    //繪制操作范圍

    createOptionRangeView(){

        let width = this.eleOption.getEleWidth(this.eleOption.getCurrentEle())

        let height = this.eleOption.getEleHeight(this.eleOption.getCurrentEle())

        this.optionRangeView = this.eleOption.createEl('optionRangeViewEl')

        this.eleOption.addSubEl(this.eleOption.getCurrentEle(),this.optionRangeView)

        this.eleOption.setBackgroundColor(this.optionRangeView,'rgb(248,248,248)')

        this.eleOption.setWidth(this.optionRangeView,width)

        this.eleOption.setHeight(this.optionRangeView,height)

        this.eleOption.setCircle(this.optionRangeView)

        //添加拖拽事件

        this.eleOption.addMoveEvent(optionRangeViewEl,this,this.makeBallFollowScroll,this.resetBall)

    }


    //控制球隨鼠標(biāo)滾

    makeBallFollowScroll(point,ballOption){

        let x = (point.x - ballOption.ballOffX)

        let y = (point.y - ballOption.ballOffY)

        let currentPoint = {x,y}

        if(ballOption.checkIsTouchControlBall(point)){

            ballOption.eleOption.setCenter(ballOption.ball,currentPoint)

            ballOption.getCurrentAngle(point)

        }

    }


    //檢測是否碰觸過控制球

    checkIsTouchControlBall(point){

        if(!this.isTouchedBall){

            let isTouchBall = (

                point.x > this.optionRangeViewCenterPoint.x - this.ballWidth && 

                point.x < this.optionRangeViewCenterPoint.x + this.ballWidth &&

                point.y > this.optionRangeViewCenterPoint.y - this.ballHeight && 

                point.y < this.optionRangeViewCenterPoint.y + this.ballHeight

            )

    

            if(isTouchBall){

                this.isTouchedBall = true

                this.eleOption.setTransparency(this.ball,100)

            }

        }

        return this.isTouchedBall

    }


    //鼠標(biāo)移出事件

    resetBall(ballOption){

        ballOption.isTouchedBall = false

        ballOption.eleOption.setCenter(ballOption.ball,ballOption.optionRangeViewCenterPoint)

        ballOption.eleOption.setTransparency(ballOption.ball,40)

        if(ballOption.angleCallBack){

            ballOption.lastDeg = 0

            ballOption.angleCallBack(ballOption.lastDeg)

        }

    }


    //計算角度

    getCurrentAngle(point){

        let addX = (point.x - this.eleOption.getEleWidth(this.optionRangeView) / 2.0)

        let addY = (point.y - this.eleOption.getEleHeight(this.optionRangeView) / 2.0)

        if(addY != 0){

            let tan = addX / addY

            let angle = Math.atan(tan)

            this.lastDeg = (angle / Math.PI) * 180

            if(addX <= 0 && addY < 0){

                this.lastDeg = this.lastDeg

            } else if(addX <= 0 && addY > 0){

                this.lastDeg = (180 - Math.abs(this.lastDeg))

            } else if(addX >= 0 && addY > 0){

                this.lastDeg = 180 + Math.abs(this.lastDeg)

            } else if(addX >= 0 && addY < 0){

                this.lastDeg = (360 - Math.abs(this.lastDeg))

            }

        }

        if(this.angleCallBack){

            this.angleCallBack(360 - this.lastDeg)

        }

    }


    //繪制球滾動

    createOptionBallView(){

        let scale = 3.2

        this.ballWidth = this.eleOption.getEleWidth(this.eleOption.getCurrentEle()) / scale

        this.ballHeight = this.eleOption.getEleHeight(this.eleOption.getCurrentEle()) / scale

        this.ballOffX = this.ballWidth / 2.0

        this.ballOffY = this.ballHeight / 2.0

        this.ball = this.eleOption.createEl('optionBallViewEl')

        this.eleOption.addSubEl(this.eleOption.getCurrentEle(),this.ball)

        this.eleOption.setBackgroundColor(this.ball,'black')

        this.eleOption.setWidth(this.ball,this.ballWidth)

        this.eleOption.setHeight(this.ball,this.ballHeight)

        this.eleOption.setCircle(this.ball)

        this.eleOption.setSupCenter(this.ball)

        this.eleOption.cancleUserInreface(this.ball)

        this.eleOption.setTransparency(this.ball,40)

        //保存中心點坐標(biāo)

        this.optionRangeViewCenterPoint = this.eleOption.getCenterPoint({offX:this.ballOffX,offY:this.ballOffY})

    }

}


let snake = new Snake()

snake.begin().move()

總結(jié)

將功能劃分為 “類”,讓各自的對象去處理各自的任務(wù),實現(xiàn)起來邏輯就會清晰。主要是用“搖桿”控制方向,利用瀏覽器的 requestAnimationFrame 方法進(jìn)行刷新。元素都是 div 標(biāo)簽。


作者:頭疼腦脹的代碼搬運工
鏈接:https://juejin.cn/post/7402548056284839947
來源:稀土掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。



該文章在 2024/8/16 10:10:15 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調(diào)度、堆場、車隊、財務(wù)費用、相關(guān)報表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點,圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務(wù)都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved