Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

1 decade ago by AzZzOne

Hi guys! I'm trying to implement a chain entity in my game so i can use it in weltmeister but it doesn't work.I've read tutorials about this but i can't undrestand how to recreate it with impact.. So if some of you knows how to make it work i'll appreciate if you share

1 decade ago by Joncom

Here's a tutorial on how to do a chain in Box2D.

The challenge will be to port the code into JavaScript.

The biggest potential issue you may encounter is that the ImpactJS Box2D plugin uses a different namespace than is used in the tutorial.

For example, the line:
local shape = b2.CircleShape.new(0, 0, radius)

...would probably look like this:
var shape = new Box2D.Collision.Shapes.b2CircleShape(radius);

Here's a good Box2D reference that's valid for ImpactJS use.

1 decade ago by AzZzOne

Thanks for your answer, Joncom! I've tried to port this code into JS but it still doesn't work. i'm new in box2d so it's really hard for me. Can you please see what i'm doing wrong. Here's my code :
ig.module(
  'game.entities.chain'
  )
  .requires(
  'plugins.box2d.entity'
 )
.defines(function(){
	
	
			 EntityChain = ig.Box2DEntity.extend({
			//	 _wmScalable: true,
			 // _wmDrawBox: true,
	        _wmBoxColor: 'rgba(150, 150, 0, 0.7)',
			 radius: 10,
			 amount:5,
	 
 
               createBody: function() {
          
	 
			
			//ground
		 var groundDef =  new Box2D.Dynamics.b2BodyDef(); 
		  
         this.ground = ig.world.CreateBody(groundDef);
		
		// chain's def
		 
           	var prevBody = this.ground; 
			 
            var shapeDef = new Box2D.Collision.Shapes.b2CircleShape();
            shapeDef.SetRadius(this.radius * Box2D.SCALE);

            var fixtureDef = new Box2D.Dynamics.b2FixtureDef();
            fixtureDef.shape = shapeDef;
            fixtureDef.density = 1.0;
            fixtureDef.friction = 1;
            fixtureDef.restitution = 0.3;
			
		 
		 // create a chain
		 	for (var i=0; i <this.amount;i++) {
				
			 var newX = (this.pos.x + this.radius) * Box2D.SCALE ;
			 var newY = (this.pos.y + this.radius*i) * Box2D.SCALE ;
				 console.log(newX,newY);
				 
		  
				  var chainBodyDef = new Box2D.Dynamics.b2BodyDef(); 
				  chainBodyDef.type = this.bodyType;
				   chainBodyDef.position.Set(  newX,  newY);
				   
				   
			this.chainBody = ig.world.CreateBody(chainBodyDef);
			 this.chainBody.CreateFixture(fixtureDef);
			  console.log('create');
 	 //joint
		  var jointDef = new Box2D.Dynamics.Joints.b2RevoluteJointDef();
			   jointDef.Initialize(prevBody,this.chainBody,newX,newY);
			       this.revJoint = ig.world.CreateJoint(jointDef); 
			          jointDef.maxMotorTorque=1;
			              jointDef.enableMotor=true;
			  
			   prevBody = this.chainBody;  
			    
			 }; 

            
        }
			 });
});

And as a result i get a frozen progress bar window with the following text in the console:

13.8 11.600000000000001
create
13.8 12.600000000000001
create
13.8 13.600000000000001
create
13.8 14.600000000000001
create
13.8 15.600000000000001
create
Uncaught TypeError: Cannot set property 'entity' of null entity.js:34


And if i change my createBody function like this:

createBody: function(x,y,settings) {
            this.parent(x,y,settings);.... 

i get the same frozen window and the same console log but without this error: Uncaught TypeError: Cannot set property 'entity' of null entity.js:34



Thanks in advance! And sorry for my English ;)

1 decade ago by Joncom

What does line 34 of entity.js look like?

1 decade ago by AzZzOne

Line 34 looks like this: this.body.entity = this;

btw I'm using your plugin - impact-box2d-sugar (https://github.com/Joncom/impact-box2d-sugar) :)

I think i've understood what the problem was. i made it again like here:

http://www.binarytides.com/make-rope-box2d-javascript/

 ig.module(
  'game.entities.rope'
  )
  .requires(
   'impact.entity',
  'plugins.box2d.entity'
 )
