canvas实现太空飞船射击类游戏ASTEROIDS代码
代码语言:html
所属分类:游戏
代码描述:canvas实现太空飞船射击类游戏ASTEROIDS代码,鼠标移动控制飞船,鼠标左键单击射击。
代码标签: canvas 太空 飞船 射击类 游戏 ASTEROIDS 代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"> <style> * { padding: 0; margin: 0; } body { background-color: #000000; color: #fff; font-size: 12px; font-family: Arial, Helvetica, sans-serif; } canvas { cursor: crosshair; position: absolute; } a { color: #fff; text-decoration: none; cursor: pointer; } #menu { position: absolute; top: 50%; margin-top: -45px; text-align: center; width: 100%; } #start { font-size: 20px; font-weight: bold; } #title { font-size: 24px; margin-bottom: 15px; } #message { font-size: 14px; margin-bottom: 30px; } a#tweet { color: white; font-size: 11px; display: inline-block; margin-top: 15px; padding: 5px 10px; background-color: transparent; border: 1px solid white; } a#tweet:hover { color: black; background-color: white; } #hud { position: absolute; top: 10px; left: 10px; list-style: none; } #menu, #hud { -moz-user-select: none; -webkit-user-select: none; -khtml-user-select: none; } #hud li.score { width: 120px; overflow: hidden; } #hud li { float: left; margin-right: 20px; } </style> </head> <body > <div id='container'> <canvas id='c'></canvas> <ul id='hud'> <li class='score'>SCORE: <span id='score'>0</span></li> <li>WEPON: <span id='wepon'>NORMAL BEAM</span></li> </ul> <div id='menu'> <h2 id='title'></h2> <div id='message'></div> <a href='#' id='start'>START</a> </div> </div> <script > // Machine translation because I'm not good at English! //------------------------------------ // CONFIG //------------------------------------ // デフォルトの武器 // Default weapon var WEPON_DEFAULT = { // 武器の名前 // Weapon name name: 'NORMAL BEAM', // 与えるダメージ 0~1 // Damage dealt 0 ~ 1 power: 0.3, // 弾のスピード // Bullet speed speed: 3, // 弾の長さ // Bullet length length: 10, // 弾の幅 // Bullet width width: 1, // 弾の色, 特殊武器の場合アイテムの色に反映される, CSS カラーで指定 // The color of the bullet, in the case of special weapons, reflected in the color of the item, specified by CSS color color: 'white', // 連射速度 // Fire rate shootingInterval: 1000 * 0.35, // 貫通弾か示す // true の場合着弾しても消滅しない // explosion を指定した場合はそちらが優先される // Indicates whether the bullet // If true, will not disappear even if it lands // If explosion is specified, it takes precedence. through: false, // 爆発による着弾後の範囲攻撃 // 以下のプロパティを持つオブジェクトで指定する // { range: 爆発範囲, speed: 爆発の速度 } // * 範囲攻撃の威力は武器の基本威力の半分 // Range attack after landing due to explosion // Specify with an object that has the following properties: // { range: Explosion range, speed: Explosion speed } // * The power of range attacks is half the basic power of weapons explosion: false }; // 特殊武器の配列, UFO を撃破するとランダムで出現する // Special weapon array, Randomly appear when you destroy a UFO var WEPON_SPECIAL = [ { name: 'TINY BEAM', power: 0.1, speed: 10, length: 5, width: 1, color: 'rgb(131, 224, 8)', shootingInterval: 1000 * 0.1, through: false, explosion: false }, { name: 'BLASTER', power: 1, speed: 3, length: 15, width: 3, color: 'rgb(244, 0, 122)', shootingInterval: 1000 * 0.3, through: false, explosion: false }, { name: 'LASER', power: 0.2, speed: 35, length: 200, width: 2, color: 'rgb(138, 227, 252)', shootingInterval: 1000 * 0.6, through: true, explosion: false }, { name: 'EXPLOSION BEAM', power: 0.15, speed: 15, length: 10, width: 2, color: 'rgb(255, 153, 0)', shootingInterval: 1000 * 0.5, through: false, explosion: { range: 100, speed: 4.5 } } /* ,{ name: 'INSANE BEAM', power: 0.035, speed: 7.5, length: 5, color: 'rgb(255, 246, 0)', width: 2, shootingInterval: 1000 * 0.015, through: true, explosion: false, explosion: { range: 75, speed: 2 } }//*/]; var ASTEROID_MAX_SIZE = 80; // 小惑星の最大サイズ var ASTEROID_MIN_SIZE = 5; // 小惑星の最小サイズ var ASTEROID_MAX_NUM = 75; // 小惑星の最大数 var ASTEROID_SPAWN_TIME = 350; // 小惑星の復活時間 var SHIP_SPEED = 1.5; // 自機のスピード var UFO_SPEED = 2; // UFO のスピード var ITEM_SPEED = 0.5; // アイテムのスピード // UFO の出現率 0~1 var UFO_INCIDENCE = 0.0035; // 特殊武器の持続時間 var SPECIAL_WEPON_TIME = 1000 * 20; // 各種スコア var SCORE = { ASTEROID_DAMAGE: 10, ASTEROID_DESTROY: 50, UFO_DAMAGE: 0, UFO_DESTROY: 300 }; //------------------------------------ // CONSTANTS //------------------------------------ var PI = Math.PI; var TWO_PI = PI * 2; var DEG_TO_RAD = PI / 180; var FPS = 60; //------------------------------------ // VARS //------------------------------------ var canvas; var canvasWidth; var canvasHeight; var context; var mouse; var isMouseDown = false; var ship; // Ship var beams; // Collection of Beam var asteroids; // Collection of Asteroid var splinters; // Collection of Splinter var debris; // Collection of Debri var ufo; // Ufo var item; // Item var asteroidLastSpawn = 0; // 小惑星が最後に復活した時間 var ufoLastSpawn = 0; // UFO が最後に復活した時間 var debriLastSpawn = 0; // 背景の星屑が最後に出現した時間 var fieldRange; // フィールドの範囲 var score = 0; // スコア var isPlay = false; // ゲームが開始されているか示す var dom = { menu: null, title: null, message: null, tweet: null, start: null, score: null, wepon: null }; //------------------------------------ // INITIALIZE //------------------------------------ function init() { canvas = document.getElementById('c'); fieldRange = new Range(); window.addEventListener('resize', resize, false); resize(); mouse = new Point(); dom.menu = document.getElementById('menu'); dom.title = document.getElementById('title'); dom.message = document.getElementById('message'); dom.start = document.getElementById('start'); dom.score = document.getElementById('score'); dom.wepon = document.getElementById('wepon'); dom.start.addEventListener('click', start, false); canvas.addEventListener('mousemove', mouseMove, false); canvas.addEventListener('mousedown', mouseDown, false); canvas.addEventListener('mouseup', mouseUp, false); canvas.addEventListener('click', click, false); canvas.addEventListener('touchmove', touchMove, false); canvas.addEventListener('touchstart', mouseDown, false); canvas.addEventListener('touchend', mouseUp, false); debris = new Collection(); for (var i = 0; i < 30; i++) { debris.push(new Debri(randInt(canvasWidth))); } setInterval(loop, 1000 / FPS); } //------------------------------------ // EVENT HANDLERS //------------------------------------ function resize(e) { canvas.width = canvasWidth = fieldRange.right = window.innerWidth; canvas.height = canvasHeight = fieldRange.bottom = window.innerHeight; context = canvas.getContext('2d'); context.fillStyle = 'white'; context.strokeStyle = 'white'; context.lineWidth = 1; } function start(e) { play(); dom.menu.style.display = 'none'; e.preventDefault(); } function mouseMove(e) {mouse.set(e.clientX, e.clientY);} function touchMove(e) {mouse.set(e.touches[0].clientX, e.touches[0].clientY);console.log(e.touches[0].clientX, e.touches[0].clientY);} function mouseDown(e) {isMouseDown = true;} function mouseUp(e) {isMouseDown = false;} function click(e) {if (ship) ship.fire(beams);} //------------------------------------ // FRAME LOOP //------------------------------------ function loop() { context.clearRect(0, 0, canvasWidth, canvasHeight); var now = new Date().getTime(); // Spawn Debri if (now - debriLastSpawn > 300) { debris.push(new Debri(canvasWidth)); debriLastSpawn = now; } // Debri update debris.eachUpdate(); if (isPlay) { // Spawn if (now - asteroidLastSpawn > ASTEROID_SPAWN_TIME && asteroids.length < ASTEROID_MAX_NUM) { asteroids.push(Asteroid.spawn()); asteroidLastSpawn = now; } if (!ufo && !item && Math.random() < UFO_INCIDENCE) { ufo = Ufo.spawn(); } // Update if (ship) { if (isMouseDown) ship.fire(beams); ship.update(mouse); } if (ufo) { ufo.update(); if (ufo.vanished) { item = new Item(ufo.x, ufo.y); ufo = null; } else if (hitDetection(ufo, ship)) { gameOver(); } } if (item) { item.update(); if (item.vanished) { item = null; } else if (hitDetection(item, ship)) { ship.setSpecialWepon(item.wepon); item = null; } } beams.eachUpdate(function (index, beam) { for (var i = 0; i < asteroids.length; i++) { asteroid = asteroids[i]; if (hitDetection(beam, asteroid)) { score += asteroid.damage(beam.power, splinters); beam.notifyHit(); } } if (ufo && hitDetection(beam, ufo)) { score += ufo.damage(beam.power, splinters); beam.notifyHit(); } }); asteroids.eachUpdate(function (index, asteroid) { if (hitDetection(asteroid, ship)) { gameOver(); } }); splinters.eachUpdate(); // Display dom.wepon.innerHTML = ship.currentWepon.name; dom.score.innerHTML = score; } // Draw context.beginPath(); context.strokeStyle = 'rgb(255, 255, 255)'; context.lineWidth = 1; if (ship) ship.draw(context); if (ufo) ufo.draw(context); if (asteroids) asteroids.eachDraw(context); context.stroke(); // Beam は個別に描画 if (beams) beams.eachDraw(context); if (item) { context.beginPath(); context.strokeStyle = item.wepon.color; context.lineWidth = 1; item.draw(context); context.stroke(); } context.beginPath(); context.fillStyle = 'rgb(255, 255, 255)'; if (splinters) splinters.eachDraw(context); if (debris) debris.eachDraw(context); // Game over if (ship && ship.died) { ship.update(); ship.splinter.draw(context); } context.fill(); } //------------------------------------ // FUNCTIONS //------------------------------------ function play() { ship = new Ship(canvasWidth / 2, canvasHeight / 2, 8); mouse.set(ship.x, ship.y); beams = new Collection(); asteroids = new Collection(); splinters = new Collection(); ufo = null; item = null; score = 0; isMouseDown = false; isPlay = true; } function gameOver() { ship.destroy(); isPlay = false; dom.title.innerHTML = 'GAME OVER!'; dom.message.innerHTML = 'YOUR SCORE ' + score + ' POINTS<br />'; dom.message.appendChild(tweetLink()); dom.menu.style.display = 'block'; } function tweetLink() { var exc = score < 1000 ? '...' : score > 3000 ? '!!!' : '!'; if (!dom.tweet) { dom.tweet = document.createElement('a'); dom.tweet.id = 'tweet'; dom.tweet.innerHTML = 'TWEET YOUR SCORE'; } dom.tweet.href = 'https://twitter.com/intent/tweet?url=https://codepen.io/akm2/pen/eYYyELr&text=SCORE ' + score + ' PTS' + exc + ' - ASTEROIDS'; dom.tweet.target = '_blank'; return dom.tweet; } // パスの衝突判定を行う // 引数に指定するオブジェクトは path プロパティから Path オブジェクトが参照可能であること // Perform path collision detection // The object specified in the argument can be referenced from the path property. function hitDetection(a, b) { var ap = a.path,bp = b.path; var as, bs; // Segments var a1, a2, b1, b2; // Points for (i = 0, ilen = ap.segmentNum(); i < ilen; i++) { as = ap.segment(i); a1 = as[0]; a2 = as[1]; for (j = 0, jlen = bp.segmentNum(); j < jlen; j++) { bs = bp.segment(j); b1 = bs[0]; b2 = bs[1]; if (intersection(a1, a2, b1, b2)) return true; } } return false; } // hitDetection で使用される直線の交差判定 // 交差しているなら true // Straight line intersection detection used in hitDetection // True if they intersect function intersection(a1, a2, b1, b2) { var ax = a2.x - a1.x,ay = a2.y - a1.y; var bx = b2.x - b1.x,by = b2.y - b1.y; return (ax * (b1.y - a1.y) - ay * (b1.x - a1.x)) * ( ax * (b2.y - a1.y) - ay * (b2.x - a1.x)) <= 0 && (bx * (a1.y - b1.y) - by * (a1.x - b1.x)) * ( bx * (a2.y - b1.y) - by * (a2.x - b1.x)) <= 0; } //------------------------------------ // UTILS //------------------------------------ function extend() { var target = arguments[0] || {},o,p; for (var i = 1, len = arguments.length; i < len; i++) { o = arguments[i]; if (!isObject(o) || isNull(o)) continue; for (p in o) { target[p] = o[p]; } } return target; }; function randUniform(max, min) { if (min === undefined) min = 0; return Math.random() * (max - min) + min; }; function randInt(max, min) { if (min === undefined) min = 0; return Math.floor(Math.random() * (max - min + 1) + min); }; isObject = function (value) { return typeof value === 'object' && value !== null; }; isNumber = function (value) { return typeof value === 'number'; }; isNumeric = function (value) { return !isNaN(value) && isFinite(value); }; isString = function (value) { return typeof value === 'string'; }; isFunction = function (value) { return typeof value === 'function'; }; isArray = function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; isNull = function (value) { return value === null; }; isUndefined = function (value) { return typeof value === 'undefined'; }; //------------------------------------ // CLASSES //------------------------------------ /** * Collection * * @super Array */ function Collection() { for (var i = 0, len = arguments.length; i < len; i++) { this.push(arguments[i]); } } Collection.prototype = extend([], { eachUpdate: function (callback) { for (var i = 0, len = this.length, item; i < len; i++) { item = this[i]; if (item.vanished) { this.splice(i, 1); len--; i--; continue; } item.update(); if (callback) callback.call(this, i, item); } }, eachDraw: function (ctx) { for (var i = 0, len = this.length; i < len; i++) { this[i].draw(ctx); } } }); /** * Path * * @super Array */ function Path(points, closed) { if (isArray(points)) { for (var i = 0, len = points.length; i < len; i++) { this.push(points[i]); } } this.closed = isUndefined(closed) ? true : closed; } Path.prototype = extend([], { closed: true, segment: function (index) { if (index > this.segmentNum()) return null; return [ this[index], this[index === this.length - 1 ? 0 : index + 1]]; }, segmentNum: function () { return this.closed ? this.length : this.length - 1; }, eachSegments: function (callback) { for (var i = 0, len = this.segmentNum(); i < len; i++) { if (callback.call(this, this.segment(i), i) === false) break; } }, eachPoints: function (callback) { for (var i = 0, len = this.length; i < len; i++) { if (callback.call(this, this[i], i) === false) break; } }, draw: function (ctx) { this.eachPoints(function (p, i) { ctx[i === 0 ? 'moveTo' : 'lineTo'](p.x, p.y); }); if (this.closed && this.length > 2) { var p = this[0]; ctx.lineTo(p.x, p.y); } } }); /** * Point */ function Point(x, y) { this.set(x, y); }; Point.interpolate = function (p1, p2, f) { var dx = p2.x - p1.x, dy = p2.y - p1.y; return new Point(p1.x + dx * f, p1.y + dy * f); }; Point.polar = function (length, angle) { return new Point(length * Math.cos(angle), length * Math.sin(angle)); }; Point.prototype = { set: function (x, y) { if (isObject(x)) { y = x.y; x = x.x; } this.x = x || 0; this.y = y || 0; return this; }, offset: function (x, y) { this.x += x || 0; this.y += y || 0; return this; }, add: function (p) { this.x += p.x; this.y += p.y; return this; }, sub: function (p) { this.x -= p.x; this.y -= p.y; return this; }, scale: function (scale) { this.x *= scale; this.y *= scale; return this; }, length: function () { return Math.sqrt(this.x * this.x + this.y * this.y); }, lengthSq: function () { return this.x * this.x + this.y * this.y; }, normalize: function (thickness) { if (isUndefined(thickness)) thickness = 1; var len = Math.sqrt(this.x * this.x + this.y * this.y); var nx = 0,ny = 0; if (len) { nx = this.x / len; ny = this.y / len; } this.x = nx * thickness; this.y = ny * thickness; return this; }, angle: function () { return Math.atan2(this.y, this.x); }, angleTo: function (p) { var dx = p.x - this.x, dy = p.y - this.y; return Math.atan2(dy, dx); }, distanceTo: function (p) { var dx = this.x - p.x, dy = this.y - p.y; return Math.sqrt(dx * dx .........完整代码请登录后点击上方下载按钮下载查看
网友评论0