БлогNot. Очки жизни и смерти

Очки жизни и смерти

Приснилась мне ночи 2 назад странная сущность в "очках жизни и смерти", совершенно круглых и с левым светлым стеклом, а правым тёмным. И на кого смотрела она, видела в левом стекле его жизнь, а в правом смерть.

Она знала всё о будущем, но не умела изобразить его. Пришлось сегодня напрячься и помочь ей, задействовав примерно те же образы, что там были. Ну, с точностью до параметров, конечно :)

Отчасти скрипт построен на кодах из Galaga. Модель можно дальше балансировать, чтобы заменить вероятности исходов, особенно в местах, помеченных в исходнике знаком !!!.

Ниже показан скрипт в работе и прикреплён исходник на момент написания, который можно сохранить как файл .html (без стандартного обрамления) в кодировке Юникода UTF-8. Наверное, это может быть достаточно медленно на слабом компьютере, у меня быстро. Остановки в коде не предусмотрено, как и в жизни, ну, сдохнет когда-нибудь браузер да и всё. Проверил сейчас только в Firefox и Microsoft Edge, других браузеров на компе не держу. Кто дождётся конца процесса, узнает ответ на волнующий всех вопрос (долго). Ну, и я ожидал другого результата.

Чтобы начать всё сначала достаточно обновить страницу в браузере нажатием клавиши F5.

