I would like to know if there's such a very basic method to know where exactly the translated object is in 2D space. I would like to clarify my thoughts regarding OpenGL matrices.
Please have a time to take a look at this very few code examples:
class Rectangle
{
public:
//this function does amazing magic!
//..so continue reading
void draw();
inline bool contains(int x, int y) const {
return x >= this->x && x <= this->x + width &&
y >= this->y && y <= this->y + height;
}
int x;
int y;
uint32_t width;
uint32_t height;
protected:
std::vector<Rectangle *> children;
}
solution #1
void Rectangle::draw()
{
glPushMatrix();
glTranslatef(x, y, 0);
...
//popped out the previous matrix so I have a fresh one
glPopMatrix();
//outside the matrix of parent
//not logical (?)
for (auto &i : children)
{
i->draw();
}
}
solution #2
void Rectangle::draw()
{
glPushMatrix();
glTranslatef(x, y, 0);
...
//inside the matrix of parent
//good! the origin now is parent's coordinate.
for (auto &i : children)
{
//previous matrix is not popped out so the origin is parent's (x,y)
i->draw();
}
glPopMatrix();
}
In solution #1, it is simple and very easy to locate the coordinates of each Rectangle::children, however, its quite hard to manage the code and its not an obvious choice for me because those Rectangle::children's origin position must be their parent container, right?
On the other hand, I much preferred the solution #2 and it is an obvious choice because, for every children I will create, their origin will be the parent's location. But, it's very hard for me to manage those Rectangle::children's coordinates. For example, I want to have a hover effect applied on certain Rectangle::children, I would do in implementation #1 as simple as this:
solution #1
for (auto &i : children)
{
if (i->contains(mouse().x, mouse().y)
{
//hover effect!
}
}
solution #2
for (auto &i : children)
{
if (i->contains(mouse().x - this->x,
mouse().y - this->y)
{
//hover effect!
}
}
The main problem I'm really concern of is that I want to have a fixed function in the Rectangle class like isHovering() this will accept 0 number of parameters and I want it be a cv-qualified. What this will do is: will check that the mouse cursor is inside the rectangle.
I think I would mess up the code for this function if I implement the solution #2 here. What do you think? Is there any nice way algorithm existing there I didn't know yet? I would like to ask first before I proceed along way.
Or...there's an existing magic way to implement in the drawing function to be able to achieve this?
Thanks for reading!
Update
Suppose the drawing hierarchy I want to achieve is something like this:
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
//one matrix for every parent-rectangle and its child-rectangle component
xPushMatrix();
//parent
glTranslatef(parent.x, parent.y, 0);
glDrawables();
//children
glTranslatef(child.x, child.y, 0);
glDrawables();
...to N child
xPopMatrix();
xSwapBuffers(window);
xPollEvents();
The problem: What is the right(efficient, clean code) way to find the coordinates of Rectangle::children ?
Hope you get what I mean.
Related
Hello I have a question with Irrlicht library
I want to do a map with a floor I use createHillPlaneMesh.
I'm actually learning Irrlicht, I actually have a camera and cubes.
here is when I launch it :
while (_device.get_device()->run()) {
_device.get_driver()->beginScene(true, true, color);
_scene.get_sceneManager()->drawAll();
_device.get_driver()->endScene();
}
I call addMapBlock and its work great :
void Eo::Scene::addMapBlock(irr::f32 x, irr::f32 y, irr::f32 z)
{
irr::f32 unitSize = 10.0f;
irr::core::vector3df pos;
pos.X = x;
pos.Y = y;
pos.Z = z;
irr::scene::IMeshSceneNode *cube = _sceneManager->addCubeSceneNode(
unitSize, nullptr, -1, pos);
cube->setMaterialFlag(irr::video::EMF_LIGHTING, false);
cube->setMaterialTexture(0,
_device.get_driver()->getTexture("../assets/img/texture.jpg"));
_map.push(cube);
}
and here is when I create the floor but nothing happen :
void Eo::Scene::addMapFloor()
{
irr::core::dimension2d<irr::f32> tileSize(100.0,100.0);
irr::core::dimension2d<irr::u32> tileCount(50,50);
auto material = new irr::video::SMaterial();
irr::f32 hillHeight = 0;
irr::core::dimension2d<irr::f32> countHills(20.0,20.0);
irr::core::dimension2d<irr::f32> textureRepeatCount(1.0,1.0);
irr::scene::IMesh *cube =
_sceneManager->getGeometryCreator()->createHillPlaneMesh(
tileSize,
tileCount,
material,
hillHeight,
countHills,
textureRepeatCount);
material->ColorMaterial = irr::video::E_COLOR_PLANE::ECP_BLUE;
cube->setMaterialFlag(irr::video::EMF_WIREFRAME, true);
}
Might be I miss something but I try to read and replicate the documentation.
When you do:
_sceneManager->getGeometryCreator()->createHillPlaneMesh(/* args */);
You just create a mesh (the geometric description of an object). You then have to create a scene node to display your mesh somewhere in your scene:
IMesh* mesh = _sceneManager->getGeometryCreator()->createHillPlaneMesh(/* args */);
IMeshSceneNode* node = _sceneManager->addMeshSceneNode(mesh /*, optional args*/);
// Once you don't need the mesh variable anymore, drop it.
mesh->drop();
Side note: It's extremely easy to forget to drop something (especially if parts of the code can throw exceptions), resulting in memory leaks. I advise that you wrap these pointers in some sort of smart pointer (here std::unique_ptr with a custom Deleter, for example).
I've been lately working on a simple game using C++ and SFML latest version, but I had a problem which is that the collision detection is not that good, for example the player dies even if the enemy didn't touch him yet, but just near him. Here is the code of the player class with the move function and collision detection code AND the moves of the enemy class:
`class PlayerA : public CircleShape
{
public:
//Constructor:
PlayerA(float xposition, float yposition, float radius, float s)
{
setRadius(radius);
setFillColor(Color::Yellow);
setOutlineColor(Color(00,80,00));
setOutlineThickness(-2);
setPointCount(3);
setSpeed(s);
setPosition(xposition,yposition);
}
//Movements of the player:
void up()
{
move(0,-10*speed);
}
void down()
{
move(0,10*speed);
}
void right()
{
move(10*speed,0);
}
void left()
{
move(-10*speed,0);
}
void checkA(ObsA *obs1=NULL,ObsA *obs2=NULL, ObsA *obs3=NULL, ObsA *obs4=NULL, ObsA *obs5=NULL)
{
if(obs2==NULL)
{
if(getGlobalBounds().intersects(obs1->getGlobalBounds()))
{
relevel();
}
}
private:
float speed=0.00;
void obs()
{
if(speed > 0)
{
rotate(0.5*speed);
}
else
{
rotate(0.5*speed);
}
}
private:
float speed = 0.00;
void obs()
{
if(speed > 0)
{
rotate(0.5*speed);
}
else
{
rotate(0.5*speed);
}
}
private:
float speed = 0.00;
Is there something wrong with the code, how to fix the problem, thank you!
The intersects function just check if two rectangles intersect. If you want pixel perfect collision detection in SFML you have to write that yourself.
Basically, start with intersects, if it is true, then get the intersecting rectangle and check if any pixels therein from both original rectangles contains overlaping relevant pixels.
You can use this function to perform better collision detection.Its a basic one but works well
bool circleTest(const sf::Sprite &first, const sf::Sprite &second)
{
sf::Vector2f firstRect(first.getTextureRect().width, first.getTextureRect().height);
firstRect.x *= first.getScale().x;
firstRect.y *= first.getScale().y;
sf::Vector2f secondRect(second.getTextureRect().width, second.getTextureRect().height);
secondRect.x *= second.getScale().x;
secondRect.y *= second.getScale().y;
float r1 = (firstRect.x + firstRect.y) / 4;
float r2 = (secondRect.x + secondRect.y) / 4;
float xd = first.getPosition().x - second.getPosition().x;
float yd = first.getPosition().y - second.getPosition().y;
return std::sqrt(xd * xd + yd * yd) <= r1 + r2;
}
Are you using a circle? If I remember correctly, the circle will have a rectangle hitbox. If that is the case, then you may have collision between the invisible rectangle corners.
If you're using a circle, Perhaps change class to a square rectangle and see if collision works correctly. Or try testing collision directly on an x or y axis with your circles; i.e. having them moving in a straight line towards each other only changing 1 axis. (the edge of the circle will be the same as the edge of the rectangle at the left, right, top, and bottom sections).
If you're needing a better collision for circles, there may be one already built in SFML. But I don't think it would be too much to write your own logic using the radius of your two circles, the center of your two objects, and the angle hypotenuse between the centers.
edit based on Merlyn Morgan-Graham's comment.
Hey so i've made a 'body' class, which inherits from sf::drawable in SFML that holds shapes together so i can form more complicated shapes and figures. I found i had to do a few updates on each individual member shape at render time, based on what's happened to the body over-all since last render.
This included:
Rotation
Translations
Scaling
I thought i would have to manually write the code to factor in these changes that could have occured to the overall body, so the shape positions turned out right. However when coding the Rotation part, i found after writing the manual code that even though i made Bodies Render() function only iterate through and render each shape without changing them, they somehow came out with the right orientation anyway. HOW CAN THIS BE?
I commented out the code i wrote and apparently didn't need, and i use the Draw() function to render. Please explain to me my own code! (God i feel retarded).
here's the class:
class Body : public sf::Drawable{
public:
Body(const sf::Vector2f& Position = sf::Vector2f(0, 0), const sf::Vector2f& Scale = sf::Vector2f(1, 1), float Rotation = 0.f, const sf::Color& Col = sf::Color(255, 255, 255, 255)){
SetPosition(Position);
SetScale(Scale);
SetRotation(Rotation);
SetColor(Col);
RotVal=0;};
////////////////// Drawable Functions ////////////////////
void SetX(float X){
MoveVal.x += X - GetPosition().x;
Drawable::SetX(X);};
void SetY(float Y){
MoveVal.y += Y - GetPosition().y;
Drawable::SetY(Y);};
void SetRotation(float Rotation){
RotVal+= Rotation-GetRotation();
Drawable::SetRotation(Rotation);};
////////////////////////////////////////////////////////////
bool AddShape(sf::Shape& S){
Shapes.push_back(S); return true;};
bool AddSprite(sf::Sprite& S){
Sprites.push_back(S); return true;};
void Draw(sf::RenderTarget& target){
for(unsigned short I=0; I<Shapes.size(); I++){
//Body offset
Shapes[I].SetPosition(
Shapes[I].GetPosition().x + MoveVal.x,
Shapes[I].GetPosition().y + MoveVal.y);
// Aparrently Body shapes rotate on their own...
//WWTFFFF>>>>??????????
//Body Rotation
//float px= GetPosition().x,
// py= GetPosition().y,
// x= Shapes[I].GetPosition().x,
// y= Shapes[I].GetPosition().y,
// rot= ConvToRad(RotVal);
/*Shapes[I].SetPosition(
px + ((x-px)*cos(rot)) - ((y-py)*sin(rot)),
py - ((x-px)*sin(rot)) + ((y-py)*cos(rot)));*/ //TODO: put this in a math header
//Shapes[I].Rotate(RotVal);
}
target.Draw(*this); // draws each individual shape
//Reset all the Change Values
RotVal=0;
MoveVal.x=0;
MoveVal.y=0;
};
private:
sf::Vector2f MoveVal;
float RotVal;
std::vector<sf::Shape> Shapes;
std::vector<sf::Sprite> Sprites;
virtual void Render(sf::RenderTarget& target) const{
for(unsigned short I=0; I<Shapes.size(); I++){
target.Draw(Shapes[I]);}
for(unsigned short I=0; I<Sprites.size(); I++){
target.Draw(Sprites[I]);}
};
};
My guess was confirmed by the SFML source code.
When you call target.Draw(*this) it eventually calls Drawable::Draw(RenderTarget& Target) const, which sets up a render matrix which has the rotation that you gave it with the Drawable::SetRotation call. Your virtual Render function is then called, with that rotation environment set up. This means that your body-parts get rotated.
Have a look at the source yourself to get a better understanding. (;
i am drawing an array of pool balls in opengl using c++
the problem i am facing is the array draws in a straight line.
when i use gltranslate the balls still only translate along the line when i edit the z and y axis
what i want to do is set the balls up in a triangle shape like the breaking of a pool match
how do i use the array code to set the balls up like this?
any help would be much appreciated
balls[7];
for (int x = ball-start; x<ball-end;x++)
{
glTranslatef(0,0,0.5);
glColor3f(1,0,0);
ball[x].drawball();
}
assuming:
struct Ball {
double x,y,z;
void drawball(void);
/* ... */
} ball[7];
try:
for(int i=0; i<7 ;i++)
{
glPushMatrix();
glTranslated(ball[i].x,ball[i].y,ball[i].z);
glColor3f(1,0,0);
ball[i].drawball();
glPopMatrix();
}
details probably vary, but hopefully you get the idea.
Do something like this:
// first of all, include the x,y position (assuming 2D, since pool) in the Ball object:
class Ball
{
//...
private:
float xpos, ypos;
//...
};
Then when you construct the array of balls, rather than just making 8 balls, you're going to want to allocate the memory on the heap so that it will last throughout your entire game. So do this:
Ball *ball= new Ball*[8];
ball[0] = new Ball(x0,y0);
ball[1] = new Ball(x1,y1);
ball[2] = new Ball(x2,y2);
ball[3] = new Ball(x3,y3);
// ...
Make sure that when your game is over, you clean up after yourself.
for (int i = 0; i < 8; i++)
delete ball[i];
delete [] ball;
Then in your Ball::draw() do something like this:
Ball::draw()
{
glColor3f(/*yellow*/); // Set the color to yellow
glTranslatef(-xpos, -ypos, 0); // Move to the position of the ball
// Draw the ball
glTranslatef(xpos, ypos, 0); // Move back to the default position
}
All you have to do is come up with the correct (x0,y0),(x1,y1),(x2,y2)... to form a triangle! Does this make sense/answer your question?
I'm a openFrameworks newbie. I am learning basic 2d drawing which is all great so far. I have drawn a circle using:
ofSetColor(0x333333);
ofFill;
ofCircle(100,650,50);
My question is how do I give the circle a variable name so that I can manipulate in the mousepressed method? I tried adding a name before the ofCircle
theball.ofSetColor(0x333333);
theball.ofFill;
theball.ofCircle(100,650,50);
but get I 'theball' was not declared in this scope error.
As razong pointed out that's not how OF works. OF (to the best of my knowledge) provides a handy wrapper to a lot of OpenGL stuff. So you should use OF calls to effect the current drawing context (as opposed to thinking of a canvas with sprite objects or whatever). I usually integrate that kind of thing into my objects. So lets say you have a class like this...
class TheBall {
protected:
ofColor col;
ofPoint pos;
public:
// Pass a color and position when we create ball
TheBall(ofColor ballColor, ofPoint ballPosition) {
col = ballColor;
pos = ballPosition;
}
// Destructor
~TheBall();
// Make our ball move across the screen a little when we call update
void update() {
pos.x++;
pos.y++;
}
// Draw stuff
void draw(float alpha) {
ofEnableAlphaBlending(); // We activate the OpenGL blending with the OF call
ofFill(); //
ofSetColor(col, alpha); // Set color to the balls color field
ofCircle(pos.x, pos.y, 5); // Draw command
ofDisableAlphaBlending(); // Disable the blending again
}
};
Ok cool, I hope that makes sense. Now with this structure you can do something like the following
testApp::setup() {
ofColor color;
ofPoint pos;
color.set(255, 0, 255); // A bright gross purple
pos.x, pos.y = 50;
aBall = new TheBall(color, pos);
}
testApp::update() {
aBall->update()
}
testApp::draw() {
float alpha = sin(ofGetElapsedTime())*255; // This will be a fun flashing effect
aBall->draw(alpha)
}
Happy programming.
Happy designing.
You can't do it that way. ofCircle is a global drawing method and draws just a circle.
You can declare a variable (or better three int for rgb - since you can't use ofColor as an argument for ofSetColor) that store the color for the circle and modify it in the mousepressed method.
Inside the draw method use your variables for ofSetColor before rendering the circle.