.defines(function(){
		 EntityRope= ig.Box2DEntity.extend({
			 
			 gravityFactor :1,
		 _wmDrawBox: true,
	_wmBoxColor: 'rgba(150, 150, 255, 0.7)',
	
			   createBody: function(x,y,settings) {
             
		      //ceiling
	   
	   var bodyDef = new   Box2D.Dynamics.b2BodyDef(); 
			   var shapeDef = new Box2D.Collision.Shapes.b2PolygonShape();
                      shapeDef.SetAsBox(0.5,0.5);

             var fixtureDef = new Box2D.Dynamics.b2FixtureDef();
                   fixtureDef.shape = shapeDef;
          
          
			  bodyDef.position.Set(
                (this.pos.x +5  ) * Box2D.SCALE,
                (this.pos.y +5 ) * Box2D.SCALE
            );
			
			
			this.bodyCeiling  = ig.world.CreateBody(bodyDef);
			  this.bodyCeiling.CreateFixture(fixtureDef);
			  
			 var prevBody = this.bodyCeiling;
			 
			 
			 //rope 
			  
			 var rope_height = 0.8;
		         var rope_width = 0.3;
			     var last_anchor_point = new  Box2D.Common.Math.b2Vec2(0, 0.5);
			 
			 
			 
			    // start creating rope
			 for (i=0; i<7;i++){
				  
			    var bodyRopeDef = new Box2D.Dynamics.b2BodyDef();
    
            bodyRopeDef.position.Set( 
                (this.pos.x +5  ) * Box2D.SCALE,
                (this.pos.y+5 +i*8 ) * Box2D.SCALE
            );
			
			bodyRopeDef.type =  Box2D.Dynamics.b2Body.b2_dynamicBody,
                 this.body   = ig.world.CreateBody(bodyRopeDef);
           
            var shape2Def = new Box2D.Collision.Shapes.b2PolygonShape();
                    shape2Def.SetAsBox(rope_width,rope_height);

            var fixtureRopeDef = new Box2D.Dynamics.b2FixtureDef();
            fixtureRopeDef.shape = shape2Def;
            fixtureRopeDef.density = 1;
            fixtureRopeDef.friction = 1;
         fixtureRopeDef.restitution = 0.5  ;
			this.body.CreateFixture(fixtureRopeDef);
			  
			    var jointDef = new Box2D.Dynamics.Joints.b2RevoluteJointDef();
			  // jointDef.Initialize(prevBody,this.body,prevBody.GetWorldCenter() ) ;
			  
			  // jointDef.Initialize(prevBody,this.body, new 	  //Box2D.Common.Math.b2Vec2(this.pos.x*Box2D.SCALE,this.pos.y*Box2D.SCALE+rope_height*i*2)) ;
			  
			  jointDef.bodyA = prevBody;
			   jointDef.bodyB = this.body;
			   jointDef.localAnchorA  = last_anchor_point;
			      jointDef.localAnchorB  = new   Box2D.Common.Math.b2Vec2(0, rope_height ) ;
			         this.revJoint = ig.world.CreateJoint(jointDef);
			 // this.revJoint.collideConnected = false; 
               last_anchor_point = new   Box2D.Common.Math.b2Vec2(0, -1*rope_height ) ;
				   prevBody = this.body; 
			          
			 }
			 
			  
			 
			   } ,
		 
		  
			 
			 
			 })
		 
		 
		 
	
});

And it works but i still have some problems:

1) this rope consists of 7 sections but the gravity affects only the last one. How can i make gravity work with each section? I think it's not a problem in the standard box2d but in the impact-box2d-sugar it is.

2)I can't understand how does it work :
 bodyRopeDef.position.Set( 
                (this.pos.x +5  ) * Box2D.SCALE,
                (this.pos.y+5 +i*8 ) * Box2D.SCALE
            );

I mean i'm trying to make each following section appear one by one ( 5 is height and width of my ceiling and 8 is the height of one section) but the last section looks like appear on the top of the my ceiling.. and when rope is initiated it literally falls down from my ceiling body.. If i make position look like this my rope appears from the bottom but it looks stable :
bodyRopeDef.position.Set( 
                (this.pos.x +5  ) * Box2D.SCALE,
                (this.pos.y+300 ) * Box2D.SCALE
            );

But of course it's not the right way to do it)

I'll be really appreciate any help!

1 decade ago by Joncom

1.

