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 View859 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 Tweet QR code Embed Design view Code view <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> zip tags Tweet twitter Favorite by clockmaker Forked sort new page view favorite forked TowerDefence(HTML5 DnD + Canva.. eller86 21 805views 304/4/11 canvas games