Прошу совета по коду игры
Здравствуйте, вот сделал простенькую стрелялку и теперь прошу ваших советов по коду, а именно, как правильно задавать скорость движения объектов.
Ссылка на скрипт: 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, время: 15:18. |