首页 > 解决方案 > 画布动画圈不显示

问题描述

我正在使用 JavaScript 和 HTML 画布对两体轨道进行建模。我有一个动画函数,它绘制一个圆,它是太阳,第二个圆在设定的坐标是地球。我已经转换了坐标系,所以页面的中心是(0,0)。我还有一个未完成的跳跃功能,最终每次都会更新位置和速度。

我的问题是第二个圆圈在动画功能中不再显示,但太阳仍然显示。我认为它与 requestAnimationFrame() 方法有关,但我真的不确定该怎么做。

这是 animate 函数的代码,也是 jumpfrog 函数的结尾(返回的值在 animate 函数中使用)和调用其他函数的 main 函数:

//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>

任何帮助都会很棒!

标签: javascriptanimationcanvashtml5-canvas

解决方案


<!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>


推荐阅读