I am re-writing a game a made using easlejs with Box2Dweb to flutter's flame engine with the dart port of box2d. My problem is that the objects are move really really slow. Gravity setting seems to progress in a linear fashion.
I read about scale factors etc... just don't know how to link it all. The World class does not have that,
can someone show me an example of how to setup the initial screen to box2d world ratios?
I get the screenSize using flames resize override I want to use that to set the scale or whatever works.
The examples in GitHub never seem to use that and even when I download then and run them... again painfully slow falling bodies.
A simple screen with a circle or a Square falling (correctly) will be appreciated.
Here's how I instantiate the code. (I need the object to be 80x80 pixels)
class MyGame extends Game with TapDetector {
MyGame() : _world = Box2D.World.withGravity(Box2D.Vector2(0, 10)) {
_world.setAllowSleep(true);
spawnBlocks();
}
void createSquare(int index, double w, double h, double x, double y) {
int randomNumber = random.nextInt(letters.length);
var bodyDef = Box2D.BodyDef();
bodyDef.type = Box2D.BodyType.DYNAMIC;
bodyDef.position = Box2D.Vector2(x - 5, y);
bodyDef.angle = 0;
dynamicBody = _world.createBody(bodyDef);
dynamicBody.userData = letters[randomNumber];
var boxShape = Box2D.PolygonShape();
boxShape.setAsBox(w / 2, h / 2, Box2D.Vector2(w / 2, -h * 2), 0);
var boxFixtureDef = Box2D.FixtureDef();
boxFixtureDef.shape = boxShape;
boxFixtureDef.density = 0;
boxFixtureDef.restitution = 0;
boxFixtureDef.friction = 1;
dynamicBody.createFixtureFromFixtureDef(boxFixtureDef);
blocks.add(dynamicBody);
}
spawnBlocks() {
for (var i = 0; i < 8; i++) {
createSquare(
i, blockWidth, blockHeight, blockWidth * i + 18, -100 * i.toDouble());
}
}
}
It doesn't matter how high I set the gravity, the body still falls at the same speed.
Even when they hit the floor they bounce very slowly, I have used the body.setTransform to increase the position.y etc but it just seems to move right through the static body(floor).
Since the density of your square is 0 it is not affected by gravity, try to set it to something higher and see if the objects are more affected.
Don't use the body.setTransform if you don't really need to, since it will break the physics set up in the world.
Did you try this example?
https://github.com/flame-engine/flame/tree/master/doc/examples/box2d/contact_callbacks
And don't forget to add the scale argument to your world, otherwise you'll hit the speed limits quite fast since you'll be so zoomed out.
I'm the maintainer of box2d for flame (now Forge2D), if you have more questions you can join the box2d channel on our discord and I'll try to help you.
Related
I am making a scientific visualization app of the Galaxy. Among other things, it displays where certain deep sky objects (stars, star clusters, nebulae, etc) are located in and around the Galaxy.
There are 6 or 7 classes of object types (stars, star clusters, nebulae, globular clusters, etc). Each object within a class looks the same (i.e. using the same image).
I've tried creating GameObjects for each deep sky object, but the system can get bogged down with many objects (~10,000). So instead I create a particle system for each class of deep sky object, setting the specific image to display for each class.
Each particle (i.e. deep sky object) is created at the appropriate location and then I do a SetParticles() to add them to that class's particle system. This works really well and I can have 100,000 objects (particles) with decent performance.
However, I need to allow the user to click/tap on an object to select it. I have not found any examples of how to do hit testing on individual particles in the particle system. Is this possible in Unity?
Thanks,
Bill
You'll have to do the raycasting yourself.
Just implement a custom raycasting algorithm using a simple line rectangle intersection. Simply assume a small rectangle at each particle's position. Since you do not rely on Unity's built in methods you can do this async. For performance optimization you can also cluster the possible targets at simulation start, allowing the elimination of whole clusters when their bounding box is not hit by your ray.
Note: Imho you should choose a completely different approach for your data rendering.
Take a look at unity's entity component system. This allows for large amounts of data, but comes with some disadvantages (e.g. when using Unity's physics engine) (which will not be of relevance for your case I suppose).
I ended up rolling my own solution.
In Update(), upon detecting a click, I iterate through all the particles. For each particle, I calculate its size on the screen based on the particle's size and its distance from the camera.
Then I take the particle's position and translate that into screen coordinates. I use the screen size to generate a bounding rectangle and then test to see if the mouse point is inside it.
As I iterate through the particles I keep track of which is the closest hit. At the end, that is my answer.
if (Input.GetMouseButtonDown(0))
{
Particle? closestHitParticle = null;
var closestHitDist = float.MaxValue;
foreach (var particle in gcParticles)
{
var pos = particle.position;
var size = particle.GetCurrentSize(gcParticleSystem);
var distance = Vector3.Distance(pos, camera.transform.position);
var screenSize = Utility.angularSizeOnScreen(size, distance, camera);
var screenPos = camera.WorldToScreenPoint(pos);
var screenRect = new Rect(screenPos.x - screenSize / 2, screenPos.y - screenSize / 2, screenSize, screenSize);
if (screenRect.Contains(Input.mousePosition) && distance < closestHitDist)
{
closestHitParticle = particle;
closestHitDist = distance;
}
}
if (closestHitDist < float.MaxValue)
{
Debug.Log($"Hit particle at {closestHitParticle?.position}");
}
Here is the angularSizeOnScreen method:
public static float angularSizeOnScreen (float diam, float dist, Camera cam)
{
var aSize = (diam / dist) * Mathf.Rad2Deg;
var pSize = ((aSize * Screen.height) / cam.fieldOfView);
return pSize;
}
I've been working on a scene in Unity3D where I have the KinectV2 depth information coming in at 512 x 424 and I'm converting that in real time to Mesh that is also 512 x 424. So there is a 1:1 ratio of pixel data (depth) and vertices (mesh).
My end goal is to make the 'Monitor 3D View' scene found in 'Microsoft Kinect Studio v2.0' with the Depth.
I've pretty much got it working in terms of the point cloud. However, there is a large amount of warping in my Unity scene. I though it might of been down to my maths, etc.
However I noticed that its the same case for the Unity Demo kinect supplied in their Development kit.
I'm just wondering if I'm missing something obvious here? Each of my pixels (or vertices in this case) is mapped out in a 1 by 1 fashion.
I'm not sure if its because I need to process the data from the DepthFrame before rendering it to scene? Or if there's some additional step I've missed out to get the true representation of my room? Because it looks like theres a slight 'spherical' effect being added right now.
These two images are a top down shot of my room. The green line represents my walls.
The left image is the Kinect in a Unity scene, and the right is within Microsoft Kinect Studio. Ignoring the colour difference, you can see that the left (Unity) is warped, whereas the right is linear and perfect.
I know it's quite hard to make out, especially that you don't know the layout of the room I'm sat in :/ Side view too. Can you see the warping on the left? Use the green lines as a reference - these are straight in the actual room, as shown correctly on the right image.
Check out my video to get a better idea:
https://www.youtube.com/watch?v=Zh2pAVQpkBM&feature=youtu.be
Code C#
Pretty simple to be honest. I'm just grabbing the depth data straight from the Kinect SDK, and placing it into a point cloud mesh on the Z axis.
//called on application start
void Start(){
_Reader = _Sensor.DepthFrameSource.OpenReader();
_Data = new ushort[_lengthInPixels];
_Sensor.Open();
}
//called once per frame
void Update(){
if(_Reader != null){
var dep_frame = _Reader.AcquireLatestFrame();
dep_frame.CopyFrameDataToArray(_Data);
dep_frame.Dispose();
dep_frame = null;
UpdateScene();
}
}
//update point cloud in scene
void UpdateScene(){
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int index = (y * width) + x;
float depthAdjust = 0.1;
Vector3 new_pos = new Vector3(points[index].x, points[index].y, _Data[index] * depthAdjust;
points[index] = new_pos;
}
}
}
Kinect API can be found here:
https://msdn.microsoft.com/en-us/library/windowspreview.kinect.depthframe.aspx
Would appreciate any advise, thanks!
With thanks to Edward Zhang, I figured out what I was doing wrong.
It's down to me not projecting my depth points correctly, in where I need to use the CoordinateMapper to map my DepthFrame into CameraSpace.
Currently, my code assumes an orthogonal depth instead of using a perspective depth camera. I just needed to implement this:
https://msdn.microsoft.com/en-us/library/windowspreview.kinect.coordinatemapper.aspx
//called once per frame
void Update(){
if(_Reader != null){
var dep_frame = _Reader.AcquireLatestFrame();
dep_frame.CopyFrameDataToArray(_Data);
dep_frame.Dispose();
dep_frame = null;
CameraSpacePoint[] _CameraSpace = new CameraSpacePoint[_Data.Length];
_Mapper.MapDepthFrameToCameraSpace(_Data, _CameraSpace);
UpdateScene();
}
}
//update point cloud in scene
void UpdateScene(){
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int index = (y * width) + x;
Vector3 new_pos = new Vector3(_CameraSpace[index].X, _CameraSpace[index].Y, _CameraSpace[index].Z;
points[index] = new_pos;
}
}
}
I have a problem with trying to keep my character from rolling over, yet allow it to pitch and yaw. The suggestions I have seen have been to lock different axis, but no matter if I lock the x, y, or z axis I always run into a situation where the character can fall over. The best I can get is to lock both the y and z axis. This allows the character to change pitch to conform to the terrain. But, again, if I turn left or right while going up or down a hill and I can roll the character over.
Here is my current code for movement (in case it helps). I have no other code and my rigid body is all defaults. I have a mesh collier for the character set to convex but defaults otherwise.
Any suggestions on how to make this work?
Here's a live demo of y and z axis being locked. Just waltz up the hill and hang a left or right and you'll fall over. (ASWD controls)
https://dl.dropboxusercontent.com/u/27946381/Builds/builds.html
Thanks so much!
var speed = 3.0;
var rotateSpeed = 3.0;
function FixedUpdate() {
var hAxis = 0;
var vAxis = 0;
if( Input.GetAxis("Horizontal") > 0 ) { hAxis = 1.0; } else if( Input.GetAxis("Horizontal") < 0 ) { hAxis = -1.0; } else { hAxis = 0.0; }
if( Input.GetAxis("Vertical") > 0 ) { vAxis = 1.0; } else if( Input.GetAxis("Vertical") < 0 ) { vAxis = -1.0; } else { vAxis = 0.0; }
var rigidBody: Rigidbody = GetComponent(Rigidbody);
// Rotate around y axis
// transform.Rotate(0, hAxis * rotateSpeed, 0);
var deltaRotation : Quaternion = Quaternion.Euler(0, hAxis * rotateSpeed, 0);
rigidbody.MoveRotation(rigidbody.rotation * deltaRotation);
// Move forward / backward
var forward = transform.TransformDirection(Vector3.forward);
var currSpeed = speed * vAxis;
rigidBody.MovePosition( rigidBody.position + (forward * currSpeed) );
var animatorController: Animator = GetComponent(Animator);
animatorController.SetFloat("Speed", currSpeed);
}
well maybe you should check your rigidbody properties called gravity scale.. set it to 0 and you will never fall
I believe your problem is in these MovePosition and MoveRotation. Take a look into scripting reference - these methods basically ignores collision until body is teleported at the specified pose. I.e. you may place the body into some kind of irresolvable situation, when physics engice unable to find appropriate forces to push the body away from another collider, and therefore the body will fall through. In this case it is better to use AddForce and AddTorque.
Also, you can use CharacterController instead of RigidBody. Though it cannot be rotated at all, there are fine methods for kinematic motion with precise collision detection. And you can attach another body to the character controller and rotate it as you wish.
Changing code will change nothing.
Try changing the hitbox of the player to a big cube
(Better) Try to look into the rigidbody properties, as far as I remember I had the same problem and fixed it that way, it might help
I am having trouble keeping game objects inside of a contained space. When they reach the edge, there is some momentary push back but then they will go right through the wall.
I am using a Box Collider on the player, and a Mesh Collider for the level's wall. I am having issues with both a Player Character (a space ship) that the movement is controlled by the player. And with projectiles, which are fire and forget moving at a constant speed.
This is my movement code for my player. It is being run in the FixedUpdate() function.
//Movement
haxis = Input.GetAxis("Horizontal") * speed;
vaxis = Input.GetAxis("Vertical") * speed;
moveVector.x = haxis;
moveVector.z = vaxis;
if(moveVector.magnitude > 1)
{
moveVector.Normalize();
}
rigidbody.MovePosition(transform.position + moveVector * speed);
With the bullets, they are given a velocity and the engine calculates their moviements. They are using Box Collider and it is set as a Trigger so they don't have physics. But I use OnTriggerEnter to destroy them.
//Projectiles without physics collisiions
function OnTriggerEnter (other : Collider) {
Destroy(gameObject);
}
Some, but not all of the bullets will be destroyed when hitting the mesh collider wall. The player will sometimes hit it and stop, but can usually push through it. How can I make the collisions with the mesh collider work every time?
Collision with fast-moving objects is always a problem. A good way to ensure that you detect all collision is to use Raycasting instead of relying on the physics simulation. This works well for bullets or small objects, but will not produce good results for large objects.
http://unity3d.com/support/documentation/ScriptReference/Physics.Raycast.html
Pseudo-codeish (I don't have code-completion here and a poor memory):
void FixedUpdate()
{
Vector3 direction = new Vector3(transform.position - lastPosition);
Ray ray = new Ray(lastPosition, direction);
RaycastHit hit;
if (Physics.Raycast(ray, hit, direction.magnitude))
{
// Do something if hit
}
this.lastPosition = transform.position;
}
I have a pinball prototype that also gave me much trouble in the same areas. These are all the steps I've taken to almost (but not yet entirely) solve these problems:
For fast moving objects:
Set the rigidbody's Interpolate to 'Interpolate' (this does not affect the actual physics simulation, but updates the rendering of the object properly - use this only on important objects from a rendering point of view, like the player, or a pinball, but not for projectiles)
Set Collision Detection to Continuous Dynamic
Attach the script DontGoThroughThings (https://www.auto.tuwien.ac.at/wordpress/?p=260) to your object. This script cleverly uses the Raycasting solution I posted in my other answer to pull back offending objects to before the collision points.
In Edit -> Project Settings -> Physics:
Set Min Penetration for Penalty to a very low value. I've set mine to 0.001
Set Solver Iteration Count to a higher value. I've set mine to 50, but you can probably do ok with much less.
All that is going to have a penalty in performace, but that's unavoidable. The defaults values are soft on performance but are not really intented for proper simulation of small and fast-moving objects.
How about set the Collision Detection of rigidbody to Continuous or Continuous Dynamic?
http://unity3d.com/support/documentation/Components/class-Rigidbody.html
So I haven't been able to get the Mesh Colliders to work. I created a composite collider using simple box colliders and it worked exactly as expected.
Other tests with simple Mesh Colliders have come out the same.
It looks like the best answer is to build a composite collider out of simple box/sphere colliders.
For my specific case I wrote a Wizard that creates a Pipe shaped compound collider.
#script AddComponentMenu("Colliders/Pipe Collider");
class WizardCreatePipeCollider extends ScriptableWizard
{
public var outterRadius : float = 200;
public var innerRadius : float = 190;
public var sections : int = 12;
public var height : float = 20;
#MenuItem("GameObject/Colliders/Create Pipe Collider")
static function CreateWizard()
{
ScriptableWizard.DisplayWizard.<WizardCreatePipeCollider>("Create Pipe Collider");
}
public function OnWizardUpdate() {
helpString = "Creates a Pipe Collider";
}
public function OnWizardCreate() {
var theta : float = 360f / sections;
var width : float = outterRadius - innerRadius;
var sectionLength : float = 2 * outterRadius * Mathf.Sin((theta / 2) * Mathf.Deg2Rad);
var container : GameObject = new GameObject("Pipe Collider");
var section : GameObject;
var sectionCollider : GameObject;
var boxCollider : BoxCollider;
for(var i = 0; i < sections; i++)
{
section = new GameObject("Section " + (i + 1));
sectionCollider = new GameObject("SectionCollider " + (i + 1));
section.transform.parent = container.transform;
sectionCollider.transform.parent = section.transform;
section.transform.localPosition = Vector3.zero;
section.transform.localRotation.eulerAngles.y = i * theta;
boxCollider = sectionCollider.AddComponent.<BoxCollider>();
boxCollider.center = Vector3.zero;
boxCollider.size = new Vector3(width, height, sectionLength);
sectionCollider.transform.localPosition = new Vector3(innerRadius + (width / 2), 0, 0);
}
}
}
1.) Never use MESH COLLIDER. Use combination of box and capsule collider.
2.) Check constraints in RigidBody. If you tick Freeze Position X than it will pass through the object on the X axis. (Same for y axis).
Old Question but maybe it helps someone.
Go to Project settings > Time and Try dividing the fixed timestep and maximum allowed timestep by two or by four.
I had the problem that my player was able to squeeze through openings smaller than the players collider and that solved it. It also helps with stopping fast moving objects.
Edit ---> Project Settings ---> Time ... decrease "Fixed Timestep" value .. This will solve the problem but it can affect performance negatively.
Another solution is could be calculate the coordinates (for example, you have a ball and wall. Ball will hit to wall. So calculate coordinates of wall and set hitting process according these cordinates )
Try setting the models to environment and static. That fix my issue.
I'm developing a game on iOS w/ cocos2d+box2d as the game engine, and am trying to add a CCRibbon (wherein the points get populated with touches), that I know how to, and to get that CCRibbon's shape linked up to box2d, so when an object collides with it (due to gravity), it bounces off as if it were a normal thing. Would anyone happen to know how to do this / give me alternatives ?
Many thanks,
Alexandre Cassagne
Take each point and create a thin static rectangular box2d polygon using the points + the adjustment to make it a shape.
for (int i = 0; i < ccribbon.points.length - 1; i++)
{
int j = i;
j++;
int width = 2;
Array ar = [];
ar[0] = new b2Vec2(ccribbon.points[i].x, ccribbon.points[i].y);
ar[1] = new b2Vec2(ccribbon.points[i].x + width, ccribbon.points[i].y + width);
ar[2] = new b2Vec2(ccribbon.points[j].x, ccribbon.points[j].y);
ar[3] = new b2Vec2(ccribbon.points[j].x + width, ccribbon.points[j].y + width);
//create new static object
b2Polygon b2p = new b2Polygon();
b2p.setAsArray(ar);
//do rest to add it to world etc.
}
of course don't copy that code exactly its just from what i remember and i'm also sure its a combination of C# and Actionscript 3. its kindof a not so pseudo code with lots of blanks you'll need to fill in. Why the comments are there :P.
Thats basically how i would do it though. My experience is only in box2d for flash though.
Have you read this....http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone