--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <title>HTML5 Test</title>
+ <link rel="stylesheet" href="http://sfpg.seesaa.net/styles-index.css" type="text/css" />
+ <style type="text/css">
+ #disp01 {margin:10px;}
+ </style>
+<script type="text/javascript" src="../scripts/jquery-1.4.4.min.js"></script>
+<!--<script type="text/javascript">
+
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-15457703-1']);
+ _gaq.push(['_setDomainName', '.seesaa.net']);
+ _gaq.push(['_trackPageview']);
+
+ (function () {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+ })();
+
+</script>-->
+</head>
+<body>
+<div id="div001">
+<canvas id="disp01" width="320" height="240" ></canvas>
+</div>
+<div>
+<button type="button" id="start" disabled="true">開始</button>
+<button type="button" id="stop" disabled="true" >停止</button>
+</div>
+<script type="text/javascript">
+
+ var sx = 80;
+ var sy = 60;
+ var width = 320;
+ var height = 240;
+
+
+ var ctx_main = $("#disp01")[0].getContext("2d");
+ var screenWidth = $("#disp01")[0].width;
+ var screenHeight = $("#disp01")[0].height;
+ var img;
+ var imageRoot = "../image/";
+ var imageCount = 0;
+ var imageLength = 0;
+ var imageLoaded = false;
+
+ var keyCheck = {up:false,down:false,left:false,right:false,z:false};
+
+ function ImageFile(src) {
+ this.src = src;
+ this.image = new Image();
+ this.image.parent = this;
+ this.image.onload = function () {
+// this.parent.canvas = $("<canvas>")[0];
+// this.parent.canvas.width = this.width;
+// this.parent.canvas.height = this.height;
+// this.parent.canvas.getContext("2d").drawImage(this, 0, 0);
+ ++imageLength;
+ };
+ this.image.onerror = function () { ExitError("Image Load Error"); };
+ return this;
+ }
+
+ ImageFile.prototype.load = function () { this.image.src = imageRoot + this.src; };
+
+ var imageFiles = {
+ font : new ImageFile("Font.png"),
+ font1 : new ImageFile("Font2.png"),
+ author : new ImageFile("author.png"),
+ sky : new ImageFile("sky.png"),
+ player: new ImageFile("player.png")
+ };
+
+ var backBuffer = $("<canvas>")[0];
+ backBuffer.width = width + 160;
+ backBuffer.height = height + 120;
+
+ var eraseColor = "black";
+ var ctx = backBuffer.getContext("2d");
+ var t = 0;
+ var renderTimerId = undefined;
+ var mainTimerId = undefined;
+ var keyBuffer = Array(0);
+ var player;
+
+
+ // プレイヤー
+ function Player() {
+ this.x = width / 2;
+ this.image = imageFiles.player.image;
+ this.y = height - this.image.height;
+ this.dir = 0;
+ this.count = 0;
+ return this;
+ }
+
+ Player.prototype.move = function () {
+
+ if(keyCheck.right){
+ this.dir = 1;
+ this.x += this.dir * 3;
+ if (this.x > (width - 16)) {
+ this.x = width - 16;
+ }
+
+ } else if(keyCheck.left){
+ this.dir = -1;
+ this.x += this.dir * 3;
+ if (this.x < 0) {
+ this.x = 0;
+ }
+ } else {
+ this.dir = 0;
+ }
+ this.count++;
+ }
+
+ Player.prototype.draw = function () {
+ var imagePos = 0;
+ switch (this.dir) {
+ case -1:
+ imagePos = 4 + ((this.count & 4) >> 2);
+ break;
+ case 1:
+ imagePos = 2 + ((this.count & 4) >> 2);
+ break;
+ }
+ ctx.drawImage(this.image, imagePos * 16, 0, 16, 16, this.x, this.y, 16, 16);
+ }
+
+
+ // ボールオブジェクト
+ function Ball(x, y, radius, xSpeed, ySpeed,index,color) {
+ this.x = x;
+ this.y = y;
+ this.xSpeed = xSpeed;
+ this.ySpeed = ySpeed;
+ this.radius = radius;
+ this.index = index;
+ this.color = color;
+ this.enable = false;
+ return this;
+ };
+
+// Ball.prototype.init = function (x, y, radius,xSpeed,ySpeed,index) {
+// this.x = x;
+// this.y = y;
+// this.xSpeed = xSpeed;
+// this.ySpeed = ySpeed;
+// this.radius = radius;
+// this.index = index;
+// this.enable = true;
+// }
+
+ Ball.prototype.move = function () {
+
+ this.ySpeed += 0.25;
+ this.x += this.xSpeed;
+
+ if ((this.x + this.radius) > width) {
+ this.x = width - this.radius;
+ this.xSpeed = -(this.xSpeed);
+ }
+
+ if (this.x < this.radius) {
+ this.x = this.radius; // -this.x;
+ this.xSpeed = -(this.xSpeed);
+ }
+
+ this.y += this.ySpeed;
+
+ if ((this.y + this.radius) > height) {
+ this.y = height - this.radius;
+ this.ySpeed = -this.ySpeed ;
+ }
+
+ if (this.y < this.radius) {
+ this.y = this.radius;
+ this.ySpeed = -this.ySpeed ;
+ }
+ };
+
+ Ball.prototype.draw = function (pctx) {
+ var fillStyle = pctx.fillStyle;
+ //pctx.globalAlpha = 0.7;
+ pctx.fillStyle = this.color;
+ pctx.beginPath();
+ pctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
+ pctx.closePath();
+ pctx.fill();
+ pctx.fillStyle = fillStyle;
+ //pctx.globalAlpha = 1.0;
+ };
+
+ Ball.prototype.checkCollision = function (other) {
+ if (Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2) < Math.pow(this.radius + other.radius, 2)) {
+ // 衝突しているので反発させる。
+ return true;
+ }
+ return false;
+ };
+
+ // ボール配列
+ var balls = new Array(0);
+
+ // コンストラクタ
+ function Tasks() {
+ this.array = new Array(0);
+ this.needSort = false;
+ return this;
+ }
+
+
+ Tasks.prototype = {
+ // indexの位置のタスクを置き換える
+ setNextTask: function (index, func, priority) {
+ if (priority == undefined) {
+ priority = 10000;
+ }
+ func.priority = priority;
+ this.array[index] = func;
+ this.needSort = true;
+ },
+
+ pushTask: function (func, priority) {
+ if (priority == undefined) {
+ priority = 10000;
+ }
+ func.priority = priority;
+ for (var i = 0; i < this.length; ++i) {
+ if (this.array[i] == null) {
+ this.array[i] = func;
+ return;
+ }
+ }
+ this.array.push(func);
+ this.needSort = true;
+ },
+ // 配列を取得する
+ getArray: function () {
+ return this.array;
+ },
+ // タスクをクリアする
+ clear: function () {
+ this.array.length = 0;
+ },
+ // ソートが必要かチェックし、ソートする
+ checkSort: function () {
+ if (this.needSort) {
+ this.array.sort(function (a, b) { return a.priority > b.priority; });
+ needSort = false;
+ }
+ }
+ };
+
+ var tasks = new Tasks();
+ var img = new Image();
+
+
+ $(window).ready(function () {
+ ctx.fillStyle = "blue";
+ ctx.fillRect(0, 0, backBuffer.width, backBuffer.height);
+ ctx.setTransform(1, 0, 0, 1, sx, sy);
+ ctx.fillStyle = "white";
+
+ ctx.font = "12px 'MS ゴシック'";
+ ctx.fillText("なんちゃってボール反発です。", 0, 20, 240);
+ ctx.fillText("クリックするとボールが追加されます。", 0, 40, 240);
+ ctx.fillText("背景画像を表示してみました。", 0, 60, 240);
+ render();
+ var color = ["#0030ff", "#0060ff", "#0090ff", "#00c0ff"];
+
+ // 開始ボタンをクリックした時の処理
+ $("#start").click(function () {
+ // renderTimerId = setInterval(render, 100);
+ tasks.pushTask(init);
+ tasks.pushTask(render, 65000);
+ tasks.pushTask(eraseBackBuffer, 65535);
+ balls.length = 0;
+ for (var i = 0; i < 5; ++i) {
+ var rad = 1 + Math.random() * 10;
+ balls.push(
+ new Ball(
+ Math.random() * (width - rad * 2) + rad,
+ Math.random() * (height - rad * 2) + rad,
+ rad,
+ (Math.random() * 5 + 5) * (Math.random() >= 0.5 ? -1 : 1),
+ Math.random() * 4 + 9,
+ i,
+ color[(Math.random() * 4) | 0]
+ )
+ );
+ }
+ mainTimerId = setTimeout(processMain, 50);
+ $("#stop")[0].disabled = false;
+ $("#start")[0].disabled = true;
+ });
+
+ // 停止ボタンをクリックしたときの処理
+ $("#stop").click(function () {
+ // if (renderTimerId != undefined) {
+ // clearInterval(renderTimerId);
+ // renderTimerId = undefined;
+ // }
+ if (mainTimerId != undefined) {
+ clearTimeout(mainTimerId);
+ mainTimerId = undefined;
+ }
+
+ tasks.clear();
+
+ $("#stop")[0].disabled = true;
+ $("#start")[0].disabled = false;
+ });
+
+ // マウスクリックした時の処理
+ $("#disp01").click(function (e) {
+ if ($("#start")[0].disabled && balls.length < 300) {
+ var color = ["#ff3000", "#ff6000", "#ff9000", "#ffc000"];
+ var x = e.pageX - this.offsetLeft;
+ var y = e.pageY - this.offsetTop;
+ var rad = 1 + Math.random() * 10;
+ balls.push(
+ new Ball(
+ x,
+ y,
+ rad,
+ (Math.random() * 9) * (Math.random() >= 0.5 ? -1 : 1),
+ Math.random() * -12,
+ balls.length,
+ color[(Math.random() * 4) | 0]
+ )
+ );
+ }
+ });
+
+ $(document.body).keydown(function (e) {
+
+ if (keyBuffer.length > 16) {
+ keyBuffer.shift();
+ }
+ keyBuffer.push(e.keyCode);
+ switch (e.keyCode) {
+ case 37:
+ keyCheck.left = true;
+ break;
+ case 38:
+ keyCheck.up = true;
+ break;
+ case 39:
+ keyCheck.right = true;
+ break;
+ case 40:
+ keyCheck.down = true;
+ break;
+ case 90:
+ keyCheck.z = true;
+ break;
+ }
+ });
+
+ $(document.body).keyup(function (e) {
+ switch (e.keyCode) {
+ case 37:
+ keyCheck.left = false;
+ break;
+ case 38:
+ keyCheck.up = false;
+ break;
+ case 39:
+ keyCheck.right = false;
+ break;
+ case 40:
+ keyCheck.down = false;
+ break;
+ case 90:
+ keyCheck.z = false;
+ break;
+ }
+
+ });
+
+ // 準備ができたので開始ボタンを押せるようにする
+ $("#start")[0].disabled = false;
+ });
+
+ var r = 0;
+
+ // 描画処理
+ function render() {
+ ctx_main.drawImage(backBuffer, sx, sy, width, height, 0, 0, screenWidth, screenHeight);
+ }
+
+ // バックバッファの消去
+ function eraseBackBuffer() {
+ ctx.fillStyle = eraseColor;
+ ctx.fillRect(0, 0, width, height);
+ }
+
+
+ // 処理メイン
+ // バックバッファの描画
+ var period = 0;
+ var ellapsedTime = 0;
+ var processCount = 0;
+
+ function processMain() {
+ var startTime = new Date().getTime();
+ processCount++;
+ // メインに描画
+ try {
+ tasks.checkSort();
+ $.each(tasks.getArray(),function (taskIndex) {
+ if (this != null) {
+ this(taskIndex);
+ }
+ }
+ );
+ } catch(e) {
+ ExitError(e);
+ }
+ //render();
+ //ctx.fillStyle = "black";
+ var endTime = new Date().getTime();
+ ellapsedTime = endTime - startTime;
+ period = 33 - (ellapsedTime) % 33;
+ mainTimerId = setTimeout(processMain, period);
+ }
+
+ // 初期化タスク
+ function init(taskIndex) {
+ if (!imageLoaded) {
+ ctx.fillStyle = "black";
+ ctx.fillRect(0, 0, width, height);
+ ctx.fillStyle = "white";
+ ctx.fillText("Loadint Image Data", 0, 20, 240);
+ $.each(imageFiles, function (key, value) {
+ imageCount++;
+ this.load();
+ });
+ }
+ tasks.setNextTask(taskIndex, checkLoad);
+ }
+
+
+ // エラーで終了する。
+ function ExitError(e) {
+ clearTimeout(mainTimerId);
+ ctx.fillStyle = "red";
+ ctx.fillRect(0, 0, width, height);
+ ctx.fillStyle = "white";
+ ctx.fillText("Error : " + e, 0, 20, 240);
+ render();
+ throw e;
+ }
+
+ // イメージがとロードされたかチェックする
+ function checkLoad(taskIndex) {
+ if (this.message == undefined) {
+ this.message = "Loading Image Data";
+ this.counter = 0;
+ } else {
+ this.counter++;
+ if (counter >= 10) {
+ this.counter = 0;
+ this.message += ".";
+ }
+ }
+ ctx.fillStyle = "black";
+ ctx.fillRect(0, 0, width, height);
+
+ if (imageCount == imageLength || imageLoaded) {
+ this.message = "Loading Image Data";
+ this.counter = 0;
+ imageLoaded = true;
+ tasks.setNextTask(taskIndex, printAuthor());
+ ctx.fillStyle = "white";
+ ctx.fillText(this.message + "OK", 0, 20, width);
+ } else {
+ ctx.fillStyle = "white";
+ ctx.fillText(this.message, 0, 20, width);
+ }
+ }
+
+ // 作者表示
+ function printAuthor() {
+ var step = 0;
+ var count = 0;
+ var wait = 60;
+ keyBuffer.length = 0;
+ return function (taskIndex) {
+
+ // 何かキー入力があった場合は次のタスクへ
+ if (keyBuffer.length > 0) {
+ keyBuffer.length = 0;
+ step = 4;
+ }
+
+ switch (step) {
+ // フェード・イン
+ case 0:
+ count += 0.1;
+ if (count >= 1.0) step++;
+ break;
+ // 待ち
+ case 1:
+ if (! --wait) step++;
+ break;
+ //フェードアウト
+ case 2:
+ count -= 0.1;
+ if (count <= 0.0) {
+ count = 0.0;
+ wait = 30;
+ step++;
+ }
+ break;
+ // 少し待ち
+ case 3:
+ if (! --wait) {
+ step++;
+ }
+ // 次のタスクへ
+ case 4:
+ tasks.setNextTask(taskIndex, ballAction);
+ tasks.pushTask(function () { ctx.drawImage(imageFiles.sky.image, 0, 0); }, 5000);
+ player = new Player();
+ tasks.pushTask(function () { player.move(); player.draw(); });
+ tasks.pushTask(addCount);
+ break;
+ }
+ var backup = ctx.globalAlpha;
+ ctx.globalAlpha = count;
+ ctx.drawImage(imageFiles.author.image, (width - imageFiles.author.image.width) / 2, (height - imageFiles.author.image.height) / 2);
+ ctx.globalAlpha = backup;
+ };
+ }
+
+ // 処理時間を表示する。
+ function addCount() {
+// var txt = "処理時間:" + ellapsedTime + "ms";
+// ctx.textBaseline = "top";
+// var textWidth = ctx.measureText(txt);
+// ctx.fillStyle = "black";
+// ctx.fillRect(0, 0, textWidth.width, 12);
+// ctx.fillStyle = "white";
+ // ctx.fillText(txt, 0, 0, textWidth.width);
+ var txt = "Process Time: " + ellapsedTime + "ms\n\nTest Program.";
+ print(0, 0, txt);
+ }
+
+ // ボール初期化タスク
+ function ballAction() {
+ for (var i = 0, last = balls.length; i < last; ++i) {
+ var srcBall = balls[i];
+ srcBall.move();
+ srcBall.draw(ctx);
+ for (var j = i + 1; j < last; ++j) {
+ if (srcBall.checkCollision(balls[j])) {
+ bound(srcBall, balls[j]);
+ }
+ }
+ }
+ }
+
+ // 衝突時の処理
+ function bound(src, dest) {
+ // 半径を質量と見立てる。
+ var srcMass = src.radius ;
+ var destMass = dest.radius ;
+ var totalMass = srcMass + destMass;
+ var boundRate = 1.95;
+ var c = { x: dest.x - src.x, y: dest.y - src.y };
+
+ // 正規化
+ var vs = Math.sqrt(c.x * c.x + c.y * c.y);
+ c.x = c.x / vs;
+ c.y = c.y / vs;
+
+ // 内積
+ var dot = (src.xSpeed - dest.xSpeed) * c.x + (src.ySpeed - dest.ySpeed) * c.y;
+
+ // めり込みを補正する。
+ if ((src.radius + dest.radius) > vs) {
+ var a = src.radius + dest.radius - vs;
+
+// var m = (src.radius + dest.radius) / vs;
+ var ax = (c.x * a) / 2;
+ var ay = (c.y * a) / 2;
+ dest.x = dest.x + ax;
+ dest.y = dest.y + ay;
+ src.x = src.x - ax;
+ src.y = src.y - ay;
+// while ((Math.pow(dest.x - src.x, 2) + Math.pow(dest.y - src.y, 2)) <= Math.pow(src.radius + dest.radius, 2)) {
+// dest.x += c.x/2;
+// dest.y += c.y/2;
+// src.x -= c.x/2;
+// src.y -= c.y/2;
+// }
+//
+
+ }
+
+
+ // 定数ベクトル
+ var v = { x: boundRate * dot / totalMass * c.x, y: boundRate * dot / totalMass * c.y };
+ src.xSpeed = -destMass * v.x + src.xSpeed;
+ src.ySpeed = -destMass * v.y + src.ySpeed;
+
+ dest.xSpeed = srcMass * v.x + dest.xSpeed;
+ dest.ySpeed = srcMass * v.y + dest.ySpeed;
+
+// src.x += src.xSpeed;
+// src.y += src.ySpeed;
+
+// dest.x += dest.xSpeed;
+// dest.y += dest.ySpeed;
+
+ }
+
+ // ビットマップキャラクターで文字表示する
+ function print(x, y, str) {
+ var startx = x;
+ var font = imageFiles.font.image;
+ for (var i = 0; i < str.length; ++i) {
+ var c = str.charCodeAt(i);
+ if (c == 0xa) {
+ y += 8;
+ x = startx;
+ } else {
+ c -= 0x20;
+ var ypos = parseInt(c / 16) * 8;
+ var xpos = (c % 16) * 8;
+ ctx.drawImage(font, xpos, ypos, 8, 8, x, y, 8, 8);
+ x += 8;
+ }
+ }
+ }
+
+</script>
+</body>
+</html>