Форум программистов, компьютерный форум, киберфорум
JavaScript: HTML5 Canvas
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.81/21: Рейтинг темы: голосов - 21, средняя оценка - 4.81
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572

Как сделать столкновение объектов?

24.03.2024, 21:02. Показов 6296. Ответов 70
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте мне нужно сделать столкновение объектов через функцию. Вот пример варианта, что нужно получить.
Название: GameCollision.gif
Просмотров: 615

Размер: 63.7 Кб
Я для этого специально написала функцию hitTest. Выше пример это обычный вариант где сравниваются по оси координат столкновения граней.

Через hitTest у меня фиксируется только столкновение когда объект находиться внутри. Пример на gif-анимации.
Название: GameHitTest.gif
Просмотров: 618

Размер: 88.7 Кб

Как проверять грани и запускать hitTest?

В прошлый раз мне не ответили поэтому я код изменила и сделала более легкую версию.

Здесь используются функции

- Transform
- setTransform. Все это важно для проверки столкновения.

Вот код, чтобы протестировать достаточно скопировать, сохранить в html файл и загрузить в браузере. Никакие библиотеки дополнительно подключать не нужно.
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Пример hitTest </title>
<script>
window.onload = function()
{
var canvas = document.getElementById("drawingCanvas");
var context = canvas.getContext("2d");
 
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
 
var dragok = false;
var startX;
var startY;
var _activeInstructions = [];
 
var shapeW = 50, hitW = 100;
 
 
 
   localToLocal = function(hit1,x, y, target, pt) {
        var tx1,ty1,pt1;
        tx1 = 1*hit1.x+0*hit1.y+0;
        ty1 = 0*hit1.x+1*hit1.y+0;
 
        
        pt1 = {};
        pt1.x = x*1+y*0+tx1;
        pt1.y = x*0+y*1+ty1;
        
      
     
        return globalToLocal(target,pt1.x, pt1.y, pt);
    };
 
 
 
 
 
globalToLocal = function(hit1,x, y, pt) {
  
      
      var mtx1 = {a:1,b:0,c:0,d:1,tx:-150,ty:-150};
      
     
      var pt1 = {};
      pt1.x = x*1+y*0+mtx1.tx;
      pt1.y = x*0+y*1+mtx1.ty;
      
      
      return pt1;
       
}
 
 
 
Shape = function(x,y,w,h,color,color1,lineWidth1)
{
   
    this.x1 = x;
    this.y1 = y;
    this.w = w;
    this.h = h;
    this.color = color;
    this.color1 = color1;
    this.lineWidth = lineWidth1;
    this.exec = function(ctx)
    {
      ctx.lineWidth =  this.lineWidth;
      ctx.beginPath(); 
     
      
      ctx.rect(this.x1, this.y1, this.w, this.h);
      ctx.fillStyle = this.color;
      ctx.fill();
      
     
      ctx.strokeStyle = this.color1;
      ctx.stroke();
        
    }
    
   this.hitTest = function(ctx, x, y) {
     
      ctx.setTransform(1, 0, 0, 1, -x, -y);
      this.exec(ctx);
      
      var hit = this._testHit(ctx);
      
       
      ctx.setTransform(1, 0, 0, 1, 0, 0);
      ctx.clearRect(0, 0, 2, 2);
      return hit;
      
    };
   this.set = function(props) {
        
        for (var n in props) { 
        this[n] = props[n]; 
        }
        return this;
    };
    
  this._testHit = function(ctx) {
        try {
          
            var hit = ctx.getImageData(0, 0, 1, 1).data[3] > 1;
            
        } catch (e) {
            
        }
        
        return hit;
    };
    
    
 
    this.updateContext = function(ctx) {
        var o = this;
          var a1 = 1;
          var b1 = 0;
          var c1 = 0;
          var d1 = 1;
          
          var tx1 = a1*o.x+c1*o.y+0;
          var ty1 = b1*o.x+d1*o.y+0;
          
          var mtx = {a:1,b:0,c:0,d:1,tx:tx1,ty:ty1};
        
        var tx = mtx.tx,
            ty = mtx.ty;
       
        
        ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, tx, ty);
     
    }
}
 
Rectangle = function(x,y,w,h,color)
{
  this.x1 = x;
  this.y1 = y;
  this.w = w;
  this.h = h;
  this.color = color;
  this.exec = function(ctx)
  {
  
    ctx.beginPath(); 
    ctx.rect(0, 0, this.w, this.h);
    ctx.fillStyle = "#906";
    ctx.fill();
   
  }
  this.set = function(props) {
      
        for (var n in props) { this[n] = props[n]; }
        return this;
  };
  
  
  
  
  this.updateContext = function(ctx) {
        var o = this;
 
       
        
        
        var a1 = 1;
          var b1 = 0;
          var c1 = 0;
          var d1 = 1;
          
          var tx1 = a1*o.x+c1*o.y+0;
          var ty1 = b1*o.x+d1*o.y+0;
          
           
       var mtx = {a:1,b:0,c:0,d:1,tx:tx1,ty:ty1};
       var tx = mtx.tx,
            ty = mtx.ty;
        ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, tx, ty);
        ctx.globalAlpha *= 1;
    }
} 
 
 
 
function clear() {
  context.clearRect(0, 0, WIDTH, HEIGHT);
}
 
 
 
 
   setInterval(() => {
              (
                function() {
                  clear();
                  draw();
                }).call(this);
   }, 33);
var shape1,rect1; 
 
 
function init() {
  clear();
  
  shape1 = new Shape(0,0,hitW,hitW,"#ddd","blue",1);
  shape1.set({x:150, y:150});
  
  
 
  
  rect1 = new Rectangle(0,0,50,50,"#906");
  rect1.set({x:10, y:170});
  
   
   
   
 canvas.addEventListener("mousedown", (e) => {
      e.preventDefault();
      e.stopPropagation();
      
      var mx=parseInt(e.clientX-offsetX);
      var my=parseInt(e.clientY-offsetY);
      dragok=false;
      
      
      if(mx>rect1.x && mx<rect1.x+rect1.w && my>rect1.y && my<rect1.y+rect1.h){
          
         
          dragok=true;
          
     }
      
      
       startX=mx;
       startY=my;
      
      
  });
  canvas.addEventListener("mouseup", (e) => {
     e.preventDefault();
     e.stopPropagation();
 
 
     dragok = false;
      
  });
  
  canvas.addEventListener("mousemove", (e) => {
     
   if (dragok){
       e.preventDefault();
      e.stopPropagation();
 
    
      var mx=parseInt(e.clientX-offsetX);
      var my=parseInt(e.clientY-offsetY);
 
     
      var dx=mx-startX;
      var dy=my-startY;
      
     
      
      
      rect1.x+=dx;
      rect1.y+=dy;
      
      
       var pt = localToLocal(rect1,rect1.x-shape1.x,rect1.y-shape1.y,shape1);
                  if (shape1.hitTest(context,pt.x, pt.y)) {
                      shape1.color1 = "green";
                      shape1.lineWidth = 7;
                    } else {
                      shape1.color1 = "blue";
                      shape1.lineWidth = 1;
                   }
      startX=mx;
      startY=my;
      
      
    }
     
      
  });
   
   
  
 draw();
  
 
}
function draw()
{
  context.save();
  shape1.updateContext(context);
  shape1.exec(context);
  context.restore();
  
  context.save();
  rect1.updateContext(context);
  rect1.exec(context);
  context.restore();
}
init();
}
</script>
</head>
<body>
 
<canvas id="drawingCanvas" width="500" height="500"></canvas>
</body>
</html>
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
24.03.2024, 21:02
Ответы с готовыми решениями:

Непростое столкновение объектов на Canvas
Здравствуйте, уважаемые форумчане. Познаю работу с canvas. Нужно написать скрипт, реализующий перемещение круга мышкой из А в Б,...

Как определить столкновение объектов
Как сделать столкновение объектов. Когда зеленый объект прикасается слева или справа красный объект или когда верхняя часть зеленого...

Столкновение объектов
Есть проблемка, запутался ,помогите,пожалуйста.Не реагирует на столкновение,заранее большое спасибо &lt;html&gt; ...

70
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
25.05.2024, 15:04  [ТС]
Студворк — интернет-сервис помощи студентам
8Observer8, закончила игру шутер для двух игроков. Новые улучшения.
1.Сделала полностью уровень.
2.Текстом добавила количество жизней.
3.Добавила броню. Действует – 10 секунд. Перезарядка (чтобы она снова появилась на карте) – 30 секунд. Броня дает полную неуязвимость от прямого попадания лазера.

4.Так как карта небольшая, то высокий шанс встретить другого игрока. Роботы погибают с одного прямого выстрела (если нет защиты), поэтому разместила два портала. Чтобы игрок мог отступить, если враг подобрал защиту и стал неуязвимым. Придумано для баланса.

