最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - MatterJS in React Native Performance issue - Stack Overflow

matteradmin2PV0评论

I have made a small demo showcasing colliding balls and moving them to a centerpoint. Whilst this works, the performance could be a lot better.

Originally the idea was to create something like a bubble chart, like for example in the following package React-Native-Bubble-Chart. However all packages, libraries, etc. are either out-of-date or simply do not work on both Android & iOS. Therefore I have taken it into my own hands to make something myself.

Like I have said, this example works but the performance is not good. Is it possible to get some advice on this issue?

import React, { FC, useEffect, useRef, useState } from "react";
import { View, StyleSheet, Dimensions } from "react-native";
import Matter from "matter-js";
import Svg, { Circle } from "react-native-svg";

const { width, height } = Dimensions.get("screen");

const PhysicsDemo: FC<{ bubbleData: { name: string; color: string; value: number }[] }> = ({ bubbleData }) => {
  const [bodies, setBodies] = useState<Matter.Body[]>([]);
  const engine = useRef(Matter.Engine.create()).current;
  const world = engine.world;
  const simulationStopped = useRef(false); // Track if we've stopped movement
  const centerCoords = { x: width / 2.5, y: height / 4 }; // The target center coordinates

  useEffect(() => {
    const balls = bubbleData.map((item, i) => {
      return Matter.Bodies.circle(100 + i * 50, 100, item.value * 10, {
        restitution: 0,
        density: item.value * 10 <= 10 ? 0.0025 : item.value * 10 <= 20 ? 0.0005 : 0.00005, // Inverse density scaling
        frictionAir: 0.02 * item.value, // Increase air resistance for bigger bubbles
      });
    });

    Matter.World.add(world, [...balls]);
    setBodies([...balls]);

    // Run physics engine (don't manually setInterval, Matter.js will handle this)
    const runner = Matter.Runner.create();
    Matter.Runner.run(runner, engine);

    // Function to apply force towards the center for each ball
    const applyForceToCenter = () => {
      if (simulationStopped.current) return; // Stop applying force once a ball reaches the center

      let allBallsAtCenter = true;

      for (const ball of balls) {
        const { x: bodyX, y: bodyY } = ball.position;

        // Calculate distance to center
        const forceX = centerCoords.x - bodyX;
        const forceY = centerCoords.y - bodyY;
        const distance = Math.sqrt(forceX ** 2 + forceY ** 2);

        // Only apply force to balls not near the center
        if (distance > 30) {
          allBallsAtCenter = false;

          // Normalize the force to counteract mass difference
          const normalizedX = forceX / distance;
          const normalizedY = forceY / distance;

          // Adjust force based on mass (inversely proportional)
          const massFactor = 1 / (ball.mass || 1); // Avoid division by zero

          // Apply the force
          Matter.Body.applyForce(ball, ball.position, {
            x: normalizedX * 0.005 * massFactor,
            y: normalizedY * 0.005 * massFactor,
          });
        }
      }

      // If all balls are at the center, stop the simulation
      if (allBallsAtCenter) {
        console.log("STOP");
        simulationStopped.current = true;
        balls.forEach((b) => {
          Matter.Body.setVelocity(b, { x: 0, y: 0 });
          Matter.Body.setStatic(b, true);
        });
      }
    };

    const updatePhysics = () => {
      Matter.Engine.update(engine, 1000 / 60); // Update every 16ms (60 FPS)
      applyForceToCenter();
      setBodies([...world.bodies]); // Update bodies for re-render
    };

    const renderLoop = () => {
      if (!simulationStopped.current) {
        updatePhysics();
        requestAnimationFrame(renderLoop); // Continue the loop
      }
    };

    requestAnimationFrame(renderLoop);

    return () => {
      Matter.Engine.clear(engine);
    };
  }, [bubbleData, centerCoords.x, centerCoords.y, engine, world]);

  return (
    <View style={styles.container}>
      <Svg height="100%" width="100%">
        {bodies.map((body, index) =>
          body.circleRadius ? (
            <Circle
              key={index}
              cx={body.position.x}
              cy={body.position.y}
              r={body.circleRadius}
              fill={bubbleData[index - 1]?.color || "red"}
            />
          ) : null,
        )}
      </Svg>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    width: "100%",
    height: "100%",
  },
});

export default PhysicsDemo;
Post a comment

comment list (0)

  1. No comments so far