Good morning, I just conducted tests on box2d and nape drop blocks. I created a starling to test the performance of box2d and nape
This test turned off debugging drawing and used only blocks drawn by Starling for testing. On my current computer, the performance of Nape is slightly better than Box2d. Box2d can only add 600 blocks with a fps of 60, while Nape can add 630 blocks with a fps of 60, a difference of 30 blocks. Of course, the results of testing on my old computer more than 10 years ago showed that my motherboard was still DDR3, and I only tested it on the HTML5 target. I won’t send any pictures, just go ahead and write the code. If you are interested in a detailed physics engine, you can take a look and refer to it. I’m just making a record here. Thank you everyone
I have noticed that there are some differences between the translation software and the meaning I want to express, but I believe that after reading the code and relying on years of development experience, everyone should know what I mean. Thank you, thank you to all contributors, thank you to the haxe openfl community and team
<?xml version="1.0" encoding="utf-8"?>
<project>
<meta title="Box2dnape" package="com.sample.box2dnape" version="1.0.0" company="Company Name" />
<app main="Main" path="Export" file="Box2dnape" />
<window allow-high-dpi="true" />
<source path="Source" />
<haxelib name="openfl" />
<haxelib name="starling" />
<haxelib name="box2d" />
<haxelib name="nape-haxe4" />
<assets path="Assets" rename="assets" />
</project>
package;
import openfl.display.StageAlign;
import openfl.display.StageScaleMode;
import starling.core.Starling;
import openfl.display.Sprite;
class Main extends Sprite {
private var starling:Starling;
public function new() {
super();
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.color = 0x808080;
stage.frameRate = 60;
starling = new Starling(StarlingMain, stage);
starling.supportHighResolutions = true;
starling.showStats = true;
starling.showStatsAt("left", "top", 1.5);
starling.start();
}
}
package;
import starling.events.EnterFrameEvent;
import box2D.collision.shapes.B2CircleShape;
import box2D.dynamics.B2FixtureDef;
import box2D.collision.shapes.B2PolygonShape;
import box2D.dynamics.B2Body;
import box2D.dynamics.B2BodyDef;
import starling.core.Starling;
import box2D.dynamics.B2DebugDraw;
import box2D.common.math.B2Vec2;
import box2D.dynamics.B2World;
import openfl.display.Sprite;
class Box2dMain extends Sprite {
private var PHYSICS_SCALE:Float = 1 / 30;
private var World:B2World;
public function new() {
super();
World = new B2World(new B2Vec2(0, 10.0), true);
var debugDraw:B2DebugDraw = new B2DebugDraw();
debugDraw.setSprite(Starling.current.nativeOverlay);
debugDraw.setFillAlpha(0.5);
debugDraw.setLineThickness(2.0);
debugDraw.setDrawScale(1 / PHYSICS_SCALE);
debugDraw.setFlags(B2DebugDraw.e_shapeBit);
World.setDebugDraw(debugDraw);
}
public function CreateBox(x:Float, y:Float, width:Float, height:Float, dynamicBody:Bool):B2Body {
var bodyDefinition:B2BodyDef = new B2BodyDef();
bodyDefinition.position.x = x * PHYSICS_SCALE;
bodyDefinition.position.y = y * PHYSICS_SCALE;
switch (dynamicBody) {
case false:
bodyDefinition.type = B2Body.b2_staticBody;
case true:
bodyDefinition.type = B2Body.b2_dynamicBody;
}
var polygon:B2PolygonShape = new B2PolygonShape();
polygon.setAsBox((width / 2) * PHYSICS_SCALE, (height / 2) * PHYSICS_SCALE);
var fixtureDefinition:B2FixtureDef = new B2FixtureDef();
fixtureDefinition.density = 5;
fixtureDefinition.friction = 0.5;
fixtureDefinition.restitution = 0.2;
fixtureDefinition.shape = polygon;
var body:B2Body = World.createBody(bodyDefinition);
body.createFixture(fixtureDefinition);
return body;
}
public function CreateCircle(x:Float, y:Float, radius:Float, dynamicBody:Bool):B2Body {
var bodyDefinition:B2BodyDef = new B2BodyDef();
bodyDefinition.position.x = x * PHYSICS_SCALE;
bodyDefinition.position.y = y * PHYSICS_SCALE;
switch (dynamicBody) {
case false:
bodyDefinition.type = B2Body.b2_staticBody;
case true:
bodyDefinition.type = B2Body.b2_dynamicBody;
}
var circle:B2CircleShape = new B2CircleShape(radius * PHYSICS_SCALE);
var fixtureDefinition:B2FixtureDef = new B2FixtureDef();
fixtureDefinition.density = 5;
fixtureDefinition.friction = 0.5;
fixtureDefinition.restitution = 0.2;
fixtureDefinition.shape = circle;
var body:B2Body = World.createBody(bodyDefinition);
body.createFixture(fixtureDefinition);
return body;
}
public function update(e:EnterFrameEvent):Void {
World.step(1 / 30, 10, 10);
// World.clearForces();
// World.drawDebugData();
}
}
package;
import nape.shape.Circle;
import starling.events.EnterFrameEvent;
import nape.phys.BodyType;
import nape.shape.Polygon;
import nape.phys.Body;
import starling.core.Starling;
import nape.geom.Vec2;
import nape.util.ShapeDebug;
import nape.space.Space;
import starling.display.Sprite;
class NapeMain extends Sprite {
private var space:Space;
private var debug:ShapeDebug;
public function new() {
super();
var gravity:Vec2 = new Vec2(0, 10.0 * 30);
space = new Space(gravity);
debug = new ShapeDebug(Starling.current.stage.stageWidth, Starling.current.stage.stageHeight);
debug.thickness = 2;
Starling.current.nativeOverlay.addChild(debug.display);
}
public function CreateBox(x:Float, y:Float, width:Float, height:Float, dynamicBody:Bool = false):Body {
var polygon:Polygon = new Polygon(Polygon.box(width, height));
polygon.material.density = 5;
polygon.material.elasticity = 0.2;
polygon.material.dynamicFriction = 0.5;
polygon.material.staticFriction = 0.7;
var body:Body = new Body();
body.position.x = x;
body.position.y = y;
body.shapes.add(polygon);
body.space = space;
switch (dynamicBody) {
case false:
body.type = BodyType.STATIC;
case true:
body.type = BodyType.DYNAMIC;
}
return body;
}
public function CreateCircle(x:Float, y:Float, radius:Float, dynamicBody:Bool = false):Body {
var circle:Circle = new Circle(radius);
circle.material.density = 5;
circle.material.elasticity = 0.2;
circle.material.dynamicFriction = 0.5;
circle.material.staticFriction = 0.7;
circle.material.rollingFriction = 0.001;
var body:Body = new Body();
body.position.x = x;
body.position.y = y;
body.shapes.add(circle);
body.space = space;
switch (dynamicBody) {
case false:
body.type = BodyType.STATIC;
case true:
body.type = BodyType.DYNAMIC;
}
return body;
}
public function update(e:EnterFrameEvent):Void {
space.step(1 / 30, 10, 10);
// debug.clear();
// debug.draw(space);
}
}
package;
import nape.phys.Body;
import starling.display.Canvas;
import openfl.geom.Point;
import box2D.common.math.B2Vec2;
import box2D.dynamics.B2Body;
import starling.events.EnterFrameEvent;
import starling.events.Event;
import starling.display.Sprite;
class StarlingMain extends Sprite {
// private var bns:Box2dMain; // box2d
private var bns:NapeMain; // nape
// private var bodyArr:Array<B2Body> = []; // box2d
private var bodyArr:Array<Body> = []; // nape
private var ii:Int = 0;
public function new() {
super();
this.addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event):Void {
this.removeEventListener(Event.ADDED_TO_STAGE, init);
// bns = new Box2dMain(); // box2d
bns = new NapeMain(); // nape
bns.CreateBox(0, stage.stageHeight / 2, 10, stage.stageHeight, false);
bns.CreateBox(stage.stageWidth, stage.stageHeight / 2, 10, stage.stageHeight, false);
bns.CreateBox(stage.stageWidth / 2, stage.stageHeight, stage.stageWidth, 10, false);
this.addEventListener(EnterFrameEvent.ENTER_FRAME, update);
}
private function adds(x:Float, y:Float, w:Float, h:Float):Sprite {
final node:Sprite = new Sprite();
node.pivotX = w / 2;
node.pivotY = h / 2;
node.x = x;
node.y = y;
this.addChild(node);
final cc:Canvas = new Canvas();
cc.beginFill(0xff0000, 0.5);
cc.drawRectangle(0, 0, w, h);
node.addChild(cc);
return node;
}
private function update(e:EnterFrameEvent):Void {
bns.update(e);
ii += 1;
if (ii < 650) {
final node:Sprite = adds(0, 0, 30, 30);
final body = bns.CreateBox(30 + Math.random() * stage.stageWidth - 30, -100, 30, 30, true);
// body.setUserData(node); // box2d
body.userData.dis = node; // nape
bodyArr.push(body);
}
for (i in 0...bodyArr.length) {
final body = bodyArr[i];
// final dis:Sprite = body.getUserData(); // box2d
final dis:Sprite = body.userData.dis; // nape
// final position = body.getPosition(); // box2d
final position = body.position; // nape
// final rotation:Float = body.getAngle(); // box2d
final rotation:Float = body.rotation; // nape
// final xx:Float = position.x * 30; // box2d
// final yy:Float = position.y * 30; // box2d
final xx:Float = position.x; // nape
final yy:Float = position.y; // nape
final po:Point = this.globalToLocal(new Point(xx, yy));
dis.x = po.x;
dis.y = po.y;
dis.rotation = rotation;
}
}
}