MegaBall2D — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
(→Описание) |
|||
(не показано 13 промежуточных версий 4 участников) | |||
Строка 1: | Строка 1: | ||
+ | |||
+ | |||
== Описание == | == Описание == | ||
Игра, где нужно попасть левым мячиком в правый. Присутствуют отскоки от стенок и гравитация. Радиус мячиков уменьшается с каждым уровнем. Если левый мячик уже никак не достигнет правого, то игра начинается заново. | Игра, где нужно попасть левым мячиком в правый. Присутствуют отскоки от стенок и гравитация. Радиус мячиков уменьшается с каждым уровнем. Если левый мячик уже никак не достигнет правого, то игра начинается заново. | ||
+ | |||
+ | Исполнитель: [http://tm.spbstu.ru/%D0%93%D1%80%D0%B5%D1%88%D0%BD%D0%B8%D0%BA%D0%BE%D0%B2_%D0%9F%D0%B0%D0%B2%D0%B5%D0%BB Грешников П.С.] | ||
+ | |||
+ | Группа 13632/1 Кафедра Теоретической механики. | ||
+ | |||
+ | Файл: [[http://tm.spbstu.ru/htmlets/Greshnikov%20PS/KR_JS.docx]] | ||
+ | |||
== Математическая модель == | == Математическая модель == | ||
+ | |||
Рассматриваем левый мячик как тело, брошенное под углом к горизонту. | Рассматриваем левый мячик как тело, брошенное под углом к горизонту. | ||
− | {{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/ | + | |
+ | == Визуализация == | ||
+ | |||
+ | {{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/Greshnikov%20PS/BB.html |width=1050 |height=600 |border=1 }} | ||
+ | |||
+ | == Код программы == | ||
+ | <div class="mw-collapsible mw-collapsed"> | ||
+ | <syntaxhighlight lang=javascript> | ||
+ | window.addEventListener("load",main,false); | ||
+ | function main(){ | ||
+ | var ctx = example_canvas.getContext("2d"); | ||
+ | var h=example_canvas.height; | ||
+ | var w=example_canvas.width; | ||
+ | var lvl=1; | ||
+ | var r=40*10/(10+lvl); | ||
+ | var dt=0.05; | ||
+ | var fps=100; | ||
+ | var flag=false; | ||
+ | var x=250; | ||
+ | var y=h/2; | ||
+ | var x0=0; | ||
+ | var y0=0; | ||
+ | var x_k=250; | ||
+ | var y_k=800; | ||
+ | var vx=0; | ||
+ | var vy=0; | ||
+ | var padding ={x:0, y:0}; | ||
+ | var defaultColor="black"; | ||
+ | var TouchColor="red"; | ||
+ | var XSL; | ||
+ | var YSL; | ||
+ | var start=false; | ||
+ | var imp=0; | ||
+ | setInterval(control,1000/fps); | ||
+ | function get_mouse_coords(e){ | ||
+ | var m={}; // объявление пустого объекта | ||
+ | var rect = example_canvas.getBoundingClientRect(); | ||
+ | m.x=e.clientX-rect.left; | ||
+ | m.y=e.clientY-rect.top; | ||
+ | return m; | ||
+ | } | ||
+ | example_canvas.onmousedown=function(e){ | ||
+ | m=get_mouse_coords(e); | ||
+ | var dx=m.x-x; | ||
+ | var dy=m.y-y; | ||
+ | padding.x=dx; | ||
+ | padding.y=dy; | ||
+ | if (Math.sqrt(dx*dx+dy*dy)<r) { | ||
+ | x0=m.x; | ||
+ | y0=m.y; | ||
+ | flag = true; | ||
+ | ctx.fillStyle=TouchColor; | ||
+ | draw(); | ||
+ | } | ||
+ | } | ||
+ | star(); | ||
+ | example_canvas.onmouseup=function(e){ | ||
+ | flag = false; | ||
+ | ctx.fillStyle=defaultColor; | ||
+ | draw(); | ||
+ | m=get_mouse_coords(e); | ||
+ | var dx=m.x-x; | ||
+ | var dy=m.y-y; | ||
+ | padding.x=dx; | ||
+ | padding.y=dy; | ||
+ | if (Math.sqrt(dx*dx+dy*dy)<r) { | ||
+ | x_k=m.x; | ||
+ | y_k=m.y; | ||
+ | speed(); | ||
+ | start=true; | ||
+ | } | ||
+ | } | ||
+ | example_canvas.onmousemove = function(e){ | ||
+ | if (flag) { | ||
+ | m=get_mouse_coords(e); | ||
+ | x=m.x-padding.x; | ||
+ | y=m.y-padding.y; | ||
+ | draw(); | ||
+ | ctx.beginPath(); | ||
+ | ctx.moveTo(Math.round(x),Math.round(y)); | ||
+ | ctx.lineTo(Math.round(x0),Math.round(y0)); | ||
+ | ctx.stroke(); | ||
+ | } | ||
+ | } | ||
+ | function phys(){ | ||
+ | if (vy*vy<(y-YSL-2*r)) console.log('imp'); | ||
+ | vy+=100*dt; | ||
+ | x=x+vx*dt; | ||
+ | y=y+vy*dt+100*dt*dt/2; | ||
+ | if(x>=w-(r)) { | ||
+ | vx=(-0.9)*Math.abs(vx); | ||
+ | } | ||
+ | else | ||
+ | if(x<=(r)) | ||
+ | vx=0.9*Math.abs(vx); | ||
+ | if(y>=h-(r)){ | ||
+ | vy=-0.9*Math.abs(vy); | ||
+ | if (Math.abs(vy)<10){ | ||
+ | vy=-150*dt; | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | if(y<=(r)) | ||
+ | vy=0.9*Math.abs(vy); | ||
+ | |||
+ | if ((x >w/2-5-r)&&(x<w/2)&&(y>h*1/3-r)) { | ||
+ | vx=-0.9*Math.abs(vx); | ||
+ | } | ||
+ | if ((x>w/2)&&(x<w/2+5+r)&&(y>h*1/3-r)){ | ||
+ | vx=0.9*Math.abs(vx); | ||
+ | } | ||
+ | if ((x>w/2-5)&&(x<w/2+5)&&(y<h/3-r+5)&&(y>h/3-r)){ | ||
+ | vy=-1000*Math.abs(vx); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function speed(){ | ||
+ | vx=-(x_k-x0)*2; | ||
+ | vy=-(y_k-y0)*2; | ||
+ | } | ||
+ | |||
+ | function draw() { | ||
+ | ctx.clearRect(0,0,w,h); | ||
+ | ctx.beginPath(); | ||
+ | ctx.arc(x,y,r,0,2*Math.PI); | ||
+ | ctx.arc(XSL,YSL,r,0,2*Math.PI); | ||
+ | ctx.moveTo(Math.round(x0),Math.round(y0)); | ||
+ | ctx.lineTo(x,y); | ||
+ | ctx.font = 'bold 30px sans-serif'; | ||
+ | ctx.strokeText("CURRENT LEVEL:", 600, 100); | ||
+ | ctx.strokeText(lvl, 900, 100); | ||
+ | |||
+ | |||
+ | ctx.fill(); | ||
+ | ctx.beginPath(); | ||
+ | ctx.moveTo(w/2-5,h); | ||
+ | ctx.lineTo(w/2-5,h/3); | ||
+ | ctx.moveTo(w/2+5,h/3); | ||
+ | ctx.lineTo(w/2+5,h); | ||
+ | ctx.moveTo(w/2+5,h/3); | ||
+ | ctx.lineTo(w/2-5,h/3); | ||
+ | ctx.stroke(); | ||
+ | } | ||
+ | |||
+ | |||
+ | draw(); | ||
+ | |||
+ | function control() { | ||
+ | if (start) | ||
+ | phys(); | ||
+ | draw(); | ||
+ | confront(); | ||
+ | imposible(); | ||
+ | } | ||
+ | |||
+ | function star(){ | ||
+ | XSL=Math.random()*(500-2*(r))+w/2+r; | ||
+ | YSL=Math.random()*(h-2*(r))+r; | ||
+ | } | ||
+ | |||
+ | function confront(){ | ||
+ | if (((x-XSL)*(x-XSL)+(y-YSL)*(y-YSL)<=4*(r)*(r))&&(start)){ | ||
+ | levelup(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function levelup(){ | ||
+ | x=250; | ||
+ | y=h/2; | ||
+ | vx=0; | ||
+ | vy=0; | ||
+ | lvl++; | ||
+ | r=40*10/(10+lvl); | ||
+ | star(); | ||
+ | start=false; | ||
+ | } | ||
+ | |||
+ | function restart(){ | ||
+ | x=250; | ||
+ | y=h/2; | ||
+ | vx=0; | ||
+ | vy=0; | ||
+ | lvl=1; | ||
+ | r=40*10/(10+lvl); | ||
+ | star(); | ||
+ | start=false; | ||
+ | } | ||
+ | |||
+ | function imposible() { | ||
+ | if ((start)&&((vy*vy<(y-YSL-2*r))||((x<w/2)&&(vy*vy<(2*y/3+r))))) { | ||
+ | imp++; | ||
+ | } | ||
+ | if (imp>40) { | ||
+ | imp=0; | ||
+ | restart(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | <div> |
Текущая версия на 15:18, 19 июня 2019
Описание[править]
Игра, где нужно попасть левым мячиком в правый. Присутствуют отскоки от стенок и гравитация. Радиус мячиков уменьшается с каждым уровнем. Если левый мячик уже никак не достигнет правого, то игра начинается заново.
Исполнитель: Грешников П.С.
Группа 13632/1 Кафедра Теоретической механики.
Файл: [[1]]
Математическая модель[править]
Рассматриваем левый мячик как тело, брошенное под углом к горизонту.
Визуализация[править]
Код программы[править]
window.addEventListener("load",main,false);
function main(){
var ctx = example_canvas.getContext("2d");
var h=example_canvas.height;
var w=example_canvas.width;
var lvl=1;
var r=40*10/(10+lvl);
var dt=0.05;
var fps=100;
var flag=false;
var x=250;
var y=h/2;
var x0=0;
var y0=0;
var x_k=250;
var y_k=800;
var vx=0;
var vy=0;
var padding ={x:0, y:0};
var defaultColor="black";
var TouchColor="red";
var XSL;
var YSL;
var start=false;
var imp=0;
setInterval(control,1000/fps);
function get_mouse_coords(e){
var m={}; // объявление пустого объекта
var rect = example_canvas.getBoundingClientRect();
m.x=e.clientX-rect.left;
m.y=e.clientY-rect.top;
return m;
}
example_canvas.onmousedown=function(e){
m=get_mouse_coords(e);
var dx=m.x-x;
var dy=m.y-y;
padding.x=dx;
padding.y=dy;
if (Math.sqrt(dx*dx+dy*dy)<r) {
x0=m.x;
y0=m.y;
flag = true;
ctx.fillStyle=TouchColor;
draw();
}
}
star();
example_canvas.onmouseup=function(e){
flag = false;
ctx.fillStyle=defaultColor;
draw();
m=get_mouse_coords(e);
var dx=m.x-x;
var dy=m.y-y;
padding.x=dx;
padding.y=dy;
if (Math.sqrt(dx*dx+dy*dy)<r) {
x_k=m.x;
y_k=m.y;
speed();
start=true;
}
}
example_canvas.onmousemove = function(e){
if (flag) {
m=get_mouse_coords(e);
x=m.x-padding.x;
y=m.y-padding.y;
draw();
ctx.beginPath();
ctx.moveTo(Math.round(x),Math.round(y));
ctx.lineTo(Math.round(x0),Math.round(y0));
ctx.stroke();
}
}
function phys(){
if (vy*vy<(y-YSL-2*r)) console.log('imp');
vy+=100*dt;
x=x+vx*dt;
y=y+vy*dt+100*dt*dt/2;
if(x>=w-(r)) {
vx=(-0.9)*Math.abs(vx);
}
else
if(x<=(r))
vx=0.9*Math.abs(vx);
if(y>=h-(r)){
vy=-0.9*Math.abs(vy);
if (Math.abs(vy)<10){
vy=-150*dt;
}
}
else
if(y<=(r))
vy=0.9*Math.abs(vy);
if ((x >w/2-5-r)&&(x<w/2)&&(y>h*1/3-r)) {
vx=-0.9*Math.abs(vx);
}
if ((x>w/2)&&(x<w/2+5+r)&&(y>h*1/3-r)){
vx=0.9*Math.abs(vx);
}
if ((x>w/2-5)&&(x<w/2+5)&&(y<h/3-r+5)&&(y>h/3-r)){
vy=-1000*Math.abs(vx);
}
}
function speed(){
vx=-(x_k-x0)*2;
vy=-(y_k-y0)*2;
}
function draw() {
ctx.clearRect(0,0,w,h);
ctx.beginPath();
ctx.arc(x,y,r,0,2*Math.PI);
ctx.arc(XSL,YSL,r,0,2*Math.PI);
ctx.moveTo(Math.round(x0),Math.round(y0));
ctx.lineTo(x,y);
ctx.font = 'bold 30px sans-serif';
ctx.strokeText("CURRENT LEVEL:", 600, 100);
ctx.strokeText(lvl, 900, 100);
ctx.fill();
ctx.beginPath();
ctx.moveTo(w/2-5,h);
ctx.lineTo(w/2-5,h/3);
ctx.moveTo(w/2+5,h/3);
ctx.lineTo(w/2+5,h);
ctx.moveTo(w/2+5,h/3);
ctx.lineTo(w/2-5,h/3);
ctx.stroke();
}
draw();
function control() {
if (start)
phys();
draw();
confront();
imposible();
}
function star(){
XSL=Math.random()*(500-2*(r))+w/2+r;
YSL=Math.random()*(h-2*(r))+r;
}
function confront(){
if (((x-XSL)*(x-XSL)+(y-YSL)*(y-YSL)<=4*(r)*(r))&&(start)){
levelup();
}
}
function levelup(){
x=250;
y=h/2;
vx=0;
vy=0;
lvl++;
r=40*10/(10+lvl);
star();
start=false;
}
function restart(){
x=250;
y=h/2;
vx=0;
vy=0;
lvl=1;
r=40*10/(10+lvl);
star();
start=false;
}
function imposible() {
if ((start)&&((vy*vy<(y-YSL-2*r))||((x<w/2)&&(vy*vy<(2*y/3+r))))) {
imp++;
}
if (imp>40) {
imp=0;
restart();
}
}
}