Wierd behaviour with cc.PhysicsSprite in cocos2dx and chipmunk - cocos2d-x

I have a game where balls bounce around the screen - simple. I have walls that prevent balls from escaping the screen space. I use the following code to add balls to the screen, which happens with some delay between each addition:
var ball = {};
ball.markedForDelete = false;
ball.dir = spawnPoint.dir;
var ballMass = 1;
var ballBody = new cp.Body( ballMass, cp.momentForCircle( ballMass, 0, this._ballRadius, cp.v(0,0) ) );
ballBody.setPos( spawnPoint.position );
var magnitude = 200;
var ang = spawnPoint.dir * Math.PI / 180;
var vel = cp.v( magnitude * Math.cos(ang), magnitude * Math.sin(ang) );
var shape = new cp.CircleShape( ballBody, this._ballRadius, cp.v( 0,0 ) );
shape.ballShapeId = this.model.getNextBallShapeId ();
shape.setElasticity( 1 );
shape.setFriction( 0 );
shape.setCollisionType( collision_type );
this._space.addShape( shape );
ball.shape = shape;
shape.ball = ball;
var sprite = cc.PhysicsSprite.create( file );
sprite.nodeName = "Ball:" + shape.ballShapeId;
sprite.setColor( cc.c3b( 255, 255, 255 ) );
sprite.setScale ( 0.5 * this.ballScale );
sprite.setBody( ballBody );
this._gameStage.addChild( sprite, 5 );
ball.sprite = sprite;
sprite.ball = ball;
this._space.addBody( ballBody );
ballBody.setVel( vel ) ;
return ball;
This code works as expected when running on a device (iOS or Android), but when I use exact same code on the web things get weird. First, it spawns about 4 balls from random spawn points without a hitch, but all following balls get spawned on top of an existing ball and seems like the two (or three or four depending on how long you play) share physics. If I enable debug physics node:
cc.PhysicsDebugNode.create( this._space );
I can see that these balls are right over each other and they stack velocities. What is going on? Is there a limit on how many I can have? Any pointers? I am so lost and confused.
Thanks!

So, i figured it out. I created an array of 4 spawn points (notice it matches how many balls i was seeing). Each spawn point was something like this spawnPoint: { position: cc.p ( x, y ) }. So, when I assign position for the body using ballBody.setPos( spawnPoint.position ) it was not creating a new cc.p object to store position, but actually using the one i provided. So, every ball i created shared one of these 4 positions. On mobile devices this works properly and cc.p is actually created, instead of just pointing to the one I provided. Hope it helps someone.

Related

function that detects if a ray is intersecting an object

I have a function that detects if a ray is intersecting an object, but it works with a radius around the center of the object, I want it to work with a bounding box, I want to give it 2 Vector3D of the bounding box, and one vector of the origin of the ray and one of the direction of the ray, and it will calculate if there is an intersection, can anyone help me with that? what is the mathematical formula for this?
intersectRay(origin:Vector3D, dir:Vector3D):
Found the solution.
1. I use a bounding box of 8 points, each for each corner.
2. I used this function to give each point a location of x and y on a 2D plain this way I turned the 3D problem into a 2D problem, the x and y are really the horizontal angle of the point relative to the camera position and the vertical angle relative to the camera position point:
public function AngleBetween2vectors(v1:Vector3D,v2:Vector3D):Point
{
var angleX:Number = Math.atan2(v1.x-v2.x,v1.z-v2.z);
angleX = angleX*180/Math.PI;
var angleY:Number = Math.atan2(v1.y-v2.y,v1.z-v2.z);
angleY = angleY*180/Math.PI;
return new Point(angleX,angleY);
}
Then I use a convex hull algorithm to delete the point that are not part of the external outline polygon which marks the place of the object on the screen, can be found on the net, make sure the bounding box doesn't contain duplicate points like if you have a flat plain with no depth, this can cause problem for the algorithm, so when you create the bounding box clean them out.
Then I use this algorithm to determine if the point of the mouse click falls within this polygon or outside of it:
private function pnpoly( A:Array,p:Point ):Boolean
{
var i:int;
var j:int;
var c:Boolean = false;
for( i = 0, j = A.length-1; i < A.length; j = i++ ) {
if( ( ( A[i].y > p.y ) != ( A[j].y > p.y ) ) &&
( p.x < ( A[j].x - A[i].x ) * ( p.y - A[i].y ) / ( A[j].y - A[i].y ) + A[i].x ) )
{
c = !c;
}
}
return c;
}
Then I measure the distance to the object and pick the closest one to the camera position, using this function:
public function DistanceBetween2Vectors(v1:Vector3D,v2:Vector3D):Number
{
var a:Number = Math.sqrt(Math.pow((v1.x-v2.x),2)+Math.pow((v1.y-v2.y),2));
var b:Number = Math.sqrt(Math.pow((v1.z-v2.z),2)+Math.pow((v1.y-v2.y),2));
return Math.sqrt(Math.pow(a,2)+Math.pow(b,2));
}
I'm sure there are more efficient ways, but this way is an interesting one, and it's good enough for me, I like it because it is intuitive, I don't like to work with abstract mathematics, it's very hard for me, and if there is a mistake, it's very hard to find it. If anyone has any suggestions on how I can make it more efficient, I'll be happy to hear them.

