vue3+threejs新手从零开发卡牌游戏(十八):己方场上手牌添加画线

手牌上场后,点击己方怪兽区卡牌会跟随鼠标移动画出线条,之后可以通过判断鼠标移动到对方场地的某卡牌进行战斗操作,代码主要改动在game/index.vue文件。

1.添加鼠标移动监听事件(移动端):

window.addEventListener('touchstart', onMousedown)
window.addEventListener('touchmove', onMousemove)
window.addEventListener('touchend', onMouseup)

2.鼠标按下获取选中手牌:

// 鼠标按下事件
const onMousedown = (ev: any) => {...// 鼠标选中场上卡牌事件onSelectSiteCard(ev)
}// 鼠标选中场上卡牌事件
const onSelectSiteCard = (point: any) => {let p1Cards = scene.children.filter((v: any) => v.userData?.areaType?.indexOf("己方怪兽区") > -1)if (p1Cards.length <= 0) {return}let arr = raycaster.intersectObjects(p1Cards, true)if (arr.length > 0) {selectedCard.value = arr[0].objectconsole.log(444, arr[0].object)drawLine()}}

3.添加画线逻辑,主要通过CatmullRomCurve3和TubeGeometry管道缓冲几何体配合画线,网上随便找了个箭头的png图做素材:

// 鼠标移动事件
const onMousemove = (ev: any) => {// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)pointer.x = ev.clientX || ev.changedTouches[0].pageXpointer.y = ev.clientY || ev.changedTouches[0].pageY// 画线if (selectedCard.value) {drawLine()}
}// 鼠标抬起事件
const onMouseup = (ev: any) => {let lineMesh = scene.getObjectByName("移动线")if (lineMesh) {scene.remove(lineMesh)}
}// 画线
const drawLine = () => {let mesh = scene.getObjectByName("移动线")if (mesh) {scene.remove(mesh)}let startPos = new THREE.Vector3(0, 0, 0)selectedCard.value.getWorldPosition(startPos)let point = transPos(pointer.x, pointer.y)// 通过摄像机和鼠标位置更新射线raycaster.setFromCamera( point, camera );let plane = scene.getObjectByName("地面")let arr = raycaster.intersectObject(plane)if (arr.length > 0) {// let pos = new THREE.Vector3(0, 0, 0)// arr[0].object.getWorldPosition(pos)let point = arr[0].pointlet curve = new THREE.CatmullRomCurve3([new THREE.Vector3(startPos.x, startPos.y + 0.2, startPos.z),new THREE.Vector3(point.x, point.y + 0.2, point.z)]);let tubeGeometry = new THREE.TubeGeometry(curve, 80, 0.08);const material = new THREE.MeshBasicMaterial({map: arrowTexture,side: THREE.BackSide, //显示背面transparent: true,// color: new THREE.Color("#ff6347")});const _mesh = new THREE.Mesh( tubeGeometry, material );_mesh.name = "移动线"scene.add(_mesh);}
}

页面效果如下,后续方便进行战斗逻辑处理:

附:
game/index.vue代码:

<template><div ref="sceneRef" class="scene"></div><!-- 玩家区 --><Player ref="playerRef"/><!-- 手牌 --><Hand ref="handRef"/><!-- 卡组 --><Deck ref="deckRef"/><!-- 战域 --><Site ref="siteRef"/><!-- 抽卡逻辑 --><DrawCard ref="drawCardRef" :handRef="handRef"/><!-- 对话框 --><Dialog ref="dialogRef" @handToSite="handToSite" @onCancel="onCancel"/>
</template><script setup lang="ts">
import { reactive, ref, onMounted, onBeforeUnmount, watch, defineComponent, getCurrentInstance, nextTick } from 'vue'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; // 轨道控制器
import { DragControls } from 'three/addons/controls/DragControls.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { GlitchPass } from 'three/addons/postprocessing/GlitchPass.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
import { GammaCorrectionShader } from 'three/examples/jsm/shaders/GammaCorrectionShader.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
import { useCommonStore } from "@/stores/common.ts"
import { transPos, editDeckCard, renderDeckText, renderSiteCardText } from "@/utils/common.ts"
import { Card } from "./Card.ts"
import { CARD_DICT } from "@/utils/dict/card.ts"
import { p1TestDeck, p2TestDeck} from "@/utils/deck/test.ts"
import Hand from "./hand/index.vue"
import Deck from "./deck/index.vue"
import Site from "./site/index.vue"
import Player from "./player/index.vue"
import DrawCard from "@/components/DrawCard.vue"
import Dialog from "@/components/Dialog.vue"
import { resolve } from 'dns';// 引入threejs变量
const {proxy} = getCurrentInstance()
const THREE = proxy['THREE']
const scene = proxy['scene']
const camera = proxy['camera']
const renderer = proxy['renderer']
const composer = proxy['composer']
const TWEEN = proxy['TWEEN']// 后期处理
const renderPass = new RenderPass( scene, camera );
composer.addPass( renderPass );// 
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();const commonStore = useCommonStore()// 场景ref
const sceneRef = ref()
const playerRef = ref()
const siteRef = ref()
const handRef = ref()
const deckRef = ref()
const drawCardRef = ref()
const dialogRef = ref()
const selectedCard = ref() // 选中的场上card// 坐标轴辅助
const axesHelper = new THREE.AxesHelper(5);
// 创建轨道控制器
// const orbitControls = new OrbitControls( camera, renderer.domElement );
// 字体加载器
const fontLoader = new FontLoader();onMounted(async () => {await initResource()initScene()initGame()// 鼠标按下window.addEventListener('touchstart', onMousedown)window.addEventListener('touchmove', onMousemove)window.addEventListener('touchend', onMouseup)// window.addEventListener('click', onMousedown)// 监听浏览器窗口变化进行场景自适应window.addEventListener('resize', onWindowResize, false);
})// 资源加载
const initResource = () => {// 字体加载return new Promise((resolve, reject) => {// Microsoft YaHei_Regular// fonts/helvetiker_regular.typeface.jsonfontLoader.load('fonts/helvetiker_bold.typeface.json', (font: any) => {commonStore.loadFont(font)resolve(true)});})
}// 初始化场景
const initScene = async () => {renderer.setSize( window.innerWidth, window.innerHeight );sceneRef.value.appendChild( renderer.domElement );scene.add(axesHelper)// addSceneBg()// camera.position.set( 5, 5, 5 );camera.position.set( 0, 6.5, 0 );camera.lookAt(0, 0, 0)// const glitchPass = new GlitchPass();// composer.addPass( glitchPass );// const outputPass = new OutputPass();// composer.addPass( outputPass );addPlane()animate();
}// scene添加动态背景
const addSceneBg = () => {const vertices = [];for ( let i = 0; i < 5000; i ++ ) {const x = THREE.MathUtils.randFloatSpread( 1000 );const y = THREE.MathUtils.randFloatSpread( 1000 );const z = THREE.MathUtils.randFloatSpread( 1000 );vertices.push( x, y, z );}const particlesGeometry = new THREE.BufferGeometry();particlesGeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );// 设置点材质const pointsMaterial = new THREE.PointsMaterial();// pointsMaterial.size = 0.9;pointsMaterial.color.set(new THREE.Color("#fff"));// 相机深度而衰减pointsMaterial.sizeAttenuation = true;const points = new THREE.Points(particlesGeometry, pointsMaterial);scene.add(points);// const texture = new THREE.TextureLoader().load( "textures/bg.jpg" );// // const geometry = new THREE.SphereGeometry( 1, 32, 16 );// const geometry = new THREE.CircleGeometry( 6, 32 );// const material = new THREE.MeshBasicMaterial({//   map: texture// });// const sphere = new THREE.Mesh( geometry, material );// sphere.name = "场景背景"// sphere.position.set(0, 0, 0)// sphere.rotateX(-90 * (Math.PI / 180)) // 弧度// scene.add( sphere );// texture.wrapS = THREE.RepeatWrapping;// texture.wrapT = THREE.RepeatWrapping;// scene.background = texture
}// scene中添加plane几何体
const addPlane = () => {const geometry = new THREE.PlaneGeometry( 20, 20);const material = new THREE.MeshBasicMaterial( {color: new THREE.Color("gray"), side: THREE.FrontSide, alphaHash: true,// alphaTest: 0,opacity: 0} );const plane = new THREE.Mesh( geometry, material );plane.rotateX(-90 * (Math.PI / 180)) // 弧度plane.name = "地面"scene.add( plane );
}// 用requestAnimationFrame进行渲染循环
// let bgMesh = scene.getObjectByName("场景背景")
// console.log(123, bgMesh)let arrowTexture = new THREE.TextureLoader().load('textures/arrow.png');
arrowTexture.wrapT = THREE.RepeatWrapping;
arrowTexture.repeat.set(1, 4);
arrowTexture.center = new THREE.Vector2(0.5, 0.5)
arrowTexture.rotation = (-90 * (Math.PI / 180))
arrowTexture.needsUpdate = true;const animate = () => {requestAnimationFrame( animate );if (arrowTexture) {arrowTexture.offset.y -= 0.02; //更新箭头纹理偏移量}TWEEN.update()// let bgMesh = scene.getObjectByName("场景背景")// if (bgMesh) {//   bgMesh.rotation.z += 0.0002// }// renderer.render( scene, camera );composer.render()
}// 场景跟随浏览器窗口大小自适应
const onWindowResize = () => {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);
}// 初始化游戏
const initGame = async () => {// 初始化玩家initPlayer()// 初始化场地initSite()// 初始化卡组await initDeck()// 初始化手牌await initHand()// 绑定手牌事件onHandEvent()// await p2DrawCardEvent(1)let p2_handGroup = scene.getObjectByName("p2_handGroup")let cards = p2_handGroup.children.filter((v: any) => v.userData.type === "怪兽")console.log(123, cards)p2HandToSite(cards[0])
}// 初始化玩家
const initPlayer = () => {playerRef.value.init()
}// 初始化场地
const initSite = () => {siteRef.value.init()
}// 初始化卡组
const initDeck = () => {return new Promise((resolve, reject) => {let p1Deck: any = []let p2Deck: any = []// 洗牌p1TestDeck.sort(() => {return Math.random() - 0.5})p2TestDeck.sort(() => {return Math.random() - 0.5})p1TestDeck.forEach((v: any, i: any) => {let obj = CARD_DICT.find((b: any) => b.card_id === v)if (obj) {p1Deck.push({card_id: v,name: `${obj.name}_${i}`})}})p2TestDeck.forEach((v: any, i: any) => {let obj = CARD_DICT.find((b: any) => b.card_id === v)if (obj) {p2Deck.push({card_id: v,name: `${obj.name}_${i}`})}})// console.log("p1Deck", newDeck)commonStore.updateP1Deck(p1Deck)commonStore.updateP2Deck(p2Deck)nextTick(() => {handRef.value.init()deckRef.value.init()resolve(true)})})
}// 初始化手牌
const initHand = () => {let p1 = new Promise((resolve, reject) => {let cardNumber = 4let _number = 0let p1Deck = JSON.parse(JSON.stringify(commonStore.$state.p1Deck))let deckGroup = scene.getObjectByName("p1_deckGroup")let position = new THREE.Vector3(0, 0.005 * p1Deck.length, 0)let _interval = setInterval(async() => {// console.log(123, p1Deck)if (_number < cardNumber) {let obj = p1Deck[p1Deck.length - 1]p1Deck.splice(p1Deck.length-1, 1)commonStore.updateP1Deck(p1Deck)// 修改卡组await editDeckCard(deckGroup, obj, "remove")await renderDeckText(deckGroup, `${commonStore.$state.p1Deck.length}`, commonStore.$state._font, position)// 手牌区添加手牌handRef.value.addP1HandCard(obj, deckGroup)} else {clearInterval(_interval)resolve(true)}_number++}, 200)})let p2 = new Promise((resolve, reject) => {let cardNumber = 4let _number = 0let p2Deck = JSON.parse(JSON.stringify(commonStore.$state.p2Deck))let deckGroup = scene.getObjectByName("p2_deckGroup")let position = new THREE.Vector3(0, 0.005 * p2Deck.length, 0)let _interval = setInterval(async() => {// console.log(123, p1Deck)if (_number < cardNumber) {let obj = p2Deck[p2Deck.length - 1]p2Deck.splice(p2Deck.length-1, 1)commonStore.updateP2Deck(p2Deck)// 修改卡组await editDeckCard(deckGroup, obj, "remove")await renderDeckText(deckGroup, `${commonStore.$state.p2Deck.length}`, commonStore.$state._font, position)// 手牌区添加手牌handRef.value.addP2HandCard(obj, deckGroup)} else {clearInterval(_interval)resolve(true)}_number++}, 200)})return new Promise((resolve, reject) => {Promise.all([p1, p2]).then((res: any) => {resolve(true)})})
}// p2抽牌事件
const p2DrawCardEvent = (cardNumber: any) => {return new Promise((resolve, reject) => {let _number = 0let p2Deck = JSON.parse(JSON.stringify(commonStore.$state.p2Deck))let deckGroup = scene.getObjectByName("p2_deckGroup")let position = new THREE.Vector3(0, 0.005 * p2Deck.length, 0)let _interval = setInterval(async() => {// console.log(123, p1Deck)if (_number < cardNumber) {let obj = p2Deck[p2Deck.length - 1]p2Deck.splice(p2Deck.length-1, 1)commonStore.updateP2Deck(p2Deck)// 修改卡组await editDeckCard(deckGroup, obj, "remove")await renderDeckText(deckGroup, `${commonStore.$state.p2Deck.length}`, commonStore.$state._font, position)// 手牌区添加手牌handRef.value.addP2HandCard(obj, deckGroup)} else {clearInterval(_interval)resolve(true)}_number++}, 200)})
}// p2卡牌上场事件
const p2HandToSite = (card: any) => {let sitePlane = scene.getObjectByName("对方战域Plane")let userData = card.userDataif (userData.type === "怪兽") {let meshes = sitePlane.children.filter((v: any) => v.name.indexOf("对方怪兽区") > -1 && v.userData.empty === true)if (meshes.length > 0) {let _mesh = nulllet m1 = meshes.find((v: any) => v.name.indexOf(1) > -1)let m2 = meshes.find((v: any) => v.name.indexOf(2) > -1)let m3 = meshes.find((v: any) => v.name.indexOf(3) > -1)if (m2) {_mesh = m2} else if (m1) {_mesh = m1} else if (m3) {_mesh = m3}let p2_handGroup = scene.getObjectByName("p2_handGroup")// card.rotateX(180 * (Math.PI / 180)) // 弧度renderSiteCard(p2_handGroup, card, _mesh)}}
}// 鼠标按下事件
const onMousedown = (ev: any) => {// console.log(222, ev.target)// 判断是否点击到canvas上if(!(ev.target instanceof HTMLCanvasElement)){return;}// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)let clientX = ev.clientX || ev.changedTouches[0].pageXlet clientY = ev.clientY || ev.changedTouches[0].pageYlet point = transPos(clientX, clientY)// 通过摄像机和鼠标位置更新射线raycaster.setFromCamera( point, camera );// 点击卡组事件// onP1DeckEvent()// 鼠标选中场上卡牌事件onSelectSiteCard(ev)
}// 鼠标移动事件
const onMousemove = (ev: any) => {// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)pointer.x = ev.clientX || ev.changedTouches[0].pageXpointer.y = ev.clientY || ev.changedTouches[0].pageY// 画线if (selectedCard.value) {drawLine()}
}// 鼠标抬起事件
const onMouseup = (ev: any) => {let lineMesh = scene.getObjectByName("移动线")if (lineMesh) {scene.remove(lineMesh)}
}// 鼠标选中场上卡牌事件
const onSelectSiteCard = (point: any) => {let p1Cards = scene.children.filter((v: any) => v.userData?.areaType?.indexOf("己方怪兽区") > -1)if (p1Cards.length <= 0) {return}let arr = raycaster.intersectObjects(p1Cards, true)if (arr.length > 0) {selectedCard.value = arr[0].objectconsole.log(444, arr[0].object)drawLine()}}// 画线
const drawLine = () => {let mesh = scene.getObjectByName("移动线")if (mesh) {scene.remove(mesh)}let startPos = new THREE.Vector3(0, 0, 0)selectedCard.value.getWorldPosition(startPos)let point = transPos(pointer.x, pointer.y)// 通过摄像机和鼠标位置更新射线raycaster.setFromCamera( point, camera );let plane = scene.getObjectByName("地面")let arr = raycaster.intersectObject(plane)if (arr.length > 0) {// let pos = new THREE.Vector3(0, 0, 0)// arr[0].object.getWorldPosition(pos)let point = arr[0].pointlet curve = new THREE.CatmullRomCurve3([new THREE.Vector3(startPos.x, startPos.y + 0.2, startPos.z),new THREE.Vector3(point.x, point.y + 0.2, point.z)]);let tubeGeometry = new THREE.TubeGeometry(curve, 80, 0.08);const material = new THREE.MeshBasicMaterial({map: arrowTexture,side: THREE.BackSide, //显示背面transparent: true,// color: new THREE.Color("#ff6347")});const _mesh = new THREE.Mesh( tubeGeometry, material );_mesh.name = "移动线"scene.add(_mesh);}
}// 点击卡组事件
const onP1DeckEvent = () => {if (commonStore.$state.p1Deck.length <= 0) {return}let p1_deckGroup = scene.getObjectByName("p1_deckGroup")let arr = raycaster.intersectObject(p1_deckGroup, true)if (arr.length <= 0) {return}let pos1 = p1_deckGroup.userData.positionlet pos2 = new THREE.Vector3(0, 2, 0)// console.log(444, pos1, pos2)if (p1_deckGroup.position.x !== pos2.x) {drawCardRef.value.drawCardAnimate1(p1_deckGroup, pos1, pos2)}
}// 手牌事件
const onHandEvent = () => {let handGroup = scene.getObjectByName("p1_handGroup")const dragControls = new DragControls( handGroup.children, camera, renderer.domElement );dragControls.addEventListener( 'dragstart', function ( event: any ) {event.object.position.y += 0.04});dragControls.addEventListener( 'drag', function ( event: any ) {event.object.position.y += 0.04});dragControls.addEventListener( 'dragend', function ( event: any ) {event.object.position.y -= 0.04let p1SitePlane = scene.getObjectByName("己方战域Plane")let point = transPos(pointer.x, pointer.y)// 通过摄像机和鼠标位置更新射线raycaster.setFromCamera( point, camera );const intersects = raycaster.intersectObjects(p1SitePlane.children);if (intersects.length > 0) {dialogRef.value.init({type: "handToSite",obj: event.object,message: "是否上场该卡牌"})} else {handRef.value.backPosition(event.object)}});
}// 手牌移入己方战域
const handToSite = (data: any) => {let sitePlane = scene.getObjectByName("己方战域Plane")console.log(data)let userData = data.userDataif (userData.type === "怪兽") {let meshes = sitePlane.children.filter((v: any) => v.name.indexOf("己方怪兽区") > -1 && v.userData.empty === true)if (meshes.length > 0) {let _mesh = nulllet m1 = meshes.find((v: any) => v.name.indexOf(1) > -1)let m2 = meshes.find((v: any) => v.name.indexOf(2) > -1)let m3 = meshes.find((v: any) => v.name.indexOf(3) > -1)if (m2) {_mesh = m2} else if (m1) {_mesh = m1} else if (m3) {_mesh = m3}let p1_handGroup = scene.getObjectByName("p1_handGroup")renderSiteCard(p1_handGroup, data, _mesh)}}
}// 绘制场上卡牌
const renderSiteCard = async (handGroup: any, data: any, mesh: any) => {let position = new THREE.Vector3(0, 0, 0)mesh.getWorldPosition(position)mesh.userData.empty = falselet oldMesh = handGroup.children.find((v: any) => v.name === data.name)let newMesh = oldMesh.clone()newMesh.userData.areaType = mesh.name // 用来记录卡牌在哪个区域,怪兽区、墓地、手牌、卡组、场地等newMesh.scale.set(0.8, 0.8, 0.8)if (handGroup.name === "p1_handGroup") {handRef.value.removeP1HandCard(oldMesh)} else if (handGroup.name === "p2_handGroup") {handRef.value.removeP2HandCard(oldMesh)newMesh.rotateX(180 * (Math.PI / 180)) // 弧度newMesh.rotateY(180 * (Math.PI / 180)) // 弧度}scene.add(newMesh)newMesh.position.set(position.x, position.y, position.z)await renderSiteCardText(handGroup, newMesh, commonStore.$state._font)// 创建伽马校正通道// const gammaPass= new ShaderPass(GammaCorrectionShader)// composer.addPass( gammaPass );// const outlinePass = new OutlinePass(new THREE.Vector2( window.innerWidth, window.innerHeight ), scene, camera); // 模糊// outlinePass.edgeStrength = 1.0; // 调整边缘强度// outlinePass.edgeGlow = 1.0; // 边缘发光强度// outlinePass.usePatternTexture = false; // 是否使用纹理// outlinePass.visibleEdgeColor.set(0xffffff); // 设置边缘颜色// outlinePass.hiddenEdgeColor.set(0x000000); // 设置隐藏边缘的颜色// outlinePass.selectedObjects = [newMesh.children[0]]// composer.addPass( outlinePass );console.log(123, newMesh)
}// 取消
const onCancel = (data: any) => {handRef.value.backPosition(data)
}
</script><style lang="scss" scoped>
.scene {position: fixed;top: 0;left: 0;width: 100%;height: 100vh;
}
</style>

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

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

相关文章

相册清理大师-手机重复照片整理、垃圾清理软件

相册清理大师是一款超级简单实用的照片视频整理工具。通过便捷的操作手势&#xff0c;帮助你极速整理相册中的照片和视频、释放手机存储空间。 【功能简介】 向上滑动&#xff1a;删除不要的照片 向左滑动&#xff1a;切换下一张照片 向右滑动&#xff1a;返回上一张照片 整理分…

excel使用技巧-自动计算过滤后的数据(=SUBTOTAL(109,B2:B110))

语法&#xff1a;SUBTOTAL(function_num,ref1,ref2, …) Function_num 为 1 到 11&#xff08;包含隐藏值&#xff09;或 101 到 111&#xff08;忽略隐藏值&#xff09;之间的数字&#xff0c;指定使用何种函数在列表中进行分类汇总计算。对应的含义如下面表格所示&#xff1…

Java常用的API

跟着黑马的Java学习视频学者本篇常用的API Math public static int abs(int a) {return (a < 0) ? -a : a; }public static double ceil(double a) {return StrictMath.ceil(a); }public static double floor(double a) {return StrictMath.floor(a); }public static doub…

学习JavaEE的日子 Day29 yield,join,线程的中断,守护线程,线程局部变量共享,线程生命周期

Day29 多线程 12. 线程的礼让 Thread.yield(); 理解&#xff1a;此方法为静态方法&#xff0c;此方法写在哪个线程中&#xff0c;哪个线程就礼让 注意&#xff1a;所谓的礼让是指当前线程退出CPU资源&#xff0c;并转到就绪状态&#xff0c;接着再抢 需求&#xff1a;创建两个…

Kimi和ChatGPT做古诗词阅读理解,谁更胜一筹?

前几天发过一篇Kimi整理会议的体验教程&#xff0c;没想到大家很感兴趣&#xff0c;这次再来拿Kimi做古诗词阅读理解看看&#xff0c;同时也对比下ChatGPT的效果。 ChatGPT是几乎家喻户晓的AI大模型&#xff0c;Kimi和它对比有哪些异同点呢&#xff1f; 首先它们都是基于对话…

【Flink架构】关于FLink BLOB的组织架构:FLIP-19: Improved BLOB storage architecture:官网解读

文章目录 一. BlobServer架构1.BlobClient2. BlobServer3. BlobCache4. LibraryCacheManager 二、BLOB的生命周期1. 分阶段清理2. BlobCache的生命周期3. BlobServer 三、文件上下载流程1. BlobCache 下载2. BlobServer 上传3. BlobServer 下载 四. Flink中支持的BLOB文件类型1…

uniapp流浪动物救助小程序Java宠物领养小程序springboot

uniapp流浪动物救助小程序Java宠物领养小程序springboot 代码40块&#xff0c;需要的私聊 前台基于uniapp小程序 后台管理基于springbootvue前后端分离项目 开发语言&#xff1a;Java 框架&#xff1a;springboot vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xf…

VTK 示例 基本的流程-事件交互、球体、

流程可以总结如下&#xff1a; 导入所需的头文件&#xff1a; 首先&#xff0c;导入了一系列 VTK 头文件&#xff0c;这些文件包含了所需的类和函数声明。 创建对象&#xff1a; 创建了两个球体&#xff08;一个较大&#xff0c;一个较小&#xff09;&#xff0c;一个平面&…

FANUC机器人KAREL语言程序结构(入门)

一、karel语言程序结构 FANUC机器人keral语言编程结构如下图所示&#xff1a; Keral指令对应的基础用法如下所示&#xff1a; 二、创建一个简单的写屏程序 依照对应的karel语法写写入下列程序 运行对应的程序进行测试&#xff1a;

南网科研院携手百度智能云,入选信通院AI原生应用优秀案例

为呈现AI原生研发和应用成效&#xff0c;提供AI原生相关技术、服务、部署、运营、基础设施等选型参考&#xff0c;近期&#xff0c;中国信息通信研究院发布了AI原生技术及应用优秀案例&#xff0c;由南方电网公司输配电部牵头、南方电网科学研究院有限责任公司&#xff08;以下…

Web安全攻防世界01 fileinclude(宜兴网信办)

<html> <head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /></head> //规定 HTML 文档的字符集<br /> <b>Notice</b>: Undefined index: language in <b>/var/www/html/index.ph…

Docket常见的软件部署1

1 安装MySQL # 查看MySQL镜像 docker search mysql # 拉起镜像 docker pull mysql:5.7 # 创建MySQL数据映射卷&#xff0c;防止数据不丢失 mkdir -p /hmoe/tem/docker/mysql/data/ # 启动镜像 docker run -d --name mysql -e MYSQL_ROOT_PASSWORD123456 -p 3306:3306 -v /home…

牛客NC79 丑数【中等 堆、优先级队列 Java,Go,PHP Go和PHP中我自己实现了优先级队列】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/6aa9e04fc3794f68acf8778237ba065b 思路 注意&#xff1a; 数据范围&#xff1a;0≤n≤2000&#xff0c; 2000肯定到不了&#xff0c;最多到1690&#xff0c;相同题目链接&#xff1a;https://www.lintcode.com…

Dockerfile:自定义镜像

Dockerfile 是一个文本文件&#xff0c;其中包含了一系列用于自动化构建Docker镜像的指令。通过编写Dockerfile&#xff0c;开发者能够明确地定义一个软件应用及其运行环境应该如何被封装进一个可移植、可重复构建的Docker镜像中。 第一步&#xff1a;在/tmp文件下新建docker…

hadoop 查询hdfs资源信息的方式

hdfs dfsadmin -report &#xff3b;-live&#xff3d;&#xff3b;-dead&#xff3d;&#xff3b;-decommissioning&#xff3d;

前缀和算法(1)

目录 一维前缀和[模板] 一、题目描述 二、思路解析 三、代码 二维前缀和[模板] 一、题目描述 二、思路解析 三、代码 724.寻找数组的中心下标 一、题目描述 二、思路解析 三、代码 238.除自身以外数组的乘积 一、题目描述 二、思路解析 三、代码 一维前缀和[模…

SQLynx发布3.0.0版本:带来更流畅便捷的SQL开发体验

作为新一代的一站式数据库管理开发工具&#xff0c; SQLynx自发布上线以来&#xff0c;一直受到广大用户的好评与鼓励。 为了给用户提供更高效、更便捷、更可靠的数据库管理开发体验&#xff0c;SQLynx今日正式发布3.0.0版本&#xff0c;同步在麦聪软件官网上线&#xff0c;全…

0DAY漏洞是什么,如何进行有效的防护

零日漏洞&#xff0c;指的是软件或系统中未被公开的、未被厂商知晓的安全漏洞。这些漏洞未被修复&#xff0c;因此黑客可以利用它们进行攻击&#xff0c;而受害者往往无法防范。由于这些漏洞的存在时间很短&#xff0c;因此称之为“零日漏洞”&#xff0c;也称为“0day漏洞”。…

VMware ESXi部署macOS Monterey

正文共&#xff1a;1024 字 30 图&#xff0c;预估阅读时间&#xff1a;2 分钟 最早使用黑苹果是在2015年&#xff0c;装在了古老的Acer商务本上&#xff08;老樹發新芽&#xff0c;acer tm 4750g裝黑蘋果&#xff09;&#xff1b;上次安装黑苹果是在两年前&#xff08;VMware…

淘宝详情数据采集(商品上货,数据分析,属性详情,价格监控),海量数据值得get

淘宝详情数据采集涉及多个环节&#xff0c;包括商品上货、数据分析、属性详情以及价格监控等。在采集这些数据时&#xff0c;尤其是面对海量数据时&#xff0c;需要采取有效的方法和技术来确保数据的准确性和完整性。以下是一些关于淘宝详情数据采集的建议&#xff1a; 请求示…