Javascript React本地游戏引擎+;matter.js物体的动态比例
我正在尝试用圆形物体(气泡)构建一个屏幕。气泡应能够以一定间隔改变刻度,例如每3秒和随机值(从1到3)。刻度应该改变气泡的大小和质量 召唤 物质、身体、尺度 没有任何效果。泡沫保持不变。可能是因为我没有使用带有纹理的精灵,而是使用渲染器为React.PureComponent的游戏引擎实体。不确定 气泡节点:Javascript React本地游戏引擎+;matter.js物体的动态比例,javascript,react-native,matter.js,Javascript,React Native,Matter.js,我正在尝试用圆形物体(气泡)构建一个屏幕。气泡应能够以一定间隔改变刻度,例如每3秒和随机值(从1到3)。刻度应该改变气泡的大小和质量 召唤 物质、身体、尺度 没有任何效果。泡沫保持不变。可能是因为我没有使用带有纹理的精灵,而是使用渲染器为React.PureComponent的游戏引擎实体。不确定 气泡节点: export interface BubbleProps { body: Matter.Body; item: Item; } class BubbleNode extends
export interface BubbleProps {
body: Matter.Body;
item: Item;
}
class BubbleNode extends React.Component<BubbleProps> {
render() {
const {body, item} = this.props;
const x = body.position.x - body.circleRadius;
const y = body.position.y - body.circleRadius;
const style: ViewStyle = {
position: 'absolute',
left: x,
top: y,
width: body.circleRadius * 2,
height: body.circleRadius * 2,
backgroundColor: item.color,
borderRadius: body.circleRadius,
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden',
padding: 3,
};
return <View style={style}>{item.content}</View>;
}
}
更新方法:
// find out if the entity was already added to the world
if (Object.prototype.hasOwnProperty.call(entities, id)) {
//update scale
const scale = bubble.item.scale
Matter.Body.scale(bubble.body, scale, scale)
} else {
//add new entity
entities[id] = bubble;
Matter.World.add(physics.world, [bubble.body]);
}
另外,我需要使缩放平滑
编辑:
有趣的事。我能够使用Matter.Body.scale缩放气泡,但就在添加到世界之前。我想知道是否有一种方法可以在添加到世界之后更新身体
最终编辑
这是我用来为GameEngine框架设置世界和指定实体的方法
private setupWorld = (layout: LayoutRectangle) => {
const engine = Matter.Engine.create({enableSleeping: false});
const world = engine.world;
world.gravity.x = 0;
world.gravity.y = 0;
//center gravity body
Matter.use(MatterAttractors);
var attractiveBody = Matter.Bodies.circle(
layout.width / 2,
layout.height / 2,
1,
{
isSensor: true,
plugin: {
attractors: [centerGravity],
},
},
);
Matter.World.add(world, attractiveBody);
//walls
const wallThickness = 5;
let floor = Matter.Bodies.rectangle(
layout.width / 2,
layout.height - wallThickness / 2,
layout.width,
wallThickness,
{isStatic: true},
);
let ceiling = Matter.Bodies.rectangle(
layout.width / 2,
wallThickness / 2,
layout.width,
wallThickness,
{isStatic: true},
);
let left = Matter.Bodies.rectangle(
wallThickness / 2,
layout.height / 2,
wallThickness,
layout.height,
{isStatic: true},
);
let right = Matter.Bodies.rectangle(
layout.width - wallThickness / 2,
layout.height / 2,
wallThickness,
layout.height,
{isStatic: true},
);
Matter.World.add(world, [floor, ceiling, left, right]);
//basic entitites
this.entities = {
physics: {engine, world},
floor: {body: floor, color: 'green', renderer: Wall},
ceiling: {body: ceiling, color: 'green', renderer: Wall},
left: {body: left, color: 'green', renderer: Wall},
right: {body: right, color: 'green', renderer: Wall},
};
};
这是一个由父组件以一定间隔触发的方法
public updateNodes = (items: Item[]) => {
if (!this.state.mounted || !this.entities || !this.entities.physics || !this.layout) {
console.log('Missiing required data');
return;
}
const layout = this.layout
const entities = this.entities
const bubbles: BubbleEntity[] = items.map((item) => {
const randomX = randomPositionValue(layout.width);
const randomY = randomPositionValue(layout.height);
const body = Matter.Bodies.circle(
randomX,
randomY,
RADIUS, {
mass: 30,
}
);
body.label = item.id
return {
body,
item,
renderer: BubbleNode,
};
});
const physics = this.entities.physics as PhysicsEntity;
const allBodies = Matter.Composite.allBodies(physics.world)
bubbles.forEach((bubble) => {
//update existing or add new
const id = `bubble#${bubble.item.id}`;
if (Object.prototype.hasOwnProperty.call(entities, id)) {
//do physical node update here
//update scale and mass
const scale = bubble.item.scale
console.log('Updating item', id, scale);
//right her there used to be an issue because I used **bubble.body** which was not a correct reference to the world's body.
//so when I started to use allBodies array to find a proper reference of the body, everything started to work
let body = allBodies.find(item => item.label === bubble.item.id)
if (!!body) {
const scaledRadius = RADIUS*scale
const current = body.circleRadius || RADIUS
const scaleValue = scaledRadius/current
Matter.Body.scale(body, scaleValue, scaleValue)
}else{
console.warn('Physycal body not found, while the entity does exist');
}
} else {
console.log('Adding entity to the world');
entities[id] = bubble;
Matter.World.add(physics.world, [bubble.body]);
}
});
this.entities = entities
};
在未来,我将改进代码,我将为主体使用一些变量,并将创建一个matter.js插件,该插件将允许我平滑地缩放主体,而不是像现在这样即时缩放。此外,上面的方法需要一些干净、简短的实现,而不是我试图让它工作时所做的垃圾您的示例并不完全完整;目前尚不清楚MJS发动机是如何(或是否)运转的。第一步是使用循环中的调用确保有一个实际的渲染循环 反应在这里似乎并不重要。它不应该影响结果,因为MJS引擎中每个实体的x/y坐标和半径都被提取出来并传递给视图组件,因此数据沿一个方向流动。我将在本例的其余部分略去这一点,但一旦你让MJS一方工作到你满意的程度,应该很容易重新介绍它 在MJS中缩放身体的方法是调用。此函数用于重新计算身体的其他物理特性,如质量 这个函数有一个优点:它没有像JS画布上下文或CSS转换那样设置绝对比例,而是设置相对比例。这意味着对该函数的每次调用都会更改未来调用的基线比例。这样做的问题是舍入误差可能会累积并发生漂移。这也使得应用定制的tweens变得困难 解决方法可能取决于您希望实现的实际动画是什么(甚至可能不是必需的),因此我将避免规定任何过于具体的内容,而不是建议将与半径相关的书写逻辑作为参考点,以确保其保持在范围内。其他解决方法包括重新创建和缩放每帧的圆 当使用圆时,另一个难题是意识到,当放大时,小圆会失去分辨率。同样,这取决于用例,但您可能希望创建一个包含更多方面的应用程序,而不是在您遇到异常行为时创建的应用程序 这就是说,这里有一个简单完整的简单缩放示例,它向您展示了如何运行动画循环并调用
scale
随时间动态调整它。认为它是一个概念证明,并且需要适应你的用例(无论它是什么)的工作。
const-engine=Matter.engine.create();
常量圆=[…数组(15)].map((ux,i)=>{
常量elem=document.createElement(“div”);
元素类列表。添加(“圆圈”);
文件.正文.附加(elem);
const body=Matter.Bodies.circle(
//x,y,半径
10*i+60,0,Math.random()*5+20
);
返回{
埃伦,
身体,
抵消:我,
scaleAmt:0.05,
速度:0.25,
};
});
const mouseConstraint=Matter.mouseConstraint.create(
引擎,{element:document.body}
);
常数墙=[
长方形(
//x,y,宽度,高度
innerWidth/2,0,innerWidth,40,{isStatic:true}
),
长方形(
innerWidth/2180,innerWidth,40,{isStatic:true}
),
长方形(
0,innerHeight/2,40,innerHeight,{isStatic:true}
),
长方形(
300,innerHeight/2,40,innerHeight,{isStatic:true}
),
];
Matter.World.add(
引擎世界,
[mouseConstraint,…walls,…circles.map(e=>e.body)]
);
/*
缓解随时间推移的缩放漂移的简单方法。
更好的方法是按半径成比例缩放。
*/
常数基标度=1.00063;
(函数更新(){
requestAnimationFrame(更新);
圆。forEach(e=>{
常数{body,elem}=e;
常数{x,y}=body.position;
常数{circleRadius:radius}=体;
常量比例=基本比例+e.scalemt*Math.sin(e.offset);
物质。身体。尺度(身体,尺度,尺度);
e、 偏移量+=e.速度;
elem.style.top=`y-radius/2}px`;
elem.style.left=`${x-radius/2}px`;
elem.style.width=`${2*半径}px`;
elem.style.height=`${2*半径}px`;
elem.style.transform=`rotate(${body.angle}rad)`;
});
物质。引擎。更新(引擎);
})();代码>
*{
保证金:0;
填充:0;
}
正文,html{
身高:100%;
}
.圆圈{
边界半径:50%;
位置:绝对位置;
光标:移动;
背景:rgb(23,0,36,1);
背景:线性梯度(
90度,
rgba(23,0,36,1)0%,
rgba(0,212,255,1)100%
);
}
您如何运行Matter.js引擎?我认为React在这里没有太大的相关性;我会把它和一个需要在不使用渲染器的情况下向前推进引擎并缩放实体的过程分开,然后在你让React单独在MJS中工作后将其插入React。嘿。谢谢你的回答。实际上,我能够解决我的问题。我使用游戏引擎的entities对象来存储对物质实体的引用,这似乎不起作用。在我的更新方法中,我决定使用Matter.Composite.allbody(physics.world)来找到一个
public updateNodes = (items: Item[]) => {
if (!this.state.mounted || !this.entities || !this.entities.physics || !this.layout) {
console.log('Missiing required data');
return;
}
const layout = this.layout
const entities = this.entities
const bubbles: BubbleEntity[] = items.map((item) => {
const randomX = randomPositionValue(layout.width);
const randomY = randomPositionValue(layout.height);
const body = Matter.Bodies.circle(
randomX,
randomY,
RADIUS, {
mass: 30,
}
);
body.label = item.id
return {
body,
item,
renderer: BubbleNode,
};
});
const physics = this.entities.physics as PhysicsEntity;
const allBodies = Matter.Composite.allBodies(physics.world)
bubbles.forEach((bubble) => {
//update existing or add new
const id = `bubble#${bubble.item.id}`;
if (Object.prototype.hasOwnProperty.call(entities, id)) {
//do physical node update here
//update scale and mass
const scale = bubble.item.scale
console.log('Updating item', id, scale);
//right her there used to be an issue because I used **bubble.body** which was not a correct reference to the world's body.
//so when I started to use allBodies array to find a proper reference of the body, everything started to work
let body = allBodies.find(item => item.label === bubble.item.id)
if (!!body) {
const scaledRadius = RADIUS*scale
const current = body.circleRadius || RADIUS
const scaleValue = scaledRadius/current
Matter.Body.scale(body, scaleValue, scaleValue)
}else{
console.warn('Physycal body not found, while the entity does exist');
}
} else {
console.log('Adding entity to the world');
entities[id] = bubble;
Matter.World.add(physics.world, [bubble.body]);
}
});
this.entities = entities
};