Skip to content

Instantly share code, notes, and snippets.

@edom18
Created August 29, 2013 12:39
Show Gist options
  • Save edom18/6377548 to your computer and use it in GitHub Desktop.
Save edom18/6377548 to your computer and use it in GitHub Desktop.
[THREE.js] ジプシー・デンジャーを操作できるようにする
#ジプシー・デンジャーを歩けるようにしていきます。
まずはキー押下時に歩くモーション、なにもしていないときは待機モーションになるようにしました。
モデルの移動方向については、ヨモツ先生のこちらを参考にしました → http://yomotsu.github.io/threejs-examples/tps/
@import "compass/reset";
img, canvas {
vertical-align: top;
}
#gui {
position: absolute;
left: 5px;
top: 5px;
padding: 10px;
background: rgba(0, 0, 0, 0.5);
border: solid 1px rgba(255, 255, 255, 0.5);
color: #fff;
}
<div id="gui">
<p>A key: move to left.</p>
<p>S key: move to back.</p>
<p>D key: move to right.</p>
<p>W key: move to front.</p>
</div>
(function (win, doc) {
'use strict';
var container, camera, scene, renderer, model,
globalLight, clock,
//for skybox.
sceneCube, cameraCube, textureCube, meshCube;
var offsetX = 0,
offsetY = 100,
offsetZ = 220;
//for model information.
var modelUrl = 'http://resources.edo-m18.me/models/gips-danger/gips-danger_rig_animation.js';
var modelFrames = {
stand: [ 0, 32, 0, {state: 'stand', action: false}],
walk : [33, 65, 1.6, {state: 'stand', action: false}],
run : [66, 98, 3.2, {state: 'stand', action: false}]
};
var player = {
position: {
x: 0,
y: 0,
z: 0,
distance: 0
},
camera: {
speed: 300,
distance: 400,
x: 0,
y: 100,
z: 0
}
};
var groundTextureUrl = 'http://jsrun.it/assets/h/M/n/q/hMnqT.jpg';
//
function createModel(geometry, materials) {
var facematerial;
var scale = 17;
if (materials) {
for (var i = 0; i < materials.length; i++) {
materials[i].morphTargets = true;
}
facematerial = new THREE.MeshFaceMaterial(materials);
}
else {
facematerial = new THREE.MeshLambertMaterial({color: 0xcccccc});
facematerial.morphTargets = true;
}
win.model = model = new THREE.MorphAnimMesh(geometry, facematerial);
model.scale.set(scale, scale, scale);
model.position.set(0, 0, 0);
model.castShadow = true;
model.receiveShadow = true;
model.setFrameRange(modelFrames.stand[0], modelFrames.stand[1]);
//model.add(camera);
scene.add(model);
animate();
}
/**
* Initialize sky box.
*/
function initSkybox() {
//Skyebox用のシーン、カメラを生成
sceneCube = new THREE.Scene();
cameraCube = new THREE.PerspectiveCamera(25, window.innerWidth / window.innerHeight, 1, 10000);
cameraCube.position.y = 20;
sceneCube.add(cameraCube);
//p = positive, n = negative
var urls = [
'/assets/k/z/5/Y/kz5YB.jpg',
'/assets/x/P/8/J/xP8JV.jpg',
'/assets/p/S/A/e/pSAes.jpg',
'/assets/4/v/3/x/4v3xz.jpg',
'/assets/g/a/G/S/gaGSG.jpg',
'/assets/x/z/w/I/xzwIo.jpg'
];
//キューブマップ用にテクスチャをロード
textureCube = THREE.ImageUtils.loadTextureCube(urls);
//
var shader, material;
//Skyebox用にデフォルトで準備されているシェーダを読み込み
shader = THREE.ShaderLib.cube;
//キューブマップ用テクスチャを、uniform変数「tCube」にアップロード
shader.uniforms.tCube.value = textureCube;
//上記のシェーダを、ShaderMaterialとしてマテリアルを生成
material = new THREE.ShaderMaterial({
fragmentShader: shader.fragmentShader,
vertexShader : shader.vertexShader,
uniforms : shader.uniforms,
depthWrite : false,
side : THREE.BackSide
});
//Skyboxメッシュを生成
meshCube = new THREE.Mesh(new THREE.CubeGeometry(1000, 1000, 1000), material);
//生成したメッシュをSkybox用シーンに追加
sceneCube.add(meshCube);
}
/**
* Initialize ground plane.
*/
function initGround() {
var initColor, initTexture,
groundMaterial, groundTexture,
mesh;
initColor = new THREE.Color(0xaea893);
initTexture = THREE.ImageUtils.generateDataTexture(1, 1, initColor);
groundMaterial = new THREE.MeshPhongMaterial({color: 0xffffff, specular: 0x111111, map: initTexture});
groundTexture = THREE.ImageUtils.loadTexture(groundTextureUrl, undefined, function () { groundMaterial.map = groundTexture; });
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
groundTexture.repeat.set(500, 500);
groundTexture.anisotropy = 6;
mesh = new THREE.Mesh(new THREE.PlaneGeometry(20000, 20000), groundMaterial);
mesh.rotation.x = -Math.PI / 2;
mesh.receiveShadow = true;
mesh.castShadow = true;
scene.add(mesh);
}
/**
* All of initialize to the WebGL scene.
*/
function init() {
container = doc.createElement('div');
doc.body.appendChild(container);
clock = new THREE.Clock();
//Create a main scene.
scene = new THREE.Scene();
win.camera = camera = new THREE.PerspectiveCamera(50, win.innerWidth / win.innerHeight, 1, 10000);
camera.position.set(offsetX, offsetY, -offsetZ);
scene.add(camera);
//
var d = 1000;
var pos = d / 5;
globalLight = new THREE.DirectionalLight(0xefefff, 2);
globalLight.position.set(-pos, pos, pos);//.normalize();
globalLight.castShadow = true;
globalLight.shadowMapWidth = 2048;
globalLight.shadowMapHeight = 2048;
globalLight.shadowCameraLeft = -d;
globalLight.shadowCameraRight = d;
globalLight.shadowCameraTop = d;
globalLight.shadowCameraBottom = -d;
globalLight.shadowCameraNear = 0.1;
globalLight.shadowCameraFar = d;
globalLight.shadowCameraFov = 40;
//globalLight.shadowCameraVisible = true;
globalLight.shadowBias = 0.0001;
globalLight.shadowDarkness = 0.5;
scene.add(globalLight);
var light2 = new THREE.DirectionalLight(0xffefef, 0.4);
light2.position.set(0, d, 0).normalize();
scene.add(light2);
var light3 = new THREE.DirectionalLight(0xffefef, 0.2);
light3.position.set(d, d, d).normalize();
//scene.add(light3);
var ambLight = new THREE.AmbientLight(0x666666);
scene.add(ambLight);
//load a gips-danger
var loader = new THREE.JSONLoader();
loader.load(modelUrl, createModel);
//load buildings.
loader.load('http://resources.edo-m18.me/models/gips-danger/building.js', function (geometry, materials) {
var face_material,
s = 100;
if (materials) {
face_material = new THREE.MeshFaceMaterial(materials);
}
else {
face_material = new THREE.MeshLambertMaterial({color: 0xcccccc});
}
var building = new THREE.Mesh(geometry, face_material);
building.scale.set(s, s, s);
building.position.x += 70;
building.position.y += 28;
building.castShadow = true;
building.receiveShadow = true;
scene.add(building);
});
//
initGround();
initSkybox();
//
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.sortObjects = false;
renderer.setSize(win.innerWidth, win.innerHeight);
renderer.setClearColor(0x000000, 1);
renderer.shadowMapEnabled = true;
renderer.shadowMapType = THREE.PCFShadowMap;
renderer.autoClear = false;
container.appendChild(renderer.domElement);
//
win.addEventListener('resize', onWindowResize, false);
}
//
function onWindowResize() {
camera.aspect = win.innerWidth / win.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(win.innerWidth, win.innerHeight);
}
//
function animate() {
requestAnimationFrame(animate);
render();
}
//
//var duration = 5000,
// keyframes = 30,
// lastKeyframe = 0,
// currentKeyframe = 0,
// interpolation = duration / keyframes;
function render() {
if (model) {
var delta = clock.getDelta();
model.updateAnimation(700 * delta);
//if (model.morphTargetInfluences) {
// // Alternate morph targets
// var time = Date.now() % duration;
// var keyframe = Math.floor(time / interpolation);
// if (keyframe != currentKeyframe) {
// model.morphTargetInfluences[lastKeyframe] = 0;
// model.morphTargetInfluences[currentKeyframe] = 1;
// model.morphTargetInfluences[keyframe] = 0;
// lastKeyframe = currentKeyframe;
// currentKeyframe = keyframe;
// }
// model.morphTargetInfluences[keyframe] = (time % interpolation) / interpolation;
// model.morphTargetInfluences[lastKeyframe] = 1 - model.morphTargetInfluences[keyframe];
//}
}
renderer.clear();
renderer.render(sceneCube, cameraCube);
renderer.render(scene, camera);
var distance = player.camera.distance,
position = player.position;
model.position.x = player.position.x;
model.position.y = player.position.y;
model.position.z = player.position.z;
//カメラのpositionを決める
camera.position.x = position.x + distance * Math.sin((player.camera.x) * Math.PI / 180);
camera.position.z = position.z + distance * Math.cos((player.camera.x) * Math.PI / 180);
camera.position.y = position.y + distance * Math.sin((player.camera.y) * Math.PI / 360);
camera.position.y += 1;
var vec3 = new THREE.Vector3(player.position.x, player.position.y + 100, player.position.z);
camera.lookAt(vec3);
}
var moveState = {
moving : false,
front : false,
Backwards : false,
left : false,
right : false,
speed : .1,
angle : 0
};
var pointer = {x: 0, y: 0};
doc.addEventListener('mousemove', function (e) {
var mouseX = e.clientX,
mouseY = e.clientY;
pointer.x = (mouseX / renderer.domElement.width) * 2 - 1;
pointer.y = -(mouseY / renderer.domElement.height) * 2 + 1;
}, false);
var oldPointerX = 0,
oldPointerY = 0;
function rotateStart() {
oldPointerX = pointer.x;
oldPointerY = pointer.y;
renderer.domElement.addEventListener('mousemove', rotate, false);
renderer.domElement.addEventListener('mouseup', rotateStop, false);
}
function rotateStop() {
renderer.domElement.removeEventListener('mousemove', rotate, false);
renderer.domElement.removeEventListener('mouseup', rotateStop, false);
}
function rotate() {
player.camera.x += (oldPointerX - pointer.x) * player.camera.speed;
player.camera.y += (oldPointerY - pointer.y) * player.camera.speed;
if (player.camera.y > 150) {
player.camera.y = 150;
}
if (player.camera.y < -150) {
player.camera.y = -150;
}
moveState.angle = player.camera.x % 360;
oldPointerX = pointer.x;
oldPointerY = pointer.y;
}
doc.addEventListener('mousedown', rotateStart, false);
doc.addEventListener('mousewheel', function (e) {
player.camera.distance += e.wheelDelta / 100;
}, false);
doc.addEventListener('DOMMouseScroll', function (e) {
player.camera.distance += e.detail / 10;
}, false);
//A = left, S = back, D = right, W = front
var A = 65, S = 83, D = 68, W = 87, sp = 0;
function move(e) {
if (!new RegExp(A + '|' + S + '|' + D + '|' + W).test(e.keyCode)) {
return;
}
if (e.shiftKey) {
setAction('run');
}
else {
setAction('walk');
}
var direction = moveState.angle;
switch (e.keyCode) {
case A:
direction += 270;
break;
case S:
direction += 0;
break;
case D:
direction += 90;
break;
case W:
direction += 180;
break;
}
model.rotation.y = direction * Math.PI / 180;
player.position.x += Math.sin(direction * Math.PI / 180) * sp;
player.position.z += Math.cos(direction * Math.PI / 180) * sp;
}
doc.addEventListener('keydown', move, false);
function setAction(actionName) {
var action = modelFrames[actionName];
if (!action || !model) {
return;
}
model.setFrameRange(action[0], action[1]);
sp = action[2];
}
doc.addEventListener('keyup', function () {
setAction('stand');
}, false);
//
doc.addEventListener('DOMContentLoaded', init, false);
}(window, document));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment