HTML5实现一笔画游戏

HTML5实现一笔画游戏

一笔画问题

一笔画是图论科普中一个著名的问题,它起源于柯尼斯堡七桥问题科普。当时的东普鲁士哥尼斯堡城中有一条河,在这条河上有七座桥:

蓝色的代表河,这条河将城市分开成为四个区域,而七个橙色的矩形为座桥。

欧拉把实际的问题抽象为平面上的点与线,每一座桥视为一条线,桥所连接的地区视为点。

 “一笔画”问题涉及的核心概念包括连通图、奇点、偶点等。连通图指的是图中任意两个顶点之间都存在一条路径相连且没有重复。奇点则是与奇数个边相连的顶点,偶点则是与偶数个边相连的顶点。

欧拉发现,一个连通图能够一笔画出的条件是:要么图中所有顶点都是偶点,要么图中只有两个奇点。这个规律被称为欧拉定理,它为解决一笔画问题提供了理论基础。

由于哥尼斯堡七桥问题的抽象图中的四个顶点全部是奇顶点,所以它无法实现符合要求的走法,也就是不可能一笔画成。

数学家欧拉在他1736年发表的论文《柯尼斯堡的七桥》中不仅解决了七桥问题,也提出了一笔画定理,顺带解决了一笔画问题。他的这篇论文也成为图论史上第一篇重要文献。

HTML5实现一笔画游戏

HTML5和Canvas API提供了强大的图形处理能力,足以支持一笔画这样的游戏开发。

先给出效果图示:

游戏由两个文件构成:html文件(我这里命名为:一笔画游戏.html)和JavaScript脚本文件 (我这里命名为:game.js),我这里将这两个文件放在同一文件夹中。

html文件“一笔画游戏.html”源码如下

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>一笔画游戏</title><style>canvas {border: 1px solid black;}</style>
</head>
<body><canvas id="gameCanvas" width="300" height="300"></canvas><div><button onclick="startGame('easy')">简单</button><button onclick="startGame('medium')">中等</button><button onclick="startGame('hard')">困难</button><br> 连接线段时,必须按照一定的顺序来连接点。<br> 两点间连线方法:从一个点按下鼠标左键拖动到释放。</div><script src="game.js"></script>
</body>
</html>

JavaScript脚本文件 game.js源码如下

