问题描述
我是画布和游戏引擎的新手。我在以下代码段中有一些随机弹跳球。它似乎工作正常,直到这些球堆积起来,如果我在检查碰撞时不减去重力,它们最终会坍塌并重叠。然而,减去重力会使那些球疯狂地跳舞/摇晃,我相信这不是模拟重力和碰撞的正确方法。
我知道有一些很棒的 JS 游戏引擎,但我想了解如何在游戏中正确实现重力。
P.S.:点击画布以生成球。
let GAMEOBJ=[{R:50,N:1}];
let RADIUS=30;
let GraviTY=9.81;
let _UPDATE=function(C){
return{
INERTIA:B=>{
this.CO=false;
this.DPR=C.DPR;
if(!this.R)this.R=Math.max(15,Math.random()*RADIUS);
this.RR=this.R*this.DPR;
if(!this.V)this.V={}; //V=veLocity
if(!this.V.R)this.V.R=Math.min(.99,1/this.R*(GraviTY));
['X','Y'].map(D=>{
if(undefined==this[D])this[D]=Math.random()*C[D];
if(undefined==this.V[D])this.V[D]=C.RSP();
if(B){
if(C[D]-this.RR<=this[D]||this.RR>=this[D]){
this.V[D]=this.V[D]*-1;
this.V[D]-=this.V[D]*(1-this.V.R);
if(this.RR>=this[D])this[D]=this.RR
else// if(C[D]-this.RR<=this[D])
this[D]=C[D]-this.RR;
}
}else this[D]=C[D]<=this[D]?0:0>=this[D]?C[D]:this[D];
});
this.V.X-=this.V.X*(1-this.V.R)/100;
this.V.Y+=GraviTY*this.DPR;
},POSITION:()=>{
['X','Y'].map(D=>{
this[D]+=this.V[D]*C.LOOP.DELTA;
});
this.V.A=Math.atan2(this.V.Y,this.V.X); //A=angle
}
};
};
let _COLLISION=function(){
return{
CIRCLE:O=>{
if(!this.V)this.V={};
if(!this.V.D)this.V.D={}; //D=distance
['X','Y'].map(D=>{
this.V.D[D]=O[D]-this[D];
});
this.V.D.D=Math.sqrt(this.V.D.X*this.V.D.X+this.V.D.Y*this.V.D.Y);
if(this.V.D.D<this.RR+O.RR){
this.CO=O; //CO=collision object
O.CO=this;
this.COLLISION().PHYSIC();
}
},PHYSIC:()=>{
this.V.CN={ //CN=collision normalized
X:this.V.D.X/this.V.D.D,Y:this.V.D.Y/this.V.D.D
};
this.V.S=(this.V.X-this.CO.V.X)*this.V.CN.X+(this.V.Y-this.CO.V.Y)*this.V.CN.Y; //S=speed
if(this.V.S>0){
this.V.I=2*this.V.S/(this.V.R+this.CO.V.R); //I=impulse
['X','Y'].map(D=>{
this.V[D]-=this.V.CN[D]*this.V.I*this.V.R;
this.CO.V[D]+=this.V.CN[D]*this.V.I*this.CO.V.R;
});
this.V.Y-=GraviTY*this.DPR;
}
}
};
};
CanvasRenderingContext2D.prototype.PUSH=function(O){
if(!this.OBJ)this.OBJ=[];
if(!O||'object'!=typeof O)O={};
O.UPDATE=_UPDATE;
O.COLLISION=_COLLISION;
this.OBJ.push(O);
};
CanvasRenderingContext2D.prototype.DRAW=function(I){
return{
CIRCLE:()=>{
this.translate(this.OBJ[I].X,this.OBJ[I].Y);
this.rotate(this.OBJ[I].V.A);
this.translate(-this.OBJ[I].X,-this.OBJ[I].Y);
this.fillStyle=this.OBJ[I].S?'red':this.OBJ[I].CO?'#ff8080':'#0099b0';//this.OBJ[I].C;
this.beginPath();
this.arc(this.OBJ[I].X,this.OBJ[I].Y,this.OBJ[I].RR,2*Math.PI);
this.fill();
this.closePath();
this.strokeStyle='white';
this.linewidth=1*this.DPR;
this.beginPath();
this.moveto(this.OBJ[I].X,this.OBJ[I].Y);
this.lineto(this.OBJ[I].X+(this.OBJ[I].RR),this.OBJ[I].Y);
this.stroke();
this.closePath();
this.setTransform(1,1,0); //reset transform
},TEXT:STR=>{
this.fillStyle='red';
this.font=`${24*this.DPR}px Arial`;
this.textAlign='left';
this.textBaseline='top';
this.fillText(STR,10,10);
}
}
};
HTMLCanvasElement.prototype.RSP=function(){ //RSP=random speed
return(Math.random()*this.width*2-this.width);
};
HTMLCanvasElement.prototype.RESIZE=function(){
this.DPR=devicePixelRatio;
this.width=this.X=window.innerWidth*this.DPR;//screen.width;
this.height=this.Y=window.innerHeight*this.DPR;//screen.height;
}
HTMLCanvasElement.prototype.INIT=function(CTNR,L){ //CTNR=container
(window.onresize=window.onorientationchange=()=>this.RESIZE())();
let CTX=this.getContext('2d');
if(!CTNR)CTNR=[];
if(L)CTNR=CTNR.concat(Array.apply(0,Array(L)));
CTNR.map(O=>CTX.PUSH(O));
this.LOOP={
DRAW:()=>{
requestAnimationFrame(T=>{
//this.RESIZE();
CTX.DPR=this.DPR;
CTX.OBJ.map(O=>O.UPDATE(this).INERTIA(true));
//*/
CTX.OBJ.map(O1=>CTX.OBJ.map(O2=>{
if(O1!=O2)O1.COLLISION().CIRCLE(O2);
}));
//*/
CTX.OBJ.map(O=>O.UPDATE(this).POSITION());
//this.width=this.width;
CTX.clearRect(0,this.width,this.height); //clear the canvas
CTX.OBJ.map((O,I)=>CTX.DRAW(I).CIRCLE());
CTX.DRAW().TEXT(`FPS: ${this.LOOP.FPS(T)}`);
this.LOOP.DRAW();
});
},DELTA:1,FPS:(T,LT)=>{
LT=this.LOOP.LT||0;
this.LOOP.DELTA=(T-LT)/1000;
this.LOOP.LT=T;
return(Math.round(1/this.LOOP.DELTA));
}
};
this.LOOP.DRAW();
this.onclick=function(){
/*
CTX.OBJ.map(O=>{
O.Y--;
O.V.Y=(GraviTY*O.DPR*O.V.R*50)*-1;
});
//*/
this.getContext('2d').PUSH({Y:0,V:{Y:0}});
};
};
window.onload=()=>CANVAS.INIT(GAMEOBJ,10);
/*tmP*/
*{Box-sizing:border-Box;}
*:focus{outline:none;}
html,body{
overflow:hidden;
user-select:none;
-webkit-user-select:none;
-webkit-touch-callout:none;
-webkit-text-size-adjust:100%;
-webkit-tap-highlight-color:transparent;
margin:0;
padding:0;
height:100%;
/*font-family:'Noto Sans HK',sans-serif;*/
color:#777;
position:fixed;
left:0;
right:0;
top:0;
bottom:0;
}
img{
max-width:100%;
user-drag:none;
-webkit-user-drag:none;
}
main{
display:block;
position:fixed;
z-index:2;
left:0;
right:0;
top:0;
bottom:0;
width:100%;
height:100%;
overflow:hidden;
/*
overflow-x:hidden;
overflow-y:scroll;*/
-webkit-overflow-scrolling:touch;
}
[CC]{border:1px dotted red;}
[W100]{width:100%;}
[H100]{height:100%;}
<!DOCTYPE HTML>
<html prefix='og: http://ogp.me/ns#' lang='zh'>
<Meta charset='UTF-8'>
<Meta name='viewport' content='width=device-width,initial-scale=1'>
<link rel='icon' href='asset/img/favicon.ico'>
<link rel='stylesheet' href='asset/style/game.css'>
<body>
<code hidden>prototype.cloud GAME</code>
<main>
<canvas id='CANVAS' W100 CC>
<code>Your browser does not support the HTML5 canvas tag</code>
</canvas>
</main>
</body>
<script defer type='module' src='asset/script/game.js'></script>
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)