5.Переписала код и убрала лишние свойства из функций.
Вот исходник, чтобы посмотреть и протестировать.
ShooterPlatformer.zip
1
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
25.05.2024, 18:48
У меня русский текст отображается вопросами в игре:

Название: questions-instead-of-russian-text.png
Просмотров: 81

Размер: 1.7 Кб

А в редакторе кода Sublime Text 4 русский текст отображается кракозябами:



Я с этим столкнулся впервые, поэтому не могу точно описать проблему. Попробуйте погуглить. Может быть в вашем редакторе кода выставлена какая-то неправильная кодировка. Скорее всего, должа быть установлена кодировка UTF-8.

Отыскал место, где должны выводиться слова "Игрок" и "Жизни":

JavaScript
1
2
    livesPlayer1.getText("Èãðîê 1 - Æèçíè: " + lives1);
    livesPlayer2.getText("Èãðîê 2 - Æèçíè: " + lives2);
Заменил на:

JavaScript
1
2
    livesPlayer1.getText("Игрок 1 - Жизни: " + lives1);
    livesPlayer2.getText("Игрок 2 - Жизни: " + lives2);
Вывелось сообщение в Sublime Text после сохранения изменений выше:



Теперь этот текст в браузере отображается нормально:

Название: player-1-lifes-in-russian.png
Просмотров: 81

Размер: 1.0 Кб

Миниатюры
0
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
25.05.2024, 19:07
Попробуйте разместить игру на бесплатном хостинге https://www.netlify.com/ Это популярный и проверенный хостинг. Постарайтесь интуитивно понять, как это сделать. Если возникнут трудности, то я подскажу. Если кратко, то справа нужно кликнуть "Add new site" и выбрать "Deploy manually". Далее, выбрать папку с игрой, где содержится файл index.html
0
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
25.05.2024, 19:37  [ТС]
Попробуйте разместить игру на бесплатном хостинге https://www.netlify.com/
У меня ошибку выдает когда я пытаюсь перйти Log In.
0
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
25.05.2024, 20:12
Попробуйте сначала нажать "Sing Up". Или ошибка происходит после регистрации? Если внизу страницы есть кнопка "Применить Cookies, то примените"
0
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
25.05.2024, 20:19  [ТС]
Почему нельзя сделать через Apache или похожую программу, которая умеет создавать локальные хосты и запускать сайты прямо на компьютере? Я именно так и делаю свои проекты. В интернет вообще не выхожу.
0
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
25.05.2024, 20:48
Я вместо Apache использую Node.js пакет http-server. Я просто хотел, чтобы другие кто открывает тему могли поиграть в браузере просто кликнув один раз по ссылке, а не нужно было им скачивать, извлекать архив, запускать локальный сервер - в основно будет неохота это делать. Кстати, я пробовал запускать вашу игру без локального сервера - она работает. Просто кликнул два раза по index.html. На всякий случай, на будущее, мне ещё известны (хорошо с ними знаком) бесплатные хостинги Glitch и Render (на них даже можно сделать back end на Node.js), а так же без серверной части: https://pages.github.com/ и https://plnkr.co/ Вдруг потом вам пригодится, чтобы публиковать игры и получать обратную связь в виде найденных ошибок или идей, что можно улучшить. Есть ещё хостинг https://itch.io/ - в него можно закинуь архив с игрой, где главный файл должен называться index.html
0
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
25.05.2024, 21:44  [ТС]
Я сделала тестовый пример легкую версию и запустила его в браузере.
Вот исходники:
ShooterPlatformerLite.zip
При тестировании в браузере у меня тоже были проблемы с кодировкой. Я просто сменила кодировку в браузере на кирилицу.
0
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
25.05.2024, 23:08
Цитата Сообщение от Katerina1993 Посмотреть сообщение
ShooterPlatformerLite.zip
При тестировании в браузере у меня тоже были проблемы с кодировкой.
Я закинул папку "ShooterPlatformerLite" на хостинг Netlify. Кликните эту ссылку, чтобы запустить в браузере. Есть ли проблема с кодировкой в вашем браузере?

На гифке показал, как развёртывается сайт на Netlify перетаскиванием мышкой, а заодно показал, что есть проблема с кодировкой в конце гифки:



Миниатюры
0
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
26.05.2024, 07:50  [ТС]
8Observer8, я проверила пример по ссылке работает. Есть проблема с кодировкой, но ее можно изменить в браузере или в документе на windows-1251.

Для столкновения лазера со щитом я использовала Math.sqrt и написала функцию dist. Чтобы проверить как она работает я сделала отдельный тестовый пример.
Где происходит столкновение двух окружностей. Вот исходники, может кому пригодиться.
CollisionElipse.zip
После тестирования столкновений я внедрила этот пример в проект.
0
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
26.05.2024, 10:55
Цитата Сообщение от Katerina1993 Посмотреть сообщение
Есть проблема с кодировкой, но ее можно изменить в браузере или в документе на windows-1251.
В этом случае для пользователей вашей игры нужно написать пошаговую инструкцию для Chrome, FireFox, Edge и т.д. Я, например, не знаю, как менять кодировку в браузере. Вы программируете в Notepad или в Far? Например, в редакторе кода Sublime Text 4 никаких проблем с кодировкой нет. Мне в каждом вашем примере нужно вручную исправлять кракозябы на руссский? Решите, пожалуйста, эту проблему, которая повторилась в CollisionElipse: демка в браузере

Название: collision-elipse.png
Просмотров: 75

Размер: 1.7 Кб

Исправил кракозабы на русский в ShooterPlatformerLite в Sublime Text 4, развернул на хостинге и проблемы нет:



Миниатюры
0
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
26.05.2024, 14:33
Замечание по поводу ковыче в примере "CollisionElipse". В половине примера у вас одинарные ковычки:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
keyboard1.keyMappings[38] = 'moveForwards'; //w
keyboard1.keyMappings[40] = 'moveBackwards'; //s
keyboard1.keyMappings[37] = 'moveLeft'; // a
keyboard1.keyMappings[39] = 'moveRight'; // d
 
/* ... */
 
document.addEventListener('keydown', function(event) {
    event.preventDefault();
    var keyName = _self.keyMappings[event.which];
    if (keyName != undefined) {
        _self.inputs[keyName] = true;
    }
});
document.addEventListener('keyup', function(event) {
    event.preventDefault();
    event.preventDefault();
    var keyName = _self.keyMappings[event.which];
    if (keyName != undefined) {
        _self.inputs[keyName] = false;
    }
}, true);
А в другой половине двойные:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function init() {
    stage = new createjs.Stage("demoCanvas");
 
    target1 = stage.addChild(new createjs.Shape());
    target1.graphics.beginFill("red").drawCircle(0, 0, 45);
 
    target1.x = 100;
    target1.y = 180;
 
    target2 = stage.addChild(new createjs.Shape());
    target2.graphics.beginFill("blue").drawCircle(0, 0, 45);
 
    target2.x = 200;
    target2.y = 380;
 
    setEventListeners();
    createjs.Ticker.on("tick", tick);
}
Это неаккуратно. Надо чтобы везде в JS-коде были либо двойные либо одинарные. У вас опять везде разные выравнивания. Прочитайте главу в книге "Совершенный код" про важность форматирования кода и именования переменных для процесса разработки. Особенно если ещё кто-то кроме вас потенциально будет читает ваш код. Неужели вам самой притно смотреть на такие выравнивания:

JavaScript
1
2
3
4
5
6
        var p1 = new createjs.SpriteSheet(_tmpTile); 
                 this.tmpTile = new createjs.Sprite(p1);
                 this.set({x:x, y:y});
                 
                this.regX = regX;
                this.regY = regY;
