I know that this might sound pretty simple. I am having a problem with accessing the userdata of a b2Body in one method through the update method. I need to access the userdata property in the update method to set multiple gravities. I am just not getting it. Below is the update method
-(void) update: (ccTime) dt
{
int32 velocityIterations = 8;
int32 positionIterations = 1;
world->Step(dt, velocityIterations, positionIterations);
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() != NULL) {
if (b == spriteData) {
b->ApplyForce( b2Vec2(0.0,9.8*b->GetMass()),b->GetWorldCenter()); // here 0.0 is x, 9.8 is y (the gravity)
}
}
}
}
How do I access the userdata property (spriteData) which is in another method. Please Help
I suggest you declare an data structure MyUserData (use whatever name you see fit). It will contains two things :
pointer to the actual user data object
id number
Use this structure to store you body's user data and use the id to recognize specific user data :
if (b->GetUserData() != NULL) {
MyUserData *myUserData = (MyUserData *)b->GetUserData();
if (myUserData->id == <id for sprites which require other gravity force>) {
b->ApplyForce( b2Vec2(0.0,9.8*b->GetMass()),b->GetWorldCenter()); // here 0.0 is x, 9.8 is y (the gravity)
}
}
Related
Good morning.
Im learning some concepts about inheritance and consoles manipulation.
Im pretty beginner as you could see.
So Im trying to have a single character drawn on a console and I want its position to be updated.
Now please note that I know my code is probably very bad in multiple ways and that there are probably hundreds better completely alternative ways to do this, but I want to understand some inheritance concepts first and why it doesn't work the way it is.
So, I draw my player character "X" on the console, then I update its position calling a specific member method to move it.
Now, because I made it that Player class expand DrawConsole class, I would like to call drawConsole on the Player instance.
When I do this, I have that playerA instance have its position coordinates actually updated, but the reference to the player instance have now two member called 'position', as you can see on the image.
How can I say to choice the playerA one without completely remake the code or use a completely different approach?
Or maybe simply I cant and I have actually complete change the approach?
Hope I was able to comunicate what my doubt actually is.
Here is the code
#include <ctime>
#include <cstdlib>
#include "windows.h"
#define width 100
#define height 15
class StaticBuffer
{
public:
StaticBuffer() { srand(time(0)); }
void loadBackGround(CHAR_INFO *backGround, int swidth, int sheight)
{
for (int y = 0; y < sheight; y++)
{
int rnd = rand() % 100 + 1;
for (int x = 0; x < swidth; x++)
if (y == 0 || y == sheight - 1)
{
backGround[y * swidth + x].Char.AsciiChar = (unsigned char)127;
backGround[y * swidth + x].Attributes = (unsigned char)23;
}
else if (x > 4 * rnd && x < (4 * rnd) + 5 || x > 4 * rnd / 2 && x < (4 * rnd / 2) + 5)
{
backGround[y * swidth + x].Char.AsciiChar = (unsigned char)178;
backGround[y * swidth + x].Attributes = (unsigned char)12;
}
else
{
backGround[y * swidth + x].Char.AsciiChar = 32;
backGround[y * swidth + x].Attributes = (unsigned char)3;
}
}
}
private:
};
class DrawConsole
{
public:
DrawConsole()
{
wConsole = GetStdHandle(STD_OUTPUT_HANDLE);
rConsole = GetStdHandle(STD_INPUT_HANDLE);
windowSizeInit = {0, 0, 30, 10};
windowSize = {0, 0, bufferSize.X - 1, bufferSize.Y - 1};
backGround = new CHAR_INFO[bufferSize.X * bufferSize.Y];
obstacle = new CHAR_INFO[bufferSize.X * bufferSize.Y];
inputBuffer = new INPUT_RECORD[4];
drawBackGround.loadBackGround(backGround, bufferSize.X, bufferSize.Y);
nInputWritten = 0;
nOutputWritten = 0;
playerString[0] = L'X';
charLenght = 1;
position = {10,13};
}
void drawConsole()
{
wConsole = GetStdHandle(STD_OUTPUT_HANDLE);
rConsole = GetStdHandle(STD_INPUT_HANDLE);
SetConsoleWindowInfo(wConsole, TRUE, &windowSizeInit);
wConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleScreenBufferSize(wConsole, bufferSize);
SetConsoleWindowInfo(wConsole, TRUE, &windowSize);
WriteConsoleOutputA(wConsole, backGround, bufferSize, {0,0}, &windowSize);
WriteConsoleOutputCharacterW(wConsole, playerString, charLenght, position, &nOutputWritten);
}
void drawChar()
{
WriteConsoleOutputA(wConsole, backGround, bufferSize, {0,0}, &windowSize);
WriteConsoleOutputCharacterW(wConsole, playerString, charLenght, position, &nOutputWritten);
}
protected:
HANDLE wConsole;
HANDLE rConsole;
COORD bufferSize{width, height};
SMALL_RECT windowSizeInit;
SMALL_RECT windowSize;
CHAR_INFO *backGround;
CHAR_INFO *obstacle;
INPUT_RECORD *inputBuffer;
DWORD nInputWritten;
DWORD nOutputWritten;
DWORD charLenght;
StaticBuffer drawBackGround;
wchar_t playerString[2];
COORD position;
};
class Player :public DrawConsole
{
public:
Player()
{
position.X = 20;
position.Y = height - 2;
}
void movePlayerRight()
{
for (int i = 0; i < 3; i++)
position.X += 1;
}
COORD getPositionC() { return position; }
private:
COORD position;
};
Player *playerA = new Player;
DrawConsole *myConsole = new DrawConsole;
int main()
{
myConsole->drawConsole();
while (true)
{
//Sleep(5000);
playerA->movePlayerRight();
playerA->drawChar();
}
}
It depends on what you really want. If the idea is that both variables represent the same concept, you shouldn't have to re-define it in the derived class, because it is "protected" in the base class so the derived class is able to access it.
If the variables represent different things, but they happen to have the same name (which, by the way, would be a bad idea), you can qualify it with the class the variable has been defined in. So, for instance, you could do:
DrawConsole::position.X += 1;
To modify the position variable declared in DrawConsole and:
Player::position.X += 1;
To modify the position variable declared in Player
But, as I said before, I would try to avoid having two variables with the same name because it can easily result in errors.
UPDATE:
If you want to maintain the inheritance as is, just remove the attribute position from Player. The reason is as follows:
Currently, when you call drawChar, you are executing code that is in the DrawConsole class (Player itself does not define a drawChar method). This code cannot access Player::position because a method in a parent class cannot access an attribute in a child class (even if you are calling the method from an instance of the child class), so it only sees DrawConsole::position and that is the variable that it is using.
But when you call movePlayerRigth in an instance of Player, the code that is being executed is a method in the Player class. This method tries to access a position attribute and it finds out that there are two possibilities: DrawConsole::position and Player::position. In this case, it chooses Player::position because it is defined in the same class.
So, you have a method that draws the console based on DrawConsole::position and another method that modifies Player::position. This can't work and in fact if you run it, you will see that the X is not moving.
If you remove the position variable from Player, in movePlayerRight when you try to access the variable position, the code will see that Player does not define a position attribute, but it realizes that its parent class (DrawConsole) does indeed define a position attribute, and with protected access. Being protected means that code in child classes can access it directly, and so movePlayerRight will modify DrawConsole::position. In this case, both drawChar and movePlayerRight will access the same variable and it will work as expected.
So, if you want it this way, remove from the Player class the line:
COORD position;
And you will see that the code compiles and works as expected (the X moves right) because now the code in Player and the code in DrawConsole are accessing both the same variable (DrawConsole::position).
Im trying to write a looping block of code that codes that asks the following following within c++
while object A, or B or C or D == X, Y, Z (coords)
if A meets conditions, move object A East.
If B meets conditions, move object B East.
and so on,
I've pre-established each object coords as a string, so I just need to compare them against a control, Currently, I just have a loop that happens that doesn't recognise which object is triggering it.
The code to read coords and move the object is within a specific library, My tutor suggests using an array and a while loop to achieve this but I'm not sure how to do it even after spending several hours researching it.
I come from a background of unity and unreal engine so something simple like this goes over my head because I want to just use a conditional on the point, rather than react to each of the objects.
I'm very fresh to c# so please try to keep solutions simple thankyou!
EDIT: This is the code I am using at the moment
//Load strings at the start of the game
```string bblocal = (ballblue->GetLocalX, ballblue->GetLocalY, ballblue->GetLocalZ);
string bilocal = (ballindigo->GetLocalX,ballbindigo->GetLocalY, ballindigo->GetLocalZ);
string bvlocal = (ballviolet->GetLocalX,ballviolet->GetLocalY, ballviolet->GetLocalZ);
string bflocal = (ballfawn->GetLocalX,ballfawn->GetLocalY, ballfawn->GetLocalZ);
string bb = bblocal;
string bi = bilocal;
string bv = bvlocal;
string bf = bflocal;```
//For each tick, check the following
```while (bb || bi || bv || vf == (-50, 10, 50)
{
//Turn blue and move it to next point
if blue
{
ballblue->MoveX (0);
ballblue->MoveZ (100);
ballblue->RotateX (-50);
ballblue->RotateZ (50);
}
//Turn Indigo and move it to next point
//Turn Violet and move it to next point
//Turn Fawn and move it to next point
}
With a given class Point like:
public class Point
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}
You have a brunch of define point:
var A = new Point{X=1, Y=0, Z=0};
var B = new Point{X=0, Y=1, Z=0};
var C = new Point{X=0, Y=0, Z=1};
// Etc
And a refenrece point to compare them with. List all the point you have to check in an array.
var referencePoint = new Point{X=0, Y=0, Z=1};
var pointsToCheck = new []{A, B, C};
An for each element of this array do your validation. You can have access to the point via the variable.
foreach(var p in pointsToCheck){
// Would be nice If Point add IEquatable<Point> with Equals gethashcode
if( p.X == referencePoint.X
&& p.Y == referencePoint.Y
&& p.Z == referencePoint.Z
)
{
//Do something!
p.X ++;
// Break; // if only the first must be moved.
}
}
Query them directly with LinQ
pointsToCheck.Where( p => p.X == referencePoint.X
&& p.Y == referencePoint.Y
&& p.Z == referencePoint.Z) ;
If you have an array of "corner" you point position in it, you will need the IEquatable.
var currentCornerIndex = Array.IndexOf(cornersList, CurrentPoint);
//Will return the next corner:
// if it's the last corner return the first
// if not a corner return the first.
var nextCornerIndex = (currentCornerIndex + 1) % cornersList.Length;
var nextCorner = cornersList[nextCornerIndex];
I have gone through the 3D object documentation in JPCT but i couldn't find a way to scale an 3D object[a Cylinder] along y axis only. My world have multiple objects and I goal is to scale one particular object. Appreciate any leads. Thank you!!
Something like this openGL function glScalef(1,10,1).
The user AGP lists a method of achieving this here:
JPCT Forums
It basically uses the following vertex controller class, and I've used it successfully as well:
class VertexController extends GenericVertexController
{
public VertexController(Object3D toCheck) {
super.init(toCheck.getMesh(), true);
}
protected void scale(SimpleVector scale)
{
SimpleVector[] vertices = getSourceMesh();
SimpleVector[] destination = getDestinationMesh();
for (int i = 0; i < vertices.length; i++)
{
vertices[i].x *= scale.x;
vertices[i].y *= scale.y;
vertices[i].z *= scale.z;
destination[i].x = vertices[i].x;
destination[i].y = vertices[i].y;
destination[i].z = vertices[i].z;
}
this.updateMesh();
}
public void apply() {}
}
And you can call it like this:
vertexController = new VertexController(object);
Then in your onDrawFrame, or whereever required:
vertexController.scale(new SimpleVector(1,1.5f,1));
I have an Entity.h like this:
using namespace physx;
class Entity
{
public:
Entity(Ogre::Vector3 dims, Ogre::Vector3 pos, std::string mesh, std::string id);
virtual ~Entity(void);
virtual void update(Ogre::Real dt);
virtual void init(Ogre::SceneManager* sceneMgr, PxPhysics* physics, PxScene* scene, PxVec3 velocity=PxVec3(0, 0, 0));
protected:
Ogre::Entity* mOgreEntity = NULL;
Ogre::SceneNode* mOgreNode = NULL;
Ogre::Vector3 mPosition;
Ogre::Vector3 mDimensions;
std::string mMesh;
std::string mId;
PxRigidDynamic* mActor;
PxMaterial* mMaterial;
};
And here is my Entity source:
#include "Entity.h"
Entity::Entity(Ogre::Vector3 dims, Ogre::Vector3 pos, std::string mesh, std::string id)
{
mDimensions = dims;
mPosition = pos;
mMesh = mesh;
mId = id;
mActor = NULL;
mMaterial = NULL;
}
Entity::~Entity(void)
{
}
void Entity::update(Ogre::Real dt)
{
PxVec3 pos = mActor->getGlobalPose().p;
Ogre::Real r = 0;
mOgreNode->setPosition(Ogre::Vector3(pos.x + r, pos.y + r, pos.z + r));
}
void Entity::init(Ogre::SceneManager* sceneMgr, PxPhysics* physics, PxScene* scene, PxVec3 velocity)
{
// Create an Entity
mOgreEntity = sceneMgr->createEntity(mId, mMesh);
mOgreEntity->setCastShadows(true);
// Create a SceneNode and attach the Entity to it
mOgreNode = sceneMgr->getRootSceneNode()->createChildSceneNode(mId + "Node");
Ogre::AxisAlignedBox box = mOgreEntity->getBoundingBox();
Ogre::Vector3 realSizes = box.getSize();
mOgreNode->setPosition(mPosition);
mOgreNode->attachObject(mOgreEntity);
Ogre::Vector3 scaler = Ogre::Vector3(mDimensions.x / realSizes.x, mDimensions.y / realSizes.y, mDimensions.z / realSizes.z);
mOgreNode->scale(scaler);
mMaterial = physics->createMaterial(1.5f, 1.5f, 1.0f);
PxGeometry* geometry = NULL;
if(mMesh == "sphere.mesh")
{
PxGeometry g = PxSphereGeometry(mDimensions.x / 2); // Because it's a radius
geometry = &g;
} else {
// geometry = NULL;
}
PxTransform transform = PxTransform(PxVec3(mPosition.x, mPosition.y, mPosition.z));
mActor = PxCreateDynamic(*physics, transform, *geometry, *mMaterial, PxReal(.1));
// if(!mActor) {
// MessageBox( NULL, "no actor", "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
// return;
// }
mActor->setLinearVelocity(velocity);
// And add the actor to a scene:
scene->addActor(*mActor);
}
Now, if I create a single entity and initialize it works. Even wirh a second entity var it works as well. Now with an array:
Entity *mEntities[20];
for(int i = 0 ; i < 20 ; i++ ){
ostringstream nameStream;
nameStream << "Sphere_" << i;
string name = nameStream.str();
Entity* sphere = new Entity(Ogre::Vector3(i*5, i*4.5, i*6), Ogre::Vector3(i*5, i*4.5, i*6), "sphere.mesh", name);
sphere->init(mSceneMgr, mPhysics, gScene, PxVec3(-10.0f, 0, 0));
mEntities[i] = sphere;
}
I got Access violation. W/ the just-in-time debugger, it turned out that mActorwas null as well as mMaterial
EDIT:
This code does not work either:
mEntity = Entity(Ogre::Vector3(50.0f, 50.0f, 50.0f), Ogre::Vector3(50.0f, 40.5f, 60.0f), "sphere.mesh", "sphere");
mEntity.init(mSceneMgr, mPhysics, gScene, PxVec3(-10.0f, 0, 0));
1)
Entity* sphere = new Entity(Ogre::Vector3(i*5, i*4.5, i*6),
Ogre::Vector3(i*5, i*4.5, i*6),
"sphere.mesh",
"Sphere_"+i);
Look at the "Sphere_"+i
If the i is larger then length of ”Sphere_” you are passing pointer to some random memory. I assume that you wanted to create a string with i at the end.
Use sprintf or std::string for that.
2)
If you change the loop range from 20 to let's say 3 it will probably work. The problem is that your names will be:
Sphere_, phere_, here_
Because by doing "Sphere_"+i you are not adding integer to the string.
This is "equal" to:
char *string = "String";
string += 3;
3)
This code will generate string that you need:
std::ostringstream newStringStream;
newStringStream << "Sphere_" << i;
std::string newString = newStringStream.str();
Here is another issue:
PxGeometry* geometry = NULL;
if(mMesh == "sphere.mesh")
{
geometry = &PxSphereGeometry(mDimensions.x / 2); // Because it's a radius
}
The problem with this is that you are assigning to geometry the address of a temporary value. Once that line of code is completed, that temporary is gone.
The probable fix for this is to do this:
PxGeometry geometry;
if(mMesh == "sphere.mesh")
{
geometry = PxSphereGeometry(mDimensions.x / 2); // Because it's a radius
}
//...
mActor = PxCreateDynamic(*physics, transform, geometry, *mMaterial, PxReal(.1));
Now geometry is no longer a pointer, and you're assigning geometry to the value returned, (not address-of the value returned).
I am reading the documentation here:
http://docs.nvidia.com/gameworks/content/gameworkslibrary/physx/apireference/files/classPxSphereGeometry.html
So PxSphereGeometry(x) is a constructor call. So you need to assign the return value to a PxShpereGeometry, not a PxSphereGeometry*.
Edit: Your latest changes also do not have the desired effect:
if(mMesh == "sphere.mesh")
{
PxGeometry g = PxSphereGeometry(mDimensions.x / 2); // Because it's a radius
geometry = &g;
}
The g is local to the if() block. You assign the address of this g to geometry. Then when that block exits, g is gone, and now you have geometry pointing to something that no longer exists.
The difference between your edited code and the answer I gave is that my answer assigns the return value to an existing object. So I created a duplicate of the return value. What your doing in the edited code is not creating a duplicate, but pointing to a local object, which as explained, won't exist after it leaves scope.
So if you were to write code that follows the pattern of your edited code, and have it be valid, the change would look like this:
PxGeometry geometry;
if(mMesh == "sphere.mesh")
{
PxGeometry g = PxSphereGeometry(mDimensions.x / 2); // Because it's a radius
geometry = g;
}
However, this does extraneous work. The original answer is sufficient.
I tried the alternate way to create a rigid body and it worked!!!!
mActor = physics->createRigidDynamic(PxTransform(PxVec3(mPosition.x, mPosition.y, mPosition.z)));
PxShape* shape = mActor->createShape(PxSphereGeometry(mDimensions.x / 2), *mMaterial);
PxRigidBodyExt::updateMassAndInertia(*mActor, 0.4f);
I have loaded an array from a text file, which contains positions of objects, and it looks like this:
0,0,0,5
0,5,0,0
0,0,5,0
0,5,5,0
The object looks like this:
struct object
{
int x, y, value;
}
Where x,y are coordinates, and value is 1 or 0 (it tells if an object was "picked", all objects have 1 at the beginning). Objects are stored in an array object obj_array[5].
To draw them, I use this function:
(BOARD_Y and BOARD_Y is size of the array, here is 4x4)
void draw_board(){
for (int iy = 0; iy < BOARD_Y; iy++) {
for (int ix = 0; ix < BOARD_X; ix++) {
if ( (board[iy][ix] == 5) )
{
glPushMatrix();
glTranslatef( ix, iy, 0 );
glutSolidCube(1);
glPopMatrix();
}
}
}
}
And it draws all of them perfectly. But I want to skip drawing an object, if its value is 0 (the object was picked by a player). How can I do this?
Okey, I can see what's going on; you've complicated the things a bit. There's no way to access the arbitrary object just from this loop, apart from pretty stupid comparison of position:
if ( (board[iy][ix] == 5) ) {
for (auto const& obj : objects) {
if (obj.x == ix && obj.y == iy) {
// obj is the object in given position
// ...
break;
}
}
}
Don't do that.
Instead either store some reference to the objects on the board. By reference I mean (not limited to!):
An unique object ID
Pointer to the object
Then, you will be able to access the object residing on given tile much faster and easier. If you want examples, drop a comment, but I think both options are fairly easy to implement.
If you still want to hold these "5" inside, change board to array of structs. And oh, please use std::array instead of int**.
Here's the example
using id_t = unsigned;
std::map<id_t, object> objects;
constexpr std::size_t size_x = 4, size_y = 4;
std::array<id_t, size_x * size_y> board;
Let's assume that id equal to 0 means that the object is not there.
Now you can access the specific object by:
unsigned x, y;
id_t obj_id = board[x + size_x * y];
if (obj_id != 0) // is there any object?
if (objects[obj_id].value != 0) // is its value equal to 0?
// ...
And set it by board[...] = obj;
Easy way to generate unique id for every object is just to increment the counter.
id_t last_id = 1;
objects[last_id++] = obj_id;