vue3+threejs新手从零开发卡牌游戏(九):添加抽卡逻辑和动效

news2024/12/28 8:03:53

首先优化下之前的代码,把game/deck/p1.vue中修改卡组方法和渲染卡组文字方法提到公共方法中,此时utils/common.ts完整代码如下:


import { nextTick } from 'vue';
import * as THREE from 'three';
import * as TWEEN from '@tweenjs/tween.js'
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';

// 坐标归一化
const transPos = (x: any, y: any) => {
  let pointer = new THREE.Vector2()
  
  pointer.x = ( x / window.innerWidth ) * 2 - 1;
  pointer.y = - ( y / window.innerHeight ) * 2 + 1;

  return pointer
}
export { transPos }

// 修改卡组
const editDeckCard = (group:any, mesh: any, type: any) => {
  return new Promise((resolve, reject) => {
    let text = group.children.find((v: any) => v.name === "卡组数量")
    let shadowText = group.children.find((v: any) => v.name === "卡组数量阴影")
    // console.log(22, group.children, commonStore.$state.p1Deck)
    if (type === "remove") { // 删除卡组中的卡牌
      let child = group.children.find((v: any) => v.name === mesh.name)
      if (child) {
        group.remove(child)
      }
    }
    group.remove(text)
    group.remove(shadowText)
    group.children.forEach((v: any, i: any) => {
      v.position.set(0, 0.005 * i, 0)
    })
    resolve(true)
  })
}
export { editDeckCard }

// 渲染卡组文字
const renderText = (group: any, text: any, font: any, position: any) => {
  return new Promise((resolve, reject) => {
    const geometry = new TextGeometry( `${text}`, {
      font,
      size: 0.4,
      height: 0,
      curveSegments: 4,
      bevelEnabled: true,
      bevelThickness: 0,
      bevelSize: 0,
      bevelSegments: 0
    });
    geometry.center()
    const material = new THREE.MeshBasicMaterial({ 
      color: new THREE.Color("white"),
      alphaHash: true
    })
    const mesh = new THREE.Mesh( geometry, material ) ;
    mesh.position.set(position.x, position.y + 0.01, position.z)
    // mesh.position.set(0, 0.005 * commonStore.$state.p1Deck.length + 0.01, 0)
    mesh.rotateX(-90 * (Math.PI / 180)) // 弧度
    mesh.name = "卡组数量"
  
    // 阴影
    let shadowGeometry = geometry.clone()
    shadowGeometry.translate(0.02, 0.02, 0);
    let shadowMaterial = new THREE.MeshBasicMaterial({
      color: new THREE.Color("black"),
      alphaHash: true
    });
    let shadowMesh = new THREE.Mesh(shadowGeometry, shadowMaterial);
    shadowMesh.position.set(position.x, position.y, position.z)
    // shadowMesh.position.set(0, 0.005 * commonStore.$state.p1Deck.length, 0)
    shadowMesh.rotateX(-90 * (Math.PI / 180)) // 弧度
    shadowMesh.name = "卡组数量阴影"
  
    group.add(mesh)
    group.add(shadowMesh)

    resolve(true)
  })
}
export { renderText }

同步修改game/index.vue中对修改卡组方法的使用:


import { transPos, editDeckCard, renderText } from "@/utils/common.ts"

// 初始化手牌
const initHand = () => {
  let cardNumber = 4
  let _number = 0
  let 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 renderText(deckGroup, `${commonStore.$state.p1Deck.length}`, commonStore.$state._font, position)
      // 手牌区添加手牌
      handRef.value.addHandCard(obj, deckGroup)
    } else {
      clearInterval(_interval)
    }
    _number++
  }, 200)

}

之后我们思考下抽卡逻辑:
1.点击卡组,将卡组平移到页面中心位置(0, 0, 0)(y轴可以适当调高一点,这里点击事件只是为了测试抽卡,之后可以删掉)
2.然后卡组上展示“点击抽卡”的文字(文字用的是div+css的形式)

3.点击抽卡,执行抽卡动画

4.抽卡结束后,卡组移回到原位

首先我们在game/index.vue中添加点击事件,用raycaster射线进行鼠标拾取,当点击在卡组上时,执行onP1DeckEvent,这里由于是移动端所以只监听了touch事件,pc端则需要额外监听click事件:

