前端实现弹小球功能

        这篇文章将会做弹小球游戏,弹小球游戏大家小时候都玩过,玩家需要在小球到达游戏区域底部时候控制砖块去承接小球,并不断的将小球弹出去。

        首先看一下实现的效果。

效果演示

玩家需要通过控制鼠标来实现砖块的移动,保证在小球下落到底部时接到小球。

技术实现

html布局

        游戏区域包括小球和砖块2个部分,小球在来回移动,砖块在底部移动。

import {useEffect, useState} from "react";

const BounceBall = () => {

    // 游戏区域配置
    const gameArea = {
        width: 500,
        height: 400
    }

    // 小球对象
    const initBall = {
        width: 20, // 小球宽度
        height: 20,// 小球高度
        posX: 240, // 240 ~ 260
        posY: 190,  // 190 ~ 210
        speedX: 0, // 小球移动速度
        speedY: 2  // 小球移动速度
    }

    const [ball, setBall] = useState(initBall)

    // 砖块对象
    const initPaddle = {
        width: 80, // 砖块宽度
        height: 20,// 砖块高度
        posX: 210, // 210 ~ 290
        posY: 380  // 380 ~ 400
    }

    const [paddle, setPaddle] = useState(initPaddle)



    // 游戏区域样式
    const gameAreaStyle = {
        position: "relative", /*相对定位*/
        width: `${gameArea.width}px`, /*区域宽度*/
        height: `${gameArea.height}px`, /*区域高度*/
        backgroundColor: "#333"
    }

    // 小球样式
    const ballStyle = {
        position: "absolute",/* 绝对定位 */
        top: `${ball.posY}px`,   /*小球位置*/
        left: `${ball.posX}px`, /*小球位置*/
        width: `${ball.width}px`,/* 设置小球的宽度 */
        height: `${ball.height}px`, /* 设置小球的高度 */
        borderRadius: "50%", /* 设置小球为圆形 */
        backgroundColor: "red" /* 设置小球的背景颜色 */
    }

    // 砖块样式
    const paddleStyle = {
        position: 'absolute', /* 绝对定位 */
        top: `${paddle.posY}px`, /*板块位置*/
        left: `${paddle.posX}px`, /*板块位置*/
        width: `${paddle.width}px`, /* 设置砖块的宽度 */
        height: `${paddle.height}px`, /* 设置砖块的高度 */
        backgroundColor: "blue", /* 设置砖块的背景颜色 */
        border: "1px solid black" /* 设置砖块的边框 */
    }

    return (<>
        <div style={gameAreaStyle}>
            {/*小球*/}
            <div style={ballStyle}>
            </div>
            {/*砖块*/}
            <div style={paddleStyle}>
            </div>
        </div>
    </>)
}

游戏控制处理

小球移动处理

        小球移动通过定时器实现,定时器会在小球发生碰撞、游戏失败后清楚。

const [failCnt, setFailCnt] = useState(0)
// 定时器控制小球移动
useEffect(()=>{
       const intervalId = setInterval(()=>{
            // 小球移動
            ball.posX += ball.speedX;
            ball.posY += ball.speedY;
            setBall({...ball})
        }, 20)
        return ()=> {clearInterval(intervalId)} // 返回是一个函数,并非结果
 },[ball.speedX, ball.speedY, failCnt])
砖块移动处理

        砖块移动通过控制鼠标移动实现

// 砖块移动
useEffect(()=>{
        document.addEventListener('mousemove',(ev => {
            const mouseX = ev.clientX;
            let paddlePosX = mouseX - paddle.width/2;
            if (paddlePosX < 0){
                paddlePosX = 0;
            }else if (paddlePosX >= gameArea.width - paddle.width){
                paddlePosX = gameArea.width - paddle.width;
            }
            setPaddle({
                ...paddle,
                posX: paddlePosX
            })
        }))
},[])
小球位置判断

   需要考虑边界碰撞、砖块碰撞等场景

// 小球位置判断
useEffect(()=>{

    // 边界判断
    if (ball.posX <= 0 || ball.posX >= gameArea.width - ball.width) {
        ball.speedX = -1 * ball.speedX;
        setBall({...ball});
        return;
    }
    if (ball.posY <= 0) {
        ball.speedY = -1 * ball.speedY;
        setBall({...ball});
        return;
    }

    // 判断是否碰撞到砖块
    if (ball.posY >= gameArea.height - ball.height - paddle.height) {
        // 未碰撞砖块
        if (ball.posX + ball.width <= paddle.posX || ball.posX >= paddle.posX + paddle.width) {
            alert('游戏失败')

            setBall({...initBall})
            setPaddle({...initPaddle})
            setFailCnt(failCnt + 1)
            return;
        }
        console.log(ball)
        // 计算小球x speed
        const collisionPoint = (ball.posX + ball.width/2 ) - (paddle.posX + paddle.width/2) ; // 计算碰撞点距离挡板中心点的距离
        ball.speedX = collisionPoint * 0.1
        ball.speedY = -1 * ball.speedY
        setBall({...ball})
    }
}, [ball.posX, ball.posY])

