Forked from: eller86's TowerDefence(HTML5 DnD + Canvas) diff(114) TowerDefence(HTML5 DnD + Canvas) 2nd eller86 Follow 2010-08-29 00:48:27 License: MIT License Fork1 Fav1 View958 Play Stop Reload Fullscreen Smart Phone Fork tree Readme JavaScript 261 lines HTML 4 lines CSS 11 lines TowerDefence(HTML5 DnD + Canvas) 2nd jQuery v1.4.2 // forked from eller86's "TowerDefence(HTML5 DnD + Canvas)" http://jsdo.it/eller86/oJjB /* DnD plugin */ (function(){ jQuery.fn.draggable = function(data, type) { type = type || 'text/plain'; this.bind('dragstart', function(ev) { var dt = ev.originalEvent.dataTransfer; dt.setData(type, data); return true; }); }; jQuery.fn.droppable = function(){ this.bind('dragover', function(ev) { ev.preventDefault(); return false; }); }; jQuery.fn.drop = function(callback){ this.bind('drop', function(ev) { callback(ev); ev.stopPropagation(); return false; }); }; })(jQuery); /* グローバル変数群 */ units = []; missiles = []; colors = ['rgba(128, 128, 255, 0.8)', 'rgba(255, 128, 128, 0.8)']; game = {}; game.GRID_SIZE = 32; game.WIDTH = 320; game.HEIGHT = 320; game.GRID_W = game.WIDTH / game.GRID_SIZE; game.GRID_H = game.HEIGHT / game.GRID_SIZE; game.GOAL_GRID_X = game.GRID_W - 1; game.GOAL_GRID_Y = game.GRID_H - 1; game.fieldDistance = []; /* ready? */ $(function(){ canvas = document.getElementById('world'); ctx = canvas.getContext('2d'); canvas = $(canvas); ctx.font = "12px 'MS Pゴシック'"; calcFieldDistance(); initCanvas(); setInterval(scheduled, 60); // unitsの排他制御は必要?JSはシングルスレッドのはず function scheduled() { createEnemy(); moveUnits(); fireMissiles(); moveMissiles(); checkCollisions(); initCanvas(); drawUnits(); drawMissiles(); } function createEnemy() { if (Math.random() < 0.9) return; var y = Math.random() * 320; var vy = 0; var enemy = { x: -10, y: centered(y), vx: 3, vy: vy, life: 10, team: 1, sleep: 0 }; units.push(enemy); } function initCanvas() { ctx.fillStyle = '#666'; ctx.fillRect(0, 0, game.WIDTH, game.HEIGHT); ctx.lineWidth = 0; ctx.strokeStyle = '#DDD'; ctx.beginPath(); for (var x = 0; x < game.GRID_W; ++x) { ctx.moveTo(x * game.GRID_SIZE, game.HEIGHT); ctx.lineTo(x * game.GRID_SIZE, 0); } for (var y = 0; y < game.GRID_H; ++y) { ctx.moveTo(game.WIDTH, y * game.GRID_SIZE); ctx.lineTo(0, y * game.GRID_SIZE); } ctx.stroke(); } function drawUnits() { ctx.lineWidth = 0; for (var i = 0; i < units.length; ++i) { var unit = units[i]; ctx.strokeStyle = ctx.fillStyle = colors[unit.team]; ctx.beginPath(); ctx.arc(unit.x, unit.y, 10, 0, Math.PI*2, false); ctx.fill(); } } function drawMissiles() { ctx.lineWidth = 2; for (var i = 0; i < missiles.length; ++i) { var missile = missiles[i]; ctx.strokeStyle = ctx.fillStyle = colors[missile.team]; ctx.beginPath(); ctx.moveTo(missile.x, missile.y); ctx.lineTo(missile.x - Math.cos(missile.angle) * missile.speed, missile.y - Math.sin(missile.angle) * missile.speed); ctx.stroke(); } ctx.lineWidth = 0; } function moveUnits() { for (var i = 0; i < units.length; ++i) { var unit = units[i]; unit.x += unit.vx; unit.y += unit.vy; if (unit.sleep) unit.sleep--; } function isLive(elem, index, array) { return elem.life > 0 && elem.x > -20 && elem.x < 340 && elem.y > -20 && elem.y < 340; } units = units.filter(isLive); } function moveMissiles() { for (var i = 0; i < missiles.length; ++i) { var missile = missiles[i]; missile.x += missile.speed * Math.cos(missile.angle); missile.y += missile.speed * Math.sin(missile.angle); } function isLive(elem, index, array) { return elem.x > -20 && elem.x < 340 && elem.y > -20 && elem.y < 340 && elem.damage > 0; } missiles = missiles.filter(isLive); } function distOf(from, to) { var dx = to.x - from.x; var dy = to.y - from.y; return Math.sqrt(dx * dx + dy * dy); } function checkCollisions() { for (var i = 0; i < missiles.length; ++i) { var missile = missiles[i]; for (var j = 0; j < units.length; ++j) { var unit = units[j]; if (unit.team == missile.team) { continue; } if (distOf(missile, unit) > 7) { continue; } unit.life -= missile.damage; missile.damage = 0; break; } } } function fireMissiles() { for (var i = 0; i < units.length; ++i) { var from = units[i]; if (from.team == 1 || from.sleep > 0) { continue; } for (var j = 0; j < units.length; ++j) { var to = units[j]; if (from.team == to.team) { continue; } var dx = to.x - from.x; var dy = to.y - from.y; if (distOf(from, to) > 40) { continue; } // 距離充分、発射! from.sleep = 10; var missile = { x:from.x, y:from.y, team:from.team, angle: Math.atan2(dy, dx), speed: 10, damage: 20 }; missiles.push(missile); break; } } } function centered(pos) { return game.GRID_SIZE / 2 + Math.floor(pos / game.GRID_SIZE) * game.GRID_SIZE; } $('#drag').draggable('hoge'); canvas.droppable(); canvas.drop(function(ev){ function createUnit(x, y) { var unit = { x: centered(x), y: centered(y), vx: 0, vy: 0, life: 10, team: 0, sleep: 0 }; units.push(unit); calcFieldDistance(); } var dx = ev.pageX - canvas.position().left; var dy = ev.pageY - canvas.position().top; createUnit(dx, dy); }); function calcFieldDistance() { function calc(x, y, val) { var i = y * game.GRID_W + x; if (x < 0 || y < 0 || game.GRID_W <= x || game.GRID_H <= y || isUsed( x * game.GRID_SIZE, y * game.GRID_SIZE) || (!!distance[i] && distance[i] <= val)) { return; } distance[i] = val; val++; calc(x + 1, y, val); calc(x - 1, y, val); calc(x, y + 1, val); calc(x, y - 1, val); } var distance = []; calc(game.GOAL_GRID_X, game.GOAL_GRID_Y, 1); game.fieldDistance = distance; } function isUsed(x, y) { for (var i = 0; i < units.length; ++i) { var unit = units[i]; if (unit.team != 0) continue; if (centered(x) == unit.x && centered(y) == unit.y) return true; } return false; } }); <canvas id='world' width='320' height='320'> <p>test</p> </canvas> <p draggable='true' id='drag'>drag & drop me.</p> TowerDefence(HTML5 DnD + Canvas) 2nd body { background-color: #DDDDDD; font: 30px sans-serif; } canvas { display: block; } #drag { border: 1px dashed black; cursor: pointer; } // forked from eller86's "TowerDefence(HTML5 DnD + Canvas)" http://jsdo.it/eller86/oJjB /* DnD plugin */ (function(){ jQuery.fn.draggable = function(data, type) { type = type || 'text/plain'; this.bind('dragstart', function(ev) { var dt = ev.originalEvent.dataTransfer; dt.setData(type, data); return true; }); }; jQuery.fn.droppable = function(){ this.bind('dragover', function(ev) { ev.preventDefault(); return false; }); }; jQuery.fn.drop = function(callback){ this.bind('drop', function(ev) { callback(ev); ev.stopPropagation(); return false; }); }; })(jQuery); /* グローバル変数群 */ units = []; missiles = []; colors = ['rgba(128, 128, 255, 0.8)', 'rgba(255, 128, 128, 0.8)']; game = {}; game.GRID_SIZE = 32; game.WIDTH = 320; game.HEIGHT = 320; game.GRID_W = game.WIDTH / game.GRID_SIZE; game.GRID_H = game.HEIGHT / game.GRID_SIZE; game.GOAL_GRID_X = game.GRID_W - 1; game.GOAL_GRID_Y = game.GRID_H - 1; game.fieldDistance = []; /* ready? */ $(function(){ canvas = document.getElementById('world'); ctx = canvas.getContext('2d'); canvas = $(canvas); ctx.font = "12px 'MS Pゴシック'"; calcFieldDistance(); initCanvas(); setInterval(scheduled, 60); // unitsの排他制御は必要?JSはシングルスレッドのはず function scheduled() { createEnemy(); moveUnits(); fireMissiles(); moveMissiles(); checkCollisions(); initCanvas(); drawUnits(); drawMissiles(); } function createEnemy() { if (Math.random() < 0.9) return; var y = Math.random() * 320; var vy = 0; var enemy = { x: -10, y: centered(y), vx: 3, vy: vy, life: 10, team: 1, sleep: 0 }; units.push(enemy); } function initCanvas() { ctx.fillStyle = '#666'; ctx.fillRect(0, 0, game.WIDTH, game.HEIGHT); ctx.lineWidth = 0; ctx.strokeStyle = '#DDD'; ctx.beginPath(); for (var x = 0; x < game.GRID_W; ++x) { ctx.moveTo(x * game.GRID_SIZE, game.HEIGHT); ctx.lineTo(x * game.GRID_SIZE, 0); } for (var y = 0; y < game.GRID_H; ++y) { ctx.moveTo(game.WIDTH, y * game.GRID_SIZE); ctx.lineTo(0, y * game.GRID_SIZE); } ctx.stroke(); } function drawUnits() { ctx.lineWidth = 0; for (var i = 0; i < units.length; ++i) { var unit = units[i]; ctx.strokeStyle = ctx.fillStyle = colors[unit.team]; ctx.beginPath(); ctx.arc(unit.x, unit.y, 10, 0, Math.PI*2, false); ctx.fill(); } } function drawMissiles() { ctx.lineWidth = 2; for (var i = 0; i < missiles.length; ++i) { var missile = missiles[i]; ctx.strokeStyle = ctx.fillStyle = colors[missile.team]; ctx.beginPath(); ctx.moveTo(missile.x, missile.y); ctx.lineTo(missile.x - Math.cos(missile.angle) * missile.speed, missile.y - Math.sin(missile.angle) * missile.speed); ctx.stroke(); } ctx.lineWidth = 0; } function moveUnits() { for (var i = 0; i < units.length; ++i) { var unit = units[i]; unit.x += unit.vx; unit.y += unit.vy; if (unit.sleep) unit.sleep--; } function isLive(elem, index, array) { return elem.life > 0 && elem.x > -20 && elem.x < 340 && elem.y > -20 && elem.y < 340; } units = units.filter(isLive); } function moveMissiles() { for (var i = 0; i < missiles.length; ++i) { var missile = missiles[i]; missile.x += missile.speed * Math.cos(missile.angle); missile.y += missile.speed * Math.sin(missile.angle); } function isLive(elem, index, array) { return elem.x > -20 && elem.x < 340 && elem.y > -20 && elem.y < 340 && elem.damage > 0; } missiles = missiles.filter(isLive); } function distOf(from, to) { var dx = to.x - from.x; var dy = to.y - from.y; return Math.sqrt(dx * dx + dy * dy); } function checkCollisions() { for (var i = 0; i < missiles.length; ++i) { var missile = missiles[i]; for (var j = 0; j < units.length; ++j) { var unit = units[j]; if (unit.team == missile.team) { continue; } if (distOf(missile, unit) > 7) { continue; } unit.life -= missile.damage; missile.damage = 0; break; } } } function fireMissiles() { for (var i = 0; i < units.length; ++i) { var from = units[i]; if (from.team == 1 || from.sleep > 0) { continue; } for (var j = 0; j < units.length; ++j) { var to = units[j]; if (from.team == to.team) { continue; } var dx = to.x - from.x; var dy = to.y - from.y; if (distOf(from, to) > 40) { continue; } // 距離充分、発射! from.sleep = 10; var missile = { x:from.x, y:from.y, team:from.team, angle: Math.atan2(dy, dx), speed: 10, damage: 20 }; missiles.push(missile); break; } } } function centered(pos) { return game.GRID_SIZE / 2 + Math.floor(pos / game.GRID_SIZE) * game.GRID_SIZE; } $('#drag').draggable('hoge'); canvas.droppable(); canvas.drop(function(ev){ function createUnit(x, y) { var unit = { x: centered(x), y: centered(y), vx: 0, vy: 0, life: 10, team: 0, sleep: 0 }; units.push(unit); calcFieldDistance(); } var dx = ev.pageX - canvas.position().left; var dy = ev.pageY - canvas.position().top; createUnit(dx, dy); }); function calcFieldDistance() { function calc(x, y, val) { var i = y * game.GRID_W + x; if (x < 0 || y < 0 || game.GRID_W <= x || game.GRID_H <= y || isUsed( x * game.GRID_SIZE, y * game.GRID_SIZE) || (!!distance[i] && distance[i] <= val)) { return; } distance[i] = val; val++; calc(x + 1, y, val); calc(x - 1, y, val); calc(x, y + 1, val); calc(x, y - 1, val); } var distance = []; calc(game.GOAL_GRID_X, game.GOAL_GRID_Y, 1); game.fieldDistance = distance; } function isUsed(x, y) { for (var i = 0; i < units.length; ++i) { var unit = units[i]; if (unit.team != 0) continue; if (centered(x) == unit.x && centered(y) == unit.y) return true; } return false; } }); <canvas id='world' width='320' height='320'> <p>test</p> </canvas> <p draggable='true' id='drag'>drag & drop me.</p> body { background-color: #DDDDDD; font: 30px sans-serif; } canvas { display: block; } #drag { border: 1px dashed black; cursor: pointer; } use an iframe compat browser, deer Play on jsdo.it games Share Embed QR Tag Download Complete! Description どんなゲームですか? Control Device スマートフォンコントローラー jsdo.it WebSocket Controller» マウス キーボード タッチデバイス Fullscreen 有効 無効 jsdo.it games から削除する Submit Tweet style Design view Code view code <script type="text/javascript" src="http://jsdo.it/blogparts/z5Gb/js?view=design"></script><p class="ttlBpJsdoit" style="width: 465px; margin: 0; text-align: right; font-size: 11px;"><a href="http://jsdo.it/eller86/z5Gb" title="TowerDefence(HTML5 DnD + Canvas) 2nd">TowerDefence(HTML5 DnD + Canvas) 2nd - jsdo.it - share JavaScript, HTML5 and CSS</a></p> Tweet twitter Favorite by clockmaker Forked sort new page view favorite forked TowerDefence(HTML5 DnD + Canva.. eller86 21 881views 304/4/11 canvas games