사과 생성 위치를 나뭇잎 표면 랜덤 지점으로, 다람쥐 도주 방향을 좌우로 변경하고 나뭇잎 모양을 단순 사각형에서 잎 실루엣으로 개선
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
42
index.html
42
index.html
@@ -243,16 +243,12 @@ basketShadow.position.set(BASKET_POS.x, 0.005, BASKET_POS.z);
|
|||||||
scene.add(basketShadow);
|
scene.add(basketShadow);
|
||||||
|
|
||||||
// ---------- apples ----------
|
// ---------- apples ----------
|
||||||
const appleHomes = [
|
const APPLE_COUNT = 8;
|
||||||
new THREE.Vector3(1.55, 2.75, 0.65),
|
function randomAppleHome(){
|
||||||
new THREE.Vector3(-1.5, 2.65, -0.55),
|
const spec = foliageSpecs[Math.floor(Math.random() * foliageSpecs.length)];
|
||||||
new THREE.Vector3(0.25, 3.75, 0.85),
|
const dir = new THREE.Vector3(Math.random() - 0.5, Math.random() - 0.2, Math.random() - 0.5).normalize();
|
||||||
new THREE.Vector3(0.95, 1.95, -1.25),
|
return new THREE.Vector3(spec.pos[0], spec.pos[1], spec.pos[2]).addScaledVector(dir, spec.r * 0.92);
|
||||||
new THREE.Vector3(-0.85, 1.9, 1.15),
|
}
|
||||||
new THREE.Vector3(1.1, 3.15, -0.55),
|
|
||||||
new THREE.Vector3(-1.05, 3.05, 0.3),
|
|
||||||
new THREE.Vector3(0.15, 2.4, 1.35),
|
|
||||||
];
|
|
||||||
const appleGeo = new THREE.SphereGeometry(0.16, 10, 8);
|
const appleGeo = new THREE.SphereGeometry(0.16, 10, 8);
|
||||||
const appleMat = new THREE.MeshStandardMaterial({ color: 0xd1453b, roughness: 0.5, flatShading:true });
|
const appleMat = new THREE.MeshStandardMaterial({ color: 0xd1453b, roughness: 0.5, flatShading:true });
|
||||||
const stemGeo = new THREE.CylinderGeometry(0.015, 0.02, 0.14, 5);
|
const stemGeo = new THREE.CylinderGeometry(0.015, 0.02, 0.14, 5);
|
||||||
@@ -274,8 +270,10 @@ const LEAF_LINGER = 1.8; // how long a fallen leaf rests before fading away
|
|||||||
const SQUIRREL_COOLDOWN = 6; // min seconds between squirrel appearances
|
const SQUIRREL_COOLDOWN = 6; // min seconds between squirrel appearances
|
||||||
|
|
||||||
// a tree "slot" holds at most one apple at a time and regrows independently of
|
// a tree "slot" holds at most one apple at a time and regrows independently of
|
||||||
// whatever happens to the apple once it falls (caught in the basket or not)
|
// whatever happens to the apple once it falls (caught in the basket or not);
|
||||||
const treeSlots = appleHomes.map((home) => {
|
// each grow picks a fresh random spot on the foliage rather than a fixed home
|
||||||
|
const treeSlots = Array.from({ length: APPLE_COUNT }, () => {
|
||||||
|
const home = randomAppleHome();
|
||||||
const mesh = createAppleMesh();
|
const mesh = createAppleMesh();
|
||||||
mesh.position.copy(home);
|
mesh.position.copy(home);
|
||||||
treeGroup.add(mesh);
|
treeGroup.add(mesh);
|
||||||
@@ -287,12 +285,21 @@ const basketApples = []; // apples caught and resting in the basket
|
|||||||
let basketCount = 0;
|
let basketCount = 0;
|
||||||
|
|
||||||
// ---------- leaves ----------
|
// ---------- leaves ----------
|
||||||
const leafGeo = new THREE.PlaneGeometry(0.14, 0.18);
|
const leafShape = new THREE.Shape();
|
||||||
|
leafShape.moveTo(0, -0.09);
|
||||||
|
leafShape.quadraticCurveTo(0.07, -0.04, 0.065, 0.03);
|
||||||
|
leafShape.quadraticCurveTo(0.05, 0.08, 0, 0.11);
|
||||||
|
leafShape.quadraticCurveTo(-0.05, 0.08, -0.065, 0.03);
|
||||||
|
leafShape.quadraticCurveTo(-0.07, -0.04, 0, -0.09);
|
||||||
|
const leafGeo = new THREE.ShapeGeometry(leafShape);
|
||||||
const leafMats = [0x4f9d6e, 0x3f8a5d, 0x5aab77].map(
|
const leafMats = [0x4f9d6e, 0x3f8a5d, 0x5aab77].map(
|
||||||
(c) => new THREE.MeshStandardMaterial({ color: c, roughness: 0.85, side: THREE.DoubleSide })
|
(c) => new THREE.MeshStandardMaterial({ color: c, roughness: 0.85, side: THREE.DoubleSide })
|
||||||
);
|
);
|
||||||
function createLeafMesh(){
|
function createLeafMesh(){
|
||||||
return new THREE.Mesh(leafGeo, leafMats[Math.floor(Math.random() * leafMats.length)]);
|
const mesh = new THREE.Mesh(leafGeo, leafMats[Math.floor(Math.random() * leafMats.length)]);
|
||||||
|
const s = 0.8 + Math.random() * 0.35;
|
||||||
|
mesh.scale.set(s, s, s);
|
||||||
|
return mesh;
|
||||||
}
|
}
|
||||||
const fallingLeaves = []; // falling | resting | vanishing
|
const fallingLeaves = []; // falling | resting | vanishing
|
||||||
|
|
||||||
@@ -379,7 +386,9 @@ function knockOffSquirrel(){
|
|||||||
const shadow = makeShadowBlob(0.55);
|
const shadow = makeShadowBlob(0.55);
|
||||||
scene.add(shadow);
|
scene.add(shadow);
|
||||||
|
|
||||||
const fleeAngle = Math.random() * Math.PI * 2;
|
// camera looks down roughly -Z, so world X is screen left/right — flee sideways
|
||||||
|
const fleeSign = Math.random() < 0.5 ? -1 : 1;
|
||||||
|
const fleeDir = new THREE.Vector3(fleeSign, 0, (Math.random() - 0.5) * 0.35).normalize();
|
||||||
fallingSquirrels.push({
|
fallingSquirrels.push({
|
||||||
mesh,
|
mesh,
|
||||||
shadow,
|
shadow,
|
||||||
@@ -388,7 +397,7 @@ function knockOffSquirrel(){
|
|||||||
0.6 + Math.random() * 0.4,
|
0.6 + Math.random() * 0.4,
|
||||||
(Math.random() - 0.5) * 1.2
|
(Math.random() - 0.5) * 1.2
|
||||||
),
|
),
|
||||||
fleeDir: new THREE.Vector3(Math.sin(fleeAngle), 0, Math.cos(fleeAngle)),
|
fleeDir,
|
||||||
state: 'falling',
|
state: 'falling',
|
||||||
timer: 0,
|
timer: 0,
|
||||||
});
|
});
|
||||||
@@ -485,6 +494,7 @@ function knockOffRandomApple(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function growSlotApple(slot){
|
function growSlotApple(slot){
|
||||||
|
slot.home = randomAppleHome();
|
||||||
const mesh = createAppleMesh();
|
const mesh = createAppleMesh();
|
||||||
mesh.position.copy(slot.home);
|
mesh.position.copy(slot.home);
|
||||||
mesh.scale.setScalar(0.001);
|
mesh.scale.setScalar(0.001);
|
||||||
|
|||||||
Reference in New Issue
Block a user