JavaScript
1
2
3
4
5
6
7
8
  if(this._type2 == 1)
  {
   this.on("tick", function(event)
   {
     
      if(!this.running && this.running!==null)
      {
        this.running = null;
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
     if(keyboard1.inputs.turnLeft==true)
      {
         lefttrigger2 = 1;
         
       }
       else
       {
        lefttrigger2 = 0; 
       }
         if(keyboard1.inputs.turnRight==true)
        {
          righttrigger2 = 1;
          
         }
         else
         {
          righttrigger2 = 0; 
         }
Хорошо, что есть инструменты для автоматического выравнивания типа js-beautify, а то бы я не стал читать ваш код, потому что такое выравнивание портило бы настроение его читать.

Отступы внутри скобок. То у вас вместе написано:

JavaScript
1
if(keyboard1.inputs.turnRight==true)
то раздельно:

JavaScript
1
if(this._type2 == 1)
0
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
26.05.2024, 17:07
Цитата Сообщение от Katerina1993 Посмотреть сообщение
Для столкновения лазера со щитом я использовала Math.sqrt и написала функцию dist. Чтобы проверить как она работает я сделала отдельный тестовый пример.
Где происходит столкновение двух окружностей. Вот исходники, может кому пригодиться.
CollisionElipse.zip
После тестирования столкновений я внедрила этот пример в проект.
В этом примере я оставил без изменений вашу физику определения столкновений, а заменил только графическую библиотеку рисования на Three.js

Демка на беплатном хостинге Netlify Управление клавишами-стрелками



index.html

PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
<!DOCTYPE html>
<html>
 
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spheres | Custom collision detection | Three.js</title>
    <style>
        html,
        body {
            overflow: hidden;
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }
 
        #renderCanvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
 
<body>
    <canvas id="renderCanvas"></canvas>
 
    <!-- Since import maps are not yet supported by all browsers, its is
        necessary to add the polyfill es-module-shims.js -->
    <script async src="https://8observer8.github.io/libs/es-module-shims@1.10.0/es-module-shims.js"></script>
 
    <script type="importmap">
        {
            "imports": {
                "three": "https://8observer8.github.io/libs/three@0.164.1/build/three.module.min.js",
                "orbit-controls": "https://8observer8.github.io/libs/three@0.164.1/examples/jsm/controls/OrbitControls.js"
            }
        }
    </script>
 
    <script type="module">
        import * as THREE from "three";
        import { OrbitControls } from "orbit-controls";
 
        let camera, renderer, scene;
        let orbitControls;
        let target1, target2;
        const target1Speed = 0.1;
 
        var keyboard = [];
        keyboard.keyMappings = [];
 
        keyboard.keyMappings[38] = "moveForwards"; //w
        keyboard.keyMappings[40] = "moveBackwards"; //s
        keyboard.keyMappings[37] = "moveLeft"; // a
        keyboard.keyMappings[39] = "moveRight"; // d
 
        keyboard.inputs = {
            moveForwards: false,
            moveBackwards: false,
            moveLeft: false,
            moveRight: false,
        };
 
        init();
 
        function setEventListeners() {
            const _self = keyboard;
 
            document.addEventListener("keydown", (event) => {
                event.preventDefault();
                const keyName = _self.keyMappings[event.which];
                if (keyName != undefined) {
                    _self.inputs[keyName] = true;
                }
            });
 
            document.addEventListener("keyup", (event) => {
                event.preventDefault();
                event.preventDefault();
                var keyName = _self.keyMappings[event.which];
                if (keyName != undefined) {
                    _self.inputs[keyName] = false;
                }
            }, true);
        }
 
        function init() {
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(
                50, window.innerWidth / window.innerHeight, 0.1, 500);
            camera.position.z = 10;
 
            const canvas = document.getElementById("renderCanvas");
            renderer = new THREE.WebGLRenderer({ canvas: canvas });
            renderer.setClearColor(new THREE.Color("rgb(50, 50, 50)"), 1);
            renderer.setSize(window.innerWidth, window.innerHeight);
 
            const geometry1 = new THREE.SphereGeometry(1, 32, 16);
            const material1 = new THREE.MeshPhongMaterial({
                color: 0x0000ff
            });
            target1 = new THREE.Mesh(geometry1, material1);
            target1.position.set(2, -2, 0);
            scene.add(target1);
 
            const geometry2 = new THREE.SphereGeometry(1, 32, 16);
            const material2 = new THREE.MeshPhongMaterial({
                color: 0xff0000
            });
            material2.transparent = true;
            material2.opacity = 0.2;
            target2 = new THREE.Mesh(geometry2, material2);
            scene.add(target2);
 
            orbitControls = new OrbitControls(camera, canvas);
            orbitControls.target = new THREE.Vector3(0, 0, 0);
 
            const lightColor = new THREE.Color("rgb(255, 255, 255)");
            const lightIntensity = 3;
            const light = new THREE.DirectionalLight(lightColor, lightIntensity);
            light.position.set(3, 5, 4);
            scene.add(light);
 
            const hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.1);
            hemiLight.position.set(0, 5, 0);
            scene.add(hemiLight);
 
            setEventListeners();
            render();
        }
 
        function diff(num1, num2) {
            if (num1 > num2) {
                return (num1 - num2);
            } else {
                return (num2 - num1);
            }
        }
 
        function dist(x1, y1, x2, y2) {
            var deltaX = diff(x1, x2);
            var deltaY = diff(y1, y2);
            var dist = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
            return (dist);
        }
 
        function resize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }
        window.onresize = resize;
 
        function render() {
 
            if (keyboard.inputs.moveForwards == true) {
                target1.position.y += target1Speed;
            }
            if (keyboard.inputs.moveBackwards == true) {
                target1.position.y -= target1Speed;
            }
            if (keyboard.inputs.moveLeft == true) {
                target1.position.x -= target1Speed;
            }
            if (keyboard.inputs.moveRight == true) {
                target1.position.x += target1Speed;
            }
 
            const x1 = target1.position.x;
            const y1 = target1.position.y;
            const x2 = target2.position.x;
            const y2 = target2.position.y;
            const d = dist(x1, y1, x2, y2);
 
            target2.material.opacity = 0.2;
            if (d < 2) {
                target2.material.opacity = 1;
            }
 
            orbitControls.update();
            renderer.render(scene, camera);
            requestAnimationFrame(render);
        }
    </script>
</body>
 
</html>
Миниатюры
1
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
26.05.2024, 20:18
Эту функцию можно сократить:

JavaScript
1
2
3
4
5
6
7
function diff(num1, num2) {
    if (num1 > num2) {
        return (num1 - num2);
    } else {
        return (num2 - num1);
    }
}
Используя Math.abs:

JavaScript
1
2
3
function diff(num1, num2) {
    return Math.abs(num1, num2);
}
Либо удалить её и написать:

JavaScript
1
2
3
4
5
6
function dist(x1, y1, x2, y2) {
    const deltaX = Math.abs(x1, x2);
    const deltaY = Math.abs(y1, y2);
    const dist = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
    return (dist);
}
1
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
28.05.2024, 10:55  [ТС]
Для одного игрока столкновение объектов на Phaser без мультиплеера.
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>Phaser 3 First Game</title>
</head>
 
<body>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/phaser/3.16.2/phaser.min.js'></script>
      <script>
const config = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
  physics: {
    default: 'arcade',
    arcade: {
      gravity: { y: 300 },
      debug: false } },
 
 
  scene: {
    preload: preload,
    create: create,
    update: update } };
 
 
 
let score = 0;
let scoreText;
 
let keyA;
let keyS;
let keyD;
let keyW;
 
const game = new Phaser.Game(config);
 
function preload() {
  this.load.image('sky', 'assets/sky.png');
  this.load.image('ground', 'assets/platform.png');
  this.load.image('star', 'assets/star.png');
  this.load.image('bomb', 'assets/bomb.png');
  this.load.spritesheet('dude',
  'assets/dude.png',
  { frameWidth: 32, frameHeight: 48 });
 
}
 
function create() {
  // Добавление фона
  this.add.image(0, 0, 'sky').setOrigin(0, 0);
 
  // Устанавливает текст для оценки. (должен быть после фона, чтобы его можно было увидеть)
  scoreText = this.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });
 
  // Добавить платформу.
  platforms = this.physics.add.staticGroup();
 
  platforms.create(400, 568, 'ground').setScale(2).refreshBody();
  platforms.create(600, 400, 'ground');
  platforms.create(50, 250, 'ground');
  platforms.create(750, 220, 'ground');
 
  // Добавьте игрока.
  player = this.physics.add.sprite(100, 450, 'dude');
  this.physics.add.collider(player, platforms);
 
  player.setBounce(0.2);
  // player.body.setGravityY(300)
  player.setCollideWorldBounds(true);
 
  this.anims.create({
    key: 'left',
    frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3 }),
    frameRate: 10,
    repeat: -1 });
 
 
  this.anims.create({
    key: 'turn',
    frames: [{ key: 'dude', frame: 4 }],
    frameRate: 20 });
 
 
  this.anims.create({
    key: 'right',
    frames: this.anims.generateFrameNumbers('dude', { start: 5, end: 8 }),
    frameRate: 10,
    repeat: -1 });
 
 
  // Создание экземпляра клавиатуры.
  cursors = this.input.keyboard.createCursorKeys();
 
  // Добавление пикапов.
  stars = this.physics.add.group({
    key: 'star',
    repeat: 11,
    setXY: { x: 12, y: 0, stepX: 70 } });
 
 
  this.physics.add.collider(stars, platforms);
  this.physics.add.overlap(player, stars, collectStar, null, this);
 
  stars.children.iterate(function (child) {
 
    child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
 
  });
  
  keyA = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
  keyS = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
  keyD = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
  keyW = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
 
  // Добавляет бомбы, которые сталкиваются с игроком и платформами.
  bombs = this.physics.add.group();
  this.physics.add.collider(bombs, platforms);
  this.physics.add.collider(player, bombs, hitBomb, null, this);
}
 
