feat: add scene for task2 n vanilla
This commit is contained in:
parent
0f9a918873
commit
46c9ed9a2d
@ -8,10 +8,11 @@
|
|||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background: white;
|
background: #f3f5f8;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
font-family: "Avenir Next", "Segoe UI", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
@ -19,10 +20,78 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#state-panel {
|
||||||
|
position: fixed;
|
||||||
|
top: 16px;
|
||||||
|
left: 16px;
|
||||||
|
z-index: 10;
|
||||||
|
background: rgba(255, 255, 255, 0.82);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#state-panel h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
color: #1b2530;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-btn {
|
||||||
|
border: 1px solid #cfd8e3;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #203448;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-btn:hover {
|
||||||
|
border-color: #8ea2b8;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-btn.active {
|
||||||
|
background: #203448;
|
||||||
|
border-color: #203448;
|
||||||
|
color: #f4f8fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#hint {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #4f647a;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body> <script type="module" src="/main.js"></script>
|
<body>
|
||||||
|
<div id="state-panel">
|
||||||
|
<h2>Scene States</h2>
|
||||||
|
<div class="state-buttons">
|
||||||
|
<button class="state-btn" data-state="state1">State 1 (1)</button>
|
||||||
|
<button class="state-btn" data-state="state2">State 2 (2)</button>
|
||||||
|
<button class="state-btn" data-state="state3">State 3 (3)</button>
|
||||||
|
</div>
|
||||||
|
<p id="hint">Press 1, 2, or 3 to switch state.</p>
|
||||||
|
</div>
|
||||||
|
<script type="module" src="/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@ -0,0 +1,130 @@
|
|||||||
|
import * as THREE from 'three'
|
||||||
|
|
||||||
|
const scene = new THREE.Scene()
|
||||||
|
scene.background = new THREE.Color(0xf3f5f8)
|
||||||
|
|
||||||
|
const camera = new THREE.PerspectiveCamera(
|
||||||
|
55,
|
||||||
|
window.innerWidth / window.innerHeight,
|
||||||
|
0.1,
|
||||||
|
100
|
||||||
|
)
|
||||||
|
camera.position.set(0, 2, 7)
|
||||||
|
camera.lookAt(0, 0, 0)
|
||||||
|
|
||||||
|
const renderer = new THREE.WebGLRenderer({ antialias: true })
|
||||||
|
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight)
|
||||||
|
document.body.appendChild(renderer.domElement)
|
||||||
|
|
||||||
|
scene.add(new THREE.AmbientLight(0xffffff, 0.9))
|
||||||
|
|
||||||
|
const keyLight = new THREE.DirectionalLight(0xffffff, 1)
|
||||||
|
keyLight.position.set(3, 4, 5)
|
||||||
|
scene.add(keyLight)
|
||||||
|
|
||||||
|
const objects = {
|
||||||
|
center: new THREE.Mesh(
|
||||||
|
new THREE.BoxGeometry(1.2, 1.2, 1.2),
|
||||||
|
new THREE.MeshStandardMaterial({ color: 0x2a9d8f })
|
||||||
|
),
|
||||||
|
left: new THREE.Mesh(
|
||||||
|
new THREE.BoxGeometry(0.9, 0.9, 0.9),
|
||||||
|
new THREE.MeshStandardMaterial({ color: 0xe76f51 })
|
||||||
|
),
|
||||||
|
right: new THREE.Mesh(
|
||||||
|
new THREE.BoxGeometry(0.9, 0.9, 0.9),
|
||||||
|
new THREE.MeshStandardMaterial({ color: 0x457b9d })
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.add(objects.center, objects.left, objects.right)
|
||||||
|
|
||||||
|
const states = {
|
||||||
|
state1: {
|
||||||
|
center: { position: [0, 0, 0], rotation: [0, 0, 0], visible: true },
|
||||||
|
left: { position: [0, 0, 0], rotation: [0, 0, 0], visible: false },
|
||||||
|
right: { position: [0, 0, 0], rotation: [0, 0, 0], visible: false },
|
||||||
|
},
|
||||||
|
state2: {
|
||||||
|
center: { position: [0, 0, 0], rotation: [0.25, 0.4, 0], visible: true },
|
||||||
|
left: { position: [-2.1, 0, 0.2], rotation: [0, 0.2, 0], visible: true },
|
||||||
|
right: { position: [2.1, 0, -0.2], rotation: [0, -0.2, 0], visible: true },
|
||||||
|
},
|
||||||
|
state3: {
|
||||||
|
center: { position: [0, 1.3, 0], rotation: [0.6, 0.9, 0], visible: true },
|
||||||
|
left: { position: [-1.2, -1, 1.2], rotation: [0.3, 0.3, 0.1], visible: true },
|
||||||
|
right: { position: [0, 0, 0], rotation: [0, 0, 0], visible: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const targets = {
|
||||||
|
center: { position: new THREE.Vector3(), rotation: new THREE.Euler() },
|
||||||
|
left: { position: new THREE.Vector3(), rotation: new THREE.Euler() },
|
||||||
|
right: { position: new THREE.Vector3(), rotation: new THREE.Euler() },
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttons = Array.from(document.querySelectorAll('.state-btn'))
|
||||||
|
let activeState = 'state1'
|
||||||
|
|
||||||
|
function updateButtonState(stateName) {
|
||||||
|
buttons.forEach((button) => {
|
||||||
|
button.classList.toggle('active', button.dataset.state === stateName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyState(stateName) {
|
||||||
|
const nextState = states[stateName]
|
||||||
|
if (!nextState) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
activeState = stateName
|
||||||
|
|
||||||
|
Object.keys(objects).forEach((name) => {
|
||||||
|
const object = objects[name]
|
||||||
|
const config = nextState[name]
|
||||||
|
|
||||||
|
targets[name].position.set(...config.position)
|
||||||
|
targets[name].rotation.set(...config.rotation)
|
||||||
|
object.visible = config.visible
|
||||||
|
})
|
||||||
|
|
||||||
|
updateButtonState(stateName)
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons.forEach((button) => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
applyState(button.dataset.state)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addEventListener('keydown', (event) => {
|
||||||
|
if (event.key === '1') applyState('state1')
|
||||||
|
if (event.key === '2') applyState('state2')
|
||||||
|
if (event.key === '3') applyState('state3')
|
||||||
|
})
|
||||||
|
|
||||||
|
applyState(activeState)
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
Object.keys(objects).forEach((name) => {
|
||||||
|
const object = objects[name]
|
||||||
|
const target = targets[name]
|
||||||
|
|
||||||
|
object.position.lerp(target.position, 0.1)
|
||||||
|
object.rotation.x += (target.rotation.x - object.rotation.x) * 0.1
|
||||||
|
object.rotation.y += (target.rotation.y - object.rotation.y) * 0.1
|
||||||
|
object.rotation.z += (target.rotation.z - object.rotation.z) * 0.1
|
||||||
|
})
|
||||||
|
|
||||||
|
renderer.render(scene, camera)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.setAnimationLoop(animate)
|
||||||
|
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
camera.aspect = window.innerWidth / window.innerHeight
|
||||||
|
camera.updateProjectionMatrix()
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight)
|
||||||
|
})
|
||||||
Loading…
x
Reference in New Issue
Block a user