PointerLockControls 是 Three.js 中用于处理鼠标锁定状态下的相机控制的类。它允许用户通过鼠标移动来控制相机的旋转方向。

news2024/11/17 15:41:02

demo案例

PointerLockControls 是 Three.js 中用于处理鼠标锁定状态下的相机控制的类。它允许用户通过鼠标移动来控制相机的旋转方向。下面是它的详细讲解:

在这里插入图片描述

构造函数:

PointerLockControls(object: Camera, domElement?: HTMLElement)
  • object:THREE.Camera 实例,控制器将用于控制该相机。
  • domElement (可选):用于监听鼠标事件的 HTML 元素。如果未提供,则默认为 document

属性:

  1. enabled: boolean

    • 控制器是否启用。
  2. isLocked: boolean

    • 当前鼠标是否被锁定。
  3. minPolarAngle: number

    • 极角的最小值。
  4. maxPolarAngle: number

    • 极角的最大值。

方法:

  1. connect(): void

    • 连接控制器。
  2. disconnect(): void

    • 断开控制器。
  3. dispose(): void

    • 清理控制器所占用的资源,释放内存。
  4. getObject(): Camera

    • 获取控制器使用的相机对象。
  5. lock(): void

    • 锁定鼠标。
  6. unlock(): void

    • 解锁鼠标。
  7. update(delta: number): void

    • 更新控制器状态。

示例:

import * as THREE from 'three';
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';

// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 1, -5);

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建 PointerLockControls 实例
const controls = new PointerLockControls(camera, document.body);

// 添加 PointerLockControls 到场景中
scene.add(controls.getObject());

// 锁定鼠标
controls.lock();

// 监听鼠标锁定状态改变事件
document.addEventListener('pointerlockchange', () => {
    if (document.pointerLockElement === document.body) {
        controls.enabled = true;
    } else {
        controls.enabled = false;
    }
});

// 动画循环
function animate() {
    requestAnimationFrame(animate);
    controls.update(); // 更新控制器状态
    renderer.render(scene, camera);
}

animate();

示例代码解读