// 鼠标按下
window.addEventListener('touchstart', onMousedown)

// 鼠标按下事件
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].pageX
  let clientY = ev.clientY || ev.changedTouches[0].pageY
  // pointer.x = ( clientX / window.innerWidth ) * 2 - 1;
  // pointer.y = - ( clientY / window.innerHeight ) * 2 + 1;

  let point = transPos(clientX, clientY) // 卡组起始位置的屏幕坐标

  // 通过摄像机和鼠标位置更新射线
  raycaster.setFromCamera( point, camera );

  // 点击卡组事件
  onP1DeckEvent()
}

// 点击卡组事件
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.position
  let 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)
  }
}

然后我们在src下新建一个抽卡组件:

这个组件其实是用div+css画了一个透明的蒙层,卡组移到中央后,展示蒙层和“点击抽卡”字样,然后卡组动画我们分为两步,第一步是卡组飞到页面中心,用户点击抽卡后,执行之前的修改卡组和添加手牌方法,然后隐藏蒙层,执行第二步卡组移回原文动画,components/DrawCard.vue完整代码如下:

<!-- 抽卡 -->
<template>
  <div v-if="state.visible" ref="maskRef" class="mask">
    <div class="box" @click="onDrawCard">
      <p>点击抽卡</p>
    </div>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref, onMounted, onBeforeUnmount, watch, defineComponent, getCurrentInstance, nextTick } from 'vue'
import { useCommonStore } from "@/stores/common.ts"
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
import { transPos, editDeckCard, renderText } from "@/utils/common.ts"

const props: any = defineProps({
  handRef: {},
  deckRef: {}
})

// 引入threejs变量
const {proxy} = getCurrentInstance()
const THREE = proxy['THREE']
const scene = proxy['scene']
const camera = proxy['camera']
const renderer = proxy['renderer']
const TWEEN = proxy['TWEEN']

const commonStore = useCommonStore()
const maskRef = ref()

const state = reactive({
  visible: false
})

// 卡组抽卡动画1-卡组移到页面中央
const drawCardAnimate1 = (deckGroup: any, startPos: any, endPos: any) => {
  // 隐藏卡组数量和卡组数量阴影几何体
  let textMesh = deckGroup.children.find((v: any) => v.name === "卡组数量")
  let textShadowMesh = deckGroup.children.find((v: any) => v.name === "卡组数量阴影")

  const tw = new TWEEN.Tween({
    x: startPos.x,
    y: startPos.y,
    z: startPos.z,
    opacity: 1.0,
    group: deckGroup
  })
  tw.to({
    x: endPos.x,
    y: endPos.y,
    z: endPos.z,
    opacity: 0.0,
  }, 200)
  tw.easing(TWEEN.Easing.Quadratic.Out)
  tw.onUpdate((obj: any) => {
    obj.group.position.set(obj.x, obj.y, obj.z)
    textMesh.material.opacity = obj.opacity
    textShadowMesh.material.opacity = obj.opacity
  })
  tw.onComplete(function() {
    state.visible = true
    TWEEN.remove(tw)
  })
  tw.start();
}

// 卡组抽卡动画2-卡组回到原位
const drawCardAnimate2 = (deckGroup: any, startPos: any, endPos: any) => {
  // 隐藏卡组数量和卡组数量阴影几何体
  let textMesh = deckGroup.children.find((v: any) => v.name === "卡组数量")
  let textShadowMesh = deckGroup.children.find((v: any) => v.name === "卡组数量阴影")
  // textMesh.material.opacity = 1
  // textShadowMesh.material.opacity = 1

  const tw = new TWEEN.Tween({
    x: startPos.x,
    y: startPos.y,
    z: startPos.z,
    opacity: 0,
    group: deckGroup
  })
  tw.to({
    x: endPos.x,
    y: endPos.y,
    z: endPos.z,
    opacity: 1,
  }, 200)
  tw.easing(TWEEN.Easing.Quadratic.Out)
  tw.onUpdate((obj: any) => {
    obj.group.position.set(obj.x, obj.y, obj.z)
    textMesh.material.opacity = obj.opacity
    textShadowMesh.material.opacity = obj.opacity
  })
  tw.onComplete(function() {
    TWEEN.remove(tw)
  })
  tw.start();
}