整体代码

import {useEffect, useState} from "react";

const BounceBall = () => {

    // 游戏区域配置
    const gameArea = {
        width: 500,
        height: 400
    }

    // 小球对象
    const initBall = {
        width: 20, // 小球宽度
        height: 20,// 小球高度
        posX: 240, // 240 ~ 260
        posY: 190,  // 190 ~ 210
        speedX: 0, // 小球移动速度
        speedY: 2  // 小球移动速度
    }

    const [ball, setBall] = useState(initBall)

    // 砖块对象
    const initPaddle = {
        width: 80, // 砖块宽度
        height: 20,// 砖块高度
        posX: 210, // 210 ~ 290
        posY: 380  // 380 ~ 400
    }

    const [paddle, setPaddle] = useState(initPaddle)


    const [failCnt, setFailCnt] = useState(0)
    // 定时器控制小球移动
    useEffect(()=>{
       const intervalId = setInterval(()=>{
            // 小球移動
            ball.posX += ball.speedX;
            ball.posY += ball.speedY;
            setBall({...ball})
        }, 20)
        return ()=> {clearInterval(intervalId)} // 返回是一个函数,并非结果
    },[ball.speedX, ball.speedY, failCnt])


    // 小球位置判断
    useEffect(()=>{

        // 边界判断
        if (ball.posX <= 0 || ball.posX >= gameArea.width - ball.width) {
            ball.speedX = -1 * ball.speedX;
            setBall({...ball});
            return;
        }
        if (ball.posY <= 0) {
            ball.speedY = -1 * ball.speedY;
            setBall({...ball});
            return;
        }

        // 判断是否碰撞到砖块
        if (ball.posY >= gameArea.height - ball.height - paddle.height) {
            // 未碰撞砖块
            if (ball.posX + ball.width <= paddle.posX || ball.posX >= paddle.posX + paddle.width) {
                alert('游戏失败')

                setBall({...initBall})
                setPaddle({...initPaddle})
                setFailCnt(failCnt + 1)
                return;
            }
            console.log(ball)
            // 计算小球x speed
            const collisionPoint = (ball.posX + ball.width/2 ) - (paddle.posX + paddle.width/2) ; // 计算碰撞点距离挡板中心点的距离
            ball.speedX = collisionPoint * 0.1
            ball.speedY = -1 * ball.speedY
            setBall({...ball})
        }
    }, [ball.posX, ball.posY])


    // 砖块移动
    useEffect(()=>{
        document.addEventListener('mousemove',(ev => {
            const mouseX = ev.clientX;
            let paddlePosX = mouseX - paddle.width/2;
            if (paddlePosX < 0){
                paddlePosX = 0;
            }else if (paddlePosX >= gameArea.width - paddle.width){
                paddlePosX = gameArea.width - paddle.width;
            }
            setPaddle({
                ...paddle,
                posX: paddlePosX
            })
        }))

    },[])

    // 游戏区域样式
    const gameAreaStyle = {
        position: "relative", /*相对定位*/
        width: `${gameArea.width}px`, /*区域宽度*/
        height: `${gameArea.height}px`, /*区域高度*/
        backgroundColor: "#333"
    }

    // 小球样式
    const ballStyle = {
        position: "absolute",/* 绝对定位 */
        top: `${ball.posY}px`,   /*小球位置*/
        left: `${ball.posX}px`, /*小球位置*/
        width: `${ball.width}px`,/* 设置小球的宽度 */
        height: `${ball.height}px`, /* 设置小球的高度 */
        borderRadius: "50%", /* 设置小球为圆形 */
        backgroundColor: "red" /* 设置小球的背景颜色 */
    }

    // 砖块样式
    const paddleStyle = {
        position: 'absolute', /* 绝对定位 */
        top: `${paddle.posY}px`, /*板块位置*/
        left: `${paddle.posX}px`, /*板块位置*/
        width: `${paddle.width}px`, /* 设置砖块的宽度 */
        height: `${paddle.height}px`, /* 设置砖块的高度 */
        backgroundColor: "blue", /* 设置砖块的背景颜色 */
        border: "1px solid black" /* 设置砖块的边框 */
    }

    return (<>
        <div style={gameAreaStyle}>
            {/*小球*/}
            <div style={ballStyle}>
            </div>
            {/*砖块*/}
            <div style={paddleStyle}>
            </div>
        </div>
    </>)
}

export default BounceBall

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值