function init() {
    // 创建透视相机
    camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.y = 10; // 设置相机位置

    // 创建场景
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff); // 设置场景背景颜色
    scene.fog = new THREE.Fog(0xffffff, 0, 750); // 添加雾效

    // 添加半球光
    const light = new THREE.HemisphereLight(0xeeeeff, 0x777788, 2.5);
    light.position.set(0.5, 1, 0.75);
    scene.add(light);

    // 创建 PointerLockControls 实例
    controls = new PointerLockControls(camera, document.body);

    // 获取页面元素
    const blocker = document.getElementById('blocker');
    const instructions = document.getElementById('instructions');

    // 点击提示时锁定鼠标
    instructions.addEventListener('click', function () {
        controls.lock();
    });

    // 锁定时隐藏提示
    controls.addEventListener('lock', function () {
        instructions.style.display = 'none';
        blocker.style.display = 'none';
    });

    // 解锁时显示提示
    controls.addEventListener('unlock', function () {
        blocker.style.display = 'block';
        instructions.style.display = '';
    });

    // 将控制器的相机对象添加到场景中
    scene.add(controls.getObject());

    // 监听按键事件
    document.addEventListener('keydown', onKeyDown);
    document.addEventListener('keyup', onKeyUp);

    // 创建射线投射器
    raycaster = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3(0, -1, 0), 0, 10);

    // 创建地面
    let floorGeometry = new THREE.PlaneGeometry(2000, 2000, 100, 100);
    floorGeometry.rotateX(-Math.PI / 2); // 旋转地面几何体

    // 为地面顶点添加随机偏移
    let position = floorGeometry.attributes.position;
    for (let i = 0, l = position.count; i < l; i++) {
        vertex.fromBufferAttribute(position, i);
        vertex.x += Math.random() * 20 - 10;
        vertex.y += Math.random() * 2;
        vertex.z += Math.random() * 20 - 10;
        position.setXYZ(i, vertex.x, vertex.y, vertex.z);
    }

    floorGeometry = floorGeometry.toNonIndexed(); // 确保每个面的顶点是唯一的

    position = floorGeometry.attributes.position;
    const colorsFloor = [];

    // 为地面顶点设置随机颜色
    for (let i = 0, l = position.count; i < l; i++) {
        color.setHSL(Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace);
        colorsFloor.push(color.r, color.g, color.b);
    }

    // 将颜色属性添加到地面几何体中
    floorGeometry.setAttribute('color', new THREE.Float32BufferAttribute(colorsFloor, 3));

    // 创建地面网格
    const floorMaterial = new THREE.MeshBasicMaterial({ vertexColors: true });
    const floor = new THREE.Mesh(floorGeometry, floorMaterial);
    scene.add(floor);

    // 创建立方体对象并添加到场景中
    const boxGeometry = new THREE.BoxGeometry(20, 20, 20).toNonIndexed();
    position = boxGeometry.attributes.position;
    const colorsBox = [];

    // 为立方体顶点设置随机颜色
    for (let i = 0, l = position.count; i < l; i++) {
        color.setHSL(Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace);
        colorsBox.push(color.r, color.g, color.b);
    }

    // 将颜色属性添加到立方体几何体中
    boxGeometry.setAttribute('color', new THREE.Float32BufferAttribute(colorsBox, 3));

    // 创建多个立方体对象并添加到场景中
    for (let i = 0; i < 500; i++) {
        const boxMaterial = new THREE.MeshPhongMaterial({ specular: 0xffffff, flatShading: true, vertexColors: true });
        boxMaterial.color.setHSL(Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace);

        const box = new THREE.Mesh(boxGeometry, boxMaterial);
        box.position.x = Math.floor(Math.random() * 20 - 10) * 20;
        box.position.y = Math.floor(Math.random() * 20) * 20 + 10;
        box.position.z = Math.floor(Math.random() * 20 - 10) * 20;

        scene.add(box);
        objects.push(box);
    }

    // 创建渲染器
    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // 监听窗口大小变化事件
    window.addEventListener('resize', onWindowResize);
}

更新逻辑

function animate() {
    // 请求下一帧动画
    requestAnimationFrame(animate);

    // 获取当前时间
    const time = performance.now();

    // 如果控制器被锁定
    if (controls.isLocked === true) {

        // 更新射线投射器的起点为相机位置,并向下偏移
        raycaster.ray.origin.copy(controls.getObject().position);
        raycaster.ray.origin.y -= 10;

        // 检测相机位置下方是否有物体
        const intersections = raycaster.intersectObjects(objects, false);
        const onObject = intersections.length > 0;

        // 计算时间间隔
        const delta = (time - prevTime) / 1000;

        // 更新速度
        velocity.x -= velocity.x * 10.0 * delta;
        velocity.z -= velocity.z * 10.0 * delta;

        // 应用重力影响
        velocity.y -= 9.8 * 100.0 * delta; // 100.0 = mass

        // 计算移动方向
        direction.z = Number(moveForward) - Number(moveBackward);
        direction.x = Number(moveRight) - Number(moveLeft);
        direction.normalize(); // 保证在所有方向上的移动一致性

        // 根据移动方向和按键状态更新速度
        if (moveForward || moveBackward) velocity.z -= direction.z * 400.0 * delta;
        if (moveLeft || moveRight) velocity.x -= direction.x * 400.0 * delta;

        // 如果在物体上方,使y速度为0并允许跳跃
        if (onObject === true) {
            velocity.y = Math.max(0, velocity.y);
            canJump = true;
        }

        // 更新相机位置
        controls.moveRight(-velocity.x * delta);
        controls.moveForward(-velocity.z * delta);

        // 更新相机位置的y值
        controls.getObject().position.y += (velocity.y * delta); // 新的行为

        // 如果相机位置低于地面高度,使y速度为0并固定在地面上
        if (controls.getObject().position.y < 10) {
            velocity.y = 0;
            controls.getObject().position.y = 10;
            canJump = true;
        }
    }

    // 更新时间
    prevTime = time;

    // 渲染场景
    renderer.render(scene, camera);
}


完整源码


<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js - pointerlock controls</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
		<style>
			#blocker {
				position: absolute;
				width: 100%;
				height: 100%;
				background-color: rgba(0,0,0,0.5);
			}

			#instructions {
				width: 100%;
				height: 100%;

				display: flex;
				flex-direction: column;
				justify-content: center;
				align-items: center;

				text-align: center;
				font-size: 14px;
				cursor: pointer;
			}
		</style>
	</head>
	<body>
		<div id="blocker">
			<div id="instructions">
				<p style="font-size:36px">
					Click to play
				</p>
				<p>
					Move: WASD<br/>
					Jump: SPACE<br/>
					Look: MOUSE
				</p>
			</div>
		</div>

		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "./jsm/"
				}
			}
		</script>

		<script type="module">

			import * as THREE from 'three';

			import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';

			let camera, scene, renderer, controls;

			const objects = [];

			let raycaster;

			let moveForward = false;
			let moveBackward = false;
			let moveLeft = false;
			let moveRight = false;
			let canJump = false;

			let prevTime = performance.now();
			const velocity = new THREE.Vector3();
			const direction = new THREE.Vector3();
			const vertex = new THREE.Vector3();
			const color = new THREE.Color();

			init();
			animate();

			function init() {

				camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );
				camera.position.y = 10;

				scene = new THREE.Scene();
				scene.background = new THREE.Color( 0xffffff );
				scene.fog = new THREE.Fog( 0xffffff, 0, 750 );

				const light = new THREE.HemisphereLight( 0xeeeeff, 0x777788, 2.5 );
				light.position.set( 0.5, 1, 0.75 );
				scene.add( light );

				controls = new PointerLockControls( camera, document.body );

				const blocker = document.getElementById( 'blocker' );
				const instructions = document.getElementById( 'instructions' );

				instructions.addEventListener( 'click', function () {

					controls.lock();

				} );

				controls.addEventListener( 'lock', function () {

					instructions.style.display = 'none';
					blocker.style.display = 'none';

				} );

				controls.addEventListener( 'unlock', function () {

					blocker.style.display = 'block';
					instructions.style.display = '';

				} );

				scene.add( controls.getObject() );

				const onKeyDown = function ( event ) {

					switch ( event.code ) {

						case 'ArrowUp':
						case 'KeyW':
							moveForward = true;
							break;

						case 'ArrowLeft':
						case 'KeyA':
							moveLeft = true;
							break;

						case 'ArrowDown':
						case 'KeyS':
							moveBackward = true;
							break;

						case 'ArrowRight':
						case 'KeyD':
							moveRight = true;
							break;

						case 'Space':
							if ( canJump === true ) velocity.y += 350;
							canJump = false;
							break;

					}

				};

				const onKeyUp = function ( event ) {

					switch ( event.code ) {

						case 'ArrowUp':
						case 'KeyW':
							moveForward = false;
							break;

						case 'ArrowLeft':
						case 'KeyA':
							moveLeft = false;
							break;

						case 'ArrowDown':
						case 'KeyS':
							moveBackward = false;
							break;

						case 'ArrowRight':
						case 'KeyD':
							moveRight = false;
							break;

					}

				};

				document.addEventListener( 'keydown', onKeyDown );
				document.addEventListener( 'keyup', onKeyUp );

				raycaster = new THREE.Raycaster( new THREE.Vector3(), new THREE.Vector3( 0, - 1, 0 ), 0, 10 );

				// floor

				let floorGeometry = new THREE.PlaneGeometry( 2000, 2000, 100, 100 );
				floorGeometry.rotateX( - Math.PI / 2 );

				// vertex displacement

				let position = floorGeometry.attributes.position;

				for ( let i = 0, l = position.count; i < l; i ++ ) {

					vertex.fromBufferAttribute( position, i );

					vertex.x += Math.random() * 20 - 10;
					vertex.y += Math.random() * 2;
					vertex.z += Math.random() * 20 - 10;

					position.setXYZ( i, vertex.x, vertex.y, vertex.z );

				}

				floorGeometry = floorGeometry.toNonIndexed(); // ensure each face has unique vertices

				position = floorGeometry.attributes.position;
				const colorsFloor = [];

				for ( let i = 0, l = position.count; i < l; i ++ ) {

					color.setHSL( Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace );
					colorsFloor.push( color.r, color.g, color.b );

				}

				floorGeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colorsFloor, 3 ) );

				const floorMaterial = new THREE.MeshBasicMaterial( { vertexColors: true } );

				const floor = new THREE.Mesh( floorGeometry, floorMaterial );
				scene.add( floor );

				// objects

				const boxGeometry = new THREE.BoxGeometry( 20, 20, 20 ).toNonIndexed();

				position = boxGeometry.attributes.position;
				const colorsBox = [];

				for ( let i = 0, l = position.count; i < l; i ++ ) {

					color.setHSL( Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace );
					colorsBox.push( color.r, color.g, color.b );

				}

				boxGeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colorsBox, 3 ) );

				for ( let i = 0; i < 500; i ++ ) {

					const boxMaterial = new THREE.MeshPhongMaterial( { specular: 0xffffff, flatShading: true, vertexColors: true } );
					boxMaterial.color.setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace );

					const box = new THREE.Mesh( boxGeometry, boxMaterial );
					box.position.x = Math.floor( Math.random() * 20 - 10 ) * 20;
					box.position.y = Math.floor( Math.random() * 20 ) * 20 + 10;
					box.position.z = Math.floor( Math.random() * 20 - 10 ) * 20;

					scene.add( box );
					objects.push( box );

				}

				//

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				document.body.appendChild( renderer.domElement );

				//

				window.addEventListener( 'resize', onWindowResize );

			}

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			function animate() {

				requestAnimationFrame( animate );

				const time = performance.now();

				if ( controls.isLocked === true ) {

					raycaster.ray.origin.copy( controls.getObject().position );
					raycaster.ray.origin.y -= 10;

					const intersections = raycaster.intersectObjects( objects, false );

					const onObject = intersections.length > 0;

					const delta = ( time - prevTime ) / 1000;

					velocity.x -= velocity.x * 10.0 * delta;
					velocity.z -= velocity.z * 10.0 * delta;

					velocity.y -= 9.8 * 100.0 * delta; // 100.0 = mass

					direction.z = Number( moveForward ) - Number( moveBackward );
					direction.x = Number( moveRight ) - Number( moveLeft );
					direction.normalize(); // this ensures consistent movements in all directions

					if ( moveForward || moveBackward ) velocity.z -= direction.z * 400.0 * delta;
					if ( moveLeft || moveRight ) velocity.x -= direction.x * 400.0 * delta;

					if ( onObject === true ) {

						velocity.y = Math.max( 0, velocity.y );
						canJump = true;

					}

					controls.moveRight( - velocity.x * delta );
					controls.moveForward( - velocity.z * delta );

					controls.getObject().position.y += ( velocity.y * delta ); // new behavior

					if ( controls.getObject().position.y < 10 ) {

						velocity.y = 0;
						controls.getObject().position.y = 10;

						canJump = true;

					}

				}

				prevTime = time;

				renderer.render( scene, camera );

			}

		</script>
	</body>