function update() {
  // Map keys to player sprite.
  
 // if(keyA.isDown) {
 //  console.log('A key pressed')
//} else if(keyS.isDown) {
 //  console.log('S key pressed')
//} else if(keyD.isDown) {
 //  console.log('D key pressed')
//} else if(keyW.isDown) {
//   console.log('W key pressed')
//}
  
  
   if (keyA.isDown) {
    player.setVelocityX(-160);
 
    player.anims.play('left', true);
  } 
  else
  if (keyD.isDown) {
    player.setVelocityX(160);
 
    player.anims.play('right', true);
  } 
  else
  {
    player.setVelocityX(0);
 
    player.anims.play('turn');
  }
 
  if (keyW.isDown && player.body.touching.down) {
    player.setVelocityY(-310);
  }
}
 
function collectStar(player, star) {
  // Уничтожает звезду. 
  star.disableBody(true, true);
  // Добавляет к счету за каждую собранную звезду.
  score += 10;
  scoreText.setText('Score: ' + score);
 
  if (stars.countActive(true) === 0) {
    stars.children.iterate(function (child) {
      child.enableBody(true, child.x, 0, true, true);
    });
 
    var x = player.x < 400 ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);
 
    var bomb = bombs.create(x, 16, 'bomb');
    bomb.setBounce(1);
    bomb.setCollideWorldBounds(true);
    bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);
 
  }
}
 
// Если в игрока попала бомба, остановите ее и сделайте ее красной.
function hitBomb(player, bomb) {
  this.physics.pause();
  player.setTint(0xff0000);
  player.anims.play('turn');
  gameOver = true;
}
</script>
 
  
</body>
 
</html>
Исходники:
Phaser3MovePlayer.zip
1
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
29.05.2024, 15:45  [ТС]
Сделала столкновение объектов окружностей, они движутся в случайном направлении и сталкиваются. Для этого создала отдельный файл Vector2.js, где происходят расчеты столкновения и отталкивания меньшего от большого объекта.

В тег textarea выводиться информация какой объект с кем столкнулся. Также добавила данные о кинетической энергии.
Вот код:
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>Столкновение объектов - окружностей</title>
</head>
 
<body>
<canvas id="canvas1" width="400" height="300"></canvas><br>
<textarea id="info" cols="35", rows="15"></textarea>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>
<script src='./easeljs.js'></script>
<script src='./Vector2.js'></script>
<script>
(function (window) {
var i = 0;
function drawObject(x,y,regX,regY,_type,param,canvas) {
   this.x1 = x;
   this.y1 = y;
   this.regX1 = regX;
   this.regY1 = regY;
   this._type = _type;
   this.param = param;
   this.canvas = canvas;
   this.cont = new createjs.Container();
   
    if (typeof _type === "undefined") {
       this._type = "";
     }
     
     if (typeof canvas === "undefined") {
       this._type = "";
       this.canvas = document.getElementById('canvas1');
     }
    
   if (typeof param === "undefined") {
      this.param = [];
      this.width = 0;
      this.height = 0;
      this.radius = 0;
      
   }
   
   if (typeof regX === "undefined") {
      this.regX1 = 0;
   }
   
   if (typeof regY === "undefined") {
      this.regY1 = 0;
   }
   if(_type == "animation" || _type == "image" || _type == "square")
   {
      this.width = param.width;
      this.height = param.height;
   }
   if(_type == "circle")
   {
     this.Velocity = new Vector2(4*(Math.random()-0.5),4*(Math.random()-0.5));
     this.stagewidth = this.canvas.width;
     this.stageheight = this.canvas.height;
     this.radius = param.radius;
     
   }
  
   if(_type == "text")
   {
     
     this.font = param.font;
     this.text = "";
   }
   console.log(this.canvas);
   this.Container_constructor(); 
    
    
   this.activate(this.x1,this.y1,this.regX1,this.regY1,this._type,this.param);
}
 
 
 
 
 
var p = createjs.extend(drawObject, createjs.Container);
 
 
p.activate = function (x,y,regX,regY,_type,param) {
    
      if (_type === "") {
       
          this.getLevel(x,y);
      }
      
}
 
 
 
p.getLevel = function (x,y) {
    
    this._ground = new createjs.Container(); 
    this.set({x:x, y:y});
    this.addChild(this._ground);
}
 
 
p.getDrawImg = function (URL_IMG) {
     
      var x = this.x1;
      var y = this.y1;
      var regX = this.regX1;
      var regY = this.regY1;
      var width = this.width;
      var height = this.height;
      this.tmpTile = new createjs.Bitmap(URL_IMG);
      this.set({x:x, y:y});
      
      
      this.regX = regX;
            this.regY = regY;
    
            this.tmpTile.width = width;
            this.tmpTile.height = height;
                 
            
            this.addChild(this.tmpTile);
        
}
 
p.getCircle = function () {
      
      var r = this.radius;
      this.tmpTile = new createjs.Shape();
            
            this.tmpTile.graphics.beginFill("black").beginFill("red").drawCircle(0,0,r);
      this.set({x:this.x1, y:this.y1});
      
            this.addChild(this.tmpTile);
        
}
 
p.getMassa = function() {
        var r = this.radius;
        return (4/3*Math.PI*r*r*r)/100; // ianna oa?a
}
 
p.distance2 = function(obj2) {
        var dx = this.x - obj2.x;
        var dy = this.y - obj2.y;
        return dx*dx + dy*dy;
}
 
p.CheckCollision = function(obj2) {
        var d2 = this.distance2(obj2); // eaaa?ao ?annoiyiey
        var dr = this.radius + obj2.radius; // noiia ?aaeonia - ieieiaeuii aicii?iia ?annoiyiea ia?ao iauaeoaie
        return (d2 < dr*dr); // anee ?annoiyiea ia?ao iauaeoaie iaiuoa noiiu eo ?aaeonia - noieeiiaaiea
    }
p.move = function() {
        this.x += this.Velocity.x;
        this.y += this.Velocity.y;
        
}
 
p._update = function()
{
  
  this.on("tick", this.tick);
  
}
p.tick = function()
{
  var new_x = this.x+this.Velocity.x;
    var new_y = this.y+this.Velocity.y;
    var r = this.radius;
        
 
    if (new_x-r<0 || new_x+r>this.stagewidth) this.Velocity.x=-this.Velocity.x;
    if (new_y-r<0 || new_y+r>this.stageheight) this.Velocity.y=-this.Velocity.y;
  this.move();
}
 
 
 
p.drawText = function (_text,_color) {
      
    
      this.tmpTile = new createjs.Text(_text, this.font, _color);
            this.set({x:this.x1, y:this.y1});
        
      
         this.addChild(this.tmpTile);
        
}
 
 
 
p.getText = function (_text) {
      
    
     this.tmpTile.text = _text;
      
}
 
window.drawObject = createjs.promote(drawObject, "Container");
}(window));
 
 
$(document).ready(function init() {
  
 
 
  var canvas = document.getElementById('canvas1'),
  stage = new createjs.Stage(canvas);
  var stagewidth = canvas.width;
  var stageheight = canvas.height;
 var items = new createjs.Container();
 var ball1 = new drawObject(70,38,0,0,"circle",{radius:30});
 ball1.getCircle();
 ball1._update();
 
 
 var ball2 = new drawObject(48.5,221.9,0,0,"circle",{radius:15},canvas);
 ball2.getCircle();
 ball2._update();
 
 var ball3 = new drawObject(286.35,124.9,0,0,"circle",{radius:16},canvas);
 ball3.getCircle();
 ball3._update();
 var ball4 = new drawObject(150.45,162.9,0,0,"circle",{radius:15},canvas);
 ball4.getCircle();
 ball4._update();
 
 var ball5 = new drawObject(358.35,47.85,0,0,"circle",{radius:20},canvas);
 ball5.getCircle();
 ball5._update();
  var ball6 = new drawObject(179,245.4,0,0,"circle",{radius:8.5},canvas);
 ball6.getCircle();
  ball6._update();
  
  var ball7 = new drawObject(206,81.5,0,0,"circle",{radius:7.5},canvas);
 ball7.getCircle();
 ball7._update(); 
 
   var ball8 = new drawObject(330.3,213.8,0,0,"circle",{radius:60},canvas);
 ball8.getCircle();
  ball8._update();
    var ball9 = new drawObject(235.35,240.85,0,0,"circle",{radius:20},canvas);
 ball9.getCircle();
  ball9._update();
 
  var infa = new drawObject(20,20,0,0,"text",{font:'bold 14px Arial'});
 infa.drawText("Кинетическая энергия всех шаров = ",'black');
 
 items.addChild(ball1,ball2,ball3,ball4,ball5,ball6,ball7,ball8,ball9);
 
 
   stage.addChild(items,infa);
   stage.update();
    
 
 
 document.getElementById("info").innerHTML = "";
 
  function onTick() {
    var cnt = 9; // количество шаров
   
     var obj1,obj2;
     
    for (var i=0; i<cnt; i++) {
            
            obj1=items.children[i];
        
            for (j=i+1; j<cnt; j++) {
               obj2=items.children[j];
                
                if (obj1.CheckCollision(obj2)) {
                  document.getElementById("info").innerHTML += "Boom "+i+" vs "+j+"\r\n"
                    resolve(obj1, obj2);
                }
            }
        } 
        
        var Ek=0;
        for (i=0; i<cnt; i++) {
            obj1=items.children[i];
            Ek += obj1.getMassa() / 2*obj1.Velocity.magnitude2();
        }
    infa.getText("Кинетическая энергия всех шаров = "+Ek);
    stage.update();
  }
  function resolve(ball1, ball2)
  {
    var b1Velocity = ball1.Velocity;
    var b2Velocity = ball2.Velocity;
    var b1Mass     = ball1.getMassa();
        var b2Mass     = ball2.getMassa();
        if (b1Mass<b2Mass) PullBalls(ball1, ball2);
        else PullBalls(ball2, ball1);
        
        var lineOfSight = new Vector2(ball1.x-ball2.x, ball1.y-ball2.y);
        var v1Prime = b1Velocity.vectorProjectionOnto(lineOfSight);
        var v2Prime = b2Velocity.vectorProjectionOnto(lineOfSight);
        
        var v1Prime2 = new Vector2();
        v1Prime2.copyVector(v2Prime);
        
        v1Prime2.mulScalar(2*b2Mass);
        v1Prime2.addVector(v1Prime.getMulScalar(b1Mass - b2Mass));
        v1Prime2.mulScalar(1.0/(b1Mass + b2Mass));
        
        
        var v2Prime2 = new Vector2();
        v2Prime2.copyVector(v1Prime);
        v2Prime2.mulScalar(2*b1Mass);
        v2Prime2.subVector(v2Prime.getMulScalar(b1Mass - b2Mass));
        v2Prime2.mulScalar(1.0/(b1Mass + b2Mass));
        
        v1Prime2.subVector(v1Prime);
        v2Prime2.subVector(v2Prime);
 
        b1Velocity.addVector(v1Prime2);
        b2Velocity.addVector(v2Prime2);
        
  }
  function PullBalls(ball1, ball2) {
        var v = new Vector2(ball1.x-ball2.x, ball1.y-ball2.y);
        var distance = v.magnitude();
        
        var min_distance = ball1.radius + ball2.radius;
        if (distance > min_distance) return; // не пересекаются
        v.mulScalar((0.1+min_distance-distance)/distance);
        ball1.x += v.x;
        ball1.y += v.y;
    }
  
  
  createjs.Ticker.setFPS(60);
  createjs.Ticker.addEventListener("tick", onTick);
 
});
 
    </script>
 
  
