Попадание шарика в ячейку

127
19 июля 2021, 18:50

let roulette = document.getElementById('roulette'); 
let svg = document.getElementById('svg'); 
let count = +prompt('Введите число: '); 
 
let rouletteLever; 
let rouletteSpin; 
let balls; 
let runByButton; 
 
class rouletteGame extends Phaser.Scene { 
  constructor() { 
    super('WorldGame'); 
 
    this.ellipse = { 
      forBall: { 
        ball: null, 
        graphics: null, 
        circle: null, 
        hideTheBall: true 
      } 
    }; 
 
    this.boundsCoords = { 
      x: 0, 
      y: 0, 
      width: 20, 
      height: 20 
    } 
  } 
 
  changeRouletteSpin() { 
    rouletteSpin = this.add.sprite(108, 110, 'rouletteSpin', 'Num_Spin_00359.png.webp'); 
    rouletteSpin.setScale(0.7); 
 
    let rouletteSpinFrames = this.anims.generateFrameNames('rouletteSpin', { 
      start: 358, 
      end: 0, 
      zeroPad: 5, 
      prefix: 'Num_Spin_', 
      suffix: '.png.webp' 
    }); 
 
    this.anims.create({ 
      key: 'rouletteSpin', 
      frames: rouletteSpinFrames, 
      frameRate: 29, 
      repeat: -1 
    }); 
    rouletteSpin.anims.play('rouletteSpin'); 
  } 
 
  changeRouletteLever() { 
    rouletteLever = this.add.sprite(200, 150, 'rouletteLever', 'ColumnSpin_00089.png.webp').setScale(0.7); 
 
    let rouletteLeverFrames = this.anims.generateFrameNames('rouletteLever', { 
      start: 88, 
      end: 0, 
      zeroPad: 5, 
      prefix: 'ColumnSpin_', 
      suffix: '.png.webp' 
    }); 
 
    this.anims.create({ 
      key: 'rouletteLever', 
      frames: rouletteLeverFrames, 
      frameRate: 29, 
      repeat: -1 
    }); 
    rouletteLever.anims.play('rouletteLever'); 
  } 
 
  preload() { 
    this.load.image('background', 'images/table_en.png.webp'); 
    this.load.image('wheel', 'images/UpperWheel.png.webp'); 
    this.load.image('ball', 'images/ball.png.webp'); 
    this.load.image('top-panel', 'images/3droulette_lobby_up_bar_full_wide_sdk.png.webp'); 
    this.load.multiatlas('rouletteSpin', 'images/roulette.json', 'images'); 
    this.load.multiatlas('rouletteLever', 'images/lever.json', 'images'); 
    this.load.spritesheet('button-deposit', 'images/button-deposit.png', { 
      frameWidth: 180, 
      frameHeight: 60 
    }); 
  } 
 
  create() { 
    this.matter.world.setBounds(this.boundsCoords.x, this.boundsCoords.y, this.boundsCoords.width, this.boundsCoords.height, 1).disableGravity(); 
 
    this.ellipse.forBall.graphics = this.add.graphics({ 
      lineStyle: { 
        width: 2, 
        color: 0x00ff00 
      }, 
      fillStyle: { 
        color: 0xff0000 
      } 
    }); 
    this.time.advancedTiming = true; 
    this.add.image(0, -160, 'background').setOrigin(0, 0).setScale(0.7); 
    this.add.image(20, 30, 'wheel').setOrigin(0, 0).setScale(0.7); 
 
    //Смена спрайтов колеса 
 
    this.changeRouletteSpin(); 
 
    //Смена спрайтов столба 
 
    this.changeRouletteLever(); 
 
    //Эллипс, по которому движется шарик, который должен упасть на ячейку 
 
    this.ellipse.forBall.circle = new Phaser.Geom.Ellipse(260, 235, 380, 300); 
    this.ellipse.forCells.path.point = this.add.image(-50, -50, 'ball').setScale(0.7); 
 
    //Изображение самого шарика 
 
    this.ellipse.forBall.ball = this.add.image(-50, -50, 'ball').setScale(0.7); 
  } 
 
  decreaseEllipseRadius(c, coeff = 0) { 
    this.ellipse.forBall.circle.width -= (this.ellipse.forBall.circle.width / c + coeff); 
    this.ellipse.forBall.circle.height -= (this.ellipse.forBall.circle.height / c + 0.2 + coeff); 
  } 
 
  update() { 
    this.ellipse.forBall.graphics.clear(); 
    this.ellipse.forBall.circle.getPoint(this.ellipse.forCells.path.step, this.ellipse.forCells.path.point); 
    this.ellipse.forBall.graphics.strokeEllipseShape(this.ellipse.forBall.circle, 64); 
  } 
} 
 
let config = { 
  type: Phaser.WEBGL, 
  parent: 'roulette', 
  physics: { 
    default: 'matter', 
    matter: { 
      debug: true, 
    }, 
    arcade: { 
      gravity: { 
        y: 0 
      }, 
      debug: false, 
    } 
  }, 
  scale: { 
    mode: Phaser.Scale.FIT, 
    autoCenter: Phaser.Scale.CENTER_BOTH, 
    width: 1340, 
    height: 760, 
  }, 
  scene: rouletteGame 
}; 
 
let game = new Phaser.Game(config); 
 
document.querySelector('.roulette-spin').addEventListener('click', () => { 
  runByButton = true; 
});

Есть рулетка на canvas(понимаю, что скрин не самый лучший вариант, но по-другому никак):

Шарик движется по внешней оболочке, и через некоторое время(задаётся) скатывается на колесо с числами(оно крутится), и останавливается. Само колесо - это целая картинка. Таких картинок в сумме 360. Единственное, чем они отличаются, это поворот картинки на 1 градус.

Каким образом можно программно понять, в какую "ячейку" упал шарик?

Возможно, необходимо разместить на каждой ячейке какой- то объект, к которому притягивать шарик. Но как сделать, чтобы эти объекты двигались синхронно с обновлением рулетки(колеса)? Пробовал двигать их по эллипсу, который бы совпадал с колесом, но не нашёл идеальной формулы(рано или поздно объекты, находящиеся на своих ячейках, начинают отставать от своих ячеек)

Answer 1

Смотрите.

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

Если (получили_ячейку_с_сервера И ближе_всего_мы_к_нужной_ячейке){
    прикрепить_к_ячейке();
}
Answer 2

Сильно палками не бить. Попытаюсь описать свой вариант решения.

Сделать 2 файла анимации: для шарика и для рулетки. В каждом из них кадров = количеству ячеек в рулетке или кратно этому количеству.

Осуществлять управление шариком и рулеткой путем смены кадров. Т.о. всегда можно четко указать на каком кадре (на какой ячейке рулетки) должен остановиться шарик. Для шарика та же процедура. Принцип: 1) Запускаем анимации шарика и рулетки (с обычным ticktime) 2) Пока идет анимация, получаем значение выпавшей ячейки с сервера 3) После получения значения задаем по убывающей функции ticktime функцию обратного счета для анимаций (скорость кадров будет уменьшаться до 0). 4) Когда анимация остановится - шарик должен оказаться в нужной ячейке.

Там дело только за расчетом функции обратного счета от длительности анимации остановки рулетки.

Answer 3

Нужно строить случайное перемещение шарика начиная от номера ячейки, пришедшего с сервера к стартовой позиции шарика (стартовый кадр анимации при рендеринге).

Т.е., чтобы правильно визуализировать, нужно всё просчитать в обратном порядке БЕЗ визуализации, а затем - запустить визуализацию (в прямом порядке) и шарик упадёт точно в нужное место (в нужную ячейку).

Answer 4

В общем, спасибо всем за ответы, но всё это было не то, что нужно)

Реализацию придумал сам:

1) Рисуем эллипс(внешний): на нём будет двигаться шарик, который мы должны приземлить на ячейку.

2) Рисуем внутренний эллипс: на нём будут расположены шарики, к которым нам надо примагнитить шарик, двигающийся по внешнему эллипсу.

3) Как по мне, самое интересное) В какой момент начать уменьшать радиус так, чтобы приземляющийся шарик оказался ровно в своей ячейке, не затрагивая соседние?

Делим всё колесо на определённые "секторы", в моём случае - квадраты: Их схема такая:

"0 1 2"
"3 4 5"
"6 7 8"

Мы должны начать "ронять" нужный нам шарик на ячейку только в том случае, если шарик находится, допустим, в 0 и 1 секторах, а нужная нам ячейка - в 4. И дальше по такому принципу... Но как узнать на какую величину уменьшать радиус? Для этого мне вполне подошла обычная теорема Пифагора: находим расстояние между ячейкой(шариком на ней) и шарик, который нужно приземлить, как Math.sqrt(a **2 + b ** 2), где a - расстояние по x между ними, а b - расстояние по y. И уже от радиуса внешнего эллипса вычитаем эту величину(всё-таки придётся немного поковыряться с коэффициентами)

Для чего это нужно? Чтобы шарик не проскользил случайно по другим ячейкам.

4) После того, как произошла коллизия 2 шариков, шарик, который упал на ячейку, скрываем. А тот, что уже лежал на ячейке, показываем)

Вот и всё :)

READ ALSO
Пропал InternalToponymInfo

Пропал InternalToponymInfo

Хотел бы уточнить следующий вопросВчера столкнулся с тем, что геокодер в ответе больше не возвращает поле InternalToponymInfo (расположение поля в ответе...

89
CSS: проблемы с position:fixed

CSS: проблемы с position:fixed

Делаю сайдбар с контентом, который можно проскроллитьПри этом сам сайдбар должен оставаться в фиксированном положении

303
Фон картинкой рамки слева

Фон картинкой рамки слева

Не могу уже несколько часов примудрить в стилях css изображение для фонаТо есть необходимо сделать рамку слева одним изображением и рамку...

98
Прелоадер иконки атома в SVG

Прелоадер иконки атома в SVG

Надо сделать заливку цвета прелоадера как тут вот так

238