Moving Object to another Objects position

Hey everyone so I am having some trouble trying to get this to work correctly. I have a MC Object called character and another called "points". I have a container object called planetContainer I add the character to the planetContainer the character is rotating around the planets that are also added to the container. The main issue I am having is when the points power up is activated I want the points to move off the other planets and to the charactercenter position. It was working perfect but had to update some code and remove the Points out of the planetContainer and attach them to the planets instead. I know I might have to use localToGlobal but not too sure.
Here is how I setup the character:
private function newCounterClockWise():void
{
planetContainer.addChild(character);
character.rotation = (Math.atan2(character.y - planetHit.y, character.x - planetHit.x) * 180 / Math.PI);
}
How the points are added to the Planets:
private function addPoints():void
{
points = new mcPoints();
var planetPosition:Point = planetContainer.parent.localToGlobal(new Point(0, 0));
points.x = planetPosition.x;
points.y = planetPosition.y;
outerPlanets.addChild(points);
aPointsArray.push(points);
}
Now this is the main function that handles the points to move to the character but it is not working correctly. The points move but they move off the screen or cause the game to kinda tweak out and do different things. Also the "magnetHandler(); is in my EnterFRame Event:
private function magnetHandler():void
{
for (var i:int = 0; i < aPointsArray.length; i++)
{
var currentPoints:mcPoints = aPointsArray[i];
var characterPosition:Point = planetContainer.parent.globalToLocal(new Point(character.x, character.y));
if (currentPoints.hitTestObject(playScreen.mcPointsHit))
{
trace("POINTS MID STAGE");
currentPoints.x -= (currentPoints.x - characterPosition.x);
currentPoints.y -= (currentPoints.y - characterPosition.y);
//currentPoints.x = character.x;
//currentPoints.y = character.y;
//TweenMax.to(currentPoints, 0.5, {x:characterGlobalPosition.x, y:characterGlobalPosition.y , ease:Power1.easeInOut } );
}
}
}
Can anyone see what I am doing wrong?
It's a hard to understand your question fully (or to understand why you're putting things that relate to each other in separate containers), but likely this line is where it's falling down:
var characterPosition:Point = planetContainer.parent.globalToLocal(new Point(character.x, character.y));
What you want to do, is get the characters x/y coordinates in the currentPoints parent space. To do that, you would do something like this:
//first, find the global position of character:
var globalCharacterPoint:Point = character.localToGlobal(new Point());
//then, convert that to the currentPoints parent local space:
var localCharacterPoint:Point = currentPoints.parent.globalToLocal(globalCharacterPoint);
Also, in this code of yours:
points = new mcPoints();
var planetPosition:Point = planetContainer.parent.localToGlobal(new Point(0, 0));
points.x = planetPosition.x;
points.y = planetPosition.y;
You are getting the global space of the planetContainer's parent, which is probably NOT what you want. You likely want:
planetContainer.localToGlobal(new Point()); //this gives you the global location of the planet container's top left corner
And, since you're adding the points object to outerPlanets, you probably want to convert to its local space (unless it's positioned at 0,0 globally - then it doesn't especially matter).
var outerPoint:Point = outerPlanets.globalToLocal(planetPosition);
points.x = outerPoint.x;
points.y = outerPoint.y;
Needless to say, for games it's best to have everything in the global coordinate space unless it's truly encapsulated assets (like smoke on a rocket etc.)

AS3 drawing lines, making shorter after that

i have a little math/coding problem witch i don`t have any idea how could i do it work in a simple way, so the problem is is need to make a line shorter, with 15
in my program i have :
http://gyazo.com/aff5ff61fb9ad3ecedde3118d9c0895e
the line takes the center coordinates of both circles and draws from one to another, but i need it to be from the circumference of the circles, so it wont get inside
the code im using is :
var line:Shape = new Shape();
line.graphics.lineStyle(3,0xFF0000,2);
line.graphics.moveTo(sx,sy);
line.graphics.lineTo(fx,fy);
this.addChild(line);
arrow2(sx,sy,fx,fy);
var rline:Shape = new Shape();
rline.graphics.lineStyle(3,0xFF0000,2);
rline.graphics.moveTo(fx,fy);
rline.graphics.lineTo(xa,ya);
this.addChild(rline);
var rline2:Shape = new Shape();
rline2.graphics.lineStyle(3,0xFF0000,2);
rline2.graphics.moveTo(fx,fy);
rline2.graphics.lineTo(xb,yb);
this.addChild(rline2);
the rline and rline2 function is for the arrow lines, now my question is how do i make it shorter not depending on it direction so it will not overlap the circle
You can use vectors to solve your problem; they're pretty easy to get the hang of, and pretty much indispensable for things like game dev or what you're trying to do. You can get an overview here: http://www.mathsisfun.com/algebra/vectors.html or by searching "vector math" in google
So first step is to get a vector from one circle to another (pretty much what you've done):
var vector:Point = new Point( circle2.x - circle1.x, circle2.y - circle1.y );
var length:Number = vector.length; // store the length of the vector for later
This is the equivalent of saying "if you start at circle1 and move along vector, you'll arrive at circle2"
Next thing we're going to do is normalise it; all this does is set the length to 1 - the direction is unchanged - this makes it easier to work with for what you're looking to do. A vector with length 1.0 is called a unit vector:
vector.normalize( 1.0 ); // you can pass any length you like, but for this example, we'll stick with 1.0
Now, to draw a line from one circle to another, but starting from the outside, we simply find the start and the end points. The starting point is simple the position of circle1 plus vector (normalised to unit length) multiplied by the radius of circle1:
var sx:Number = circle1.x + vector.x * circle1.radius; // or circle1.width * 0.5 if you don't store the radius
var sy:Number = circle1.y + vector.y * circle1.radius;
The ending point can be found by starting at our start point, and continuing along our vector for a distance equal to the distance between the two circles (minus their radii). The length value that we created earlier is the distance between your two circles, from one center point to another, so we can use that to get the distance minus the radii:
var dist:Number = length - ( circle1.radius + circle2.radius ); // or circle1.width * 0.5 etc
And so the end point:
var ex:Number = sx + vector.x * dist;
var ey:Number = sy + vector.y * dist;
And to draw the line between them:
var line:Shape = new Shape;
line.graphics.lineStyle( 1.0, 0x000000 );
line.graphics.moveTo( sx, sy );
line.graphics.lineTo( ex, ey );
this.addChild( line )

AS3 - make a new bitmapData with non integar width and height

Hey guys hoping someone can help here. I am cropping a bitmap image into tiles using the following function:
function crop( _x:Number, _y:Number, _width:Number, _height:Number, callingScope:MovieClip, displayObject:DisplayObject = null, pixelSnapping:Boolean = false):Bitmap
{
var cropArea:Rectangle = new Rectangle( 0, 0, _width, _height );
var croppedBitmap:Bitmap;
if(pixelSnapping == true)
{
croppedBitmap = new Bitmap( new BitmapData( _width, _height ), PixelSnapping.ALWAYS, true );
}
else
{
croppedBitmap = new Bitmap( new BitmapData( _width, _height ), PixelSnapping.NEVER, true );
}
croppedBitmap.bitmapData.draw( (displayObject!=null) ? displayObject : callingScope.stage, new Matrix(1, 0, 0, 1, -_x, -_y) , null, null, cropArea, true );
return croppedBitmap;
}
The width and height being passed in is a non integer value, for instance 18.75. When the new BitmapData is created it always rounds down the value to an integer, since the arguments for BitmapData are typed as such. In the case of my needs here, the width and height will not likely ever be integers. Is there a way to create these bitmap pieces of another image at the exact width and height I need or can a new bitmapData only be created with integer values for height and width?
Thanks for any insight.
EDIT: I realize you can't have a fraction of a pixel, but... What I am trying to achieve is dividing an image into tiles. I want the amount of tiles to be variable, say 4 rows by 4 columns, or 6 rows by 8 columns. the division of an image into X number of parts results in widths and heights in most cases to be non integar values like 18.75 for example. The goal is to divide an image up into tiles, and have that image appear, assembled seamlessly, above the source image, where I would then manipulate the individual tiles for various purposes (puzzle game, tiled animation to new scene, etc). I need the image, when assembled from all the tile pieces, to be an exact copy of the original image, with no lines between tiles, or white edges anywhere, and I need this to happen with non integer widths and heights for the bitmapData pieces that comprise the tiles. Does that makes sense? O_o
A BitmapData can only be created with integer values for the dimensions.
And to be honest, I'm trying to think what a BitmapData object with floating number values for dimensions would be like, but my brain starts to scream in pain: DOES NOT MAKE SENSE!
My brain's a bit melodramatic sometimes.
-- EDIT --
Answer to your edited question:
2 options:
1/ Just copy the original full bitmap data as many times as you have tiles and then use masks on bitmap objects to show the appropriate parts of the tiles
2/make sure no fractional widths or heights are generated by the slicing. For instance if you got an image of width 213 you want to split in 2 rows and 2 columns, then set the width of the left tiles to 106 and the width of the right tiles to 107
Maybe there are other options, but those two seem to me to be the easiest with most chance of success.
If you need to create tiles with preferred size you can use something like that:
private function CreateTilesBySize( bigImage:Bitmap, preferredTileWidth:int, preferredTileHeight:int ):Tiles
{
var result:Tiles = new Tiles();
var y:int = 0;
while ( y < bigImage.height ) {
result.NewRow();
const tileHeight:int = Math.min( preferredTileHeight, bigImage.height - y );
var x:int = 0;
while ( x < bigImage.width ) {
const tileWidth:int = Math.min( preferredTileWidth, bigImage.width - x );
const tile:Bitmap = Crop( x, y, tileWidth, tileHeight, bigImage );
result.AddTile( tile );
x += tileWidth;
}
y += tileHeight;
}
return result;
}
If you need to create exact amount of rows and calls. Then you can use:
private function CreateTilesByNum( bigImage:Bitmap, cols:int, rows:int ):Tiles
{
const preferredTileWidth:int = Math.ceil( bigImage.width / cols );
const preferredTileHeight:int = Math.ceil( bigImage.height / rows );
return CreateTilesBySize( bigImage, preferredTileWidth, preferredTileHeight );
}
But remember that tiles will have diferent sizes (last tiles in a row and last tiles in a column)

How to get unrotated display object width/height of a rotated display object?

If I create a rectangle with 100px width and 100px height and then rotate it, the size of the element's "box" will have increased.
With 45 rotation, the size becomes about 143x143 (from 100x100).
Doing sometimes like cos(angleRad) * currentWidth seems to work for 45 rotation, but for other bigger angles it doesn't.
At the moment I am doing this:
var currentRotation = object.rotation;
object.rotation = 0;
var normalizedWidth = object.width;
var normalizedHeight = object.height;
object.rotation = currentRotation;
Surely, there must be a better and more efficient way. How should I get the "normalized" width and height of a displayobject, aka the size when it has not been rotated?
The best approach would probably be to use the code posted in the question - i.e. to unrotate the object, check its width, and then re-rotate it. Here's why.
First, simplicity. It's obvious what's being done, and why it works. Anyone coming along later should have no trouble understanding it.
Second, accuracy. Out of curiosity I coded up all three suggestions currently in this thread, and I was not really surprised to find that for an arbitrarily scaled object, they give three slightly different answers. The reason for this, in a nutshell, is that Flash's rendering internals are heavily optimized, and among other things, width and height are not stored internally as floats. They're stored as "twips" (twentieths of a pixel) on the ground that further accuracy is visually irrelevant.
Anyway, if the three methods give different answers, which is the most accurate? For my money, the most correct answer is what Flash thinks the width of the object is when it's unrotated, which is what the simple method gives us. Also, this method is the only one that always give answers rounded to the nearest 1/20, which I surmise (though I'm guessing) to mean it's probably equal to the value being stored internally, as opposed to being a calculated value.
Finally, speed. I assume this will surprise you, but when I coded the three methods up, the simple approach was the fastest by a small margin. (Don't read too much into that - they were all very close, and if you tweak my code, a different method might edge into the lead. The point is they're very comparable.)
You probably expected the simple method to be slower on the grounds that changing an object's rotation would cause lots of other things to be recalculated, incurring overhead. But all that really happens immediately when you change the rotation is that the object's transform matrix gets some new values. Flash doesn't really do much with that matrix until it's next time to draw the object on the screen. As for what math occurs when you then read the object's width/height, it's difficult to say. But it's worth noting that whatever math takes place in the simple method is done by the Player's heavily optimized internals, rather than being done in AS3 like the algebraic method.
Anyway I invite you to try out the sample code, and I think you'll find that the simple straightforward method is, at the least, no slower than any other. That plus simplicity makes it the one I'd go with.
Here's the code I used:
// init
var clip:MovieClip = new MovieClip();
clip.graphics.lineStyle( 10 );
clip.graphics.moveTo( 12.345, 37.123 ); // arbitrary
clip.graphics.lineTo( 45.678, 29.456 ); // arbitrary
clip.scaleX = .87; // arbitrary
clip.scaleY = 1.12; // arbitrary
clip.rotation = 47.123; // arbitrary
// run the test
var iterations:int = 1000000;
test( method1, iterations );
test( method2, iterations );
test( method3, iterations );
function test( fcn:Function, iter:int ) {
var t0:uint = getTimer();
for (var i:int=0; i<iter; i++) {
fcn( clip, i==0 );
}
trace(["Elapsed time", getTimer()-t0]);
}
// the "simple" method
function method1( m:MovieClip, traceSize:Boolean ) {
var rot:Number = m.rotation;
m.rotation = 0;
var w:Number = m.width;
var h:Number = m.height;
m.rotation = rot;
if (traceSize) { trace([ "method 1", w, h ]); }
}
// the "algebraic" method
function method2( m:MovieClip, traceSize:Boolean ) {
var r:Number = m.rotation * Math.PI/180;
var c:Number = Math.abs( Math.cos( r ) );
var s:Number = Math.abs( Math.sin( r ) );
var denominator:Number = (c*c - s*s); // an optimization
var w:Number = (m.width * c - m.height * s) / denominator;
var h:Number = (m.height * c - m.width * s) / denominator;
if (traceSize) { trace([ "method 2", w, h ]); }
}
// the "getBounds" method
function method3( m:MovieClip, traceSize:Boolean ) {
var r:Rectangle = m.getBounds(m);
var w:Number = r.width*m.scaleX;
var h:Number = r.height*m.scaleY;
if (traceSize) { trace([ "method 3", w, h ]); }
}
And my output:
method 1,37.7,19.75
Elapsed time,1416
method 2,37.74191378925391,19.608455916982187
Elapsed time,1703
method 3,37.7145,19.768000000000004
Elapsed time,1589
Surprising, eh? But there's an important lesson here about Flash development. I hereby christen Fen's Law of Flash Laziness:
Whenever possible, avoid tricky math by getting the renderer to do it for you.
It not only gets you done quicker, in my experience it usually results in a performance win anyway. Happy optimizing!
Here's the algorithmic approach, and its derivation.
First, let's do the opposite problem: Given a rectangle of unrotated width w, unrotated height h, and rotation r, what is the rotated width and height?
wr = abs(sin(r)) * h + abs(cos(r)) * w
hr = abs(sin(r)) * w + abs(cos(r)) * h
Now, try the problem as given: Given a rectangle of rotated width wr, rotated height hr, and rotation r, what is the unrotated width and height?
We need to solve the above equations for h and w. Let c represent abs(cos(r)) and s represent abs(sin(r)). If my rusty algebra skills still work, then the above equations can be solved with:
w = (wr * c - hr * s) / (c2 - s2)
h = (hr * c - wr * s) / (c2 - s2)
You should get the bounds of your square in your object's coordinate space (which means no rotations).
e.g.
var b:Sprite = new Sprite();
b.graphics.lineStyle(0.1);
b.graphics.drawRect(0,0,100,100);
b.rotation = 10;
trace('global coordinate bounds: ' + b.getBounds(this));//prints global coordinate bounds: (x=-17.35, y=0, w=115.85, h=115.85);
trace('local coordinate bounds: ' + b.getBounds(b));//prints local coordinate bounds: (x=0, y=0, w=100, h=100)
HTH,
George
Chip's answer in code:
// convert degrees to radians
var r:Number = this.rotation * Math.PI/180;
// cos, c in the equation
var c:Number = Math.abs(Math.cos(r));
// sin, s in the equation
var s:Number = Math.abs(Math.sin(r));
// get the unrotated width
var w:Number = (this.width * c - this.height * s) / (Math.pow(c, 2) - Math.pow(s, 2));