返回列表 发布新帖
查看: 9|回复: 0

狼来了

3

主题

0

回帖

23

积分

管理员

积分
23
发表于 前天 22:42 | 查看全部 |阅读模式 IP:江苏
这是一款基于 Three.js 和 GSAP TweenMax 开发的 3D 网页小游戏,玩家操控兔子奔跑、跳跃并收集胡萝卜,同时躲避刺猬。游戏使用 WebGL 渲染、响应式设计,支持鼠标与触屏交互,适合展示前端动画、3D 建模与游戏开发技巧


HTML在线运行工具:https://tool.fenx.top/beeseek/HTML/


  1. <!DOCTYPE html>
  2. <html lang="zh">
  3.   <head>
  4.     <meta charset="UTF-8" />
  5.     <title>狼来了</title>
  6.     <link
  7.       rel="stylesheet"
  8.       href="https://public.codepenassets.com/css/reset-2.0.min.css"
  9.     />
  10.     <style>
  11.       @import url("https://fonts.googleapis.com/css?family=Voltaire");
  12.       #world {
  13.         position: absolute;
  14.         width: 100%;
  15.         height: 100%;
  16.         background-color: #dbe6e6;
  17.         overflow: hidden;
  18.       }

  19.       #gameoverInstructions {
  20.         position: absolute;
  21.         font-family: "Voltaire", sans-serif;
  22.         font-weight: bold;
  23.         text-transform: uppercase;
  24.         font-size: 120px;
  25.         text-align: center;
  26.         color: #ffc5a2;
  27.         opacity: 0;
  28.         left: 50%;
  29.         top: 50%;
  30.         width: 100%;
  31.         transform: translate(-50%, -100%);
  32.         -webkit-user-select: none;
  33.         -moz-user-select: none;
  34.         -ms-user-select: none;
  35.         user-select: none;
  36.         transition: all 500ms ease-in-out;
  37.       }
  38.       #gameoverInstructions.show {
  39.         opacity: 1;
  40.         transform: translate(-50%, -50%);
  41.         transition: all 500ms ease-in-out;
  42.       }

  43.       #dist {
  44.         position: absolute;
  45.         left: 50%;
  46.         top: 50px;
  47.         transform: translate(-50%, 0%);
  48.         -webkit-user-select: none;
  49.         -moz-user-select: none;
  50.         -ms-user-select: none;
  51.         user-select: none;
  52.       }

  53.       .label {
  54.         position: relative;
  55.         font-family: "Voltaire", sans-serif;
  56.         text-transform: uppercase;
  57.         color: #ffa873;
  58.         font-size: 12px;
  59.         letter-spacing: 2px;
  60.         text-align: center;
  61.         margin-bottom: 5px;
  62.       }

  63.       #distValue {
  64.         position: relative;
  65.         text-transform: uppercase;
  66.         color: #dc5f45;
  67.         font-size: 40px;
  68.         font-family: "Voltaire";
  69.         text-align: center;
  70.       }

  71.       #credits {
  72.         position: absolute;
  73.         width: 100%;
  74.         margin: auto;
  75.         bottom: 0;
  76.         margin-bottom: 20px;
  77.         font-family: "Voltaire", sans-serif;
  78.         color: #544027;
  79.         font-size: 12px;
  80.         letter-spacing: 0.5px;
  81.         text-transform: uppercase;
  82.         text-align: center;
  83.         -webkit-user-select: none;
  84.         -moz-user-select: none;
  85.         -ms-user-select: none;
  86.         user-select: none;
  87.       }

  88.       #credits a {
  89.         color: #544027;
  90.       }

  91.       #credits a:hover {
  92.         color: #dc5f45;
  93.       }

  94.       #instructions {
  95.         position: absolute;
  96.         width: 100%;
  97.         bottom: 0;
  98.         margin: auto;
  99.         margin-bottom: 50px;
  100.         font-family: "Voltaire", sans-serif;
  101.         color: #dc5f45;
  102.         font-size: 16px;
  103.         letter-spacing: 1px;
  104.         text-transform: uppercase;
  105.         text-align: center;
  106.         -webkit-user-select: none;
  107.         -moz-user-select: none;
  108.         -ms-user-select: none;
  109.         user-select: none;
  110.       }

  111.       .lightInstructions {
  112.         color: #5f9042;
  113.       }
  114.     </style>
  115.   </head>
  116.   <body>
  117.     <div id="world" />
  118.     <div id="gameoverInstructions">游戏结束</div>
  119.     <div id="dist">
  120.       <div class="label">距离</div>
  121.       <div id="distValue">000</div>
  122.     </div>

  123.     <div id="instructions">
  124.       点击跳跃<span class="lightInstructions"> — 捡起胡萝卜 / 避开刺猬</span>
  125.     </div>

  126.     <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r80/three.js"></script>
  127.     <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
  128.     <script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/OrbitControls.js"></script>
  129.     <script>
  130.       //THREEJS RELATED VARIABLES

  131.       var scene,
  132.         camera,
  133.         fieldOfView,
  134.         aspectRatio,
  135.         nearPlane,
  136.         farPlane,
  137.         gobalLight,
  138.         shadowLight,
  139.         backLight,
  140.         renderer,
  141.         container,
  142.         controls,
  143.         clock;
  144.       var delta = 0;
  145.       var floorRadius = 200;
  146.       var speed = 6;
  147.       var distance = 0;
  148.       var level = 1;
  149.       var levelInterval;
  150.       var levelUpdateFreq = 3000;
  151.       var initSpeed = 5;
  152.       var maxSpeed = 48;
  153.       var monsterPos = 0.65;
  154.       var monsterPosTarget = 0.65;
  155.       var floorRotation = 0;
  156.       var collisionObstacle = 10;
  157.       var collisionBonus = 20;
  158.       var gameStatus = "play";
  159.       var cameraPosGame = 160;
  160.       var cameraPosGameOver = 260;
  161.       var monsterAcceleration = 0.004;
  162.       var malusClearColor = 0xb44b39;
  163.       var malusClearAlpha = 0;
  164.       var audio = new Audio(
  165.         "https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/Antonio-Vivaldi-Summer_01.mp3"
  166.       );

  167.       var fieldGameOver, fieldDistance;

  168.       //SCREEN & MOUSE VARIABLES

  169.       var HEIGHT,
  170.         WIDTH,
  171.         windowHalfX,
  172.         windowHalfY,
  173.         mousePos = {
  174.           x: 0,
  175.           y: 0,
  176.         };

  177.       //3D OBJECTS VARIABLES

  178.       var hero;

  179.       // Materials
  180.       var blackMat = new THREE.MeshPhongMaterial({
  181.         color: 0x100707,
  182.         shading: THREE.FlatShading,
  183.       });

  184.       var brownMat = new THREE.MeshPhongMaterial({
  185.         color: 0xb44b39,
  186.         shininess: 0,
  187.         shading: THREE.FlatShading,
  188.       });

  189.       var greenMat = new THREE.MeshPhongMaterial({
  190.         color: 0x7abf8e,
  191.         shininess: 0,
  192.         shading: THREE.FlatShading,
  193.       });

  194.       var pinkMat = new THREE.MeshPhongMaterial({
  195.         color: 0xdc5f45, //0xb43b29,//0xff5b49,
  196.         shininess: 0,
  197.         shading: THREE.FlatShading,
  198.       });

  199.       var lightBrownMat = new THREE.MeshPhongMaterial({
  200.         color: 0xe07a57,
  201.         shading: THREE.FlatShading,
  202.       });

  203.       var whiteMat = new THREE.MeshPhongMaterial({
  204.         color: 0xa49789,
  205.         shading: THREE.FlatShading,
  206.       });
  207.       var skinMat = new THREE.MeshPhongMaterial({
  208.         color: 0xff9ea5,
  209.         shading: THREE.FlatShading,
  210.       });

  211.       // OTHER VARIABLES

  212.       var PI = Math.PI;

  213.       //INIT THREE JS, SCREEN AND MOUSE EVENTS

  214.       function initScreenAnd3D() {
  215.         HEIGHT = window.innerHeight;
  216.         WIDTH = window.innerWidth;
  217.         windowHalfX = WIDTH / 2;
  218.         windowHalfY = HEIGHT / 2;

  219.         scene = new THREE.Scene();

  220.         scene.fog = new THREE.Fog(0xd6eae6, 160, 350);

  221.         aspectRatio = WIDTH / HEIGHT;
  222.         fieldOfView = 50;
  223.         nearPlane = 1;
  224.         farPlane = 2000;
  225.         camera = new THREE.PerspectiveCamera(
  226.           fieldOfView,
  227.           aspectRatio,
  228.           nearPlane,
  229.           farPlane
  230.         );
  231.         camera.position.x = 0;
  232.         camera.position.z = cameraPosGame;
  233.         camera.position.y = 30;
  234.         camera.lookAt(new THREE.Vector3(0, 30, 0));

  235.         renderer = new THREE.WebGLRenderer({
  236.           alpha: true,
  237.           antialias: true,
  238.         });
  239.         renderer.setPixelRatio(window.devicePixelRatio);
  240.         renderer.setClearColor(malusClearColor, malusClearAlpha);

  241.         renderer.setSize(WIDTH, HEIGHT);
  242.         renderer.shadowMap.enabled = true;

  243.         container = document.getElementById("world");
  244.         container.appendChild(renderer.domElement);

  245.         window.addEventListener("resize", handleWindowResize, false);
  246.         document.addEventListener("mousedown", handleMouseDown, false);
  247.         document.addEventListener("touchend", handleMouseDown, false);

  248.         /*
  249.   controls = new THREE.OrbitControls(camera, renderer.domElement);
  250.   //controls.minPolarAngle = -Math.PI / 2;
  251.   //controls.maxPolarAngle = Math.PI / 2;
  252.   //controls.noZoom = true;
  253.   controls.noPan = true;
  254.   //*/

  255.         clock = new THREE.Clock();
  256.       }

  257.       function handleWindowResize() {
  258.         HEIGHT = window.innerHeight;
  259.         WIDTH = window.innerWidth;
  260.         windowHalfX = WIDTH / 2;
  261.         windowHalfY = HEIGHT / 2;
  262.         renderer.setSize(WIDTH, HEIGHT);
  263.         camera.aspect = WIDTH / HEIGHT;
  264.         camera.updateProjectionMatrix();
  265.       }

  266.       function handleMouseDown(event) {
  267.         if (gameStatus == "play") hero.jump();
  268.         else if (gameStatus == "readyToReplay") {
  269.           replay();
  270.         }
  271.       }

  272.       function createLights() {
  273.         globalLight = new THREE.AmbientLight(0xffffff, 0.9);

  274.         shadowLight = new THREE.DirectionalLight(0xffffff, 1);
  275.         shadowLight.position.set(-30, 40, 20);
  276.         shadowLight.castShadow = true;
  277.         shadowLight.shadow.camera.left = -400;
  278.         shadowLight.shadow.camera.right = 400;
  279.         shadowLight.shadow.camera.top = 400;
  280.         shadowLight.shadow.camera.bottom = -400;
  281.         shadowLight.shadow.camera.near = 1;
  282.         shadowLight.shadow.camera.far = 2000;
  283.         shadowLight.shadow.mapSize.width =
  284.           shadowLight.shadow.mapSize.height = 2048;

  285.         scene.add(globalLight);
  286.         scene.add(shadowLight);
  287.       }

  288.       function createFloor() {
  289.         floorShadow = new THREE.Mesh(
  290.           new THREE.SphereGeometry(floorRadius, 50, 50),
  291.           new THREE.MeshPhongMaterial({
  292.             color: 0x7abf8e,
  293.             specular: 0x000000,
  294.             shininess: 1,
  295.             transparent: true,
  296.             opacity: 0.5,
  297.           })
  298.         );
  299.         //floorShadow.rotation.x = -Math.PI / 2;
  300.         floorShadow.receiveShadow = true;

  301.         floorGrass = new THREE.Mesh(
  302.           new THREE.SphereGeometry(floorRadius - 0.5, 50, 50),
  303.           new THREE.MeshBasicMaterial({
  304.             color: 0x7abf8e,
  305.           })
  306.         );
  307.         //floor.rotation.x = -Math.PI / 2;
  308.         floorGrass.receiveShadow = false;

  309.         floor = new THREE.Group();
  310.         floor.position.y = -floorRadius;

  311.         floor.add(floorShadow);
  312.         floor.add(floorGrass);
  313.         scene.add(floor);
  314.       }

  315.       Hero = function () {
  316.         this.status = "running";
  317.         this.runningCycle = 0;
  318.         this.mesh = new THREE.Group();
  319.         this.body = new THREE.Group();
  320.         this.mesh.add(this.body);

  321.         var torsoGeom = new THREE.CubeGeometry(7, 7, 10, 1);

  322.         this.torso = new THREE.Mesh(torsoGeom, brownMat);
  323.         this.torso.position.z = 0;
  324.         this.torso.position.y = 7;
  325.         this.torso.castShadow = true;
  326.         this.body.add(this.torso);

  327.         var pantsGeom = new THREE.CubeGeometry(9, 9, 5, 1);
  328.         this.pants = new THREE.Mesh(pantsGeom, whiteMat);
  329.         this.pants.position.z = -3;
  330.         this.pants.position.y = 0;
  331.         this.pants.castShadow = true;
  332.         this.torso.add(this.pants);

  333.         var tailGeom = new THREE.CubeGeometry(3, 3, 3, 1);
  334.         tailGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 0, -2));
  335.         this.tail = new THREE.Mesh(tailGeom, lightBrownMat);
  336.         this.tail.position.z = -4;
  337.         this.tail.position.y = 5;
  338.         this.tail.castShadow = true;
  339.         this.torso.add(this.tail);

  340.         this.torso.rotation.x = -Math.PI / 8;

  341.         var headGeom = new THREE.CubeGeometry(10, 10, 13, 1);

  342.         headGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 0, 7.5));
  343.         this.head = new THREE.Mesh(headGeom, brownMat);
  344.         this.head.position.z = 2;
  345.         this.head.position.y = 11;
  346.         this.head.castShadow = true;
  347.         this.body.add(this.head);

  348.         var cheekGeom = new THREE.CubeGeometry(1, 4, 4, 1);
  349.         this.cheekR = new THREE.Mesh(cheekGeom, pinkMat);
  350.         this.cheekR.position.x = -5;
  351.         this.cheekR.position.z = 7;
  352.         this.cheekR.position.y = -2.5;
  353.         this.cheekR.castShadow = true;
  354.         this.head.add(this.cheekR);

  355.         this.cheekL = this.cheekR.clone();
  356.         this.cheekL.position.x = -this.cheekR.position.x;
  357.         this.head.add(this.cheekL);

  358.         var noseGeom = new THREE.CubeGeometry(6, 6, 3, 1);
  359.         this.nose = new THREE.Mesh(noseGeom, lightBrownMat);
  360.         this.nose.position.z = 13.5;
  361.         this.nose.position.y = 2.6;
  362.         this.nose.castShadow = true;
  363.         this.head.add(this.nose);

  364.         var mouthGeom = new THREE.CubeGeometry(4, 2, 4, 1);
  365.         mouthGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 0, 3));
  366.         mouthGeom.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI / 12));
  367.         this.mouth = new THREE.Mesh(mouthGeom, brownMat);
  368.         this.mouth.position.z = 8;
  369.         this.mouth.position.y = -4;
  370.         this.mouth.castShadow = true;
  371.         this.head.add(this.mouth);

  372.         var pawFGeom = new THREE.CubeGeometry(3, 3, 3, 1);
  373.         this.pawFR = new THREE.Mesh(pawFGeom, lightBrownMat);
  374.         this.pawFR.position.x = -2;
  375.         this.pawFR.position.z = 6;
  376.         this.pawFR.position.y = 1.5;
  377.         this.pawFR.castShadow = true;
  378.         this.body.add(this.pawFR);

  379.         this.pawFL = this.pawFR.clone();
  380.         this.pawFL.position.x = -this.pawFR.position.x;
  381.         this.pawFL.castShadow = true;
  382.         this.body.add(this.pawFL);

  383.         var pawBGeom = new THREE.CubeGeometry(3, 3, 6, 1);
  384.         this.pawBL = new THREE.Mesh(pawBGeom, lightBrownMat);
  385.         this.pawBL.position.y = 1.5;
  386.         this.pawBL.position.z = 0;
  387.         this.pawBL.position.x = 5;
  388.         this.pawBL.castShadow = true;
  389.         this.body.add(this.pawBL);

  390.         this.pawBR = this.pawBL.clone();
  391.         this.pawBR.position.x = -this.pawBL.position.x;
  392.         this.pawBR.castShadow = true;
  393.         this.body.add(this.pawBR);

  394.         var earGeom = new THREE.CubeGeometry(7, 18, 2, 1);
  395.         earGeom.vertices[6].x += 2;
  396.         earGeom.vertices[6].z += 0.5;

  397.         earGeom.vertices[7].x += 2;
  398.         earGeom.vertices[7].z -= 0.5;

  399.         earGeom.vertices[2].x -= 2;
  400.         earGeom.vertices[2].z -= 0.5;

  401.         earGeom.vertices[3].x -= 2;
  402.         earGeom.vertices[3].z += 0.5;
  403.         earGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 9, 0));

  404.         this.earL = new THREE.Mesh(earGeom, brownMat);
  405.         this.earL.position.x = 2;
  406.         this.earL.position.z = 2.5;
  407.         this.earL.position.y = 5;
  408.         this.earL.rotation.z = -Math.PI / 12;
  409.         this.earL.castShadow = true;
  410.         this.head.add(this.earL);

  411.         this.earR = this.earL.clone();
  412.         this.earR.position.x = -this.earL.position.x;
  413.         this.earR.rotation.z = -this.earL.rotation.z;
  414.         this.earR.castShadow = true;
  415.         this.head.add(this.earR);

  416.         var eyeGeom = new THREE.CubeGeometry(2, 4, 4);

  417.         this.eyeL = new THREE.Mesh(eyeGeom, whiteMat);
  418.         this.eyeL.position.x = 5;
  419.         this.eyeL.position.z = 5.5;
  420.         this.eyeL.position.y = 2.9;
  421.         this.eyeL.castShadow = true;
  422.         this.head.add(this.eyeL);

  423.         var irisGeom = new THREE.CubeGeometry(0.6, 2, 2);

  424.         this.iris = new THREE.Mesh(irisGeom, blackMat);
  425.         this.iris.position.x = 1.2;
  426.         this.iris.position.y = 1;
  427.         this.iris.position.z = 1;
  428.         this.eyeL.add(this.iris);

  429.         this.eyeR = this.eyeL.clone();
  430.         this.eyeR.children[0].position.x = -this.iris.position.x;

  431.         this.eyeR.position.x = -this.eyeL.position.x;
  432.         this.head.add(this.eyeR);

  433.         this.body.traverse(function (object) {
  434.           if (object instanceof THREE.Mesh) {
  435.             object.castShadow = true;
  436.             object.receiveShadow = true;
  437.           }
  438.         });
  439.       };

  440.       BonusParticles = function () {
  441.         this.mesh = new THREE.Group();
  442.         var bigParticleGeom = new THREE.CubeGeometry(10, 10, 10, 1);
  443.         var smallParticleGeom = new THREE.CubeGeometry(5, 5, 5, 1);
  444.         this.parts = [];
  445.         for (var i = 0; i < 10; i++) {
  446.           var partPink = new THREE.Mesh(bigParticleGeom, pinkMat);
  447.           var partGreen = new THREE.Mesh(smallParticleGeom, greenMat);
  448.           partGreen.scale.set(0.5, 0.5, 0.5);
  449.           this.parts.push(partPink);
  450.           this.parts.push(partGreen);
  451.           this.mesh.add(partPink);
  452.           this.mesh.add(partGreen);
  453.         }
  454.       };

  455.       BonusParticles.prototype.explose = function () {
  456.         var _this = this;
  457.         var explosionSpeed = 0.5;
  458.         for (var i = 0; i < this.parts.length; i++) {
  459.           var tx = -50 + Math.random() * 100;
  460.           var ty = -50 + Math.random() * 100;
  461.           var tz = -50 + Math.random() * 100;
  462.           var p = this.parts[i];
  463.           p.position.set(0, 0, 0);
  464.           p.scale.set(1, 1, 1);
  465.           p.visible = true;
  466.           var s = explosionSpeed + Math.random() * 0.5;
  467.           TweenMax.to(p.position, s, {
  468.             x: tx,
  469.             y: ty,
  470.             z: tz,
  471.             ease: Power4.easeOut,
  472.           });
  473.           TweenMax.to(p.scale, s, {
  474.             x: 0.01,
  475.             y: 0.01,
  476.             z: 0.01,
  477.             ease: Power4.easeOut,
  478.             onComplete: removeParticle,
  479.             onCompleteParams: [p],
  480.           });
  481.         }
  482.       };

  483.       function removeParticle(p) {
  484.         p.visible = false;
  485.       }

  486.       Hero.prototype.run = function () {
  487.         this.status = "running";

  488.         var s = Math.min(speed, maxSpeed);

  489.         this.runningCycle += delta * s * 0.7;
  490.         this.runningCycle = this.runningCycle % (Math.PI * 2);
  491.         var t = this.runningCycle;

  492.         var amp = 4;
  493.         var disp = 0.2;

  494.         // BODY

  495.         this.body.position.y = 6 + Math.sin(t - Math.PI / 2) * amp;
  496.         this.body.rotation.x = 0.2 + Math.sin(t - Math.PI / 2) * amp * 0.1;

  497.         this.torso.rotation.x = Math.sin(t - Math.PI / 2) * amp * 0.1;
  498.         this.torso.position.y = 7 + Math.sin(t - Math.PI / 2) * amp * 0.5;

  499.         // MOUTH
  500.         this.mouth.rotation.x = Math.PI / 16 + Math.cos(t) * amp * 0.05;

  501.         // HEAD
  502.         this.head.position.z = 2 + Math.sin(t - Math.PI / 2) * amp * 0.5;
  503.         this.head.position.y = 8 + Math.cos(t - Math.PI / 2) * amp * 0.7;
  504.         this.head.rotation.x = -0.2 + Math.sin(t + Math.PI) * amp * 0.1;

  505.         // EARS
  506.         this.earL.rotation.x = Math.cos(-Math.PI / 2 + t) * (amp * 0.2);
  507.         this.earR.rotation.x = Math.cos(-Math.PI / 2 + 0.2 + t) * (amp * 0.3);

  508.         // EYES
  509.         this.eyeR.scale.y = this.eyeL.scale.y =
  510.           0.7 + Math.abs(Math.cos(-Math.PI / 4 + t * 0.5)) * 0.6;

  511.         // TAIL
  512.         this.tail.rotation.x = Math.cos(Math.PI / 2 + t) * amp * 0.3;

  513.         // FRONT RIGHT PAW
  514.         this.pawFR.position.y = 1.5 + Math.sin(t) * amp;
  515.         this.pawFR.rotation.x = (Math.cos(t) * Math.PI) / 4;

  516.         this.pawFR.position.z = 6 - Math.cos(t) * amp * 2;

  517.         // FRONT LEFT PAW

  518.         this.pawFL.position.y = 1.5 + Math.sin(disp + t) * amp;
  519.         this.pawFL.rotation.x = (Math.cos(t) * Math.PI) / 4;

  520.         this.pawFL.position.z = 6 - Math.cos(disp + t) * amp * 2;

  521.         // BACK RIGHT PAW
  522.         this.pawBR.position.y = 1.5 + Math.sin(Math.PI + t) * amp;
  523.         this.pawBR.rotation.x = (Math.cos(t + Math.PI * 1.5) * Math.PI) / 3;

  524.         this.pawBR.position.z = -Math.cos(Math.PI + t) * amp;

  525.         // BACK LEFT PAW
  526.         this.pawBL.position.y = 1.5 + Math.sin(Math.PI + t) * amp;
  527.         this.pawBL.rotation.x = (Math.cos(t + Math.PI * 1.5) * Math.PI) / 3;

  528.         this.pawBL.position.z = -Math.cos(Math.PI + t) * amp;
  529.       };

  530.       Hero.prototype.jump = function () {
  531.         if (this.status == "jumping") return;
  532.         this.status = "jumping";
  533.         var _this = this;
  534.         var totalSpeed = 10 / speed;
  535.         var jumpHeight = 45;

  536.         TweenMax.to(this.earL.rotation, totalSpeed, {
  537.           x: "+=.3",
  538.           ease: Back.easeOut,
  539.         });
  540.         TweenMax.to(this.earR.rotation, totalSpeed, {
  541.           x: "-=.3",
  542.           ease: Back.easeOut,
  543.         });

  544.         TweenMax.to(this.pawFL.rotation, totalSpeed, {
  545.           x: "+=.7",
  546.           ease: Back.easeOut,
  547.         });
  548.         TweenMax.to(this.pawFR.rotation, totalSpeed, {
  549.           x: "-=.7",
  550.           ease: Back.easeOut,
  551.         });
  552.         TweenMax.to(this.pawBL.rotation, totalSpeed, {
  553.           x: "+=.7",
  554.           ease: Back.easeOut,
  555.         });
  556.         TweenMax.to(this.pawBR.rotation, totalSpeed, {
  557.           x: "-=.7",
  558.           ease: Back.easeOut,
  559.         });

  560.         TweenMax.to(this.tail.rotation, totalSpeed, {
  561.           x: "+=1",
  562.           ease: Back.easeOut,
  563.         });

  564.         TweenMax.to(this.mouth.rotation, totalSpeed, {
  565.           x: 0.5,
  566.           ease: Back.easeOut,
  567.         });

  568.         TweenMax.to(this.mesh.position, totalSpeed / 2, {
  569.           y: jumpHeight,
  570.           ease: Power2.easeOut,
  571.         });
  572.         TweenMax.to(this.mesh.position, totalSpeed / 2, {
  573.           y: 0,
  574.           ease: Power4.easeIn,
  575.           delay: totalSpeed / 2,
  576.           onComplete: function () {
  577.             //t = 0;
  578.             _this.status = "running";
  579.           },
  580.         });
  581.       };

  582.       Monster = function () {
  583.         this.runningCycle = 0;

  584.         this.mesh = new THREE.Group();
  585.         this.body = new THREE.Group();

  586.         var torsoGeom = new THREE.CubeGeometry(15, 15, 20, 1);
  587.         this.torso = new THREE.Mesh(torsoGeom, blackMat);

  588.         var headGeom = new THREE.CubeGeometry(20, 20, 40, 1);
  589.         headGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 0, 20));
  590.         this.head = new THREE.Mesh(headGeom, blackMat);
  591.         this.head.position.z = 12;
  592.         this.head.position.y = 2;

  593.         var mouthGeom = new THREE.CubeGeometry(10, 4, 20, 1);
  594.         mouthGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, -2, 10));
  595.         this.mouth = new THREE.Mesh(mouthGeom, blackMat);
  596.         this.mouth.position.y = -8;
  597.         this.mouth.rotation.x = 0.4;
  598.         this.mouth.position.z = 4;

  599.         this.heroHolder = new THREE.Group();
  600.         this.heroHolder.position.z = 20;
  601.         this.mouth.add(this.heroHolder);

  602.         var toothGeom = new THREE.CubeGeometry(2, 2, 1, 1);

  603.         toothGeom.vertices[1].x -= 1;
  604.         toothGeom.vertices[4].x += 1;
  605.         toothGeom.vertices[5].x += 1;
  606.         toothGeom.vertices[0].x -= 1;

  607.         for (var i = 0; i < 3; i++) {
  608.           var toothf = new THREE.Mesh(toothGeom, whiteMat);
  609.           toothf.position.x = -2.8 + i * 2.5;
  610.           toothf.position.y = 1;
  611.           toothf.position.z = 19;

  612.           var toothl = new THREE.Mesh(toothGeom, whiteMat);
  613.           toothl.rotation.y = Math.PI / 2;
  614.           toothl.position.z = 12 + i * 2.5;
  615.           toothl.position.y = 1;
  616.           toothl.position.x = 4;

  617.           var toothr = toothl.clone();
  618.           toothl.position.x = -4;

  619.           this.mouth.add(toothf);
  620.           this.mouth.add(toothl);
  621.           this.mouth.add(toothr);
  622.         }

  623.         var tongueGeometry = new THREE.CubeGeometry(6, 1, 14);
  624.         tongueGeometry.applyMatrix(
  625.           new THREE.Matrix4().makeTranslation(0, 0, 7)
  626.         );

  627.         this.tongue = new THREE.Mesh(tongueGeometry, pinkMat);
  628.         this.tongue.position.z = 2;
  629.         this.tongue.rotation.x = -0.2;
  630.         this.mouth.add(this.tongue);

  631.         var noseGeom = new THREE.CubeGeometry(4, 4, 4, 1);
  632.         this.nose = new THREE.Mesh(noseGeom, pinkMat);
  633.         this.nose.position.z = 39.5;
  634.         this.nose.position.y = 9;
  635.         this.head.add(this.nose);

  636.         this.head.add(this.mouth);

  637.         var eyeGeom = new THREE.CubeGeometry(2, 3, 3);

  638.         this.eyeL = new THREE.Mesh(eyeGeom, whiteMat);
  639.         this.eyeL.position.x = 10;
  640.         this.eyeL.position.z = 5;
  641.         this.eyeL.position.y = 5;
  642.         this.eyeL.castShadow = true;
  643.         this.head.add(this.eyeL);

  644.         var irisGeom = new THREE.CubeGeometry(0.6, 1, 1);

  645.         this.iris = new THREE.Mesh(irisGeom, blackMat);
  646.         this.iris.position.x = 1.2;
  647.         this.iris.position.y = -1;
  648.         this.iris.position.z = 1;
  649.         this.eyeL.add(this.iris);

  650.         this.eyeR = this.eyeL.clone();
  651.         this.eyeR.children[0].position.x = -this.iris.position.x;
  652.         this.eyeR.position.x = -this.eyeL.position.x;
  653.         this.head.add(this.eyeR);

  654.         var earGeom = new THREE.CubeGeometry(8, 6, 2, 1);
  655.         earGeom.vertices[1].x -= 4;
  656.         earGeom.vertices[4].x += 4;
  657.         earGeom.vertices[5].x += 4;
  658.         earGeom.vertices[5].z -= 2;
  659.         earGeom.vertices[0].x -= 4;
  660.         earGeom.vertices[0].z -= 2;

  661.         earGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 3, 0));

  662.         this.earL = new THREE.Mesh(earGeom, blackMat);
  663.         this.earL.position.x = 6;
  664.         this.earL.position.z = 1;
  665.         this.earL.position.y = 10;
  666.         this.earL.castShadow = true;
  667.         this.head.add(this.earL);

  668.         this.earR = this.earL.clone();
  669.         this.earR.position.x = -this.earL.position.x;
  670.         this.earR.rotation.z = -this.earL.rotation.z;
  671.         this.head.add(this.earR);

  672.         var eyeGeom = new THREE.CubeGeometry(2, 4, 4);

  673.         var tailGeom = new THREE.CylinderGeometry(5, 2, 20, 4, 1);
  674.         tailGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 10, 0));
  675.         tailGeom.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI / 2));
  676.         tailGeom.applyMatrix(new THREE.Matrix4().makeRotationZ(Math.PI / 4));

  677.         this.tail = new THREE.Mesh(tailGeom, blackMat);
  678.         this.tail.position.z = -10;
  679.         this.tail.position.y = 4;
  680.         this.torso.add(this.tail);

  681.         var pawGeom = new THREE.CylinderGeometry(1.5, 0, 10);
  682.         pawGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, -5, 0));
  683.         this.pawFL = new THREE.Mesh(pawGeom, blackMat);
  684.         this.pawFL.position.y = -7.5;
  685.         this.pawFL.position.z = 8.5;
  686.         this.pawFL.position.x = 5.5;
  687.         this.torso.add(this.pawFL);

  688.         this.pawFR = this.pawFL.clone();
  689.         this.pawFR.position.x = -this.pawFL.position.x;
  690.         this.torso.add(this.pawFR);

  691.         this.pawBR = this.pawFR.clone();
  692.         this.pawBR.position.z = -this.pawFL.position.z;
  693.         this.torso.add(this.pawBR);

  694.         this.pawBL = this.pawBR.clone();
  695.         this.pawBL.position.x = this.pawFL.position.x;
  696.         this.torso.add(this.pawBL);

  697.         this.mesh.add(this.body);
  698.         this.torso.add(this.head);
  699.         this.body.add(this.torso);

  700.         this.torso.castShadow = true;
  701.         this.head.castShadow = true;
  702.         this.pawFL.castShadow = true;
  703.         this.pawFR.castShadow = true;
  704.         this.pawBL.castShadow = true;
  705.         this.pawBR.castShadow = true;

  706.         this.body.rotation.y = Math.PI / 2;
  707.       };

  708.       Monster.prototype.run = function () {
  709.         var s = Math.min(speed, maxSpeed);
  710.         this.runningCycle += delta * s * 0.7;
  711.         this.runningCycle = this.runningCycle % (Math.PI * 2);
  712.         var t = this.runningCycle;

  713.         this.pawFR.rotation.x = (Math.sin(t) * Math.PI) / 4;
  714.         this.pawFR.position.y = -5.5 - Math.sin(t);
  715.         this.pawFR.position.z = 7.5 + Math.cos(t);

  716.         this.pawFL.rotation.x = (Math.sin(t + 0.4) * Math.PI) / 4;
  717.         this.pawFL.position.y = -5.5 - Math.sin(t + 0.4);
  718.         this.pawFL.position.z = 7.5 + Math.cos(t + 0.4);

  719.         this.pawBL.rotation.x = (Math.sin(t + 2) * Math.PI) / 4;
  720.         this.pawBL.position.y = -5.5 - Math.sin(t + 3.8);
  721.         this.pawBL.position.z = -7.5 + Math.cos(t + 3.8);

  722.         this.pawBR.rotation.x = (Math.sin(t + 2.4) * Math.PI) / 4;
  723.         this.pawBR.position.y = -5.5 - Math.sin(t + 3.4);
  724.         this.pawBR.position.z = -7.5 + Math.cos(t + 3.4);

  725.         this.torso.rotation.x = (Math.sin(t) * Math.PI) / 8;
  726.         this.torso.position.y = 3 - Math.sin(t + Math.PI / 2) * 3;

  727.         //this.head.position.y = 5-Math.sin(t+Math.PI/2)*2;
  728.         this.head.rotation.x = -0.1 + Math.sin(-t - 1) * 0.4;
  729.         this.mouth.rotation.x = 0.2 + Math.sin(t + Math.PI + 0.3) * 0.4;

  730.         this.tail.rotation.x = 0.2 + Math.sin(t - Math.PI / 2);

  731.         this.eyeR.scale.y = 0.5 + Math.sin(t + Math.PI) * 0.5;
  732.       };

  733.       Hero.prototype.nod = function () {
  734.         var _this = this;
  735.         var sp = 0.5 + Math.random();

  736.         // HEAD
  737.         var tHeadRotY = -Math.PI / 6 + (Math.random() * Math.PI) / 3;
  738.         TweenMax.to(this.head.rotation, sp, {
  739.           y: tHeadRotY,
  740.           ease: Power4.easeInOut,
  741.           onComplete: function () {
  742.             _this.nod();
  743.           },
  744.         });

  745.         // EARS
  746.         var tEarLRotX = Math.PI / 4 + (Math.random() * Math.PI) / 6;
  747.         var tEarRRotX = Math.PI / 4 + (Math.random() * Math.PI) / 6;

  748.         TweenMax.to(this.earL.rotation, sp, {
  749.           x: tEarLRotX,
  750.           ease: Power4.easeInOut,
  751.         });
  752.         TweenMax.to(this.earR.rotation, sp, {
  753.           x: tEarRRotX,
  754.           ease: Power4.easeInOut,
  755.         });

  756.         // PAWS BACK LEFT

  757.         var tPawBLRot = (Math.random() * Math.PI) / 2;
  758.         var tPawBLY = -4 + Math.random() * 8;

  759.         TweenMax.to(this.pawBL.rotation, sp / 2, {
  760.           x: tPawBLRot,
  761.           ease: Power1.easeInOut,
  762.           yoyo: true,
  763.           repeat: 2,
  764.         });
  765.         TweenMax.to(this.pawBL.position, sp / 2, {
  766.           y: tPawBLY,
  767.           ease: Power1.easeInOut,
  768.           yoyo: true,
  769.           repeat: 2,
  770.         });

  771.         // PAWS BACK RIGHT

  772.         var tPawBRRot = (Math.random() * Math.PI) / 2;
  773.         var tPawBRY = -4 + Math.random() * 8;
  774.         TweenMax.to(this.pawBR.rotation, sp / 2, {
  775.           x: tPawBRRot,
  776.           ease: Power1.easeInOut,
  777.           yoyo: true,
  778.           repeat: 2,
  779.         });
  780.         TweenMax.to(this.pawBR.position, sp / 2, {
  781.           y: tPawBRY,
  782.           ease: Power1.easeInOut,
  783.           yoyo: true,
  784.           repeat: 2,
  785.         });

  786.         // PAWS FRONT LEFT

  787.         var tPawFLRot = (Math.random() * Math.PI) / 2;
  788.         var tPawFLY = -4 + Math.random() * 8;

  789.         TweenMax.to(this.pawFL.rotation, sp / 2, {
  790.           x: tPawFLRot,
  791.           ease: Power1.easeInOut,
  792.           yoyo: true,
  793.           repeat: 2,
  794.         });

  795.         TweenMax.to(this.pawFL.position, sp / 2, {
  796.           y: tPawFLY,
  797.           ease: Power1.easeInOut,
  798.           yoyo: true,
  799.           repeat: 2,
  800.         });

  801.         // PAWS FRONT RIGHT

  802.         var tPawFRRot = (Math.random() * Math.PI) / 2;
  803.         var tPawFRY = -4 + Math.random() * 8;

  804.         TweenMax.to(this.pawFR.rotation, sp / 2, {
  805.           x: tPawFRRot,
  806.           ease: Power1.easeInOut,
  807.           yoyo: true,
  808.           repeat: 2,
  809.         });

  810.         TweenMax.to(this.pawFR.position, sp / 2, {
  811.           y: tPawFRY,
  812.           ease: Power1.easeInOut,
  813.           yoyo: true,
  814.           repeat: 2,
  815.         });

  816.         // MOUTH
  817.         var tMouthRot = (Math.random() * Math.PI) / 8;
  818.         TweenMax.to(this.mouth.rotation, sp, {
  819.           x: tMouthRot,
  820.           ease: Power1.easeInOut,
  821.         });
  822.         // IRIS
  823.         var tIrisY = -1 + Math.random() * 2;
  824.         var tIrisZ = -1 + Math.random() * 2;
  825.         var iris1 = this.iris;
  826.         var iris2 = this.eyeR.children[0];
  827.         TweenMax.to([iris1.position, iris2.position], sp, {
  828.           y: tIrisY,
  829.           z: tIrisZ,
  830.           ease: Power1.easeInOut,
  831.         });

  832.         //EYES
  833.         if (Math.random() > 0.2)
  834.           TweenMax.to([this.eyeR.scale, this.eyeL.scale], sp / 8, {
  835.             y: 0,
  836.             ease: Power1.easeInOut,
  837.             yoyo: true,
  838.             repeat: 1,
  839.           });
  840.       };

  841.       Hero.prototype.hang = function () {
  842.         var _this = this;
  843.         var sp = 1;
  844.         var ease = Power4.easeOut;

  845.         TweenMax.killTweensOf(this.eyeL.scale);
  846.         TweenMax.killTweensOf(this.eyeR.scale);

  847.         this.body.rotation.x = 0;
  848.         this.torso.rotation.x = 0;
  849.         this.body.position.y = 0;
  850.         this.torso.position.y = 7;

  851.         TweenMax.to(this.mesh.rotation, sp, { y: 0, ease: ease });
  852.         TweenMax.to(this.mesh.position, sp, { y: -7, z: 6, ease: ease });
  853.         TweenMax.to(this.head.rotation, sp, {
  854.           x: Math.PI / 6,
  855.           ease: ease,
  856.           onComplete: function () {
  857.             _this.nod();
  858.           },
  859.         });

  860.         TweenMax.to(this.earL.rotation, sp, { x: Math.PI / 3, ease: ease });
  861.         TweenMax.to(this.earR.rotation, sp, { x: Math.PI / 3, ease: ease });

  862.         TweenMax.to(this.pawFL.position, sp, { y: -1, z: 3, ease: ease });
  863.         TweenMax.to(this.pawFR.position, sp, { y: -1, z: 3, ease: ease });
  864.         TweenMax.to(this.pawBL.position, sp, { y: -2, z: -3, ease: ease });
  865.         TweenMax.to(this.pawBR.position, sp, { y: -2, z: -3, ease: ease });

  866.         TweenMax.to(this.eyeL.scale, sp, { y: 1, ease: ease });
  867.         TweenMax.to(this.eyeR.scale, sp, { y: 1, ease: ease });
  868.       };

  869.       Monster.prototype.nod = function () {
  870.         var _this = this;
  871.         var sp = 1 + Math.random() * 2;

  872.         // HEAD
  873.         var tHeadRotY = -Math.PI / 3 + Math.random() * 0.5;
  874.         var tHeadRotX = Math.PI / 3 - 0.2 + Math.random() * 0.4;
  875.         TweenMax.to(this.head.rotation, sp, {
  876.           x: tHeadRotX,
  877.           y: tHeadRotY,
  878.           ease: Power4.easeInOut,
  879.           onComplete: function () {
  880.             _this.nod();
  881.           },
  882.         });

  883.         // TAIL

  884.         var tTailRotY = -Math.PI / 4;
  885.         TweenMax.to(this.tail.rotation, sp / 8, {
  886.           y: tTailRotY,
  887.           ease: Power1.easeInOut,
  888.           yoyo: true,
  889.           repeat: 8,
  890.         });

  891.         // EYES

  892.         TweenMax.to([this.eyeR.scale, this.eyeL.scale], sp / 20, {
  893.           y: 0,
  894.           ease: Power1.easeInOut,
  895.           yoyo: true,
  896.           repeat: 1,
  897.         });
  898.       };

  899.       Monster.prototype.sit = function () {
  900.         var sp = 1.2;
  901.         var ease = Power4.easeOut;
  902.         var _this = this;
  903.         TweenMax.to(this.torso.rotation, sp, { x: -1.3, ease: ease });
  904.         TweenMax.to(this.torso.position, sp, {
  905.           y: -5,
  906.           ease: ease,
  907.           onComplete: function () {
  908.             _this.nod();
  909.             gameStatus = "readyToReplay";
  910.           },
  911.         });

  912.         TweenMax.to(this.head.rotation, sp, {
  913.           x: Math.PI / 3,
  914.           y: -Math.PI / 3,
  915.           ease: ease,
  916.         });
  917.         TweenMax.to(this.tail.rotation, sp, {
  918.           x: 2,
  919.           y: Math.PI / 4,
  920.           ease: ease,
  921.         });
  922.         TweenMax.to(this.pawBL.rotation, sp, { x: -0.1, ease: ease });
  923.         TweenMax.to(this.pawBR.rotation, sp, { x: -0.1, ease: ease });
  924.         TweenMax.to(this.pawFL.rotation, sp, { x: 1, ease: ease });
  925.         TweenMax.to(this.pawFR.rotation, sp, { x: 1, ease: ease });
  926.         TweenMax.to(this.mouth.rotation, sp, { x: 0.3, ease: ease });
  927.         TweenMax.to(this.eyeL.scale, sp, { y: 1, ease: ease });
  928.         TweenMax.to(this.eyeR.scale, sp, { y: 1, ease: ease });

  929.         //TweenMax.to(this.body.rotation, sp, {y:Math.PI/4});
  930.       };

  931.       Carrot = function () {
  932.         this.angle = 0;
  933.         this.mesh = new THREE.Group();

  934.         var bodyGeom = new THREE.CylinderGeometry(5, 3, 10, 4, 1);
  935.         bodyGeom.vertices[8].y += 2;
  936.         bodyGeom.vertices[9].y -= 3;

  937.         this.body = new THREE.Mesh(bodyGeom, pinkMat);

  938.         var leafGeom = new THREE.CubeGeometry(5, 10, 1, 1);
  939.         leafGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 5, 0));
  940.         leafGeom.vertices[2].x -= 1;
  941.         leafGeom.vertices[3].x -= 1;
  942.         leafGeom.vertices[6].x += 1;
  943.         leafGeom.vertices[7].x += 1;

  944.         this.leaf1 = new THREE.Mesh(leafGeom, greenMat);
  945.         this.leaf1.position.y = 7;
  946.         this.leaf1.rotation.z = 0.3;
  947.         this.leaf1.rotation.x = 0.2;

  948.         this.leaf2 = this.leaf1.clone();
  949.         this.leaf2.scale.set(1, 1.3, 1);
  950.         this.leaf2.position.y = 7;
  951.         this.leaf2.rotation.z = -0.3;
  952.         this.leaf2.rotation.x = -0.2;

  953.         this.mesh.add(this.body);
  954.         this.mesh.add(this.leaf1);
  955.         this.mesh.add(this.leaf2);

  956.         this.body.traverse(function (object) {
  957.           if (object instanceof THREE.Mesh) {
  958.             object.castShadow = true;
  959.             object.receiveShadow = true;
  960.           }
  961.         });
  962.       };

  963.       Hedgehog = function () {
  964.         this.angle = 0;
  965.         this.status = "ready";
  966.         this.mesh = new THREE.Group();
  967.         var bodyGeom = new THREE.CubeGeometry(6, 6, 6, 1);
  968.         this.body = new THREE.Mesh(bodyGeom, blackMat);

  969.         var headGeom = new THREE.CubeGeometry(5, 5, 7, 1);
  970.         this.head = new THREE.Mesh(headGeom, lightBrownMat);
  971.         this.head.position.z = 6;
  972.         this.head.position.y = -0.5;

  973.         var noseGeom = new THREE.CubeGeometry(1.5, 1.5, 1.5, 1);
  974.         this.nose = new THREE.Mesh(noseGeom, blackMat);
  975.         this.nose.position.z = 4;
  976.         this.nose.position.y = 2;

  977.         var eyeGeom = new THREE.CubeGeometry(1, 3, 3);

  978.         this.eyeL = new THREE.Mesh(eyeGeom, whiteMat);
  979.         this.eyeL.position.x = 2.2;
  980.         this.eyeL.position.z = -0.5;
  981.         this.eyeL.position.y = 0.8;
  982.         this.eyeL.castShadow = true;
  983.         this.head.add(this.eyeL);

  984.         var irisGeom = new THREE.CubeGeometry(0.5, 1, 1);

  985.         this.iris = new THREE.Mesh(irisGeom, blackMat);
  986.         this.iris.position.x = 0.5;
  987.         this.iris.position.y = 0.8;
  988.         this.iris.position.z = 0.8;
  989.         this.eyeL.add(this.iris);

  990.         this.eyeR = this.eyeL.clone();
  991.         this.eyeR.children[0].position.x = -this.iris.position.x;
  992.         this.eyeR.position.x = -this.eyeL.position.x;

  993.         var spikeGeom = new THREE.CubeGeometry(0.5, 2, 0.5, 1);
  994.         spikeGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 1, 0));

  995.         for (var i = 0; i < 9; i++) {
  996.           var row = i % 3;
  997.           var col = Math.floor(i / 3);
  998.           var sb = new THREE.Mesh(spikeGeom, blackMat);
  999.           sb.rotation.x =
  1000.             -Math.PI / 2 + (Math.PI / 12) * row - 0.5 + Math.random();
  1001.           sb.position.z = -3;
  1002.           sb.position.y = -2 + row * 2;
  1003.           sb.position.x = -2 + col * 2;
  1004.           this.body.add(sb);
  1005.           var st = new THREE.Mesh(spikeGeom, blackMat);
  1006.           st.position.y = 3;
  1007.           st.position.x = -2 + row * 2;
  1008.           st.position.z = -2 + col * 2;
  1009.           st.rotation.z =
  1010.             Math.PI / 6 - (Math.PI / 6) * row - 0.5 + Math.random();
  1011.           this.body.add(st);

  1012.           var sr = new THREE.Mesh(spikeGeom, blackMat);
  1013.           sr.position.x = 3;
  1014.           sr.position.y = -2 + row * 2;
  1015.           sr.position.z = -2 + col * 2;
  1016.           sr.rotation.z =
  1017.             -Math.PI / 2 + (Math.PI / 12) * row - 0.5 + Math.random();
  1018.           this.body.add(sr);

  1019.           var sl = new THREE.Mesh(spikeGeom, blackMat);
  1020.           sl.position.x = -3;
  1021.           sl.position.y = -2 + row * 2;
  1022.           sl.position.z = -2 + col * 2;
  1023.           sl.rotation.z =
  1024.             Math.PI / 2 - (Math.PI / 12) * row - 0.5 + Math.random();
  1025.           this.body.add(sl);
  1026.         }

  1027.         this.head.add(this.eyeR);
  1028.         var earGeom = new THREE.CubeGeometry(2, 2, 0.5, 1);
  1029.         this.earL = new THREE.Mesh(earGeom, lightBrownMat);
  1030.         this.earL.position.x = 2.5;
  1031.         this.earL.position.z = -2.5;
  1032.         this.earL.position.y = 2.5;
  1033.         this.earL.rotation.z = -Math.PI / 12;
  1034.         this.earL.castShadow = true;
  1035.         this.head.add(this.earL);

  1036.         this.earR = this.earL.clone();
  1037.         this.earR.position.x = -this.earL.position.x;
  1038.         this.earR.rotation.z = -this.earL.rotation.z;
  1039.         this.earR.castShadow = true;
  1040.         this.head.add(this.earR);

  1041.         var mouthGeom = new THREE.CubeGeometry(1, 1, 0.5, 1);
  1042.         this.mouth = new THREE.Mesh(mouthGeom, blackMat);
  1043.         this.mouth.position.z = 3.5;
  1044.         this.mouth.position.y = -1.5;
  1045.         this.head.add(this.mouth);

  1046.         this.mesh.add(this.body);
  1047.         this.body.add(this.head);
  1048.         this.head.add(this.nose);

  1049.         this.mesh.traverse(function (object) {
  1050.           if (object instanceof THREE.Mesh) {
  1051.             object.castShadow = true;
  1052.             object.receiveShadow = true;
  1053.           }
  1054.         });
  1055.       };

  1056.       Hedgehog.prototype.nod = function () {
  1057.         var _this = this;
  1058.         var speed = 0.1 + Math.random() * 0.5;
  1059.         var angle = -Math.PI / 4 + (Math.random() * Math.PI) / 2;
  1060.         TweenMax.to(this.head.rotation, speed, {
  1061.           y: angle,
  1062.           onComplete: function () {
  1063.             _this.nod();
  1064.           },
  1065.         });
  1066.       };

  1067.       function createHero() {
  1068.         hero = new Hero();
  1069.         hero.mesh.rotation.y = Math.PI / 2;
  1070.         scene.add(hero.mesh);
  1071.         hero.nod();
  1072.       }

  1073.       function createMonster() {
  1074.         monster = new Monster();
  1075.         monster.mesh.position.z = 20;
  1076.         //monster.mesh.scale.set(1.2,1.2,1.2);
  1077.         scene.add(monster.mesh);
  1078.         updateMonsterPosition();
  1079.       }

  1080.       function updateMonsterPosition() {
  1081.         monster.run();
  1082.         monsterPosTarget -= delta * monsterAcceleration;
  1083.         monsterPos += (monsterPosTarget - monsterPos) * delta;
  1084.         if (monsterPos < 0.56) {
  1085.           gameOver();
  1086.         }

  1087.         var angle = Math.PI * monsterPos;
  1088.         monster.mesh.position.y =
  1089.           -floorRadius + Math.sin(angle) * (floorRadius + 12);
  1090.         monster.mesh.position.x = Math.cos(angle) * (floorRadius + 15);
  1091.         monster.mesh.rotation.z = -Math.PI / 2 + angle;
  1092.       }

  1093.       function gameOver() {
  1094.         fieldGameOver.className = "show";
  1095.         gameStatus = "gameOver";
  1096.         monster.sit();
  1097.         hero.hang();
  1098.         monster.heroHolder.add(hero.mesh);
  1099.         TweenMax.to(this, 1, { speed: 0 });
  1100.         TweenMax.to(camera.position, 3, {
  1101.           z: cameraPosGameOver,
  1102.           y: 60,
  1103.           x: -30,
  1104.         });
  1105.         carrot.mesh.visible = false;
  1106.         obstacle.mesh.visible = false;
  1107.         clearInterval(levelInterval);
  1108.       }

  1109.       function replay() {
  1110.         gameStatus = "preparingToReplay";

  1111.         fieldGameOver.className = "";

  1112.         TweenMax.killTweensOf(monster.pawFL.position);
  1113.         TweenMax.killTweensOf(monster.pawFR.position);
  1114.         TweenMax.killTweensOf(monster.pawBL.position);
  1115.         TweenMax.killTweensOf(monster.pawBR.position);

  1116.         TweenMax.killTweensOf(monster.pawFL.rotation);
  1117.         TweenMax.killTweensOf(monster.pawFR.rotation);
  1118.         TweenMax.killTweensOf(monster.pawBL.rotation);
  1119.         TweenMax.killTweensOf(monster.pawBR.rotation);

  1120.         TweenMax.killTweensOf(monster.tail.rotation);
  1121.         TweenMax.killTweensOf(monster.head.rotation);
  1122.         TweenMax.killTweensOf(monster.eyeL.scale);
  1123.         TweenMax.killTweensOf(monster.eyeR.scale);

  1124.         //TweenMax.killTweensOf(hero.head.rotation);

  1125.         monster.tail.rotation.y = 0;

  1126.         TweenMax.to(camera.position, 3, {
  1127.           z: cameraPosGame,
  1128.           x: 0,
  1129.           y: 30,
  1130.           ease: Power4.easeInOut,
  1131.         });
  1132.         TweenMax.to(monster.torso.rotation, 2, {
  1133.           x: 0,
  1134.           ease: Power4.easeInOut,
  1135.         });
  1136.         TweenMax.to(monster.torso.position, 2, {
  1137.           y: 0,
  1138.           ease: Power4.easeInOut,
  1139.         });
  1140.         TweenMax.to(monster.pawFL.rotation, 2, {
  1141.           x: 0,
  1142.           ease: Power4.easeInOut,
  1143.         });
  1144.         TweenMax.to(monster.pawFR.rotation, 2, {
  1145.           x: 0,
  1146.           ease: Power4.easeInOut,
  1147.         });
  1148.         TweenMax.to(monster.mouth.rotation, 2, {
  1149.           x: 0.5,
  1150.           ease: Power4.easeInOut,
  1151.         });

  1152.         TweenMax.to(monster.head.rotation, 2, {
  1153.           y: 0,
  1154.           x: -0.3,
  1155.           ease: Power4.easeInOut,
  1156.         });

  1157.         TweenMax.to(hero.mesh.position, 2, { x: 20, ease: Power4.easeInOut });
  1158.         TweenMax.to(hero.head.rotation, 2, {
  1159.           x: 0,
  1160.           y: 0,
  1161.           ease: Power4.easeInOut,
  1162.         });
  1163.         TweenMax.to(monster.mouth.rotation, 2, {
  1164.           x: 0.2,
  1165.           ease: Power4.easeInOut,
  1166.         });
  1167.         TweenMax.to(monster.mouth.rotation, 1, {
  1168.           x: 0.4,
  1169.           ease: Power4.easeIn,
  1170.           delay: 1,
  1171.           onComplete: function () {
  1172.             resetGame();
  1173.           },
  1174.         });
  1175.       }

  1176.       Fir = function () {
  1177.         var height = 200;
  1178.         var truncGeom = new THREE.CylinderGeometry(2, 2, height, 6, 1);
  1179.         truncGeom.applyMatrix(
  1180.           new THREE.Matrix4().makeTranslation(0, height / 2, 0)
  1181.         );
  1182.         this.mesh = new THREE.Mesh(truncGeom, greenMat);
  1183.         this.mesh.castShadow = true;
  1184.       };

  1185.       var firs = new THREE.Group();

  1186.       function createFirs() {
  1187.         var nTrees = 100;
  1188.         for (var i = 0; i < nTrees; i++) {
  1189.           var phi = (i * (Math.PI * 2)) / nTrees;
  1190.           var theta = Math.PI / 2;
  1191.           //theta += .25 + Math.random()*.3;
  1192.           theta +=
  1193.             Math.random() > 0.05
  1194.               ? 0.25 + Math.random() * 0.3
  1195.               : -0.35 - Math.random() * 0.1;

  1196.           var fir = new Tree();
  1197.           fir.mesh.position.x = Math.sin(theta) * Math.cos(phi) * floorRadius;
  1198.           fir.mesh.position.y =
  1199.             Math.sin(theta) * Math.sin(phi) * (floorRadius - 10);
  1200.           fir.mesh.position.z = Math.cos(theta) * floorRadius;

  1201.           var vec = fir.mesh.position.clone();
  1202.           var axis = new THREE.Vector3(0, 1, 0);
  1203.           fir.mesh.quaternion.setFromUnitVectors(axis, vec.clone().normalize());
  1204.           floor.add(fir.mesh);
  1205.         }
  1206.       }

  1207.       function createCarrot() {
  1208.         carrot = new Carrot();
  1209.         scene.add(carrot.mesh);
  1210.       }

  1211.       function updateCarrotPosition() {
  1212.         carrot.mesh.rotation.y += delta * 6;
  1213.         carrot.mesh.rotation.z = Math.PI / 2 - (floorRotation + carrot.angle);
  1214.         carrot.mesh.position.y =
  1215.           -floorRadius +
  1216.           Math.sin(floorRotation + carrot.angle) * (floorRadius + 50);
  1217.         carrot.mesh.position.x =
  1218.           Math.cos(floorRotation + carrot.angle) * (floorRadius + 50);
  1219.       }

  1220.       function updateObstaclePosition() {
  1221.         if (obstacle.status == "flying") return;

  1222.         // TODO fix this,
  1223.         if (floorRotation + obstacle.angle > 2.5) {
  1224.           obstacle.angle = -floorRotation + Math.random() * 0.3;
  1225.           obstacle.body.rotation.y = Math.random() * Math.PI * 2;
  1226.         }

  1227.         obstacle.mesh.rotation.z = floorRotation + obstacle.angle - Math.PI / 2;
  1228.         obstacle.mesh.position.y =
  1229.           -floorRadius +
  1230.           Math.sin(floorRotation + obstacle.angle) * (floorRadius + 3);
  1231.         obstacle.mesh.position.x =
  1232.           Math.cos(floorRotation + obstacle.angle) * (floorRadius + 3);
  1233.       }

  1234.       function updateFloorRotation() {
  1235.         floorRotation += delta * 0.03 * speed;
  1236.         floorRotation = floorRotation % (Math.PI * 2);
  1237.         floor.rotation.z = floorRotation;
  1238.       }

  1239.       function createObstacle() {
  1240.         obstacle = new Hedgehog();
  1241.         obstacle.body.rotation.y = -Math.PI / 2;
  1242.         obstacle.mesh.scale.set(1.1, 1.1, 1.1);
  1243.         obstacle.mesh.position.y = floorRadius + 4;
  1244.         obstacle.nod();
  1245.         scene.add(obstacle.mesh);
  1246.       }

  1247.       function createBonusParticles() {
  1248.         bonusParticles = new BonusParticles();
  1249.         bonusParticles.mesh.visible = false;
  1250.         scene.add(bonusParticles.mesh);
  1251.       }

  1252.       function checkCollision() {
  1253.         var db = hero.mesh.position.clone().sub(carrot.mesh.position.clone());
  1254.         var dm = hero.mesh.position.clone().sub(obstacle.mesh.position.clone());

  1255.         if (db.length() < collisionBonus) {
  1256.           getBonus();
  1257.         }

  1258.         if (dm.length() < collisionObstacle && obstacle.status != "flying") {
  1259.           getMalus();
  1260.         }
  1261.       }

  1262.       function getBonus() {
  1263.         bonusParticles.mesh.position.copy(carrot.mesh.position);
  1264.         bonusParticles.mesh.visible = true;
  1265.         bonusParticles.explose();
  1266.         carrot.angle += Math.PI / 2;
  1267.         //speed*=.95;
  1268.         monsterPosTarget += 0.025;
  1269.       }

  1270.       function getMalus() {
  1271.         obstacle.status = "flying";
  1272.         var tx =
  1273.           Math.random() > 0.5
  1274.             ? -20 - Math.random() * 10
  1275.             : 20 + Math.random() * 5;
  1276.         TweenMax.to(obstacle.mesh.position, 4, {
  1277.           x: tx,
  1278.           y: Math.random() * 50,
  1279.           z: 350,
  1280.           ease: Power4.easeOut,
  1281.         });
  1282.         TweenMax.to(obstacle.mesh.rotation, 4, {
  1283.           x: Math.PI * 3,
  1284.           z: Math.PI * 3,
  1285.           y: Math.PI * 6,
  1286.           ease: Power4.easeOut,
  1287.           onComplete: function () {
  1288.             obstacle.status = "ready";
  1289.             obstacle.body.rotation.y = Math.random() * Math.PI * 2;
  1290.             obstacle.angle = -floorRotation - Math.random() * 0.4;

  1291.             obstacle.angle = obstacle.angle % (Math.PI * 2);
  1292.             obstacle.mesh.rotation.x = 0;
  1293.             obstacle.mesh.rotation.y = 0;
  1294.             obstacle.mesh.rotation.z = 0;
  1295.             obstacle.mesh.position.z = 0;
  1296.           },
  1297.         });
  1298.         //
  1299.         monsterPosTarget -= 0.04;
  1300.         TweenMax.from(this, 0.5, {
  1301.           malusClearAlpha: 0.5,
  1302.           onUpdate: function () {
  1303.             renderer.setClearColor(malusClearColor, malusClearAlpha);
  1304.           },
  1305.         });
  1306.       }

  1307.       function updateDistance() {
  1308.         distance += delta * speed;
  1309.         var d = distance / 2;
  1310.         fieldDistance.innerHTML = Math.floor(d);
  1311.       }

  1312.       function updateLevel() {
  1313.         if (speed >= maxSpeed) return;
  1314.         level++;
  1315.         speed += 2;
  1316.       }

  1317.       function loop() {
  1318.         delta = clock.getDelta();
  1319.         updateFloorRotation();

  1320.         if (gameStatus == "play") {
  1321.           if (hero.status == "running") {
  1322.             hero.run();
  1323.           }
  1324.           updateDistance();
  1325.           updateMonsterPosition();
  1326.           updateCarrotPosition();
  1327.           updateObstaclePosition();
  1328.           checkCollision();
  1329.         }

  1330.         render();
  1331.         requestAnimationFrame(loop);
  1332.       }

  1333.       function render() {
  1334.         renderer.render(scene, camera);
  1335.       }

  1336.       window.addEventListener("load", init, false);

  1337.       function init(event) {
  1338.         initScreenAnd3D();
  1339.         createLights();
  1340.         createFloor();
  1341.         createHero();
  1342.         createMonster();
  1343.         createFirs();
  1344.         createCarrot();
  1345.         createBonusParticles();
  1346.         createObstacle();
  1347.         initUI();
  1348.         resetGame();
  1349.         loop();

  1350.         //setInterval(hero.blink.bind(hero), 3000);
  1351.       }

  1352.       function resetGame() {
  1353.         scene.add(hero.mesh);
  1354.         hero.mesh.rotation.y = Math.PI / 2;
  1355.         hero.mesh.position.y = 0;
  1356.         hero.mesh.position.z = 0;
  1357.         hero.mesh.position.x = 0;

  1358.         monsterPos = 0.56;
  1359.         monsterPosTarget = 0.65;
  1360.         speed = initSpeed;
  1361.         level = 0;
  1362.         distance = 0;
  1363.         carrot.mesh.visible = true;
  1364.         obstacle.mesh.visible = true;
  1365.         gameStatus = "play";
  1366.         hero.status = "running";
  1367.         hero.nod();
  1368.         audio.play();
  1369.         updateLevel();
  1370.         levelInterval = setInterval(updateLevel, levelUpdateFreq);
  1371.       }

  1372.       function initUI() {
  1373.         fieldDistance = document.getElementById("distValue");
  1374.         fieldGameOver = document.getElementById("gameoverInstructions");
  1375.       }

  1376.       ////////////////////////////////////////////////
  1377.       //                                        MODELS
  1378.       ////////////////////////////////////////////////

  1379.       // TREE

  1380.       Tree = function () {
  1381.         this.mesh = new THREE.Object3D();
  1382.         this.trunc = new Trunc();
  1383.         this.mesh.add(this.trunc.mesh);
  1384.       };

  1385.       Trunc = function () {
  1386.         var truncHeight = 50 + Math.random() * 150;
  1387.         var topRadius = 1 + Math.random() * 5;
  1388.         var bottomRadius = 5 + Math.random() * 5;
  1389.         var mats = [
  1390.           blackMat,
  1391.           brownMat,
  1392.           pinkMat,
  1393.           whiteMat,
  1394.           greenMat,
  1395.           lightBrownMat,
  1396.           pinkMat,
  1397.         ];
  1398.         var matTrunc = blackMat; //mats[Math.floor(Math.random()*mats.length)];
  1399.         var nhSegments = 3; //Math.ceil(2 + Math.random()*6);
  1400.         var nvSegments = 3; //Math.ceil(2 + Math.random()*6);
  1401.         var geom = new THREE.CylinderGeometry(
  1402.           topRadius,
  1403.           bottomRadius,
  1404.           truncHeight,
  1405.           nhSegments,
  1406.           nvSegments
  1407.         );
  1408.         geom.applyMatrix(
  1409.           new THREE.Matrix4().makeTranslation(0, truncHeight / 2, 0)
  1410.         );

  1411.         this.mesh = new THREE.Mesh(geom, matTrunc);

  1412.         for (var i = 0; i < geom.vertices.length; i++) {
  1413.           var noise = Math.random();
  1414.           var v = geom.vertices[i];
  1415.           v.x += -noise + Math.random() * noise * 2;
  1416.           v.y += -noise + Math.random() * noise * 2;
  1417.           v.z += -noise + Math.random() * noise * 2;

  1418.           geom.computeVertexNormals();

  1419.           // FRUITS

  1420.           if (Math.random() > 0.7) {
  1421.             var size = Math.random() * 3;
  1422.             var fruitGeometry = new THREE.CubeGeometry(size, size, size, 1);
  1423.             var matFruit = mats[Math.floor(Math.random() * mats.length)];
  1424.             var fruit = new THREE.Mesh(fruitGeometry, matFruit);
  1425.             fruit.position.x = v.x;
  1426.             fruit.position.y = v.y + 3;
  1427.             fruit.position.z = v.z;
  1428.             fruit.rotation.x = Math.random() * Math.PI;
  1429.             fruit.rotation.y = Math.random() * Math.PI;

  1430.             this.mesh.add(fruit);
  1431.           }

  1432.           // BRANCHES

  1433.           if (Math.random() > 0.5 && v.y > 10 && v.y < truncHeight - 10) {
  1434.             var h = 3 + Math.random() * 5;
  1435.             var thickness = 0.2 + Math.random();

  1436.             var branchGeometry = new THREE.CylinderGeometry(
  1437.               thickness / 2,
  1438.               thickness,
  1439.               h,
  1440.               3,
  1441.               1
  1442.             );
  1443.             branchGeometry.applyMatrix(
  1444.               new THREE.Matrix4().makeTranslation(0, h / 2, 0)
  1445.             );
  1446.             var branch = new THREE.Mesh(branchGeometry, matTrunc);
  1447.             branch.position.x = v.x;
  1448.             branch.position.y = v.y;
  1449.             branch.position.z = v.z;

  1450.             var vec = new THREE.Vector3(v.x, 2, v.z);
  1451.             var axis = new THREE.Vector3(0, 1, 0);
  1452.             branch.quaternion.setFromUnitVectors(axis, vec.clone().normalize());

  1453.             this.mesh.add(branch);
  1454.           }
  1455.         }

  1456.         this.mesh.castShadow = true;
  1457.       };
  1458.     </script>
  1459.   </body>
  1460. </html>
复制代码





您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

投诉/建议联系

admin@discuz.vip

未经授权禁止转载,复制和建立镜像,
如有违反,追究法律责任
  • 关注公众号
  • 添加微信客服
Copyright © 2001-2025 九歌社区 版权所有 All Rights Reserved.
关灯 在本版发帖
扫一扫添加微信客服
返回顶部
快速回复 返回顶部 返回列表