| function buildGorillaCharacter(materials) { |
| const geos = getCharacterGeometry('gorilla'); |
| const group = new THREE.Group(); |
| const parts = {}; |
| parts.body = addPart(group, geos.body, materials.primary, 0, 0.72, 0, 'body'); |
| parts.chest = addPart(group, geos.chest, materials.secondary, 0, 0.67, 0.34, 'chest'); |
| parts.head = addPart(group, geos.head, materials.primary, 0, 1.38, 0.08, 'head'); |
| addPart(group, geos.brow, materials.primary, 0, 1.5, 0.28, 'brow'); |
| addPart(group, geos.muzzle, materials.secondary, 0, 1.24, 0.34, 'muzzle'); |
| addPart(group, geos.eye, materials.eye, -0.14, 1.33, 0.38, 'eye_l'); |
| addPart(group, geos.eye, materials.eye, 0.14, 1.33, 0.38, 'eye_r'); |
| parts.armL = addPart(group, geos.arm, materials.primary, -0.62, 0.48, 0.04, 'arm_l'); |
| parts.armR = addPart(group, geos.arm, materials.primary, 0.62, 0.48, 0.04, 'arm_r'); |
| parts.legL = addPart(group, geos.leg, materials.primary, -0.22, 0.18, 0, 'leg_l'); |
| parts.legR = addPart(group, geos.leg, materials.primary, 0.22, 0.18, 0, 'leg_r'); |
| group.userData.parts = parts; |
| return group; |
| } |
|
|
| function buildPandaCharacter(materials) { |
| const geos = getCharacterGeometry('panda'); |
| const group = new THREE.Group(); |
| const parts = {}; |
| parts.body = addPart(group, geos.body, materials.primary, 0, 0.72, 0, 'body'); |
| addPart(group, geos.belly, materials.secondary, 0, 0.66, 0.34, 'belly'); |
| parts.head = addPart(group, geos.head, materials.primary, 0, 1.36, 0.08, 'head'); |
| addPart(group, geos.ear, materials.secondary, -0.26, 1.68, 0.02, 'ear_l'); |
| addPart(group, geos.ear, materials.secondary, 0.26, 1.68, 0.02, 'ear_r'); |
| addPart(group, geos.snout, materials.secondary, 0, 1.24, 0.34, 'snout'); |
| addPart(group, geos.eye, materials.secondary, -0.16, 1.34, 0.36, 'eye_l'); |
| addPart(group, geos.eye, materials.secondary, 0.16, 1.34, 0.36, 'eye_r'); |
| parts.armL = addPart(group, geos.arm, materials.secondary, -0.52, 0.56, 0.02, 'arm_l'); |
| parts.armR = addPart(group, geos.arm, materials.secondary, 0.52, 0.56, 0.02, 'arm_r'); |
| parts.legL = addPart(group, geos.leg, materials.secondary, -0.2, 0.16, 0, 'leg_l'); |
| parts.legR = addPart(group, geos.leg, materials.secondary, 0.2, 0.16, 0, 'leg_r'); |
| parts.scarf = addPart(group, geos.scarf, materials.accent, 0, 1.02, 0.2, 'scarf'); |
| parts.scarfTail = addPart(group, geos.scarfTail, materials.accent, 0.22, 0.86, 0.22, 'scarf_tail'); |
| group.userData.parts = parts; |
| return group; |
| } |
|
|
| function buildChameleonCharacter(materials) { |
| const geos = getCharacterGeometry('chameleon'); |
| const group = new THREE.Group(); |
| const parts = {}; |
| parts.body = addPart(group, geos.body, materials.primary, 0, 0.62, 0, 'body'); |
| addPart(group, geos.belly, materials.secondary, 0, 0.58, 0.24, 'belly'); |
| parts.head = addPart(group, geos.head, materials.primary, 0, 1.12, 0.14, 'head'); |
| addPart(group, geos.crest, materials.accent, 0, 1.34, 0.06, 'crest'); |
| addPart(group, geos.eye, materials.eye, -0.12, 1.18, 0.28, 'eye_l'); |
| addPart(group, geos.eye, materials.eye, 0.12, 1.18, 0.28, 'eye_r'); |
| parts.armL = addPart(group, geos.arm, materials.primary, -0.42, 0.54, 0.06, 'arm_l'); |
| parts.armR = addPart(group, geos.arm, materials.primary, 0.42, 0.54, 0.06, 'arm_r'); |
| parts.legL = addPart(group, geos.leg, materials.primary, -0.16, 0.2, 0.06, 'leg_l'); |
| parts.legR = addPart(group, geos.leg, materials.primary, 0.16, 0.2, 0.06, 'leg_r'); |
| parts.tailBase = addPart(group, geos.tailBase, materials.secondary, 0, 0.64, -0.34, 'tail_base'); |
| parts.tailTip = addPart(group, geos.tailTip, materials.accent, 0, 0.64, -0.68, 'tail_tip'); |
| group.userData.parts = parts; |
| return group; |
| } |
|
|
| function buildBisonCharacter(materials) { |
| const geos = getCharacterGeometry('bison'); |
| const group = new THREE.Group(); |
| const parts = {}; |
| parts.body = addPart(group, geos.body, materials.primary, 0, 0.72, 0, 'body'); |
| parts.hump = addPart(group, geos.hump, materials.secondary, 0, 1.0, -0.1, 'hump'); |
| parts.head = addPart(group, geos.head, materials.secondary, 0, 1.2, 0.26, 'head'); |
| addPart(group, geos.muzzle, materials.accent, 0, 1.08, 0.48, 'muzzle'); |
| addPart(group, geos.eye, materials.eye, -0.14, 1.22, 0.42, 'eye_l'); |
| addPart(group, geos.eye, materials.eye, 0.14, 1.22, 0.42, 'eye_r'); |
| addPart(group, geos.horn, materials.accent, -0.22, 1.42, 0.24, 'horn_l', { rotation: { x: 0, y: 0, z: 0.4 } }); |
| addPart(group, geos.horn, materials.accent, 0.22, 1.42, 0.24, 'horn_r', { rotation: { x: 0, y: 0, z: -0.4 } }); |
| parts.armL = addPart(group, geos.arm, materials.primary, -0.46, 0.48, 0.08, 'arm_l'); |
| parts.armR = addPart(group, geos.arm, materials.primary, 0.46, 0.48, 0.08, 'arm_r'); |
| parts.legL = addPart(group, geos.leg, materials.primary, -0.22, 0.2, 0.04, 'leg_l'); |
| parts.legR = addPart(group, geos.leg, materials.primary, 0.22, 0.2, 0.04, 'leg_r'); |
| parts.beard = addPart(group, geos.beard, materials.dark, 0, 0.92, 0.42, 'beard'); |
| group.userData.parts = parts; |
| return group; |
| } |
|
|
| function buildSongoku() { |
| const group = new THREE.Group(); |
|
|
| |
| const legGeo = new THREE.BoxGeometry(0.22, 0.42, 0.24); |
| const legMat = createMaterial(PALETTE.martial_blue); |
| const legL = new THREE.Mesh(legGeo, legMat); |
| legL.position.set(-0.18, 0.21, 0); |
| group.add(legL); |
| const legR = new THREE.Mesh(legGeo, legMat); |
| legR.position.set(0.18, 0.21, 0); |
| group.add(legR); |
|
|
| |
| const bodyGeo = new THREE.BoxGeometry(1.0, 0.88, 0.62); |
| const bodyMat = createMaterial(PALETTE.gi_orange); |
| const giTex = makeSongokuGiTexture(); |
| bodyMat.map = giTex; |
| bodyMat.map.wrapS = THREE.RepeatWrapping; |
| bodyMat.map.wrapT = THREE.RepeatWrapping; |
| const body = new THREE.Mesh(bodyGeo, bodyMat); |
| body.position.set(0, 0.86, 0); |
| group.add(body); |
|
|
| |
| const armGeo = new THREE.BoxGeometry(0.16, 0.52, 0.18); |
| const armMat = createMaterial(PALETTE.gi_orange); |
| const armL = new THREE.Mesh(armGeo, armMat); |
| armL.position.set(-0.58, 0.92, 0); |
| group.add(armL); |
| const armR = new THREE.Mesh(armGeo, armMat); |
| armR.position.set(0.58, 0.92, 0); |
| group.add(armR); |
|
|
| |
| const wristGeo = new THREE.BoxGeometry(0.18, 0.12, 0.20); |
| const wristMat = createMaterial(PALETTE.martial_blue); |
| const wristL = new THREE.Mesh(wristGeo, wristMat); |
| wristL.position.set(-0.58, 0.62, 0); |
| group.add(wristL); |
| const wristR = new THREE.Mesh(wristGeo, wristMat); |
| wristR.position.set(0.58, 0.62, 0); |
| group.add(wristR); |
|
|
| |
| const headGeo = new THREE.BoxGeometry(0.68, 0.52, 0.56); |
| const headMat = createMaterial(PALETTE.skin_tan); |
| const head = new THREE.Mesh(headGeo, headMat); |
| head.position.set(0, 1.60, 0.04); |
| group.add(head); |
|
|
| |
| const hairMainGeo = new THREE.BoxGeometry(0.76, 0.34, 0.60); |
| const hairMat = createMaterial(PALETTE.dark_black); |
| const hairTex = makeSongokuHairTexture(); |
| hairMat.map = hairTex; |
| hairMat.map.wrapS = THREE.RepeatWrapping; |
| hairMat.map.wrapT = THREE.RepeatWrapping; |
| const hairMain = new THREE.Mesh(hairMainGeo, hairMat); |
| hairMain.position.set(0, 1.97, -0.02); |
| group.add(hairMain); |
|
|
| |
| const hairSpikeGeo = new THREE.BoxGeometry(0.22, 0.28, 0.18); |
| const hairSpikeL = new THREE.Mesh(hairSpikeGeo, hairMat); |
| hairSpikeL.position.set(-0.24, 2.24, -0.08); |
| group.add(hairSpikeL); |
| const hairSpikeR = new THREE.Mesh(hairSpikeGeo, hairMat); |
| hairSpikeR.position.set(0.24, 2.20, -0.04); |
| group.add(hairSpikeR); |
|
|
| |
| const eyeGeo = new THREE.BoxGeometry(0.09, 0.09, 0.08); |
| const eyeMat = createMaterial(PALETTE.black); |
| const eyeL = new THREE.Mesh(eyeGeo, eyeMat); |
| eyeL.position.set(-0.14, 1.62, 0.28); |
| group.add(eyeL); |
| const eyeR = new THREE.Mesh(eyeGeo, eyeMat); |
| eyeR.position.set(0.14, 1.62, 0.28); |
| group.add(eyeR); |
|
|
| return group; |
| } |
|
|
| function buildFallenLog() { |
| const group = new THREE.Group(); |
|
|
| |
| const bodyGeo = new THREE.BoxGeometry(2.2, 0.48, 0.62); |
| const bodyMat = createMaterial(PALETTE.brown_dark); |
| const body = new THREE.Mesh(bodyGeo, bodyMat); |
| body.position.set(0, 0.24, 0); |
| group.add(body); |
|
|
| |
| const capGeo = new THREE.BoxGeometry(0.18, 0.40, 0.54); |
| const capMat = createMaterial(PALETTE.brown_darker); |
| const capL = new THREE.Mesh(capGeo, capMat); |
| capL.position.set(-1.01, 0.24, 0); |
| group.add(capL); |
| const capR = new THREE.Mesh(capGeo, capMat); |
| capR.position.set(1.01, 0.24, 0); |
| group.add(capR); |
|
|
| return group; |
| } |
|
|
| function buildSaiyanPod() { |
| const group = new THREE.Group(); |
|
|
| |
| const bodyLowerGeo = new THREE.BoxGeometry(1.0, 0.52, 0.90); |
| const bodyMat = createMaterial(PALETTE.purple_dark); |
| const bodyLower = new THREE.Mesh(bodyLowerGeo, bodyMat); |
| bodyLower.position.set(0, 0.76, 0); |
| group.add(bodyLower); |
|
|
| |
| const bodyUpperGeo = new THREE.BoxGeometry(0.82, 0.34, 0.74); |
| const bodyUpperMat = createMaterial(PALETTE.purple_mid); |
| const bodyUpper = new THREE.Mesh(bodyUpperGeo, bodyUpperMat); |
| bodyUpper.position.set(0, 1.19, 0); |
| group.add(bodyUpper); |
|
|
| |
| const finGeo = new THREE.BoxGeometry(0.14, 0.30, 0.42); |
| const finMat = createMaterial(PALETTE.purple_mid); |
| const finL = new THREE.Mesh(finGeo, finMat); |
| finL.position.set(-0.57, 0.88, 0); |
| group.add(finL); |
| const finR = new THREE.Mesh(finGeo, finMat); |
| finR.position.set(0.57, 0.88, 0); |
| group.add(finR); |
|
|
| |
| const windowGeo = new THREE.BoxGeometry(0.42, 0.24, 0.12); |
| const windowMat = createMaterial(PALETTE.threat_red_violet); |
| const window = new THREE.Mesh(windowGeo, windowMat); |
| window.position.set(0, 0.96, 0.51); |
| group.add(window); |
|
|
| return group; |
| } |
|
|
| function buildDragonBall() { |
| const group = new THREE.Group(); |
|
|
| |
| const orbBottomGeo = new THREE.BoxGeometry(0.34, 0.12, 0.34); |
| const orbMat = createMaterial(PALETTE.gold_bright); |
| const orbBottom = new THREE.Mesh(orbBottomGeo, orbMat); |
| orbBottom.position.set(0, 0.06, 0); |
| group.add(orbBottom); |
|
|
| |
| const orbMiddleGeo = new THREE.BoxGeometry(0.42, 0.28, 0.42); |
| const orbMiddle = new THREE.Mesh(orbMiddleGeo, orbMat); |
| orbMiddle.position.set(0, 0.26, 0); |
| group.add(orbMiddle); |
|
|
| |
| const orbTopGeo = new THREE.BoxGeometry(0.34, 0.12, 0.34); |
| const orbTop = new THREE.Mesh(orbTopGeo, orbMat); |
| orbTop.position.set(0, 0.46, 0); |
| group.add(orbTop); |
|
|
| |
| const starGeo = new THREE.PlaneGeometry(0.12, 0.12); |
| const starMat = createMaterial(PALETTE.threat_red_violet); |
| const star = new THREE.Mesh(starGeo, starMat); |
| star.position.set(0, 0.26, 0.211); |
| star.rotation.z = Math.PI / 4; |
| group.add(star); |
|
|
| return group; |
| } |
|
|
| function buildWastelandTile() { |
| const group = new THREE.Group(); |
|
|
| |
| const baseTex = makeWastelandTileTexture(); |
| const baseGeo = new THREE.BoxGeometry(1.0, 0.20, 1.0); |
| const baseMat = createMaterial(PALETTE.stone_tan); |
| baseMat.map = baseTex; |
| baseMat.map.wrapS = THREE.RepeatWrapping; |
| baseMat.map.wrapT = THREE.RepeatWrapping; |
| const base = new THREE.Mesh(baseGeo, baseMat); |
| base.position.set(0, 0.10, 0); |
| group.add(base); |
|
|
| |
| const highlightGeo = new THREE.BoxGeometry(0.96, 0.10, 0.96); |
| const highlightMat = createMaterial(PALETTE.warm_sand); |
| const highlight = new THREE.Mesh(highlightGeo, highlightMat); |
| highlight.position.set(0, 0.25, 0); |
| group.add(highlight); |
|
|
| return group; |
| } |
|
|
| function buildTournamentWall() { |
| const group = new THREE.Group(); |
|
|
| |
| const wallTex = makeTournamentWallTexture(); |
| const wallGeo = new THREE.BoxGeometry(4.0, 1.60, 0.50); |
| const wallMat = createMaterial(PALETTE.warm_sand); |
| wallMat.map = wallTex; |
| wallMat.map.wrapS = THREE.RepeatWrapping; |
| wallMat.map.wrapT = THREE.RepeatWrapping; |
| const wall = new THREE.Mesh(wallGeo, wallMat); |
| wall.position.set(0, 0.80, -14.00); |
| group.add(wall); |
|
|
| |
| const roofGeo = new THREE.BoxGeometry(4.2, 0.14, 0.70); |
| const roofMat = createMaterial(PALETTE.brown_dark); |
| const roof = new THREE.Mesh(roofGeo, roofMat); |
| roof.position.set(0, 1.67, -14.00); |
| group.add(roof); |
|
|
| return group; |
| } |
|
|
| function buildStoneMarker() { |
| const group = new THREE.Group(); |
|
|
| |
| const baseTex = makeStoneMarkerTexture(); |
| const baseGeo = new THREE.BoxGeometry(0.52, 0.34, 0.52); |
| const baseMat = createMaterial(PALETTE.stone_tan); |
| baseMat.map = baseTex; |
| baseMat.map.wrapS = THREE.RepeatWrapping; |
| baseMat.map.wrapT = THREE.RepeatWrapping; |
| const base = new THREE.Mesh(baseGeo, baseMat); |
| base.position.set(3.50, 0.17, 0); |
| group.add(base); |
|
|
| |
| const topGeo = new THREE.BoxGeometry(0.34, 0.42, 0.34); |
| const topMat = createMaterial(PALETTE.brown_dark); |
| const top = new THREE.Mesh(topGeo, topMat); |
| top.position.set(3.50, 0.55, 0); |
| group.add(top); |
|
|
| return group; |
| } |
|
|
| function buildKiOrb() { |
| const group = new THREE.Group(); |
|
|
| |
| const coreTex = makeKiOrbTexture(); |
| const coreGeo = new THREE.BoxGeometry(0.28, 0.28, 0.28); |
| const coreMat = createMaterial(PALETTE.sky_blue); |
| coreMat.map = coreTex; |
| coreMat.map.wrapS = THREE.RepeatWrapping; |
| coreMat.map.wrapT = THREE.RepeatWrapping; |
| const core = new THREE.Mesh(coreGeo, coreMat); |
| core.position.set(0, 0.14, 0); |
| group.add(core); |
|
|
| |
| const glowGeo = new THREE.BoxGeometry(0.40, 0.40, 0.40); |
| const glowMat = createMaterial(PALETTE.martial_blue); |
| const glow = new THREE.Mesh(glowGeo, glowMat); |
| glow.position.set(0, 0.14, 0); |
| group.add(glow); |
|
|
| return group; |
| } |
|
|
| function buildDistantButte() { |
| const group = new THREE.Group(); |
|
|
| |
| const baseTex = makeDistantButteTexture(); |
| const baseGeo = new THREE.BoxGeometry(4.8, 1.6, 3.6); |
| const baseMat = createMaterial(PALETTE.brown_dark); |
| baseMat.map = baseTex; |
| baseMat.map.wrapS = THREE.RepeatWrapping; |
| baseMat.map.wrapT = THREE.RepeatWrapping; |
| const base = new THREE.Mesh(baseGeo, baseMat); |
| base.position.set(0, 0.80, -30.00); |
| group.add(base); |
|
|
| |
| const midGeo = new THREE.BoxGeometry(4.1, 1.2, 3.0); |
| const midMat = createMaterial(PALETTE.stone_tan); |
| const mid = new THREE.Mesh(midGeo, midMat); |
| mid.position.set(0.10, 2.20, -30.10); |
| group.add(mid); |
|
|
| |
| const topGeo = new THREE.BoxGeometry(3.3, 0.9, 2.4); |
| const top = new THREE.Mesh(topGeo, midMat); |
| top.position.set(-0.06, 3.25, -29.95); |
| group.add(top); |
|
|
| |
| const capGeo = new THREE.BoxGeometry(2.7, 0.14, 1.9); |
| const capMat = createMaterial(PALETTE.warm_sand); |
| const cap = new THREE.Mesh(capGeo, capMat); |
| cap.position.set(-0.02, 3.77, -29.88); |
| group.add(cap); |
|
|
| return group; |
| } |
|
|
| function buildShowcase() { |
| |
| if (gameState.hero) { |
| scene.remove(gameState.hero); |
| } |
| gameState.hero = buildSongoku(); |
| gameState.hero.position.set(0, 1.8, 0); |
| scene.add(gameState.hero); |
|
|
| |
| const pedestalGeo = new THREE.BoxGeometry(1.8, 0.18, 1.8); |
| const pedestalMat = createMaterial(PALETTE.stone_tan); |
| const pedestal = new THREE.Mesh(pedestalGeo, pedestalMat); |
| pedestal.position.set(0, 0.09, 0); |
| pedestal.name = 'pedestal'; |
| scene.add(pedestal); |
|
|
| |
| camera.position.copy(CAMERA_SHOWCASE.position); |
| camera.lookAt(CAMERA_SHOWCASE.lookAt); |
|
|
| |
| gameState.score = 0; |
| gameState.distance = 0; |
| gameState.scrollSpeed = SCROLL.initial; |
| gameState.elapsedTime = 0; |
| gameState.heroVelocityY = 0; |
| gameState.heroLane = 0; |
| gameState.obstacles = []; |
| gameState.collectibles = []; |
| gameState.spawnTimer = 0; |
|
|
| updateHUD(); |
| } |
|
|
| function buildRaticate(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.70,0.50,0.80,'#c8a87a',0,0.25,0);p(0.58,0.28,0.30,'#c8a87a',0,0.42,-0.28); |
| p(0.48,0.28,0.58,'#f5f0e8',0,0.22,0.30);p(0.58,0.48,0.52,'#c8a87a',0,0.62,0.22); |
| p(0.40,0.18,0.26,'#c8a87a',0,0.52,0.48); |
| p(0.09,0.22,0.06,'#f8f8f8',-0.07,0.54,0.61);p(0.09,0.22,0.06,'#f8f8f8',0.07,0.54,0.61); |
| p(0.14,0.13,0.05,'#f8f8f8',-0.17,0.71,0.46);p(0.08,0.08,0.04,'#1a1a1a',-0.17,0.71,0.49); |
| p(0.14,0.13,0.05,'#f8f8f8',0.17,0.71,0.46);p(0.08,0.08,0.04,'#1a1a1a',0.17,0.71,0.49); |
| p(0.12,0.24,0.08,'#c8a87a',-0.26,0.87,0.18);p(0.08,0.16,0.05,'#e8c8b0',-0.26,0.87,0.21); |
| p(0.12,0.24,0.08,'#c8a87a',0.26,0.87,0.18);p(0.08,0.16,0.05,'#e8c8b0',0.26,0.87,0.21); |
| p(0.18,0.02,0.02,'#1a1a1a',-0.27,0.59,0.56);p(0.18,0.02,0.02,'#1a1a1a',-0.27,0.54,0.56); |
| p(0.18,0.02,0.02,'#1a1a1a',0.27,0.59,0.56);p(0.18,0.02,0.02,'#1a1a1a',0.27,0.54,0.56); |
| p(0.14,0.30,0.14,'#c8a87a',-0.32,0.08,0.24);p(0.14,0.30,0.14,'#c8a87a',0.32,0.08,0.24); |
| p(0.16,0.32,0.16,'#c8a87a',-0.30,0.08,-0.22);p(0.16,0.32,0.16,'#c8a87a',0.30,0.08,-0.22); |
| p(0.10,0.10,0.30,'#c8a87a',0,0.20,-0.55);p(0.08,0.08,0.22,'#c8a87a',0,0.30,-0.74);p(0.06,0.06,0.16,'#c8a87a',0,0.38,-0.88); |
| return g; |
| } |
|
|
| function buildPersian(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.58,0.40,0.88,'#c8c8d4',0,0.20,0);p(0.38,0.24,0.68,'#e8e8f0',0,0.18,0.10); |
| p(0.28,0.22,0.26,'#c8c8d4',0,0.43,0.36);p(0.58,0.50,0.48,'#c8c8d4',0,0.68,0.28); |
| p(0.20,0.28,0.26,'#c8c8d4',-0.30,0.64,0.26);p(0.20,0.28,0.26,'#c8c8d4',0.30,0.64,0.26); |
| p(0.26,0.14,0.20,'#d8d8e4',0,0.60,0.50);p(0.12,0.12,0.06,'#e05050',0,0.75,0.52); |
| p(0.14,0.08,0.06,'#1a1a1a',-0.17,0.75,0.51);p(0.06,0.05,0.04,'#f8f8f8',-0.17,0.76,0.54); |
| p(0.14,0.08,0.06,'#1a1a1a',0.17,0.75,0.51);p(0.06,0.05,0.04,'#f8f8f8',0.17,0.76,0.54); |
| p(0.11,0.20,0.08,'#c8c8d4',-0.25,0.94,0.26);p(0.07,0.13,0.05,'#e8a8a8',-0.25,0.94,0.29); |
| p(0.11,0.20,0.08,'#c8c8d4',0.25,0.94,0.26);p(0.07,0.13,0.05,'#e8a8a8',0.25,0.94,0.29); |
| p(0.22,0.02,0.02,'#1a1a1a',-0.32,0.64,0.50);p(0.22,0.02,0.02,'#1a1a1a',-0.32,0.60,0.50); |
| p(0.22,0.02,0.02,'#1a1a1a',0.32,0.64,0.50);p(0.22,0.02,0.02,'#1a1a1a',0.32,0.60,0.50); |
| p(0.13,0.32,0.13,'#c8c8d4',-0.24,0.13,0.32);p(0.13,0.32,0.13,'#c8c8d4',0.24,0.13,0.32); |
| p(0.15,0.34,0.15,'#c8c8d4',-0.22,0.13,-0.28);p(0.15,0.34,0.15,'#c8c8d4',0.22,0.13,-0.28); |
| p(0.08,0.08,0.26,'#c8c8d4',0,0.18,-0.56);p(0.08,0.18,0.10,'#c8c8d4',0,0.28,-0.70);p(0.10,0.14,0.08,'#c8c8d4',0,0.36,-0.76); |
| return g; |
| } |
|
|
| function buildTauros(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.88,0.56,0.96,'#8b6914',0,0.30,-0.08);p(0.76,0.42,0.28,'#8b6914',0,0.36,0.32); |
| p(0.44,0.34,0.34,'#8b6914',0,0.56,0.48);p(0.68,0.52,0.50,'#8b6914',0,0.80,0.46); |
| p(0.48,0.28,0.26,'#d0b860',0,0.70,0.72);p(0.22,0.06,0.06,'#c8c8c8',0,0.66,0.88); |
| p(0.09,0.08,0.05,'#1a1a1a',-0.13,0.70,0.86);p(0.09,0.08,0.05,'#1a1a1a',0.13,0.70,0.86); |
| p(0.13,0.13,0.06,'#1a1a1a',-0.29,0.92,0.68);p(0.13,0.13,0.06,'#1a1a1a',0.29,0.92,0.68); |
| p(0.14,0.12,0.12,'#d0b860',-0.32,1.06,0.42);p(0.08,0.08,0.26,'#d0b860',-0.36,1.14,0.24); |
| p(0.14,0.12,0.12,'#d0b860',0.32,1.06,0.42);p(0.08,0.08,0.26,'#d0b860',0.36,1.14,0.24); |
| p(0.20,0.28,0.20,'#8b6914',-0.33,0.14,0.30);p(0.20,0.10,0.22,'#1a1a1a',-0.33,-0.14,0.30); |
| p(0.20,0.28,0.20,'#8b6914',0.33,0.14,0.30);p(0.20,0.10,0.22,'#1a1a1a',0.33,-0.14,0.30); |
| p(0.22,0.30,0.22,'#8b6914',-0.31,0.14,-0.34);p(0.22,0.10,0.24,'#1a1a1a',-0.31,-0.14,-0.34); |
| p(0.22,0.30,0.22,'#8b6914',0.31,0.14,-0.34);p(0.22,0.10,0.24,'#1a1a1a',0.31,-0.14,-0.34); |
| p(0.06,0.06,0.34,'#8b6914',-0.11,0.23,-0.60);p(0.06,0.06,0.34,'#8b6914',0,0.28,-0.60);p(0.06,0.06,0.34,'#8b6914',0.11,0.23,-0.60); |
| p(0.20,0.16,0.08,'#1a1a1a',0,0.30,-0.80); |
| return g; |
| } |
|
|
| function buildSnorlax(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.42,0.14,0.46,'#6080a0',-0.40,0.07,0.08);p(0.42,0.14,0.46,'#6080a0',0.40,0.07,0.08); |
| p(0.36,0.40,0.32,'#6080a0',-0.38,0.34,0.06);p(0.36,0.40,0.32,'#6080a0',0.38,0.34,0.06); |
| p(1.36,0.68,1.08,'#6080a0',0,0.72,0);p(1.16,0.56,0.94,'#6080a0',0,1.22,0); |
| p(0.88,0.84,0.28,'#e8d8b0',0,0.82,0.50);p(0.70,0.42,0.22,'#e8d8b0',0,1.30,0.44); |
| p(0.28,0.38,0.26,'#6080a0',-0.74,1.14,0.08);p(0.24,0.30,0.24,'#6080a0',-0.76,0.80,0.10); |
| p(0.30,0.22,0.28,'#6080a0',-0.78,0.62,0.08);p(0.10,0.10,0.14,'#6080a0',-0.86,0.57,0.14);p(0.10,0.10,0.14,'#6080a0',-0.70,0.57,0.14); |
| p(0.28,0.38,0.26,'#6080a0',0.74,1.14,0.08);p(0.24,0.30,0.24,'#6080a0',0.76,0.80,0.10); |
| p(0.30,0.22,0.28,'#6080a0',0.78,0.62,0.08);p(0.10,0.10,0.14,'#6080a0',0.86,0.57,0.14);p(0.10,0.10,0.14,'#6080a0',0.70,0.57,0.14); |
| p(0.54,0.22,0.50,'#6080a0',0,1.60,0.02);p(0.98,0.70,0.76,'#6080a0',0,1.94,0); |
| p(0.78,0.26,0.58,'#6080a0',0,2.26,0); |
| p(0.34,0.28,0.28,'#8098b0',-0.48,1.86,0.26);p(0.34,0.28,0.28,'#8098b0',0.48,1.86,0.26); |
| p(0.28,0.07,0.07,'#1a1a1a',-0.28,2.04,0.36);p(0.28,0.07,0.07,'#1a1a1a',0.28,2.04,0.36); |
| p(0.34,0.07,0.07,'#1a1a1a',0,1.86,0.38); |
| p(0.17,0.26,0.13,'#8098b0',-0.50,2.20,-0.02);p(0.17,0.26,0.13,'#8098b0',0.50,2.20,-0.02); |
| return g; |
| } |
|
|
| function buildGraveler(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(1.00,0.90,0.90,'#808080',0,0.46,0);p(0.84,0.28,0.74,'#808080',0,0.93,0); |
| p(0.22,0.60,0.60,'#606060',-0.56,0.46,0);p(0.22,0.60,0.60,'#606060',0.56,0.46,0); |
| p(0.18,0.14,0.16,'#404040',-0.42,0.78,-0.22);p(0.14,0.12,0.14,'#404040',-0.30,0.86,0.28); |
| p(0.18,0.14,0.16,'#404040',0.42,0.78,-0.22);p(0.14,0.12,0.14,'#404040',0.30,0.86,0.28); |
| p(0.18,0.16,0.06,'#f0f0f0',-0.22,0.64,0.44);p(0.10,0.10,0.05,'#e83030',-0.22,0.64,0.47); |
| p(0.18,0.16,0.06,'#f0f0f0',0.22,0.64,0.44);p(0.10,0.10,0.05,'#e83030',0.22,0.64,0.47); |
| p(0.22,0.08,0.06,'#404040',-0.22,0.74,0.44);p(0.22,0.08,0.06,'#404040',0.22,0.74,0.44); |
| p(0.20,0.14,0.18,'#808080',-0.62,0.70,0.16);p(0.22,0.18,0.20,'#404040',-0.88,0.52,0.22); |
| p(0.20,0.14,0.18,'#808080',0.62,0.70,0.16);p(0.22,0.18,0.20,'#404040',0.88,0.52,0.22); |
| p(0.20,0.12,0.18,'#808080',-0.58,0.28,0.18);p(0.22,0.16,0.20,'#404040',-0.84,0.10,0.24); |
| p(0.20,0.12,0.18,'#808080',0.58,0.28,0.18);p(0.22,0.16,0.20,'#404040',0.84,0.10,0.24); |
| p(0.26,0.22,0.28,'#808080',-0.28,0.08,0.04);p(0.26,0.22,0.28,'#808080',0.28,0.08,0.04); |
| return g; |
| } |
|
|
| function buildOnix(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| const sc=[1.0,0.88,0.76,0.64,0.52],zs=[0,-1.8,-3.6,-5.4,-7.2]; |
| for(let i=0;i<5;i++){ |
| const s=sc[i],z=zs[i]; |
| p(0.90*s,0.70*s,1.20*s,'#909090',0,0.37*s,z); |
| p(0.22*s,0.22*s,0.22*s,'#707070',-0.42*s,0.52*s,z);p(0.22*s,0.22*s,0.22*s,'#707070',0.42*s,0.52*s,z); |
| p(0.18*s,0.30*s,0.18*s,'#505050',0,0.80*s,z); |
| p(0.14*s,0.12*s,0.14*s,'#707070',-0.30*s,0.66*s,z+0.20*s);p(0.14*s,0.12*s,0.14*s,'#707070',0.30*s,0.66*s,z-0.20*s); |
| } |
| p(0.12,0.12,0.06,'#e8e060',-0.22,0.54,0.58);p(0.12,0.12,0.06,'#e8e060',0.22,0.54,0.58); |
| return g; |
| } |
|
|
| function buildZubat(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.48,0.46,0.36,'#9060c0',0,0.24,0);p(0.36,0.20,0.26,'#7040b0',0,0.06,0.04); |
| p(0.10,0.24,0.08,'#9060c0',-0.20,0.52,0);p(0.06,0.16,0.05,'#d090f8',-0.20,0.52,0.03); |
| p(0.10,0.24,0.08,'#9060c0',0.20,0.52,0);p(0.06,0.16,0.05,'#d090f8',0.20,0.52,0.03); |
| p(0.40,0.14,0.10,'#e83060',0,0.14,0.20);p(0.30,0.08,0.06,'#1a1a1a',0,0.14,0.24); |
| p(0.06,0.10,0.06,'#f8f8f8',-0.08,0.09,0.22);p(0.06,0.10,0.06,'#f8f8f8',0.08,0.09,0.22); |
| p(0.26,0.10,0.52,'#7040b0',-0.34,0.30,0);p(0.44,0.08,0.60,'#7040b0',-0.70,0.24,0);p(0.36,0.06,0.44,'#604090',-1.04,0.18,0); |
| p(0.26,0.10,0.52,'#7040b0',0.34,0.30,0);p(0.44,0.08,0.60,'#7040b0',0.70,0.24,0);p(0.36,0.06,0.44,'#604090',1.04,0.18,0); |
| p(0.08,0.06,0.46,'#8050b0',-0.54,0.28,-0.06);p(0.08,0.06,0.40,'#8050b0',-0.88,0.22,-0.04); |
| p(0.08,0.06,0.46,'#8050b0',0.54,0.28,-0.06);p(0.08,0.06,0.40,'#8050b0',0.88,0.22,-0.04); |
| p(0.16,0.08,0.08,'#1a1a1a',-0.18,0.02,0.04);p(0.16,0.08,0.08,'#1a1a1a',0.18,0.02,0.04); |
| p(0.06,0.04,0.12,'#1a1a1a',-0.22,0.00,0.10);p(0.06,0.04,0.12,'#1a1a1a',0.22,0.00,0.10); |
| return g; |
| } |
|
|
| function buildGolbat(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.60,0.50,0.42,'#7040b0',0,0.26,0);p(0.44,0.18,0.30,'#5a3090',0,0.06,0); |
| p(0.60,0.44,0.44,'#7040b0',0,0.60,0); |
| p(0.72,0.30,0.12,'#e83060',0,0.52,0.24);p(0.64,0.22,0.08,'#1a1a1a',0,0.52,0.28); |
| p(0.08,0.16,0.07,'#f8f8f8',-0.22,0.60,0.30);p(0.08,0.16,0.07,'#f8f8f8',0.22,0.60,0.30); |
| p(0.08,0.12,0.07,'#f8f8f8',-0.14,0.43,0.30);p(0.08,0.12,0.07,'#f8f8f8',0.14,0.43,0.30); |
| p(0.30,0.08,0.08,'#e83060',0,0.49,0.32); |
| p(0.12,0.26,0.08,'#7040b0',-0.26,0.82,0);p(0.12,0.26,0.08,'#7040b0',0.26,0.82,0); |
| p(0.12,0.10,0.05,'#e83060',-0.20,0.70,0.21);p(0.12,0.10,0.05,'#e83060',0.20,0.70,0.21); |
| p(0.30,0.10,0.64,'#8050c0',-0.42,0.34,0);p(0.54,0.08,0.74,'#6040a0',-0.84,0.26,0);p(0.42,0.06,0.56,'#5030a0',-1.18,0.18,0); |
| p(0.30,0.10,0.64,'#8050c0',0.42,0.34,0);p(0.54,0.08,0.74,'#6040a0',0.84,0.26,0);p(0.42,0.06,0.56,'#5030a0',1.18,0.18,0); |
| p(0.08,0.06,0.62,'#9060c0',-0.66,0.30,-0.05);p(0.08,0.06,0.62,'#9060c0',0.66,0.30,-0.05); |
| p(0.06,0.04,0.14,'#1a1a1a',-0.20,0.00,0.11);p(0.06,0.04,0.14,'#1a1a1a',0.20,0.00,0.11); |
| return g; |
| } |
|
|
| function buildPidgey(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.44,0.42,0.60,'#c09060',0,0.22,0);p(0.30,0.30,0.44,'#e8d8b0',0,0.20,0.20); |
| p(0.44,0.40,0.40,'#c09060',0,0.56,0.14);p(0.36,0.16,0.32,'#a07040',0,0.74,0.10); |
| p(0.08,0.14,0.06,'#1a1a1a',0,0.88,0.06); |
| p(0.10,0.08,0.22,'#e8c040',0,0.54,0.38);p(0.08,0.06,0.18,'#1a1a1a',0,0.49,0.38); |
| p(0.10,0.10,0.05,'#1a1a1a',-0.16,0.62,0.34);p(0.05,0.05,0.04,'#f8f8f8',-0.16,0.63,0.37); |
| p(0.10,0.10,0.05,'#1a1a1a',0.16,0.62,0.34);p(0.05,0.05,0.04,'#f8f8f8',0.16,0.63,0.37); |
| p(0.08,0.32,0.56,'#a07040',-0.30,0.26,0);p(0.06,0.22,0.42,'#906030',-0.46,0.20,-0.18); |
| p(0.08,0.32,0.56,'#a07040',0.30,0.26,0);p(0.06,0.22,0.42,'#906030',0.46,0.20,-0.18); |
| p(0.24,0.14,0.26,'#a07040',0,0.22,-0.38); |
| p(0.08,0.10,0.18,'#906030',-0.10,0.20,-0.52);p(0.08,0.10,0.18,'#906030',0.10,0.20,-0.52); |
| p(0.08,0.22,0.08,'#e8c040',-0.12,0.04,0.20);p(0.08,0.22,0.08,'#e8c040',0.12,0.04,0.20); |
| p(0.14,0.04,0.08,'#e8c040',-0.18,0.00,0.26);p(0.14,0.04,0.08,'#e8c040',0.06,0.00,0.24); |
| p(0.14,0.04,0.08,'#e8c040',0.18,0.00,0.26);p(0.14,0.04,0.08,'#e8c040',-0.06,0.00,0.24); |
| return g; |
| } |
|
|
| function buildFearow(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.54,0.48,0.72,'#c06030',0,0.24,0);p(0.36,0.30,0.52,'#e8d0a0',0,0.22,0.18); |
| p(0.24,0.40,0.22,'#c06030',0,0.58,0.22);p(0.40,0.36,0.36,'#c06030',0,0.78,0.18); |
| p(0.08,0.08,0.54,'#f0c040',0,0.78,0.50);p(0.06,0.06,0.46,'#1a1a1a',0,0.74,0.50); |
| p(0.12,0.22,0.10,'#c06030',0,0.96,0.14);p(0.08,0.14,0.06,'#e8d0a0',0.04,1.08,0.12); |
| p(0.10,0.10,0.05,'#1a1a1a',-0.16,0.82,0.36);p(0.14,0.14,0.04,'#f0d080',-0.16,0.82,0.34); |
| p(0.10,0.10,0.05,'#1a1a1a',0.16,0.82,0.36);p(0.14,0.14,0.04,'#f0d080',0.16,0.82,0.34); |
| p(0.10,0.38,0.68,'#c06030',-0.36,0.28,-0.02);p(0.08,0.28,0.54,'#a04820',-0.60,0.22,-0.12);p(0.06,0.18,0.38,'#804010',-0.78,0.16,-0.22); |
| p(0.10,0.38,0.68,'#c06030',0.36,0.28,-0.02);p(0.08,0.28,0.54,'#a04820',0.60,0.22,-0.12);p(0.06,0.18,0.38,'#804010',0.78,0.16,-0.22); |
| p(0.06,0.06,0.44,'#904020',-0.46,0.14,-0.20);p(0.06,0.06,0.44,'#904020',0.46,0.14,-0.20); |
| p(0.28,0.16,0.32,'#c06030',0,0.22,-0.48); |
| p(0.08,0.10,0.24,'#a04820',-0.12,0.20,-0.62);p(0.08,0.10,0.24,'#a04820',0.12,0.20,-0.62); |
| p(0.08,0.24,0.08,'#f0c040',-0.12,0.04,0.28);p(0.08,0.24,0.08,'#f0c040',0.12,0.04,0.28); |
| p(0.24,0.06,0.18,'#f0c040',0,0.01,0.32); |
| return g; |
| } |
|
|
| function buildBeedrill(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.26,0.46,0.30,'#f8d840',0,0.36,0);p(0.28,0.10,0.32,'#1a1a1a',0,0.52,0); |
| p(0.22,0.64,0.22,'#f8d840',0,0.34,-0.38); |
| p(0.24,0.10,0.24,'#1a1a1a',0,0.18,-0.36);p(0.24,0.10,0.24,'#1a1a1a',0,0.44,-0.44); |
| p(0.14,0.18,0.14,'#f8d840',0,0.10,-0.60);p(0.06,0.06,0.22,'#1a1a1a',0,0.06,-0.74); |
| p(0.30,0.28,0.28,'#f8d840',0,0.68,0.12); |
| p(0.14,0.18,0.08,'#e83060',-0.12,0.70,0.24);p(0.06,0.07,0.05,'#f8f8f8',-0.12,0.72,0.27); |
| p(0.14,0.18,0.08,'#e83060',0.12,0.70,0.24);p(0.06,0.07,0.05,'#f8f8f8',0.12,0.72,0.27); |
| p(0.04,0.04,0.22,'#1a1a1a',-0.10,0.86,0.10);p(0.04,0.04,0.22,'#1a1a1a',0.10,0.86,0.10); |
| p(0.08,0.08,0.54,'#1a1a1a',-0.28,0.52,0.22);p(0.06,0.06,0.10,'#f0f080',-0.28,0.52,0.50); |
| p(0.08,0.08,0.54,'#1a1a1a',0.28,0.52,0.22);p(0.06,0.06,0.10,'#f0f080',0.28,0.52,0.50); |
| p(0.06,0.28,0.52,'#f0f0f8',-0.32,0.52,-0.10);p(0.04,0.20,0.40,'#d8e8f8',-0.52,0.48,-0.14); |
| p(0.06,0.28,0.52,'#f0f0f8',0.32,0.52,-0.10);p(0.04,0.20,0.40,'#d8e8f8',0.52,0.48,-0.14); |
| p(0.06,0.22,0.42,'#f0f0f8',-0.28,0.30,-0.12);p(0.06,0.22,0.42,'#f0f0f8',0.28,0.30,-0.12); |
| p(0.08,0.08,0.16,'#1a1a1a',-0.20,0.42,0.08);p(0.08,0.08,0.16,'#1a1a1a',0.20,0.42,0.08); |
| return g; |
| } |
|
|
| function buildButterfree(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.22,0.60,0.20,'#f0f0f8',0,0.36,0);p(0.20,0.24,0.18,'#d0d0e0',0,0.60,0); |
| p(0.14,0.22,0.14,'#d0d0e8',0,0.10,-0.14);p(0.28,0.28,0.26,'#f0f0f8',0,0.80,0.04); |
| p(0.12,0.16,0.08,'#e83060',-0.10,0.82,0.16);p(0.12,0.16,0.08,'#e83060',0.10,0.82,0.16); |
| p(0.04,0.04,0.26,'#1a1a1a',-0.08,0.98,0.06);p(0.08,0.08,0.06,'#9060c0',-0.10,1.10,0.06); |
| p(0.04,0.04,0.26,'#1a1a1a',0.08,0.98,0.06);p(0.08,0.08,0.06,'#9060c0',0.10,1.10,0.06); |
| p(0.06,0.58,0.74,'#f8f8ff',-0.40,0.56,-0.06);p(0.04,0.44,0.58,'#d8d0f8',-0.64,0.52,-0.12); |
| p(0.04,0.30,0.38,'#9060c0',-0.54,0.64,-0.08);p(0.04,0.12,0.12,'#9060c0',-0.46,0.72,-0.04); |
| p(0.06,0.58,0.74,'#f8f8ff',0.40,0.56,-0.06);p(0.04,0.44,0.58,'#d8d0f8',0.64,0.52,-0.12); |
| p(0.04,0.30,0.38,'#9060c0',0.54,0.64,-0.08);p(0.04,0.12,0.12,'#9060c0',0.46,0.72,-0.04); |
| p(0.06,0.42,0.58,'#f0f0ff',-0.34,0.18,-0.04);p(0.04,0.30,0.44,'#d8d0f8',-0.54,0.14,-0.10);p(0.04,0.22,0.28,'#9060c0',-0.44,0.22,-0.06); |
| p(0.06,0.42,0.58,'#f0f0ff',0.34,0.18,-0.04);p(0.04,0.30,0.44,'#d8d0f8',0.54,0.14,-0.10);p(0.04,0.22,0.28,'#9060c0',0.44,0.22,-0.06); |
| p(0.18,0.06,0.08,'#1a1a1a',-0.12,0.04,0.08);p(0.18,0.06,0.08,'#1a1a1a',0.12,0.04,0.08); |
| return g; |
| } |
|
|
| function buildVoltorb(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.72,0.36,0.72,'#e83030',0,0.52,0);p(0.44,0.42,0.52,'#e83030',-0.32,0.44,0);p(0.44,0.42,0.52,'#e83030',0.32,0.44,0); |
| p(0.52,0.38,0.36,'#e83030',0,0.44,0.32);p(0.50,0.30,0.28,'#e83030',0,0.46,-0.28); |
| p(0.54,0.14,0.54,'#e83030',0,0.64,0);p(0.38,0.10,0.38,'#e83030',0,0.72,0); |
| p(0.80,0.08,0.76,'#1a1a1a',0,0.30,0);p(0.46,0.08,0.58,'#1a1a1a',-0.30,0.30,0);p(0.46,0.08,0.58,'#1a1a1a',0.30,0.30,0); |
| p(0.72,0.36,0.72,'#f8f8f8',0,0.10,0);p(0.44,0.38,0.52,'#f0f0f0',-0.32,0.14,0);p(0.44,0.38,0.52,'#f0f0f0',0.32,0.14,0); |
| p(0.52,0.32,0.36,'#f0f0f0',0,0.12,0.30);p(0.38,0.08,0.38,'#f0f0f0',0,0.04,0); |
| p(0.16,0.14,0.06,'#f8f8f8',-0.20,0.42,0.35);p(0.10,0.09,0.04,'#1a1a1a',-0.20,0.42,0.38); |
| p(0.16,0.14,0.06,'#f8f8f8',0.20,0.42,0.35);p(0.10,0.09,0.04,'#1a1a1a',0.20,0.42,0.38); |
| p(0.18,0.08,0.05,'#1a1a1a',-0.20,0.52,0.35);p(0.18,0.08,0.05,'#1a1a1a',0.20,0.52,0.35); |
| p(0.24,0.08,0.05,'#1a1a1a',0,0.30,0.37); |
| return g; |
| } |
|
|
| function buildElectrode(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.90,0.44,0.90,'#f8f8f8',0,0.60,0);p(0.54,0.52,0.64,'#f0f0f0',-0.38,0.52,0);p(0.54,0.52,0.64,'#f0f0f0',0.38,0.52,0); |
| p(0.64,0.46,0.44,'#f0f0f0',0,0.52,0.38);p(0.62,0.36,0.34,'#f0f0f0',0,0.54,-0.34); |
| p(0.68,0.18,0.68,'#f8f8f8',0,0.82,0);p(0.48,0.12,0.48,'#f8f8f8',0,0.92,0); |
| p(0.96,0.10,0.92,'#1a1a1a',0,0.36,0);p(0.58,0.10,0.72,'#1a1a1a',-0.36,0.36,0);p(0.58,0.10,0.72,'#1a1a1a',0.36,0.36,0); |
| p(0.90,0.44,0.90,'#e83030',0,0.14,0);p(0.54,0.48,0.64,'#e83030',-0.38,0.20,0);p(0.54,0.48,0.64,'#e83030',0.38,0.20,0); |
| p(0.64,0.40,0.44,'#e83030',0,0.16,0.36);p(0.48,0.10,0.48,'#e83030',0,0.06,0); |
| p(0.20,0.16,0.06,'#1a1a1a',-0.24,0.50,0.44);p(0.12,0.10,0.04,'#f8f8f8',-0.24,0.50,0.47); |
| p(0.20,0.16,0.06,'#1a1a1a',0.24,0.50,0.44);p(0.12,0.10,0.04,'#f8f8f8',0.24,0.50,0.47); |
| p(0.22,0.09,0.05,'#1a1a1a',-0.24,0.62,0.44);p(0.22,0.09,0.05,'#1a1a1a',0.24,0.62,0.44); |
| p(0.30,0.09,0.05,'#1a1a1a',0,0.36,0.46); |
| return g; |
| } |
|
|
| function buildJigglypuff(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.80,0.70,0.80,'#ffb0c8',0,0.38,0);p(0.56,0.52,0.60,'#ffb0c8',-0.34,0.34,0);p(0.56,0.52,0.60,'#ffb0c8',0.34,0.34,0); |
| p(0.64,0.56,0.64,'#ffb0c8',0,0.38,0.32);p(0.60,0.42,0.50,'#ffb0c8',0,0.38,-0.28); |
| p(0.64,0.22,0.62,'#ffb0c8',0,0.68,0);p(0.46,0.14,0.44,'#ffb0c8',0,0.78,0); |
| p(0.14,0.14,0.06,'#f0f0ff',-0.22,0.48,0.40);p(0.28,0.28,0.08,'#6898f8',-0.22,0.48,0.42);p(0.10,0.10,0.05,'#1a1a1a',-0.22,0.48,0.45); |
| p(0.14,0.14,0.06,'#f0f0ff',0.22,0.48,0.40);p(0.28,0.28,0.08,'#6898f8',0.22,0.48,0.42);p(0.10,0.10,0.05,'#1a1a1a',0.22,0.48,0.45); |
| p(0.28,0.06,0.05,'#e05878',0,0.36,0.41); |
| p(0.08,0.12,0.06,'#ffb0c8',-0.28,0.74,0.06);p(0.06,0.08,0.05,'#e890b0',0,0.82,0.06); |
| p(0.26,0.24,0.14,'#ffb0c8',-0.44,0.26,0.12);p(0.14,0.10,0.10,'#ffb0c8',-0.54,0.14,0.14); |
| p(0.26,0.24,0.14,'#ffb0c8',0.44,0.26,0.12);p(0.14,0.10,0.10,'#ffb0c8',0.54,0.14,0.14); |
| p(0.22,0.18,0.22,'#ffb0c8',-0.24,0.04,0.08);p(0.22,0.18,0.22,'#ffb0c8',0.24,0.04,0.08); |
| p(0.10,0.06,0.14,'#ffb0c8',-0.28,0.00,0.16);p(0.10,0.06,0.14,'#ffb0c8',0.22,0.00,0.16); |
| return g; |
| } |
|
|
| function buildAbra(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),tmat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.48,0.44,0.54,'#e8c840',0,0.24,0);p(0.34,0.28,0.40,'#c0a030',0,0.24,0.14); |
| p(0.36,0.36,0.38,'#e8c840',0,0.60,0.10);p(0.28,0.20,0.26,'#e8c840',0,0.52,0.32); |
| p(0.22,0.08,0.06,'#1a1a1a',-0.10,0.64,0.26);p(0.22,0.08,0.06,'#1a1a1a',0.10,0.64,0.26); |
| p(0.10,0.22,0.08,'#e8c840',-0.18,0.82,0.06);p(0.06,0.14,0.06,'#c0a030',-0.18,0.82,0.09); |
| p(0.10,0.22,0.08,'#e8c840',0.18,0.82,0.06);p(0.06,0.14,0.06,'#c0a030',0.18,0.82,0.09); |
| p(0.40,0.36,0.36,'#c0a030',0,0.06,0); |
| p(0.16,0.26,0.14,'#e8c840',-0.28,0.40,0.04);p(0.14,0.22,0.12,'#c0a030',-0.38,0.24,0.08); |
| p(0.16,0.26,0.14,'#e8c840',0.28,0.40,0.04);p(0.14,0.22,0.12,'#c0a030',0.38,0.24,0.08); |
| p(0.12,0.10,0.16,'#c0a030',-0.42,0.16,0.14);p(0.12,0.10,0.16,'#c0a030',0.42,0.16,0.14); |
| p(0.10,0.06,0.06,'#c0a030',-0.48,0.14,0.18);p(0.10,0.06,0.06,'#c0a030',0.48,0.14,0.18); |
| p(0.30,0.10,0.22,'#c0a030',-0.08,0.08,-0.22);p(0.26,0.10,0.22,'#c0a030',0.08,0.08,-0.22); |
| p(0.28,0.08,0.06,'#c0a030',0,0.48,0.02); |
| p(0.06,0.28,0.06,'#e8c840',0,0.54,-0.26);p(0.06,0.14,0.14,'#c0a030',0,0.42,-0.34); |
| return g; |
| } |
|
|
| function buildAlakazam(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),tmat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.36,0.60,0.30,'#e8c840',0,0.32,0);p(0.26,0.34,0.22,'#c0a030',0,0.32,0.12); |
| p(0.44,0.44,0.40,'#e8c840',0,0.76,0.04);p(0.22,0.14,0.20,'#c0a030',0,0.62,0.24); |
| p(0.36,0.08,0.06,'#d0b050',-0.02,0.64,0.24);p(0.36,0.08,0.06,'#d0b050',0.02,0.60,0.24); |
| p(0.10,0.10,0.06,'#1a1a1a',-0.14,0.80,0.20);p(0.10,0.10,0.06,'#1a1a1a',0.14,0.80,0.20); |
| p(0.10,0.28,0.08,'#e8c840',-0.22,0.96,0.02);p(0.10,0.28,0.08,'#e8c840',0.22,0.96,0.02); |
| p(0.26,0.48,0.14,'#e8c840',-0.32,0.36,0.04);p(0.20,0.38,0.12,'#c0a030',-0.44,0.22,0.06); |
| p(0.26,0.48,0.14,'#e8c840',0.32,0.36,0.04);p(0.20,0.38,0.12,'#c0a030',0.44,0.22,0.06); |
| p(0.06,0.06,0.46,'#d0b050',-0.52,0.14,0.20);p(0.04,0.04,0.06,'#f0d880',-0.52,0.14,0.44); |
| p(0.06,0.06,0.46,'#d0b050',0.52,0.14,0.20);p(0.04,0.04,0.06,'#f0d880',0.52,0.14,0.44); |
| p(0.20,0.44,0.20,'#e8c840',-0.14,0.10,0.02);p(0.20,0.44,0.20,'#e8c840',0.14,0.10,0.02); |
| p(0.24,0.10,0.28,'#c0a030',-0.14,0.00,0.06);p(0.24,0.10,0.28,'#c0a030',0.14,0.00,0.06); |
| p(0.08,0.30,0.08,'#c0a030',0,0.14,-0.20);p(0.12,0.08,0.14,'#c0a030',0,0.04,-0.28); |
| return g; |
| } |
|
|
| function buildGengar(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),tmat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.82,0.70,0.78,'#7850a0',0,0.38,0);p(0.60,0.52,0.60,'#604080',-0.38,0.30,0);p(0.60,0.52,0.60,'#604080',0.38,0.30,0); |
| p(0.66,0.54,0.64,'#7850a0',0,0.38,0.30);p(0.58,0.44,0.52,'#7850a0',0,0.40,-0.28); |
| p(0.74,0.40,0.70,'#7850a0',0,0.78,0); |
| p(0.18,0.26,0.08,'#604080',-0.36,1.02,-0.08);p(0.18,0.26,0.08,'#604080',0.36,1.02,-0.08); |
| p(0.12,0.20,0.08,'#604080',-0.20,1.10,-0.04);p(0.12,0.20,0.08,'#604080',0.20,1.10,-0.04); |
| p(0.22,0.18,0.08,'#e83060',-0.20,0.80,0.34);p(0.14,0.10,0.05,'#1a1a1a',-0.20,0.80,0.38); |
| p(0.22,0.18,0.08,'#e83060',0.20,0.80,0.34);p(0.14,0.10,0.05,'#1a1a1a',0.20,0.80,0.38); |
| p(0.54,0.18,0.08,'#f8f8f8',0,0.62,0.38);p(0.44,0.10,0.06,'#1a1a1a',0,0.62,0.40); |
| p(0.06,0.14,0.06,'#f8f8f8',-0.18,0.56,0.38);p(0.06,0.14,0.06,'#f8f8f8',-0.06,0.56,0.38); |
| p(0.06,0.14,0.06,'#f8f8f8',0.06,0.56,0.38);p(0.06,0.14,0.06,'#f8f8f8',0.18,0.56,0.38); |
| p(0.30,0.26,0.22,'#7850a0',-0.54,0.34,0.12);p(0.22,0.20,0.18,'#604080',-0.66,0.20,0.14); |
| p(0.30,0.26,0.22,'#7850a0',0.54,0.34,0.12);p(0.22,0.20,0.18,'#604080',0.66,0.20,0.14); |
| p(0.14,0.10,0.08,'#604080',-0.72,0.14,0.20);p(0.14,0.10,0.08,'#604080',0.72,0.14,0.20); |
| p(0.60,0.22,0.56,'#604080',0,0.06,0); |
| return g; |
| } |
|
|
| function buildDoduo(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.60,0.42,0.52,'#c8a840',0,0.22,0);p(0.44,0.24,0.38,'#e8c860',0,0.20,0.14); |
| p(0.12,0.54,0.12,'#c8a840',-0.14,0.62,0.04);p(0.12,0.54,0.12,'#c8a840',0.14,0.62,0.04); |
| p(0.36,0.34,0.32,'#c8a840',-0.14,0.96,0.04);p(0.36,0.34,0.32,'#c8a840',0.14,0.96,0.04); |
| p(0.10,0.08,0.22,'#e84820',-0.14,0.96,0.22);p(0.10,0.08,0.22,'#e84820',0.14,0.96,0.22); |
| p(0.10,0.10,0.05,'#1a1a1a',-0.22,1.02,0.18);p(0.10,0.10,0.05,'#1a1a1a',-0.06,1.02,0.18); |
| p(0.10,0.10,0.05,'#1a1a1a',0.06,1.02,0.18);p(0.10,0.10,0.05,'#1a1a1a',0.22,1.02,0.18); |
| p(0.10,0.16,0.08,'#c8a840',-0.22,1.10,0.02);p(0.10,0.16,0.08,'#c8a840',0.22,1.10,0.02); |
| p(0.20,0.16,0.18,'#c8a840',-0.16,0.08,0.06);p(0.20,0.16,0.18,'#c8a840',0.16,0.08,0.06); |
| p(0.08,0.28,0.08,'#e84820',-0.18,0.00,0.08);p(0.08,0.28,0.08,'#e84820',0.18,0.00,0.08); |
| p(0.22,0.06,0.14,'#e84820',-0.18,-0.02,0.14);p(0.22,0.06,0.14,'#e84820',0.18,-0.02,0.14); |
| p(0.08,0.06,0.10,'#e84820',-0.24,-0.02,0.12);p(0.08,0.06,0.10,'#e84820',0.22,-0.02,0.12); |
| p(0.26,0.20,0.24,'#c8a840',0,0.40,-0.28);p(0.08,0.14,0.08,'#e8c860',0,0.28,-0.34); |
| return g; |
| } |
|
|
| function buildRapidash(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.52,0.48,0.88,'#f8f8f8',0,0.42,0);p(0.38,0.34,0.70,'#f0f0f0',0,0.40,0.10); |
| p(0.32,0.40,0.30,'#f8f8f8',0,0.70,0.36);p(0.26,0.42,0.28,'#f8f8f8',0,0.88,0.52); |
| p(0.36,0.34,0.34,'#f8f8f8',0,1.04,0.60);p(0.18,0.10,0.26,'#f8f8f8',0,0.96,0.78); |
| p(0.06,0.06,0.20,'#f0f080',0,1.06,0.90); |
| p(0.10,0.10,0.05,'#1a1a1a',-0.14,1.10,0.74);p(0.10,0.10,0.05,'#1a1a1a',0.14,1.10,0.74); |
| p(0.06,0.24,0.06,'#f89020',0,0.88,0.36);p(0.10,0.36,0.10,'#f89020',0,1.02,0.26); |
| p(0.14,0.48,0.10,'#f89020',-0.10,1.00,0.20);p(0.14,0.48,0.10,'#f89020',0.10,1.00,0.20); |
| p(0.10,0.30,0.08,'#f8d840',-0.06,1.08,0.22);p(0.10,0.30,0.08,'#f8d840',0.06,1.08,0.22); |
| p(0.16,0.42,0.16,'#f8f8f8',-0.18,0.16,0.28);p(0.12,0.34,0.12,'#f0f0f0',-0.18,-0.04,0.28);p(0.16,0.10,0.20,'#f0f0f0',-0.18,-0.16,0.28); |
| p(0.16,0.42,0.16,'#f8f8f8',0.18,0.16,0.28);p(0.12,0.34,0.12,'#f0f0f0',0.18,-0.04,0.28);p(0.16,0.10,0.20,'#f0f0f0',0.18,-0.16,0.28); |
| p(0.16,0.42,0.16,'#f8f8f8',-0.18,0.16,-0.36);p(0.12,0.34,0.12,'#f0f0f0',-0.18,-0.04,-0.36);p(0.16,0.10,0.20,'#f0f0f0',-0.18,-0.16,-0.36); |
| p(0.16,0.42,0.16,'#f8f8f8',0.18,0.16,-0.36);p(0.12,0.34,0.12,'#f0f0f0',0.18,-0.04,-0.36);p(0.16,0.10,0.20,'#f0f0f0',0.18,-0.16,-0.36); |
| p(0.08,0.10,0.24,'#f89020',0,0.42,-0.52);p(0.10,0.18,0.12,'#f8d840',0,0.54,-0.62);p(0.08,0.26,0.08,'#f89020',0,0.64,-0.58); |
| return g; |
| } |
|
|
| function buildHaunter(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),tmat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.66,0.60,0.62,'#9060b8',0,0.40,0);p(0.48,0.44,0.48,'#7040a0',-0.32,0.32,0);p(0.48,0.44,0.48,'#7040a0',0.32,0.32,0); |
| p(0.56,0.50,0.54,'#9060b8',0,0.40,0.24);p(0.52,0.42,0.46,'#7040a0',0,0.38,-0.22); |
| p(0.62,0.48,0.60,'#9060b8',0,0.76,0); |
| p(0.16,0.24,0.08,'#7040a0',-0.34,1.00,-0.04);p(0.16,0.24,0.08,'#7040a0',0.34,1.00,-0.04); |
| p(0.22,0.20,0.08,'#e83060',-0.18,0.78,0.30);p(0.12,0.12,0.05,'#1a1a1a',-0.18,0.78,0.34); |
| p(0.22,0.20,0.08,'#e83060',0.18,0.78,0.30);p(0.12,0.12,0.05,'#1a1a1a',0.18,0.78,0.34); |
| p(0.40,0.14,0.08,'#f8f8f8',0,0.62,0.32); |
| p(0.06,0.12,0.06,'#f8f8f8',-0.12,0.56,0.34);p(0.06,0.12,0.06,'#f8f8f8',0.12,0.56,0.34); |
| p(0.26,0.24,0.22,'#c080ff',-0.72,0.56,0.16);p(0.08,0.18,0.08,'#c080ff',-0.82,0.46,0.20);p(0.08,0.18,0.08,'#c080ff',-0.72,0.44,0.22); |
| p(0.26,0.24,0.22,'#c080ff',0.72,0.56,0.16);p(0.08,0.18,0.08,'#c080ff',0.82,0.46,0.20);p(0.08,0.18,0.08,'#c080ff',0.72,0.44,0.22); |
| p(0.52,0.18,0.48,'#7040a0',0,0.06,0); |
| p(0.12,0.16,0.10,'#7040a0',-0.18,0.00,-0.08);p(0.12,0.16,0.10,'#7040a0',0,0.00,-0.10);p(0.12,0.16,0.10,'#7040a0',0.18,0.00,-0.08); |
| return g; |
| } |
|
|
| function buildCaterpie(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.38,0.34,0.34,'#60c040',0,0.18,0.30);p(0.26,0.22,0.24,'#78d858',0,0.18,0.30); |
| p(0.10,0.10,0.05,'#1a1a1a',-0.12,0.24,0.45);p(0.10,0.10,0.05,'#1a1a1a',0.12,0.24,0.45); |
| p(0.04,0.04,0.14,'#e83030',0,0.32,0.40);p(0.06,0.08,0.06,'#e83030',0,0.40,0.44); |
| p(0.40,0.36,0.32,'#60c040',0,0.19,0);p(0.28,0.14,0.26,'#f8f840',0,0.10,0.02); |
| p(0.06,0.06,0.08,'#60c040',-0.20,0.06,0.04);p(0.06,0.06,0.08,'#60c040',0.20,0.06,0.04); |
| p(0.38,0.34,0.30,'#60c040',0,0.18,-0.32);p(0.26,0.12,0.24,'#f8f840',0,0.10,-0.30); |
| p(0.06,0.06,0.08,'#60c040',-0.20,0.06,-0.30);p(0.06,0.06,0.08,'#60c040',0.20,0.06,-0.30); |
| p(0.34,0.30,0.28,'#60c040',0,0.16,-0.62);p(0.24,0.10,0.22,'#f8f840',0,0.10,-0.60); |
| p(0.06,0.06,0.08,'#60c040',-0.18,0.06,-0.60);p(0.06,0.06,0.08,'#60c040',0.18,0.06,-0.60); |
| p(0.30,0.26,0.22,'#60c040',0,0.14,-0.88);p(0.08,0.18,0.06,'#e83030',0,0.28,-0.96); |
| p(0.06,0.06,0.08,'#78d858',-0.18,0.06,0.30);p(0.06,0.06,0.08,'#78d858',0.18,0.06,0.30); |
| p(0.06,0.06,0.08,'#78d858',-0.18,0.06,-0.62);p(0.06,0.06,0.08,'#78d858',0.18,0.06,-0.62); |
| return g; |
| } |
|
|
| function buildMagnemite(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.56,0.52,0.50,'#a0a8b8',0,0.40,0);p(0.40,0.36,0.36,'#b8c0d0',0,0.40,0.12); |
| p(0.14,0.14,0.06,'#f0f0f0',0,0.40,0.25);p(0.10,0.10,0.04,'#1a1a1a',0,0.40,0.28); |
| p(0.08,0.08,0.06,'#e8d840',-0.10,0.46,0.24);p(0.08,0.08,0.06,'#e8d840',0.10,0.46,0.24); |
| p(0.08,0.08,0.06,'#e8d840',-0.10,0.34,0.24);p(0.08,0.08,0.06,'#e8d840',0.10,0.34,0.24); |
| p(0.38,0.12,0.12,'#808898',-0.44,0.40,0);p(0.14,0.22,0.14,'#e83030',-0.64,0.48,0);p(0.14,0.22,0.14,'#f8f8f8',-0.64,0.32,0); |
| p(0.38,0.12,0.12,'#808898',0.44,0.40,0);p(0.14,0.22,0.14,'#e83030',0.64,0.48,0);p(0.14,0.22,0.14,'#f8f8f8',0.64,0.32,0); |
| p(0.06,0.06,0.04,'#c0c8d8',-0.20,0.54,0.24);p(0.06,0.06,0.04,'#c0c8d8',0.20,0.54,0.24); |
| p(0.06,0.06,0.04,'#c0c8d8',-0.20,0.26,0.24);p(0.06,0.06,0.04,'#c0c8d8',0.20,0.26,0.24); |
| p(0.06,0.06,0.04,'#c0c8d8',-0.26,0.40,0.24);p(0.06,0.06,0.04,'#c0c8d8',0.26,0.40,0.24); |
| p(0.30,0.08,0.08,'#808898',0,0.40,-0.26); |
| p(0.04,0.04,0.18,'#e8d840',0,0.50,-0.28);p(0.04,0.04,0.18,'#e8d840',0,0.30,-0.28); |
| p(0.12,0.04,0.04,'#808898',-0.44,0.50,0);p(0.12,0.04,0.04,'#808898',0.44,0.50,0); |
| p(0.18,0.18,0.04,'#c0c8d8',0,0.40,0.14); |
| return g; |
| } |
|
|
| function buildGeodude(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.64,0.58,0.62,'#c8a870',0,0.32,0);p(0.48,0.42,0.48,'#b89050',-0.28,0.28,0.10);p(0.48,0.42,0.48,'#b89050',0.28,0.28,0.10); |
| p(0.52,0.44,0.50,'#c8a870',0,0.32,0.22);p(0.46,0.36,0.44,'#b89050',0,0.30,-0.20); |
| p(0.46,0.22,0.44,'#c8a870',0,0.58,0); |
| p(0.14,0.14,0.06,'#f0f0e8',-0.14,0.42,0.30);p(0.08,0.09,0.04,'#1a1a1a',-0.14,0.42,0.33); |
| p(0.14,0.14,0.06,'#f0f0e8',0.14,0.42,0.30);p(0.08,0.09,0.04,'#1a1a1a',0.14,0.42,0.33); |
| p(0.22,0.08,0.06,'#604020',-0.14,0.54,0.30);p(0.22,0.08,0.06,'#604020',0.14,0.54,0.30); |
| p(0.28,0.06,0.05,'#604020',0,0.30,0.33); |
| p(0.16,0.14,0.14,'#a08050',-0.34,0.48,-0.12);p(0.12,0.10,0.10,'#604020',-0.28,0.56,0.14); |
| p(0.16,0.14,0.14,'#a08050',0.34,0.48,-0.12);p(0.12,0.10,0.10,'#604020',0.28,0.56,0.14); |
| p(0.20,0.16,0.18,'#c8a870',-0.46,0.28,0.12);p(0.24,0.20,0.22,'#a08050',-0.64,0.18,0.16); |
| p(0.08,0.08,0.10,'#604020',-0.72,0.12,0.20);p(0.08,0.08,0.10,'#604020',-0.60,0.10,0.22); |
| p(0.20,0.16,0.18,'#c8a870',0.46,0.28,0.12);p(0.24,0.20,0.22,'#a08050',0.64,0.18,0.16); |
| p(0.08,0.08,0.10,'#604020',0.72,0.12,0.20);p(0.08,0.08,0.10,'#604020',0.60,0.10,0.22); |
| return g; |
| } |
|
|
| function buildHero_dragon_ball_no_complete(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(1.00,0.78,1.18,'#e67e22',0,0.39,0); |
| p(0.56,0.56,0.12,'#f3d9b1',0,0.36,0.53); |
| p(0.34,0.20,0.24,'#e67e22',0,0.76,0.42); |
| p(0.72,0.52,0.66,'#e67e22',0,1.06,0.70); |
| p(0.46,0.24,0.26,'#e67e22',0,0.98,1.10); |
| p(0.10,0.16,0.14,'#f3d9b1',-0.20,1.38,0.56); |
| p(0.10,0.16,0.14,'#f3d9b1',0.20,1.38,0.56); |
| const wGeo=geo(0.14,0.78,0.92); |
| const wMatL=new THREE.MeshToonMaterial({color:'#2aa6a4',flatShading:true}); |
| const wMatR=new THREE.MeshToonMaterial({color:'#2aa6a4',flatShading:true}); |
| const wL=new THREE.Mesh(wGeo,wMatL); wL.position.set(-0.57,0.82,-0.02); wL.castShadow=true; g.add(wL); |
| const wR=new THREE.Mesh(wGeo,wMatR); wR.position.set(0.57,0.82,-0.02); wR.castShadow=true; g.add(wR); |
| p(0.24,0.28,0.28,'#e67e22',-0.24,0.14,0.12); |
| p(0.24,0.28,0.28,'#e67e22',0.24,0.14,0.12); |
| p(0.24,0.24,0.68,'#e67e22',0,0.30,-0.90); |
| p(0.18,0.18,0.18,'#f4c542',0,0.34,-1.32); |
| return g; |
| } |
|
|
| function buildCollectible(){ |
| const g=new THREE.Group(); |
| const gem=new THREE.Mesh(geo(0.42,0.42,0.42),mat('#f4c542')); |
| gem.position.set(0,0.21,0); gem.castShadow=true; g.add(gem); |
| const star=new THREE.Mesh(geo(0.18,0.18,0.10),mat('#8c3b2a')); |
| star.position.set(0,0.21,0.21); star.castShadow=true; g.add(star); |
| const glow=new THREE.PointLight('#f4c542',0.8,5,2); |
| glow.position.set(0,0.2,0.2); g.add(glow); |
| return g; |
| } |
|
|
| function buildPlatformTile(){ |
| const g=new THREE.Group(); |
| const tile=new THREE.Mesh(geo(6.0,0.12,TILE.depth),mat('#d8c7a1')); |
| tile.position.set(0,0.06,0); tile.receiveShadow=true; g.add(tile); |
| const border=new THREE.Mesh(geo(5.7,0.02,TILE.depth-0.18),mat('#caa56a')); |
| border.position.set(0,0.13,0); g.add(border); |
| return g; |
| } |
|
|
| function buildDecoA(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.34,0.18,0.20,'#1a1a1a',0,0.09,0);p(0.62,0.52,0.34,'#caa56a',0,0.44,0); |
| p(0.40,0.36,0.34,'#f3d9b1',0,0.88,0.04);p(0.24,0.22,0.12,'#f2f2f0',0,0.76,0.21); |
| p(0.05,0.05,0.08,'#1a1a1a',-0.08,0.90,0.20);p(0.05,0.05,0.08,'#1a1a1a',0.08,0.90,0.20); |
| return g; |
| } |
|
|
| function buildDecoB(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.46,0.24,0.24,'#8c3b2a',0,0.12,0);p(0.92,0.66,0.46,'#8c3b2a',0,0.57,0); |
| p(0.52,0.38,0.36,'#caa56a',0,1.07,0.06); |
| p(0.12,0.14,0.12,'#f3d9b1',-0.26,1.24,0.02);p(0.12,0.14,0.12,'#f3d9b1',0.26,1.24,0.02); |
| return g; |
| } |
|
|
| function buildDecoC(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.12,0.26,0.12,'#5e2418',-0.08,0.13,0);p(0.12,0.26,0.12,'#5e2418',0.08,0.13,0); |
| p(0.42,0.42,0.24,'#2aa6a4',0,0.47,0);p(0.30,0.28,0.24,'#f3d9b1',0,0.82,0.02); |
| p(0.32,0.12,0.26,'#5e2418',0,0.96,0.02);p(0.10,0.16,0.12,'#5e2418',-0.15,0.84,0.10); |
| return g; |
| } |
|
|
| function buildBackgroundProp(){ |
| const g=new THREE.Group(); |
| function p(w,h,d,c,x,y,z){const m=new THREE.Mesh(geo(w,h,d),mat(c));m.position.set(x,y,z);m.castShadow=true;g.add(m);} |
| p(0.34,0.28,0.18,'#5e2418',0,0.14,0);p(0.52,0.50,0.26,'#caa56a',0,0.53,0); |
| p(0.66,0.16,0.16,'#caa56a',0,0.54,0.12);p(0.32,0.30,0.28,'#f3d9b1',0,0.93,0.02); |
| p(0.34,0.12,0.30,'#5e2418',0,1.08,0.02); |
| return g; |
| } |
|
|
| function buildStaticWorld(){ |
| bgGroup=new THREE.Group(); scene.add(bgGroup); |
| const groundMat=mat('#e6d29a'); |
| const sideGeo=geo(8,0.2,60); |
| const lG=new THREE.Mesh(sideGeo,groundMat); lG.position.set(-7.5,-0.24,-18); bgGroup.add(lG); |
| const rG=new THREE.Mesh(sideGeo,groundMat); rG.position.set(7.5,-0.24,-18); bgGroup.add(rG); |
| for(let i=0;i<4;i++){ |
| const prop=buildBackgroundProp(); prop.scale.setScalar(1.6); |
| prop.position.set(i%2===0?-6.0:6.0,0,-12-i*8); bgGroup.add(prop); |
| } |
| } |
|
|
| function buildHero_jungle() { |
| const g = new THREE.Group(); |
| g.name = 'hero'; |
| addPart(g, geos.heroBody, materials.heroDark, 0, 0.69, 0, 'body'); |
| addPart(g, geos.heroChest, materials.heroChest, 0, 0.64, 0.33, 'chest_plate'); |
| addPart(g, geos.heroHead, materials.heroDark, 0, 1.35, 0.10, 'head'); |
| addPart(g, geos.heroBrow, materials.heroDark, 0, 1.46, 0.31, 'brow'); |
| addPart(g, geos.heroMuzzle, materials.heroChest, 0, 1.24, 0.34, 'muzzle'); |
| addPart(g, geos.eye, materials.black, -0.14, 1.33, 0.37, 'eye_l'); |
| addPart(g, geos.eye, materials.black, 0.14, 1.33, 0.37, 'eye_r'); |
| addPart(g, geos.arm, materials.heroDark, -0.62, 0.49, 0.05, 'arm_l'); |
| addPart(g, geos.arm, materials.heroDark, 0.62, 0.49, 0.05, 'arm_r'); |
| addPart(g, geos.leg, materials.heroDark, -0.22, 0.17, 0, 'leg_l'); |
| addPart(g, geos.leg, materials.heroDark, 0.22, 0.17, 0, 'leg_r'); |
|
|
| g.position.set(0, PHYSICS.playerGroundY, SPAWN.heroZ); |
| g.userData = { hitTimer: 0, hitFlash: 0, collectTimer: 0 }; |
| return g; |
| } |
|
|
| function buildObstacleGround() { |
| const g = new THREE.Group(); |
| g.name = 'obstacle_ground'; |
| addPart(g, geos.logBody, materials.earth, 0, 0.18, 0, 'log_body'); |
| addPart(g, geos.logCap, materials.bark, -0.64, 0.18, 0, 'end_cap_l'); |
| addPart(g, geos.logCap, materials.bark, 0.64, 0.18, 0, 'end_cap_r'); |
| g.userData = { bobAmp: 0.08, bobPhase: Math.random() * Math.PI * 2, baseY: 0 }; |
| return g; |
| } |
|
|
| function buildObstacleAerial() { |
| const g = new THREE.Group(); |
| g.name = 'obstacle_aerial'; |
| addPart(g, geos.toucanBody, materials.heroDark, 0, 0.21, 0, 'body'); |
| addPart(g, geos.toucanHead, materials.heroDark, 0, 0.48, 0.20, 'head'); |
| addPart(g, geos.toucanBeakBase, materials.fruitOrange, 0, 0.48, 0.6, 'beak_base'); |
| addPart(g, geos.toucanBeakTip, materials.fruitGold, 0, 0.5, 0.95, 'beak_tip'); |
| addPart(g, geos.toucanWing, materials.fruitGold, -0.56, 0.24, 0, 'wing_l'); |
| addPart(g, geos.toucanWing, materials.fruitGold, 0.56, 0.24, 0, 'wing_r'); |
| addPart(g, geos.toucanEye, materials.black, -0.1, 0.52, 0.34, 'eye_l'); |
| addPart(g, geos.toucanEye, materials.black, 0.1, 0.52, 0.34, 'eye_r'); |
| g.userData = { bobAmp: 0.10, bobPhase: Math.random() * Math.PI * 2, baseY: 0, wingFlip: Math.random() * 10 }; |
| return g; |
| } |
|
|
| function buildBackgroundWall(x, z, scaleY) { |
| const mesh = new THREE.Mesh(geos.backgroundBlock, materials.moss); |
| mesh.position.set(x, 0.9 * scaleY, z); |
| mesh.scale.y = scaleY; |
| return mesh; |
| } |
|
|
| function buildCanopy(z, y) { |
| const mesh = new THREE.Mesh(geos.canopyBlock, materials.moss); |
| mesh.position.set(0, y, z); |
| return mesh; |
| } |
|
|
| function buildHero_pokemon() { |
| const hero = new THREE.Group(); |
|
|
| |
| const bodyGeom = buildSphere(0.38, 8, 6); |
| const body = new THREE.Mesh(bodyGeom, MAT_BODY); |
| body.position.set(0, 0.4, 0); |
| body.castShadow = true; |
| hero.add(body); |
|
|
| |
| const bellyGeom = buildSphere(0.22, 6, 5); |
| const belly = new THREE.Mesh(bellyGeom, MAT_BELLY); |
| belly.position.set(0, 0.34, 0.3); |
| belly.scale.set(1, 0.7, 0.4); |
| hero.add(belly); |
|
|
| |
| const bulbGeom = buildSphere(0.22, 6, 5); |
| const bulb = new THREE.Mesh(bulbGeom, MAT_BULB); |
| bulb.position.set(0, 0.72, -0.2); |
| hero.add(bulb); |
|
|
| |
| const bulbInnerGeom = buildSphere(0.12, 5, 4); |
| const bulbInner = new THREE.Mesh(bulbInnerGeom, MAT_BELLY); |
| bulbInner.position.set(0, 0.85, -0.14); |
| hero.add(bulbInner); |
|
|
| |
| const eyeGeom = buildSphere(0.07, 5, 4); |
| const eyeL = new THREE.Mesh(eyeGeom, MAT_EYE); |
| const eyeR = eyeL.clone(); |
| eyeL.position.set(-0.18, 0.52, 0.32); |
| eyeR.position.set( 0.18, 0.52, 0.32); |
| hero.add(eyeL, eyeR); |
|
|
| |
| const legGeom = buildBox(0.15, 0.22, 0.18); |
| const legPositions = [ |
| [-0.22, 0.12, 0.16], [ 0.22, 0.12, 0.16], |
| [-0.20, 0.12,-0.12], [ 0.20, 0.12,-0.12], |
| ]; |
| legPositions.forEach(p => { |
| const leg = new THREE.Mesh(legGeom, MAT_BODY); |
| leg.position.set(...p); |
| leg.castShadow = true; |
| hero.add(leg); |
| }); |
|
|
| return hero; |
| } |
|
|
| function buildHero_wreck_it() { |
| const group = new THREE.Group(); |
| group.add(makePart(GEO.g026_052_028, MAT.brown, -0.22, 0.26, 0, false)); |
| group.add(makePart(GEO.g026_052_028, MAT.brown, 0.22, 0.26, 0, false)); |
| group.add(makePart(GEO.g100_092_062, MAT.red, 0, 0.98, 0, false)); |
| group.add(makePart(GEO.g014_076_008, MAT.brown, -0.20, 1.06, 0.27, false)); |
| group.add(makePart(GEO.g014_076_008, MAT.brown, 0.20, 1.06, 0.27, false)); |
| group.add(makePart(GEO.g022_052_022, MAT.red, -0.61, 0.96, 0.02, false)); |
| group.add(makePart(GEO.g022_052_022, MAT.red, 0.61, 0.96, 0.02, false)); |
| group.add(makePart(GEO.g034_028_034, MAT.skin, -0.61, 0.74, 0.23, true)); |
| group.add(makePart(GEO.g034_028_034, MAT.skin, 0.61, 0.74, 0.23, true)); |
| group.add(makePart(GEO.g070_054_056, MAT.skin, 0, 1.75, 0.05, false)); |
| group.add(makePart(GEO.g076_018_038, MAT.darkBrown, 0, 2.11, 0.02, false)); |
| group.add(makePart(GEO.g020_016_018, MAT.darkBrown, -0.24, 2.19, 0.10, false)); |
| group.add(makePart(GEO.g016_012_016, MAT.darkBrown, 0.22, 2.17, -0.02, false)); |
| return group; |
| } |
|
|
| function buildCandyCastleTower() { |
| const group = new THREE.Group(); |
| group.add(makePart(GEO.g110_140_110, MAT.blue, 0, 0.70, 0, false)); |
| group.add(makePart(GEO.g072_062_072, MAT.pink, 0, 1.71, 0, false)); |
| group.add(makePart(GEO.g040_026_040, MAT.cream, 0, 2.15, 0, true)); |
| return group; |
| } |
|
|
| function buildLollipopPost() { |
| const group = new THREE.Group(); |
| group.add(makePart(GEO.g014_180_014, MAT.brown, 0, 0.90, 0, false)); |
| group.add(makePart(GEO.g062_062_012, MAT.pink, 0, 1.74, 0, true)); |
| group.add(makePart(GEO.g046_010_013, MAT.cream, 0, 1.74, 0.01, false)); |
| group.add(makePart(GEO.g010_046_013, MAT.cream, 0, 1.74, 0.01, false)); |
| return group; |
| } |
|
|
| function buildArcadeBeacon() { |
| const group = new THREE.Group(); |
| group.add(makePart(GEO.g046_046_046, MAT.blue, 0, 1.60, 0, true)); |
| group.add(makePart(GEO.g062_010_062, MAT.gold, 0, 1.93, 0, false)); |
| return group; |
| } |
|
|
| function buildDistantSugarHills() { |
| const group = new THREE.Group(); |
| group.add(makePart(GEO.g800_160_220, MAT.blue, 0, 0.80, -22, false)); |
| group.add(makePart(GEO.g640_120_200, MAT.pink, -1.20, 0.60, -20, false)); |
| group.add(makePart(GEO.g520_096_180, MAT.cream, 1.60, 0.48, -18, false)); |
| return group; |
| } |
|
|
| function buildFruitCollectible() { |
| const group = new THREE.Group(); |
| addPart(group, WORLD_GEOMETRY.fruitBase, WORLD_MATERIALS.accent, 0, 0.12, 0, 'fruit_base'); |
| addPart(group, WORLD_GEOMETRY.fruitMid, WORLD_MATERIALS.accent, 0, 0.31, 0, 'fruit_mid'); |
| addPart(group, WORLD_GEOMETRY.fruitTop, WORLD_MATERIALS.obstacleAlt, 0, 0.46, 0, 'fruit_top'); |
| addPart(group, WORLD_GEOMETRY.bananaStem, WORLD_MATERIALS.decorMain, 0, 0.64, 0, 'fruit_stem'); |
| group.userData.type = 'fruit'; |
| return group; |
| } |
|
|
| function buildCheckpointBanana() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.36, 0.16, 0.22), WORLD_MATERIALS.checkpoint, -0.18, 0.3, 0, 'banana_l', { rotation: { z: -0.25 } }); |
| addPart(group, new THREE.BoxGeometry(0.36, 0.16, 0.22), WORLD_MATERIALS.checkpoint, 0.18, 0.3, 0, 'banana_r', { rotation: { z: 0.25 } }); |
| addPart(group, WORLD_GEOMETRY.bananaStem, WORLD_MATERIALS.decorMain, 0, 0.54, 0, 'banana_stem'); |
| addPart(group, WORLD_GEOMETRY.pedestalMini, WORLD_MATERIALS.emissive, 0, 0.02, 0, 'banana_glow'); |
| group.userData.type = 'checkpoint'; |
| return group; |
| } |
|
|
| function buildToucanGlider() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(1.0, 0.42, 0.6), WORLD_MATERIALS.obstacleMain, 0, 0.2, 0, 'body'); |
| addPart(group, new THREE.BoxGeometry(0.44, 0.34, 0.34), WORLD_MATERIALS.obstacleMain, 0, 0.46, 0.2, 'head'); |
| addPart(group, new THREE.BoxGeometry(0.24, 0.18, 0.44), WORLD_MATERIALS.obstacleAlt, 0, 0.44, 0.6, 'beak'); |
| addPart(group, new THREE.BoxGeometry(0.14, 0.12, 0.92), WORLD_MATERIALS.accent, -0.56, 0.26, 0, 'wing_l'); |
| addPart(group, new THREE.BoxGeometry(0.14, 0.12, 0.92), WORLD_MATERIALS.accent, 0.56, 0.26, 0, 'wing_r'); |
| group.userData.animKind = 'fly'; |
| group.userData.baseY = 1.8; |
| group.userData.collisionHalf = COLLISION.aerialObstacleHalf; |
| return group; |
| } |
|
|
| function buildBambooSpikes() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(1.2, 0.18, 0.6), WORLD_MATERIALS.obstacleAlt, 0, 0.09, 0, 'base'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.72, 0.18), WORLD_MATERIALS.obstacleMain, -0.28, 0.42, 0, 'spike_l'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.86, 0.18), WORLD_MATERIALS.obstacleMain, 0, 0.49, 0, 'spike_m'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.68, 0.18), WORLD_MATERIALS.obstacleMain, 0.28, 0.38, 0, 'spike_r'); |
| group.userData.animKind = 'still'; |
| group.userData.baseY = 0; |
| group.userData.collisionHalf = COLLISION.groundObstacleHalf; |
| return group; |
| } |
|
|
| function buildBambooBundle() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(1.1, 0.62, 0.62), WORLD_MATERIALS.obstacleMain, 0, 0.31, 0, 'bundle'); |
| addPart(group, new THREE.BoxGeometry(1.2, 0.08, 0.08), WORLD_MATERIALS.accent, 0, 0.22, 0.24, 'band_1'); |
| addPart(group, new THREE.BoxGeometry(1.2, 0.08, 0.08), WORLD_MATERIALS.accent, 0, 0.4, -0.24, 'band_2'); |
| group.userData.animKind = 'roll'; |
| group.userData.baseY = 1.1; |
| group.userData.collisionHalf = COLLISION.aerialObstacleHalf; |
| return group; |
| } |
|
|
| function buildStoneWall(options) { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(1.2, 1.0, 0.44), WORLD_MATERIALS.obstacleMain, 0, 0.5, 0, 'wall'); |
| addPart(group, new THREE.BoxGeometry(1.28, 0.18, 0.48), WORLD_MATERIALS.obstacleAlt, 0, 0.96, 0, 'cap'); |
| if (options && options.wallOfHonor) { |
| addPart(group, new THREE.BoxGeometry(0.14, 0.14, 0.08), WORLD_MATERIALS.accent, -0.18, 0.55, 0.24, 'honor_l'); |
| addPart(group, new THREE.BoxGeometry(0.14, 0.14, 0.08), WORLD_MATERIALS.accent, 0.18, 0.55, 0.24, 'honor_r'); |
| } |
| group.userData.animKind = 'still'; |
| group.userData.baseY = 0; |
| group.userData.collisionHalf = COLLISION.groundObstacleHalf; |
| return group; |
| } |
|
|
| function buildDragonKite() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(1.1, 0.16, 0.82), WORLD_MATERIALS.obstacleAlt, 0, 0.1, 0, 'wing'); |
| addPart(group, new THREE.BoxGeometry(0.34, 0.22, 0.28), WORLD_MATERIALS.obstacleMain, 0, 0.18, 0.1, 'head'); |
| addPart(group, new THREE.BoxGeometry(0.12, 0.12, 0.9), WORLD_MATERIALS.accent, 0, 0.02, -0.48, 'tail'); |
| group.userData.animKind = 'glide'; |
| group.userData.baseY = 1.8; |
| group.userData.collisionHalf = COLLISION.aerialObstacleHalf; |
| return group; |
| } |
|
|
| function buildDumpster() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(1.1, 0.82, 0.72), WORLD_MATERIALS.obstacleMain, 0, 0.41, 0, 'bin'); |
| addPart(group, new THREE.BoxGeometry(1.12, 0.12, 0.76), WORLD_MATERIALS.obstacleAlt, 0, 0.86, -0.02, 'lid'); |
| group.userData.animKind = 'still'; |
| group.userData.baseY = 0; |
| group.userData.collisionHalf = COLLISION.groundObstacleHalf; |
| return group; |
| } |
|
|
| function buildTaxi() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(1.14, 0.52, 0.72), WORLD_MATERIALS.obstacleAlt, 0, 0.26, 0, 'body'); |
| addPart(group, new THREE.BoxGeometry(0.66, 0.26, 0.56), WORLD_MATERIALS.neutral, 0, 0.56, -0.02, 'roof'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.18, 0.18), WORLD_MATERIALS.dark, -0.34, 0.05, 0.22, 'wheel_lf'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.18, 0.18), WORLD_MATERIALS.dark, 0.34, 0.05, 0.22, 'wheel_rf'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.18, 0.18), WORLD_MATERIALS.dark, -0.34, 0.05, -0.22, 'wheel_lr'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.18, 0.18), WORLD_MATERIALS.dark, 0.34, 0.05, -0.22, 'wheel_rr'); |
| group.userData.animKind = 'hover_roll'; |
| group.userData.baseY = 1.25; |
| group.userData.collisionHalf = COLLISION.aerialObstacleHalf; |
| return group; |
| } |
|
|
| function buildSkullRock() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(1.04, 0.84, 0.76), WORLD_MATERIALS.obstacleMain, 0, 0.42, 0, 'skull'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.18, 0.12), WORLD_MATERIALS.dark, -0.18, 0.52, 0.28, 'eye_l'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.18, 0.12), WORLD_MATERIALS.dark, 0.18, 0.52, 0.28, 'eye_r'); |
| addPart(group, new THREE.BoxGeometry(0.14, 0.18, 0.1), WORLD_MATERIALS.dark, 0, 0.34, 0.3, 'nose'); |
| group.userData.animKind = 'still'; |
| group.userData.baseY = 0; |
| group.userData.collisionHalf = COLLISION.groundObstacleHalf; |
| return group; |
| } |
|
|
| function buildVulture() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.72, 0.32, 0.46), WORLD_MATERIALS.obstacleMain, 0, 0.18, 0, 'body'); |
| addPart(group, new THREE.BoxGeometry(0.28, 0.22, 0.22), WORLD_MATERIALS.obstacleMain, 0, 0.42, 0.18, 'head'); |
| addPart(group, new THREE.BoxGeometry(0.16, 0.08, 0.2), WORLD_MATERIALS.accent, 0, 0.36, 0.34, 'beak'); |
| addPart(group, new THREE.BoxGeometry(0.12, 0.08, 0.9), WORLD_MATERIALS.obstacleAlt, -0.46, 0.22, 0, 'wing_l'); |
| addPart(group, new THREE.BoxGeometry(0.12, 0.08, 0.9), WORLD_MATERIALS.obstacleAlt, 0.46, 0.22, 0, 'wing_r'); |
| group.userData.animKind = 'vulture'; |
| group.userData.baseY = 1.9; |
| group.userData.collisionHalf = COLLISION.aerialObstacleHalf; |
| return group; |
| } |
|
|
| function buildMonkeyLookout() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.9, 0.1, 0.2), WORLD_MATERIALS.obstacleMain, 0, 0.42, 0, 'branch'); |
| addPart(group, new THREE.BoxGeometry(0.34, 0.3, 0.28), WORLD_MATERIALS.neutral, 0, 0.72, 0, 'body'); |
| addPart(group, new THREE.BoxGeometry(0.24, 0.22, 0.22), WORLD_MATERIALS.neutral, 0.08, 0.98, 0.06, 'head'); |
| addPart(group, new THREE.BoxGeometry(0.1, 0.24, 0.1), WORLD_MATERIALS.obstacleMain, -0.18, 0.68, 0.04, 'arm_l'); |
| addPart(group, new THREE.BoxGeometry(0.1, 0.28, 0.1), WORLD_MATERIALS.obstacleMain, 0.18, 0.62, 0.08, 'arm_r'); |
| addPart(group, new THREE.BoxGeometry(0.1, 0.1, 0.48), WORLD_MATERIALS.obstacleMain, -0.22, 0.58, -0.18, 'tail'); |
| group.userData.animKind = 'watcher'; |
| return group; |
| } |
|
|
| function buildParrotHover() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.38, 0.34, 0.3), WORLD_MATERIALS.obstacleAlt, 0, 0.82, 0.06, 'body'); |
| addPart(group, new THREE.BoxGeometry(0.26, 0.24, 0.24), WORLD_MATERIALS.obstacleAlt, 0, 1.06, 0.14, 'head'); |
| addPart(group, new THREE.BoxGeometry(0.12, 0.1, 0.2), WORLD_MATERIALS.accent, 0, 1.0, 0.34, 'beak'); |
| addPart(group, new THREE.BoxGeometry(0.12, 0.14, 0.58), WORLD_MATERIALS.accent, -0.24, 0.84, 0.08, 'wing_l'); |
| addPart(group, new THREE.BoxGeometry(0.12, 0.14, 0.58), WORLD_MATERIALS.accent, 0.24, 0.84, 0.08, 'wing_r'); |
| group.userData.animKind = 'hover'; |
| return group; |
| } |
|
|
| function buildLemurWatcher() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.3, 0.34, 0.24), WORLD_MATERIALS.decorAlt, 0, 0.72, 0, 'body'); |
| addPart(group, new THREE.BoxGeometry(0.24, 0.22, 0.22), WORLD_MATERIALS.decorMain, 0, 0.98, 0.04, 'head'); |
| addPart(group, new THREE.BoxGeometry(0.1, 0.62, 0.1), WORLD_MATERIALS.decorMain, 0.18, 0.42, -0.08, 'tail'); |
| group.userData.animKind = 'watcher'; |
| return group; |
| } |
|
|
| function buildElephantBackdrop() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(1.2, 0.72, 0.72), WORLD_MATERIALS.decorAlt, 0, 0.52, 0, 'body'); |
| addPart(group, new THREE.BoxGeometry(0.46, 0.42, 0.42), WORLD_MATERIALS.decorAlt, 0.48, 0.6, 0.02, 'head'); |
| addPart(group, new THREE.BoxGeometry(0.16, 0.42, 0.16), WORLD_MATERIALS.decorMain, 0.58, 0.26, 0.18, 'trunk'); |
| group.userData.animKind = 'slow'; |
| return group; |
| } |
|
|
| function buildBambooStalk() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.2, 1.8, 0.2), WORLD_MATERIALS.decorMain, 0, 0.9, 0, 'stalk'); |
| addPart(group, new THREE.BoxGeometry(0.5, 0.1, 0.24), WORLD_MATERIALS.groundAccent, -0.22, 1.45, 0, 'leaf_l', { rotation: { z: 0.35 } }); |
| addPart(group, new THREE.BoxGeometry(0.5, 0.1, 0.24), WORLD_MATERIALS.groundAccent, 0.22, 1.3, 0, 'leaf_r', { rotation: { z: -0.35 } }); |
| group.userData.animKind = 'sway'; |
| return group; |
| } |
|
|
| function buildFireflyCluster() { |
| const group = new THREE.Group(); |
| for (let i = 0; i < 3; i++) { |
| const lightOrb = addPart(group, new THREE.BoxGeometry(0.06, 0.06, 0.06), WORLD_MATERIALS.emissive, randRange(-0.2, 0.2), randRange(0.8, 1.3), randRange(-0.2, 0.2), 'orb_' + i); |
| const point = new THREE.PointLight(0xffeb88, 0.25, 3, 2); |
| point.position.copy(lightOrb.position); |
| group.add(point); |
| } |
| group.userData.animKind = 'fireflies'; |
| return group; |
| } |
|
|
| function buildGuardTower() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.8, 1.8, 0.8), WORLD_MATERIALS.decorMain, 0, 0.9, 0, 'tower'); |
| addPart(group, new THREE.BoxGeometry(1.0, 0.16, 1.0), WORLD_MATERIALS.obstacleAlt, 0, 1.74, 0, 'roof'); |
| group.userData.animKind = 'slow'; |
| return group; |
| } |
|
|
| function buildLanternPost() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.12, 1.8, 0.12), WORLD_MATERIALS.decorMain, 0, 0.9, 0, 'post'); |
| addPart(group, new THREE.BoxGeometry(0.38, 0.38, 0.38), WORLD_MATERIALS.emissive, 0, 1.54, 0, 'lantern'); |
| group.userData.animKind = 'lantern'; |
| return group; |
| } |
|
|
| function buildNeonSign() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.18, 1.4, 0.18), WORLD_MATERIALS.decorMain, 0, 0.7, 0, 'post'); |
| addPart(group, new THREE.BoxGeometry(0.92, 0.34, 0.14), WORLD_MATERIALS.sign, 0.44, 1.18, 0, 'panel'); |
| group.userData.animKind = 'neon'; |
| return group; |
| } |
|
|
| function buildHydrant() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.26, 0.44, 0.26), WORLD_MATERIALS.obstacleAlt, 0, 0.22, 0, 'body'); |
| addPart(group, new THREE.BoxGeometry(0.46, 0.14, 0.14), WORLD_MATERIALS.obstacleAlt, 0, 0.3, 0, 'crossbar'); |
| group.userData.animKind = 'still'; |
| return group; |
| } |
|
|
| function buildStreetlamp() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.12, 1.9, 0.12), WORLD_MATERIALS.decorMain, 0, 0.95, 0, 'pole'); |
| addPart(group, new THREE.BoxGeometry(0.52, 0.08, 0.08), WORLD_MATERIALS.decorMain, 0.18, 1.72, 0, 'arm'); |
| addPart(group, new THREE.BoxGeometry(0.22, 0.3, 0.22), WORLD_MATERIALS.emissive, 0.42, 1.5, 0, 'lamp'); |
| group.userData.animKind = 'lamp'; |
| return group; |
| } |
|
|
| function buildCactus() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.34, 1.1, 0.34), WORLD_MATERIALS.decorMain, 0, 0.55, 0, 'stem'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.52, 0.18), WORLD_MATERIALS.decorMain, -0.22, 0.68, 0, 'arm_l'); |
| addPart(group, new THREE.BoxGeometry(0.18, 0.46, 0.18), WORLD_MATERIALS.decorMain, 0.22, 0.56, 0, 'arm_r'); |
| group.userData.animKind = 'slow'; |
| return group; |
| } |
|
|
| function buildBones() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.6, 0.12, 0.12), WORLD_MATERIALS.decorAlt, -0.14, 0.06, 0, 'bone_l', { rotation: { z: 0.35 } }); |
| addPart(group, new THREE.BoxGeometry(0.6, 0.12, 0.12), WORLD_MATERIALS.decorAlt, 0.14, 0.06, 0, 'bone_r', { rotation: { z: -0.35 } }); |
| group.userData.animKind = 'still'; |
| return group; |
| } |
|
|
| function buildDustDevil() { |
| const group = new THREE.Group(); |
| addPart(group, new THREE.BoxGeometry(0.18, 1.2, 0.18), WORLD_MATERIALS.groundAccent, 0, 0.6, 0, 'core'); |
| addPart(group, new THREE.BoxGeometry(0.44, 0.08, 0.44), WORLD_MATERIALS.obstacleAlt, 0, 0.22, 0, 'ring_1'); |
| addPart(group, new THREE.BoxGeometry(0.62, 0.08, 0.62), WORLD_MATERIALS.obstacleAlt, 0, 0.64, 0, 'ring_2'); |
| addPart(group, new THREE.BoxGeometry(0.78, 0.08, 0.78), WORLD_MATERIALS.obstacleAlt, 0, 1.0, 0, 'ring_3'); |
| group.userData.animKind = 'dust_devil'; |
| return group; |
| } |
|
|
| function buildBiomeObstacle(biome, type, options) { |
| const key = type === 'ground' ? biome.obstacleKinds.ground : biome.obstacleKinds.aerial; |
| const builder = OBSTACLE_BUILDERS[key]; |
| if (!builder) return buildFallenLog(); |
| const obstacle = builder(options || {}); |
| obstacle.name = key; |
| obstacle.userData.type = type; |
| return obstacle; |
| } |
|
|
| function buildBiomeDecor(kind) { |
| const builder = DECOR_BUILDERS[kind] || buildMonkeyLookout; |
| const decor = builder(); |
| decor.name = kind; |
| return decor; |
| } |
|
|
| function buildSelectionScene() { |
| clearGroup(selectionGroup); |
| selectionDisplays.length = 0; |
| applyBiomeMaterials(getBiome(0)); |
| scene.background.setHex(getBiome(0).background); |
| scene.fog.color.setHex(getBiome(0).fog); |
| scene.fog.near = 18; |
| scene.fog.far = 52; |
| for (let i = 0; i < SELECT_LAYOUT.length; i++) { |
| const layout = SELECT_LAYOUT[i]; |
| const display = createSelectionDisplay(layout.key); |
| display.position.set(layout.x, 0, layout.z); |
| selectionGroup.add(display); |
| selectionDisplays.push(display); |
| } |
| camera.position.set(CAMERA.select.x, CAMERA.select.y, CAMERA.select.z); |
| tempCameraLook.set(CAMERA.select.lookAt.x, CAMERA.select.lookAt.y, CAMERA.select.lookAt.z); |
| camera.lookAt(tempCameraLook); |
| } |
|
|
| function buildPatternForBiome() { |
| const base = JSON.parse(JSON.stringify(pickOne(PATTERN_LIBRARY))); |
| const used = {}; |
| for (let i = 0; i < base.obstacles.length; i++) { |
| if (base.obstacles[i].lane === null) { |
| let lane = randInt(0, 2); |
| while (used[lane]) lane = randInt(0, 2); |
| used[lane] = true; |
| base.obstacles[i].lane = lane; |
| } |
| } |
| for (let i = 0; i < base.fruits.length; i++) { |
| if (base.fruits[i].lane === null) base.fruits[i].lane = randInt(0, 2); |
| } |
|
|
| if (currentBiome.specialHazard === 'bamboo_wall' && totalRunTime > 8 && Math.random() < 0.18) { |
| const lane = randInt(0, 1); |
| base.obstacles.push({ type: 'ground', lane, zOffset: -1.1 }); |
| base.obstacles.push({ type: 'aerial', lane: lane + 1, zOffset: -2.2 }); |
| } |
| if (currentBiome.specialHazard === 'double_step' && totalRunTime > 12 && Math.random() < 0.2) { |
| const lane = randInt(0, 2); |
| base.obstacles.push({ type: 'ground', lane, zOffset: -1.25 }); |
| } |
| if (bananaHoardTimer > 0) { |
| const extra = []; |
| for (let i = 0; i < base.fruits.length; i++) { |
| extra.push({ lane: clamp(base.fruits[i].lane - 1, 0, 2), zOffset: base.fruits[i].zOffset - 0.4 }); |
| extra.push({ lane: clamp(base.fruits[i].lane + 1, 0, 2), zOffset: base.fruits[i].zOffset - 0.8 }); |
| } |
| base.fruits = base.fruits.concat(extra); |
| } |
| return base; |
| } |
|
|