我正在使用JavaScript和HTML画布对两个物体的轨道进行建模。我有一个动画函数,该函数绘制一个圆,该圆是太阳,而第二个圆是在设置的坐标上是地球。我已经转换了坐标系,因此页面的中心是(0,0)。我还有一个未完成的跳越函数,它将最终每次更新位置和速度。
我的问题是,当第二个圆圈处于动画功能时,第二个圆圈不再显示,但太阳仍然显示。我认为这与requestAnimationFrame()方法有关,但是我真的不确定要怎么做。
这是动画函数的代码,也是跳越函数的末尾(返回值,这些值在动画函数中使用)和调用其他函数的主函数:
//retrieving the DOM
var canvas = document.getElementById("solarsys");
// context variable
var c = canvas.getContext('2d');
//initial positions for the earth unit m
// two sets so that data can be stored for reset function
var initialXPos = (-7.564432386799773E-01 * 1.496e+11);
var initialYPos = (-6.718892710848022E-01 * 1.496e+11);
var xPos = (-7.564432386799773E-01 * 1.496e+11);
var yPos = (-6.718892710848022E-01 * 1.496e+11);
//initial velocities for the earth unit ms-1
var initialXVel = ((1.110596439833439E-02 * 1.496e+11) / 86400);
var initialYVel = ((-1.296782278648682E-02 * 1.496e+11) / 86400);
var xVel = ((1.110596439833439E-02 * 1.496e+11) / 86400);
var yVel = ((-1.296782278648682E-02 * 1.496e+11) / 86400);
//position and velocity scales
var posScale = 1E9;
var velScale = 1000;
function axis(c) {
//this function translates the canvas co-ordinates to cartesian co-ordinates
//moves the origin to the centre of the page
c.translate(400, 275);
//makes the y axis grow up and shrink down
c.scale(1, -1);
};
function leapfrog(xPos, yPos, posScale, xVel, yVel, velScale) {
//gravitational constant m3kg-1s-2
var G = 6.67E-11;
//mass of earth kg
var m2 = 5.972E24;
//mass of sun kg
var m1 = 1.989E30;
// earth sun distance 1AU = 149 600 000 000 m but depends on where in orbit
// therefore do pythagoras on current x and y co-ordinates of position
//first covert xPos and yPos to m so force equation dimensionally constant
var xPosm = xPos * 1.496E+11;
var yPosm = yPos * 1.496e+11;
var r = (Math.sqrt((Math.pow(xPosm, 2)) + (Math.pow(yPosm, 2))));
//calculate the force on the earth using F = Gm1m2/r^2
//force is towards the centre of the sun
var F = ((G * m1 * m2) / (Math.pow(r, 2)));
//calculate earths acceleration using Newton 2nd a = F / m
var a = (F / m2);
//leapfrog loop for new position and velocity
//position new = previous position + previous half velocity * time step
//velocity new +1/2 from pos = previous velocity 1/2 from pos + acceleration
// calculates scaled positions
var xPosScaled = xPos / posScale;
var yPosScaled = yPos / posScale;
//calculates scaled velocities
var xVelScaled = xVel / velScale;
var yVelScaled = yVel / velScale;
return [xPosScaled, yPosScaled, xVelScaled, yVelScaled];
};
function drawEarth(c, xPosScaled, yPosScaled) {
//draws a blue circle - the earth
c.beginPath();
c.arc(xPosScaled, yPosScaled, 10, Math.PI * 0, Math.PI * 2, false);
c.fillStyle = '#003399';
c.fill();
c.stroke();
c.closePath();
};
function drawSun(c) {
//draw a yellow circle - the sun
c.beginPath();
c.arc(0, 0, 30, Math.PI * 0, Math.PI * 2, false);
c.fillStyle = '#ffcc00';
c.fill();
c.stroke();
c.closePath();
};
function animate(c, xPosScaled, yPosScaled) {
requestAnimationFrame(animate);
c.clearRect(-innerWidth / 2, -innerHeight / 2, innerWidth, innerHeight);
//if want a black background
//c.fillRect(-innerWidth/2,-innerHeight/2,innerWidth,innerHeight);
drawSun(c);
drawEarth(c, xPosScaled, yPosScaled);
};
function main(c, xPos, yPos, posScale, xVel, yVel, velScale) {
axis(c);
var posVelArray = leapfrog(xPos, yPos, posScale, xVel, yVel, velScale);
var xPosScaled = posVelArray[0];
var yPosScaled = posVelArray[1];
var xVelScaled = posVelArray[2];
var yVelScaled = posVelArray[3];
animate(c, xPosScaled, yPosScaled);
};
<canvas id="solarsys"></canvas>
任何帮助都会很棒!
答案 0 :(得分:0)
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
display: block;
margin: auto;
border: solid 1px white;
border-radius: 10px;
}
div {
display: block;
margin: auto;
margin-top: 20px;
padding-left: 10px;
padding-bottom: 10px;
width: 150px;
height: 40px;
background-color: gray;
border: solid 1px white;
border-radius: 10px;
}
p {
display: inline-block;
color: white;
}
input {
display: inline-block;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div>
<p>Enable Collision:</p>
<input type="checkbox" onclick="callbacks.toggleCollision();"></input>
</div>
<script type="application/javascript">
var callbacks = function() {
"use strict";
/*
Calculate a body's acceleration due to gravity
f = G * ((m1 * m2) / r^2)
f = m1 * a1
=> m1 * a1 = G * ((m1 * m2) / r^2)
=> a1 = G * m2 / r^2 -> m2 being the mass of the other object
Below this formula is integrated using the verlet method
*/
// Constants
var canvasWidth = 180;
var canvasHeight = 160;
// Classes
function StaticBody(x,y,r,m) {
this.x = x || console.error("Static body missing x coordinate");
this.y = y || console.error("Static body missing y coordinate");
this.r = r || console.error("Static body missing radius");
this.m = m || console.error("Static body missing mass");
}
StaticBody.prototype = {
STATIC: true,
preTick: function(bodies) {
// Something static doesn't really need to update
},
tick: function() {
// Something static doesn't really need to update
},
render: function(ctx) {
ctx.strokeStyle = "black";
ctx.fillStyle = "#FDB813FF";
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0.0,2.0 * Math.PI,false);
ctx.fill();
ctx.stroke();
}
};
function DynamicBody(x,y,r,m) {
this.x = x || console.error("Dynamic body missing x coordinate");
this.y = y || console.error("Dynamic body missing y coordinate");
this.r = r || console.error("Dynamic body missing radius");
this.m = m || console.error("Dynamic body missing mass");
this.ox = this.x + Math.random() * 1.0 - 0.5;
this.oy = this.y + Math.random() * 1.0 - 0.5;
this.ax = 0.0;
this.ay = 0.0;
}
DynamicBody.prototype = {
STATIC: false,
GRAVITY_CONSTANT: 0.1, // I've tickered with this value to get better looking behaviour
MAX_VELOCITY: 1.0,
preTick: function(bodies) {
this.ax = 0.0;
this.ay = 0.0;
for (var i = 0; i < bodies.length; ++i) {
var body = bodies[i];
if (body !== this) {
var x = body.x - this.x;
var y = body.y - this.y;
var invR = 1.0 / Math.max(1.0,Math.sqrt(Math.pow(x,2.0) + Math.pow(y,2.0)));
var a = this.GRAVITY_CONSTANT * body.m * invR;
this.ax += x * invR * a;
this.ay += y * invR * a;
}
}
},
tick: function(bodies,isCollisionEnabled) {
var nx = this.x + (this.x - this.ox) + this.ax * 0.016;
var ny = this.y + (this.y - this.oy) + this.ay * 0.016;
this.ox = this.x;
this.oy = this.y;
this.x = nx;
this.y = ny;
if (this.x < this.r) {
this.x = this.ox = this.r;
} else if (this.x > canvasWidth - this.r) {
this.x = this.ox = canvasWidth - this.r;
}
if (this.y < this.r) {
this.y = this.oy = this.r;
} else if (this.y > canvasHeight - this.r) {
this.y = this.oy = canvasHeight - this.r;
}
if (isCollisionEnabled) {
for (var i = 0; i < bodies.length; ++i) {
var body = bodies[i];
if (body !== this) {
var x = body.x - this.x;
var y = body.y - this.y;
var r = Math.sqrt(Math.pow(x,2.0) + Math.pow(y,2.0));
var invR = 1.0 / r;
var cr = this.r + body.r;
if (r < cr) {
var d = cr - r;
if (body.STATIC) {
this.x -= x * invR * d;
this.y -= y * invR * d;
} else {
this.x -= x * invR * d * 0.5;
this.y -= y * invR * d * 0.5;
body.x += x * invR * d * 0.5;
body.y += y * invR * d * 0.5;
}
}
}
}
}
},
render: function(ctx) {
ctx.strokeStyle = "black";
ctx.fillStyle = "#888888FF";
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0.0,2.0 * Math.PI,false);
ctx.fill();
ctx.stroke();
}
};
// Variables
var canvas = null;
var ctx = null;
var bodies = [];
var isCollisionEnabled = false;
// functions
function toggleCollision() {
isCollisionEnabled = !isCollisionEnabled;
}
// Game loop
function loop() {
// Tick
for (var i = 0; i < bodies.length; ++i) {
bodies[i].preTick(bodies);
}
for (var i = 0; i < bodies.length; ++i) {
bodies[i].tick(bodies,isCollisionEnabled);
}
// Render
ctx.fillStyle = "gray";
ctx.fillRect(0,0,canvasWidth,canvasHeight);
for (var i = 0; i < bodies.length; ++i) {
bodies[i].render(ctx);
}
//
requestAnimationFrame(loop);
}
// Event Listeners
function onMouseDown(e) {
var bounds = canvas.getBoundingClientRect();
var r = 2.0 + Math.random() * 2.0;
bodies.push(new DynamicBody(
e.clientX - bounds.left,
e.clientY - bounds.top,
r,
r
));
}
// Entry point
onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
canvas.onmousedown = onMouseDown;
ctx = canvas.getContext("2d");
bodies.push(new StaticBody(90.0,80.0,10.0,50.0));
for (var i = 0, l = 10 + (Math.random() * 20) | 0; i < l; ++i) {
var r = 2.0 + Math.random() * 2.0
bodies.push(new DynamicBody(
Math.random() * canvasWidth,
Math.random() * canvasHeight,
r,
r * 2
));
}
loop();
}
return {
toggleCollision: toggleCollision
};
}();
</script>
</body>
</html>