Moving origin co ordinates from bottom left to center of screen - cocos2d-iphone

The origin i.e - X and Y (0, 0) co-ordinates starts from bottom left of screen (Portrait mode).
Is there a way I can move origin(0, 0) to center of screen.
So, that I can differentiate when my sprite is on positive or negative axis on both X and Y co-ordinates ?
Or is there any other logic that could be used to know when sprite is either left or right side of screen ?

Cocos2d works with a tree of nodes, the position of each subnode is relative to the parent.
This means that if you add a middle node between your layer and everything else you can easily obtain the desired behavior. For example:
Node* mainNode = Node::create();
mainNode->setPosition(Point(WIDTH/2, HEIGHT/2));
layer->addChild(mainNode);
// this will now place the sprite in the middle of the viewport
Node* sprite = ...
sprite->setPosition(Point::ZERO);
mainNode->addChild(sprite);

Related

Why is the screen space coordinate system for my sfml rendered app inverted?

I am learning C++ and I thought I'd make the original asteroids game with a fresh coat of paint using the SFML graphics library. However, for my player sprite, while the origin is at the top left corner of the screen, to the right of it is the negative x axis and downwards is negative y axis (opposite of what it's supposed to be in both cases). Also, no matter what object or rotation, invoking the setRotation function always rotates any object about the top left corner of the screen even if, for that object, I have set the origin to the object's center.
#include<SFML\Graphics.hpp>
using namespace sf;
const int W{ 1200 }, H{ 800 };
const float degToRad = 0.017453f;
int main() {
float x{ -600 }, y{ -400 };
float dx{}, dy{}, angle{};
bool thrust;
RenderWindow app(VideoMode(W, H), "Asteroids!");
app.setFramerateLimit(60);
Texture t1, t2;
t1.loadFromFile("images/spaceship.png");
t2.loadFromFile("images/background.jpg");
Sprite sPlayer(t1), sBackground(t2);
sPlayer.setTextureRect(IntRect(40, 0, 40, 40));
sPlayer.setOrigin(-600, -400);
while (app.isOpen())
{
app.clear();
app.draw(sPlayer);
app.display();
}
return 0;
}
The above code draws the player (spaceship.png) to the center of my rendered window (app) but notice how I have had to put in negative coordinates. Also, if I further put in the code for taking keyboard inputs and call the setRotation function, instead of rotating my sPlayer sprite about its center (i.e. (-600,-400)), it rotates the sprite about the top left corner of the screen which is (0,0). I can't find any explanation for this in the SFML online documentation. What should I do?
As I mentioned I have tried reading the documentation. I've watched online tutorials but to no avail.
Origin is the point on sprite where you "hold" it.
Position is the point on screen where you put Origin of the sprite.
In short, you take your sprite by Origin and put it so Origin is on Position.
By default, both Origin and Position are (0, 0), so top left of your sprite is put at top left of the screen. What you did was to say "take this point on sprite, which is way to the upper-left that actual visible part of the sprite is and put it to the top left of the screen". This had an effect of moving your sprite to the bottom right.
You probably want something like:
// This is will make sure that Origin, i.e. point which defines rotation and other transformations center is at center of the ship
sPlayer.setOrigin(sprite_width / 2, sprite_height / 2);
// This will put Origin (center of the ship) at center of the screen
sPlayer.setPosition(screen_width / 2, screen_height / 2);

OpenGL - get mouse position co-ordinates

I am making a 2D board game. the game board grid is 8x8 and each cell of the grid is an object. So a board consists of 64 cell objects. My aim is to work out which cell the mouse is in. I am attempting this by tracking the mouse coordinates and comparing it to the grid coordinates.
my coordinate system is as follows:
gluOrtho2D(-4,4,-4,4);
I am trying to get the current mouse position by using the following in my update function:
POINT p
if (GetCursorPos(&p)){
}
if (ScreenToClient(hWnd, &p))
{
}
However although this is tracking the coordinates of the mouse it is not correctly tracking the world coordinates that I set with gluOrtho2D. How can I achieve this?
It depends on your glViewPort
Let's say you have:
glViewport(0,0, 640, 640);
The mouse position is (mousePos.x,mousePos.y) and the world position you want to know is (world.x, world.y)
And, give that the top/left corner of your screen is the (0, 0) coordinate
Then we can make the following:
world.x = -4.0 + (mousePos.x / 640.0) * (4*2)
world.y = 4.0 - (mousePos.y / 640.0) * (4*2)
What we are doing here is a linear interpolation using the normalize position of the mouse within the screen (mousePos.x / 640) and then multiplying this value to the width of the word (4*2).
Given that the top/left corner of the grid start at (-4, 4), we add the offset of the world position.

Rotating a fire / exhaust animated sprite around a 2D spaceship whilst still keeping it at the bottom - C++

