当前位置:网站首页>Play Parkour with threejs Technology
Play Parkour with threejs Technology
2022-07-29 08:24:00 【Bean bag 3D world】
Create a canvas , The camera
container = document.getElementById('threejs')
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 300000 )
camera.position.set( 0, 150, 400 )
scene = new THREE.Scene()
// Set canvas background transparency
scene.background = null
Create lights
const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444 )
hemiLight.position.set( 0, 200, 0 )
scene.add( hemiLight )
# new THREE.HemisphereLight You can create outdoor lighting effects that are closer to nature
# color: The color of the light from the sky
# groundColor: The color of the light emitted from the ground
# intensity: The intensity of the light source . The default value is :1.
# position: The position of the light source in the scene . The default value is :(0, 100, 0)
# visible: Set to ture( The default value is ), The light will turn on . Set to false, The light will turn off .
const dirLight = new THREE.DirectionalLight( 0xffffff )
dirLight.position.set( 0, 200, 100 )
// dirLight.castShadow = true
dirLight.shadow.camera.top = 180
dirLight.shadow.camera.bottom = - 100
dirLight.shadow.camera.left = - 120
dirLight.shadow.camera.right = 120
scene.add( dirLight )
/** new THREE.DirectionalLight Parallel light The whole area illuminated by the directional light receives the same light intensity . The light is parallel directionalLight.shadow.camera.near = 20; // The closest distance to produce shadows directionalLight.shadow.camera.far = 200; // The farthest distance to produce shadows directionalLight.shadow.camera.left = -50; // The leftmost position where the shadow is generated directionalLight.shadow.camera.right = 50; // Far right directionalLight.shadow.camera.top = 50; // At the top directionalLight.shadow.camera.bottom = -50; // At the bottom // These two values determine how many pixels are used to generate shadows Default 512 directionalLight.shadow.mapSize.height = 1024; directionalLight.shadow.mapSize.width = 1024; */
Create materials and floors
floor = new THREE.MeshPhongMaterial( {
color: '#ffffff'
} )
/** THREE.MeshPhongMaterial, You can create a shiny material It can simulate glossy surfaces with specular highlights ( Paint wood as above ) ambient This is the ambient color of the material . It is used with the ambient light source mentioned in the previous chapter . This color will be multiplied by the color provided by the ambient light . The default is white emissive This is the color emitted by the material . It doesn't really want a light source , Just a pure 、 Color unaffected by other light . The default value is black . specular This attribute specifies the brightness of the material and the color of the highlights . If it is set to be the same as color Attribute the same color , You will get a material more similar to metal . If you set it to gray (grey), The material will become more plastic shininess This attribute specifies the brightness of the specular highlights . The default value is 30 metal If this property is set to true,Three.js The color of pixels will be calculated in a slightly different way , To make the object look more like metal . It should be noted that , This effect is very small wrapAround If this property is set to true, Then start half lambert Lighting technology . With it , Light drops more subtly . If the mesh is rough 、 Dark areas , Turning on this attribute will soften the shadows and distribute them more evenly wrapRGB When wrapAround Property is set to true when , have access to THREE.Vector3 To control the speed of light falling */
const loaderImage = new THREE.TextureLoader()
/** loader Image resources */
loaderImage.load(paodaoPng, (texture) => {
texture.wrapS = THREE.RepeatWrapping
texture.wrapT = THREE.RepeatWrapping
texture.repeat.set(1, 15)
floor.map = texture
floorMesh = new THREE.Mesh( new THREE.PlaneGeometry( 150, 21000 ), floor )
floorMesh.rotation.x = - Math.PI / 2
floorMesh.receiveShadow = true
scene.add( floorMesh )
},
(xhr) => {
// console.log( (xhr.loaded / xhr.total * 100) + '% loaded' )
},
(error) => {
console.log( 'error' )
},
)
/** PlaneGeometry It is two-dimensional plane geometry , It looks flat , Because it has only two dimensions , Given width and height , You can create this geometry PlaneGeometry(width : Float, height : Float, widthSegments : Integer, heightSegments : Integer) width: Along X Width of axis , The default value is 1 height: Along Y The height of the shaft , The default is 1 widthSegments : Number of width segments , The default is 1 heightSegments: Number of height segments , The default is 1 */
Create left and right ground
const loaderImageLeftRight = new THREE.TextureLoader()
loaderImageLeftRight.load(`${
hrefs.value}${
dir.value}/a.png`, (texture2) => {
texture2.wrapS = THREE.RepeatWrapping
texture2.wrapT = THREE.RepeatWrapping
texture2.repeat.set(10, 20)
floor2.map = texture2
floorMesh2 = new THREE.Mesh( new THREE.PlaneGeometry( 1100, 20000), floor2 )
floorMesh2.rotation.x = - Math.PI / 2
floorMesh2.position.x = -626
floorMesh2.name = 'floorMesh2'
floorMesh3 = new THREE.Mesh( new THREE.PlaneGeometry( 1100, 20000), floor2 )
floorMesh3.rotation.x = - Math.PI / 2
// floorMesh2.rotation.y = - Math.PI / 1
floorMesh3.position.x = 628
floorMesh3.name = 'floorMesh3'
scene.add( floorMesh2, floorMesh3)
}, (xhr) => {
console.log( (xhr.loaded / xhr.total * 100) + '% loaded' )
}, (error) => {
console.log('error')
})
Create street lights
importGltfLoader('Light.gltf', `${
hrefs.value}${
dir.value}/d`, 'Light')
const importGltfLoader = (gltfurl: string, setPath: string, type?: string) => {
let gltfLoader = new GLTFLoader()
gltfLoader.setPath(setPath)
gltfLoader.load(gltfurl, (gltf) => {
if (gltf) {
if (gltf.scene && gltf.scene.children && gltf.scene.children.length > 0) {
if (type === 'light') {
gltf.scene.children.map((item) => {
// item.scale.setScalar(200000000000)
// item.position.set(0, 0, 0)
})
gltf.scene.scale.setScalar(0.9)
gltf.scene.name = 'dcw-glob'
gltf.scene.position.y = 0
gltf.scene.position.x = 0
gltf.scene.position.z = -300
a = gltf.scene.clone()
}
}
}, (xhr) => {
// called while loading is progressing
// console.log(`${(xhr.loaded / xhr.total * 100)}% loaded`)
},
(error) => {
// called when loading has errors
// console.error('An error happened', error)
})
}
// new GLTFLoader() loading Street lamp model
Create a business logo Model Building models
const importObj = () => {
let mtlLoader = new MTLLoader()
mtlLoader.setPath(`${
hrefs.value}${
dir.value}b/`)
// load mtl file
mtlLoader.load('city.mtl', function (material) {
let objLoader = new OBJLoader()
// Sets the currently loaded texture
objLoader.setMaterials(material)
objLoader.setPath(`${
hrefs.value}${
dir.value}/b`)
objLoader.load('a.obj', function (object) {
if (object.children && object.children.length > 0) {
for(let i=0; i< object.children.length; i++) {
if(i === 2) {
cityMesh = object.children[185].clone()
cityMesh.name = 'city-dcw'
}
if(i === 1) {
cityMesh2 = object.children[185].clone()
cityMesh.name = 'city-dcw'
}
}
// let scale = new colorsFn().chroma.scale(['yellow', '008ae5'])
// let color = scale(Math.random()).hex()
cityMesh.position.set(-1682, -2, -2000)
cityMesh.scale.setScalar(8.8)
cityMesh.material.map((item) => {
item.color = new THREE.Color('#1890ff')
item.transparent = true
item.opacity = 0.6
})
cityMesh2.position.set(-2400, -2, -4500)
cityMesh2.scale.setScalar(8.8)
// cityMesh2.material.color = new THREE.Color('yellow')
cityMesh2.material.transparent = true
cityMesh2.material.opacity = 0.7
cityGroup.add(cityMesh, cityMesh2)
let image = new THREE.TextureLoader()
image.load(`${
hrefs.value}${
dir.value}/static/logo/b.png`, (img) => {
img.wrapS = THREE.RepeatWrapping
img.wrapT = THREE.RepeatWrapping
img.matrixAutoUpdate = false
// img.repeat.set(1, 1)
let imgM = new THREE.MeshBasicMaterial({
map: img,
color: '#ffffff',
transparent: true,
opacity: 0.9
})
image.load(`${
hrefs.value}${
dir.value}logo/xiaodoubao.png`, (img) => {
img.wrapS = THREE.RepeatWrapping
img.wrapT = THREE.RepeatWrapping
img.matrixAutoUpdate = false
let imgM = new THREE.MeshBasicMaterial({
map: img,
color: '#ffffff',
transparent: true,
opacity: 0.8,
// wireframe: true
})
const geometry = new THREE.BoxGeometry( 185.1, 49.0, 49.1)
cityPaiMaiLogo = new THREE.Mesh(geometry, imgM)
cityPaiMaiLogo.rotation.x = Math.PI * 1.5
cityPaiMaiLogo.position.set(-590, 20, -3300)
cityGroup.add(cityPaiMaiLogo)
})
})
});
}
// let mtlLoader = new MTLLoader() obj Model loding
Add game protagonists
const loader = new FBXLoader()
loader.load( `${
hrefs.value}${
dir.value}/d/a.fbx`, function ( object ) {
object.name = 'a-dcw'
mixer = new THREE.AnimationMixer( object )
object.scale.setScalar(0.08)
object.rotateY(Math.PI * 3)
// object.traverse( function ( child ) {
// if ( (child as any).isMesh ) {
// child.castShadow = true
// child.receiveShadow = true
// }
// } )
object.position.y = 25
scene.add(object)
aBox3d = new THREE.Box3()
aBox3d.setFromObject(object)
aBox3d.name = 'a-dcw-box3'
aBoxHelper = new THREE.BoxHelper(object, 0xff0000)
scene.add(aBoxHelper)
})
// const loader = new FBXLoader() // loding Game protagonist model
// Add game dynamics and animation mixer = new THREE.AnimationMixer( object )
Render canvas set canvas size
renderer = new THREE.WebGLRenderer( {
alpha: true, antialias: true } )
renderer.setPixelRatio( window.devicePixelRatio )
renderer.setSize( window.innerWidth, window.innerHeight )
// renderer.shadowMap.enabled = true
container.appendChild( renderer.domElement )
renderer.setClearColor(0xEEEEEE, 0.0)
// Set background transparency
scene.background = null
The model moves
animate()
floor.map.offset.y += (0.0009 * globSpeed.value) // Walk on the runway
// Create gold coins and obstacles
const runIf = randomInt(0, 3)
const numberGlob = randomInt(1, 15)
const Y = [20, 45, 65]
const numberY = randomInt(0, 3)
const difficulty = randomInt(0, 3)
const numberZ = randomInt(1000, 1500)
const time = randomInt(1200, 2800)
numberGlobNumber.value ++
if (numberGlobNumber.value % 2 === 1) {
globs(runIf, numberGlob, Y[numberY], difficulty, numberZ, time)
}
// Gold coin Z Location
const meshPosition = (cloneMesh, numberX, numberY, numberZ, Z, i, type) => {
const mesh = cloneMesh.clone()
mesh.position.set(numberX, numberY, -i * numberZ - zNumber.value - Z)
mesh.name = `glob${
i}`
globGroup.add(mesh)
}
// obstacle Z Location
const meshPositionObstacles = (cloneMesh, numberX, numberY, numberZ, Z, i, type) => {
const mesh = cloneMesh.clone()
mesh.position.set(numberX, numberY, -i * numberZ - zNumber.value - Z)
mesh.name = `obstacle`
globGroup.add(mesh)
}
// Update model animation
const delta = clock.getDelta()
if ( mixer ) mixer.update( delta )
//
Hit gold coin and obstacle logic
for(const item of globGroup.children) {
// Create an impact box
let itemBox3 = new THREE.Box3()
itemBox3.setFromObject(item)
// See if it hits
if (aBox3d) {
if (aBox3d.intersectsBox(itemBox3)) {
// Obstacle impact
if (item.name === "obstacle") {
item.name = 'start-on'
// No points, no resurrection card Jump to the end page after toast
if (resurrectionSkp.value <= 0) {
const gameNoHref = encodeURIComponent(window.btoa(gameNo.value))
window.location.replace(`${
hrefs.value}/b.html`)
start.value = false
} else {
start.value = false
if ((integralsNumber.value <=1 && resurrection.value <= 0) ) {
TostSkipOver.value = true
globGroup.traverse(function(obj) {
if (obj.type === 'Mesh') {
(obj as any).geometry.dispose();
(obj as any).material.dispose();
}
})
window.location.replace(`${
hrefs.value}/over.html`)
} else {
itemBox3.makeEmpty()
itemBox3 = null
globGroup.remove(item)
globGroup.traverse(function(obj) {
if (obj.type === 'Mesh') {
(obj as any).geometry.dispose();
(obj as any).material.dispose();
}
})
scene.remove(globGroup)
processTimeFn()
closeHelp.value = true
closeRequestAnimationFrame.value = true
setTimeout(() => {
globGroup = new THREE.Group()
scene.add(globGroup)
}, 11000)
}
}
}
// Gold coin impact
if (item.name !== "obstacle") {
if (globNumber.value >= 1000) {
} else {
if (!A.value) {
} else {
globNumber.value++
globNumberCopy.value++
}
}
globGroup.remove(item)
}
}
} else {
if (item.position.z - 210 >= -zNumber.value) {
globGroup.remove(item)
}
}
}
}
Manipulation The mobile terminal slides up and down, left and right
const EventUtil = {
addHandler: function (element, type, handler) {
if (element.addEventListener)
element.addEventListener(type, handler, false);
else if (element.attachEvent)
element.attachEvent("on" + type, handler);
else
element["on" + type] = handler;
},
removeHandler: function (element, type, handler) {
if(element.removeEventListener)
element.removeEventListener(type, handler, false);
else if(element.detachEvent)
element.detachEvent("on" + type, handler);
else
element["on" + type] = handler;
},
/** * Monitor the direction of the touch * @param target To bind the listening target element * @param isPreventDefault Whether to block the default behavior of touch sliding ( For example, scrolling the page up and down , Zoom, etc ) * @param upCallback Listen callback sliding up ( If you don't care , Can not pass , Or pass on false) * @param rightCallback Sniffer callback sliding right ( If you don't care , Can not pass , Or pass on false) * @param downCallback Sliding down the listening callback ( If you don't care , Can not pass , Or pass on false) * @param leftCallback Monitor callback sliding left ( If you don't care , Can not pass , Or pass on false) */
listenTouchDirection: function (target, isPreventDefault, upCallback, rightCallback, downCallback, leftCallback) {
this.addHandler(target, "touchstart", handleTouchEvent, {
passive: false });
this.addHandler(target, "touchend", handleTouchEvent);
this.addHandler(target, "touchmove", handleTouchEvent);
var startX;
var startY;
function handleTouchEvent(event) {
switch (event.type){
case "touchstart":
startX = event.touches[0].pageX;
startY = event.touches[0].pageY;
break;
case "touchend":
var spanX = event.changedTouches[0].pageX - startX;
var spanY = event.changedTouches[0].pageY - startY;
if(Math.abs(spanX) > Math.abs(spanY)){
// It is recognized as horizontal sliding
if(spanX > 0){
// towards the right
if(rightCallback)
rightCallback()
} else if(spanX < 0){
// towards the left
if(leftCallback)
leftCallback()
}
} else {
// It's identified as vertical sliding
if(spanY > 0){
// Down
if(downCallback)
downCallback();
} else if (spanY < 0) {
// Up
if(upCallback)
upCallback();
}
}
break;
case "touchmove":
// Blocking default behavior
if(isPreventDefault)
event.preventDefault();
break;
}
}
}
};
export default EventUtil
// Instantiate the control component
EventUtil.listenTouchDirection(document, true, up, right, down, left)
const up = () => {
if(start.value) {
if (!upStop.value) {
upStop.value = true
if (scene && scene.getObjectByName) {
let a = scene.getObjectByName('a-dcw')
const aY = JSON.stringify(a.position.y + 120)
const aCY = JSON.stringify(a.position.y)
let y = false
time = setInterval(() => {
if (a.position.y >= aY) {
y = true
if (a.position.y <= aCY) {
clearInterval(time)
}
a.position.y = a.position.y - 7
if (a.position.z > 0) {
a.position.z = 100
}
if (a.position.z < -4500) {
a.position.z = -4500
}
aBox3d = new THREE.Box3()
aBox3d.setFromObject(a)
aBoxMove(a)
} else {
if (!y) {
a.position.y = a.position.y + 5
if (a.position.z > 0) {
a.position.z = 100
}
if (a.position.z < -4500) {
a.position.z = -4500
}
aBox3d = new THREE.Box3()
aBox3d.setFromObject(a)
aBoxMove(a)
} else if (y){
a.position.z = a.position.z - 18
a.position.y = a.position.y - 7
if (a.position.z > 0) {
a.position.z = 100
}
if (a.position.z < -4500) {
a.position.z = -4500
}
aBox3d = new THREE.Box3()
aBox3d.setFromObject(a)
if (a.position.y <= 0) {
upStop.value = false
clearInterval(time)
atime = setInterval(() => {
a.position.z = a.position.z + 5
if (a.position.z > 0) {
a.position.z = 100
}
if (a.position.z < -4500) {
a.position.z = -4500
}
aBox3d = new THREE.Box3()
aBox3d.setFromObject(a)
if (a.position.z >= -20 || !start.value) {
a.position.z = 0
aBox3d = new THREE.Box3()
aBox3d.setFromObject(a)
clearInterval(atime)
}
}, 3)
}
aBoxMove(a)
}
}
}, 12)
}
}
}
}
const right = () => {
if (start.value) {
if (scene && scene.getObjectByName) {
const a = scene.getObjectByName('a-dcw')
if (a.position.x > 30) {
} else {
a.position.x = a.position.x + 40
// aBox3d = new THREE.Box3()
// aBoxHelper = new THREE.BoxHelper(a, 0xff0000)
// scene.add(aBoxHelper)
aBox3d.setFromObject(a)
aBoxMove(a)
}
}
}
}
const down = () => {
// console.log("action:down");
}
const left = () => {
if (start.value) {
if (scene && scene.getObjectByName) {
const a = scene.getObjectByName('a-dcw')
if (a.position.x < -35) {
} else {
a.position.x = a.position.x - 40
aBox3d = new THREE.Box3()
aBox3d.setFromObject(a)
aBoxMove(a)
}
}
}
}
For more information, please go to Xiaodou Bao 》
Scan the code to visit Xiaodou bag

Scan the code and follow the official account of xiaodoubao

边栏推荐
- TCP - sliding window
- Arduino uno error analysis avrdude: stk500_ recv(): programmer is not responding
- Alibaba political commissar system - Chapter III, Alibaba political commissar and cultural docking
- Stm8s003 domestic substitute for dp32g003 32-bit microcontroller chip
- ROS common instructions
- Noise monitoring and sensing system
- Unicode private use areas
- 简易计算器微信小程序项目源码
- Stm32ff030 replaces domestic MCU dp32g030
- Component transfer participation lifecycle
猜你喜欢

Day15 (day16 extension): file contains vulnerability

Unity Shader学习(六)实现雷达扫描效果

数字人民币时代隐私更安全

Qt/pyqt window type and window flag

Unity多人联机框架Mirro学习记录(一)

Third week weekly report resnet+resnext

RPC and rest

Reading of false news detection papers (3): semi supervised content-based detection of misinformation via tensor embeddings

Simple operation of SQL server data table
![[robomaster] a board receives jy-me01 angle sensor data -- Modbus Protocol & CRC software verification](/img/0e/e5be0fffb154d081c20b09832530d4.png)
[robomaster] a board receives jy-me01 angle sensor data -- Modbus Protocol & CRC software verification
随机推荐
sql判断语句的编写
Day15 (day16 extension): file contains vulnerability
[noi simulation] computational geometry (convex hull, violence, and search set)
Simplefoc parameter adjustment 3-pid parameter setting strategy
What is Amazon self support number and what should sellers do?
Leetcode Hot 100 (brush question 9) (301/45/517/407/offer62/mst08.14/)
STM32 printf problem summary semihosting microlib understanding
Privacy is more secure in the era of digital RMB
125kHz wake-up function 2.4GHz single transmitter chip-si24r2h
深度学习(1):银行客户流失预测
Simple calculator wechat applet project source code
The difference between torch.tensor and torch.tensor
Temperature acquisition and control system based on WiFi
集群使用规范
分段分页以及段页结合
User identity identification and account system practice
DAC0832 waveform generator based on 51 single chip microcomputer
leetcode hot 100(刷题篇9)(301/45/517/407/offer62/MST08.14/)
[academic related] why can't many domestic scholars' AI papers be reproduced?
用户身份标识与账号体系实践