🔬 AI発明ギャラリー syunsuke 宿命の戦い(T.レックス・スーVSトリケラトプス・レイン)
🔒 サンドボックス内で実行中 ⛶ 全画面で遊ぶ
HTML / CSS / JS
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>T-REX & TRICERATOPS - Jungle Discovery</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background-color: #1a2e1a;
            font-family: 'Helvetica Neue', Arial, sans-serif;
            color: #fff;
        }
        #ui-overlay {
            position: absolute;
            top: 40px;
            left: 40px;
            pointer-events: none;
            z-index: 10;
        }
        .discovery-label {
            background: rgba(0, 40, 0, 0.6);
            padding: 20px;
            border-left: 5px solid #2ecc71;
            box-shadow: 0 10px 30px rgba(0,0,0,0.3);
            backdrop-filter: blur(8px);
        }
        h1 { margin: 0; font-size: 24px; letter-spacing: 2px; color: #2ecc71; }
        p { margin: 5px 0; font-size: 14px; color: #eee; }
        .controls-hint {
            position: absolute;
            bottom: 30px;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(0, 0, 0, 0.7);
            color: #fff;
            padding: 10px 25px;
            border-radius: 30px;
            font-size: 12px;
            pointer-events: none;
        }
        #loading {
            position: fixed;
            top: 0; left: 0; width: 100%; height: 100%;
            background: #1a2e1a;
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 100;
            transition: opacity 1s;
        }
    </style>
</head>
<body>

<div id="loading">古代の対峙を再現中...</div>

<div id="ui-overlay">
    <div class="discovery-label">
        <h1>APEX PREDATOR vs DEFENDER</h1>
        <p>Discovery: T-Rex & Triceratops "Lane" Style</p>
        <p>Location: Hell Creek Formation (Deep Jungle)</p>
        <p style="font-style: italic; color: #ffcc00; font-weight: bold;">[ ROARING POSE vs DEFENSIVE STANCE ]</p>
    </div>
</div>

<div class="controls-hint">
    マウスで回転 / スクロールでズーム / 迫力の対決シーンを鑑賞
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>

<script>
    let scene, camera, renderer, controls, trexGroup, triceratopsGroup;

    function init() {
        scene = new THREE.Scene();
        const forestGreen = 0x1a2e1a;
        scene.background = new THREE.Color(forestGreen);
        scene.fog = new THREE.Fog(forestGreen, 40, 160);

        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(45, 25, 50);

        renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        document.body.appendChild(renderer.domElement);

        controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.target.set(8, 6, 0);

        const ambient = new THREE.AmbientLight(0xffffff, 1.0); 
        scene.add(ambient);

        const sunLight = new THREE.DirectionalLight(0xfffdf5, 1.6);
        sunLight.position.set(40, 60, 30);
        sunLight.castShadow = true;
        sunLight.shadow.mapSize.width = 2048;
        sunLight.shadow.mapSize.height = 2048;
        scene.add(sunLight);

        const hemiLight = new THREE.HemisphereLight(0x88ccff, 0x224422, 0.4);
        scene.add(hemiLight);

        createForestEnv();
        createTREX();
        createTriceratops();

        document.getElementById('loading').style.opacity = '0';
        setTimeout(() => document.getElementById('loading').remove(), 1000);

        window.addEventListener('resize', onWindowResize, false);
        animate();
    }

    function createForestEnv() {
        const groundGeo = new THREE.PlaneGeometry(400, 400, 32, 32);
        const groundMat = new THREE.MeshStandardMaterial({ color: 0x2d422d, roughness: 1.0 });
        const ground = new THREE.Mesh(groundGeo, groundMat);
        ground.rotation.x = -Math.PI / 2;
        ground.receiveShadow = true;
        scene.add(ground);

        for (let i = 0; i < 120; i++) {
            const tree = createTree();
            const angle = Math.random() * Math.PI * 2;
            const dist = 50 + Math.random() * 120;
            const x = Math.cos(angle) * dist;
            const z = Math.sin(angle) * dist;
            if (Math.abs(x) < 30 && Math.abs(z) < 30) continue;
            tree.position.set(x, 0, z);
            tree.rotation.y = Math.random() * Math.PI;
            const scale = 1.0 + Math.random() * 2.0;
            tree.scale.set(scale, scale, scale);
            scene.add(tree);
        }
    }

    function createTree() {
        const group = new THREE.Group();
        const trunkGeo = new THREE.CylinderGeometry(0.4, 0.7, 14, 8);
        const trunkMat = new THREE.MeshStandardMaterial({ color: 0x4d382d });
        const trunk = new THREE.Mesh(trunkGeo, trunkMat);
        trunk.position.y = 7;
        trunk.castShadow = true;
        group.add(trunk);
        const leafMat = new THREE.MeshStandardMaterial({ color: 0x163d16 });
        for (let i = 0; i < 4; i++) {
            const leafGeo = new THREE.ConeGeometry(4 - i * 0.8, 8, 8);
            const leaves = new THREE.Mesh(leafGeo, leafMat);
            leaves.position.y = 11 + i * 3;
            leaves.castShadow = true;
            group.add(leaves);
        }
        return group;
    }

    function createBonePart(geo, x, y, z, rx=0, ry=0, rz=0, color=0x5d4632) {
        const mat = new THREE.MeshStandardMaterial({ color: color, roughness: 0.6, metalness: 0.1 });
        const mesh = new THREE.Mesh(geo, mat);
        mesh.position.set(x, y, z);
        mesh.rotation.set(rx, ry, rz);
        mesh.castShadow = true;
        mesh.receiveShadow = true;
        return mesh;
    }

    function createCurvedBone(path, radius, radialSegments, tubularSegments, color=0x5d4632) {
        const geo = new THREE.TubeGeometry(path, tubularSegments, radius, radialSegments, false);
        const mat = new THREE.MeshStandardMaterial({ color: color, roughness: 0.6 });
        const mesh = new THREE.Mesh(geo, mat);
        mesh.castShadow = true;
        mesh.receiveShadow = true;
        return mesh;
    }

    function createTREX() {
        trexGroup = new THREE.Group();
        trexGroup.position.set(0, 0.5, 0);

        const skullGroup = new THREE.Group();
        const snout = createBonePart(new THREE.BoxGeometry(3.5, 1.3, 1.5), 1.8, 0.4, 0);
        skullGroup.add(snout);
        const backSkull = createBonePart(new THREE.BoxGeometry(1.6, 1.9, 1.9), 0, 0.7, 0);
        skullGroup.add(backSkull);

        for(let i=0; i<8; i++) {
            const tooth = createBonePart(new THREE.ConeGeometry(0.08, 0.5, 8), -1.5 + i * 0.45, -0.65, 0.6, Math.PI);
            snout.add(tooth);
            const toothR = tooth.clone(); toothR.position.z = -0.6; snout.add(toothR);
        }

        const lowerJawGroup = new THREE.Group();
        const jawBone = createBonePart(new THREE.BoxGeometry(3.8, 0.4, 1.4), 1.9, 0, 0);
        lowerJawGroup.add(jawBone);
        for(let i=0; i<7; i++) {
            const tooth = createBonePart(new THREE.ConeGeometry(0.07, 0.4, 8), -1.4 + i * 0.5, 0.4, 0.5);
            jawBone.add(tooth);
            const toothR = tooth.clone(); toothR.position.z = -0.5; jawBone.add(toothR);
        }
        lowerJawGroup.position.set(-0.5, -0.3, 0); lowerJawGroup.rotation.z = -0.8; 
        skullGroup.add(lowerJawGroup);

        skullGroup.position.set(11, 9, 0); skullGroup.rotation.z = 0.6; 
        trexGroup.add(skullGroup);

        for (let i = 0; i < 55; i++) {
            const t = i / 55;
            const x = 10 - t * 45;
            const y = 6.5 + Math.sin(t * 3.5 + 0.6) * 2.5;
            const size = (t < 0.1) ? 0.5 : (1.4 * (1 - t));
            trexGroup.add(createBonePart(new THREE.BoxGeometry(1.0, size, size*0.8), x, y, 0, 0, 0, Math.cos(t * 3.5 + 0.6) * 0.5));
            if (i > 6 && i < 20) {
                const ribSize = 4.8 * (1 - (i-7)/25);
                trexGroup.add(createBonePart(new THREE.CylinderGeometry(0.14, 0.07, ribSize), x, y-ribSize/2, 1.4, 0.3, 0, 0.5));
                trexGroup.add(createBonePart(new THREE.CylinderGeometry(0.14, 0.07, ribSize), x, y-ribSize/2, -1.4, -0.3, 0, -0.5));
            }
        }
        
        const pelvis = createBonePart(new THREE.BoxGeometry(4.2, 3.0, 3.5), -3, 7.0, 0); trexGroup.add(pelvis);
        const legR = createLeg(); legR.position.set(-2, 9.0, 2.5); legR.rotation.z = 0.3; trexGroup.add(legR);
        const legL = createLeg(); legL.position.set(1.5, 9.0, -2.5); legL.rotation.z = -0.4; trexGroup.add(legL);
        const armR = createBonePart(new THREE.CylinderGeometry(0.2, 0.15, 2.0), 9, 5.5, 1.5, 0, 0, 0.6); trexGroup.add(armR);
        const armL = createBonePart(new THREE.CylinderGeometry(0.2, 0.15, 2.0), 9, 5.5, -1.5, 0, 0, -0.6); trexGroup.add(armL);

        scene.add(trexGroup);
    }

    function createLeg() {
        const leg = new THREE.Group();
        leg.add(createBonePart(new THREE.CylinderGeometry(0.7, 0.6, 6), 0, -3, 0));
        leg.add(createBonePart(new THREE.CylinderGeometry(0.5, 0.4, 6), 0, -8.5, 0.5, 0.5));
        leg.add(createBonePart(new THREE.BoxGeometry(2.8, 0.6, 2.0), 1.0, -11.5, 0.5));
        return leg;
    }

    function createTriceratops() {
        triceratopsGroup = new THREE.Group();
        const boneColor = 0x4a3a2a;
        
        triceratopsGroup.position.set(24, 0.5, 3); 
        triceratopsGroup.rotation.y = -Math.PI / 1.1;

        // --- 頭部ユニット ---
        const skullGroup = new THREE.Group();
        
        // 1. 吻部 (Snout)
        const snout = createBonePart(new THREE.BoxGeometry(3.8, 2.2, 2.0), 0.8, 0.5, 0, 0, 0, 0, boneColor);
        skullGroup.add(snout);

        // 2. 後頭部 (Back of the head)
        const backHead = createBonePart(new THREE.BoxGeometry(1.6, 1.8, 2.0), -1.0, 0.8, 0, 0, 0, 0, boneColor);
        skullGroup.add(backHead);

        // 3. フリルの再構築 (より幅広で扇状の盾に)
        const frillShape = new THREE.Shape();
        const frillSegments = 32;
        const frillRadius = 5.2; // さらに大きく
        const scallopHeight = 0.35;

        // 縁のギザギザ(エポキシピタル)を持つ扇型
        for(let i = 0; i <= frillSegments; i++) {
            const angle = (i / frillSegments) * Math.PI - Math.PI / 2;
            const r = frillRadius + (i % 2 === 0 ? scallopHeight : 0);
            const x = Math.cos(angle) * r;
            const y = Math.sin(angle) * r * 1.2;
            if(i === 0) frillShape.moveTo(x, y);
            else frillShape.lineTo(x, y);
        }
        frillShape.lineTo(0, 0); // 中心へ戻る

        // フェネストラ (穴)
        const holeL = new THREE.Path();
        holeL.absellipse(1.4, 2.6, 0.9, 1.6, 0, Math.PI * 2, true);
        frillShape.holes.push(holeL);
        const holeR = new THREE.Path();
        holeR.absellipse(-1.4, 2.6, 0.9, 1.6, 0, Math.PI * 2, true);
        frillShape.holes.push(holeR);

        const frillGeo = new THREE.ExtrudeGeometry(frillShape, { 
            depth: 0.3, 
            bevelEnabled: true, 
            bevelThickness: 0.1, 
            bevelSize: 0.1 
        });
        
        // フリルの位置と角度を再調整 (後頭部から斜め後ろに流れるように)
        const frillMesh = createBonePart(frillGeo, -1.0, 1.2, 0, Math.PI / 2, Math.PI, 0.5, boneColor);
        skullGroup.add(frillMesh);

        // 4. 嘴 (Beak)
        const beak = createBonePart(new THREE.ConeGeometry(0.8, 2.2, 8), 3.2, -0.4, 0, 0, 0, -Math.PI / 2, boneColor);
        beak.scale.z = 0.7;
        skullGroup.add(beak);

        // 5. 角 (前方へ鋭く)
        const hornPathL = new THREE.CatmullRomCurve3([
            new THREE.Vector3(0, 0, 0),
            new THREE.Vector3(2.5, 1.2, 0.5),
            new THREE.Vector3(6.5, 1.8, 0.4)
        ]);
        const hornL = createCurvedBone(hornPathL, 0.42, 12, 30, boneColor);
        hornL.position.set(0.8, 2.2, 1.1);
        hornL.rotation.set(0.3, 0.1, 0);
        skullGroup.add(hornL);
        
        const hornPathR = new THREE.CatmullRomCurve3([
            new THREE.Vector3(0, 0, 0),
            new THREE.Vector3(2.5, 1.2, -0.5),
            new THREE.Vector3(6.5, 1.8, -0.4)
        ]);
        const hornR = createCurvedBone(hornPathR, 0.42, 12, 30, boneColor);
        hornR.position.set(0.8, 2.2, -1.1);
        hornR.rotation.set(-0.3, -0.1, 0);
        skullGroup.add(hornR);

        const hornN = createBonePart(new THREE.ConeGeometry(0.45, 1.6, 12), 2.8, 1.8, 0, 0, 0, 0.3, boneColor);
        skullGroup.add(hornN);

        // 6. 眼窩
        const eyeL = createBonePart(new THREE.BoxGeometry(1.0, 1.0, 0.3), -0.2, 1.6, 1.1, 0, 0, 0, 0x111111);
        skullGroup.add(eyeL);
        const eyeR = eyeL.clone(); eyeR.position.z = -1.1;
        skullGroup.add(eyeR);

        skullGroup.position.set(6, 4.5, 0);
        skullGroup.rotation.z = 0.1;
        triceratopsGroup.add(skullGroup);

        // --- 胴体 ---
        const spinePoints = [];
        for(let i=0; i<=12; i++) {
            const t = i/12;
            spinePoints.push(new THREE.Vector3(5 - t * 25, 5 + Math.sin(t * Math.PI) * 1.6, 0));
        }
        const spineCurve = new THREE.CatmullRomCurve3(spinePoints);
        triceratopsGroup.add(createCurvedBone(spineCurve, 0.8, 12, 60, boneColor));

        for(let i=0; i<16; i++) {
            const t = i / 16;
            const p = spineCurve.getPoint(t);
            const ribW = 5.5 * Math.sin(t * Math.PI * 0.8 + 0.35);
            if(ribW < 1.8) continue;

            const ribLPath = new THREE.CatmullRomCurve3([
                new THREE.Vector3(0, 0, 0),
                new THREE.Vector3(1.4, -ribW*0.6, ribW*0.6),
                new THREE.Vector3(0.4, -ribW, 0.4)
            ]);
            const ribL = createCurvedBone(ribLPath, 0.25, 8, 20, boneColor);
            ribL.position.set(p.x, p.y - 0.5, 1.2);
            triceratopsGroup.add(ribL);
            
            const ribRPath = new THREE.CatmullRomCurve3([
                new THREE.Vector3(0, 0, 0),
                new THREE.Vector3(1.4, -ribW*0.6, -ribW*0.6),
                new THREE.Vector3(0.4, -ribW, -0.4)
            ]);
            const ribR = createCurvedBone(ribRPath, 0.25, 8, 20, boneColor);
            ribR.position.set(p.x, p.y - 0.5, -1.2);
            triceratopsGroup.add(ribR);
        }

        const createLimb = (isFront) => {
            const group = new THREE.Group();
            const h1 = isFront ? 4.0 : 5.0;
            const h2 = isFront ? 3.0 : 4.0;
            const w = isFront ? 0.95 : 1.2;
            group.add(createBonePart(new THREE.CylinderGeometry(w, w*0.8, h1, 12), 0, -h1/2, 0, 0, 0, 0, boneColor));
            group.add(createBonePart(new THREE.CylinderGeometry(w*0.8, w*0.6, h2, 12), 0, -h1 - h2/2, 0, 0.15, 0, 0, boneColor));
            group.add(createBonePart(new THREE.BoxGeometry(2.5, 0.8, 2.5), 0.8, -h1 - h2 - 0.4, 0, 0, 0, 0, boneColor));
            return group;
        };

        const fL = createLimb(true); fL.position.set(2.8, 4.5, 3.0); triceratopsGroup.add(fL);
        const fR = createLimb(true); fR.position.set(2.8, 4.5, -3.0); triceratopsGroup.add(fR);
        const bL = createLimb(false); bL.position.set(-10, 5.2, 3.5); triceratopsGroup.add(bL);
        const bR = createLimb(false); bR.position.set(-10, 5.2, -3.5); triceratopsGroup.add(bR);

        scene.add(triceratopsGroup);
    }

    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function animate() {
        requestAnimationFrame(animate);
        controls.update();
        renderer.render(scene, camera);
    }

    window.onload = init;
</script>

</body>
</html>

宿命の戦い(T.レックス・スーVSトリケラトプス・レイン)

2匹の恐竜が戦っているシーンを再現しました

🤖 使用したAI
Gemini
👁 25 回閲覧
📅 投稿:2026年4月18日 🔄 更新:2026年8月13日
応援スタンプを押してみよう!