I have two UIButtons, the user can select one of them, so when one is selected the other is deselected. I want to animate this change like this :
I know I need to use Core Graphics, but how can I achieve this ?
Thanks for your help
You want to use linear interpolation on the hover circle graphic.
The way it works is something along these lines:
Final Position = [(Destination Position) * Time/TotalTimeForMovement] + [(Origin Position) * (1-Time/TotalTimeForMovement)]
Let's say you want to move the white hover graphic from Layer1 to Layer2 in 0.2 seconds when the user shifts his/her mouse from Layer1 to Layer2. In that case, you'd want to update the graphics position every frame, where:
Final Position = [(Layer2 Position) * CurrentTimePassed/0.2] + [(Layer1 Position) * 1-(CurrentTimePassed/0.2)]
So to continue this example: Let's assume that the position of Layer1 is (0, 0) and the position of Layer2 is (10, 0). Then, 0.1 seconds into the movement (assuming that it moves completely in 0.2 seconds), the position of the graphic should be:
= (0, 10) * 0.1/0.2 + (0, 0) * 1-(0.1/0.2)
= (0, 10) * 0.5 + (0, 0) * 1-0.5
= (0, 10) * 0.5 + (0, 0) * 0.5
= (0, 5) + (0, 0)
= (0, 5)
Which is halway between Layer1 and Layer2. Hope that helps.
Related
I can move object (star) around cube’s corner using accelerometer. Object move following the orbit (green circle). Control inverted, if I tilt right object go left and vise versa.
While spinning cube around corner object move perfect. But when I stop spinning cube, object on one of the cube’s edges, cause of inverted control start jittering.
For example if I try to stop object between red and blue planes, it begins jumping from one plane to another.
Code for object movement
new accelX = abi_MTD_GetFaceAccelX(object.plane);
new accelY = abi_MTD_GetFaceAccelY(object.plane);
object.angle -= accelX - accelY;
if (object.angle >= 90) {
object.plane = GetRightPlane(object.plane);
object.angle -= 90;
} else if (object.angle <= 0) {
object.plane= GetBottomPlane(object.plane);
object.angle = 90 + spaceship.angle;
}
MovePointAlongCircle(OUT object.posX, OUT object.posY, object.orbit, object.angle);
Find coordinate on plane
const OBJECT _ORBIT_CENTER = 260;
new objectOrbit = 150;
MovePointAlongCircle(&posX, &posY, objectOrbit, anglePhi) {
posX = OBJECT_ORBIT_CENTER - (objectOrbit * cos(anglePhi));
posY = OBJECT _ORBIT_CENTER - (objectOrbit * sin(anglePhi));
}
I can get accelerometer values individually on each plane or like the cube is a one thing.
Trigonometric functions like sin and cos use fixed point and look up table.
I've got atan function, which return angle [-45; 45].
Atan(x) {
return ((PI_4_FIXED * x >> FP) - ((x * (ABS(x) - 256) >> FP) * (62 + (17 * ABS(x) >> FP)) >> FP)) * RAD_2_DEG >> FP;
}
I've got a project where I'm designing an image viewer for tiled images. Every image tile is 256x256 pixels. For each level of scaling, I'm increasing the size of each image by 5%. I represent the placement of the tiles by dividing the screen into tiles the same size as each image. An offset is used to precicely place each image where needed. When the scaling reaches a certain point(1.5), I switch over to a new layer of images that altogether has a greater resolution than the previous images. The zooming method itself looks like this:
def zoomer(self, mouse_pos, zoom_in): #(tuple, bool)
x, y = mouse_pos
x_tile, y_tile = x / self.tile_size, y / self.tile_size
old_scale = self.scale
if self.scale > 0.75 and self.scale < 1.5:
if zoom_in:
self.scale += SCALE_STEP # SCALE_STEP = 5% = 0.05
ratio = (SCALE_STEP + 1)
else:
self.scale -= SCALE_STEP
ratio = 1 / (SCALE_STEP + 1)
else:
if zoom_in:
self.zoom += 1
self.scale = 0.8
ratio = (SCALE_STEP + 1)
else:
self.zoom -= 1
self.scale = 1.45
ratio = 1 / (SCALE_STEP + 1)
# Results in x/y lengths of the relevant full image
x_len = self.size_list[self.levels][0] / self.power()
y_len = self.size_list[self.levels][1] / self.power()
# Removing extra pixel if present
x_len = x_len - (x_len % 2)
y_len = y_len - (y_len % 2)
# The tile's picture coordinates
tile_x = self.origo_tile[0] + x_tile
tile_y = self.origo_tile[1] + y_tile
# The mouse's picture pixel address
x_pic_pos = (tile_x * self.tile_size) -
self.img_x_offset + (x % self.tile_size)
y_pic_pos = (tile_y * self.tile_size) -
self.img_y_offset + (y % self.tile_size)
# Mouse percentile placement within the image
mouse_x_percent = (x_pic_pos / old_scale) / x_len
mouse_y_percent = (y_pic_pos / old_scale) / y_len
# The mouse's new picture pixel address
new_x = (x_len * self.scale) * mouse_x_percent
new_y = (y_len * self.scale) * mouse_y_percent
# Scaling tile size
self.tile_size = int(TILE_SIZE * self.scale)
# New mouse screen tile position
new_mouse_x_tile = x / self.tile_size
new_mouse_y_tile = y / self.tile_size
# The mouse's new tile address
new_tile_x = new_x / self.tile_size
new_tile_y = new_y / self.tile_size
# New tile offsets
self.img_x_offset = (x % self.tile_size) - int(new_x % self.tile_size)
self.img_y_offset = (y % self.tile_size) - int(new_y % self.tile_size)
# New origo tile
self.origo_tile = (int(new_tile_x) - new_mouse_x_tile,
int(new_tile_y) - new_mouse_y_tile)
Now, the issue arising from this is that the mouse_.._percent variables never seem to match up with the real position. For testing purposes, I feed the method with a mouse position centered in the middle of the screen and the picture centered in the middle too. As such, the resulting mouse_.._percent variable should, in a perfect world, always equal 50%. For the first level, it does, but quickly wanders off when scaling. By the time I reach the first zoom breakpoint (self.scale == 1.5), the position has drifted to x = 48%, y = 42%.
The self.origo_tile is a tuple containing the x/y coordinate for the tile to be drawn on screen tile (0, 0)
I've been staring at this for hours, but can't seen to find a remedy for it...
How the program works:
I apologize that I didn't have enough time to apply this to your code, but I wrote the following zooming simulator. The program allows you to zoom the same "image" multiple times, and it outputs the point of the image that would appear in the center of the screen, along with how much of the image is being shown.
The code:
from __future__ import division #double underscores, defense against the sinister integer division
width=256 #original image size
height=256
posx=128 #original display center, relative to the image
posy=128
while 1:
print "Display width: ", width
print "Display height: ", height
print "Center X: ", posx
print "Center Y: ", posy
anchx = int(raw_input("Anchor X: "))
anchy = int(raw_input("Anchor Y: "))
zmag = int(raw_input("Zoom Percent (0-inf): "))
zmag /= 100 #convert from percent to decimal
zmag = 1/zmag
width *= zmag
height *= zmag
posx = ((anchx-posx)*zmag)+posx
posy = ((anchy-posy)*zmag)+posy
Sample output:
If this program outputs the following:
Display width: 32.0
Display height: 32.0
Center X: 72.0
Center Y: 72.0
Explanation:
This means the zoomed-in screen shows only a part of the image, that part being 32x32 pixels, and the center of that part being at the coordinates (72,72). This means on both axes it is displaying pixels 56 - 88 of the image in this specific example.
Solution/Conclusion:
Play around with that program a bit, and see if you can implement it into your own code. Keep in mind that different programs move the Center X and Y differently, change the program I gave if you do not like how it works already (though you probably will, it's a common way of doing it). Happy Coding!
I'm having trouble figuring out how to generate matrixes.
Hopefully that picture explains it, but basically I have an initial position, and I'm trying to rotate the main joint, 90 degrees, then following that, rotate the last joint, by 90 degrees. I then apply translation afterwards to get a final matrix (see code). That is applied to a set of points, that are relative to its joint.
The last rotation doesn't seem to work, it is ok if I don't put in the line: matrixPositions[2].appliedRotationMatrix *= (matrixRotX * matrixRotY * matrixRotZ); (the leg is straight down). I must be missing something obvious? Can you not do matrix multiplication this way for rotations?
D3DXMATRIX matrixRotX, matrixRotY, matrixRotZ;
D3DXMatrixRotationX(&matrixRotX, 0);
D3DXMatrixRotationY(&matrixRotY, 0);
D3DXMatrixRotationZ(&matrixRotZ, -PI/2);
matrixPositions[0].appliedRotationMatrix *= (matrixRotX * matrixRotY * matrixRotZ);
D3DXMATRIX matTranslationIn1;
D3DXMatrixTranslation(&matTranslationIn1, (matrixPositions[0].position.x-matrixPositions[1].position.x), (matrixPositions[0].position.y-matrixPositions[1].position.y), (matrixPositions[0].position.z-matrixPositions[1].position.z));
D3DXMATRIX matTranslationOut1;
D3DXMatrixTranslation(&matTranslationOut1, -(matrixPositions[0].position.x-matrixPositions[1].position.x), -(matrixPositions[0].position.y-matrixPositions[1].position.y), -(matrixPositions[0].position.z-matrixPositions[1].position.z));
matrixPositions[1].appliedRotationMatrix *= (matTranslationIn1 * (matrixRotX * matrixRotY * matrixRotZ) * matTranslationOut1);
D3DXMatrixTranslation(&matTranslationIn1, (matrixPositions[0].position.x-matrixPositions[2].position.x), (matrixPositions[0].position.y-matrixPositions[2].position.y), (matrixPositions[0].position.z-matrixPositions[2].position.z));
D3DXMatrixTranslation(&matTranslationOut1, -(matrixPositions[0].position.x-matrixPositions[2].position.x), -(matrixPositions[0].position.y-matrixPositions[2].position.y), -(matrixPositions[0].position.z-matrixPositions[2].position.z));
matrixPositions[2].appliedRotationMatrix *= (matTranslationIn1 * (matrixRotX * matrixRotY * matrixRotZ) * matTranslationOut1);
matrixPositions[2].appliedRotationMatrix *= (matrixRotX * matrixRotY * matrixRotZ);
D3DXMATRIX matrix[3];
for (int x = 0; x < 3; x++)
{
D3DXMatrixIdentity( &matrix[x]);
D3DXMATRIX matTranslation;
D3DXMatrixTranslation(&matTranslation, matrixPositions[x].position.x, matrixPositions[x].position.y, matrixPositions[x].position.z);
matrix[x] = matrix[x] * matrixPositions[x].appliedRotationMatrix * matTranslation;
}
There are two main steps for your requirements.
Rotate joints 0, 1 and 2 around the origin by 90 degrees.
Rotate joint 2 around joint 1 by 90 degrees.
I write some pseudo code, it almost done, but you still need some updates to use it. see comments in the code for details.
void Rotatation()
{
// Build up the rotation matrix for step 1
D3DXVECTOR3 rotAxis(0, 0, 1);
float angle = -(D3DX_PI / 2);
D3DXMATRIX rotMatrix;
D3DXMatrixRotationAxis(&rotMatrix, &rotAxis, angle);
// rotate joints 0, 1 and 2 by apply the matrix above
for (int i = 0; i < 3; i++)
{
joints[i].matrix *= rotMatrix;
}
// Build up the rotation matrix for joint 2
// Since joint 2 was not rotate around the origin(I mean the axis should pass the origin), so first you need to translate the rotation center to origin
// then rotate joint 2, and last move back
// After the rotation in step 1, joint 1 now locate at (0, 2, 0)
// to translate it to the origin.
D3DXMATRIX transMat;
D3DXMatrixTranslation(&transMat, 0, 2, 0);
// Now joint 2 can rotate around z-axis, so the rotate matrix is same as step 1
// after rotation, move back, this matrix is the inverse of transMat
D3DXMATRIX inverseTransMat;
D3DXMatrixTranslation(&transMat, 0, -2, 0);
// Combine the 3 matrix above
D3DXMATRIX rotMatjoin2 = transMat * rotMatjoin2 * inverseTransMat;
// rotate jonit 2
joints[2].matrix *= rotMatjoin2;
}
So I've managed myself to write the first part (algorithm) to calculate each tile's position where should it be placed while drawing this map (see bellow). However I need to be able to convert mouse location to the appropriate cell and I've been almost pulling my hair off because I can't figure out a way how to get the cell from mouse location. My concern is that it involves some pretty high math or something i'm just something easy i'm not capable to notice.
For example if the mouse position is 112;35 how do i calculate/transform it to to get that the cell is 2;3 at that position?
Maybe there is some really good math-thinking programmer here who would help me on this or someone who knows how to do it or can give some information?
var cord:Point = new Point();
cord.x = (x - 1) * 28 + (y - 1) * 28;
cord.y = (y - 1) * 14 + (x - 1) * (- 14);
Speaking of the map, each cell (transparent tile 56x28 pixels) is placed in the center of the previous cell (or at zero position for the cell 1;1), above is the code I use for converting cell-to-position. I tried lot of things and calculations for position-to-cell but each of them failed.
Edit:
After reading lot of information it seems that using off screen color map (where colors are mapped to tiles) is the fastest and most efficient solution?
I know this is an old post, but I want to update this since some people might still look for answers to this issue, just like I was earlier today. However, I figured this out myself. There is also a much better way to render this so you don't get tile overlapping issues.
The code is as simple as this:
mouse_grid_x = floor((mouse_y / tile_height) + (mouse_x / tile_width));
mouse_grid_y = floor((-mouse_x / tile_width) + (mouse_y / tile_height));
mouse_x and mouse_y are mouse screen coordinates.
tile_height and tile_width are actual tile size, not the image itself. As you see on my example picture I've added dirt under my tile, this is just for easier rendering, actual size is 24 x 12. The coordinates are also "floored" to keep the result grid x and y rounded down.
Also notice that I render these tiles from the y=0 and x=tile_with / 2 (red dot). This means my 0,0 actually starts at the top corner of the tile (tilted) and not out in open air. See these tiles as rotated squares, you still want to start from the 0,0 pixel.
Tiles will be rendered beginning with the Y = 0 and X = 0 to map size. After first row is rendered you skip a few pixels down and to the left. This will make the next line of tiles overlap the first one, which is a great way to keep the layers overlapping coorectly. You should render tiles, then whatever in on that tile before moving on to the next.
I'll add a render example too:
for (yy = 0; yy < map_height; yy++)
{
for (xx = 0; xx < map_width; xx++)
{
draw tiles here with tile coordinates:
tile_x = (xx * 12) - (yy * 12) - (tile_width / 2)
tile_y = (yy * 6) + (xx * 6)
also draw whatever is on this tile here before moving on
}
}
(1) x` = 28x -28 + 28y -28 = 28x + 28y -56
(2) y` = -14x +14 +14y -14 = -14x + 14y
Transformation table:
[x] [28 28 -56 ] = [x`]
[y] [-14 14 0 ] [y`]
[1] [0 0 1 ] [1 ]
[28 28 -56 ] ^ -1
[-14 14 0 ]
[0 0 1 ]
Calculate that with a plotter ( I like wims )
[1/56 -1/28 1 ]
[1/56 1/28 1 ]
[0 0 1 ]
x = 1/56*x` - 1/28y` + 1
y = 1/56*x` + 1/28y` + 1
I rendered the tiles like above.
the sollution is VERY simple!
first thing:
my Tile width and height are both = 32
this means that in isometric view,
the width = 32 and height = 16!
Mapheight in this case is 5 (max. Y value)
y_iso & x_iso == 0 when y_mouse=MapHeight/tilewidth/2 and x_mouse = 0
when x_mouse +=1, y_iso -=1
so first of all I calculate the "per-pixel transformation"
TileY = ((y_mouse*2)-((MapHeight*tilewidth)/2)+x_mouse)/2;
TileX = x_mouse-TileY;
to find the tile coordinates I just devide both by tilewidth
TileY = TileY/32;
TileX = TileX/32;
DONE!!
never had any problems!
I've found algorithm on this site http://www.tonypa.pri.ee/tbw/tut18.html. I couldn't get it to work for me properly, but I change it by trial and error to this form and it works for me now.
int x = mouse.x + offset.x - tile[0;0].x; //tile[0;0].x is the value of x form witch map was drawn
int y = mouse.y + offset.y;
double _x =((2 * y + x) / 2);
double _y= ((2 * y - x) / 2);
double tileX = Math.round(_x / (tile.height - 1)) - 1;
double tileY = Math.round(_y / (tile.height - 1));
This is my map generation
for(int x=0;x<max_X;x++)
for(int y=0;y<max_Y;y++)
map.drawImage(image, ((max_X - 1) * tile.width / 2) - ((tile.width - 1) / 2 * (y - x)), ((tile.height - 1) / 2) * (y + x));
One way would be to rotate it back to a square projection:
First translate y so that the dimensions are relative to the origin:
x0 = x_mouse;
y0 = y_mouse-14
Then scale by your tile size:
x1 = x/28; //or maybe 56?
y1 = y/28
Then rotate by the projection angle
a = atan(2/1);
x_tile = x1 * cos(a) - y1 * sin(a);
y_tile = y1 * cos(a) + x1 * sin(a);
I may be missing a minus sign, but that's the general idea.
Although you didn't mention it in your original question, in comments I think you said you're programming this in Flash. In which case Flash comes with Matrix transformation functions. The most robust way to convert between coordinate systems (eg. to isometric coordinates) is using Matrix transformations:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html
You would want to rotate and scale the matrix in the inverse of how you rotated and scaled the graphics.
Here is what my code look like
CCSprite *sp = [CCSprite spriteWithFile:#"textureWithOneColorbackground.jpg"];
[self addChild:sp];
// Change the blending factors
[sp setBlendFunc:(ccBlendFunc){GL_ONE, GL_ONE}];
[sp setColor:ccBLACK];
The original texture color is (246,149,32)
The outcome now is (0, 0, 0)
According to OpenGL, the calculation should be like this:
((246 * 1 + 0 * 1), (149 * 1 + 0 * 1), (32 * 1 + 0 * 1))
So it should be the same.
Don't know why I am doing wrong here, can someone help me out?
Regards,
[sp setBlendFunc:(ccBlendFunc){GL_ONE, GL_ONE}];
setBlendFunc sets glBlendFunc. source blending factor and destination blending factor.
[sp setColor:ccBLACK];
setColor doesn't mean it is for destination blending color. It means to set color for vertex color.
You set black (R=0,G=0,B=0,A=1) for vertex color and if background color is black,
(([texture color]246 * [vertex color](0 / 255) * [GL_ONE]1 + [background color]0 * [GL_ONE]1), (149 * (0 / 255) * 1 + 0 * 1), (32 * (0 / 255) * 1 + 0 * 1)) = (0, 0, 0)
iPhone 3D Programming is a nice book for understanding OpenGL ES on iPhone.
According to the docs:
http://www.cocos2d-iphone.org/api-ref/0.99.0/interface_c_c_sprite.html#af0c786f0f5b4081a4524e78eda9c8734
The Blending function property belongs
to CCSpriteSheet, so you can't
individually set the blending function
property.
You seem to be applying it to the sprite and not the sheet. Try applying the blend to the sheet.