JavaScript 在凸形上发生墙壁碰撞,卡在 Angular 落

标签 javascript 2d collision-detection game-physics collision

这是另一个问题的后续:How do I handle player collision with corners of a wall

受到 its answer 中给出的代码的启发,我尝试编写一些新代码。

基本上,在原版中,墙壁滑动在墙壁内部效果很好,但我想让它在外部也起作用,所以我根据他的技术制作了一个新的基本代码引擎:

var aD =[]
var r
function start() {
	r = new CanvasRenderer(can),
		my = new scene();
	window.my = my
	eventHandler();
	my.add(new mesh({
		verts: [
			0,   0,
			100, 15,
			115, 60,
			50, 100,
			20, 75,2,8
		],
		position: {
			x: 100,
			y:100
		},
		scale: {

			x:4,y:5
		},
		color:"orange",
		onupdate(me) {
		//	me.position.x++
		}
	}));
	var g = false
	my.add(new mesh({
		primitive:"rect",
		name: "player",
		scale: {
			x: 50,
			y:50
		},
		position: {
			x: 311,
			y:75
		},
		origin: {
			x:0.5,
			y:0.5
		},
		onupdate(me) {
			var upKey = keys[38],
				downKey = keys[40],
				rightKey = keys[39],
				leftKey = keys[37],
				drx  = 0,
				dx = 0,
				speed = 5,
				turningSpeed = 3
			
			drx = leftKey ? -1 : rightKey ? 1 : 0
			forward = upKey ? 1 : downKey ? -1 : 0

			me.rotation.x += (
				(drx * Math.PI / 180 * turningSpeed )
			)
			me.rotation.y = 1;

			var xDir = Math.cos(me.rotation.x)
			var yDir = Math.sin(me.rotation.x)
			
			me.position.x += xDir  * forward * speed
			me.position.y += yDir * forward * speed

			for(var i = 0; i < my.objects.length; i++) {
				let cur = my.objects[i];
				if(cur.name !== me.name) {
					cur.lineSegments.forEach(l => {
						var col = checkCollision(
							me.position.x,
							me.position.y,
							me.scale.x/2,
							l
						)
						
						if(col) {
		
							me.position.y=col.y
							me.position.x = col.x
						}
					 });
				}
			}


		
			
		}

	}));
	
	let i = setInterval(() => render(r, my), 16);
	r.on("resize", () => render(r, my));

}

function checkCollision(x1, y1, rad,l) {
		var dist = distance2(
							l.start[0],
							l.start[1],
							
							l.end[0],
							l.end[1]
						),
							vec1 = [
								x1 - l.start[0],
								y1 - l.start[1]
							],

							vec2 = [
								l.end[0] - l.start[0],
								l.end[1] - l.start[1]
							],

							percentOfWall = (
								Math.max(
									0,
									Math.min(
										1, 
										dot(
											vec1[0],
											vec1[1],

											vec2[0],
											vec2[1]
										) / dist
									)
								)
							),
							projection = [
								l.start[0] + percentOfWall * vec2[0],
								l.start[1] + percentOfWall * vec2[1],
							],
							acDist = Math.sqrt(distance2(
								x1, y1,
								projection[0], projection[1]
							))
aD.push( () => {
						r.ctx.beginPath()
						r.ctx.fillStyle="green"
						r.ctx.arc(projection[0], projection[1], 5, 0, Math.PI*2);
						r.ctx.fill()
						r.ctx.closePath();
						})

					
					if(acDist < rad) {
						var mag = Math.sqrt(dist),
							delt = [
							l.end[0] - l.start[0],
							l.end[1] - l.start[1]
						],
							normal = [
							delt[0] / mag,
							delt[1] / mag
						]
						
						return {
						
							x: projection[0] + 

							rad * (normal[1] ),
						
							 y:projection[1] + 
							rad* (-normal[0] ),
							projection,
							normal
						}
					}

					
}


function dot(x1, y1, x2, y2) {
	return (
		x1 * x2 + y1 * y2
	)
}

function distance2(x1, y1, x2, y2) {
	let dx = (x1 - x2), dy = (y1 - y2);
	return (
		dx * dx + dy * dy
	);
}