When you call this.parent() within update, a call to this function is made:
applyGravity: function() {
    var gravity = new Box2D.Common.Math.b2Vec2(0, 
        ig.game.gravity * this.gravityFactor * 
        this.body.GetMass() * Box2D.SCALE);
    this.body.ApplyForce(gravity, this.body.GetPosition());
}

Notice how it only applies gravity to this.body? You need to apply gravity to your other bodies too. So overload this function to your liking.

2.

Can you put this into the form of a question?

Do you mean to ask why the rope falls?

1 decade ago by AzZzOne

1)

Yes i saw this function but i can't understand what exactly i should change to make it work. Could you please show me how this function should look like?

2)

I was trying to answer why with for example this position:
      bodyRopeDef.position.Set( 
                (this.pos.x +5  ) * Box2D.SCALE,
                (this.pos.y+10+i*8   ) * Box2D.SCALE
            );

my last section ( the one with gravity ) appears on my bodyCeiling ? not at the end of the rope? The last section's y coordinates should be (this.pos.y + 58) * Box2D.SCALE but it does not look like this, it is more like (this.pos.y+10 ) * Box2D.SCALE...And because of that i get a not stable straight rope like here http://www.binarytides.com/make-rope-box2d-javascript/ but a twisted rope with the last section that falls down from the bodeCeiling.
Sorry if it's very confusing :)

1 decade ago by Joncom

This all seems a little more complicated than it needs to be.

One problem I notice is that you are not keeping pointers to all the bodies you are creating. This means you currently cannot achieve 1. because you need to loop through all bodies and apply a force (gravity) to them.

