OSDN Git Service

久しぶりにコミット。
[html5test/HTML5Test.git] / html5test0005.htm
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <title>HTML5 Test</title>
5   <link rel="stylesheet" href="http://sfpg.seesaa.net/styles-index.css" type="text/css" />
6   <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script> 
7   <style type="text/css">
8     #disp01 {margin:10px;}
9   </style>
10 <!--<script type="text/javascript" src="http://sfpg.up.seesaa.net/scripts/jquery-1.4.4.min.js"></script>
11 <script type="text/javascript">
12
13   var _gaq = _gaq || [];
14   _gaq.push(['_setAccount', 'UA-15457703-1']);
15   _gaq.push(['_setDomainName', '.seesaa.net']);
16   _gaq.push(['_trackPageview']);
17
18   (function () {
19     var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
20     ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
21     var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
22   })();
23
24 </script>-->
25 </head>
26 <body>
27 <div>
28 <canvas id="disp01" width="320" height="240" ></canvas>
29 </div>
30 <div>
31 <button type="button" id="start" disabled="true">開始</button>
32 <button type="button" id="stop" disabled="true" >停止</button>
33 </div>
34 <script type="text/javascript">
35   
36   var sx = 80;
37   var sy = 60;
38   var width = 320;
39   var height = 240;
40
41
42   var ctx_main = $("#disp01")[0].getContext("2d");
43   var screenWidth = $("#disp01")[0].width;
44   var screenHeight = $("#disp01")[0].height;
45
46   var backBuffer = $("<canvas>")[0];
47   backBuffer.width = width + 160;
48   backBuffer.height = height + 120;
49   var ctx = backBuffer.getContext("2d");
50   var t = 0;
51   var renderTimerId = undefined;
52   var mainTimerId = undefined;
53
54   
55   // ボールオブジェクト
56   function Ball(x, y, radius, xSpeed, ySpeed,index,color) {
57     this.x = x;
58     this.y = y;
59     this.xSpeed = xSpeed;
60     this.ySpeed = ySpeed;
61     this.radius = radius;
62     this.index = index;
63     this.color = color;
64     this.enable = false;
65     return this;
66   };
67
68 //  Ball.prototype.init = function (x, y, radius,xSpeed,ySpeed,index) {
69 //    this.x = x;
70 //    this.y = y;
71 //    this.xSpeed = xSpeed;
72 //    this.ySpeed = ySpeed;
73 //    this.radius = radius;
74 //    this.index = index;
75 //    this.enable = true;
76 //  }
77
78   Ball.prototype.move = function () {
79
80     this.ySpeed += 0.25;
81     this.x += this.xSpeed;
82
83     if ((this.x + this.radius) > width) {
84       this.x = width - this.radius;
85       this.xSpeed = -(this.xSpeed);
86     }
87
88     if (this.x < this.radius) {
89       this.x = this.radius; // -this.x;
90       this.xSpeed = -(this.xSpeed);
91     }
92
93     this.y += this.ySpeed;
94
95     if ((this.y + this.radius) > height) {
96       this.y = height - this.radius;
97       this.ySpeed = -this.ySpeed ;
98     }
99
100     if (this.y < this.radius) {
101       this.y = this.radius;
102       this.ySpeed = -this.ySpeed ;
103     }
104   };
105
106   Ball.prototype.draw = function (pctx) {
107     var fillStyle = pctx.fillStyle;
108     //pctx.globalAlpha = 0.7;
109     pctx.fillStyle = this.color;
110     pctx.beginPath();
111     pctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
112     pctx.closePath();
113     pctx.fill();
114     pctx.fillStyle = fillStyle;
115     //pctx.globalAlpha = 1.0;
116   };
117
118   Ball.prototype.checkCollision = function (other) {
119     if (Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2) < Math.pow(this.radius + other.radius, 2)) {
120       // 衝突しているので反発させる。
121       return true;
122     }
123     return false;
124   };
125
126   // ボール配列
127   var balls = new Array(0);
128    
129   // コンストラクタ
130   function Tasks() {
131     this.array = new Array(0);
132     return this;
133   }
134
135
136   Tasks.prototype = {
137     // indexの位置のタスクを置き換える
138     setNextTask: function (index, func) {
139       this.array[index] = func;
140     },
141
142     pushTask : function (func) 
143     {
144       for (var i = 0; i < this.length; ++i) {
145         if (this.array[i] == null) {
146           this.array[i] = func;
147           return;
148         }
149       }
150       this.array.push(func);
151     },
152     // 配列を取得する
153     getArray: function () {
154       return this.array;
155     },
156     // タスクをクリアする
157     clear: function () {
158       this.array.length = 0;
159     }
160   };
161
162   var tasks = new Tasks();
163
164
165   $(window).ready(function () {
166     ctx.fillStyle = "blue";
167     ctx.fillRect(0, 0, backBuffer.width, backBuffer.height);
168     ctx.setTransform(1, 0, 0, 1, sx, sy);
169     ctx.fillStyle = "white";
170     ctx.font = "12px 'MS ゴシック'";
171     ctx.fillText("なんちゃってボール反発です。", 0, 20, 240);
172     ctx.fillText("クリックするとボールが追加されます。", 0, 40, 240);
173     Math.random()
174     ctx_main.drawImage(backBuffer, sx, sy, width, height, 0, 0, screenWidth, screenHeight);
175     var color = ["#0030ff", "#0060ff", "#0090ff", "#00c0ff"];
176
177     // 開始ボタンをクリックした時の処理
178     $("#start").click(function () {
179       //      renderTimerId = setInterval(render, 100);
180       tasks.pushTask(init);
181       balls.length = 0;
182       for (var i = 0; i < 100; ++i) {
183         var rad = 1 + Math.random() * 10;
184         balls.push(
185         new Ball(
186           Math.random() * (width - rad * 2) + rad,
187           Math.random() * (height - rad * 2) + rad,
188           rad,
189           (Math.random() * 5 + 5) * (Math.random() >= 0.5 ? -1 : 1),
190           Math.random() * 4 + 9,
191           i,
192           color[(Math.random() * 4) | 0]
193           )
194         );
195       }
196       mainTimerId = setTimeout(processMain, 50);
197       $("#stop")[0].disabled = false;
198       $("#start")[0].disabled = true;
199     });
200
201     // 停止ボタンをクリックしたときの処理
202     $("#stop").click(function () {
203       //      if (renderTimerId != undefined) {
204       //        clearInterval(renderTimerId);
205       //        renderTimerId = undefined;
206       //      }
207       if (mainTimerId != undefined) {
208         clearTimeout(mainTimerId);
209         mainTimerId = undefined;
210       }
211
212       tasks.clear();
213
214       $("#stop")[0].disabled = true;
215       $("#start")[0].disabled = false;
216     });
217
218     // マウスクリックした時の処理
219     $("#disp01").click(function (e) {
220       if ($("#start")[0].disabled && balls.length < 300) {
221         var color = ["#ff3000", "#ff6000", "#ff9000", "#ffc000"];
222         var x = e.pageX - this.offsetLeft;
223         var y = e.pageY - this.offsetTop;
224         var rad = 1 + Math.random() * 10;
225         balls.push(
226         new Ball(
227           x,
228           y,
229           rad,
230           (Math.random() * 9) * (Math.random() >= 0.5 ? -1 : 1),
231           Math.random() * -12,
232           balls.length,
233           color[(Math.random() * 4) | 0]
234           )
235         );
236       }
237     });
238
239     // 準備ができたので開始ボタンを押せるようにする
240     $("#start")[0].disabled = false;
241
242
243
244   });
245
246   var r = 0;
247
248   // 描画処理
249   function render() {
250     ctx_main.drawImage(backBuffer, sx, sy, width, height, 0, 0, screenWidth, screenHeight);
251   }
252
253   // 処理メイン
254   // バックバッファの描画
255   var period = 0;
256   var ellapsedTime  = 0;
257   function processMain() {
258     var startTime = new Date().getTime();
259    
260     // メインに描画
261     $(tasks.getArray()).each(function (taskIndex) {
262       if (this != null) {
263         this(taskIndex);
264       }
265     }
266     );
267     render();
268     ctx.fillStyle = "black";
269     ctx.fillRect(0, 0, width, height);
270     var endTime = new Date().getTime();
271     ellapsedTime = endTime - startTime;
272     period = 33 - (ellapsedTime) % 33;
273     mainTimerId = setTimeout(processMain, period);
274   }
275
276   // 初期化タスク
277   function init(taskIndex)
278   {
279     ctx.fillStyle = "black";
280     ctx.fillRect(0, 0, width, height);
281
282     tasks.setNextTask(taskIndex, addCount);
283     tasks.pushTask(ballAction);
284   }
285
286   // 処理時間を表示する。
287   function addCount() {
288     var txt = "処理時間:" + ellapsedTime + "ms";
289     ctx.textBaseline = "top";
290     var textWidth = ctx.measureText(txt);
291     ctx.fillStyle = "black";
292     ctx.fillRect(0, 0, textWidth.width, 12);
293     ctx.fillStyle = "white";
294     ctx.fillText(txt, 0, 0, textWidth.width);
295   }
296    
297   // ボール初期化タスク
298   function ballAction() {
299     for (var i = 0, last = balls.length; i < last; ++i) {
300       var srcBall = balls[i];
301       srcBall.move();
302       srcBall.draw(ctx);
303       for (var j = i + 1; j < last; ++j) {
304         if (srcBall.checkCollision(balls[j])) {
305           bound(srcBall, balls[j]);
306         }
307       }
308     }
309   }
310
311   // 衝突時の処理
312   function bound(src, dest) {
313     // 半径を質量と見立てる。
314     var srcMass = src.radius ;
315     var destMass = dest.radius ;
316     var totalMass = srcMass + destMass;
317     var boundRate = 1.95;
318     var c = { x: dest.x - src.x, y: dest.y - src.y };
319
320     // 正規化
321     var vs = Math.sqrt(c.x * c.x + c.y * c.y);
322     c.x = c.x / vs;
323     c.y = c.y / vs;
324
325     // 内積
326     var dot = (src.xSpeed - dest.xSpeed) * c.x + (src.ySpeed - dest.ySpeed) * c.y;
327
328     // めり込みを補正する。
329     if ((src.radius + dest.radius) > vs) {
330       var a = src.radius + dest.radius - vs;
331
332 //      var m = (src.radius + dest.radius) / vs;
333       var ax = (c.x * a) / 2;
334       var ay = (c.y * a) / 2;
335       dest.x = dest.x + ax;
336       dest.y = dest.y + ay;
337       src.x = src.x - ax;
338       src.y = src.y - ay;
339 //          while ((Math.pow(dest.x - src.x, 2) + Math.pow(dest.y - src.y, 2)) <= Math.pow(src.radius + dest.radius, 2)) {
340 //            dest.x += c.x/2;
341 //            dest.y += c.y/2;
342 //            src.x -= c.x/2;
343 //            src.y -= c.y/2;
344 //          }  
345 //         
346
347     }
348
349
350     // 定数ベクトル
351     var v = { x: boundRate * dot / totalMass * c.x, y: boundRate * dot / totalMass * c.y };
352     src.xSpeed = -destMass * v.x + src.xSpeed;
353     src.ySpeed = -destMass * v.y + src.ySpeed;
354
355     dest.xSpeed = srcMass * v.x + dest.xSpeed;
356     dest.ySpeed = srcMass * v.y + dest.ySpeed;
357
358 //    src.x += src.xSpeed;
359 //    src.y += src.ySpeed;
360
361 //    dest.x += dest.xSpeed;
362 //    dest.y += dest.ySpeed;
363
364   }
365
366 </script>
367 </body>
368 </html>