Snake/Worm movement on 2D envrimoment - algorithm

That's my goal:
I have multiple sprites that makes the personage. The first sprite (on an array of n sprites, where n is the number of segments) is the head and the other sprites must follow that.
So, If the head change his angle and then moves (in the direction where the head is pointing), the other sprites must follow the head, like a snake/worm does.
I'm doing this with cocos2D but is not that relevant because I think that I don't have the concept, because I know cocos2D, but is not this the problem (not the framework).
So, how can I do it? How can the other sprites follow perfectly the head? Game examples are Death Worm or Super Mega Worm on App Store
If needed, I can post the code that I'm using (works bad) and an image of the result, but I don't know if this is needed.
Thanks.

I would simply store all the positions of each section in an arraylist / vector. on Draw have the next head position calculated based on game play then remove the oldest (pos==0) item in the list and draw the sprites at the positions in the list.
I'm sorry if this seems similar to Alexey's answer, I just think this might be a simpler implementation.

You will need to manually set the positions of every sprite that makes the personage. The new position has to be calculated and set inside the scheduled method that gets called repeatedly.
sprite.position = ccp(newX,newY);
You may refer this too: Cocos2D set sprite position in relation to another sprite

Have an array of coordinates for every segment of the critter, including the head.
If it needs to move straight (not changing the direction), you shift the array values so the tail (last) segment gets the coordinates of the adjacent segment, that one gets the coordinates of the one before it and so on and for the head segment you set the new head coordinates, which are equal to old coordinates incremented by the direction vector d:
dx dy direction
0 -1 up
0 +1 down
-1 0 left
+1 0 right
If you want to change the direction, change the direction vector appropriately and then do the same array shift and head coordinate update.

Related

Can't center a 3D object on screen

Currently, I'm taking each corner of my object's bounding box and converting it to Normalized Device Coordinates (NDC) and I keep track of the maximum and minimum NDC. I then calculate the middle of the NDC, find it in the world and have my camera look at it.
<Determine max and minimum NDCs>
centerX = (maxX + minX) / 2;
centerY = (maxY + minY) / 2;
point.set(centerX, centerY, 0);
projector.unprojectVector(point, camera);
direction = point.sub(camera.position).normalize();
point = camera.position.clone().add(direction.multiplyScalar(distance));
camera.lookAt(point);
camera.updateMatrixWorld();
This is an approximate method correct? I have seen it suggested in a few places. I ask because every time I center my object the min and max NDCs should be equal when their are calculated again (before any other change is made) but they are not. I get close but not equal numbers (ignoring the negative sign) and as I step closer and closer the 'error' between the numbers grows bigger and bigger. IE the error for the first few centers are: 0.0022566539084770687, 0.00541687811360958, 0.011035676399427596, 0.025670088917273515, 0.06396864345885889, and so on.
Is there a step I'm missing that would cause this?
I'm using this code as part of a while loop to maximize and center the object on screen. (I'm programing it so that the user can enter a heading an elevation and the camera will be positioned so that it's viewing the object at that heading and elevation. After a few weeks I've determined that (for now) it's easier to do it this way.)
However, this seems to start falling apart the closer I move the camera to my object. For example, after a few iterations my max X NDC is 0.9989318709122867 and my min X NDC is -0.9552042384799428. When I look at the calculated point though, I look too far right and on my next iteration my max X NDC is 0.9420058636660581 and my min X NDC is 1.0128126740876888.
Your approach to this problem is incorrect. Rather than thinking about this in terms of screen coordinates, think about it terms of the scene.
You need to work out how much the camera needs to move so that a ray from it hits the centre of the object. Imagine you are standing in a field and opposite you are two people Alex and Burt, Burt is standing 2 meters to the right of Alex. You are currently looking directly at Alex but want to look at Burt without turning. If you know the distance and direction between them, 2 meters and to the right. You merely need to move that distance and direction, i.e. right and 2 meters.
In a mathematical context you need to do the following:
Get the centre of the object you are focusing on in 3d space, and then project a plane parallel to your camera, i.e. a tangent to the direction the camera is facing, which sits on that point.
Next from your camera raycast to the plane in the direction the camera is facing, the resultant difference between the centre point of the object and the point you hit the plane from the camera is the amount you need to move the camera. This should work irrespective of the direction or position of the camera and object.
You are playing the what came first problem. The chicken or the egg. Every time you change the camera attributes you are effectively changing where your object is projected in NDC space. So even though you think you are getting close, you will never get there.
Look at the problem from a different angle. Place your camera somewhere and try to make it as canonical as possible (ie give it a 1 aspect ratio) and place your object around the cameras z-axis. Is this not possible?

