cannon+three打造一个三维小球重力下滑滑滑梯效果代码
代码语言:html
所属分类:三维
代码描述:cannon+three打造一个三维小球重力下滑滑滑梯效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> :root { --tp-base-background-color: hsla(0, 0%, 40%, 1.00); --tp-base-shadow-color: hsla(0, 0%, 0%, 0.2); --tp-button-background-color: hsla(0, 0%, 100%, 1.00); --tp-button-background-color-active: hsla(0, 0%, 85%, 1.00); --tp-button-background-color-focus: hsla(0, 0%, 90%, 1.00); --tp-button-background-color-hover: hsla(0, 0%, 95%, 1.00); --tp-button-foreground-color: hsla(230, 20%, 11%, 1.00); --tp-container-background-color: hsla(0, 0%, 0%, 0.20); --tp-container-background-color-active: hsla(0, 0%, 0%, 0.35); --tp-container-background-color-focus: hsla(0, 0%, 0%, 0.30); --tp-container-background-color-hover: hsla(0, 0%, 0%, 0.25); --tp-container-foreground-color: hsla(0, 0%, 100%, 0.90); --tp-groove-foreground-color: hsla(0, 0%, 0%, 0.50); --tp-input-background-color: hsla(0, 0%, 0%, 0.50); --tp-input-background-color-active: hsla(0, 0%, 0%, 0.65); --tp-input-background-color-focus: hsla(0, 0%, 0%, 0.60); --tp-input-background-color-hover: hsla(0, 0%, 0%, 0.55); --tp-input-foreground-color: hsla(0, 0%, 100%, 0.90); --tp-label-foreground-color: hsla(0, 0%, 100%, 0.90); --tp-monitor-background-color: hsla(0, 0%, 0%, 0.50); --tp-monitor-foreground-color: hsla(0, 0%, 100%, 0.50); } html { font-family: 'Dosis', Arial, sans-serif; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } *, *::after, *::before { box-sizing: border-box; } body { padding: 0; margin: 0; background-color: #1c7dff; overflow: hidden; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; cursor: -moz-grabg; cursor: -webkit-grab; } .credits { position: absolute; z-index: 1; bottom: 0; width: auto; background-color: #07326b; padding: 10px; cursor: pointer; font-size: 8pt; font-weight: lighter; } .credits a { color: #ffffff; text-decoration: none; } .credits h1 { margin: inherit; } .credits:hover { background-color: #ff1111; color: #ffffff; } </style> <style> html { font-family: "Dosis", Arial, sans-serif; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } .stats { position: absolute; z-index: 1; top: 0; left: 0; } </style> </head> <body> <div class="stats"> </div> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/Stats-16.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/cannon.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/three.126.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/OrbitControls.126.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/TransformControls.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/gsap.3.5.2.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/tweakpane.3.02.js"></script> <script > class App { init() { this.setup(); this.createScene(); this.createCamera(); this.addCameraControls(); this.addAmbientLight(); this.addDirectionalLight(); this.addPhysicsWorld(); this.addBackWall(); this.addFloor(); this.addWoodColumns(); this.addRows(); this.addEdges(); this.addSphere(); this.addFloorBox(); this.addStatsMonitor(); this.addWindowListeners(); this.addGuiControls(); this.addDummyCameraTarget(); this.animateDummyCameraTarget(); this.animate(); } setup() { this.debug = false; this.width = window.innerWidth; this.height = window.innerHeight; this.cameraAutoAnimate = false; this.spheres = []; Sphere.loadTextures(); Sphere.buildMaterial(); Column.buildMaterial(); Row.buildMaterial(); } createScene() { this.scene = new THREE.Scene(); this.scene.background = new THREE.Color( window.getComputedStyle(document.body).backgroundColor); this.renderer = new THREE.WebGLRenderer({ antialias: true }); this.renderer.setSize(this.width, this.height); this.scene.position.set(0, -5, 0); this.renderer.shadowMap.enabled = true; this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; document.body.appendChild(this.renderer.domElement); } createCamera() { this.camera = new THREE.PerspectiveCamera( 20, this.width / this.height, 1, 1000); this.camera.position.set(20, 20, 80); this.scene.add(this.camera); } addCameraControls() { this.orbitControl = new THREE.OrbitControls( this.camera, this.renderer.domElement); this.orbitControl.minPolarAngle = THREE.MathUtils.degToRad(0); this.orbitControl.maxPolarAngle = THREE.MathUtils.degToRad(90); this.orbitControl.minAzimuthAngle = THREE.MathUtils.degToRad(-50); this.orbitControl.maxAzimuthAngle = THREE.MathUtils.degToRad(50); this.orbitControl.maxDistance = 90; this.orbitControl.minDistance = 40; this.orbitControl.enableDamping = true; this.orbitControl.dampingFactor = 0.02; this.orbitControl.enablePan = !this.cameraAutoAnimate; this.orbitControl.enableRotate = !this.cameraAutoAnimate; this.orbitControl.enableZoom = !this.cameraAutoAnimate; this.orbitControl.saveState(); this.orbitControl.addEventListener("start", () => { requestAnimationFrame(() => { document.body.style.cursor = "-moz-grabbing"; document.body.style.cursor = "-webkit-grabbing"; }); }); this.orbitControl.addEventListener("end", () => { requestAnimationFrame(() => { document.body.style.cursor = "-moz-grab"; document.body.style.cursor = "-webkit-grab"; }); }); } addPhysicsWorld() { this.physics = { fixedTimeStep: 1 / 60, maxSubSteps: 10, damping: 0.09, time: 0.01, lastTime: 0.01 }; this.world = new CANNON.World(); this.world.gravity.set(0, -120, 0); this.world.broadphase = new CANNON.NaiveBroadphase(); this.world.solver.iterations = 10; this.world.defaultContactMaterial.contactEquationStiffness = 1e6; this.world.defaultContactMaterial.contactEquationRelaxation = 3; this.world.allowSleep = true; this.cannonDebugRenderer = this.debug && new CannonDebugRenderer(this.scene, this.world, { THREE, CANNON }); } addAmbientLight() { this.scene.add(new THREE.AmbientLight({ color: "#ffffff" }, 0.5)); } addDirectionalLight() { this.directionalLight = new THREE.DirectionalLight("#ffffff", 0.8); this.directionalLight.castShadow = true; this.directionalLight.position.set(10, 15, 15); this.directionalLight.shadow.camera.needsUpdate = true; this.directionalLight.shadow.mapSize.width = 2048; this.directionalLight.shadow.mapSize.height = 2048; this.directionalLight.shadow.camera.left = -20; this.directionalLight.shadow.camera.right = 20; this.directionalLight.shadow.camera.top = 15; this.directionalLight.shadow.camera.bottom = -15; this.scene.add(this.directionalLight); } addFloor() { const geometry = new THREE.PlaneBufferGeometry(400, 150); const material = new THREE.MeshStandardMaterial({ color: "#ffffff", side: THREE.DoubleSide }); this.floor = new THREE.Mesh(geometry, material); this.floor.position.y = -5; this.floor.position.z = 0; this.floor.rotateX(Math.PI / 2); this.floor.receiveShadow = true; this.floor.body = new CANNON.Body({ mass: 0, position: new CANNON.Vec3(0, this.floor.position.y, 0), material: new CANNON.Material(), shape: new CANNON.Plane(40, 40, 40) }); this.floor.body.material.name = "floor"; this.floor.body.quaternion.setFromAxisAngle( new CANNON.Vec3(1, 0, 0), THREE.MathUtils.degToRad(-90)); this.world.addBody(this.floor.body); this.scene.add(this.floor); this.addFloorGrid(); } addFloorGrid() { const size = 400; const divisions = size; const grid = new THREE.GridHelper(size, divisions, "#888888"); grid.position.set(0, this.floor.position.y, 0); this.scene.add(grid); } addWoodColumns() { this.columnFront = new Column(); this.columnFront.build(); this.columnFront.mesh.position.y = 7; this.columnFront.mesh.position.z = 0.7; this.scene.add(this.columnFront.mesh); this.columnFront.cylinder.position.set(0, 0.2, 8.7); this.columnFront.mesh.add(this.columnFront.cylinder); const cylinder2 = this.columnFront.cylinder.clone(); cylinder2.position.set(0, 0.2, 4); this.columnFront.mesh.add(cylinder2); const cylinder3 = this.columnFront.cylinder.clone(); cylinder3.position.set(0, 0.2, -0.7); this.columnFront.mesh.add(cylinder3); const cylinder4 = this.columnFront.cylinder.clone(); cylinder4.position.set(0, 0.2, -5.5); this.columnFront.mesh.add(cylinder4); const cylinder5 = this.columnFront.cylinder.clone(); cylinder5.position.set(0, 0.2, -10.5); this.columnFront.mesh.add(cylinder5); this.columnBack = this.columnFront.mesh.clone(); this.columnBack.position.y = this.columnFront.mesh.position.y; this.columnBack.position.z = -this.columnFront.mesh.position.z; this.scene.add(this.columnBack); } addRows() { this.row1 = new Row(this.world); this.row1.build({ size: 6 }); this.row1.rotateZ(THREE.MathUtils.degToRad(-20)); this.row1.position({ x: 2.2, y: 14, z: 0, gutter: -0.18 }); this.scene.add(this.row1.mesh); this.row2 = new Row(this.world); this.row2.build({ size: 12 }); this.row2.rotateZ(THREE.MathUtils.degToRad(10)); this.row2.position({ x: 0.25, y: 10, z: 0, gutter: 0.1 }); this.scene.add(this.row2.mesh); this.row3 = new Row(this.world); this.row3.build({ size: 12 }); this.row3.rotateZ(THREE.MathUtils.degToRad(-15)); this.row3.position({ x: -1, y: 5.5, z: 0, gutter: -0.1 }); this.scene.add(this.row3.mesh); this.row4 = new Row(this.world); this.row4.build({ size: 12 }); this.row4.rotateZ(THREE.MathUtils.degToRad(10)); this.row4.position({ x: 0, y: 0.5, z: 0, gutter: 0.1 }); this.scene.add(this.row4.mesh); this.row5 = new Row(this.world); this.row5.build({ size: 12 }); this.row5.rotateZ(THREE.MathUtils.degToRad(-15)); this.row5.position({ x: -1, y: -4, z: 0, gutter: -0.1 }); this.scene.add(this.row5.mesh); } addEdges() { this.edge1 = new Edge(); this.edge1.build(this.world, "#fbff0e"); this.edge1.rotate({ x: 0, y: 0, z: THREE.MathUtils.degToRad(90) }); this.edge1.position({ x: 2, y: 14, z: 0 }); this.edge1.bottom.body.position = new CANNON.Vec3( 6.4, 14.5, this.edge1.bottom.position.z); this.edge1.bottomInside.position = new CANNON.Vec3( 6, 14.2, this.edge1.bottom.position.z); this.edge1.bottomInside.quaternion.setFromAxisAngle( new CANNON.Vec3(0, 0, -1), THREE.MathUtils.degToRad(-40)); this.scene.add(this.edge1.mesh); this.edge1.cylinder.rotateX(THREE.MathUtils.degToRad(90)); this.edge1.cylinder.position.set(2, -1, 0.75); this.edge1.mesh.add(this.edge1.cylinder); const cylinder2 = this.edge1.cylinder.clone(); cylinder2.position.set(2, 1.8, 0.75); this.edge1.mesh.add(cylinder2); this.edge2 = new Edge(); this.edge2.build(this.world, "#ff0e0e"); this.edge2.rotate({ x: 0, y: 0, z: THREE.MathUtils.degToRad(90) }); this.edge2.position({ x: -9, y: 9.8, z: 0 }); this.edge2.bottom.position.x = 1.55; this.edge2.bottom.body.position = new CANNON.Vec3( -7.5, 10, this.edge2.bottom.position.z); this.edge2.bottomInside.position = new CANNON.Vec3( -7, 10.5, this.edge2.bottom.position.z); this.edge2.bottomInside.quaternion.setFromAxisAngle( new CANNON.Vec3(0, 0, -1), THREE.MathUtils.degToRad(35)); this.scene.add(this.edge2.mesh); const cylinder3 = this.edge1.cylinder.clone(); cylinder3.material = this.edge1.cylinder.material.clone(); cylinder3.material.color = new THREE.Color("#ff0e0e"); cylinder3.position.set(4, -1, 0.75); this.edge2.mesh.add(cylinder3); const cylinder4 = cylinder3.clone(); cylinder4.position.set(4, 1.8, 0.75); this.edge2.mesh.add(cylinder4); this.edge3 = new Edge(); this.edge3.build(this.world, "#15ff47"); this.edge3.rotate({ x: 0, y: 0, z: THREE.MathUtils.degToRad(90) }); this.edge3.position({ x: 2, y: 4.8, z: 0 }); this.edge3.bottom.position.x = 4.45; this.edge3.bottom.body.position = new CANNON.Vec3( 6.5, 5.5, this.edge3.bottom.position.z); this.edge3.bottomInside.position = new CANNON.Vec3( 6, 5.2, this.edge3.bottom.position.z); this.edge3.bottomInside.quaternion.setFromAxisAngle( new CANNON.Vec3(0, 0, -1), THREE.MathUtils.degToRad(-40)); this.scene.add(this.edge3.mesh); const cylinder5 = this.edge1.cylinder.clone(); cylinder5.material = this.edge1.cylinder.material.clone(); cylinder5.material.color = new THREE.Color("#15ff47"); cylinder5.position.set(2, -1, 0.75); this.edge3.mesh.add(cylinder5); const cylinder6 = cylinder5.clone(); cylinder6.position.set(2, 1.8, 0.75); this.edge3.mesh.add(cylinder6); this.edge4 = new Edge(); this.edge4.build(this.world, "#1c57ff"); this.edge4.rotate({ x: 0, y: 0, z: THREE.MathUtils.degToRad(90) }); this.edge4.position({ x: -9, y: 0.3, z: 0 }); this.edge4.bottom.position.x = 1.55; this.edge4.bottom.body.position = new CANNON.Vec3( -7.4, 0.8, this.edge4.bottom.position.z); this.edge4.bottomInside.position = new CANNON.Vec3( -7, 1, this.edge4.bottom.position.z); this.edge4.bottomInside.quaternion.setFromAxisAngle( new CANNON.Vec3(0, 0, -1), THREE.MathUtils.degToRad(40)); this.scene.add(this.edge4.mesh); const cylinder7 = this.edge1.cylinder.clone(); cylinder7.material = this.edge1.cylinder.material.clone(); cylinder7.material.color = new THREE.Color("#1c57ff"); cylinder7.position.set(4, -0.7, 0.75); this.edge4.mesh.add(cylinder7); const cylinder8 = cylinder7.clone(); cylinder8.position.set(4, 1.8, 0.75); this.edge4.mesh.add(cylinder8); } addFloorBox() { this.floorBox = new FloorBox(); this.floorBox.build(this.world); this.scene.add(this.floorBox.mesh); } addBackWall() { const materialParams = { color: "#1c7dff", side: THREE.DoubleSide }; const geometry = new THREE.PlaneBufferGeometry(400, 140); const material = new THREE.MeshStandardMaterial(materialParams); const backwall = new THREE.Mesh(geometry, material); backwall.position.z = -10; backwall.receiveShadow = true; this.scene.add(backwall); } addSphere() { const sphere = new Sphere(); sphere.build(); const collideEvent = e => { if ( e.body.material.name === "floor" || e.body.material.name === "sphere") { sphere.mesh.body.removeEventListener("collide", collideEvent); this.moveCameraUp(); } }; sphere.mesh.body.addEventListener("collide", collideEvent); this.world.addBody(sphere.mesh.body); const mat = new CANNON.ContactMaterial( this.floor.body.material, sphere.mesh.body.material, { friction: 0.3, restitution: 0.5 }); this.world.addContactMaterial(mat); this.spheres.push(sphere); this.scene.add(sphere.mesh); } addDummyCameraTarget() { this.dummyCameraTarget = new THREE.Mesh( new THREE.SphereBufferGeometry(0.5, 8, 8), new THREE.MeshStandardMaterial()); this.dummyCameraTarget.material.needsUpdate = true; this.dummyCameraTarget.material.opacity = 0; this.dummyCameraTarget.material.alphaTest = 1; this.dummyCameraTarget.position.y = 20; this.dummyCameraTarget.position.z = 2; this.scene.add(this.dummyCameraTarget); } animateDummyCameraTarget() { const tl = gsap.timeline({ defaults: { duration: 11, ease: "sine.out", delay: 0.5 }, onComplete: () => { tl.kill(); } }); tl.to(this.dummyCameraTarget.position, { y: -4 }); } moveCameraUp() { const tl = gsap.timeline({ defaults: { duration: 3, ease: "linear", delay: 0.5 }, onComplete: () => { tl.kill(); this.dummyCameraTarget.position.y = 14; this..........完整代码请登录后点击上方下载按钮下载查看
网友评论0