前端实现弹小球功能

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

        首先看一下实现的效果。

效果演示

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

技术实现

html布局

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

import {useEffect, useState} from "react";const BounceBall = () => {// 游戏区域配置const gameArea = {width: 500,height: 400}// 小球对象const initBall = {width: 20, // 小球宽度height: 20,// 小球高度posX: 240, // 240 ~ 260posY: 190,  // 190 ~ 210speedX: 0, // 小球移动速度speedY: 2  // 小球移动速度}const [ball, setBall] = useState(initBall)// 砖块对象const initPaddle = {width: 80, // 砖块宽度height: 20,// 砖块高度posX: 210, // 210 ~ 290posY: 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 speedconst collisionPoint = (ball.posX + ball.width/2 ) - (paddle.posX + paddle.width/2) ; // 计算碰撞点距离挡板中心点的距离ball.speedX = collisionPoint * 0.1ball.speedY = -1 * ball.speedYsetBall({...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 ~ 260posY: 190,  // 190 ~ 210speedX: 0, // 小球移动速度speedY: 2  // 小球移动速度}const [ball, setBall] = useState(initBall)// 砖块对象const initPaddle = {width: 80, // 砖块宽度height: 20,// 砖块高度posX: 210, // 210 ~ 290posY: 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 speedconst collisionPoint = (ball.posX + ball.width/2 ) - (paddle.posX + paddle.width/2) ; // 计算碰撞点距离挡板中心点的距离ball.speedX = collisionPoint * 0.1ball.speedY = -1 * ball.speedYsetBall({...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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 文件和文件夹的创建与删除

目录 一. 新建1.1 mkdir 新建文件夹1.2 touch 新建空文件1.3 vi命令创建文件1.4 > 和 >> 新建文件 二. 删除 一. 新建 1.1 mkdir 新建文件夹 -p&#xff1a;递归的创建文件夹&#xff0c;当父目录不存在的时候&#xff0c;会自动创建 mkdir -p test1/test2/test31.…

递归神经网络:(01/4) 顺序数据处理的骨干

koushikkushal95 一、说明 循环神经网络是一个里程碑式的模型框架&#xff0c;它是对时间串处理的最基本构架&#xff1b;而理解RNN也是对自然语言处理模型的开端&#xff0c;本篇将对该模型的基本原理进行介绍。 二、顺序数据处理的架构 递归神经网络 &#xff08;RNN&#xf…

字典树-Python

字典树 字典树又叫前缀树、单词查找树&#xff0c;树形结构&#xff0c;是哈希树的变种。能够统计、排序和保存大量的字符串&#xff0c;经常被搜索引擎系统用于文本词频统计。优点是利用字符串的公共前缀来减少查询时间&#xff0c;最大程度减少无谓字符串的比较&#xff0c;…

HBase入门:运行机制

文章目录 HBase 系统架构客户端ZooKeeper 服务器Master 主服务器Region 服务器 Region 服务器工作原理用户读写数据的过程缓存的刷新StoreFile合并 Store 的工作原理HLog 的工作原理 HBase 系统架构 HBase 的系统架构包括客户端、ZooKeeper 服务器、Master 主服务器、Region服…

什么是SQL,什么是MYSQL?MYSQL的架构以及SQL执行语句的过程是什么?有哪些数据库的类型?一篇文章带你弄懂!

文章目录 前言一、为什么需要数据库二、数据库的相关概念1.什么是结构化查询语言 (SQL)2.什么是数据库管理系统 (DBMS)3.什么是 MySQL 数据库 三、数据库分类1.关系型数据库&#xff08;SQL&#xff09;2.非关系型数据库&#xff08;NoSQL&#xff09; 四、MYSQL架构1.各组件功…

OpenCV-27 Canny边缘检测

一、概念 Canny边缘检测算法是John F.Canny与1986年开发出来的一个多级边缘检测算法&#xff0c;也被很多人认为是边缘检测的最优算法。最优边缘检测的三个主要评价标准是&#xff1a; 低错频率&#xff1a;表示出尽可能多的实际边缘&#xff0c;同时尽可能的减小噪声产生的误…

503 Service Temporarily Unavailable nginx 原因和解决办法

前言 HTTP 503 Service Temporarily Unavailable 错误通常表示服务器无法处理请求&#xff0c;可能是由于服务器过载、维护或其他临时性问题导致的。在 Nginx 中&#xff0c;这种错误通常与后端服务的可用性问题相关。以下是可能的原因和解决办法&#xff1a; 正文…

windows安装openResty

一、openResty安装 1、下载 进入openResty官网&#xff1a; OpenResty - 下载 下载下图中的64zip包 2、解压zip&#xff0c;进入目录 进入conf目录&#xff08;openresty-1.25.3.1-win64\conf&#xff09;&#xff0c;找到nginx.conf文件&#xff0c;打开 3、修改配置文件&a…

k8s学习-DaemonSet和Job

1.1DaemonSet是什么 Deployment部署的副本Pod会分布在各个Node上&#xff0c;每个Node都可能运行好几个副本。DaemonSet的不同之处在于&#xff1a;每个Node上最多只能运行⼀个副本。DaemonSet的典型应用场景有&#xff1a; &#xff08;1&#xff09;在集群的每个节点上运⾏存…

Redis 面试题 | 16.精选Redis高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【css揭秘】

文章目录 背景与边框半透明边框多重边框box-shadowoutline 背景定位background-positionbackground-origincalc() 条纹背景水平条纹 形状圆形圆柱自适应的椭圆半椭圆四分之一椭圆 背景与边框 半透明边框 目标&#xff1a;给一个容器设置一层白色背景和一道半透明白色边框 写…

Redis学习——入门篇③

Redis学习——入门篇③ 1. Redis事务1.1 事务实际操作1.2 watch 2. Redis管道&#xff08;pipelining&#xff09;2.1 管道简介2.2 管道实际操作2.3 管道小总结 3. Redis&#xff08;pub、sub&#xff09;发布订阅(不重要)3.1 简介3.2 发布订阅实际操作 这是一个分水岭…

1.【Vue3】前端开发引入、Vue 简介

1. 前端开发引入 1.1 前端开发前置知识 通过之前的学习&#xff0c;已经通过 SpringBoot 和一些三方技术完成了大事件项目的后端开发。接下来开始学习大事件项目的前端开发&#xff0c;前端部分借助两个框架实现&#xff1a; Vue3&#xff08;一个 JS 框架&#xff09;基于 …

go 引用fork后的模块的两种方式(replace和工作区)

很久没更新了&#xff0c;一是工作琐碎&#xff0c;二是处在舒适区&#xff0c;但最近看着身边的同事一个个离开&#xff0c;危机感骤然而生&#xff0c;不得不重拾书本&#xff0c;毕竟生活还得继续&#xff0c;不卷是不可能的&#xff0c;谁让我们生在这个卷中卷的国度&#…

指数计算(填空)

解题思路&#xff1a; 7的2020次方很大&#xff0c;需要用BigInteger来进行运算。 pow用来算指数运算。 remainder用来算BigInteger之间的取余。 解题代码&#xff1a; public static void main(String[] args) {BigInteger xnew BigInteger ("7");BigInteger ynew…

开源直播电商系统的实现方式(仿抖音电商模式)

当下&#xff0c;传统的图文电商模式正在走向没落&#xff0c;以“抖音”为首的直播电商模式备受用户追捧&#xff0c;它具有直观与互动的特点&#xff0c;拥有传统电商所不具备的优势。而且&#xff0c;当前正是直播电商的红利期&#xff0c;很多主播和品牌商都通过直播电商业…

Bug: git stash恢复误drop的提交

Bug: git stash恢复误drop的提交 前几天在写ut时突然需要通过本地代码临时出一个包&#xff0c;但是本地ut又不想直接作为一个commit提交&#xff0c;所以为了省事就将ut的代码暂时stash起来。出完包后想apply stash&#xff0c;但是手误操作点成了drop stash&#xff0c;丢失了…

01.领域驱动设计:微服务设计为什么要选择DDD学习总结

目录 1、前言 2、软件架构模式的演进 3、微服务设计和拆分的困境 4、为什么 DDD适合微服务 5、DDD与微服务的关系 6、总结 1、前言 我们知道&#xff0c;微服务设计过程中往往会面临边界如何划定的问题&#xff0c;不同的人会根据自己对微服务的理 解而拆分出不同的微服…

vue2 事件总线

原图下载&#xff1a;https://download.csdn.net/download/weixin_47401101/88788636

面向Java开发者的ChatGPT提示词工程(11)扩写

什么是扩写&#xff1f; 扩写是指将较短的文本交给GPT生成更长的文本。比如&#xff1a;根据一组基本指令&#xff0c;写出一封完整的电子邮件&#xff1b;或者根据一系列主题&#xff0c;创作出一篇包含这些主题的文章。 这样的技术&#xff0c;有着广阔的应用场景&#xff…