<div id="glassesDiv" style="margin: 0 auto; text-align: center;"></div>
<script>
function glassesMain (id,createCanvas) {
 let container = document.getElementById (id);
 let canvas;
 if (createCanvas) { //В первый раз создать канву
  canvas = document.createElement('canvas');
  canvas.id = id + '_canvas';
  container.appendChild (canvas);
 }
 else canvas = document.getElementById (id + '_canvas'); //Затем получать id готовой
 let ctx = canvas.getContext('2d');
 let w = canvas.width = 600;
 let h = canvas.height = 600; //Размеры канвы
 let cx = w/2, cy=h/2;

 function clearCanvas() {
  ctx.fillStyle = '#000';
  ctx.fillRect(0, 0, w, h); 
 } 

 function linkedListElement(id) { //Один элемент
  this.next = null;
  this.prev = null;
  this.obj = null;
  this.id = id;
  this.get = function() { return this.obj; }
 }
 function linkedList() { //Список элементов
  this.first = null;
  this.last = null;
  this.counter = 0;
  this.length = 0;
  this.add = function(obj) {
   this.counter++;
   let element = new linkedListElement(this.counter);
   element.obj = obj;
   if (this.first == null) {
    this.first = element; this.last = element;
   }
   else {
    this.last.next = element; element.prev = this.last; this.last = element;
   }
   this.length++;
   return this.counter;
  }
  this.remove = function(id) {
   let element = this.get(id);
   if (element == null) return false;
   this.length--;
   if (element.prev == null && element.next == null) {
    this.first = null; this.last = null;	delete element;	return true;
   }
   if (element.prev == null) {
    this.first = element.next; element.next.prev = null;
   }
   if (element.prev != null) element.prev.next = element.next;
   if (element.next == null) {
    this.last = element.prev; element.prev.next = null;
   }
   if (element.next != null) element.next.prev = element.prev;
   delete element;
   return true;
  }
  this.clear = function() {
   while (this.first != null) this.remove(this.first.id);
  }
  this.get = function(id) {
   if (this.first == null) return null;
   var element = this.first;
   do {
    if (element.id == id) return element;
    element = element.next;
   } while (element != null);
   return null;
  }
  this.getIt = function(count) {
   count--;
   element = this.first;
   if (!element || count >= this.length) return null;
   for (var i=0; i<count; i++) element = element.next;					
   return element;
  }
 }

 function dist(p1,p2) { return Math.sqrt( Math.pow((p1.x-p2.x), 2) + Math.pow((p1.y-p2.y), 2) ); }
 function toRadians (degree,addition) { return (degree + addition) * Math.PI / 180.0; }

 let oAliens = new linkedList(); //Чужаки
 let oStars = new linkedList(); //Звездочки

 function glass() { //Стёкла реальности
  this.iColor = new Array( 'rgba(224,224,224,0.5)','rgba(53,53,53,0.5)' ); //заполнение
  this.aColor = new Array( '#eee','#666' ); //сетка к окружности
  this.msg = '';
  this.radius = new Array (h/8, h/8);
  this.grow = true;
  this.init = function () {
   this.clk = 0;
   let div = 20;
   this.gx = new Array (cx-h/8-div, cx+h/8+div);
  }
  this.init();  
  this.setPos = function() {
   if (this.clk>10) {
    this.clk = -1;
    this.init();  
   }
   this.clk++;
  }
  this.draw = function() {
   for (let i=0; i<2; i++) {
    ctx.beginPath(); 
    ctx.fillStyle=this.iColor[i]; 
    ctx.arc(this.gx[i], cy, this.radius[i], 0, Math.PI * 2, true); 
    ctx.fill();
 	  ctx.closePath();
   }
   ctx.setLineDash(new Array(2,5));
   for (let i=0; i<2; i++) {
    ctx.beginPath(); 
    for (let deg=0; deg<=360; deg+=30) {
     let rad = toRadians(deg,-90);
     let x1 = this.gx[i] + this.radius[i] * Math.cos(rad);
     let y1 = cy + this.radius[i] * Math.sin(rad);
     ctx.strokeStyle = this.aColor[i]; 
     ctx.moveTo (this.gx[i],cy); 
     ctx.lineTo (x1,y1); 
     ctx.stroke();
    }
    ctx.closePath(); 
   }
   ctx.fillStyle='#fff';
   let fontSize = 16;
   ctx.font = fontSize+"px sans-serif";
   ctx.textAlign = "center";
   ctx.textBaseline="middle";
   if (this.msg.length==0) ctx.fillText(''+oAliens.length,cx,cy);   
   else ctx.fillText(this.msg,cx,cy);   
  }
 }
 let MyGlass = new glass();
   
 function star() { //Звёздочка
  this.aColors = new Array(
   'rgb(0,0,0)', 'rgb(0,0,204)', 'rgb(0,191,0)', 'rgb(204,0,204)', 'rgb(0,245,245)', 'rgb(191,191,191)',
   'rgb(204,0,0)', 'rgb(0,204,0)', 'rgb(191,191,0)', 'rgb(245,245,0)', 'rgb(191,0,191)', 'rgb(191,0,0)');
  this.iColor = Math.round(Math.random()*3.4);
  this.clk = 0;
  this.x = Math.floor(Math.random() * w);
  this.y = Math.floor(Math.random() * h);
  this.id = oStars.add(this);
  this.setPos = function() {
   this.y++;
   if (this.y>h) this.y = 0;
   if (this.clk>10) {
    this.clk = 0;
    this.iColor = (this.iColor + 1) % this.aColors.length;
   }
   this.clk+=(Math.random()*7);
  }
  this.draw = function() {
   ctx.fillStyle = this.aColors[this.iColor];
   ctx.fillRect(this.x, this.y, 1, 1);
  }
 }
 for (let i = 0; i < 33; i++) new star();
 
 function alien(sx,sy) { //Чужак
  this.aColors = new Array(
   'rgb(0,191,0)','rgb(0,218,0)','rgb(0,209,0)','rgb(91,191,0)','rgb(0,191,91)','rgb(91,218,0)','rgb(0,218,91)'
  );
  this.init = function (sx,sy) {
   this.iColor = Math.floor(Math.random()*this.aColors.length);
   this.clk = 0;
   this.p0 = {"x": Math.floor(Math.random() * w), "y": Math.floor(Math.random() * h)};
   this.x = this.p0.x;
   this.y = this.p0.y;
   this.rad = 15;
   this.p1 = {"x": Math.floor(Math.random() * w), "y": Math.floor(Math.random() * h)};
   this.p2 = {"x": Math.floor(Math.random() * w), "y": Math.floor(Math.random() * h)};
   if (sx==0 && sy==0) //начнем движение с p3
    this.p3 = {"x": Math.floor(Math.random() * w), "y": Math.floor(Math.random() * h)};
   else     
    this.p3 = {"x": sx, "y": sy};
  }
  this.init(sx,sy);  
  this.mother = false;
  this.id = oAliens.add(this);
  this.setPos = function() {
   let d = dist({"x": this.x, "y": this.y},this.p0);
   if (d<0.1 || this.clk>10) {
    this.clk = -0.02;
    let oldx = this.p0.x, oldy = this.p0.y;
    this.init(oldx,oldy);
    if (Math.round(Math.random())==1) this.mother = true;//восстановил заражабельность с вероятностью !!!
    this.p3.x = oldx; this.p3.y = oldy; //начнем движение с p3
   }
   this.clk+=0.02;
  }
  this.draw = function() {
   let green1x = this.p0.x * this.clk + this.p1.x * (1-this.clk);
  	let green1y = this.p0.y * this.clk + this.p1.y * (1-this.clk);
	  let green2x = this.p1.x * this.clk + this.p2.x * (1-this.clk);
	  let green2y = this.p1.y * this.clk + this.p2.y * (1-this.clk);
	  let green3x = this.p2.x * this.clk + this.p3.x * (1-this.clk);
	  let green3y = this.p2.y * this.clk + this.p3.y * (1-this.clk);
	  let blue1x = green1x * this.clk + green2x * (1-this.clk);
	  let blue1y = green1y * this.clk + green2y * (1-this.clk);
	  let blue2x = green2x * this.clk + green3x * (1-this.clk);
	  let blue2y = green2y * this.clk + green3y * (1-this.clk);
	  let finalx = blue1x * this.clk + blue2x * (1-this.clk);
	  let finaly = blue1y * this.clk + blue2y * (1-this.clk);
   this.x = finalx;
   this.y = finaly;
   ctx.fillStyle = this.aColors[this.iColor];
   ctx.beginPath();
	  ctx.arc(this.x, this.y, this.rad-4, 0, 2 * Math.PI, false);
   ctx.fill();
   ctx.closePath();
 
   ctx.strokeStyle = this.iColor; 
   ctx.setLineDash(new Array(2,2));
   for (let deg=0; deg<=360; deg+=60) {
    let rad = toRadians(deg,-90);
    let x1 = this.x + this.rad * Math.cos(rad);
    let y1 = this.y + this.rad * Math.sin(rad);
    ctx.beginPath();
    ctx.moveTo (this.x,this.y);     
    ctx.lineTo (x1,y1);     
    ctx.stroke();     
    ctx.closePath();
    ctx.beginPath();
    ctx.arc(x1, y1, 2, 0, 2 * Math.PI, false); 
    ctx.fill();
    ctx.closePath();
   }
  }
  this.detect = function() {
   if ( dist({"x":this.x,"y":this.y},{"x":MyGlass.gx[0],"y":cy})<Math.min(MyGlass.radius[0],this.rad) ) { 
    //попал в белый круг
    oAliens.remove(this.id); //сдох
    if (MyGlass.grow) {
     (MyGlass.radius[0])++; 
     if (MyGlass.radius[1]>1) (MyGlass.radius[1])--;
    }
   } 
   if ( dist({"x":this.x,"y":this.y},{"x":MyGlass.gx[1],"y":cy})<Math.min(MyGlass.radius[1],2.33*this.rad) ) {
    //попал в черный круг !!!
    if (this.mother) {
     this.mother = false; //активный на время потерял заражабельность
     new alien(this.x,this.y); //но новый родился
     if (MyGlass.grow) {
      if (MyGlass.radius[0]>1) (MyGlass.radius[0])--; 
      (MyGlass.radius[1])++;
     }
    }
   }
  }
 }
 for (let i = 0; i<50; i++) new alien(0,0); //!!!
 
 let GlobalClock = 0; 
 function draw() { // Главная отрисовка
  GlobalClock++;
  if (GlobalClock % 10 == 0) {
   let oElement = oAliens.first;
   while (oElement != null) {   
    oElement.get().setPos(); oElement = oElement.next;  
   }
  }
  if (GlobalClock % 3 == 0) {
   let oElement = oStars.first;
   while (oElement != null) {
    oElement.get().setPos(); oElement = oElement.next;
   }
  }
  
  clearCanvas();
  let oElement = oStars.first;
  while (oElement != null) {
   oElement.get().draw(); oElement = oElement.next;
  }
  oElement = oAliens.first;
  while (oElement != null) {
   oElement.get().draw(); 
   oElement.get().detect();
   oElement = oElement.next;
  }
  if (oAliens.length==0) {
   MyGlass.grow = false;
   MyGlass.msg = 'Мы победили, все чужаки умерли';
  }
  else if (oAliens.length>500) { 
   MyGlass.grow = false;
   MyGlass.msg = 'Мы все умерли, чужаки съели наш мир'; //!!!
  }
  MyGlass.setPos();
  MyGlass.draw();
 }
 
 let clk = setInterval(function() {draw()}, 10);
}

window.addEventListener ('load', function (e) {
 glassesMain ('glassesDiv',true);
}); 
</script>
<noscript>
 <div style="margin: 0 auto; text-align: center;">
  Включите в браузере JavaScript для работы приложения!
 </div>
</noscript>

теги: графика сон javascript математика random игра

18.04.2020, 22:53; рейтинг: 135