In the below code I have the player ship face in the direction of the mouse position. How exactly would I go about attaching an exhaust / fire animation to the bottom of the ship so that it always stays at the bottom of the ship and rotates with the ship? The origin x, y points of all sprites are centered.
void CMyGame::OnMouseMove(Uint16 x,Uint16 y,Sint16 relx,Sint16 rely,bool bLeft,bool bRight,bool bMiddle)
{
player_rotation = atan2(y - player.GetY(), x - player.GetX()) * (180/3.14159);
if (player_rotation < 0) player_rotation = 360 - (-player_rotation);
player.SetRotation(player_rotation-90);
}
Angle 0 / 360 is when the ship is facing right. 90 is facing up. So it's clockwise starting from the right direction.
When I create an animated fuel / fire sprite, it's placed at this position:
player.GetX(), player.GetY() - player.GetWidth() / 2, fire_texture);
meaning it will be initially placed at the very bottom middle of the player ship, as you'd expect for a spaceship's exhaust. But I need it to rotate with the ship so that if the ship is facing left, the exhaust would have it's position updated to be rotated in the same angle as the ship, meaning the exhaust would be facing left as well - while still being attached to the bottom of the ship.

Parent coordinate given a CCNode local coordinate

Is there any cocos2d function that returns the parent coordinate given a node local coordinate? It must be quite a common use case, but I've not found any native cocos2d function. Is there any?
I guess it's something like this. NOTE, I haven't tested this one. ;)
-(CGPoint) nodeToParent: (CGPoint) localPoint
{
CGFloat phi = -self.rotation * B2_pi / 180;
return ccpAdd(self.position, ccpRotateByAngle(localPoint, ccp(0, 0), phi));
}
As m.ding said ... parent->ConvertToNodeSpace() .....
Here's explanation for you so you know when to do what ?
convertToWorldSpace(const CCPoint& nodePoint) converts on-node coords to SCREEN coordinates.
Lets we have layerA with anchor point and position (0,0) attached to screen and have a sprite on this layer at point (100, 100).
What will be SCREEN coords of sprite? - (100, 100)
Lets we moved layerA to point (- 50, - 20). What will be SCREEN coords of sprite? - (100 - 50, 100 - 20), i.e. (50, 80) - that's what convertToWorldSpace returns to us if we call layerA->convertToWorldSpace(ccp(100, 100)).
As for convertToWorldSpaceAR - will return the position relatevely to anchor point: so if our scene - root layer has AP (0.5f, 0.5f) - default, convertToWorldSpaceAR should return position relatively to screen center. I have used convertToNodeSpace
convertToNodeSpace(const CCPoint& worldPoint) - converts SCREEN coords to NODE's local. I.e. if for our example with moved layer call:
layerA->convertToNodeSpace(ccp(50, 80)) - that should return (100, 100) - our sprite on-node coords.
convertToNodeSpaceAR - the same logic as for convertToWorldSpaceAR
assume your parent node is
CCSprite* parent;
you can use:
parent->convertToNodeSpace();
I guess that
-(CGPoint) convertToWorldSpace:(CGPoint)pt
could do the trick, take a look here.
It looks like you are on the right track. [node position] should give the position of the node in the parent's coordinate space, so if you have a local point that is offset from the [node position] then you need to do add the offset like you have done. I'm not sure the ccpRotateByAngle is the right method to do that but you'll just have to test it and find out!

Implementing a "grab" camera panning tool in a 3D scene

In my scene I have terrain that I want to "grab" and then have the camera pan (with its height, view vector, field of view, etc. all remaining the same) as I move the cursor.
So the initial "grab" point will be the working point in world space, and I'd like that point to remain under the cursor as I drag.
My current solution is to take the previous and current screen points, unproject them, subtract one from the other, and translate my camera with that vector. This is close to what I want, but the cursor doesn't stay exactly over the initial scene position, which can be problematic if you start near the edge of the terrain.
// Calculate scene points
MthPoint3D current_scene_point =
camera->screenToScene(current_point.x, current_point.y);
MthPoint3D previous_scene_point =
camera->screenToScene(previous_point.x, previous_point.y);
// Make sure the cursor didn't go off the terrain
if (current_scene_point.x != MAX_FLOAT &&
previous_scene_point.x != MAX_FLOAT)
{
// Move the camera to match the distance
// covered by the cursor in the scene
camera->translate(
MthVector3D(
previous_scene_point.x - current_scene_point.x,
previous_scene_point.y - current_scene_point.y,
0.0));
}
Any ideas are appreciated.
With some more sleep :
Get the initial position of your intersected point, in world space and in model space ( relative to the model's origin)
i.e use screenToScene()
Create a ray that goes from the camera through the mouse position : {ray.start, ray.dir}
ray.start is camera.pos, ray.dir is (screenToScene() - camera.pos)
Solve NewPos = ray.start + x * ray.dir knowing that NewPos.y = initialpos_worldspace.y;
-> ray.start.y + x*ray.dir.y = initialpos_worldspace.y
-> x = ( initialpos_worldspace.y - ray.start.y)/rad.dir.y (beware of dividebyzeroexception)
-> reinject x in NewPos_worldspace = ray.start + x * ray.dir
substract initialpos_modelspace from that to "re-center" the model
The last bit seems suspect, though.