// 抽卡
const onDrawCard = async () => {
  let p1_deckGroup = scene.getObjectByName("p1_deckGroup")
  let p1Deck = JSON.parse(JSON.stringify(commonStore.$state.p1Deck))
  let position = new THREE.Vector3(0, 0.005 * p1Deck.length, 0)

  let obj = p1Deck[p1Deck.length - 1]
  p1Deck.splice(p1Deck.length-1, 1)
  commonStore.updateP1Deck(p1Deck)
  // 修改卡组
  await editDeckCard(p1_deckGroup, obj, "remove")
  await renderText(p1_deckGroup, `${commonStore.$state.p1Deck.length}`, commonStore.$state._font, position)
  // 手牌区添加手牌
  props.handRef.addHandCard(obj, p1_deckGroup)
  state.visible = false
  setTimeout(() => {
    nextTick(() => {
      drawCardAnimate2(p1_deckGroup, p1_deckGroup.position, p1_deckGroup.userData.position)
    })
  }, 500)
}


defineExpose({
  drawCardAnimate1,
  drawCardAnimate2
})
</script>

<style lang="scss" scoped>
.mask {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100vh;
  // background-color: white;
  .box {
    width: 50vh;
    // height: 100px;
    text-align: center;
    font-size: 20px;
    color: #fff;
  }
}
</style>

注意:由于点击事件会穿透蒙层,所以我们在onMousedown方法中添加了ev.target instanceof HTMLCanvasElement进行判断是否点击到了canvas上。

最后还优化了下卡组,给卡组添加了线框,game/deck/p1.vue完整代码如下:

<template>
  <div></div>
</template>

<script setup lang="ts">
import { reactive, ref, onMounted, onBeforeUnmount, watch, defineComponent, getCurrentInstance, nextTick } from 'vue'
import { useCommonStore } from "@/stores/common.ts"
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
import { Card } from "@/views/game/Card.ts"
import { CARD_DICT } from "@/utils/dict/card.ts"
import { transPos, renderText } from "@/utils/common.ts"

// 引入threejs变量
const {proxy} = getCurrentInstance()
const THREE = proxy['THREE']
const scene = proxy['scene']
const camera = proxy['camera']
const renderer = proxy['renderer']
const TWEEN = proxy['TWEEN']

const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();

const commonStore = useCommonStore()

// 卡组group
const deckGroup = new THREE.Group()
deckGroup.name = "p1_deckGroup"
scene.add(deckGroup)

const init = () => {
  setDeckPos()
  addDeckWireframe()
  commonStore.$state.p1Deck.forEach((v: any, i: any) => {
    let obj = CARD_DICT.find((b: any) => b.card_id === v.card_id)
    if (obj) {
      let card = new Card(obj)
      let mesh = card.init()
      mesh.position.set(0, 0.005 * i, 0)
      mesh.rotateX(180 * (Math.PI / 180)) // 弧度
      mesh.name = v.name
      deckGroup.add( mesh );
    }
  })

  let position = new THREE.Vector3(0, 0.005 * commonStore.$state.p1Deck.length, 0)
  renderText(deckGroup, `${commonStore.$state.p1Deck.length}`, commonStore.$state._font, position)

}

// 设置卡组位置
const setDeckPos = () => {
  nextTick(() => {
    let plane = scene.getObjectByName("地面")
    let point = transPos(window.innerWidth - 15, window.innerHeight - 15) // 卡组起始位置的屏幕坐标
    // 
    raycaster.setFromCamera( point, camera );
    const intersects1 = raycaster.intersectObject( plane );
    if (intersects1.length > 0) {
      let point = intersects1[0].point
      // deckGroup.position.set(point.x, point.y, point.z)
      deckGroup.position.set(point.x - 0.5, point.y, point.z - 0.7)
      // 记录卡组位置
      let position = new THREE.Vector3(point.x - 0.5, point.y, point.z - 0.7)
      deckGroup.userData["position"] = position
    }
  })
}

// 绘制卡组区域线框
const addDeckWireframe = () => {
  nextTick(() => {
    const edges = new THREE.EdgesGeometry( deckGroup.children[0].geometry );
    const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0xffffff } ) );
    deckGroup.add(line);
  })
}

defineExpose({
  init,
})
</script>

<style lang="scss" scoped>
</style>

最后看下抽卡效果:

至此基本完成了抽卡逻辑和简单动效的开发。

附录:

game/index.vue完整代码如下:

<template>
  <div ref="sceneRef" class="scene"></div>
  <!-- 手牌 -->
  <Hand ref="handRef"/>
  <!-- 卡组 -->
  <Deck ref="deckRef"/>
  <!-- 抽卡逻辑 -->
  <DrawCard ref="drawCardRef" :handRef="handRef" :deckRef="deckRef"/>
</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 { FontLoader } from 'three/addons/loaders/FontLoader.js';
import { useCommonStore } from "@/stores/common.ts"
import { transPos, editDeckCard, renderText } from "@/utils/common.ts"
import { Card } from "./Card.ts"
import { CARD_DICT } from "@/utils/dict/card.ts"
import Hand from "./hand/index.vue"
import Deck from "./deck/index.vue"
import DrawCard from "@/components/DrawCard.vue"

// 引入threejs变量
const {proxy} = getCurrentInstance()
const THREE = proxy['THREE']
const scene = proxy['scene']
const camera = proxy['camera']
const renderer = proxy['renderer']
const TWEEN = proxy['TWEEN']

const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();

const commonStore = useCommonStore()

// 场景ref
const sceneRef = ref()
const handRef = ref()
const deckRef = ref()
const drawCardRef = ref()

// 坐标轴辅助
const axesHelper = new THREE.AxesHelper(5);
// 创建轨道控制器
// const controls = new OrbitControls( camera, renderer.domElement );
// 字体加载器
const fontLoader = new FontLoader();

onMounted(async () => {
  await initResource()
  initScene()
  initGame()

  // 鼠标按下
  window.addEventListener('touchstart', onMousedown)
  // window.addEventListener('click', onMousedown)

  // 监听浏览器窗口变化进行场景自适应
  window.addEventListener('resize', onWindowResize, false);
})

// 资源加载
const initResource = () => {
  // 字体加载
  return new Promise((resolve, reject) => {
    fontLoader.load('fonts/helvetiker_regular.typeface.json', (font: any) => {
      commonStore.loadFont(font)
      resolve(true)
    });
  })
}

// 初始化场景
const initScene = () => {
  renderer.setSize( window.innerWidth, window.innerHeight );
  sceneRef.value.appendChild( renderer.domElement );
  scene.add(axesHelper)

  // camera.position.set( 5, 5, 5 );
  camera.position.set( 0, 6.5, 0 );
  camera.lookAt(0, 0, 0)

  addPlane()

  animate();
}

// 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进行渲染循环
const animate = () => {
  requestAnimationFrame( animate );
  TWEEN.update()
  renderer.render( scene, camera );
}

// 场景跟随浏览器窗口大小自适应
const onWindowResize = () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

// 初始化游戏
const initGame = async () => {
  // 初始化卡组
  await initDeck()
  // 初始化手牌
  initHand()
}

// 初始化卡组
const initDeck = () => {
  return new Promise((resolve, reject) => {
    let p1Deck = [
      "YZ-01",
      "YZ-02",
      "YZ-03",
      "YZ-04",
      "YZ-01",
      "YZ-02",
      // "YZ-03",
      // "YZ-04",
      // "YZ-01",
      // "YZ-02",
      // "YZ-03",
      // "YZ-04",
    ]
    // 洗牌
    p1Deck.sort(() => {
      return Math.random() - 0.5
    })
    let newDeck: any = []
    p1Deck.forEach((v: any, i: any) => {
      let obj = CARD_DICT.find((b: any) => b.card_id === v)
      if (obj) {
        newDeck.push({
          card_id: v,
          name: `${obj.name}_${i}`
        })
      }
    })
    // console.log("p1Deck", newDeck)
    commonStore.updateP1Deck(newDeck)
    
    nextTick(() => {
      handRef.value.init()
      deckRef.value.init()
      resolve(true)
    })
  })
}

// 初始化手牌
const initHand = () => {
  let cardNumber = 4
  let _number = 0
  let 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 renderText(deckGroup, `${commonStore.$state.p1Deck.length}`, commonStore.$state._font, position)
      // 手牌区添加手牌
      handRef.value.addHandCard(obj, deckGroup)
    } else {
      clearInterval(_interval)
    }
    _number++
  }, 200)

}

// 鼠标按下事件
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].pageX
  let clientY = ev.clientY || ev.changedTouches[0].pageY
  // pointer.x = ( clientX / window.innerWidth ) * 2 - 1;
  // pointer.y = - ( clientY / window.innerHeight ) * 2 + 1;

  let point = transPos(clientX, clientY) // 卡组起始位置的屏幕坐标

  // 通过摄像机和鼠标位置更新射线
  raycaster.setFromCamera( point, camera );

  // 点击卡组事件
  onP1DeckEvent()
}

// 点击卡组事件
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.position
  let 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)
  }
}
</script>

<style lang="scss" scoped>
.scene {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
}
</style>

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

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

相关文章

数据库基础篇-------语法结构

友友们&#xff0c;大家好&#xff0c;今天我们来回顾我们的数据库啦&#xff0c;数据库技术是在我们大一就进行了解的&#xff0c;但是在大二的时候有的学校会进行数据库开发技术的教学&#xff0c;这两本书是不一样的&#xff0c;数据库基础更加偏向于对应的基础语法结构&…

计算方法实验2:列主元消元法和Gauss-Seidel迭代法解线性方程组

Task 即已知 y 0 0 , y 100 1 y_00,y_{100}1 y0​0,y100​1&#xff0c;解线性方程组 A y b \mathbf{A}\mathbf{y} \mathbf{b} Ayb&#xff0c;其中 A 99 99 [ − ( 2 ϵ h ) ϵ h 0 ⋯ 0 ϵ − ( 2 ϵ h ) ϵ h ⋯ 0 0 ϵ − ( 2 ϵ h ) ⋯ 0 ⋮ ⋮ ⋱ ⋱ ⋮ 0 0 ⋯…

数学建模综合评价模型与决策方法

评价方法主要分为两类&#xff0c;其主要区别在确定权重的方法上 一类是主观赋权法&#xff0c;多次采取综合资讯评分确定权重&#xff0c;如综合指数法&#xff0c;模糊综合评判法&#xff0c;层次评判法&#xff0c;功效系数法等 另一类是客观赋权法&#xff0c;根据各指标…

(C语言)浮点数在内存中的存储详解

1. 浮点数 常见的浮点数&#xff1a;3.14159、 1E10等 &#xff0c;浮点数家族包括&#xff1a; float、double、long double 类型。 浮点数表示的范围&#xff1a; float.h 中定义. 2. 浮点数的存储 我们先来看一串代码&#xff1a; int main() {int n 9;float* pFloa…

高中信息技术教资刷题笔记_大题篇

1.选择排序 2. SMTP属于TCP/IP协议体系结构中的哪一层&#xff1f;请列出其通信的三个阶段。 3.高中信息技术课程的基本理念/意义 4.视频作品制作和发布的主要环节 5.信息社会责任内涵及学生表现 6.教学活动意图 ①突出学生的主体地位。材料中&#xff0c;王老师设计的“扮演谍…

关系型数据库mysql(4)事务

目录 一.事务的概念 1.事务的定义 2.事务的特点 2.1原子性 2.2一致性 2.4持久性 3.事务之间的相互影响 3.1脏读 3.2不可重复读 3.3幻读 3.4丢失更新 4. 事务的隔离级别&#xff08;如何解决事务的干扰&#xff09; 4.1查询全局事务隔离级别 4.2查询全局事务 …

【零基础C语言】联合体(共用体)和枚举

目录 自定义类型&#xff1a;联合体(共用体)和枚举 1.自定义类型&#xff1a;联合体(共用体) 1.1 联合体的声明 1.2 联合体的特点 ​编辑1.3 联合体的大小计算 1.4使⽤联合体是可以节省空间的 1.5使用联合体写一个程序判断机器是大端还是小端存储 2.自定义类型&#xff1a;…

详解|temu选品师是什么?算蓝海项目吗?

在快速发展的跨境电商行业中&#xff0c;temu选品师这一岗位逐渐受到人们的关注。temu作为拼多多旗下的跨境电商平台&#xff0c;致力于为中国商家提供一个通向全球市场的桥梁。而temu选品师&#xff0c;则是这个桥梁上不可或缺的角色。 temu选品师主要负责在海量商品中挑选出具…

探索Zalo:从社交APP到Mini App开发指南

1.Zalo是什么&#xff1f; Zalo是一款源自越南的即时通讯和社交软件&#xff08;相当于国内的微信&#xff09;&#xff0c;由越南VNG公司开发。它集成了多种功能&#xff0c;包括但不限于免费的文字、语音、视频消息发送&#xff0c;高质量的语音和视频通话&#xff0c;群聊功…

电子电器架构 —— 诊断数据DTC具体故障篇

电子电器架构 —— 诊断数据DTC起始篇 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师 (Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,喝完再挣扎…

批量重命名文件名,批量管理文件,复制后轻松删除原文件

在现代工作中&#xff0c;我们经常需要处理大量的文件&#xff0c;无论是工作文档、图片还是视频资料。对于很多人来说&#xff0c;文件管理是一项繁琐且耗时的任务。不过&#xff0c;现在有一种高效的文件管理方法&#xff0c;可以帮助你轻松复制文件后删除原文件夹&#xff0…

Redis入门到实战-第四弹

Redis实战热身Strings 篇 完整命令参考官网 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://redis.io/Redis概述 Redis是一个开源的&#xff08;采用BSD许可证&#xff09;&#xff0c;用作数据库、缓存、消息代理…

鸿蒙开发学习【地图位置服务组件】

简介 移动终端设备已经深入人们日常生活的方方面面&#xff0c;如查看所在城市的天气、新闻轶事、出行打车、旅行导航、运动记录。这些习以为常的活动&#xff0c;都离不开定位用户终端设备的位置。 当用户处于这些丰富的使用场景中时&#xff0c;系统的位置定位能力可以提供…

解析服务器出现大量 TIME_WAIT 和 CLOSE_WAIT 状态的原因及排查方法

服务器出现大量 TIME_WAIT 状态的原因有哪些&#xff1f; 首先要知道 TIME_WAIT 状态是主动关闭连接方才会出现的状态&#xff08;别陷入一个误区不是只有客户端才能主动关闭连接的&#xff09;&#xff0c;所以如果服务器出现大量的 TIME_WAIT 状态的 TCP 连接&#xff0c;就是…

分布式组件 Nacos

1.在之前的文章写过的就不用重复写。 写一些没有写过的新东西 2.细节 2.1命名空间 &#xff1a; 配置隔离 默认&#xff1a; public &#xff08;默认命名空间&#xff09;:默认新增所有的配置都在public空间下 2.1.1 开发 、测试 、生产&#xff1a;有不同的配置文件 比如…

关于mysql无法添加中文数据的问题以及解决方案

往数据库表插入语句时&#xff0c;插入中文字段&#xff0c;中文直接变成&#xff1f;的问题&#xff0c; 出现这样的问题就是在创建数据库时 数据库字符集 没有选择uft8, 数据库校对规则没有选择utf8-bin 用 SHOW CREATE DATABASE 数据名; 可以查看你的这个数据库的定义…

设计模式之状态模式(一)

设计模式专栏&#xff1a; http://t.csdnimg.cn/4Mt4u 目录 1.概述 2.结构 3.实现 4.总结 1.概述 状态模式( State Pattern)也称为状态机模式( State Machine pattern), 是允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类, 属于行为型模式。 在状…

<商务世界>《第16课 餐桌礼仪之座次》

1 简要 我国自古以来就很重视座位礼仪&#xff0c;非讲究&#xff0c;分君臣、分宾主、分方位等等而今座位礼仪已经简化为&#xff1a; 以“中”为尊&#xff1a; 中心为尊&#xff0c;突出主位。 以“右”为尊&#xff1a; 从历史上到国际上都是以右为尊。 以“内”为尊&…

算法导论第十四章练习参考答案(26) - 14.1-14.3

Exercise 14.1-1 呼叫顺序为: OS−SELECT(T.root,10) OS−SELECT(T.root.left&#xff0c;10) OS−SELECT(T.root.left.right&#xff0c;2) OS−SELECT(T.root.left.right.left&#xff0c;2) OS−SELECT(T.root.left.right.left.right&#xff0c;1) 然后&#xff0c;我们得到…

UKP3d的协同设计相关问题

用户在用UKP3d多人协同设计&#xff0c;反映以前保存的内容为什么没有呢&#xff1f; 经查&#xff0c;协同设计的某一用户并没有打开协同去用。如A,B两人协同设计&#xff0c;B并不是用“打开—协同项目”&#xff0c;而是用“打开—项目”&#xff0c;当B保存项目的时候&…