@@ -4,6 +4,7 @@ |
| 4 | 4 | import * as THREE from 'three' |
| 5 | 5 | |
| 6 | 6 | // Create a wooden dock |
| 7 | +// Dock protrudes into water - shore side at origin, water side extends in -Z direction |
| 7 | 8 | export function createDock(gradientMap) { |
| 8 | 9 | const group = new THREE.Group() |
| 9 | 10 | |
@@ -17,39 +18,67 @@ export function createDock(gradientMap) { |
| 17 | 18 | gradientMap |
| 18 | 19 | }) |
| 19 | 20 | |
| 20 | | - // Main platform |
| 21 | | - const platformGeom = new THREE.BoxGeometry(1.2, 0.08, 0.6) |
| 21 | + // Dock dimensions - extends into water |
| 22 | + const dockWidth = 0.8 |
| 23 | + const dockLength = 1.2 // How far it protrudes into water |
| 24 | + const dockHeight = 0.08 |
| 25 | + |
| 26 | + // Main platform - offset so shore edge is at z=0, water edge at z=-dockLength |
| 27 | + const platformGeom = new THREE.BoxGeometry(dockWidth, dockHeight, dockLength) |
| 22 | 28 | const platform = new THREE.Mesh(platformGeom, woodMaterial) |
| 23 | | - platform.position.y = 0.04 |
| 29 | + platform.position.set(0, 0.04, -dockLength / 2) |
| 24 | 30 | group.add(platform) |
| 25 | 31 | |
| 26 | | - // Planks (detail lines) |
| 27 | | - for (let i = 0; i < 5; i++) { |
| 28 | | - const plankGeom = new THREE.BoxGeometry(0.02, 0.09, 0.58) |
| 32 | + // Planks (crosswise detail lines) |
| 33 | + for (let i = 0; i < 6; i++) { |
| 34 | + const plankGeom = new THREE.BoxGeometry(dockWidth - 0.02, 0.09, 0.03) |
| 29 | 35 | const plank = new THREE.Mesh(plankGeom, darkWoodMaterial) |
| 30 | | - plank.position.set(-0.5 + i * 0.25, 0.045, 0) |
| 36 | + plank.position.set(0, 0.045, -0.1 - i * 0.2) |
| 31 | 37 | group.add(plank) |
| 32 | 38 | } |
| 33 | 39 | |
| 34 | | - // Support posts |
| 35 | | - const postGeom = new THREE.CylinderGeometry(0.04, 0.05, 0.4, 6) |
| 40 | + // Support posts - two at shore, two at water end |
| 41 | + const postGeom = new THREE.CylinderGeometry(0.05, 0.06, 0.5, 6) |
| 36 | 42 | const postPositions = [ |
| 37 | | - { x: -0.5, z: 0.25 }, |
| 38 | | - { x: -0.5, z: -0.25 }, |
| 39 | | - { x: 0.5, z: 0.25 }, |
| 40 | | - { x: 0.5, z: -0.25 } |
| 43 | + // Shore posts (shorter, above ground) |
| 44 | + { x: -dockWidth / 2 + 0.08, z: -0.1, height: 0.3, yOffset: -0.1 }, |
| 45 | + { x: dockWidth / 2 - 0.08, z: -0.1, height: 0.3, yOffset: -0.1 }, |
| 46 | + // Water posts (longer, go into water) |
| 47 | + { x: -dockWidth / 2 + 0.08, z: -dockLength + 0.15, height: 0.6, yOffset: -0.25 }, |
| 48 | + { x: dockWidth / 2 - 0.08, z: -dockLength + 0.15, height: 0.6, yOffset: -0.25 } |
| 41 | 49 | ] |
| 42 | 50 | |
| 43 | 51 | for (const pos of postPositions) { |
| 44 | | - const post = new THREE.Mesh(postGeom, darkWoodMaterial) |
| 45 | | - post.position.set(pos.x, -0.15, pos.z) |
| 52 | + const pGeom = new THREE.CylinderGeometry(0.05, 0.06, pos.height, 6) |
| 53 | + const post = new THREE.Mesh(pGeom, darkWoodMaterial) |
| 54 | + post.position.set(pos.x, pos.yOffset, pos.z) |
| 46 | 55 | group.add(post) |
| 47 | 56 | } |
| 48 | 57 | |
| 58 | + // Rope detail on water-end posts |
| 59 | + const ropeMaterial = new THREE.MeshToonMaterial({ |
| 60 | + color: 0x8b7355, |
| 61 | + gradientMap |
| 62 | + }) |
| 63 | + const ropeGeom = new THREE.TorusGeometry(0.06, 0.015, 6, 12) |
| 64 | + |
| 65 | + // Rope on left water post |
| 66 | + const ropeLeft = new THREE.Mesh(ropeGeom, ropeMaterial) |
| 67 | + ropeLeft.position.set(-dockWidth / 2 + 0.08, 0.08, -dockLength + 0.15) |
| 68 | + ropeLeft.rotation.x = Math.PI / 2 |
| 69 | + group.add(ropeLeft) |
| 70 | + |
| 71 | + // Rope on right water post |
| 72 | + const ropeRight = new THREE.Mesh(ropeGeom, ropeMaterial) |
| 73 | + ropeRight.position.set(dockWidth / 2 - 0.08, 0.08, -dockLength + 0.15) |
| 74 | + ropeRight.rotation.x = Math.PI / 2 |
| 75 | + group.add(ropeRight) |
| 76 | + |
| 49 | 77 | return group |
| 50 | 78 | } |
| 51 | 79 | |
| 52 | 80 | // Create a fishing hut |
| 81 | +// Hut sits on shore with front porch extending toward water (-Z direction) |
| 53 | 82 | export function createFishingHut(gradientMap) { |
| 54 | 83 | const group = new THREE.Group() |
| 55 | 84 | |
@@ -69,36 +98,64 @@ export function createFishingHut(gradientMap) { |
| 69 | 98 | opacity: 0.6 |
| 70 | 99 | }) |
| 71 | 100 | |
| 72 | | - // Base/floor |
| 73 | | - const baseGeom = new THREE.BoxGeometry(0.9, 0.06, 0.7) |
| 101 | + const darkWoodMaterial = new THREE.MeshToonMaterial({ |
| 102 | + color: 0x5c4a1a, |
| 103 | + gradientMap |
| 104 | + }) |
| 105 | + |
| 106 | + // Front porch/deck extending into water |
| 107 | + const porchGeom = new THREE.BoxGeometry(0.7, 0.06, 0.5) |
| 108 | + const porch = new THREE.Mesh(porchGeom, darkWoodMaterial) |
| 109 | + porch.position.set(0, 0.02, -0.25) |
| 110 | + group.add(porch) |
| 111 | + |
| 112 | + // Porch support posts (in water) |
| 113 | + const porchPostGeom = new THREE.CylinderGeometry(0.03, 0.04, 0.4, 6) |
| 114 | + const porchPosts = [ |
| 115 | + { x: -0.3, z: -0.45 }, |
| 116 | + { x: 0.3, z: -0.45 } |
| 117 | + ] |
| 118 | + for (const pos of porchPosts) { |
| 119 | + const post = new THREE.Mesh(porchPostGeom, darkWoodMaterial) |
| 120 | + post.position.set(pos.x, -0.15, pos.z) |
| 121 | + group.add(post) |
| 122 | + } |
| 123 | + |
| 124 | + // Main building base/floor - offset onto shore |
| 125 | + const baseGeom = new THREE.BoxGeometry(0.9, 0.08, 0.7) |
| 74 | 126 | const base = new THREE.Mesh(baseGeom, woodMaterial) |
| 75 | | - base.position.y = 0.03 |
| 127 | + base.position.set(0, 0.04, 0.35) |
| 76 | 128 | group.add(base) |
| 77 | 129 | |
| 78 | 130 | // Walls |
| 79 | 131 | const wallGeom = new THREE.BoxGeometry(0.85, 0.5, 0.65) |
| 80 | 132 | const walls = new THREE.Mesh(wallGeom, woodMaterial) |
| 81 | | - walls.position.y = 0.31 |
| 133 | + walls.position.set(0, 0.33, 0.35) |
| 82 | 134 | group.add(walls) |
| 83 | 135 | |
| 84 | 136 | // Roof |
| 85 | 137 | const roofGeom = new THREE.ConeGeometry(0.55, 0.35, 4) |
| 86 | 138 | const roof = new THREE.Mesh(roofGeom, roofMaterial) |
| 87 | | - roof.position.y = 0.73 |
| 139 | + roof.position.set(0, 0.75, 0.35) |
| 88 | 140 | roof.rotation.y = Math.PI / 4 |
| 89 | 141 | group.add(roof) |
| 90 | 142 | |
| 91 | | - // Window |
| 143 | + // Window (on side wall) |
| 92 | 144 | const windowGeom = new THREE.PlaneGeometry(0.15, 0.15) |
| 93 | 145 | const window1 = new THREE.Mesh(windowGeom, windowMaterial) |
| 94 | | - window1.position.set(0.43, 0.35, 0) |
| 146 | + window1.position.set(0.43, 0.37, 0.35) |
| 95 | 147 | window1.rotation.y = Math.PI / 2 |
| 96 | 148 | group.add(window1) |
| 97 | 149 | |
| 98 | | - // Door frame |
| 99 | | - const doorGeom = new THREE.BoxGeometry(0.02, 0.35, 0.2) |
| 100 | | - const door = new THREE.Mesh(doorGeom, roofMaterial) |
| 101 | | - door.position.set(0.43, 0.24, 0) |
| 150 | + // Door (facing water) |
| 151 | + const doorFrameGeom = new THREE.BoxGeometry(0.22, 0.35, 0.03) |
| 152 | + const doorFrame = new THREE.Mesh(doorFrameGeom, roofMaterial) |
| 153 | + doorFrame.position.set(0, 0.26, 0.03) |
| 154 | + group.add(doorFrame) |
| 155 | + |
| 156 | + const doorGeom = new THREE.BoxGeometry(0.18, 0.32, 0.02) |
| 157 | + const door = new THREE.Mesh(doorGeom, darkWoodMaterial) |
| 158 | + door.position.set(0, 0.24, 0.02) |
| 102 | 159 | group.add(door) |
| 103 | 160 | |
| 104 | 161 | return group |