// game.jslet canvas = document.getElementById("gameCanvas");
let ctx = canvas.getContext("2d");let isDrawing = false;
let startPoint = null;
let lastPointId = null;let presetPoints = [];
let presetLines = [];
let userLines = [];const levels = {easy: {points: [{id: 1, x: 50, y: 50}, {id: 2, x: 150, y: 50}, {id: 3, x: 150, y: 150},{id: 4, x: 50, y: 150}],lines: [{start: 1, end: 2}, {start: 2, end: 3}, {start: 3, end: 4},{start: 4, end: 1},{start: 2, end: 4}]},medium: {points: [{id: 1, x: 50, y: 100}, {id: 2, x: 150, y: 100}, {id: 3, x: 250, y: 100}, {id: 4, x: 100, y: 200}, {id: 5, x: 200, y: 200}],lines: [{start: 1, end: 2}, {start: 2, end: 3}, {start: 1, end: 4}, {start: 2, end: 5}, {start: 3, end: 5}, {start: 4, end: 5}]},hard: {points: [{id: 1, x: 50, y: 50}, {id: 2, x: 150, y: 50}, {id: 3, x: 250, y: 50}, {id: 4, x: 50, y: 150}, {id: 5, x: 150, y: 150}, {id: 6, x: 250, y: 150}, {id: 7, x: 50, y: 250}, {id: 8, x: 150, y: 250}, {id: 9, x: 250, y: 250}],lines: [{start: 1, end: 2}, {start: 2, end: 3}, {start: 1, end: 4}, //{start: 2, end: 5}, {start: 3, end: 6}, {start: 4, end: 5}, //{start: 5, end: 6}, {start: 4, end: 7}, {start: 5, end: 8}, {start: 6, end: 9}, {start: 7, end: 8}, {start: 8, end: 9}]}
};function startGame(difficulty) {const level = levels[difficulty];if (!level) {console.error('未知难度级别');return;}presetPoints = level.points;presetLines = level.lines;userLines = [];lastPointId = null;draw();
}canvas.addEventListener("mousedown", (e) => {isDrawing = true;startPoint = getPointFromMouseEvent(e);
});canvas.addEventListener("mouseup", (e) => {if (!isDrawing || !startPoint) return;let endPoint = getPointFromMouseEvent(e);if (endPoint && startPoint.id !== endPoint.id) {if (lastPointId === null || lastPointId === startPoint.id) {if (isPresetLine(startPoint.id, endPoint.id)) {userLines.push({start: startPoint, end: endPoint});lastPointId = endPoint.id;draw();} else {alert("不能绘制原图中不存在的线段。");}} else {alert("必须按顺序连接点。");}}isDrawing = false;
});function getPointFromMouseEvent(e) {const rect = canvas.getBoundingClientRect();const x = e.clientX - rect.left;const y = e.clientY - rect.top;return presetPoints.find(p => Math.sqrt((p.x - x) ** 2 + (p.y - y) ** 2) < 10);
}function isPresetLine(startId, endId) {return presetLines.some(line => (line.start === startId && line.end === endId) || (line.start === endId && line.end === startId));
}function draw() {ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制预设线段presetLines.forEach(line => {let start = presetPoints.find(p => p.id === line.start);let end = presetPoints.find(p => p.id === line.end);drawLine(start, end, 'black');});// 绘制用户线段userLines.forEach(line => {drawLine(line.start, line.end, 'red');});// 绘制点presetPoints.forEach(point => {drawPoint(point);});// 检查胜利条件if (checkWin()) {alert("恭喜,你完成了这个难度级别的游戏!");}
}function checkWin() {if (userLines.length !== presetLines.length) {return false;}// 检查每个用户线段是否匹配预设线段for (let userLine of userLines) {const startId = userLine.start.id;const endId = userLine.end.id;const match = presetLines.some(line => (line.start === startId && line.end === endId) || (line.start === endId && line.end === startId));if (!match) {return false;}}return true;
}function drawLine(start, end, color) {ctx.beginPath();ctx.moveTo(start.x, start.y);ctx.lineTo(end.x, end.y);ctx.strokeStyle = color;ctx.stroke();
}function drawPoint(point) {ctx.beginPath();ctx.arc(point.x, point.y, 5, 0, 2 * Math.PI);ctx.fillStyle = 'blue';ctx.fill();
}// 初始化游戏
startGame('easy');

说明,定义不同难度的关卡数据:

const levels = {
    easy: {
        // 定义简单难度的点和线段
    },
    medium: {
        // 定义中等难度的点和线段
    },
    hard: {
        // 定义高难度的点和线段
    }
};

这些点的 x 和 y 坐标是基于画布的尺寸和布局预设的。你可能需要根据你的具体实现调整这些坐标值,以确保点和线在你的游戏界面中正确显示。此外,这些关卡设计仅作为示例,你可以根据需要调整点和线的数量及布局,创造出更多不同难度的关卡。

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

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

相关文章

深度学习 精选笔记(13.2)深度卷积神经网络-AlexNet模型

学习参考&#xff1a; 动手学深度学习2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、请联系侵删。 ②已写完的笔记文章会不定时一直修订修改(删、改、增)&#xff0c;以达到集多方教程的精华于一文的目的。 ③非常推荐上面&#xff08;学习参考&#x…

深入浅出Hive性能优化策略

我们将从基础的HiveQL优化讲起&#xff0c;涵盖数据存储格式选择、数据模型设计、查询执行计划优化等多个方面。会的直接滑到最后看代码和语法。 目录 引言 Hive架构概览 示例1&#xff1a;创建表并加载数据 示例2&#xff1a;优化查询 Hive查询优化 1. 选择适当的文件格…

unity学习(61)——hierarchy和scene的全新认识+模型+皮肤+动画controller

刚刚开始&#xff0c;但又结束的感觉&#xff1f; 1.对hierarchy和scene中的内容有了全新的认识 一定要清楚自己写过几个scene&#xff1b;每个scene之间如何跳转&#xff1b;build setting是add当前的scene。 2.此时的相机需要与模型同级&#xff0c;不能在把模型放在相机下…

STM32的USART能否支持9位数据格式话题

1、问题描述 STM32L051 这款单片机。平常的 USART 串口传输是 8 位数据&#xff0c;但是他的项目需要用串口传输 9 位数据。当设置为 8 位数据时&#xff0c;串口响应中断正常。但是&#xff0c;当设置为 9 位数据时&#xff0c;串口就不产生中断了。USART2 的 ISR 寄存器 RXN…

STM32G4高精度定时器的同步功能

1、引言 STM32G474 所含的高精度定时器(HRTIMER)其实包含了多个定时器&#xff0c;多个定时器之间可以单独工作&#xff0c;也可以进行同步&#xff0c;且高精度定时器还能与片上的其他定时器以及其他芯片进行同步&#xff0c;本文将对高精度定时器的同步功能进行介绍。 2、定…

I2S 协议简介

I2S(Inter-IC Sound)是飞利浦公司提出的一种用于数字音频设备之间进行音频数据传输的总线。和 I2C、SPI 这些常见的通信协议一样&#xff0c;I2S 总线用于主控制器和音频 CODEC 芯片之间传输音频数据。 I2S 接口需要 3 根信号线(如果需要实现收和发&#xff0c;那么就要 4 根信…

Django项目创建和settings设置

2021版本的pycharm有bug,需要将settings.py中 把BASE_DIR后面的/换成, url:统一资源定位符 互联网上每个文件都有一个唯一的url,它包含的信息指出文件的位置以及浏览器应该怎么处理它 语法: protocol://hostname[:port]/path[?query][#fragment] protocol:协议 hostname:主…

适用于系统版本:CentOS 6/7/8的基线安全检测脚本

#!/bin/bash #适用于系统版本&#xff1a;CentOS 6/7/8 echo "----------------检测是否符合密码复杂度要求----------------" #把minlen&#xff08;密码最小长度&#xff09;设置为8-32位&#xff0c;把minclass&#xff08;至少包含小写字母、大写字母、数字、特殊…

51单片机—DS18B20温度传感器

目录 一.元件介绍及原理 二&#xff0c;应用&#xff1a;DS18B20读取温度 一.元件介绍及原理 1.元件 2.内部介绍 本次元件使用的是单总线 以下为单总线的介绍 时序结构 操作流程 本次需要使用的是SKIP ROM 跳过&#xff0c; CONVERT T温度变化&#xff0c;READ SCRATCHPAD…

AI美图设计室试用,可以生成PPT,以及模特试衣

文章目录 美图设计室试用 美图设计室试用 美图设计室是美图秀秀的公司推出的AI图像处理工具&#xff0c;其功能涵盖图片编辑、抠图、海报设计、文生图等常用的AI功能。尽管很多功能需要开通会员使用&#xff0c;但一些免费功能的表现也还不错&#xff0c;值得一用。 美图设计…

Spring Boot(六十九):利用Alibaba Druid对数据库密码进行加密

1 Alibaba Druid简介 之前介绍过Alibaba Druid的,章节如下,这里就不介绍了: Spring Boot(六十六):集成Alibaba Druid 连接池 这章使用Alibaba Druid进行数据库密码加密,在上面的代码上进行修改,这章只介绍密码加密的步骤。 目前越来越严的安全等级要求,我们在做产品…

JS原型和原型链的理解

原型链图&#xff0c;图中Parent是构造函数&#xff0c;p1是通过Parent实例化出来的一个对象 前置知识 js中对象和函数的关系&#xff0c;函数其实是对象的一种 函数、构造函数的区别&#xff0c;任何函数都可以作为构造函数&#xff0c;但是并不能将任意函数叫做构造函数&…

python之前端css样式(一)

css ID选择器 #c1{color:red;#边框为红色border:1px solid red; } <div id"c2">中国移动</div> 类选择器 .xx{color:blue; } <div class"xx">中国联通</div> 标签选择器 li{color: pink; } <ul><li>北京</li…

CSS动画属性(一)加两实例

keyframes 定义 使用可以创建动画&#xff08;逐步改变从一个CSS样式设定到另一个。)可以设置多次变化发生时使用%/关键字from和to 0&#xff05;是开头动画&#xff0c;100&#xff05;是当动画完成。 为了获得最佳的浏览器支持&#xff0c;始终定义为0&#xff05;和100&…

数据分析 | NumPy

NumPy&#xff0c;全称是 Numerical Python&#xff0c;它是目前 Python 数值计算中最重要的基础模块。NumPy 是针对多维数组的一个科学计算模块&#xff0c;这个模块封装了很多数组类型的常用操作。 使用numpy来创建数组 import numpy as npdata np.array([1, 2, 3]) print…

网络学习:邻居发现协议NDP

目录 前言&#xff1a; 一、报文内容 二、地址解析----NS/NA 目标的被请求组播IP地址 邻居不可达性检测&#xff1a; 重复地址检测 路由器发现 地址自动配置 默认路由器优先级和路由信息发现 重定向 前言&#xff1a; 邻居发现协议NDP&#xff08;Neighbor Discovery…

【晴问算法】入门篇—贪心算法—区间不相交问题

题目描述 给定n个开区间&#xff0c;从中选择尽可能多的开区间&#xff0c;使得这些开区间两两没有交集。 输入描述 输出描述 输出一个整数&#xff0c;表示最多选择的开区间个数。 样例1输入 4 1 3 2 4 3 5 6 7 输出 3 解释 最多选择(1,3)、(3,5)、(6,7)三个区间&#xff0c;它…

SAP前台处理:销售业务集成<VA03/VL03N/VLPOD/VF03) 01/02

一、背景&#xff1a; 从销售订单创建VA01>发货过账VL01N >POD确认>VF01开票 这个流程涉及的凭证流及各个节点如何查询上游下游凭证&#xff1b; 二、凭证流&#xff1a; 从销售订单查看销售凭证流 VA03 双击交货单&#xff1a;带出交货单对应行项目及分批次项目…

SpringBoot(文件上传功能,阿里云OSS存储,几种配置文件用法)【详解】

目录 一、新增员工 二、文件上传-技术点 1. 文件上传功能 1.客户端上传文件三要素 2 服务端接收文件 Controller接收文件示例 修改允许上传的文件大小 2. 本地存储文件 3. 阿里云OSS存储&#xff08;这里只写一种&#xff0c;可以用其它的&#xff09; 1.介绍 2.开通…

try~catch语句

用try~catch语句来处理异常&#xff0c;将可能出现的异常操作放在 try部分&#xff0c;将发生异常后的处理放在catch部分。 带finally子语句的try~catch 语法格式 执行机制 ★注意★&#xff1a; try~catch中执行了return → finally子语句仍被执行&#xff1b; try~catch中执…