box2d b2_staticBody position problem - cocos2d-iphone

I've encountered a weird problem about positioning bodies in cocos2d/box2d.
If I set b2BodyDef type as b2_staticBody, I can't set bodies on any position out of multipliers of PTM_RATIO. Let me explain:
#define PTM_RATIO 32.0
...
myBodyDef_1.type = b2_staticBody;
myBodyDef_1.position.Set(320.0/PTM_RATIO, 320.0/PTM_RATIO);
...
and
...
myBodyDef_1.type = b2_staticBody;
myBodyDef_1.position.Set(333.0/PTM_RATIO, 333.0/PTM_RATIO);
...
gives the same result. No change in position. Difference of 13 pixels means nothing.
If I make the difference more than PTM_RATIO it appears 1 PTM_RATIO (32px) away.
For example:
...
myBodyDef_1.type = b2_staticBody;
myBodyDef_1.position.Set(358.0/PTM_RATIO, 358.0/PTM_RATIO);
...
Diffrence of 38px, but appears only 32px(1 PTM_RATIO) away.
I tried using direct values like 1.0 and 1.1
It didn't work. I can't get rid of multipliers of PTM_RATIO.
One more hint, if I use b2_kinematicBody as type, it works perfect.
Any idea?

try adding explicit conversation: 358.0/((float)PTM_RATIO).
try myBodyDef_1.position = b2Vec2(333.0/PTM_RATIO, 333.0/PTM_RATIO); and explicit conversation here.
try
float x = 333.0/PTM_RATIO;
float y = 333.0/PTM_RATIO;
myBodyDef_1.position = b2Vec2(x, y);
Let me know the result please

Related

DirectX 9 not rendering after adding transforms

