• 会议分享:用React+lingo3d开发一款游戏


    一. 基础准备

    • 开发语言选择react+lingo3d
    • 模型,动画,音效
      • 模型:Blender软件,模型素材网站:https://sketchfab.com/feed
      • 动画:https://www.mixamo.com/#/
      • 音效:https://sc.chinaz.com/tag_yinxiao/cf.html
    • 介绍Blender软件(创建物体,物体颜色(材质属性上),点光,摄像机)
    • lingo3d
      • 相机(第一人称相机,第三人称相机,轨道相机)轨道相机可以触摸屏或者鼠标点击交互
      •  
    • 新建一个demo开发测试
      • 使用vite创建 yarn create vite
      • 第三方依赖:lingo3d-react @1.2.77
      • 查找天空背景:google key words: equirectangular sky / skybox background
      •  <World>
              <OrbitCamera active enableZoom autoRotate />
              <Model src="house2.glb"></Model>
            </World>  、
      • 引入人物模型,https://sketchfab.com/feed,优点:全球最全的3的模型网站,并且所有的模型网站都是可以直接加载到网站上面展示出来的
    • demo1
        • //step1
              <World>
                <Cube width={9999} depth={9999} y={-100} color={'gray'}/>
                <Model/>
              </World>
          
          //step2
          function App() {
            const [position, setPosition] = useState({x:0,y:0,z:0})

            return (
              <World>
                <Cube
                  width={9999}
                  depth={9999}
                  y={-100}
                  color='gray'
                  onClick={
                    (e)=>{
                      setPosition({x:e.point.x,y:e.point.y,z:e.point.z})}
                  }
                />
                <Model
                  src='Idle.fbx'
                />
                <Cube
                  color="orange"
                  scale={0.2}
                  x={position.x}
                  y={position.y}
                  z={position.z}
                />
                <OrbitCamera active />
              </World>
            )
          }
           
    • demo2
        •   
          //step1 添加地图 第三人称相机 人物w移动
          function App() {
            const modelRef = useRef()
          
            return (
              <World>
                <Model
                  src="map/cybercity_2099_v2/scene.gltf"
                  physics="map"
                  scale={120}
                />
                <ThirdPersonCamera active mouseControl>
                  <Model 
                    src='Idle.fbx'
                    physics="character"
                    ref={modelRef}
                    intersectIDs={['orangeBox']}
                    onIntersect={()=>{
                      console.log(1)
                      setMove(false)
                    }}
                    animations={{idle:'Idle.fbx',running:'Running.fbx'}}
                    animation={"idle"}
                  />
                </ThirdPersonCamera>
                <Keyboard
                   onKeyPress={key => {
                    if (key === "w") {
                      modelRef.current?.moveForward(-10)
                    } else if (key === "Space"){
                      modelRef.current!.velocity.y = 5
                    } else if (key === "f"){
                      modelRef.current!.velocity.y = 5
                    }
                  }}
                />
          
                <Skybox texture='sky.jpg'/>
              </World>
            )
          }
          
          //step2  添加状态机 改变动作  @xstate/react  和 xstate  vscode插件xState 可视化,
          //stateMachines/postMachine

          import { createMachine } from "xstate";

          export default createMachine({
              states: {
                  "idle": {
                      on: {
                          KEY_W_DOWN: "running",
                          KEY_SPACE_DOWN: "jumping",
                          KEY_F_DOWN: "flying"
                      }
                  },
                  "running": {
                      on: {
                          KEY_W_UP: "idle",
                          KEY_SPACE_DOWN: "jumping",
                          KEY_F_DOWN: "flying"
                      }
                  },
                  "jumping": {
                      on: {
                          LANDED: "idle",
                          KEY_F_DOWN: "flying"
                      },
                      entry: "enterJumping"
                  },
                  "flying": {
                      on: {
                          LANDED: "idle"
                      },
                      entry: "enterFlying"
                  }
              },
              initial: "idle"
          })
           

          //app,tsx
            const [pose, sendPose] = useMachine(poseMachine)
                <Model
                    physics="character"
                    src="Idle.fbx"
                    animations={{
                      idle: 'Idle.fbx',
                      running: 'Running.fbx',
                      jumping: "Jumping.fbx",
                      flying: "Flying.fbx",
                    }}
                    animation={pose.value as any}
                  />
                <Keyboard
                  onKeyPress={key => {
                    if (key === "w") {
                      sendPose("KEY_W_DOWN")
                    } else if (key === "Space"){
                      sendPose("KEY_SPACE_DOWN")
                    } else if (key === "f"){
                      sendPose("KEY_F_DOWN")
                    }
                  }}
                  onKeyUp={key => {
                    if (key === "w")
                      sendPose("KEY_W_UP")
                  }}
                />



          //添加修改app.tsx 使用useMef()  bot.onLoop函数每秒执行60次
          
          
          import { useMachine } from '@xstate/react'
           const modelRef = useMef()
            const [pose, sendPose] = useMachine(poseMachine, {
              actions: {
                enterJumping: () => {
                  const bot = modelRef.current
                  if (bot === null) return

                  bot.velocity.y = 10

                  bot.onLoop = () => {
                    if (bot.velocity.y === 0) {
                      bot.onLoop = undefined
                      sendPose("LANDED")
                    }
                  }
                },
                enterFlying: () => {
                  const bot = modelRef.current
                  if (bot === null) return

                  bot.onLoop = () => {
                    if (bot.velocity.y === 0) {
                      bot.onLoop = undefined
                      sendPose("LANDED")
                    }
                  }
                }
              }
            })
           
                  <Model
                    physics="character"
                    ref={modelRef}
                    src="Idle.fbx"
                    animations={{
                      idle: 'Idle.fbx',
                      running: 'Running.fbx',
                      jumping: "Jumping.fbx",
                      flying: "Flying.fbx",
                    }}
                    animation={pose.value as any}
                  />
          
          
          
          
                
                <Keyboard
                  onKeyPress={key => {
                    if (key === "w") {
                      sendPose("KEY_W_DOWN")
                      modelRef.current?.moveForward(-10)
                    } else if (key === "Space"){
                      sendPose("KEY_SPACE_DOWN")
                    } else if (key === "f"){
                      sendPose("KEY_F_DOWN")
                      modelRef.current!.velocity.y = 2
                    }
                  }}
                  onKeyUp={key => {
                    if (key === "w")
                      sendPose("KEY_W_UP")
                  }}
                />
    • demo3 添加准星+添加汽车
    • //添加汽车
           <Model
              ref={carRef}
              physics="character"
              id="car"
              src="pixel_car/scene.gltf"
              scale={2}
              x={-2319.68}
              y={-3855.55}
              z={-10600.00}         
           />
      
      //添加准星
      <Reticle color="white" variant={7} />

      第三人称绑定
        const xSpring = useSpring({ to: camX, bounce: 0 })
        const ySpring = useSpring({ to: camY, bounce: 0 })
        const zSpring = useSpring({ to: camZ, bounce: 0 })
      //添加显示
            <Model
              ref={carRef}
              physics="character"
              id="car"
              src="pixel_car/scene.gltf"
              scale={2}
              x={-2319.68}
              y={-3855.55}
              z={-10600.00}
            >
              <Find
                name="GLTF_SceneRootNode"
              >
                <HTML>
                  <div style={{ color: "white" }}>
                    <div style={{ fontWeight: "bold", fontSize: 20 }} duration={1000}>
                      一款霸气的汽车
                    </div>
                    <div>
                      按G上下车
                    </div>
                  </div>
                </HTML>
              </Find>
            </Model>
      
      

    二. 正式开发

    • demo1 鼠标点击控制人物移动
    • import { useState,useRef } from 'react'
      import './App.css'
      import { World,Cube,Model, OrbitCamera, Skybox, useLoop } from 'lingo3d-react'
      
      function App() {
        const [position, setPosition] = useState({x:0,y:0,z:0})
        const [move, setMove] = useState(false)
        const modelRef = useRef()
      
        useLoop(()=>{
          const model = modelRef.current
          model.moveForward(-5)
        },move)
      
        return (
          <World>
            <Cube
              width={9999}
              depth={9999}
              y={-200}
              onClick={
                (e)=>{
                  setMove(true);
                  setPosition({x:e.point.x, y:0, z:e.point.z})
                  const model = modelRef.current
                  model.lookAt(e.point)
                }
              }
              />
            <Model
              ref={modelRef}
              src="Idle.fbx"
              animations={{idle:'Idle.fbx',running:'Running.fbx'}}
              animation={move?"running" : "idle"}
              intersectIDs={['orange']}
              onIntersect={()=>{ setMove(false)}}
            />
            <OrbitCamera active />
            <Cube scale={0.5} id="orange" color="orange" x={position.x} y={position.y} z={position.z}/>
      
            <Skybox texture="sky.jpg"/>
          </World>
        )
      }
      
      export default App
    • demo2 键盘+状态管理机(@xstate/react  和 xstate),键盘控制人物移动
    • import { useMachine } from '@xstate/react'
      import {  useRef } from 'react'
      import './App.css'
      import poseMachine from './stateMachines/postMachine'
      import { World, Cube, Model, OrbitCamera, Skybox, useLoop, Editor, FirstPersonCamera, ThirdPersonCamera, Keyboard } from 'lingo3d-react'
      
      function App() {
        const botRef = useRef()
      
        const [pose, sendPose] = useMachine(poseMachine, {
          actions: {
            enterJumping: () => {
              const bot = botRef.current
              if (bot === null) return
      
              bot.velocity.y = 10
      
              bot.onLoop = () => {
                if (bot.velocity.y === 0) {
                  bot.onLoop = undefined
                  sendPose("LANDED")
                }
              }
            },
            enterFlying: () => {
              const bot = botRef.current
              if (bot === null) return
      
              bot.onLoop = () => {
                if (bot.velocity.y === 0) {
                  bot.onLoop = undefined
                  sendPose("LANDED")
                }
              }
            }
          }
        })
      
        return (
          <World >
            <Model src="map/cybercity_2099_v2/scene.gltf" scale={120} physics="map" innerRotationY={180} />
            <ThirdPersonCamera active mouseControl>
              <Model
                physics="character"
                ref={botRef}
                src="Idle.fbx"
                animations={{
                  idle: 'Idle.fbx',
                  running: 'Running.fbx',
                  jumping: "Jumping.fbx",
                  flying: "Flying.fbx",
                }}
                animation={pose.value as any}
              />
            </ThirdPersonCamera >
      
      
            <Skybox texture="sky.jpg" />
            {/* <Editor/> */}
            <Keyboard
              onKeyPress={key => {
                if (key === "w") {
                  sendPose("KEY_W_DOWN")
                  botRef.current?.moveForward(-10)
                } else if (key === "Space"){
                  sendPose("KEY_SPACE_DOWN")
                } else if (key === "f"){
                  sendPose("KEY_F_DOWN")
                  botRef.current.velocity.y = 2
                }
              }}
              onKeyUp={key => {
                if (key === "w")
                  sendPose("KEY_W_UP")
              }}
            />
          </World>
        )
      }
      
      export default App
    • 状态机:
    • import { createMachine } from "xstate";
      
      export default createMachine({
          states: {
              "idle": {
                  on: {
                      KEY_W_DOWN: "running",
                      KEY_SPACE_DOWN: "jumping",
                      KEY_F_DOWN: "flying"
                  }
              },
              "running": {
                  on: {
                      KEY_W_UP: "idle",
                      KEY_SPACE_DOWN: "jumping",
                      KEY_F_DOWN: "flying"
                  }
              },
              "jumping": {
                  on: {
                      LANDED: "idle",
                      KEY_F_DOWN: "flying"
                  },
                  entry: "enterJumping"
              },
              "flying": {
                  on: {
                      LANDED: "idle"
                  },
                  entry: "enterFlying"
              }
          },
          initial: "idle"
      })
    • demo3 瞄准器+制作汽车彩蛋+场景优化(@lincode/react-anim-text)  useSpring(弹簧--)
    import { useMachine } from '@xstate/react'
    import { useRef, useState } from 'react'
    import './App.css'
    import poseMachine from './stateMachines/postMachine'
    import { World, Cube, HTML, Model, OrbitCamera, Skybox, useLoop, Editor, FirstPersonCamera, ThirdPersonCamera, Keyboard, Reticle, useSpring, Find } from 'lingo3d-react'
    import AnimText from "@lincode/react-anim-text"
    
    function App() {
      const botRef = useRef()
      const carRef = useRef()
      const [mouseOver, setMouseOver] = useState(false)
      const [driveCar, setDriveCar] = useState(false)
      const [intersectCar, setIntersectCar] = useState(false)
    
    
      const [pose, sendPose] = useMachine(poseMachine, {
        actions: {
          enterJumping: () => {
            const bot = botRef.current
            if (bot === null) return
    
            bot.velocity.y = 10
    
            bot.onLoop = () => {
              if (bot.velocity.y === 0) {
                bot.onLoop = undefined
                sendPose("LANDED")
              }
            }
          },
          enterFlying: () => {
            const bot = botRef.current
            if (bot === null) return
    
            bot.onLoop = () => {
              if (bot.velocity.y === 0) {
                bot.onLoop = undefined
                sendPose("LANDED")
              }
            }
          }
        }
      })
    
      const camX = mouseOver ? 25 : 0
      const camY = mouseOver ? 50 : 50
      const camZ = mouseOver ? 50 : 200
    
      const xSpring = useSpring({ to: camX, bounce: 0 })
      const ySpring = useSpring({ to: camY, bounce: 0 })
      const zSpring = useSpring({ to: camZ, bounce: 0 })
    
      return (
        <>
          <World >
            <Model src="map/cybercity_2099_v2/scene.gltf" scale={120} physics="map" innerRotationY={180} >
              {/* <Find
               name="Hovercars_Holograms_0"
               outline={mouseOver}
               onMouseOver={() => setMouseOver(true)}
               onMouseOut={() => setMouseOver(false)}
              >
                {mouseOver && (
                  <HTML>
                    <div style={{ color: "white" }}>
                      <AnimText style={{ fontWeight: "bold", fontSize: 20 }} duration={1000}>
                        可乐汉堡店铺
                      </AnimText>
                      <AnimText duration={1000}>
                        hamburger coca-cola
                      </AnimText>
                    </div>
                  </HTML>
                )}
              </Find> */}
            </Model>
            <ThirdPersonCamera
              active={!driveCar}
              mouseControl
              innerY={ySpring}
              innerZ={zSpring}
              innerX={xSpring}
            >
              <Model
                physics="character"
                ref={botRef}
                src="Idle.fbx"
                animations={{
                  idle: 'Idle.fbx',
                  running: 'Running.fbx',
                  jumping: "Jumping.fbx",
                  flying: "Flying.fbx",
                }}
                animation={pose.value as any}
                intersectIDs={["car"]}
                onIntersect={() => setIntersectCar(true)}
                onIntersectOut={() => setIntersectCar(false)}
              />
            </ThirdPersonCamera >
            <ThirdPersonCamera
              active={driveCar}
              mouseControl
              innerY={ySpring}
              innerZ={zSpring}
              innerX={xSpring}
            >
              <Model
                ref={carRef}
                physics="character"
                id="car"
                src="pixel_car/scene.gltf"
                scale={2}
                x={-2319.68}
                y={-3855.55}
                z={-10600.00}
              >
                <Find
                  name="GLTF_SceneRootNode"
                  outline={!driveCar && mouseOver}
                  onMouseOver={() => setMouseOver(true)}
                  onMouseOut={() => setMouseOver(false)}
                >
                  {!driveCar && mouseOver && (
                    <HTML>
                      <div style={{ color: "white" }}>
                        <AnimText style={{ fontWeight: "bold", fontSize: 20 }} duration={1000}>
                          一款霸气的汽车
                        </AnimText>
                        <AnimText duration={1000}>
                          按G上下车
                        </AnimText>
                      </div>
                    </HTML>
                  )}
                </Find>
              </Model>
            </ThirdPersonCamera >
            <Skybox texture="sky.jpg" />
            {/* <Editor/> */}
            <Keyboard
              onKeyPress={key => {
                console.log(key)
                if (driveCar) {
                  if (key === "w") {
                    carRef.current?.moveForward(-20)
                  }
                } else {
                  if (key === "w") {
                    sendPose("KEY_W_DOWN")
                    botRef.current?.moveForward(-10)
                  } else if (key === "Space") {
                    sendPose("KEY_SPACE_DOWN")
                  } else if (key === "f") {
                    sendPose("KEY_F_DOWN")
                    botRef.current.velocity.y = 2
                  }
                }
    
              }}
              onKeyUp={key => {
                if (key === "w") {
                  sendPose("KEY_W_UP")
                } else if (key === "g") {
                  if (driveCar) {
                    botRef.current!.x = carRef.current?.x
                    botRef.current!.y = carRef.current?.y
                    botRef.current!.z = carRef.current?.z
                    setDriveCar(false)
                  } else if (intersectCar) {
                    setDriveCar(true)
                  }
                }
              }}
            />
            {/* <Editor/> */}
    
          </World>
          {!driveCar && <Reticle color="white" variant={7} />}
        </>
      )
    }
    
    export default App


    3D模型下载网站:https://sketchfab.com/feed
    3D人物动作绑定:www.mixamo.com
    3D角色生产工具:https://readyplayer.me/
    模型压缩网站:gltf.report
    查找天空背景:google key words: equirectangular sky / skybox background
    材质贴图素材:https://www.textures.com
    hdr素材库(环境贴图): https://polyhaven.com
    二次元风3D角色生产软件VRoid Studio: https://vroid.com/en/studio

  • 相关阅读:
    APK Multi-Tool强大的APK反编译工具终极教程
    Android中Intent组件详解 .
    Android游戏开发之旅 View类详解
    深入理解Android中View
    SQLite学习手册(数据表和视图)
    转)sqlite 数据类型
    (转)SQLite内置函数
    Android权限Uri.parse的几种用法(转载)
    android中与SQLite数据库相关的类
    JDK核心包学习
  • 原文地址:https://www.cnblogs.com/kangxinzhi/p/16278613.html
Copyright © 2020-2023  润新知