대포 물리학 - 3D web3 시리즈
3D-web3 시리즈의 3번째 글입니다.
1 -
2 -
3 - 3D 웹 - 대포 물리학
4 -
"Cannon" 간단한 충돌 감지, 다양한 바디 모양, 접촉, 마찰 및 제약 조건을 포함하는 강체 물리 엔진입니다.
npm i @react-three/cannon
작동시키는 간단한 단계:
1_ 물리 세계 가져오기 및 만들기
import { Physics, useBox, ... } from '@react-three/cannon'
<Physics>{/* Physics related objects in here please */}</Physics>
2_ 물체 접촉면에 맞는 모양을 선택하세요. 상자, 평면, 구 등이 될 수 있습니다. 질량도 지정하세요.
const [ref, api] = useBox(() => ({ mass: 1 }))
3_ 객체를 선택하세요. 메쉬, 라인, gltf 등 무엇이든 될 수 있으며 방금 받은 참조에 연결합니다. 이제 물리 세계 내부의 중력 및 기타 물체의 영향을 받습니다.
<mesh ref={ref} geometry={...} material={...} />
4_ 위치, 회전, 속도, 힘 및 충격을 적용할 수 있는 API를 사용하여 상호 작용할 수 있습니다.
useFrame(({ clock }) => api.position.set(Math.sin(clock.getElapsedTime()) * 5, 0, 0))
5_ 바디 API를 사용하여 속성을 구독하여 각 프레임에서 업데이트를 받을 수 있습니다.
const velocity = useRef([0, 0, 0])
useEffect(() => {
const unsubscribe = api.velocity.subscribe((v) => (velocity.current = v))
return unsubscribe
}, [])
"Box.jsx"구성 요소의 모든 단계는 다음과 같습니다.
import { Physics, useBox } from '@react-three/cannon'
import { useFrame } from '@react-three/fiber';
const Box = () => {
const [ref, api] = useBox(() => ({ mass: 1 }))
useFrame(({ clock }) => api.position.set(Math.sin(clock.getElapsedTime()) * 5, 0, 0))
const velocity = useRef([0, 0, 0])
useEffect(() => {
const unsubscribe = api.velocity.subscribe((v) => (velocity.current = v))
return unsubscribe
}, [])
return (
<Physics>
<mesh ref={ref}>
<boxGeometry attach='geometry' args={[1, 1, 1]} />
<meshStandardMaterial attach="material" color={'#000'} />
</mesh>
</Physics>
)
}
export default Box
이 패키지를 저장소에 적용해 봅시다.
앱 로직__
First check previous post if you haven't, to understand why we are not using in code-sand-box our gltf model
Instead, we are using a "yellow box" with an onClick method to change between two "camera modes"
필요한 다른 3개 구성 요소의 부모가 될 "ActivateSpawner"구성 요소를 포함합니다.
카메라 RIG 모드에서 활성화하는 onClick 메서드가 있는 "블랙 박스"를 볼 수 있습니다.
a) "생성기"구성 요소: "y"속도로 "x"개의 거품을 생성합니다. "Spawner"에는 "Bubble"구성 요소가 자식으로 있습니다.
b) "PlayerBox"구성 요소: 당신의 움직임을 모방하고 거품이 생기는 것을 피해야 합니다.
두 구성 요소 모두 콜라이더 속성이 있습니다. 따라서 "PlayerBox"가 "Bubble"구성 요소와 충돌하면 게임이 중지됩니다.
우리는 다음을 사용할 것입니다(이전 튜토리얼 "개체/후크"는 포함되지 않음):
Step_1 "ActivateSpawner"컴포넌트 생성
상자에 0의 "질량"을 제공하고 있습니다.
import React from 'react'
import { useBox } from '@react-three/cannon';
import { useState } from 'react';
import Spawner from './Spawner';
import PlayerBox from './PlayerBox';
const ActivateSpawner = () => {
const [play, setPlay] = useState(false);
// This box is used to start the game
const [ref] = useBox(() => ({
mass: 0,
position: [-5, 2, -10],
type: 'Dynamic',
args: [1, 1, 1],
}));
return (
<group>
<mesh
ref={ref}
onClick={() => {
console.log(!play)
setPlay(!play)
}}
>
<boxGeometry attach='geometry' args={[1, 1, 1]} />
<meshStandardMaterial attach="material" color={'#000'} />
</mesh>
{play && (<>
<Spawner />
<PlayerBox setPlay={setPlay} />
</>
)}
</group>
)
}
export default ActivateSpawner
Step_2 "Spawner"컴포넌트 생성
for 루프와 "randomIntBetween(a,b)"& randomIntBetweenAlsoNegatives(a,b) 함수를 사용하여 각 "버블"에 대한 임의 데이터(위치, 지연, 색상) 가져오기
import { Vector3 } from 'three';
import Bubble from './Bubble';
const Spawner = () => {
function randomIntBetween(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min)
}
function randomIntBetweenAlsoNegatives(min, max) { // min and max included
const math = Math.floor(Math.random() * (max - min + 1) + min)
const random = Math.random()
const zeroOrOne = Math.round(random)
if (zeroOrOne) return -(math)
return math
}
const attackersArray = [];
for (let i = 0; i < 20; i++) {
let position = new Vector3(
randomIntBetweenAlsoNegatives(0, 2),
randomIntBetweenAlsoNegatives(0, 2),
0)
let wait = randomIntBetween(1, 12) * 10
let color = `#${Math.random().toString(16).substring(2, 8)}`
const att = [position, wait, color]
attackersArray.push(att)
}
return (
<group>
{attackersArray.map((attackers, key) => {
return <Bubble
key={key}
pos={attackers[0]}
wait={attackers[1]}
color={attackers[2]}
/>
})}
</group>
);
};
export default Spawner;
Step_3 "PlayerBox"컴포넌트 생성
캔버스 "카메라"개체에 대한 참조를 생성하려면 '@react-three/fiber'의 "useThree"후크를 사용하세요. 이제 "useFrame"후크를 사용하여 "PlayerBox"에 동일한 값을 제공할 수 있습니다.
This hook calls you back every frame, which is good for running effects, updating controls, etc.
"Box"에 "collisionFilterGroup"및 "collisionFilterMask"속성을 추가합니다.
첫 번째는 그것이 속한 그룹을 정의하고 두 번째는 충돌할 수 있는 그룹을 정의합니다.
import { useBox, } from '@react-three/cannon';
import { useFrame } from '@react-three/fiber';
import { useThree } from '@react-three/fiber'
const PlayerBox = (props) => {
const { camera } = useThree()
const [ref, api] = useBox(() => ({
mass: 0,
type: 'Dynamic',
position: [0, 0, -5],
args: [0.3, 0.3, 0.1], // collision box size
collisionFilterGroup: 1,
// 1 PlayerBox 2 Objetive 3 BulletBox 4 Attackers
collisionFilterMask: 4,
onCollide: (e) => {
props.setPlay(false);
console.log('game over')
},
}));
// Tambien simula el movimiento de la camara (y por lo tnato el del objetivo), para poder tener un collider para el game over
useFrame(() => {
api.position.set(camera.position.x, camera.position.y, -2);
});
return (
<>
<mesh ref={ref}>
<boxBufferGeometry attach='geometry' args={[0.1, 0.1, 0.1]} /> {/* box size */}
<meshStandardMaterial attach="material" color={'#000'} />
</mesh>
</>
);
};
export default PlayerBox;
Step_4 "버블"컴포넌트 생성
동일한 "bubble"개체를 사용하여 동일한 경주를 "x"번 실행하려면 "setTimeout"함수를 추가하여 for 루프 내부의 거품 위치를 재설정합니다.
import { useSphere } from '@react-three/cannon';
import { useFrame } from '@react-three/fiber';
const Bubble = (props) => {
let zMovement = -20;
const [ref, api] = useSphere(() => ({
mass: 0,
position: [props.pos.x, props.pos.y, props.pos.z - 200],
type: 'Dynamic',
// args: [1, 1, 1],
// 1 PlayerBox 2 Objetive 3 BulletBox 4 Bubble
collisionFilterGroup: 4,
// No te va a colisionar, sino que vas a colisionar contra el
collisionFilterMask: 1,
}));
useFrame(() => {
api.position.set(
props.pos.x,
props.pos.y,
(zMovement += 0.1) - props.wait
);
});
for (let i = 1; i < 3; i++) {
window.setTimeout(() => {
zMovement = -50;
api.position.set(0, 0, -zMovement);
// 6 segs * i * wait= posicion de cada cubo para hacer que algunos salgan antes que otros
}, 6 * 1000 + props.wait * 100);
}
return (
<mesh ref={ref}>
<sphereGeometry attach='geometry' args={[1, 32, 32]} />
<meshStandardMaterial attach="material" color={props.color} />
</mesh>
);
};
export default Bubble;
Step_5 "@react-three/cannon"에서 가져온 "physics"노드를 사용하여 App.jsx에 "ActivateSpawner"를 추가합니다.
우리가 정의한 모든 구성 요소는 다음과 같은 경우 DOM에서 렌더링됩니다.
cameraMode가 false => 카메라 RIG 모드가 설정됨
import { Canvas } from '@react-three/fiber';
import ActivateSpawner from './geometry/ActivateSpawner';
...
return (
...
{!cameraMode &&
< Physics >
<ActivateSpawner />
</Physics>
}
...
)
구성 요소 재개: ActivateSpawner , Spawner, PlayerBox, Bubble
Web3는 다음 게시물에 추가됩니다.
도움이 되었기를 바랍니다.
Reference
이 문제에 관하여(대포 물리학 - 3D web3 시리즈), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/uigla/3d-web-cannon-physics-web3-serie-24jh텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)