</body>
 
</html>
Vector.js
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Vector2 = function(x, y)
{
  this.x = 0;
  this.y = 0;
  if(x != null)
      this.x = x;
  if(y != null)
      this.y = y;
  
  this.copyVector = function( v ) {
            this.x = v.x;
            this.y = v.y;
    }
  this.setMembers = function ( x, y ) {
            this.x = x;
            this.y = y;
    }
    this.addVector = function( v ) {
            this.x += v.x;
            this.y += v.y;
    }
    this.subVector = function( v ) {
            this.x -= v.x;
            this.y -= v.y;
    }
    this.mulScalar = function( i ) {
            this.x *= i;
            this.y *= i;
    }
    this.getMulScalar = function( i ) {
            return new Vector2(this.x*i, this.y*i);
    }
    this.magnitude = function() {
            return Math.sqrt( this.x*this.x + this.y*this.y );
    }
    this.magnitude2 = function() {
            return this.x*this.x + this.y*this.y;
    }
    this.vectorProjectionOnto = function(v) {
            var res = v.getUnitVector();
            res.mulScalar(this.scalarProjectionOnto(v));
            return res;
    }
    this.getUnitVector = function() {
            var len = this.magnitude();
            var res = new Vector2(this.x,this.y);
            
            if (len) {
                res.x /= len;
                res.y /= len;
            }
            return res;
        }
        
    this.scalarProjectionOnto = function(v) {
            return (this.x*v.x + this.y*v.y)/v.magnitude();
    }
        
   
  
   
    
};
Исходники.
CollisionBall.zip
Позже переделаю и добавлю космос и метеориты которые при столкновении разраушаются.
0
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
29.05.2024, 18:18
Цитата Сообщение от Katerina1993 Посмотреть сообщение
Сделала столкновение объектов окружностей, они движутся в случайном направлении и сталкиваются.
Интересно было бы некоторые окружности заменить на квадраты и прямоугольники и посмотреть, как изменится картина. Позже попробую на Box2D. Ещё бы добаить статические прямоугольники повёрнутые под углом.

Интересный момент с кодировкой. Я открыл ваши исходники в редакторе Notepad++. Кодировка уставлена в Windows-1251. Кириллица в <title> отображается нормально:



Но если прокрутить вниз, то комментарии отображаются с проблемой:



Если запустить игру в браузере, то <title> и текст в браузере отображаются вопросами:



Миниатюры
0
9949 / 2950 / 497
Регистрация: 05.10.2013
Сообщений: 8,030
Записей в блоге: 242
29.05.2024, 18:42
Цитата Сообщение от Katerina1993 Посмотреть сообщение
Для столкновения лазера со щитом я использовала Math.sqrt и написала функцию dist. Чтобы проверить как она работает я сделала отдельный тестовый пример.
Где происходит столкновение двух окружностей. Вот исходники, может кому пригодиться.
CollisionElipse.zip
После тестирования столкновений я внедрила этот пример в проект.
Переписал пример на Qt C++ и шейдерный OpenGL. Столкновения определются так же, как и в исходном примере:

C++ (Qt)
1
2
3
4
5
6
    float dist(float x1, float y1, float x2, float y2)
    {
        float deltaX = qFabs(x1 - x2);
        float deltaY = qFabs(y1 - y2);
        return qSqrt(qPow(deltaX, 2) + qPow(deltaY, 2));
    }
Собрал в WebAssembly и отгрузил демку на бесплатный хостинг Netlify Управление мышкой. Нужно кликнуть и удерживать левую кнопку мыши, чтобы двигать синюю окружность.

Qt позволяет легко собирать OpenGL приложения для мобильных платформ (Android, iOS и Raspberry Pi). Работает даже на старом телефоне Redmi 4X с Android версии 7.1.2:



Можно собирать исполняемые файлы для Desktop (Windows, Linux и macOS). Весить приложение будет значительно меньше, чем если собирать его в EXE с помощью Electron. В играх может возникнуть ситуация, когда важна будет скорость выполнения кода, а C++ потенциально быстрее JavaScript. А с поиском ошибок неоднозначная ситуация - плюсы и минусы есть там и там.

Приложение запущенное на Windows 10:



Миниатюры


Исходники в одном файле main.cpp и файл проекта с расширением ".pro":

custom-collision-detection-disks-opengles2-qt6-cpp.pro

Code
1
2
3
4
5
6
7
8
QT += core gui openglwidgets
 
win32: LIBS += -lopengl32
 
CONFIG += c++17
 
SOURCES += \
    main.cpp
main.cpp

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
#include <QtMath>
#include <QtGui/QMatrix4x4>
#include <QtGui/QMouseEvent>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QSurfaceFormat>
#include <QtGui/QVector3D>
#include <QtGui/QVector4D>
#include <QtOpenGL/QOpenGLBuffer>
#include <QtOpenGL/QOpenGLShader>
#include <QtOpenGL/QOpenGLShaderProgram>
#include <QtOpenGL/QOpenGLWindow>
#include <QtWidgets/QApplication>
 
class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions
{
public:
    OpenGLWindow()
    {
        setTitle("OpenGL ES 2.0, Qt6, C++");
        resize(500, 500);
 
        QSurfaceFormat surfaceFormat;
        surfaceFormat.setDepthBufferSize(24);
        surfaceFormat.setSamples(4);
        setFormat(surfaceFormat);
    }
 
