【发布时间】:2023-03-07 20:34:01
【问题描述】:
以下是我所知道的:
(1) 飞船对象在某种程度上被渲染了,因为我在它的渲染代码中添加了一个额外的圆圈并且正在绘制。
(2) 我的轮换方法没有任何问题(至少对我来说没有什么明显的问题),因为数字在控制台中正确显示。而top.x、top.y、bottomLeft.x、bottomLeft.y、bottomRight.x、bottomRight.y这些点都是应该的数字。
(3) 使用(2) 中提到的变量来绘制船的实际代码工作正常。当我用硬编码的数字替换变量时,船就画好了。那么是什么给了?
错误代码位于第 140 行的 Ship 对象中,您可以在此处自行测试:http://noetherherenorthere.com/practice/landscape.html。
1 /* landscape.js */
2
3 var canvas;
4 var context;
5 var landscape;
6 var ship;
7
8 function init(){
9
10 canvas = document.getElementById('canvas');
11 context = canvas.getContext('2d');
12 landscape = new Landscape();
13 ship = new Ship(375, 400);
14 animate();
15
16 window.addEventListener('keydown', function(e){
17 switch(e.keyCode){
18 case 37: // left
19 ship.theta -= 0.1;
20 ship.theta %= 2*Math.PI;
21 break;
22 case 38: // up
23 ship.v_x += 1*Math.cos(ship.theta);
24 ship.v_y -= 1*Math.sin(ship.theta);
25 break;
26 case 39: // right
27 ship.theta += 0.1;
28 ship.theta %= 2*Math.PI;
29 break;
30 case 40: // down
31 // do nothing
32 break;
33 default:
34 }
35 });
36
37 }
38
39 function animate(){
40
41 if(this.i == null){
42 this.i = 0;
43 } else{
44 this.i = (this.i + 0.1)%628; // switch it out after 100*2*PI cycles so i doesn't get too big.
45 }
46
47 landscape.sun.y += 10*Math.sin(this.i);
48 landscape.moon.y -= 10*Math.cos(this.i);
49 ship.v = Math.sqrt(Math.pow(ship.v_x, 2) + Math.pow(ship.v_y, 2));
50 ship.x += (0.1 * ship.v_x);
51 ship.y += (0.1 * ship.v_y);
52 if(ship.x < 0){
53 ship.x = canvas.width;
54 }
55 if(ship.x > canvas.width){
56 ship.x = 0;
57 }
58 if(ship.y < 0){
59 ship.y = canvas.height;
60 }
61 if(ship.y > canvas.height){
62 ship.y = 0;
63 }
64 if(ship.v > ship.vMax){
65 ship.v = ship.vMax;
66 }
67 if(ship.v < -ship.vMax){
68 ship.v = -ship.vMax;
69 }
70
71 context.clearRect(0, 0, canvas.width, canvas.height);
72
73 landscape.render();
74
75 ship.render();
76
77 // draw the dialog box
78 context.font = "14px Verdana";
79 context.fillStyle = 'DodgerBlue';
80 context.fillText("Velocity: (x: " + this.ship.v_x.toFixed(2) + ", y: " + this.ship.v_y.toFixed(2) +
81 ", angle: " + radToDeg(this.ship.theta).toFixed(2) + ")", 420, 465);
82 context.fillText("Position: (x: " + this.ship.x.toFixed(2) + ", y: " + this.ship.y.toFixed(2) + ")", 420, 485);
83
84 window.setTimeout(animate, 40);
85
86 }
87
88 function radToDeg(radians){
89
90 return radians*(180/Math.PI);
91
92 }
93
94 function degToRad(degrees){
95
96 return degrees*(Math.PI/180);
97
98 }
99
100 function Landscape(){
101
102 // order of the elements matters here
103
104 this.sky = new Sky();
105 this.sun = new Sun(600, 150, 50);
106 this.moon = new Moon(100, 100, 50);
107
108 this.render = function(){
109
110 for(var element in this){
111 if(this[element].hasOwnProperty("render")){
112 this[element].render();
113 }
114 }
115
116 }
117 }
118
119 function Ship(x, y){
120
121 this.x = x;
122 this.y = y;
123 this.r = 10;
124 this.v = 0; // initial velocity of zero
125 this.v_x = 0;
126 this.v_y = 0;
127 this.theta = Math.PI/2; // starts out pointing upwards
128 this.vMax = 200;
129 this.render = function(){
130 var top = new Vector(this.x, this.y);
131 var bottomLeft = new Vector(this.x - 10, this.y + 30);
132 var bottomRight = new Vector(this.x + 10, this.y + 30);
133
134 top.rotate(this.theta, true);
135 bottomLeft.rotate(this.theta, true);
136 bottomRight.rotate(this.theta, true);
137
138 // console.log("top: " + top + ", bottomLeft: " + bottomLeft + ", bottomRight: " + bottomRight);
139
140 context.fillStyle = 'SlateGray';
141 context.beginPath();
142 context.moveTo(top.x, top.y);
143 context.lineTo(bottomLeft.x, bottomLeft.y);
144 context.lineTo(bottomRight.x, bottomRight.y);
145 context.closePath();
146 context.fill();
147
148 // this code works even though the code above doesn't.
149 // context.fillStyle = 'SlateGray';
150 // context.beginPath();
151 // context.moveTo(this.x, this.y);
152 // context.lineTo(this.x - 10, this.y + 30);
153 // context.lineTo(this.x + 10, this.y + 30);
154 // context.closePath();
155 // context.fill();
156
157 context.fillStyle = 'LightGreen';
158 context.beginPath();
159 context.arc(200, 200, 30, 0, 2*Math.PI);
160 context.closePath();
161 context.fill();
162 }
163
164 function Vector(x, y){
165
166 this.x = x;
167 this.y = y;
168 this.rotate = function(theta, round){
169
170 var rotationMatrix = new Matrix(2, 2, Math.cos(theta), -Math.sin(theta), Math.sin(theta), Math.cos(theta));
171 var vector = new Matrix(2, 1, this.x, this.y);
172 var resultVector = Matrix.multiply(rotationMatrix, vector);
173 this.x = resultVector[0][0];
174 this.y = resultVector[1][0];
175 if(round){
176 this.x = Math.floor(this.x);
177 this.y = Math.floor(this.y);
178 }
179
180 return this;
181
182 }
183
184 this.toString = function(){
185
186 return "x: " + x + ", y: " + y;
187
188 }
189
190 }
191
192 function Matrix(rows, cols /*, var args */){
193
194 // constructor
195
196 if(rows == null || cols == null){
197 throw new Error("null rows or cols argument");
198 } else if(!isPositiveInteger(rows) || !isPositiveInteger(cols)){
199 throw new Error("rows and cols must be whole numbers");
200 } else if(rows > 1000 || cols > 1000){
201 throw new Error("rows and cols must be < 1000 in size");
202 }
203
204 this.numRows = rows;
205 this.numCols = cols;
206 if(arguments.length - 2 > rows*cols){
207 throw new Error("too many arguments to Matrix constructor");
208 } else if(arguments.length > 2 && arguments.length - 2 < rows*cols){
209 throw new Error("too few arguments to Matrix constructor for initializing Matrix." +
210 " Usage: rows, cols [, row-major list of row and col entries]");
211 }
212
213 if(rows === undefined){
214 console.log(arguments);
215 }
216
217 for(var a = 0; a < rows; a++){
218 this[a] = new Array();
219 }
220
221 for(var a = 2; a < arguments.length; a++){
222 try{
223 var row = Math.floor((a - 2)/rows);
224 var col = Math.floor((a - 2)%rows);
225 this[row][col] = arguments[a];
226 } catch(e){
227 console.log(row + ", " + col);
228 throw e;
229 }
230 }
231
232 }
233
234 Matrix.multiply = function(matrixA, matrixB){
235
236 if(matrixA.numCols != matrixB.numRows){
237 throw new Error("# of cols in first matrix must equal # of rows in second matrix");
238 }
239
240 var resultMatrix = new Matrix(matrixA.numRows, matrixB.numCols);
241 var sum, i, j, k;
242
243 for(i = 0; i < matrixA.numRows; i++){
244 for(j = 0; j < matrixB.numCols; j++){
245 sum = 0;
246 for(k = 0; k < matrixA.numCols; k++){
247 sum += matrixA[i][k] * matrixB[k][j];
248 }
249 resultMatrix[i][j] = sum;
250 }
251 }
252
253 return resultMatrix;
254 }
255
256 function isPositiveInteger(n){
257
258 if(n == null){ return false; }
259 if(typeof n != "number"){ return false; }
260 if(!isFinite(n)){ return false; }
261 if(n <= 0){ return false; }
262 if(n%1 !== 0){ return false; }
263 return true;
264
265 }
266
267 }
268
269 function Sky(){
270
271 this.x = 0;
272 this.y = 0;
273 this.width = canvas.width;
274 this.height = canvas.height;
275 this.render = function(){
276 context.fillStyle = 'Black'; // previously Indigo
277 context.fillRect(this.x, this.y, this.width, this.height);
278 }
279
280 }
281
282 function Sun(x, y, radius){
283
284 this.x = x;
285 this.y = y;
286 this.r = radius;
287 this.render = function(){
288 context.fillStyle = 'Gold';
289 context.beginPath();
290 context.arc(this.x, this.y, this.r, 0, 2*Math.PI);
291 context.closePath();
292 context.fill();
293 }
294
295 }
296
297 function Moon(x, y, radius){
298
299 this.x = x;
300 this.y = y;
301 this.r = radius;
302 this.render = function(){
303 context.fillStyle = 'LightYellow';
304 context.beginPath();
305 context.arc(this.x, this.y, this.r, 0, 2*Math.PI);
306 context.closePath();
307 context.fill();
308 }
309
310 }
【问题讨论】:
-
您的
Matrix.multiply返回(NaN, NaN)作为结果向量。 -
嗯...当我取消注释第 138 行的 console.log 打印时,我看到所有
top、bottomLeft和bottomRight向量的正确值。所以这似乎意味着rotate函数工作正常,不是吗?为什么你认为它会返回(NaN, NaN)? -
你应该使用 firebug 或者注释掉函数的片段来看看它在做什么
-
疯狂的事情是我一直在这样做,但为什么它不能正常工作对我来说毫无意义。正如我在问题中指出的那样,船边界的数字是它们应该是的,渲染函数中的其他代码得到正确渲染,如果我用原始的非旋转点代码替换旋转点代码,它工作正常。也没有错误。它不起作用在逻辑上似乎是不可能的,所以我不知道我错过了什么。
-
@NikolaDimitroff 谢谢!我终于得到了你所说的结果——矩阵确实只是返回了 NaN。我自欺欺人地认为它正在工作,因为我有
return "x: " + x + ", y: " + y;作为 Point 类的 toString 方法,它应该是this.x和this.y。 (见第 184-186 行。)现在我有事情要做了。
标签: javascript canvas