function render(r,s) {
//r.ctx.clearRect(0,0,r.ctx.canvas.width,r.ctx.canvas.height)
	s.update();
	r.render(s)
	aD.forEach(x=>x());
	aD = []
}

onload = start;

function eventHandler() {
	window.keys = {};
	addEventListener("keyup" , e=> {
		keys[e.keyCode] = false;
			
	});

	addEventListener("keydown" , e=> {
		keys[e.keyCode] = true;
	});
}

function CanvasRenderer(dom) {
	if(!dom) dom = document.createElement("canvas");
	
	var events = {}, self = this;
	function rsz() {
		dom.width = dom.clientWidth;
		dom.height = dom.clientHeight;
		self.dispatchEvent("resize");
	}
	
	window.addEventListener("resize", rsz);	

	let ctx = dom.getContext("2d");

	function render(scene) {
		ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
		for(let i = 0; i < scene.objects.length; i++) {
			let o = scene.objects[i],
				verts = o.realVerts;

			
			ctx.beginPath();
			ctx.moveTo(
				verts[0] , 

				verts[1]
			);
			verts.forEach((v, i, ar) => {
				let y = i;
				


				ctx.lineTo(
					v[0] , 

					v[1]
				);
				
			});
			ctx.lineTo(
				verts[0],
				verts[1] 
			);
			ctx.fillStyle = o.color || "blue";
			ctx.lineWidth = 1;
			ctx.fill()
			ctx.stroke();
			ctx.closePath();
		}
	}

	Object.defineProperties(this, {
		domElement: {
			get: () => dom
		},	
		ctx: {
			get: () => ctx
		},
		render: {
			get: () => render
		},
		on: {
			get: () => (nm, cb) => {
				if(!events[nm]) {
					events[nm] = [];
				}
				events[nm].push(data => {
					if(typeof cb == "function") {
						cb(data);
					}
				});
			}		
		},
		dispatchEvent: {
			get: () => (name, data) => {
				if(events[name]) {
					events[name].forEach(x => {
						x(data);
					});
				}
			}
		}
	});
	
	rsz();

}

function scene() {
	let objects = [];
	Object.defineProperties(this, {
		add: {
			get: () => obj => {
				objects.push(obj);
			}
		},
		objects: {
			get: () => objects
		},
		update: {
			get: () => () => {				
				objects.forEach(x => {
					if(typeof x.update == "function") {
						x.update();
					}
				});
				
			}
		}
	});
}

function mesh(data={}) {
	let verts = [],
		self = this,
		holder = {
			position:{},
			scale: {
				
			},
			rotation: {},
			origin:{}
		},
		actual = {
	
		},
		position = {},
		scale = {},
		rotation = {},
		origin = {},
		color,
		name,
		primitive,
		eventNames = "update",
		events = {},
		drawPrimitive = {
			circle(ctx) {
				ctx.beginPath();
				ctx.arc(
					self.position.x,
					self.position.y,
					5, 
					0,
					360 * Math.PI / 180
				);
				ctx.closePath();
			},
			rect(ctx) {
				ctx.strokeRect(
					self.position.x,
					self.position.y,
					30, 30
				);
			}
		},
		width = 1,
		height = 1,
		primitiveToVerts = {
			rect: () =>  [
					0, 0,
					width , 0,
					width, height,
					0, height
			]
		},
		realVerts = verts,
		lineSegments = [],
		o = this;
	
	function updateRealVerts() {
			
			let  actualVerts = [],
				originedVerts = [],
				adjustedVerts = [],
				rotatedVerts = [],
				stepSize = o.step || 2,
				curVerts = [];
			
			o.verts.forEach((v, i) => {
				curVerts.push(v);
				if(
					(i - 1) % stepSize === 0 &&
					i !== 0
				) {
					actualVerts.push(curVerts);
					curVerts = [];
				}
			});
			actualVerts = actualVerts.filter(x => x.length == stepSize);
			
			originedVerts = actualVerts.map(v => [
				v[0] - o.origin.x,
				v[1] - o.origin.y,
				v[2] - o.origin.z
			]);
	
			rotatedVerts = originedVerts.map(v => 
				[

					v[0] * Math.cos(o.rotation.x) - 
					v[1] * Math.sin(o.rotation.x),

					v[0] * Math.sin(o.rotation.x) + 
					v[1] *Math.cos(o.rotation.x),
v[2]
				]
			);

			adjustedVerts = rotatedVerts.map(v => 
				[
					v[0] * 
					o.scale.x + 
					o.position.x,
	
					v[1] * 
					o.scale.y + 
					o.position.y,

					v[2] * 
					o.scale.z + 
					o.position.z,
				]
			);

			realVerts = adjustedVerts;
			updateLineSegments();
	}	

	function updateLineSegments() {
				let lines = [];
				for(let i = 0, a = realVerts; i < a.length;i++) {
					let start = [], end = []
					if(i < a.length - 1) {
						start = a[i];
						end = a[i + 1];
					} else {
						start = a[i];
						end = a[0];
					}

					lines.push({
						start, end
					})
				}
				lineSegments = lines;
	}
	Object.defineProperties(position, {
		x: {
			get: () => holder.position.x || 0,
			set: v => holder.position.x = v
		},
		y: {
			get: () => holder.position.y || 0,
			set: v => holder.position.y = v
		},
		z: {
			get: () => holder.position.z || 0,
			set: v => holder.position.z = v
		}
	});

	Object.defineProperties(scale, {
		x: {
			get: () => holder.scale.x || 1,
			set: v => holder.scale.x = v
		},
		y: {
			get: () => holder.scale.y || 1,
			set: v => holder.scale.y = v
		},
		z: {
			get: () => holder.scale.z || 1,
			set: v => holder.scale.z = v
		}
	});

	Object.defineProperties(rotation, {
		x: {
			get: () => holder.rotation.x || 0,
			set: v => holder.rotation.x = v
		},
		y: {
			get: () => holder.rotation.y || 0,
			set: v => holder.rotation.y = v
		},
		z: {
			get: () => holder.rotation.z || 0,
			set: v => holder.rotation.z = v
		}
	});

	Object.defineProperties(origin, {
		x: {
			get: () => holder.origin.x || 0,
			set: v => holder.origin.x = v
		},
		y: {
			get: () => holder.origin.y || 0,
			set: v => holder.origin.y = v
		},
		z: {
			get: () => holder.origin.z || 0,
			set: v => holder.origin.z = v
		}
	});
	

	Object.defineProperties(this, {
		verts: {
			get: ()=>verts,
			set(v) {
				verts = v
			}
		},
		name: {
			get: ()=>name,
			set(v) {
				name = v
			}
		},
		primitive: {
			get: ()=>primitive,
			set(v) {
				primitive = v;
				let newVerts = primitiveToVerts[v];
				if(newVerts) {
					this.verts = newVerts();
				}
			}
		},
		width: {
			get: ()=>width,
			set(v) {
				width = v
			}
		},
		height: {
			get: ()=>height,
			set(v) {
				height = v
			}
		},
		position: {
			get: () => position,
			set: v => {
				position.x = v.x || 0;
				position.y = v.y || 0;
				position.z = v.z || 0;
			}
		},
		scale: {
			get: () => scale,
			set: v => {
				scale.x = v.x || v.x === 0 ? v.x : 1;
				scale.y = v.y  || v.y === 0 ? v.y : 1;
				scale.z = v.z  || v.z === 0 ? v.z : 1;
			}
		},
		rotation: {
			get: () => rotation,
			set: v => {
				rotation.x = v.x || 0;
				rotation.y = v.y || 0;
				rotation.z = v.z || 0;
			}
		},
		origin: {
			get: () => origin,
			set: v => {
				origin.x = v.x || 0;
				origin.y = v.y || 0;
				origin.z = v.z || 0;
			}
		},
		color: {
			get: () => color,
			set: v => {
				color = v;
			}
		},
		realVerts: {
			get: () => realVerts
		},
		lineSegments: {
			get: () => lineSegments
		},
		update: {
			get: () => () => {
				if(events["update"]) {
					events.update.forEach(x => {
						updateRealVerts();
						x(this);
					});
				}
			}
		},
		on: {
			get: () => (nm, fnc) => {
				if(!events[nm]) events[nm] = [];
				events[nm].push(stuff => {
					if(typeof fnc == "function") {
						fnc(stuff);
					}
				});
			}
		}
	});

	eventNames.split(" ").forEach(x => {
		var name = "on" + x;
		if(!this.hasOwnProperty(name)) {
			Object.defineProperty(this, name, {
				get: () => events[name],
				set(v) {
					events[x] = [
						data => {
							typeof v == "function" && v(data)
						}
					];
				}
			});
		}
	});

	for(let k in data) {
		this[k] = data[k]
	}

	updateRealVerts();

}
canvas{
	width:100%;
	height:100%;
	position:absolute;
	top:0;	
	left:0px
}

.wow{
	float:right;
	z-index:1298737198
}
<meta charset="utf-8">
<button onclick="start()" class=wow>ok</button>
<canvas id=can>

</canvas>

请参阅第 71 行,了解碰撞检测实现调用(以及那里函数的返回值)。

问题是,正如您希望看到的那样(只需全屏显示并使用箭头键移动,尝试与 Angular 落处的橙色网格碰撞)它滑动得很好,但是当它到达 Angular 落时,它会卡在他们。

有什么想法可以解决这个问题 - 不使用任何类型的外部库等(仅在代码片段中可用)?

最佳答案

我想说的是,只需检查您是否处于 Angular 落 - 当 percentOfWall 时丢弃案例恰好是 0或者正是1

编辑:为了解决评论中提到的问题,我必须解释为什么你的实现陷入困境。它计算了所有墙壁的穿透力,并通过该穿透量减少了位置变化。在 Angular 落里,物体同时与两侧边缘碰撞,同时受到两侧边缘的排斥而停止移动。

正如您所注意到的,在 Angular 落里,您的方 block 会进入障碍物一帧,然后在后续帧中被推出。

然而,替代解决方案更复杂且更难调试,但这里是几个选项的草图:

  • 将碰撞限制为一次仅从一堵墙发生排斥,并尽早退出您的 forEach环形。这是一个简单的解决方案,在这个特定的例子中可以工作,但在一般情况下不起作用,例如在 Angular 落里,当你需要与两堵墙碰撞时,阻止你朝两个方向移动。
  • 在每个 Angular 上添加一个小圆圈并与其碰撞以避免进入内部。法线是沿着圆心和接触点之间的线。这可以平滑拐 Angular 处的法线不连续性,并且始终存在一个单一法线,沿着该法线物体会被排斥,从一个线段不断变化到另一线段。

将“推”引导到障碍物的每个部分之外(这就是您所要求的)不会阻止在拐 Angular 处停止(这正是您所关心的点),两堵墙都会与您的碰撞物体和“外部”的方向相反。因此,它会以与以前相同的方式卡住,并且出于完全相同的原因 - 法线将不连续。

希望有帮助

var aD =[]
var r
function start() {
	r = new CanvasRenderer(can),
		my = new scene();
	window.my = my
	eventHandler();
	my.add(new mesh({
		verts: [
			0,   0,
			100, 15,
			115, 60,
			50, 100,
			20, 75,2,8
		],
		position: {
			x: 100,
			y:100
		},
		scale: {

			x:4,y:5
		},
		color:"orange",
		onupdate(me) {
		//	me.position.x++
		}
	}));
	var g = false
	my.add(new mesh({
		primitive:"rect",
		name: "player",
		scale: {
			x: 50,
			y:50
		},
		position: {
			x: 311,
			y:75
		},
		origin: {
			x:0.5,
			y:0.5
		},
		onupdate(me) {
			var upKey = keys[38],
				downKey = keys[40],
				rightKey = keys[39],
				leftKey = keys[37],
				drx  = 0,
				dx = 0,
				speed = 5,
				turningSpeed = 3
			
			drx = leftKey ? -1 : rightKey ? 1 : 0
			forward = upKey ? 1 : downKey ? -1 : 0

			me.rotation.x += (
				(drx * Math.PI / 180 * turningSpeed )
			)
			me.rotation.y = 1;

			var xDir = Math.cos(me.rotation.x)
			var yDir = Math.sin(me.rotation.x)
			
			me.position.x += xDir  * forward * speed
			me.position.y += yDir * forward * speed

			for(var i = 0; i < my.objects.length; i++) {
				let cur = my.objects[i];
				if(cur.name !== me.name) {
					cur.lineSegments.forEach(l => {
						var col = checkCollision(
							me.position.x,
							me.position.y,
							me.scale.x/2,
							l
						)
						
						if(col) {
							me.position.y=col.y
							me.position.x = col.x
						}
					 });
				}
			}


		
			
		}

	}));
	
	let i = setInterval(() => render(r, my), 16);
	r.on("resize", () => render(r, my));

}

function checkCollision(x1, y1, rad,l) {
		var dist = distance2(
							l.start[0],
							l.start[1],
							
							l.end[0],
							l.end[1]
						),
							vec1 = [
								x1 - l.start[0],
								y1 - l.start[1]
							],

							vec2 = [
								l.end[0] - l.start[0],
								l.end[1] - l.start[1]
							],

							percentOfWall = (
								Math.max(
									0,
									Math.min(
										1, 
										dot(
											vec1[0],
											vec1[1],

											vec2[0],
											vec2[1]
										) / dist
									)
								)
							),
							projection = [
								l.start[0] + percentOfWall * vec2[0],
								l.start[1] + percentOfWall * vec2[1],
							],
							acDist = Math.sqrt(distance2(
								x1, y1,
								projection[0], projection[1]
							))
aD.push( () => {
						r.ctx.beginPath()
						r.ctx.fillStyle="green"
						r.ctx.arc(projection[0], projection[1], 5, 0, Math.PI*2);
						r.ctx.fill()
						r.ctx.closePath();
						})

					
					if(acDist < rad && percentOfWall > 0 && percentOfWall < 1) {
						var mag = Math.sqrt(dist),
							delt = [
							l.end[0] - l.start[0],
							l.end[1] - l.start[1]
						],
							normal = [
							delt[0] / mag,
							delt[1] / mag
						]
						
						return {
						
							x: projection[0] + 

							rad * (normal[1] ),
						
							 y:projection[1] + 
							rad* (-normal[0] ),
							projection,
							normal
						}
					}

					
}


function dot(x1, y1, x2, y2) {
	return (
		x1 * x2 + y1 * y2
	)
}

function distance2(x1, y1, x2, y2) {
	let dx = (x1 - x2), dy = (y1 - y2);
	return (
		dx * dx + dy * dy
	);
}

function render(r,s) {
//r.ctx.clearRect(0,0,r.ctx.canvas.width,r.ctx.canvas.height)
	s.update();
	r.render(s)
	aD.forEach(x=>x());
	aD = []
}

onload = start;

function eventHandler() {
	window.keys = {};
	addEventListener("keyup" , e=> {
		keys[e.keyCode] = false;
			
	});

	addEventListener("keydown" , e=> {
		keys[e.keyCode] = true;
	});
}

function CanvasRenderer(dom) {
	if(!dom) dom = document.createElement("canvas");
	
	var events = {}, self = this;
	function rsz() {
		dom.width = dom.clientWidth;
		dom.height = dom.clientHeight;
		self.dispatchEvent("resize");
	}
	
	window.addEventListener("resize", rsz);	

	let ctx = dom.getContext("2d");

	function render(scene) {
		ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
		for(let i = 0; i < scene.objects.length; i++) {
			let o = scene.objects[i],
				verts = o.realVerts;

			
			ctx.beginPath();
			ctx.moveTo(
				verts[0] , 

				verts[1]
			);
			verts.forEach((v, i, ar) => {
				let y = i;
				


				ctx.lineTo(
					v[0] , 

					v[1]
				);
				
			});
			ctx.lineTo(
				verts[0],
				verts[1] 
			);
			ctx.fillStyle = o.color || "blue";
			ctx.lineWidth = 1;
			ctx.fill()
			ctx.stroke();
			ctx.closePath();
		}
	}

	Object.defineProperties(this, {
		domElement: {
			get: () => dom
		},	
		ctx: {
			get: () => ctx
		},
		render: {
			get: () => render
		},
		on: {
			get: () => (nm, cb) => {
				if(!events[nm]) {
					events[nm] = [];
				}
				events[nm].push(data => {
					if(typeof cb == "function") {
						cb(data);
					}
				});
			}		
		},
		dispatchEvent: {
			get: () => (name, data) => {
				if(events[name]) {
					events[name].forEach(x => {
						x(data);
					});
				}
			}
		}
	});
	
	rsz();

}

function scene() {
	let objects = [];
	Object.defineProperties(this, {
		add: {
			get: () => obj => {
				objects.push(obj);
			}
		},
		objects: {
			get: () => objects
		},
		update: {
			get: () => () => {				
				objects.forEach(x => {
					if(typeof x.update == "function") {
						x.update();
					}
				});
				
			}
		}
	});
}

function mesh(data={}) {
	let verts = [],
		self = this,
		holder = {
			position:{},
			scale: {
				
			},
			rotation: {},
			origin:{}
		},
		actual = {
	
		},
		position = {},
		scale = {},
		rotation = {},
		origin = {},
		color,
		name,
		primitive,
		eventNames = "update",
		events = {},
		drawPrimitive = {
			circle(ctx) {
				ctx.beginPath();
				ctx.arc(
					self.position.x,
					self.position.y,
					5, 
					0,
					360 * Math.PI / 180
				);
				ctx.closePath();
			},
			rect(ctx) {
				ctx.strokeRect(
					self.position.x,
					self.position.y,
					30, 30
				);
			}
		},
		width = 1,
		height = 1,
		primitiveToVerts = {
			rect: () =>  [
					0, 0,
					width , 0,
					width, height,
					0, height
			]
		},
		realVerts = verts,
		lineSegments = [],
		o = this;
	
	function updateRealVerts() {
			
			let  actualVerts = [],
				originedVerts = [],
				adjustedVerts = [],
				rotatedVerts = [],
				stepSize = o.step || 2,
				curVerts = [];
			
			o.verts.forEach((v, i) => {
				curVerts.push(v);
				if(
					(i - 1) % stepSize === 0 &&
					i !== 0
				) {
					actualVerts.push(curVerts);
					curVerts = [];
				}
			});
			actualVerts = actualVerts.filter(x => x.length == stepSize);
			
			originedVerts = actualVerts.map(v => [
				v[0] - o.origin.x,
				v[1] - o.origin.y,
				v[2] - o.origin.z
			]);
	
			rotatedVerts = originedVerts.map(v => 
				[

					v[0] * Math.cos(o.rotation.x) - 
					v[1] * Math.sin(o.rotation.x),

					v[0] * Math.sin(o.rotation.x) + 
					v[1] *Math.cos(o.rotation.x),
v[2]
				]
			);

			adjustedVerts = rotatedVerts.map(v => 
				[
					v[0] * 
					o.scale.x + 
					o.position.x,
	
					v[1] * 
					o.scale.y + 
					o.position.y,

					v[2] * 
					o.scale.z + 
					o.position.z,
				]
			);

			realVerts = adjustedVerts;
			updateLineSegments();
	}	

	function updateLineSegments() {
				let lines = [];
				for(let i = 0, a = realVerts; i < a.length;i++) {
					let start = [], end = []
					if(i < a.length - 1) {
						start = a[i];
						end = a[i + 1];
					} else {
						start = a[i];
						end = a[0];
					}

					lines.push({
						start, end
					})
				}
				lineSegments = lines;
	}
	Object.defineProperties(position, {
		x: {
			get: () => holder.position.x || 0,
			set: v => holder.position.x = v
		},
		y: {
			get: () => holder.position.y || 0,
			set: v => holder.position.y = v
		},
		z: {
			get: () => holder.position.z || 0,
			set: v => holder.position.z = v
		}
	});

	Object.defineProperties(scale, {
		x: {
			get: () => holder.scale.x || 1,
			set: v => holder.scale.x = v
		},
		y: {
			get: () => holder.scale.y || 1,
			set: v => holder.scale.y = v
		},
		z: {
			get: () => holder.scale.z || 1,
			set: v => holder.scale.z = v
		}
	});

	Object.defineProperties(rotation, {
		x: {
			get: () => holder.rotation.x || 0,
			set: v => holder.rotation.x = v
		},
		y: {
			get: () => holder.rotation.y || 0,
			set: v => holder.rotation.y = v
		},
		z: {
			get: () => holder.rotation.z || 0,
			set: v => holder.rotation.z = v
		}
	});

	Object.defineProperties(origin, {
		x: {
			get: () => holder.origin.x || 0,
			set: v => holder.origin.x = v
		},
		y: {
			get: () => holder.origin.y || 0,
			set: v => holder.origin.y = v
		},
		z: {
			get: () => holder.origin.z || 0,
			set: v => holder.origin.z = v
		}
	});
	

	Object.defineProperties(this, {
		verts: {
			get: ()=>verts,
			set(v) {
				verts = v
			}
		},
		name: {
			get: ()=>name,
			set(v) {
				name = v
			}
		},
		primitive: {
			get: ()=>primitive,
			set(v) {
				primitive = v;
				let newVerts = primitiveToVerts[v];
				if(newVerts) {
					this.verts = newVerts();
				}
			}
		},
		width: {
			get: ()=>width,
			set(v) {
				width = v
			}
		},
		height: {
			get: ()=>height,
			set(v) {
				height = v
			}
		},
		position: {
			get: () => position,
			set: v => {
				position.x = v.x || 0;
				position.y = v.y || 0;
				position.z = v.z || 0;
			}
		},
		scale: {
			get: () => scale,
			set: v => {
				scale.x = v.x || v.x === 0 ? v.x : 1;
				scale.y = v.y  || v.y === 0 ? v.y : 1;
				scale.z = v.z  || v.z === 0 ? v.z : 1;
			}
		},
		rotation: {
			get: () => rotation,
			set: v => {
				rotation.x = v.x || 0;
				rotation.y = v.y || 0;
				rotation.z = v.z || 0;
			}
		},
		origin: {
			get: () => origin,
			set: v => {
				origin.x = v.x || 0;
				origin.y = v.y || 0;
				origin.z = v.z || 0;
			}
		},
		color: {
			get: () => color,
			set: v => {
				color = v;
			}
		},
		realVerts: {
			get: () => realVerts
		},
		lineSegments: {
			get: () => lineSegments
		},
		update: {
			get: () => () => {
				if(events["update"]) {
					events.update.forEach(x => {
						updateRealVerts();
						x(this);
					});
				}
			}
		},
		on: {
			get: () => (nm, fnc) => {
				if(!events[nm]) events[nm] = [];
				events[nm].push(stuff => {
					if(typeof fnc == "function") {
						fnc(stuff);
					}
				});
			}
		}
	});

	eventNames.split(" ").forEach(x => {
		var name = "on" + x;
		if(!this.hasOwnProperty(name)) {
			Object.defineProperty(this, name, {
				get: () => events[name],
				set(v) {
					events[x] = [
						data => {
							typeof v == "function" && v(data)
						}
					];
				}
			});
		}
	});

	for(let k in data) {
		this[k] = data[k]
	}

	updateRealVerts();

}
canvas{
	width:100%;
	height:100%;
	position:absolute;
	top:0;	
	left:0px
}

.wow{
	float:right;
	z-index:1298737198
}
<meta charset="utf-8">
<button onclick="start()" class=wow>ok</button>
<canvas id=can>

</canvas>

关于JavaScript 在凸形上发生墙壁碰撞,卡在 Angular 落,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61518457/

相关文章:

javascript - 如果存在所选的新数据,如何从本地存储更新数据

java - 在 Java 中为具体类型重写 equals() 有什么好处吗?

java - 当使用 Java Slick 2D 或 .NET XNA 框架时,用户输入如何保持独立于 FPS?

javascript - 为什么这只鸟没有撞到壁架上?

java - 检测圆圈与内部矩形之间的碰撞

javascript - Kinetic JS(用鼠标指针拖动一个球)

javascript - 如何列出对象?

javascript - 如何使用 Wolfpack.js 测试 Sails.js 模型的独特电子邮件属性?

javascript - canvas context.drawImage 跨浏览器的差异?

wpf - 在 WPF 中的绘图和形状之间进行选择