Another thing is that if you're using my plugin, then this line:
EntityChain = ig.Box2DEntity.extend({

...should actually look like this:
EntityChain = ig.Entity.extend({

I'd probably try to make the code more simple by separating things a bit. For example make a separate entity for the ceiling. A ceiling has very little business being called a "rope"...

Another thing: if you require 'plugins.box2d.entity' then you do not need to also require 'impact.entity', because 'impact.entity' is already required within 'plugins.box2d.entity'.

PS: Any chance you use Github? Would be easier to take a look at what you've got (and play with it) if you had things uploaded there...

1 decade ago by AzZzOne

Hi, Joncom!

Thanks for yours advices. I changed the line like you said
 EntityRope= ig.Entity.extend({

and added pointers to each section of the rope so now i have gravity applied to all of them.

The second problem was solved too by my "bodyRopeDef.position.Set" and "jointDef.localAnchors" adjustment.

So at last i made it work properly!

Thanks for your help and your useful plugin! :)

1 decade ago by Joncom

Quote from AzZzOne
Thanks for your help and your useful plugin! :)
No problem. Glad you got everything working!!

1 decade ago by AzZzOne

Hi all, it's me again :)
I made the gravity affects all the bodies like Joncom said. It was not working because function Apply gravity only applied gravity to this.body. i fixed it by adding the new array this.myBody[] where i put all the rope's bodies:
...

bodyRopeDef.type =  Box2D.Dynamics.b2Body.b2_dynamicBody,
			bodyRopeDef.awake = true,
                 this.body    = ig.world.CreateBody(bodyRopeDef); 
                    this.myBody[i] =this.body ;

...

And then i changed function ApplyGravity like this
  applyGravity: function() {
				   for (i=0;i<7;i++){
            var gravity = new Box2D.Common.Math.b2Vec2(0, ig.game.gravity * this.gravityFactor * this.myBody[i].GetMass() * Box2D.SCALE);
			
			this.myBody[i].ApplyForce(gravity,  this.myBody[i].GetPosition());
				   }

It solved this problem .
But when i, for example, make a check function in my player.js it works only with the last section of my rope. If player touches the others or the ceiling it doesn't work. The quesion is: how can i make check function work with the whole rope?

1 decade ago by Joncom

Quick tip: In your applyGravity function, instead of doing this:
for (i=0;i<7;i++) {

...you can use this:
for (i=0;i<this.myBody.length;i++){

This is better because the loop will work properly regardless of whether there are 7 bodies or any other number. It also means you don't have to edit the loop code if you ever add/remove bodies.

Now, on to your question...
how can i make check function work with the whole rope?

If you take a look in box2d/entity.js at how the touches function works:
touches: function(other) {
    if(ig.global.wm) {
        return this.parent(other);
    } else {
        for (var edge = this.body.m_contactList; edge; edge = edge.next) {
            if(!edge.contact.IsTouching()) {
                continue;
            }
            if (edge.other.entity === other) {
                return true;
            }
        }
        return false;
    }
},

...we can see that only this.body is being checked against. This is the same problem you had with the gravity. And the solution will be very similar too.

touches: function(other) {
    if(ig.global.wm) {
        return this.parent(other);
    } else {
        for(var i=0; i<this.myBody.length; i++) {
            for (var edge = this.myBody[i].m_contactList; edge; edge = edge.next) {
                if(!edge.contact.IsTouching()) {
                    continue;
                }
                if (edge.other.entity === other) {
                    return true;
                }
            }
        }
        return false;
    }
},

As you can see, all we did we add the loop:
for(var i=0; i<this.myBody.length; i++) {

...and we reference this.myBody[i] instead of this.body.

1 decade ago by AzZzOne

Thanks for answer, Joncom!

I made it like your said. Now in my EntityRope i have both applyGravity and touches functions but it doesn't help. When i make fucntion (in my player.js) :
 check:function(other){
		 
		 console.log('touch');
		}, 

or call touches method (in player.js) :

 var rope = ig.game.getEntitiesByType( EntityRope )[0];
	 
	 if(this.touches(rope)){console.log('touch')}

I get word "touch" in the console only when my player collides with the last section of the rope.

1 decade ago by Joncom

Let's see your rope entity code please.

1 decade ago by AzZzOne

I have only removed the draw function to make it easier to read
  
ig.module(
  'game.entities.rope'
  )
  .requires(
    
  'plugins.box2d.entity'
 )
.defines(function(){
		 EntityRope= ig.Entity.extend({
	 	 // img: new ig.Image( 'media/rope.png'),
			 name:'rope',
			 start: false,
			 rope_height:0.8,
			 gravityFactor :1,
			 _wmScalable: true,
	       _wmDrawBox: true,
		 _wmDrawBox: true,
		 myBody: {},
		 myJoints:{},
		 allowSleep:false,
	_wmBoxColor: 'rgba(150, 150, 255, 0.7)',
	 type: ig.Entity.TYPE.B,
	 name:'rope',
	 canPlayerHang:false,
	 sections:7,
	 createdJoint:false,
	 init: function( x, y, settings ) {
 
 
  this.parent( x, y, settings );
					 	//  this.addAnim( 'idle', 1, [0] );
	 },
	 
			   createBody: function( ) {
				   
             var ceilingHeight = 0.4; 
			  var scalePositionX = this.pos.x  *  Box2D.SCALE;
			    var scalePositionY = this.pos.y  *  Box2D.SCALE;
			 
		                                 //CEILING
	   
	   var bodyDef = new   Box2D.Dynamics.b2BodyDef(); 
			   var shapeDef = new Box2D.Collision.Shapes.b2PolygonShape();
                      shapeDef.SetAsBox(ceilingHeight,ceilingHeight);

             var fixtureDef = new Box2D.Dynamics.b2FixtureDef();
                   fixtureDef.shape = shapeDef;
          
          
			  bodyDef.position.Set(
               scalePositionX +0.4,
                scalePositionY+0.4  
            );
			
			
			this.bodyCeiling  = ig.world.CreateBody(bodyDef);
			  this.bodyCeiling.CreateFixture(fixtureDef);
			  
			 var prevBody = this.bodyCeiling;
			 
			 
		                                       //ROPE
			   
			 
			this.start = true;
			 var rope_width = 0.2;
		      var scalePositionX = this.pos.x  *  Box2D.SCALE;
			   var scalePositionY = this.pos.y  *  Box2D.SCALE;
			     var last_anchor_point = new  Box2D.Common.Math.b2Vec2(0, ceilingHeight);
			 
			 
			                         //START CREATING ROPE
				
				this.myBody.length = this.sections;
			 
				
			 for (i=0; i<this.myBody.length;i++){
				  
			    var bodyRopeDef = new Box2D.Dynamics.b2BodyDef();
    
							bodyRopeDef.position.Set( 
							   scalePositionX +0.4,
								 scalePositionY+  ceilingHeight+this.rope_height/2+i*this.rope_height 
							);
		 
			
			bodyRopeDef.type =  Box2D.Dynamics.b2Body.b2_dynamicBody,
			bodyRopeDef.awake = true,
                 this.body    = ig.world.CreateBody(bodyRopeDef);
			  
                 	   this.myBody[i] =this.body ;
					
					
            var shape2Def = new Box2D.Collision.Shapes.b2PolygonShape();
                    shape2Def.SetAsBox(rope_width,this.rope_height);

            var fixtureRopeDef = new Box2D.Dynamics.b2FixtureDef();
            fixtureRopeDef.shape = shape2Def;
            fixtureRopeDef.density = 1;
            fixtureRopeDef.friction = 1;
            fixtureRopeDef.restitution = 0.5  ;
		  		this.body.CreateFixture(fixtureRopeDef);
			                                                                 
	                  //JOINTS FOR ROPE
																			 
																			 
			    var jointDef = new Box2D.Dynamics.Joints.b2RevoluteJointDef();
			  // jointDef.Initialize(prevBody,this.body,prevBody.GetWorldCenter() ) ;
			  
			  // jointDef.Initialize(prevBody,this.body, new 	  //Box2D.Common.Math.b2Vec2(this.pos.x*Box2D.SCALE,this.pos.y*Box2D.SCALE+rope_height*i*2)) ;
			  
			  jointDef.bodyA = prevBody;
			   jointDef.bodyB = this.body;
			   jointDef.localAnchorA  = last_anchor_point;
			      jointDef.localAnchorB  = new   Box2D.Common.Math.b2Vec2(0, -this.rope_height) ;
			         this.revJoint = ig.world.CreateJoint(jointDef);
					    this.myJoints[i] =this.revJoint ;
			// this.revJoint.collideConnected = false; 
               last_anchor_point = new   Box2D.Common.Math.b2Vec2(0,+this.rope_height  ) ;
				   prevBody = this.body;   
				   
		 
			        
			 }
			 
			   } ,
			   
			   
		 touches: function(other) {
    if(ig.global.wm) {
        return this.parent(other);
    } else {
        for(var i=0; i<this.myBody.length; i++) {
            for (var edge = this.myBody[i].m_contactList; edge; edge = edge.next) {
                if(!edge.contact.IsTouching()) {
                    continue;
                }
                if (edge.other.entity === other) {
                    return true;
                }
            }
        }
        return false;
    }
},
	
		  
			   applyGravity: function() {
				   for (i=0;i<7;i++){
            var gravity = new Box2D.Common.Math.b2Vec2(0, ig.game.gravity * this.gravityFactor * this.myBody[i].GetMass() * Box2D.SCALE);
			
			this.myBody[i].ApplyForce(gravity,  this.myBody[i].GetPosition());
				   }
			 
			 
        },

 })
		 
		 
		 
	
});

1 decade ago by Joncom

Try making the myBody property an array instead of an object because otherwise you're currently looping through it incorrectly.

How to loop through an array:
for(var i=0; i<myArray.length; i++)

How to loop through an object:
for(var i in myObject)

EDIT:

And since you seem to be using numerical indexes anyway, there is no major advantage to using an object over an array.

1 decade ago by AzZzOne

It's funny because i thought that i actually used an array. Anyway i fixed it but it still doesn't work. I'm out of ideas what can make it work. Hope that you will come up with something , i'll really appreciate

1 decade ago by Joncom

Another thing... Do not define this.myBody.length because length is calculated automatically! All arrays have a length property and you do not set the value yourself.

1 decade ago by AzZzOne

Yes, it was really stupid , thanks.

I made some test and turned out that my rope entity didn't even call the method touches! when i make like this:

 touches: function(other) {
			 this.parent(other);
			 console.log('CALL');
    if(ig.global.wm) {
        return this.parent(other);
    } else {
        for(var i=0; i<this.myBody.length; i++) {
			
            for (var edge = this.myBody[i].m_contactList; edge; edge = edge.next) {
				
				console.log('TOUCH');
                if(!edge.contact.IsTouching()) {
                    continue;
                }
                if (edge.other.entity === other) {
                    return true;
                }
            }
        }
	
        return false;
    }
},


i get nothing in my console at all!

1 decade ago by Joncom

Quote from AzZzOne
I made some test and turned out that my rope entity didn't even call the method touches! when i make like this... i get nothing in my console at all!
Correct, you will not get any messages in console if you're not calling the function...

1 decade ago by AzZzOne

I understood what i was doing wrong and now it works !

Thank you, Joncom!
Page 1 of 1
« first « previous next › last »