so far I got a cube rendered without any transforms (thus it was rendered in an orthographic perspective), and I am working on the previous code to get it into a perspective view, with all the matrices involved. I changed the Flexible Vertex Format so as not to have RHW (thus only having XYZ coordinates and color, tried ARGB and XRGB but I don't think it matters), and I added a function that sets all the matrices.
Debugging
showed that matrices are being created correctly, functions return correctly (as far as I could see), no crashes (DirectX will never complain if something goes wrong, it just doesn't render) and in general, step-by-step debugging shows no paranormal activity.
Existing project (which I modify and eventually prevent from working):
As I advance I also write tutorials of sorts so I can go back and see what I did last time to get it to work, and this time I've kept versions so you can get the code here along with the VS2010 solution, all the DirectX work is done in 3Dheader.h and D3DLoader.h
Changes:
- the custom vertex format FVF_CUSTOMVERTEX has been changed so as not to include RHW, as I understand it has to be removed so as to be computed through the transformations
- In Render() I add a call to the function setMatrices() which does all the matrix and transform work, and is as follows:
void setMatrices()
{
//--------------transformation code----------------//
D3DXMATRIX objectM, translationM, rotationM, projectionM, lookAtM, finalM;
HRESULT hr;
D3DXMatrixIdentity(&objectM);
D3DXMatrixRotationY(&rotationM, D3DX_PI/4);
//D3DXMatrixMultiply(&finalM, &objectM, &rotationM);
D3DXMatrixPerspectiveFovLH(&projectionM,D3DX_PI/4,(float)yRes/xRes, 1, 100);
D3DXVECTOR3 camera;
camera.x = -10;
camera.y = 0;
camera.z = 0;
D3DXVECTOR3 cameraTarget;
cameraTarget.x = 0;
cameraTarget.y = 0;
cameraTarget.z = 0;
D3DXVECTOR3 cameraUp;
cameraUp.x = 0;
cameraUp.y = 1;
cameraUp.z = 0;
D3DXMatrixLookAtLH(&lookAtM,&camera,&cameraTarget, &cameraUp);
hr = pd3dDevice->SetTransform(D3DTS_WORLD, &objectM);
hr = pd3dDevice->SetTransform(D3DTS_PROJECTION, &projectionM);
hr = pd3dDevice->SetTransform(D3DTS_VIEW, &lookAtM);
D3DVIEWPORT9 view_port;
view_port.X=0;
view_port.Y=0;
view_port.Width=xRes;
view_port.Height=yRes;
view_port.MinZ=0.0f;
view_port.MaxZ=1.0f;
pd3dDevice->SetViewport(&view_port);
}
Note of course that some elements may not be needed, placed there just in case during my attempts, this is the code I have currently so we have a common reference.
Thanks in advance for any answers and/or attempts to answer.
In your code (downloaded), xRes and yRes are ints. Due to integer division, yRes/xRes will be zero, because xRes > yRes. You are passing this into the D3DXMatrixPerspextiveFovLH function as the aspect ratio, which will produce an invalid matrix. Instead, cast them to floats first, before doing the division, and pass the result in.

Cocos2D Z values between a sprite and a label

Firstly thanks for taking the time to look at this question.
The problem I am having is with Cocos2d and the Z values which determine where the sprites are in relation to other objects.
I have a sprite ('Ball') and also a score label ('scoreLabel') using CCLabelBMFont and I want the 'Ball' sprite to appear in front of the score label. I am currently attempting this via the z values but it is not working.
I am not sure if its because one is a sprite and the other is not as the below will work when the other object is a sprite but if anyone can point me in the direction of where I am going wrong it would be greatly appreciated.
Relevant code is listed below.
// Constants.h
// TestGame
//#ifndef SpaceViking_Constants_h
//#define SpaceViking_Constants_h
#define kBallSpriteZValue 10
#define kBallSpriteTagValue 0
#define kNewScoreTagValue 0
#define kNewScoreZValue 25
// GamePlayLayer.m
// TestGame
#import "Constants.h"
-(id)init {
self = [super init];
if (self !=nil) {
Ball *ball = [[Ball alloc]
initWithSpriteFrame:[[CCSpriteFrameCache
sharedSpriteFrameCache]
spriteFrameByName:#"Ball_1.png"]];
[ball setPosition:ccp(screenSize.width * 0.19f,
screenSize.height * 0.19f)];
[sceneSpriteBatchNode
addChild:ball
z:kBallSpriteZValue
tag:kBallSpriteTagValue];
scoreLabel = [CCLabelBMFont labelWithString:#"0"
fntFile:#"Test.fnt"];
scoreLabel.position = ccp(screenSize.width * 0.5f, screenSize.height * 0.9f);
[self addChild:scoreLabel
z:kNewScoreZValue tag:kNewScoreTagValue];
}
return self;
}
Things you need to know
z ordering only matters if you nodes are siblings (they have the same parent); the z order is not global in Cocos2d
If no z order is defined than the order of adding the children is used to determine in which order they are rendered
What this means for your use case
Setting the z order for your to CCNode objects as is will make no difference, because they are not siblings.
The ball is the the child of sceneSpriteBatchNode but the label is the child of self.
This means that the ball will already show behind the text, assuming this is your hierarchy:
->sceneSpriteBatchNode->ball
->label
Bonus stuff
Instead of using defines in your code, consider using an enum like so
typedef NS_ENUM(NSUInteger, UTzOrder) {
ballsZorder = 0,
labelsZorder = 1,
otherStuffZorder = 2
};
This is better because the compiler knows that you are using the right types, it is prettier and easier to change.
Remember this is only when they are siblings.
looking at your code I see that you have given higher z value to your label. Instead of giving higher value to your sprite, you should give it to your sprite(ball) so it will be placed on the label.
Whenever you create any objects in cocos2d it will be placed at default z=0 , you can set z value to put object behind current object or above current object. you can set negative z value also to put your label behind your sprite.
ex:
define kBallSpriteZValue 0 //this value should be greater in your case
define kNewScoreZValue -1
you can also reorder your z values later
[self reorderChild:spritename z:newzvalue];

How do I find my mouse point in a scene using SceneKit?

I have set up a scene in SceneKit and have issued a hit-test to select an item. However, I want to be able to move that item along a plane in my scene. I continue to receive mouse drag events, but don't know how to transform those 2D coordinates into 3D coordinate in the scene.
My case is very simple. The camera is located at 0, 0, 50 and pointed at 0, 0, 0. I just want to drag my object along the z-plane with a z-value of 0.
The hit-test works like a charm, but how do I translate the mouse point from a drag event into a new position in the scene for the 3D object I am dragging?
You don't need to use invisible geometry — Scene Kit can do all the coordinate conversions you need without having to hit test invisible objects. Basically you need to do the same thing you would in a 2D drawing app for moving an object: find the offset between the mouseDown: location and the object position, then for each mouseMoved:, add that offset to the new mouse location to set the object's new position.
Here's an approach you could use...
Hit-test the initial click location as you're already doing. This gets you an SCNHitTestResult object identifying the node you want to move, right?
Check the worldCoordinates property of that hit test result. If the node you want to move is a child of the scene's rootNode, these is the vector you want for finding the offset. (Otherwise you'll need to convert it to the coordinate system of the parent of the node you want to move — see convertPosition:toNode: or convertPosition:fromNode:.)
You're going to need a reference depth for this point so you can compare mouseMoved: locations to it. Use projectPoint: to convert the vector you got in step 2 (a point in the 3D scene) back to screen space — this gets you a 3D vector whose x- and y-coordinates are a screen-space point and whose z-coordinate tells you the depth of that point relative to the clipping planes (0.0 is on the near plane, 1.0 is on the far plane). Hold onto this z-coordinate for use during mouseMoved:.
Subtract the position of the node you want to move from the mouse location vector you got in step 2. This gets you the offset of the mouse click from the object's position. Hold onto this vector — you'll need it until dragging ends.
On mouseMoved:, construct a new 3D vector from the screen coordinates of the new mouse location and the depth value you got in step 3. Then, convert this vector into scene coordinates using unprojectPoint: — this is the mouse location in your scene's 3D space (equivalent to the one you got from the hit test, but without needing to "hit" scene geometry).
Add the offset you got in step 3 to the new location you got in step 5 - this is the new position to move the node to. (Note: for live dragging to look right, you should make sure this position change isn't animated. By default the duration of the current SCNTransaction is zero, so you don't need to worry about this unless you've changed it already.)
(This is sort of off the top of my head, so you should probably double-check the relevant docs and headers. And you might be able to simplify this a bit with some math.)
As an experiment I implemented Mr Bishop's helpful answer. The drag doesn't quite work (the object - a chess piece - jumps off screen) because of differences in the coordinate magnitudes between the mouse click and the 3-D world. I've inserted log outputs here and there among the code.
I asked on the Apple forums if anyone knew the secret sauce to homogenize the coordinates but didn't get a decisive answer. One thing, I had made some experimental changes to Mr Bishop's method and the forum members advised me to return to his technique.
Despite my code's failings, I thought someone might find it a useful starting point. I suspect there are only one or two small problems with the code.
Note that the log of the world transform matrix of the object (chess piece) is not part of the process but one Apple forum member advised me that the matrix often offers a useful 'sanity check' - which indeed it did.
- (NSPoint)
viewPointForEvent: (NSEvent *) event_
{
NSPoint windowPoint = [event_ locationInWindow];
NSPoint viewPoint = [self.view convertPoint: windowPoint
fromView: nil];
return viewPoint;
}
- (SCNHitTestResult *)
hitTestResultForEvent: (NSEvent *) event_
{
NSPoint viewPoint = [self viewPointForEvent: event_];
CGPoint cgPoint = CGPointMake (viewPoint.x, viewPoint.y);
NSArray * points = [(SCNView *) self.view hitTest: cgPoint
options: #{}];
return points.firstObject;
}
- (void)
mouseDown: (NSEvent *) theEvent
{
SCNHitTestResult * result = [self hitTestResultForEvent: theEvent];
SCNVector3 clickWorldCoordinates = result.worldCoordinates;
log output: clickWorldCoordinates x 208.124578, y -12827.223365, z 3163.659073
SCNVector3 screenCoordinates = [(SCNView *) self.view projectPoint: clickWorldCoordinates];
log output: screenCoordinates x 245.128906, y 149.335938, z 0.985565
// save the z coordinate for use in mouseDragged
mouseDownClickOnObjectZCoordinate = screenCoordinates.z;
selectedPiece = result.node; // save selected piece for use in mouseDragged
SCNVector3 piecePosition = selectedPiece.position;
log output: piecePosition x -18.200000, y 6.483060, z 2.350000
offsetOfMouseClickFromPiece.x = clickWorldCoordinates.x - piecePosition.x;
offsetOfMouseClickFromPiece.y = clickWorldCoordinates.y - piecePosition.y;
offsetOfMouseClickFromPiece.z = clickWorldCoordinates.z - piecePosition.z;
log output: offsetOfMouseClickFromPiece x 226.324578, y -12833.706425, z 3161.309073
}
- (void)
mouseDragged: (NSEvent *) theEvent;
{
NSPoint viewClickPoint = [self viewPointForEvent: theEvent];
SCNVector3 clickCoordinates;
clickCoordinates.x = viewClickPoint.x;
clickCoordinates.y = viewClickPoint.y;
clickCoordinates.z = mouseDownClickOnObjectZCoordinate;
log output: clickCoordinates x 246.128906, y 0.000000, z 0.985565
log output: pieceWorldTransform:
m11 = 242.15889219510001, m12 = -0.000045609300002524833, m13 = -0.00000721691076126, m14 = 0,
m21 = 0.0000072168760805499971, m22 = -0.000039452697396149999, m23 = 242.15890446329999, m24 = 0,
m31 = -0.000045609300002524833, m32 = -242.15889219510001, m33 = -0.000039452676995750002, m34 = 0,
m41 = -4268.2349924762348, m42 = -12724.050221935429, m43 = 4852.6652710104272, m44 = 1)
SCNVector3 newPiecePosition;
newPiecePosition.x = offsetOfMouseClickFromPiece.x + clickCoordinates.x;
newPiecePosition.y = offsetOfMouseClickFromPiece.y + clickCoordinates.y;
newPiecePosition.z = offsetOfMouseClickFromPiece.z + clickCoordinates.z;
log output: newPiecePosition x 472.453484, y -12833.706425, z 3162.294639
selectedPiece.position = newPiecePosition;
}
I used the code written by Steve and with little modification it worked for me.
On mouseDown I save clickWorldCoordinates on a property called startClickWorldCoordinates.
On mouseDragged I calculate the selectedPiece position in this way:
SCNVector3 worldClickCoordinate = [(SCNView *) self.view unprojectPoint:clickCoordinates.x];
newPiecePosition.x = selectedPiece.position.x + worldClickCoordinate.x - startClickWorldCoordinates.x;
newPiecePosition.y = selectedPiece.position.y + worldClickCoordinate.y - startClickWorldCoordinates.y;
newPiecePosition.z = selectedPiece.position.z + worldClickCoordinate.z - startClickWorldCoordinates.z;
selectedPiece.position = newPiecePosition;
startClickWorldCoordinates = worldClickCoordinate;

Cocos2D+Box2D: Stack bodies that doesn´t fall?

EDIT 2: Problem solved! I can´t promise it will work with different settings, but by putting my block´s body density to 0, the stack of blocks did not fall when new blocks are added.
I´m sorry about the poor title of the question, I´ll explain my problem closer here:
So, I´ve used Box2D and cocos2D to setup a simple project where two boxes stacks on top of each other (I´m planning to expand to 8-10 boxes). Right now, using a friction of 10.0f on each box, the box at the top still moves around a little. If I would add more boxes, the "tower" would fall and I don´t want that.
I want the boxes to use the gravity to move down, but I never ever want them to change there start x-value.
So, how could I prevent my tower of boxes to fall over or prevent my boxes from moving in x-direction?
EDIT: Posting some code
This code creates on of the boxes, the other one just have a different sprite file.
CCSprite *block = [CCSprite spriteWithFile:#"red.png"];
block.position = ccp(200,380);
[self addChild:block];
//Body definition
b2BodyDef blockDef;
blockDef.type = b2_dynamicBody;
blockDef.position.Set(200/PTM_RATIO, 200/PTM_RATIO);
blockDef.userData = block;
b2Body *blockBody = _world->CreateBody(&blockDef);
//Create the shape
b2PolygonShape blockShape;
blockShape.SetAsBox(block.contentSize.width/PTM_RATIO/2, block.contentSize.height/PTM_RATIO/2);
//Fixture defintion
b2FixtureDef blockFixtureDef;
blockFixtureDef.shape = &blockShape;
blockFixtureDef.restitution = 0.0f;
blockFixtureDef.density = 10.0f;
blockFixtureDef.friction = 10.0f;
_redBlockFixture = blockBody->CreateFixture(&blockFixtureDef);
Nothing fancy.
Regards.
You could setup a 2 (1 pixel wide) walls in box2D to the left and right of the block. Here's some sample code for the left wall. To create the right wall, just copy and past the code and change the variable names and the position of the BodyDef.
// Constant you'll need to define
float wallHeight;
// Create wall body
b2BodyDef wallBodyDef;
wallBodyDef.type = b2_dynamicBody;
wallBodyDef.position.Set(200 - block.contentSize.width/PTM_RATIO/2, 0);
b2Body *wallBody = _world->CreateBody(&wallBodyDef);
// Create wall shape
b2PolygonShape wallShape;
wallShape.SetAsBox(1, wallHeight);
// Create shape definition and add to body
b2FixtureDef wallShapeDef;
wallShapeDef.shape = &wallShape;
wallShapeDef.density = 100.0f;
wallShapeDef.friction = 0.0f;
wallShapeDef.restitution = 0.0f;
b2Fixture *wallFixture = wallBody->CreateFixture(&wallShapeDef);
I solved this problem by adjusting the restitution (bounce) of the static surface upon which the blocks are stacked. For example, if the floor has a restitution of .2, a stack of five blocks will look like they are compressing into each other, and eventually topple:
Set the restitution of the floor to 0, and the blocks stay stacked the way you would expect:

"Invalid Handle Object" when plotting 2 figures Matlab

I'm having a difficult time understanding the paradigm of Matlab classes vs compared to c++. I wrote code the other day, and I thought it should work. It did not... until I added
<handle
after the classdef.
So I have two classes, landmarks and robot, both are called from within the simulation class. This is the main loop of obj.simulation.animate() and it works, until I try to plot two things at once.
DATA.path is a record of all the places a robot has been on the map, and it's updated every time the position is updated.
When I try to plot it, by uncommenting the two marked lines below, I get this error:
??? Error using ==> set
Invalid handle object.
Error in ==> simulation>simulation.animate at 45
set(l.lm,'XData',obj.landmarks.apparentPositions(:,1),'YData',obj.landmarks.apparentPositions(:,2));
%INITIALIZE GLOBALS
global DATA XX
XX = [obj.robot.x ; obj.robot.y];
DATA.i=1;
DATA.path = XX;
%Setup Plots
fig=figure;
xlabel('meters'), ylabel('meters')
set(fig, 'name', 'Phil''s AWESOME 80''s Robot Simulator')
xymax = obj.landmarks.mapSize*3;
xymin = -(obj.landmarks.mapSize*3);
l.lm=scatter([0],[0],'b+');
%"UNCOMMENT ME"l.pth= plot(0,0,'k.','markersize',2,'erasemode','background'); % vehicle path
axis([xymin xymax xymin xymax]);
%Simulation Loop
for n = 1:720,
%Calculate and Set Heading/Location
XX = [obj.robot.x;obj.robot.y];
store_data(XX);
if n == 120,
DATA.path
end
%Update Position
headingChange = navigate(n);
obj.robot.updatePosition(headingChange);
obj.landmarks.updatePerspective(obj.robot.heading, obj.robot.x, obj.robot.y);
%Animate
%"UNCOMMENT ME" set(l.pth, 'xdata', DATA.path(1,1:DATA.i), 'ydata', DATA.path(2,1:DATA.i));
set(l.lm,'XData',obj.landmarks.apparentPositions(:,1),'YData',obj.landmarks.apparentPositions(:,2));
rectangle('Position',[-2,-2,4,4]);
drawnow
This is the classdef for landmarks
classdef landmarks <handle
properties
fixedPositions; %# positions in a fixed coordinate system. [ x, y ]
mapSize; %Map Size. Value is side of square
x;
y;
heading;
headingChange;
end
properties (Dependent)
apparentPositions
end
methods
function obj = landmarks(mapSize, numberOfTrees)
obj.mapSize = mapSize;
obj.fixedPositions = obj.mapSize * rand([numberOfTrees, 2]) .* sign(rand([numberOfTrees, 2]) - 0.5);
end
function apparent = get.apparentPositions(obj)
currentPosition = [obj.x ; obj.y];
apparent = bsxfun(#minus,(obj.fixedPositions)',currentPosition)';
apparent = ([cosd(obj.heading) -sind(obj.heading) ; sind(obj.heading) cosd(obj.heading)] * (apparent)')';
end
function updatePerspective(obj,tempHeading,tempX,tempY)
obj.heading = tempHeading;
obj.x = tempX;
obj.y = tempY;
end
end
end
To me, this is how I understand things. I created a figure l.lm that has about 100 xy points. I can rotate this figure by using
set(l.lm,'XData',obj.landmarks.apparentPositions(:,1),'YData',obj.landmarks.apparentPositions(:,2));
When I do that, things work. When I try to plot a second group of XY points, stored in DATA.path, it craps out and I can't figure out why.
I need to plot the robots path, stored in DATA.path, AND the landmarks positions. Ideas on how to do that?
Jonas:
I'm not saying you're wrong, because I don't know the answer, but I have code from another application that plots this way without calling axes('NextPlot','add');
if dtsum==0 & ~isempty(z) % plots related to observations
set(h.xf, 'xdata', XX(4:2:end), 'ydata', XX(5:2:end))
plines= make_laser_lines (z,XX(1:3));
set(h.obs, 'xdata', plines(1,:), 'ydata', plines(2,:))
pfcov= make_feature_covariance_ellipses(XX,PX);
set(h.fcov, 'xdata', pfcov(1,:), 'ydata', pfcov(2,:))
end
drawnow
The above works on the other code, but not mine. I'll try implementing your suggestion and let you know.
When you call plot multiple times on the same figure, the previous plot is by default erased, and the handle to the previous plot points to nothing. Thus the error.
To fix this, you need to set the NextPlot property of the axes to add. You can do this by calling hold on (that's what you'd do if you were plotting from command line), or you can write
fig=figure;
%# create a set of axes where additional plots will be added on top of each other
%# without erasing
axes('NextPlot','add');
If you want, you can store the axes handle as well, and use plot(ah,x,y,...) to make sure that you plot into the right set of axes and not somewhere strange if you happen to click on a different figure window between the time the figure is opened and the plot command is issued.