    void initializeGL() override
    {
        initializeOpenGLFunctions();
        glClearColor(0.04f, 0.62f, 0.48f, 1.f);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
        QString vertShaderSrc =
            "attribute vec2 aPosition;\n"
            "uniform mat4 uMvpMatrix;"
            "void main()\n"
            "{\n"
            "    gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);\n"
            "}\n";
 
        QString fragShaderSrc =
            "#ifdef GL_ES\n"
            "precision mediump float;\n"
            "#endif\n"
            "uniform vec4 uColor;\n"
            "void main()\n"
            "{\n"
            "    gl_FragColor = uColor;\n"
            "}\n";
 
        m_program.create();
        m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex, vertShaderSrc);
        m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment, fragShaderSrc);
        m_program.link();
        m_program.bind();
 
        float vertPositions[m_amountOfDiskVertices * 2 + 8]; // Disk + Square
        float radius = 0.5f;
        float angle = 0.f;
 
        int index = 0;
        // Disk center
        vertPositions[index++] = 0.f;
        vertPositions[index++] = 0.f;
 
               // Disk
        for (int i = 0; i < m_amountOfDiskVertices - 1; i++)
        {
            float radians = qDegreesToRadians(angle);
            float x = radius * qCos(radians);
            float y = radius * qSin(radians);
            vertPositions[index++] = x;
            vertPositions[index++] = y;
            angle += m_angleStep;
        }
        // Square
        vertPositions[index++] = -0.5f;
        vertPositions[index++] = -0.5f;
        vertPositions[index++] = 0.5f;
        vertPositions[index++] = -0.5f;
        vertPositions[index++] = -0.5f;
        vertPositions[index++] = 0.5f;
        vertPositions[index++] = 0.5f;
        vertPositions[index++] = 0.5f;
        m_vertPosBuffer.create();
        m_vertPosBuffer.bind();
        m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions));
        m_program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2);
        m_program.enableAttributeArray("aPosition");
 
        m_uColorLocation = m_program.uniformLocation("uColor");
        m_uMvpMatrixLocation = m_program.uniformLocation("uMvpMatrix");
        m_viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0));
    }
 
    void resizeGL(int w, int h) override
    {
        int deviceW = w * devicePixelRatio();
        int deviceH = h * devicePixelRatio();
        float deviceAspect = deviceH / (float) deviceW;
 
        if (deviceAspect > m_worldAspect)
        {
            m_viewportWidth = deviceW;
            m_viewportHeight = (int) deviceW * m_worldAspect;
            m_viewportX = 0;
            m_viewportY = (int) (deviceH - m_viewportHeight) / 2.f;
        }
        else
        {
            m_viewportWidth = (int) deviceH / m_worldAspect;
            m_viewportHeight = deviceH;
            m_viewportX = (int) (deviceW - m_viewportWidth) / 2.f;
            m_viewportY = 0;
        }
        m_projMatrix.setToIdentity();
        m_projMatrix.ortho(0.f, m_worldWidth, 0.f, m_worldHeight, 1.f, -1.f);
        m_projViewMatrix = m_projMatrix * m_viewMatrix;
    }
 
    void paintGL() override
    {
        glClear(GL_COLOR_BUFFER_BIT);
        glClearColor(0.2, 0.2, 0.2, 1);
        glClear(GL_COLOR_BUFFER_BIT);
        glViewport(m_viewportX, m_viewportY, m_viewportWidth, m_viewportHeight);
        glScissor(m_viewportX, m_viewportY, m_viewportWidth, m_viewportHeight);
        glClearColor(0.04, 0.62, 0.48, 1);
        glEnable(GL_SCISSOR_TEST);
        glClear(GL_COLOR_BUFFER_BIT);
        glDisable(GL_SCISSOR_TEST);
 
        m_disk2Color.setW(0.2f);
        if (dist(m_disk1PosX, m_disk1PosY, m_disk2PosX, m_disk2PosY) < 30.f)
            m_disk2Color.setW(1.f);
 
        // Disk
        drawDisk(m_disk2PosX, m_disk2PosY, 30.f, m_disk2Color);
        // Disk
        drawDisk(m_disk1PosX, m_disk1PosY, 30.f, QVector4D(0.f, 0.f, 0.5f, 1.f));
        // Left border
        drawRectangle(5.f, 50.f, 5.f, 85.f, 0.f, QVector4D(0.62f, 0.04f, 0.18f, 1.f));
        // Right border
        drawRectangle(195.f, 50.f, 5.f, 85.f, 0.f, QVector4D(0.62f, 0.04f, 0.18f, 1.f));
        // Top border
        drawRectangle(100.f, 95.f, 185.f, 5.f, 0.f, QVector4D(0.62f, 0.04f, 0.18f, 1.f));
        // Bottom border
        drawRectangle(100.f, 5.f, 185.f, 5.f, 0.f, QVector4D(0.62f, 0.04f, 0.18f, 1.f));
    }
 
    float dist(float x1, float y1, float x2, float y2)
    {
        float deltaX = qFabs(x1 - x2);
        float deltaY = qFabs(y1 - y2);
        return qSqrt(qPow(deltaX, 2) + qPow(deltaY, 2));
    }
 
    void drawDisk(float x, float y, float diameter, const QVector4D& color)
    {
        m_modelMatrix.setToIdentity();
        m_modelMatrix.translate(QVector3D(x, y, 0));
        m_modelMatrix.scale(QVector3D(diameter, diameter, 1));
        m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
        m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
        m_program.setUniformValue(m_uColorLocation, color);
        glDrawArrays(GL_TRIANGLE_FAN, 0, m_amountOfDiskVertices);
    }
 
    void drawRectangle(float x, float y, float w, float h,
        float angle, const QVector4D& color)
    {
        m_modelMatrix.setToIdentity();
        m_modelMatrix.translate(QVector3D(x, y, 0));
        m_modelMatrix.rotate(angle, QVector3D(0, 0, 1));
        m_modelMatrix.scale(QVector3D(w, h, 1));
        m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
        m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
        m_program.setUniformValue(m_uColorLocation, color);
        glDrawArrays(GL_TRIANGLE_STRIP, m_amountOfDiskVertices, 4);
    }
 
    void mousePressEvent(QMouseEvent *event) override
    {
        switch (event->button()) {
            case Qt::MouseButton::LeftButton:
            {
                m_mouseHolding = true;
                int x = event->pos().x() * devicePixelRatio();
                int y = (height() - event->pos().y() - 1) * devicePixelRatio();
                if ((m_viewportX <= x && x < (m_viewportX + m_viewportWidth)) &&
                    (m_viewportY <= y && y < (m_viewportY + m_viewportHeight)))
                {
                    float normalizedX = (x - m_viewportX) / (float) m_viewportWidth;
                    float normalizedY = (y - m_viewportY) / (float) m_viewportHeight;
                    m_disk1PosX = m_worldWidth * normalizedX;
                    m_disk1PosY = m_worldHeight * normalizedY;
                }
                update();
                break;
            }
            default:
                break;
        }
    }
 
    void mouseMoveEvent(QMouseEvent *event) override
    {
        if (!m_mouseHolding)
            return;
 
        int x = event->pos().x() * devicePixelRatio();
        int y = (height() - event->pos().y() - 1) * devicePixelRatio();
        if ((m_viewportX <= x && x < (m_viewportX + m_viewportWidth)) &&
            (m_viewportY <= y && y < (m_viewportY + m_viewportHeight)))
        {
            float normalizedX = (x - m_viewportX) / (float) m_viewportWidth;
            float normalizedY = (y - m_viewportY) / (float) m_viewportHeight;
            m_disk1PosX = m_worldWidth * normalizedX;
            m_disk1PosY = m_worldHeight * normalizedY;
        }
        update();
    }
 
    void mouseReleaseEvent(QMouseEvent *event) override
    {
        switch (event->button()) {
            case Qt::MouseButton::LeftButton:
            {
                m_mouseHolding = false;
                break;
            }
            default:
                break;
        }
    }
 
private:
    QOpenGLBuffer m_vertPosBuffer;
    QOpenGLShaderProgram m_program;
    int m_uColorLocation;
    int m_uMvpMatrixLocation;
    QMatrix4x4 m_mvpMatrix;
    QMatrix4x4 m_projMatrix;
    QMatrix4x4 m_viewMatrix;
    QMatrix4x4 m_projViewMatrix;
    QMatrix4x4 m_modelMatrix;
    const float m_worldWidth = 200.f;
    const float m_worldHeight = 100.f;
    float m_worldAspect = m_worldHeight / m_worldWidth;
    int m_viewportX;
    int m_viewportY;
    int m_viewportWidth;
    int m_viewportHeight;
    float m_angleStep = 10.f;
    int m_amountOfDiskVertices = 360.f / m_angleStep + 2;
    bool m_mouseHolding = false;
    float m_disk1PosX = 150.f;
    float m_disk1PosY = 50.f;
    QVector4D m_disk2Color = QVector4D(0.8f, 0.f, 0.f, 0.2f);
    float m_disk2PosX = 70.f;
    float m_disk2PosY = 50.f;
};
 
int main(int argc, char *argv[])
{
    QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
    QApplication app(argc, argv);
    OpenGLWindow w;
    w.show();
    return app.exec();
}
0
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
04.06.2024, 20:28  [ТС]
Сделала столкновение метеоритов. Тоже самое, что и столкновение окружностей, только с графикой. Отключить и включить отображение окружностей можно нажав галочку «Show object collision».

Код:
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>Метеориты - столкновение окружностей</title>
</head>
 
<body>
<canvas id="canvas1" width="400" height="300"></canvas><br>
 