</html>

本内容来源于小豆包,想要更多内容请跳转小豆包 》

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

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

相关文章

Linux 系统 快速卸载docker

(卸载前一定要做好相关数据的备份) 卸载&#xff1a; 第一种卸载方法 1、查询docker安装过的包&#xff1a; yum list installed | grep docker 2、删除安装包&#xff1a; yum remove docker-ce.x86_64 ddocker-ce-cli.x86_64 -y 3、删除镜像/容器等 rm -rf /var/lib/dock…

力扣面试150 x 的平方根 二分 换底法 牛顿迭代法 一题多解

Problem: 69. x 的平方根 思路 &#x1f468;‍&#x1f3eb; 参考题解 &#x1f496; 袖珍计算器算法 class Solution {public int mySqrt(int x){if (x 0)return 0; // Math.exp(3)&#xff1a;e的三次方int ans (int) Math.exp(0.5 * Math.log(x));return (long) (an…

react native 键盘事件

在做修改密码功能是发现他的键盘第一次调起之后然后收起键盘焦点不会消失而且键盘也不会再调起来了 我门线引入需要的组件 import { StyleSheet, View, TextInput, Keyboard, TouchableWithoutFeedback, } from react-native; import React, {useEffect, useState, useRef} fr…

蓝桥杯真题:幸运数字

这道题可以用 integer.string&#xff08;&#xff09;求每个进制的数&#xff0c;但这里要每一位数相加&#xff0c;所以用这个方法会比较麻烦&#xff0c;如下 import java.util.Scanner; public class Main {public static void main(String[] args) {Scanner scan new Sc…

LeetCode 面试经典150题 14.最长公共前缀

题目&#xff1a; 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 思路&#xff1a; 代码&#xff1a; class Solution {public String longestCommonPrefix(String[] strs) {if (strs.length 0) {return &…

吴恩达2022机器学习专项课程(一) 3.5 可视化成本函数

问题预览 为什么要可视化成本函数&#xff1f;可视化之后的成本函数是什么样子&#xff1f;如何在三维空间里通过w和b找到一个成本函数的值&#xff1f;如何在三维空间里找到成本函数的最小值&#xff1f; 解读 可视化成本函数&#xff1a;为了更加方便的看到不同的w和b&…

【短接笔记本或者台式机的CMOS针脚解决电脑开机无法启动BIOS无法进入问题】

为什么要执行短接笔记本或者台式机的CMOS针脚操作&#xff1f; 问题&#xff1a;可以解决如下图所示&#xff0c;技嘉小雕主板开机时按delete键无法进入BIOS主板界面&#xff0c;长时间等待之后依然无法进入BIOS主板界面&#xff0c;则判定为主板问题。此时短接CMOS针脚可清空…

【数据结构】考研真题攻克与重点知识点剖析 - 第 2 篇:线性表

前言 本文基础知识部分来自于b站&#xff1a;分享笔记的好人儿的思维导图与王道考研课程&#xff0c;感谢大佬的开源精神&#xff0c;习题来自老师划的重点以及考研真题。此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析&#xff0c;本人技术…

ShardingSphere水平分表——开发经验(2)

1. 什么场景下分表&#xff1f; 数据量过大或者数据库表对应的磁盘文件过大。 Q&#xff1a;多少数据分表&#xff1f; A&#xff1a;网上有人说1kw&#xff0c;2kw&#xff1f;不准确。 1、一般看字段的数量&#xff0c;有没有包含text类型的字段。我们的主表里面是不允许有t…

Github 2024-03-24php开源项目日报 Top10