glTranslatef() is moving both, my origin and my sprite

Here is the deal, I'm programming a 2D framework/game engine with opengl ES. I am using VBOs and an ortho projection to draw an arrangement of sprites throughout the screen (as part of the testing), and everything was going nice and smooth until I had to play with translations and rotations. The specific problem I am having is that when I apply a translation with glTranslatef() prior to the rotation, the function does not only move the sprite, but also my origin, messing up my whole transformation. I am 100% sure it is working this way, because I used glTranslatef() to move to the right and bottom the sprite half of the size of the screen (yes, my origin is in the top left) and then apply a constant rotation and the thing just keeps mooving in a circular path around the center of the screen (actually rotating, but not as I expect.
If you want some code, here we go:
gl.glTranslatef(-(x+width/2), -(y+height/2), -layer);
gl.glRotatef(angle, 0.0f, 0.0f, -1.0f);
gl.glTranslatef(x+width/2, y+height/2, layer);
In this fragment of code, x and y are the position of the sprite, height and width are the size of the sprite, angle the angle of rotation, and layer just a form of organizing the sprites into several layers, pretty straight forward, right?
Again, my problem is that glTranslatef(); is moving both, the sprite and the origin, am I doing something wrong or misunderstanding something about the translation?
Thanks in advance.
you might need to use glPushMatrix and glPopMatrix since anything you do after those translations and rotations will be affected by them
but what you are describing is actually how it works, if you use a translate, that sort of becomes your new origin because once you do a translate, everything after that is affected by that translate, thats why you need to push and pop, so that you can go, push -> translate object and/or rotate -> pop, and then you can go about with whatever other translations you need to do without having that previous translation affecting everything else
its a bit confusing at first but google around and you'll see how to use them properly
http://www.khronos.org/opengles/sdk/1.1/docs/man/glPushMatrix.xml
I think you misunderstood how matrices work in openGL. When you do a matrix operation such as glRotatef and glTranslatef the matrices are being multiplied, resulting in affecting the base vectors.. For instance, let's say we are only drawing a point that starts at (0,0,0). If you call translate(1,0,0) the point will be in (1,0,0), after that you call rotate(90, 0, 0, 1) and your point will be on the same place as before but rotated. Now the last call is translate(-1,0,0) and your point is at (1,-1,0) (and not where you started)!
And that is what you did in your "fragment of code". The thing is you did not specify what you really want to do and how do you define your verices is relative as well.. If you want something like a view with some image that you want to control in sense of changing the position and rotation, you might want to create a square vertex buffer with values from -1 to 1 in both dimensions (or (-width/2, -height/2) to (width/2, height/2)). In this case the base center of your object is in (0,0,0) and that is probably the point you want to rotate it around (or am I wrong here?). So when you want to define the position of the object with origin point, you will need to write translatef(x+width/2,y+height/2,..).
As for the whole process of drawing in this case: If you want the origin to be at (x,y,z), with a (width, height) and rotated by (angle) here is the sequence
glTranslatef(x,y,z)
glTranslatef(width/2,height/2,0)
glScalef(width/2,height/2, 1) //only if verices defined at (-1,1)
glRotatef(angle, 0, 0, 1)
Do note in this case that since you rotate the object around its center its origin will not be at (x,y,z) anymore.
In general I would suggest to stay away from glRotate, glTranslate and glScale if possible. They tend to make things very nasty. So another way is to construct a matrix directly from base vectors: With little math you can compute all 4 points of your "square view" based on parameters such as origin, width, height and rotation.. The 4 points being (A-origin), (B-lower left point), (C-lower right point), (D-upper right point) your base vectors are (B-A), (D-A) and normalized(dotProduct((B-A), (D-A))) this 3 vectors can be inserted int top left 3x3 matrix of the GL matrix (witch is 4x4 or float[16]) and they represent both, rotation and scale so all you need to add is the translation part (just google around a bit for this approach).

OpenGL custom navigation/selection