<div>
    <input type="checkbox" id="collisionCheckBox" checked>
    <span style="margin-left: 5px;">Show object collision</span>
</div>
<textarea id="info" cols="35", rows="15"></textarea>
 
 
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>
<script src='./easeljs.js'></script>
<script src='./Vector2.js'></script>
<script>
(function (window) {
var i = 0;
function drawObject(x,y,regX,regY,_type,param,canvas) {
   this.x1 = x;
   this.y1 = y;
   this.regX1 = regX;
   this.regY1 = regY;
   this._type = _type;
   this.param = param;
   this.canvas = canvas;
   this.cont = new createjs.Container();
   
    if (typeof _type === "undefined") {
       this._type = "";
     }
     
     if (typeof canvas === "undefined") {
       this._type = "";
       this.canvas = document.getElementById('canvas1');
     }
    
   if (typeof param === "undefined") {
      this.param = [];
      this.width1 = 0;
      this.height1 = 0;
      this.radius = 0;
      
   }
   
   if (typeof regX === "undefined") {
      this.regX1 = 0;
   }
   
   if (typeof regY === "undefined") {
      this.regY1 = 0;
   }
   if(_type == "animation" || _type == "image" || _type == "square")
   {
      this.width1 = param.width;
      this.height1 = param.height;
      this.Velocity = new Vector2(4*(Math.random()-0.5),4*(Math.random()-0.5));
      this.stagewidth = this.canvas.width;
      this.stageheight = this.canvas.height;
   }
   if(_type == "circle")
   {
     this.radius = param.radius;
     
   }
  
   if(_type == "text")
   {
     
     this.font = param.font;
     this.text = "";
   }
   
   this.Container_constructor(); 
    
    
   this.activate(this.x1,this.y1,this.regX1,this.regY1,this._type,this.param);
}
 
 
 
 
 
var p = createjs.extend(drawObject, createjs.Container);
 
 
p.activate = function (x,y,regX,regY,_type,param) {
    
      if (_type === "") {
       
          this.getLevel(x,y);
      }
      
}
 
 
 
p.getLevel = function (x,y) {
    
    this._ground = new createjs.Container(); 
    this.set({x:x, y:y});
    this.addChild(this._ground);
}
 
p.getDraw = function (_stroke,_fill) {
 
   var x = this.x1;
   var y = this.y1
   var width = this.width1;
   var height = this.height1;
   this.tmpTile = new createjs.Shape();
   this.set({x:x, y:y});
   
   this._stroke = _stroke;
   this._fill = _fill;
    
   this.addChild(this.tmpTile);
   
}
 
p._setBounds = function (_width,_height) {
  this.tmpTile.color = this.tmpTile.graphics.s(this._stroke).command;
  this.tmpTile.graphics.f(this._fill).dr(0,0,this.width1,this.height1);
}
 
 
p.getDrawImg = function (URL_IMG) {
     
      var x = this.x1;
      var y = this.y1;
      var regX = this.regX1;
      var regY = this.regY1;
      var width = this.width;
      var height = this.height;
      this.tmpTile = new createjs.Bitmap(URL_IMG);
      this.set({x:x, y:y});
      
      
      this.regX = regX;
            this.regY = regY;
    
            this.tmpTile.width = width;
            this.tmpTile.height = height;
                 
            
            this.addChild(this.tmpTile);
        
}
 
p.getAnim = function (URL_IMG,frame) {
 
       
       this.tmpTile = new createjs.Container();
           
      
       var arr1 = [];
       var arr2 = {};
       var width1 = this.width1;
       var height1 = this.height1;
       var regX = this.regX1;
       var regY = this.regY1;
       var x = this.x1;
       var y = this.y1;
       for(var i=0; i < frame; i++)
       {
           arr1[i] = [width1*i, 0, width1,height1];
           
       }
       for(var j=1; j < frame+1; j++)
       {
          arr2[j] = [j-1];
       }
       var _tmpTile = {
          images: [URL_IMG],
          "frames": arr1,
 
            "animations": arr2 
        }; 
        var p1 = new createjs.SpriteSheet(_tmpTile); 
                var spr1 = new createjs.Sprite(p1);
                
                 
                
                this.set({x:x, y:y});
                 
                this.regX = regX;
                this.regY = regY;
                
                this.tmpTile.width1 = width1;
                this.tmpTile.height1 = height1;
                this.g = new createjs.Shape();
        
                this.tmpTile.addChild(spr1,this.g);
                this.addChild(this.tmpTile);
}
 
 
p.getCircle = function () {
      
      var r = this.radius;
      this.tmpTile = new createjs.Shape();
            
            this.tmpTile.graphics.beginFill("black").beginFill("red").drawCircle(0,0,r);
      this.set({x:this.x1, y:this.y1});
      
      
            this.addChild(this.tmpTile);
        
}
p.setVisible = function(_visible)
{
  this.g.visible = _visible;
}
p.getMassa = function() {
        var r = this.radius;
        return (4/3*Math.PI*r*r*r)/100; // ianna oa?a
}
 
p.distance2 = function(obj2) {
        var dx = this.x - obj2.x;
        var dy = this.y - obj2.y;
        return dx*dx + dy*dy;
}
 
p.CheckCollision = function(obj2) {
        var d2 = this.distance2(obj2); 
        var dr = this.radius + obj2.radius; 
        return (d2 < dr*dr); 
    }
p.move = function() {
        this.x += this.Velocity.x;
        this.y += this.Velocity.y;
}
 
p._update = function()
{
  
  this.on("tick", this.tick);
  
}
p.tick = function()
{
  var new_x = this.x+this.Velocity.x;
    var new_y = this.y+this.Velocity.y;
    var r = this.radius;
        
 
    if (new_x-r<0 || new_x+r>this.stagewidth) this.Velocity.x=-this.Velocity.x;
    if (new_y-r<0 || new_y+r>this.stageheight) this.Velocity.y=-this.Velocity.y;
  this.move();
}
 
 
 
p.drawText = function (_text,_color) {
      
    
      this.tmpTile = new createjs.Text(_text, this.font, _color);
            this.set({x:this.x1, y:this.y1});
        
      
         this.addChild(this.tmpTile);
        
}
 
 
 
p.getText = function (_text) {
      
    
     this.tmpTile.text = _text;
      
}
 
p._gotoAndPlay = function(num)
{
  this.tmpTile.children[0].gotoAndPlay(num);
 
}
p._gotoAndStop = function(num)
{
 var hp1 = 0;
 var obj1 = this.tmpTile.children[0];
 if(num==1)
 {
  this.width = 27;
  this.height = 29;
  this.regX1 = -27;
  this.regY1 = -29;
 }
 if(num==2)
 {
  this.width = 37;
  this.height = 48;
  this.regX1 = -32;
  this.regY1 = -29;
 
 }
 if(num==3)
 {
  this.width = 27;
  this.height = 35;
  this.regX1 = -27;
  this.regY1 = -30;
 }
 if(num==4)
 {
  this.width = 25;
  this.height = 35;
  this.regX1 = -27;
  this.regY1 = -30;
 }
 if(num==5)
 {
  this.width = 22;
  this.height = 30;
  this.regX1 = -27;
  this.regY1 = -30;
 }
 if(num==6)
 {
  this.width = 23;
  this.height = 25;
  this.regX1 = -27;
  this.regY1 = -30;
 }
 if(num==7)
 {
  this.width = 17;
  this.height = 25;
  this.regX1 = -27;
  this.regY1 = -30;
 }
 if(num==8)
 {
  this.width = 30;
  this.height = 28;
  this.regX1 = -30;
  this.regY1 = -28;
  
 }
  if(num==9)
 {
  this.width = 30;
  this.height = 30;
  this.regX1 = -30;
  this.regY1 = -30;
 }
  this.radius = Math.floor((this.width + this.height - 4) / 4);
  
  this.mHP = hp1 = this.radius * 3;
  this.tkHP = hp1;
 
  
  
  this.width = Math.floor(this.tkHP / this.mHP * 2*this.radius) + 1;
  this.height = 5;
  this.g.graphics.beginFill("black").beginFill("blue").drawCircle(0,0,this.radius);
  obj1.regX = -this.regX1;
  obj1.regY = -this.regX1;
  
  this.g.visible = this.visibleCollision;
  
  obj1.gotoAndStop(num-1);
 
}
 
 
window.drawObject = createjs.promote(drawObject, "Container");
}(window));
 
 
$(document).ready(function init() {
  var _visible = true;
  var canvas = document.getElementById('canvas1');
  var collisionCheckBox = document.getElementById('collisionCheckBox');
  stage = new createjs.Stage(canvas);
  var stagewidth = canvas.width;
  var stageheight = canvas.height;
 var items = new createjs.Container();
 
 
function createMeteorit(x,y,num,_canvas)
{
 
 var meteorit = new createjs.Container();
 
 var meteor1 = new drawObject(x,y,0,0,"animation",{width:60,height:60},_canvas);
 meteor1.getAnim("assets/meteorit.png",9);
 meteor1.visibleCollision = _visible;
 meteor1._gotoAndStop(num);
 
 meteor1._update();
 box1 = new drawObject(0,0,0,0,"square",{width:meteor1.width,height:5},_canvas);
 box1.getDraw("black","red");
 
 box1.x = meteor1.x+(-meteor1.radius);
 box1.y = meteor1.y+(-meteor1.radius - box1.height1);
 meteorit.addChild(meteor1,box1);
 return meteorit;
}
 
 
 var meteorit1 = createMeteorit(50,50,1,canvas);
 
 var meteorit2 = createMeteorit(100,100,2,canvas);
 
 var meteorit3 = createMeteorit(150,100,3,canvas);
 
 var meteorit4 = createMeteorit(200,100,4,canvas);
 
 var meteorit5 = createMeteorit(200,180,5,canvas);
 
 var meteorit6 = createMeteorit(150,180,6,canvas);
 
 var meteorit7 = createMeteorit(100,180,7,canvas);
 
 var meteorit8 = createMeteorit(44,180,8,canvas);
 
 var meteorit9 = createMeteorit(44,220,9,canvas);
 
 items.addChild(meteorit1,meteorit2,meteorit3,meteorit4,meteorit5,meteorit6,meteorit7,meteorit8,meteorit9);
 
  var infa = new drawObject(20,20,0,0,"text",{font:'bold 14px Arial'});
  infa.drawText("Кинетическая энергия всех шаров = ",'black');
  collisionCheckBox.onchange = () => {
    
      _visible = collisionCheckBox.checked;
   
  };
 
 
   stage.addChild(items,infa);
   stage.update();
    
 
 
 document.getElementById("info").innerHTML = "";
 
  function onTick() {
   
     var obj1,obj2;
     
     for(var i = 0; i < items.children.length; i++)
      {
        var width = items.children[i].children[0].width;
        
        
        var box1 = items.children[i].children[1];
        var meteor1 = items.children[i].children[0];
        
         meteor1.setVisible(_visible);
        
         box1._setBounds(meteor1.width,5);
         box1.x = meteor1.x+(-meteor1.radius);
         box1.y = meteor1.y+(-meteor1.radius - box1.height1);
      }
    
    
    for(var ii = 0; ii < items.children.length; ii++)
    {
      obj1=items.children[ii].children[0];
      for (jj=ii+1; jj<items.children.length; jj++) {
          obj2=items.children[jj].children[0];
          if (obj1.CheckCollision(obj2)) {
              document.getElementById("info").innerHTML += "Boom "+ii+" vs "+jj+"\r\n"
              resolve(obj1, obj2);
          }
      }
      
      
    }
 
        
        
        
         
        
        var Ek=0;
        for (i=0; i<items.children.length; i++) {
            obj1=items.children[i].children[0];
            Ek += obj1.getMassa() / 2*obj1.Velocity.magnitude2();
        }
    infa.getText("Кинетическая энергия всех шаров = "+Ek);
    stage.update();
  }
  function resolve(ball1, ball2)
  {
    var b1Velocity = ball1.Velocity;
    var b2Velocity = ball2.Velocity;
    var b1Mass     = ball1.getMassa();
        var b2Mass     = ball2.getMassa();
        if (b1Mass<b2Mass) PullBalls(ball1, ball2);
        else PullBalls(ball2, ball1);
        
        var lineOfSight = new Vector2(ball1.x-ball2.x, ball1.y-ball2.y);
        var v1Prime = b1Velocity.vectorProjectionOnto(lineOfSight);
        var v2Prime = b2Velocity.vectorProjectionOnto(lineOfSight);
        
        var v1Prime2 = new Vector2();
        v1Prime2.copyVector(v2Prime);
        
        v1Prime2.mulScalar(2*b2Mass);
        v1Prime2.addVector(v1Prime.getMulScalar(b1Mass - b2Mass));
        v1Prime2.mulScalar(1.0/(b1Mass + b2Mass));
        
        
        var v2Prime2 = new Vector2();
        v2Prime2.copyVector(v1Prime);
        v2Prime2.mulScalar(2*b1Mass);
        v2Prime2.subVector(v2Prime.getMulScalar(b1Mass - b2Mass));
        v2Prime2.mulScalar(1.0/(b1Mass + b2Mass));
        
        v1Prime2.subVector(v1Prime);
        v2Prime2.subVector(v2Prime);
 
        b1Velocity.addVector(v1Prime2);
        b2Velocity.addVector(v2Prime2);
        
  }
  function PullBalls(ball1, ball2) {
        var v = new Vector2(ball1.x-ball2.x, ball1.y-ball2.y);
        var distance = v.magnitude();
        
        var min_distance = ball1.radius + ball2.radius;
        if (distance > min_distance) return; 
        v.mulScalar((0.1+min_distance-distance)/distance);
        ball1.x += v.x;
        ball1.y += v.y;
    }
  
  
  createjs.Ticker.setFPS(60);
  createjs.Ticker.addEventListener("tick", onTick);
 
});
 
    </script>
 
  
</body>
 
</html>
Исходники:
CollisionMeteorit.zip

Красные полоски сверху это здоровье. Код я буду дорабатывать, и при столкновении метеориты будут получать урон.
0
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
04.06.2024, 20:32  [ТС]
Позже сделаю карту где будут летать астероиды и сталкиваться.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
04.06.2024, 20:32

Столкновение объектов на странице
Всем привет! Предположим у меня есть два шарика, один статичный, просто стоит в определенном месте, а другой бегает по странице от...

JavaScript: столкновение объектов
Прошу спецов по Java подсказать или помочь доработать скрипт Зинковского (написан на Java и VBScript). Описание: игра-стрелялка,...

Как сделать столкновение объектов?
Как проверять, столкнулся ли один шар с другим? Первый шар двигается нажатием клавиши, а остальные находятся на рандомных позициях, как...

Как сделать, чтобы столкновение объектов было абсолютно неупругим
Нашел пример попиксельного столкновения. Работает прекрасно, но что делать в момент столкновения, если нужно, чтоб оно было абсолютно...

Столкновение объектов. Как правильно реализовать?
Здравствуйте! Пишу игру в танчики. Borland C++ 3.1. Сейчас реализовал работу с клавиатурой, ознакомиться можно здесь :...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
сукцессия 14. Обновленная схема модели
anaschu 28.06.2026
ГЛОБАЛЬНАЯ ОПИСАТЕЛЬНАЯ СПЕЦИФИКАЦИЯ ЭКОСИСТЕМНОЙ МОДЕЛИ «SOIL CHEMISTRY & MYCORRHIZA 2. 0» https:/ / ibb. co/ NnkGpfMd Представленная интегрированная схема описывает непрерывную нелинейную. . .
сукцессия 13. Питон модель трехзонного мицелия, пока что в основном арбускулярного
anaschu 28.06.2026
## Разработка агентной модели микоризной сукцессии: от выявления артефактов к созданию комплексной системы ### Аннотация Представлено исследование по разработке агентной модели микоризной. . .
сукцессия 12. краткий список проверок модели перед запуском.
anaschu 27.06.2026
Скрытые отказы в моделях систем динамики (SD-models) экологических систем: два случая из практики Контекст Разбирался прототип модели систем динамики (SD-модели) микоризной сукцессии: пять. . .
Сукцессия 11. Проверка орудий перед войной: разработка через тестирование
anaschu 27.06.2026
Как не дать модели соврать самой себе: проверки для симуляции микоризной сукцессии Введение Когда вы строите математическую модель живой системы — грибов, растений, почвы — главная опасность. . .
10 сукцессия. Питон код войны грибов и растений
anaschu 27.06.2026
import numpy as np class PlantAgent: def __init__(self, name, strategy, initial_biomass): self. name = name self. strategy = strategy # "greedy" (широколиственные) или. . .
сукцессия 9. Математика подлости: как растения предали грибных друзей
anaschu 27.06.2026
Статья 2. Глобальная фосфорная война: эволюционно-экономические механизмы распределения биомов Земли Введение: Экологический рынок как игра с нулевой суммой Традиционная экология долгое время. . .
сукцессия 8. Как я спорил с ИИ, которые - агенты растений и ненавистники грибов!
anaschu 27.06.2026
Статья 1. Хроники грибного восстания: как Сократов диалог разрушил академические догмы ИИ Введение: Синдром «цифрового учебника» Современные большие языковые модели (LLM) обладают колоссальным. . .
Главный вопрос моделирования сукцессии
anaschu 27.06.2026
главный вопрос. Если эктомикориза лучше добывает недоступный фосфор. И ее масса максимальна из всех. А широколиственный лес тоже имеет самую крутую биомассу. То почему не возникло их симбиоза? Это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru