Прошу совета по коду игры
Здравствуйте, вот сделал простенькую стрелялку и теперь прошу ваших советов по коду, а именно, как правильно задавать скорость движения объектов.
Ссылка на скрипт: https://github.com/himbotop/first_ga...ster/script.js Сама игра: https://himbotop.github.io/first_game_js/ |
malinovsky,
убрал стиль из canvas, математику(позиционирован е элементов) проверьте снова , на экране 10 кораблей с разной скоростью, смотреть shipsGeneration <!DOCTYPE html> <html> <head> <title>1Game</title> <meta charset="utf-8"> </head> <body> <h2>Управление игрой:</h2> <p>Перемещение влево/вправо стрелки влево/вправо на клавиатуре, клавиша "пробел" - выстрел.</p> <canvas id="canvas" width=600 height=400></canvas> <script> var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var keys = { 'Left' : 37, 'Right' : 39, 'Space' : 32 }; var keyDown = {}; var setKey = function (keyCode) { keyDown[keyCode] = true; }; var clearKey = function (keyCode) { keyDown[keyCode] = false; }; var isKeyDown = function (keyName) { return keyDown[keys[keyName]] == true; }; window.onkeydown = function (e) { setKey(e.keyCode); }; window.onkeyup = function (e) { clearKey(e.keyCode); }; var drawRect = function (x, y, sizeX, sizeY, color) { ctx.beginPath(); ctx.rect(x, y, sizeX, sizeY); ctx.fillStyle = color; ctx.fill(); ctx.closePath(); }; var drawPlayer = function (x) { ctx.beginPath(); ctx.rect(x, 395, 50, 5); ctx.rect(x+10, 390, 30, 5); ctx.rect(x+23, 385, 5, 5); ctx.fillStyle = "rgb(173, 105, 82)"; ctx.fill(); ctx.closePath(); }; var Destruction = function () { for(var i = 0; i < shots.length; i++) { for(var j = 0; j < ships.length; j++) { if(~~shots[i].y == ~~ships[j].y+5 && shots[i].x+5 >= ships[j].x && shots[i].x <= ships[j].x+10) { ships.splice(j, 1); shots.splice(i, 1); break; } } } }; ; var shipsGeneration = function (time) { if( countShips > 30 && ships.length < 10) { ships.push({ t : (3 + Math.random()*13|0)*1000,//время падения от 3сек до 15сек ts : time,//время старта x : Math.random() * 590|0, y : 0 }); countShips = 0; } countShips++; for(var i = 0; i < ships.length; i++) { var s = ships[i], p = (time-s.ts)/s.t; if(p < 1)s.y = p*400|0; else {s.y= 0; s.ts = time ; s.t= (3 + Math.random()*13|0)*1000; s.x = Math.random() * 590|0; }; drawRect(s.x, s.y, 10, 10, "rgb(22, 105, 67)"); } }; var shotsGeneration = function (time) { if(isKeyDown('Space')) { var length = shots.length; if(length > 0) { if( (shots[length-1].y + 7) < 130) { shots.push({ x : xPlayer+23, y : 130 }); } } else { shots.push({ x : xPlayer+23, y : 130 }); } } for(var i = 0; i < shots.length; i++) { drawRect(shots[i].x, shots[i].y, 5, 5, "rgb(195, 55, 67)"); shots[i].y -= 2; } }; var Player = function () { if(isKeyDown('Left')) { xPlayer-=4; } if(isKeyDown('Right')) { xPlayer+=4; } drawPlayer(xPlayer); }; var ships = []; var shots = []; var countShips = 0; var xPlayer = 120; var main = function (time) { ctx.clearRect(0, 0, 600, 400); drawRect(0, 0, 600, 400, "rgb(36, 177, 219)"); Destruction(); shipsGeneration(time); shotsGeneration(); Player(); requestAnimationFrame(main); }; main(); </script> </body> </html> |
Спасибо Рони, теперь понял куда копать, только вот не совсем понял условие (p < 1), почему 1. Я еще немного изменил код.
<!DOCTYPE html> <html> <head> <title>1Game</title> <meta charset="utf-8"> </head> <body> <h2>Управление игрой:</h2> <p>Перемещение влево/вправо стрелки влево/вправо на клавиатуре, клавиша "пробел" - выстрел.</p> <canvas id="canvas" width=600 height=400></canvas> <script> var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); canvas.width = 600; canvas.height = 400; var keys = { 'Left' : 37, 'Right' : 39, 'Space' : 32 }; var keyDown = {}; var setKey = function (keyCode) { keyDown[keyCode] = true; }; var clearKey = function (keyCode) { keyDown[keyCode] = false; }; var isKeyDown = function (keyName) { return keyDown[keys[keyName]] == true; }; window.onkeydown = function (e) { setKey(e.keyCode); }; window.onkeyup = function (e) { clearKey(e.keyCode); }; var drawRect = function (x, y, sizeX, sizeY, color) { ctx.beginPath(); ctx.rect(x, y, sizeX, sizeY); ctx.fillStyle = color; ctx.fill(); ctx.closePath(); }; var drawPlayer = function (x) { ctx.beginPath(); ctx.rect(x, 395, 50, 5); ctx.rect(x+10, 390, 30, 5); ctx.rect(x+23, 385, 5, 5); ctx.fillStyle = "rgb(173, 105, 82)"; ctx.fill(); ctx.closePath(); }; var Destruction = function () { for(var i = 0; i < shots.length; i++) { for(var j = 0; j < ships.length; j++) { if(~~shots[i].y == ~~ships[j].y+5 && shots[i].x+5 >= ships[j].x && shots[i].x <= ships[j].x+10) { ships.splice(j, 1); shots.splice(i, 1); break; } } } }; ; var shipsGeneration = function (time) { if( countShips > densityShips && ships.length < numberShips) { ships.push({ t : speedShips*1000,//время падения от 3сек до 15сек ts : time,//время старта x : Math.random() * 590|0, y : 0 }); countShips = 0; } countShips++; for(var i = 0; i < ships.length; i++) { var s = ships[i], p = (time-s.ts)/s.t; if(p < 1)s.y = p*400|0; else {s.y= 0; s.ts = time ; s.t= speedShips*1000; s.x = Math.random() * 590|0; }; drawRect(s.x, s.y, 10, 10, "rgb(22, 105, 67)"); } }; var shotsGeneration = function (frameTime) { if(isKeyDown('Space')) { var length = shots.length; if(length > 0) { if( (shots[length-1].y + 7) < 380) { shots.push({ x : xPlayer+23, y : 380 }); } } else { shots.push({ x : xPlayer+23, y : 380 }); } } for(var i = 0; i < shots.length; i++) { drawRect(shots[i].x, shots[i].y, 5, 5, "rgb(195, 55, 67)"); shots[i].y -= (frameTime / 1000) * speedShots; } }; var Player = function (frameTime) { if(isKeyDown('Left')) { xPlayer -= (frameTime / 1000) * speedPlayer; } if(isKeyDown('Right')) { xPlayer += (frameTime / 1000) * speedPlayer; } drawPlayer(xPlayer); }; var ships = []; var shots = []; var densityShips = 0; var xPlayer = 120; var lastTime = 0; var countShips = 0; var speedPlayer = 200; // скорость передвижения игрока var densityShips = 30; // плотность кораблей var numberShips = 20; // количество кораблей var speedShips = 15; var speedShots = 150; // скорость пуль var main = function (time) { //console.log(time); ctx.clearRect(0, 0, 600, 400); drawRect(0, 0, 600, 400, "rgb(36, 177, 219)"); var startTime = time; var frameTime = time - lastTime; Destruction(); shipsGeneration(time); shotsGeneration(frameTime); Player(frameTime); lastTime = startTime; requestAnimationFrame(main); }; main(); </script> </body> </html> |
malinovsky,
время падения 20 сек --- прошло 10сек 10/20 = .5 или 50% пути должно быть пройдено, весь путь 400px, 400 * .5 = 200px прошло 20 сек -- 20/20 = 1 или 100% , 400 * 1 = 400px. всё что больше 1 выходит за 400px , поэтому обнуляем данные. |
Теперь дошло, даже на бумажке посчитал (15605.45 - 605.45) / 15000 = 1, плохо у меня с математикой. А как мое изменение по установке скорости для игрока и пуль?
Дальше буду работать над столкновениями. |
malinovsky,
https://learn.javascript.ru/js-animation |
Спасибо Рони, буду разбираться. А пока просто исправил условие столкновения и добавил удаление пуль улетевших за пределы канваса.
https://github.com/himbotop/first_ga...ster/script.js Играть: https://himbotop.github.io/first_game_js/ |
Rise,
ок, спасибо понял. |
|
Rise,
спасибо за науку!!! :thanks: |
Rise,
Спасибо! Буду изучать) |
Rise,
:write: |
Цитата:
|
j0hnik,
маска |
Rise,
рони, Большое Вам спасибо, что помогаете новичкам. :thanks: Начал разбирать примеры с ООП и осознал - нужно учить ООП.:-? Вот например, почему это работает: class Game { constructor() { this.loop = (time) => { console.log(time); requestAnimationFrame(this.loop); }; this.loop(); } } var game = new Game(); а это нет: class Game { constructor() { this.loop = function(time) { console.log(time); requestAnimationFrame(this.loop); }; this.loop(); } } var game = new Game(); Почему в стрелочных функциях this ведет себя не так как в обычных? Совсем запутался.:blink: |
Взялся, блин, делать игры, математику не понимаю, ООП не знаю. В GameDev меня ждет большое будущее...:-E
|
malinovsky,
"use strict" class Game { constructor() { let self = this; this.loop = function(time) { console.log(time); requestAnimationFrame(self.loop); }; this.loop(); } } var game = new Game(); "use strict" class Game { constructor() { this.loop = function(time) { console.log(time); requestAnimationFrame(this.loop); }.bind(this); this.loop(); } } var game = new Game(); |
Цитата:
|
Цитата:
this это ключевое слово в JavaScript которое на этапе лексического разбора заменяется на ссылку на вполне конкретный объект. Это поведение подробно описано в спецификации. Функции в JS это объекты первого типа т.е. их можно использовать как обычные переменные (сохранять передавать как параметры и.т.д.) функции в JS могут оперировать не только с параметрами и локальной областью видимости но и с переменными во внешней области видимости. Что заставляет интерпретатор при создании каждой функции в JS создавать [[skope]] ссылка на который есть в каждой функции. Если бы механизма сохранения внешнего окружения не было то у сохраненной или же переданной функции не было бы доступа к внешним переменным. Именно создание уникального окружения (LexicalEnvironment) для каждой функции и делает возможным механизм замыкания. this заменяется на ссылку на обычный object в котором нет ни явных ни скрытых ссылок на контекст в котором исполняется функция. Т.е. если совсем грубо и на пальцах написал ключевое слово function вне глобальной области видимости получи оверхед на создание окружения для функции. Раньше приходилось писать универсальную функцию и раскидывать логику условным ветвлением сейчас можно использовать стрелочные функции отчего код становится проще и понятнее и быстрее. |
Rise,
посмотри пожалуйста: class Game { constructor(canvas) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.world = new Set(); this._last = 0; this.count = 0; this.objPlayer = new Player(this.canvas.width/2-30, this.canvas.height-30, 30, 20, "rgb(173, 105, 82)", 200); this.world.add(this.objPlayer); this.world.add(new Line(0, 0, 600, 5, "rgb(36, 177, 219)")); this.world.add(new Line(0, 395, 600, 5, "rgb(36, 177, 219)")); console.log(this.objPlayer); this.lastObjShot = false; this._step = (now) => { this._loop = requestAnimationFrame(this._step); this.delta = Math.min(now - this._last, 100) / 1000; this._last = now; this.shipsGenerator(); this.shotsGenerator(); this.update(); this.render(); }; this._step(); } update() { for (let entity of this.world) if (entity.update) entity.update(this); } render() { this.ctx.fillStyle = "rgb(36, 177, 219)"; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); for (let entity of this.world) if (entity.render) entity.render(this); } collide(entity1, type) { for (let entity2 of this.world) { if (entity1 != entity2 && entity2.type & type && entity1.positionX < entity2.positionX + entity2.sizeX && entity1.positionX + entity1.sizeX > entity2.positionX && entity1.positionY < entity2.positionY + entity2.sizeY && entity1.sizeY + entity1.positionY > entity2.positionY) return true; } return false; } stop() { if (this._loop) this._loop = cancelAnimationFrame(this._loop); } shipsGenerator() { if(this.count > 10) { this.world.add(new Ship(Math.random() * 590|0, 5, 10, 10, "rgb(22, 105, 67)", 100)); this.count = 0; } this.count++; } shotsGenerator() { if(keyEvent.space) { if(this.lastObjShot) { if(this.lastObjShot.positionY+7 < 375) { this.lastObjShot = new Shot(this.objPlayer.positionX+11, 375, 7, 7, "rgb(173, 105, 82)", 100); this.world.add(this.lastObjShot); } } else { this.lastObjShot = new Shot(this.objPlayer.positionX+11, 375, 7, 7, "rgb(173, 105, 82)", 100); this.world.add(this.lastObjShot); } } } } class Rect { constructor(positionX, positionY, sizeX, sizeY, color, vel) { this.positionX = positionX; this.positionY = positionY; this.sizeX = sizeX; this.sizeY = sizeY; this.color = color; this.vel = vel || false; } render(game) { game.ctx.fillStyle = this.color; game.ctx.fillRect(this.positionX, this.positionY, this.sizeX, this.sizeY); } } const PLAYER = 1, SHIP = 2, SHOT = 4, LINE = 8; class Player extends Rect { constructor(positionX, positionY, sizeX, sizeY, color, vel) { super(positionX, positionY, sizeX, sizeY, color, vel); Object.assign(this, { type: PLAYER }); } update(game) { if(keyEvent.left) { this.positionX -= this.vel * game.delta; } if(keyEvent.right) { this.positionX += this.vel * game.delta; } if (game.collide(this, PLAYER | SHIP | LINE )) game.stop(); } } class Ship extends Rect { constructor(positionX, positionY, sizeX, sizeY, color, vel) { super(positionX, positionY, sizeX, sizeY, color, vel); Object.assign(this, { type: SHIP }); } update(game) { this.positionY += this.vel * game.delta; if (game.collide(this, PLAYER | SHOT | LINE )) game.world.delete(this); } } class Shot extends Rect { constructor(positionX, positionY, sizeX, sizeY, color, vel) { super(positionX, positionY, sizeX, sizeY, color, vel); Object.assign(this, { type: SHOT }); } update(game) { this.positionY -= this.vel * game.delta; if (game.collide(this, SHIP | SHOT | LINE )) game.world.delete(this); } } class Line extends Rect { constructor(positionX, positionY, sizeX, sizeY, color, vel) { super(positionX, positionY, sizeX, sizeY, color, vel); Object.assign(this, { type: LINE }); } } const keyEvent = { left : false, right : false, space : false }; window.onkeydown = function(e) { switch(e.keyCode) { case 37 : keyEvent.left = true; break; case 39 : keyEvent.right = true; break; case 32 : keyEvent.space = true; break; } }; window.onkeyup = function(e) { switch(e.keyCode) { case 37 : keyEvent.left = false; break; case 39 : keyEvent.right = false; break; case 32 : keyEvent.space = false; break; } }; const game = new Game(document.getElementById('canvas')); |
Rise,
this.delay -= game.delta; // NaN - а почему? пока сделал так: class Game { constructor(canvas) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.world = new Set(); this._last = 0; this.count = 0; this.world.add(new Player(this.canvas.width/2-30, this.canvas.height-30, 30, 20, "rgb(173, 105, 82)", 200)); this.world.add(new Attack(50)); this.world.add(new Line(0, 0, 600, 5, "rgb(36, 177, 219)")); this.world.add(new Line(0, 395, 600, 5, "rgb(36, 177, 219)")); this.lastObjShot = false; this._step = (now) => { this._loop = requestAnimationFrame(this._step); this.delta = Math.min(now - this._last, 100) / 1000; this._last = now; this.update(); this.render(); }; this._step(); } update() { for (let entity of this.world) if (entity.update) entity.update(this); } render() { this.ctx.fillStyle = "rgb(36, 177, 219)"; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); for (let entity of this.world) if (entity.render) entity.render(this); } collide(entity1, type) { for (let entity2 of this.world) { if (entity1 != entity2 && entity2.type & type && entity1.x < entity2.x + entity2.w && entity1.x + entity1.w > entity2.x && entity1.y < entity2.y + entity2.h && entity1.h + entity1.y > entity2.y) return true; } return false; } stop() { if (this._loop) this._loop = cancelAnimationFrame(this._loop); } } class Rect { constructor() { } render(game) { game.ctx.fillStyle = this.color; game.ctx.fillRect(this.x, this.y, this.w, this.h); } } const PLAYER = 1, SHIP = 2, SHOT = 4, LINE = 8; class Player extends Rect { constructor(px, py, pw, ph, c, v) { super(); Object.assign(this, { type: PLAYER, rate: 0.4, delay: 2, x : px, y : py, w : pw, h : ph, color : c, vel : v }); } update(game) { if(keyEvent.left) { this.x -= this.vel * game.delta; } if(keyEvent.right) { this.x += this.vel * game.delta; } this.delay -= 0.05; if (keyEvent.space && this.delay < 0) { this.delay = this.rate; game.world.add(new Shot(this.x+11, this.y-7, 7, 7, 'red', 100)); } if (game.collide(this, PLAYER | SHIP | LINE )) game.stop(); } } class Ship extends Rect { constructor(px, py, pw, ph, c, v) { super(); Object.assign(this, { type: SHIP, x : px, y : py, w : pw, h : ph, color : c, vel : v }); } update(game) { this.y += this.vel * game.delta; if (game.collide(this, PLAYER | SHOT | LINE )) game.world.delete(this); } } class Shot extends Rect { constructor(px, py, pw, ph, c, v) { super(); Object.assign(this, { type: SHOT, x : px, y : py, w : pw, h : ph, color : c, vel : v }); } update(game) { this.y -= this.vel * game.delta; if (game.collide(this, SHIP | SHOT | LINE )) game.world.delete(this); } } class Line extends Rect { constructor(px, py, pw, ph, c, v) { super(); Object.assign(this, { type: LINE, x : px, y : py, w : pw, h : ph, color : c, vel : v }); } } class Attack { constructor(s) { Object.assign(this, { size: s, rate: 0.5, delay: 0 }); } update(game) { this.delay -= 0.05; if (this.delay < 0) { this.delay = this.rate; game.world.add(new Ship(Math.random() * 590, 5, 10, 10, 'green', 100)); if (!--this.size) game.world.delete(this); } } } const keyEvent = { left : false, right : false, space : false }; window.onkeydown = function(e) { switch(e.keyCode) { case 37 : keyEvent.left = true; break; case 39 : keyEvent.right = true; break; case 32 : keyEvent.space = true; break; } }; window.onkeyup = function(e) { switch(e.keyCode) { case 37 : keyEvent.left = false; break; case 39 : keyEvent.right = false; break; case 32 : keyEvent.space = false; break; } }; const game = new Game(document.getElementById('canvas')); и у меня там кажется бардак в конструкторах :-? |
Rise,
спасибо) |
Rise,
Я тут еще заметил, что объекты при столкновении удаляются не все, например, если сталкивается пуля с противником и пуля удаляется первой, то противник может остаться и продолжить движение, поэтому я немного изменил код. Теперь вроде бы работает правильно. Жду твоего мнения. class Game { constructor(canvas) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.world = new Set(); this._last = 0; this.count = 0; this.world.add(new Player(this.canvas.width/2-30, this.canvas.height-30, 30, 20, "rgb(173, 105, 82)", 200)); this.world.add(new Attack(50)); this.lastObjShot = false; this._step = (now) => { this._loop = requestAnimationFrame(this._step); this.delta = Math.min(now - this._last, 100) / 1000; this._last = now; this.update(); this.render(); }; this._step(0); } update() { for (let entity of this.world) if (entity.update) entity.update(this); } render() { this.ctx.fillStyle = "rgb(36, 177, 219)"; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); for (let entity of this.world) if (entity.render) entity.render(this); } collide(entity1, type) { for (let entity2 of this.world) { if (entity1 != entity2 && entity1.x <= entity2.x + entity2.w && entity1.x + entity1.w >= entity2.x && entity1.y <= entity2.y + entity2.h && entity1.h + entity1.y >= entity2.y) { if(entity1.type == (SHOT || SHIP) && entity2.type == (SHIP || SHOT)) { this.world.delete(entity1); this.world.delete(entity2); } if(entity1.type == PLAYER && entity2.type == SHIP) { this.stop(); } } } } stop() { if (this._loop) this._loop = cancelAnimationFrame(this._loop); } } class Rect { constructor() { } render(game) { game.ctx.fillStyle = this.color; game.ctx.fillRect(this.x, this.y, this.w, this.h); } } const PLAYER = 1, SHIP = 2, SHOT = 4, LINE = 8; class Player extends Rect { constructor(px, py, pw, ph, c, v, game) { super(); Object.assign(this, { type: PLAYER, rate: 0.1, delay: 0, x : px, y : py, w : pw, h : ph, color : c, vel : v }); } update(game) { if(keyEvent.left) { this.x -= this.vel * game.delta; } if(keyEvent.right) { this.x += this.vel * game.delta; } this.delay -= game.delta; if (keyEvent.space && this.delay < 0) { this.delay = this.rate; game.world.add(new Shot(this.x+11, this.y-8, 7, 7, 'red', 200)); } game.collide(this); } } class Ship extends Rect { constructor(px, py, pw, ph, c, v, game) { super(); Object.assign(this, { type: SHIP, x : px, y : py, w : pw, h : ph, color : c, vel : v }); game.ship = this; } update(game) { this.y += this.vel * game.delta; game.collide(this); } } class Shot extends Rect { constructor(px, py, pw, ph, c, v) { super(); Object.assign(this, { type: SHOT, x : px, y : py, w : pw, h : ph, color : c, vel : v }); } update(game) { this.y -= this.vel * game.delta; game.collide(this); if(this.y < 0) game.world.delete(this); } } class Attack { constructor(s) { Object.assign(this, { size: s, rate: 0.5, delay: 0 }); } update(game) { this.delay -= game.delta; if (this.delay < 0) { this.delay = this.rate; game.world.add(new Ship(Math.random() * 590, 5, 10, 10, 'green', 100, game)); if (!--this.size) game.world.delete(this); } } } const keyEvent = { left : false, right : false, space : false }; window.onkeydown = function(e) { switch(e.keyCode) { case 37 : keyEvent.left = true; break; case 39 : keyEvent.right = true; break; case 32 : keyEvent.space = true; break; } }; window.onkeyup = function(e) { switch(e.keyCode) { case 37 : keyEvent.left = false; break; case 39 : keyEvent.right = false; break; case 32 : keyEvent.space = false; break; } }; const game = new Game(document.getElementById('canvas')); |
Rise,
тоже самое, вот игра: https://himbotop.github.io/MFG3/ и сам код class Start { constructor(canvas, urlArr) { this.canvas = canvas; this.urlCache = {}; urlArr.forEach((url) => { this.load(url); }); } load(url) { let img = new Image(); img.onload = () => { this.urlCache[url] = img; if(this.isReady()) { new Game(this, new Player(this.canvas.width/2-60, this.canvas.height-100, 102, 83, this.get('img/ship.png'), 200), new Attack(50)); } }; this.urlCache[url] = false; img.src = url; } get(url) { return this.urlCache[url]; } isReady() { let ready = true; for(let k in this.urlCache) { if(this.urlCache.hasOwnProperty(k) && !this.urlCache[k]) { ready = false; } } return ready; } } class Game { constructor(resources, ...entities) { this.ctx = resources.canvas.getContext('2d'); this.resources = resources; this.terrainPattern = this.ctx.createPattern(this.resources.get('img/starfield.png'), 'repeat'); this.world = new Set(entities); this.cache = new Set(); this._last = 0; this.lastObjShot = false; this._step = (now) => { this._loop = requestAnimationFrame(this._step); this.delta = Math.min(now - this._last, 100) / 1000; this._last = now; this.update(); this.render(); }; this._step(0); } update() { for (let entity of this.world) if (entity.update) entity.update(this); for (let entity of this.cache) { this.world.delete(entity); this.cache.delete(entity); } } render() { this.ctx.fillStyle = this.terrainPattern; this.ctx.fillRect(0, 0, this.resources.canvas.width, this.resources.canvas.height); for (let entity of this.world) if (entity.render) entity.render(this); } collide(entity1, type) { for (let entity2 of this.world) { if (entity1 != entity2 && entity2.type & type && entity1.x < entity2.x + entity2.w && entity1.x + entity1.w > entity2.x && entity1.y < entity2.y + entity2.h && entity1.h + entity1.y > entity2.y) return true; } return false; } stop() { if (this._loop) this._loop = cancelAnimationFrame(this._loop); } } class Draw { constructor(options) { const property = { x : null, y : null, w : null, h : null, image : null, vel : null }; let length = 0; for(let prop in property) { property[prop] = options[length]; length++ } Object.assign(this, property); } render(game) { game.ctx.drawImage(this.image, this.x, this.y, this.w, this.h) } } const PLAYER = 1, SHIP = 2, SHOT = 4, LINE = 8; class Player extends Draw { constructor(...options) { super(options); Object.assign(this, { type: PLAYER, rate: 0.2, delay: 0 }); } update(game) { if(keyEvent.left) { this.x -= this.vel * game.delta; } if(keyEvent.right) { this.x += this.vel * game.delta; } this.delay -= game.delta; if (keyEvent.space && this.delay < 0) { this.delay = this.rate; game.world.add(new Shot(this.x+45, this.y-30, 10, 38, game.resources.get('img/bullet.png'), 300)); } if (game.collide(this, PLAYER | SHIP | LINE)) game.stop(); } } class Ship extends Draw { constructor(...options) { super(options); Object.assign(this, { type: SHIP }); } update(game) { this.y += this.vel * game.delta; if (game.collide(this, PLAYER | SHOT | LINE )) game.cache.add(this); } } class Shot extends Draw { constructor(...options) { super(options); Object.assign(this, { type: SHOT }); } update(game) { this.y -= this.vel * game.delta; if (game.collide(this, SHIP | SHOT | LINE )) game.world.delete(this); if(this.y < 0) game.world.delete(this); } } class Attack { constructor(s) { Object.assign(this, { size: s, rate: 0.5, delay: 0 }); } update(game) { this.delay -= game.delta; if (this.delay < 0) { this.delay = this.rate; game.world.add(new Ship(Math.random() * 590, 5, 66, 74, game.resources.get('img/enemy.png'), 100)); if (!--this.size) game.world.delete(this); } } } const keyEvent = { left : false, right : false, space : false }; window.onkeydown = function(e) { switch(e.keyCode) { case 37 : keyEvent.left = true; break; case 39 : keyEvent.right = true; break; case 32 : keyEvent.space = true; break; } }; window.onkeyup = function(e) { switch(e.keyCode) { case 37 : keyEvent.left = false; break; case 39 : keyEvent.right = false; break; case 32 : keyEvent.space = false; break; } }; const canvas = document.getElementById('canvas'); const start = new Start(canvas, ["img/bullet.png", "img/enemy.png", "img/ship.png", "img/starfield.png"]); |
Часовой пояс GMT +3, время: 19:25. |