2017-06-13 1st TS627 Follow 2017-06-13 16:17:20 License: MIT License Fork0 Fav0 View347 Play Stop Reload Fullscreen Smart Phone Readme JavaScript 284 lines HTML 32 lines CSS 0 lines 布のシミュレーションの練習です。 マウスを動かすと引っ張ることができます。 2017-06-13 1st var display = { canvas: null, layer: null, maxSpeed: 10, friction: 0.1, strength: 0.5, mouseX: 0, mouseY: 0, clothColor: "#FF0000", clothColor2: "#000", }; $(function() { $("#canvas").attr({ height: $("#wrapper").height() }); $("#canvas").attr({ width: $("#wrapper").width() }); var fps = 30; var background = "#FFF"; display.canvas = document.getElementById("canvas"); display.layer = display.canvas.getContext("2d"); display.layer.globalAlpha = 0.7; var physics = new Physics(); var lineCount = 20; var heightCount = 20; var leftCloth = drawNet(physics, 0, 0, display.canvas.width / 2, display.canvas.width / 2, lineCount, heightCount); var rightCloth = drawNet(physics, display.canvas.width / 2, 0, display.canvas.width, display.canvas.width / 2, lineCount, heightCount); setInterval(function() { display.layer.fillStyle = background; display.layer.fillRect(0, 0, display.canvas.width, display.canvas.height); var mouseVec = { x: display.mouseX, y: display.mouseY }; leftCloth.forEach(function(p) { if (Vector.distance(p.pos, mouseVec) < 50) { var dir = Vector.normalize(Vector.sub(p.pos, mouseVec)); dir = Vector.mult(dir, 100); if (!isNaN(dir.x)) { p.addForce(dir); } } }); rightCloth.forEach(function(p) { if (Vector.distance(p.pos, mouseVec) < 50) { var dir = Vector.normalize(Vector.sub(p.pos, mouseVec)); dir = Vector.mult(dir, 100); if (!isNaN(dir.x)) { p.addForce(dir); } } }); physics.update(); drawCloth(leftCloth, lineCount, heightCount); drawCloth(rightCloth, lineCount, heightCount, true); }, 1000 / fps); //マウス座標取得 if (document.addEventListener) { //マウスを移動するたびに実行されるイベント document.addEventListener("mousemove", function(e) { display.mouseX = (isNaN(e.clientX)) ? 0 : e.clientX; display.mouseY = (isNaN(e.clientY)) ? 0 : e.clientY; }); document.addEventListener("touchmove", function(e) { var obj = e.changedTouches[0]; display.mouseX = obj.pageX; display.mouseY = obj.pageY; }); } //網を描く function drawNet(physics, x, y, wid, hei, lineCount, heightCount) { var margin = { x: x, y: y }; var widLen = wid / lineCount; var heiLen = hei / heightCount; var points = []; for (var i = 0; i < heightCount; i++) { for (var j = 0; j < lineCount; j++) { var p = new Point({ x: j * widLen + margin.x, y: i * heiLen + margin.y }); points.push(p); physics.addPoint(p); if (j !== 0) { var pre = points[points.length - 2]; var sp = new Spring({ point1: p, point2: pre, len: widLen, k: display.strength }); physics.addSpring(sp); } if (i !== 0) { var top = points[points.length - 1 - lineCount]; var sp2 = new Spring({ point1: p, point2: top, len: heiLen, k: display.strength }); physics.addSpring(sp2); } } } return points; } function drawCloth(points, lineCount, heightCount, isDiamond) { for (var i = 0; i < heightCount - 1; i++) { for (var j = 0; j < lineCount - 1; j++) { var corners = []; corners[0] = points[i * lineCount + j]; corners[1] = points[i * lineCount + j + 1]; corners[2] = points[(i + 1) * lineCount + j]; corners[3] = points[(i + 1) * lineCount + j + 1]; if (isDiamond) { display.layer.fillStyle = display.clothColor; display.layer.beginPath(); display.layer.moveTo(corners[0].pos.x, corners[0].pos.y); display.layer.lineTo(corners[1].pos.x, corners[1].pos.y); display.layer.lineTo(corners[2].pos.x, corners[2].pos.y); display.layer.lineTo(corners[3].pos.x, corners[3].pos.y); display.layer.closePath(); display.layer.fill(); display.layer.fillStyle = display.clothColor2; display.layer.beginPath(); display.layer.moveTo(corners[0].pos.x, corners[0].pos.y); display.layer.lineTo(corners[2].pos.x, corners[2].pos.y); display.layer.lineTo(corners[1].pos.x, corners[1].pos.y); display.layer.lineTo(corners[3].pos.x, corners[3].pos.y); display.layer.closePath(); display.layer.fill(); } else { display.layer.beginPath(); display.layer.fillStyle = display.clothColor; display.layer.moveTo(corners[0].pos.x, corners[0].pos.y); display.layer.lineTo(corners[1].pos.x, corners[1].pos.y); display.layer.lineTo(corners[3].pos.x, corners[3].pos.y); display.layer.lineTo(corners[2].pos.x, corners[2].pos.y); display.layer.closePath(); display.layer.fill(); } } } } }); function Physics() { this.inisialize.apply(this.arguments); } Physics.prototype = { points: null, springs: null, inisialize: function() { points = []; springs =[]; }, addPoint: function(point) { points.push(point); }, addSpring: function(spring) { springs.push(spring); }, update: function() { springs.forEach(function(spring) { spring.update(); }); points.forEach(function(point) { point.update(); }); } }; function Point() { this.inisialize.apply(this, arguments); } Point.prototype = { pos: { x: 0, y: 0 }, vel: { x: 0, y: 0 }, accel: { x: 0, y: 0 }, inisialize: function(option) { this.pos = { x: option.x, y: option.y }; }, addForce: function(pow) { this.accel = Vector.add(this.accel, pow); }, update: function() { this.addFriction(); this.vel = Vector.add(this.vel, this.accel); this.vel = Vector.constrain(this.vel, display.maxSpeed); this.pos = Vector.add(this.pos, this.vel); this.accel = Vector.mult(this.accel, 0); //毎フレーム加速度を初期化する }, addFriction: function() { var friction = Vector.mult(this.vel, -1); friction = Vector.mult(friction, display.friction); this.addForce(friction); }, display: function() { display.layer.fillStyle = this.color; display.layer.beginPath(); display.layer.arc(this.pos.x, this.pos.y, 10, 0, 2 * Math.PI, false); display.layer.fill(); display.layer.closePath(); }, }; function Spring() { this.inisialize.apply(this, arguments); } Spring.prototype = { point1: null, point2: null, len: 0, k: 0, inisialize: function(option) { this.point1 = option.point1; this.point2 = option.point2; this.len = option.len; this.k = option.k; }, update: function() { var dist = Vector.sub(this.point1.pos, this.point2.pos); var distMag = Vector.magnitude(dist); var stretch = distMag - this.len; var dir = Vector.normalize(dist); var force = Vector.mult(dir, -this.k * stretch); this.point1.addForce(force); this.point2.addForce(Vector.mult(force, -1)); }, display: function() { display.layer.beginPath(); display.layer.moveTo(this.point1.pos.x, this.point1.pos.y); display.layer.lineTo(this.point2.pos.x, this.point2.pos.y); display.layer.stroke(); } }; Vector = { //ベクトル同士の足し算 add: function(vec1, vec2) { return { x: vec1.x + vec2.x, y: vec1.y + vec2.y }; }, //ベクトル同士の引き算 sub: function(vec1, vec2) { return { x: vec1.x - vec2.x, y: vec1.y - vec2.y }; }, //ベクトルをスカラ―倍 mult: function(vec, scalar) { return { x: vec.x * scalar, y: vec.y * scalar }; }, //ベクトルをスカラーで割る div: function(vec, scalar) { return { x: vec.x / scalar, y: vec.y / scalar }; }, //ベクトルを正規化 normalize: function(vec) { var dist = Vector.magnitude(vec); return { x: vec.x / dist, y: vec.y / dist }; }, //ベクトルの長さ magnitude: function(vec) { return Math.sqrt(Math.pow(vec.x, 2) + Math.pow(vec.y, 2)); }, //位置ベクトル間の距離 distance: function(vec1, vec2) { var vec = this.sub(vec1, vec2); return this.magnitude(vec); }, //ベクトルの長さに上限を与える constrain: function(vec, scalar) { var dist = Vector.magnitude(vec); if (dist < scalar) { return vec; } else { return Vector.mult(Vector.normalize(vec), scalar); } } } <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>布のシミュレーション</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script src="./scripts/cloth.js"></script> </script> <style> #wrapper { height: auto; overflow: auto; position: fixed; z-index: 0; width: 100%; height: 100%; min-height: 100%; } </style> </head> <br> <body> <p id="wrapper"> <canvas id="canvas"></canvas> </p> </body> </html> 2017-06-13 1st 布のシミュレーションの練習です。 マウスを動かすと引っ張ることができます。 var display = { canvas: null, layer: null, maxSpeed: 10, friction: 0.1, strength: 0.5, mouseX: 0, mouseY: 0, clothColor: "#FF0000", clothColor2: "#000", }; $(function() { $("#canvas").attr({ height: $("#wrapper").height() }); $("#canvas").attr({ width: $("#wrapper").width() }); var fps = 30; var background = "#FFF"; display.canvas = document.getElementById("canvas"); display.layer = display.canvas.getContext("2d"); display.layer.globalAlpha = 0.7; var physics = new Physics(); var lineCount = 20; var heightCount = 20; var leftCloth = drawNet(physics, 0, 0, display.canvas.width / 2, display.canvas.width / 2, lineCount, heightCount); var rightCloth = drawNet(physics, display.canvas.width / 2, 0, display.canvas.width, display.canvas.width / 2, lineCount, heightCount); setInterval(function() { display.layer.fillStyle = background; display.layer.fillRect(0, 0, display.canvas.width, display.canvas.height); var mouseVec = { x: display.mouseX, y: display.mouseY }; leftCloth.forEach(function(p) { if (Vector.distance(p.pos, mouseVec) < 50) { var dir = Vector.normalize(Vector.sub(p.pos, mouseVec)); dir = Vector.mult(dir, 100); if (!isNaN(dir.x)) { p.addForce(dir); } } }); rightCloth.forEach(function(p) { if (Vector.distance(p.pos, mouseVec) < 50) { var dir = Vector.normalize(Vector.sub(p.pos, mouseVec)); dir = Vector.mult(dir, 100); if (!isNaN(dir.x)) { p.addForce(dir); } } }); physics.update(); drawCloth(leftCloth, lineCount, heightCount); drawCloth(rightCloth, lineCount, heightCount, true); }, 1000 / fps); //マウス座標取得 if (document.addEventListener) { //マウスを移動するたびに実行されるイベント document.addEventListener("mousemove", function(e) { display.mouseX = (isNaN(e.clientX)) ? 0 : e.clientX; display.mouseY = (isNaN(e.clientY)) ? 0 : e.clientY; }); document.addEventListener("touchmove", function(e) { var obj = e.changedTouches[0]; display.mouseX = obj.pageX; display.mouseY = obj.pageY; }); } //網を描く function drawNet(physics, x, y, wid, hei, lineCount, heightCount) { var margin = { x: x, y: y }; var widLen = wid / lineCount; var heiLen = hei / heightCount; var points = []; for (var i = 0; i < heightCount; i++) { for (var j = 0; j < lineCount; j++) { var p = new Point({ x: j * widLen + margin.x, y: i * heiLen + margin.y }); points.push(p); physics.addPoint(p); if (j !== 0) { var pre = points[points.length - 2]; var sp = new Spring({ point1: p, point2: pre, len: widLen, k: display.strength }); physics.addSpring(sp); } if (i !== 0) { var top = points[points.length - 1 - lineCount]; var sp2 = new Spring({ point1: p, point2: top, len: heiLen, k: display.strength }); physics.addSpring(sp2); } } } return points; } function drawCloth(points, lineCount, heightCount, isDiamond) { for (var i = 0; i < heightCount - 1; i++) { for (var j = 0; j < lineCount - 1; j++) { var corners = []; corners[0] = points[i * lineCount + j]; corners[1] = points[i * lineCount + j + 1]; corners[2] = points[(i + 1) * lineCount + j]; corners[3] = points[(i + 1) * lineCount + j + 1]; if (isDiamond) { display.layer.fillStyle = display.clothColor; display.layer.beginPath(); display.layer.moveTo(corners[0].pos.x, corners[0].pos.y); display.layer.lineTo(corners[1].pos.x, corners[1].pos.y); display.layer.lineTo(corners[2].pos.x, corners[2].pos.y); display.layer.lineTo(corners[3].pos.x, corners[3].pos.y); display.layer.closePath(); display.layer.fill(); display.layer.fillStyle = display.clothColor2; display.layer.beginPath(); display.layer.moveTo(corners[0].pos.x, corners[0].pos.y); display.layer.lineTo(corners[2].pos.x, corners[2].pos.y); display.layer.lineTo(corners[1].pos.x, corners[1].pos.y); display.layer.lineTo(corners[3].pos.x, corners[3].pos.y); display.layer.closePath(); display.layer.fill(); } else { display.layer.beginPath(); display.layer.fillStyle = display.clothColor; display.layer.moveTo(corners[0].pos.x, corners[0].pos.y); display.layer.lineTo(corners[1].pos.x, corners[1].pos.y); display.layer.lineTo(corners[3].pos.x, corners[3].pos.y); display.layer.lineTo(corners[2].pos.x, corners[2].pos.y); display.layer.closePath(); display.layer.fill(); } } } } }); function Physics() { this.inisialize.apply(this.arguments); } Physics.prototype = { points: null, springs: null, inisialize: function() { points = []; springs =[]; }, addPoint: function(point) { points.push(point); }, addSpring: function(spring) { springs.push(spring); }, update: function() { springs.forEach(function(spring) { spring.update(); }); points.forEach(function(point) { point.update(); }); } }; function Point() { this.inisialize.apply(this, arguments); } Point.prototype = { pos: { x: 0, y: 0 }, vel: { x: 0, y: 0 }, accel: { x: 0, y: 0 }, inisialize: function(option) { this.pos = { x: option.x, y: option.y }; }, addForce: function(pow) { this.accel = Vector.add(this.accel, pow); }, update: function() { this.addFriction(); this.vel = Vector.add(this.vel, this.accel); this.vel = Vector.constrain(this.vel, display.maxSpeed); this.pos = Vector.add(this.pos, this.vel); this.accel = Vector.mult(this.accel, 0); //毎フレーム加速度を初期化する }, addFriction: function() { var friction = Vector.mult(this.vel, -1); friction = Vector.mult(friction, display.friction); this.addForce(friction); }, display: function() { display.layer.fillStyle = this.color; display.layer.beginPath(); display.layer.arc(this.pos.x, this.pos.y, 10, 0, 2 * Math.PI, false); display.layer.fill(); display.layer.closePath(); }, }; function Spring() { this.inisialize.apply(this, arguments); } Spring.prototype = { point1: null, point2: null, len: 0, k: 0, inisialize: function(option) { this.point1 = option.point1; this.point2 = option.point2; this.len = option.len; this.k = option.k; }, update: function() { var dist = Vector.sub(this.point1.pos, this.point2.pos); var distMag = Vector.magnitude(dist); var stretch = distMag - this.len; var dir = Vector.normalize(dist); var force = Vector.mult(dir, -this.k * stretch); this.point1.addForce(force); this.point2.addForce(Vector.mult(force, -1)); }, display: function() { display.layer.beginPath(); display.layer.moveTo(this.point1.pos.x, this.point1.pos.y); display.layer.lineTo(this.point2.pos.x, this.point2.pos.y); display.layer.stroke(); } }; Vector = { //ベクトル同士の足し算 add: function(vec1, vec2) { return { x: vec1.x + vec2.x, y: vec1.y + vec2.y }; }, //ベクトル同士の引き算 sub: function(vec1, vec2) { return { x: vec1.x - vec2.x, y: vec1.y - vec2.y }; }, //ベクトルをスカラ―倍 mult: function(vec, scalar) { return { x: vec.x * scalar, y: vec.y * scalar }; }, //ベクトルをスカラーで割る div: function(vec, scalar) { return { x: vec.x / scalar, y: vec.y / scalar }; }, //ベクトルを正規化 normalize: function(vec) { var dist = Vector.magnitude(vec); return { x: vec.x / dist, y: vec.y / dist }; }, //ベクトルの長さ magnitude: function(vec) { return Math.sqrt(Math.pow(vec.x, 2) + Math.pow(vec.y, 2)); }, //位置ベクトル間の距離 distance: function(vec1, vec2) { var vec = this.sub(vec1, vec2); return this.magnitude(vec); }, //ベクトルの長さに上限を与える constrain: function(vec, scalar) { var dist = Vector.magnitude(vec); if (dist < scalar) { return vec; } else { return Vector.mult(Vector.normalize(vec), scalar); } } } <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>布のシミュレーション</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script src="./scripts/cloth.js"></script> </script> <style> #wrapper { height: auto; overflow: auto; position: fixed; z-index: 0; width: 100%; height: 100%; min-height: 100%; } </style> </head> <br> <body> <p id="wrapper"> <canvas id="canvas"></canvas> </p> </body> </html> use an iframe compat browser, deer Play on jsdo.it games Author Share ブログに埋め込む QR Tag Download Complete! Description What kind of game? 布のシミュレーションの練習です。 マウスを動かすと引っ張ることができます。 Control Device Smartphone Controllerjsdo.it WebSocket Controller» Mouse Keyboard Touch Device Fullscreen Activated Inactivated jsdo.it games から削除する Submit Author TS627 Tweet Default Panel Auto play Screenshot Readme JavaScript HTML CSS Size Width: px Height: px code <script type="text/javascript" src="http://jsdo.it/blogparts/wLbW/js"></script> art&design Discussion Questions on this code? Tags art&design