I have a situation that I'm not realy sure how I can handle. I have an openGl object of about 20k vertices, and I need to offer the user the possibility to select any one of these vertices (let's say with a smallest margin of error possible). Now here is what I want to do in order to do this:
Next to the 3D canvas of the object, I also offer the user 3 'slices' done by the planes x=0; y=0 and z=0. Say for the simplest example for a sphere these would be 3 circles, correponding to 'cutting' out one of the dimensions. Now let's take the z=0 one for the purpose of the example. When the user clicks on a point say (x_circle, y_circle) i would like to get the actual point in the 3d representation where he clicked. The z would be 0 of course but I can't figure out a way to get the x and y. I can easily translate that (x_circle, y_circle) -> (x_screen, y_screen) which would have the same result as a click on the canvas at those coordinates, but I need to find a way to translate that into the (x, y, 0) coordinate in 3D view.
The same thing would need to be done with x=0, y=0 but I think if I can understand/implement a way for z=0 I can just apply more or less the same solution with an added rotation over something. If anyone can help with any examples/code or even math behind this it would help a lot because at the moment I'm not really sure how to proceed.
When the user clicks, you can render the vertices using GL.POINTS (with a certain size, if you like) to an off-screen buffer using a shader that renders each vertex' index into RGBA. Then you read back the pixel on the mouse position and see what index it is.

How to change the rotation order in cocos3d

I'm a fresh in cocos3d, now I have a problem.
In cocos3d, I want to rotate a node. I got the angles in x axis, y axis, z axis, then I used the property:rotation to rotate, like this:
theNodeToBeRotated.rotation = cc3v(x,y,z);
But I found out it didn't rotate as I expected, because the document said the rotate order is y-x-z.
I want to change the order to x-y-z. Can anyone let me know how?
You might need to clarify further regarding the following: "it didn't rotate as I expected"
OpenGL ES (and ergo, cocos3D) uses the y-axis as up so the rotation order is still x-y-z. If you are importing a model, you then need to take into account the 3D editor's co-ordinate system and adapt accordingly.
If you are not used to working with three-dimensional representations, the leap from 2D to 3D can be a significant hurdle. Within Cocos3D:
the x-axis is positive on the right and negative on the left
the y-axis is positive upwards and negative downwards
the z-axis is positive moving towards you and negative moving away from you
Envisage those three lines of axis, or even better, a piece of string.
If you are rotating around the x-axis, hold the string horizontally from left to right: the object would rotating towards you or away from you.
If you are rotating around the y-axis, hold the string vertically from feet to head: the object would rotate as if like a revolving door.
If you are rotating around the z-axis, hold one end close to your chest and the other end as far away as possible: the object would rotate similar to a clock face.
-- Update
I heavily wouldn't recommend changing the rotation order as it is the OpenGL standard to use Y-X-Z. If you wish to modify it, take a look at CC3GLMatrixMath and look for kmMat4RotationYXZ - there is also kmMat4RotationZYX. If you want to have X-Y-Z, you would need to construct your own rotation matrix and update accordingly in CC3GLMatrix and CC3GLMatrixMath.
As a reference, you also have the OpenGL Red book - it should have some suggestions for you.

problem with a very simple tile based game

I am trying to create a pacman-like game. I have an array that looks like this:
array:
1111111111111
1000000000001
1111110111111
1000000000001
1111111111111
1 = Wall, 0 = Empty space
I use this array to draw tiles that are 16x16 in size.
The Game character is 32x32.
Initially I represented the character's position in array indexes, [1,1] etc.
I would update his position if array[character.new_y][charater.new_x] == 0
Then I translated these array coordinates to pixels, [y*16, x*16] to draw him.
He was lining up nicely, wouldn't go into walls, but I noticed that since I was updating him by 16 pixels each, he was moving very fast.
I decided to do it in reverse, to store the game character's position in pixels instead, so that he could use less than 16 pixels per move.
I thought that a simple if statement such as this:
if array[(character.new_pixel_y)/16][(character.new_pixel_x)/16] == 0
would prevent him from going into walls, but unfortunately he eats a bit of the bottom and right side walls.
Any ideas how would I properly translate pixel position to the array indexes? I guess this is something simple, but I really can't figure it out :(
you appear to have transposed your 2D array. Was that on purpose?
(is it array[x][y] or array[y][x]?)
also, a game character of double the tile size would not fit in the example map array given!
edit:
if your character eats into the bottom and right by exactly half a tile and he/she doesn't overlap the top & right, then you need to offset your character by half a tile. (+/- 8 pixels to both x & y)
so when you, "translated these array coordinates to pixels, [y*16, x*16] to draw him."
you should change this to:
[(y*16)-8, (x*16)-8] to draw him when he is 32x32.
keep storing his position as [y*16, x*16], to follow the 16x convention.
this would be easier for you if you kept everything 16x16 first!
you should also store the tile_size_x & tile_size_y as a constant.

Resources