根据Github Trendings的统计,今日(2024-03-24统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量PHP项目10JavaScript项目1Nextcloud服务器:安全的数据之家 创建周期:2796 天开发语言:PHP, JavaScript协议类型:GNU Affero General Public…

计算机网络⑧ —— IP地址

IP位于TCP/IP参考模型的第三层&#xff0c;也就是⽹络层 ⽹络层的主要作⽤&#xff1a;实现主机与主机之间的通信&#xff0c;也叫点对点通信 问题1&#xff1a;⽹络层(IP)与数据链路层(MAC)有什么关系呢&#xff1f; MAC的作⽤&#xff1a;实现直连的两个设备之间通信。IP的…

包子凑数 蓝桥杯

关于这题的数学定理&#xff0c;如果 a,b 均是正整数且互质&#xff0c;那么由 axby&#xff0c;x≥0&#xff0c;y≥0 不能凑出的最大数是 &#xff1a;a*b-a-b 想不起来的时候&#xff0c;把能列出来的数据列出来找规律&#xff0c;不互质得数不符合题目所说 类似于力扣零钱…

【boost_search搜索引擎】1.获取数据源

boost搜索引擎 1、项目介绍2、获取数据源 1、项目介绍 boost_search项目和百度那种不一样&#xff0c;百度是全站搜索&#xff0c;而boost_search是一个站内搜索。而项目的宏观上实现思路就如同图上的思路。 2、获取数据源 我们要实现一个站内搜索&#xff0c;我们就要有这…

包含多个段的程序

文章目录 包含多个段的程序在代码段中使用数据在代码段中使用栈将数据、代码、栈放入不同的段 包含多个段的程序 在代码段中使用数据 考虑这样一个问题&#xff0c;编程计算以下8个数据的和&#xff0c;结果存在ax 寄存器中&#xff1a;0123H&#xff0c;0456H&#xff0c;07…

中性点接地问题的matlab仿真与分析

1、内容简介 略 81-可以交流、咨询、答疑 2、内容说明 略电力系统的中性点接地方式通常是按电压等级 的高低来进行选取的, 我国中压电网普遍采用的有 3 种方式 :不接地 、经消弧线圈接地和经电阻接地。 电力系统在正常运行时, 对不同的中性点接地方式及其差异, 基本上没有…

海外媒体宣发:十大国外中文网站-大舍传媒

十大国外中文网站 1、欧洲时报 覆盖欧洲且较具影响力的华文媒体 国外中文新闻网站&#xff0c;欧洲时报文化传媒集团旗舰日报《欧洲时报》旗下官方网站&#xff0c;总部设在法国巴黎&#xff0c;创刊于1983年&#xff0c;现已成为唯一发行覆盖全欧、发行量最大、最具影响力的华…

ubuntu上一款好用的串口工具screen

看名字&#xff0c;你猜他是什么&#xff1f; 安装 sudo apt install screen 然后将USB串口接到虚拟机&#xff0c;执行dmesg命令查看串口设备名&#xff1a; 测试&#xff1a; sudo screen /dev/ttyUSB0 115200确实很简单。

Python入门(七)

递归 递归是函数调用其自身的操作。递归源自数学归纳法。数学归纳法&#xff08;Mathematical Induction&#xff09;是一种数学证明方法&#xff0c;常用于证明命题在自然数范围内成立。 计算1到100的和&#xff1a; def gaussian_sum(n): if n 1: return 1 else: return …

Spring Boot集成zxing实现生成二维码功能

1.二维码介绍 二维码QR Code(Quick Response Code) 由Denso公司于1994年9月研制的一种矩阵二维码符号&#xff0c;它具有一维条码及其它二维条码所具有的信息容量大、可靠性高、可表示汉字及图象多种文字信息、保密防伪性强等优点。 ZXing 一个支持在图像中解码和生成条形码(如…

项目1-加法计算器

1.创建项目 2.导入前端代码 2.1 static包内 2.2 测试前端代码是否有误 显示成功说明无误 2.3 定义用户接口 请求路径&#xff1a;calc/sum 请求方式&#xff1a;GET/POST 接口描述&#xff1a;计算两个整数相加 请求参数: 参数名类型是否必须备注num1Integer是参与计算的第…