In Cocos2d/OpenGL-ES check pixel of previous draw? - iphone

I'm drawing some lines in cocos2d (using handy ccDrawLine), nothing fancy, but i want to check if my animated line hits something. I could do some math calculations for some objects, but for some dynamic parts in the scene it would be much easier if i could do:
if pixel not black at (x,y)
// line will hit something
do handleCollisionDetectedAt(x,y)
What would you suggest? At least what would you suggest if it would be simple OpenGL ES.

Found solution:
GLubyte pColor[4];
glReadPixels(x,y,1,1,GL_RGBA,GL_UNSIGNED_BYTE,&pColor[0]);
int red = pColor[0];
int green = pColor[1];
int blue = pColor[2];
NSLog(#"(R,G,B) = (%d,%d,%d)",red,green,blue);

Related

SpriteKit : calculate distance between two texture masks

I have two irregular shapes in SpriteKit, and I want to calculate the vertical distance from the base of a space ship and the (irregular) terrain right below.
Is there a way to do it ?
Thanks !
Place an SKPhysicsBody that is in a shape of a line at the center of your ship with a width of 1 and the height of your scene, then in the didBeginContact method, grab the 2 contact points. You now know 2 points, just use the distance formula (in this case it is just y2-y1) and you have your answer
I found a different way to solve my problem, but I think that KnightOfDragon's one is conceptually better (although I did not manage to make it work).
The terrain's texture is essentially a bitmap with opaque and transparent pixels. So I decided to parse these pixels, storing the highest opaque pixel for each column, building a "radar altitude map". So I just have to calculate the difference between the bottom of the ship and the altitude of the column right beneath its center:
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(terrain.texture.CGImage));
const UInt32 *pixels = (const UInt32*)CFDataGetBytePtr(imageData);
NSMutableArray *radar = [NSMutableArray new];
for (long col = 0; col < terrain.size.width; col++)
[radar addObject:#(0)];
for (long ind = 0; ind < (terrain.size.height * terrain.size.width); ind++)
{
if (pixels[ind] & 0xff000000) // non-transparent pixel
{
long line = ind/terrain.size.width;
long col = ind - (line*terrain.size.width);
if ([radar[col]integerValue] <terrain.size.height-line) radar[col] = #(terrain.size.height-line);
}
}
This solution could be optimized, of course. It's just the basic idea.
I've added an image to show the original texture, its representation as opaque/transparent pixels, and a test by putting little white nodes to check where the "surface" was.

How to make geometry follow a curve?

Is it possible to make some sprites/objects to copy itself and bend in a curve?
I made an image to show what i mean:
Here the curve, possibly a bezier path is green and the geometry is shown in black. I want the sprite or object (on the left) to copy itself and merge it's vertices with the last copy, while the last two vertices follow the curve.
If it is, how to do it? Is there any documentation on something like this? Have you done something like this? How?
EDIT: I don't want the sprite or object to move through the path, but kind of duplicate itself and merge itself with it's copies.
Yes, what you want to do can work, and your drawing shows how it works fairly well. The pseudocode would look something like this:
curveLength = <length of entire curve>;
tileLength = <length of 1 tile>;
currentLength = 0;
while (currentLength < curveLength)
{
currentTileLength = 0;
startPt = prevPt = calculateBezierAt(0.0);
for (t = delta; (t < 1) && (currentTileLength < tileLength); t += delta) // delta is up to you. I often use 1/100th
{
nextPt = calculateBezierAt(t);
distance = distanceBetween(prevPt, nextPt);
currentTileLength += distance;
currentLength += distance;
prevPt = nextPt;
}
endPt = prevPt;
// Calculate quad here
}
To calculate each quad, you need to generate perpendiculars at the start and end points. You then have 4 points for your quad.
Note that I've simplified things by assuming there's only a single bezier. Normally, you'll have many of them connected together, so it will be a little trickier to iterate over them than I've said above, but it shouldn't be too hard.
Also note that if you have either very tight corners or if the curve loops back on itself you may get bad-looking results. Presumably you'll avoid that if your generating the curves yourself, though.
Take a look at SCNShape, which generates a SceneKit geometry from a Bézier curve.

(Unity3D) Paint with soft brush (logic)

During the last few days i was coding a painting behavior for a game am working on, and am currently in a very advanced phase, i can say that i have 90% of the work done and working perfectly, now what i need to do is being able to draw with a "soft brush" cause for now it's like am painting with "pixel style" and that was totally expected cause that's what i wrote,
my current goal consist of using this solution :
import a brush texture, this image
create an array that contain all The alpha values of that texture
When drawing use the array elements in order to define the new pixels alpha
And this is my code to do that (it's not very long, there is too much comments)
//The main painting method
//theObject = the object to be painted
//tmpTexture = the object current texture
//targetTexture = the new texture
void paint (GameObject theObject, Texture2D tmpTexture, Texture2D targetTexture)
{
//x and y are 2 floats from another class
//they store the coordinates of the pixel
//that get hit by the RayCast
int x = (int)(coordinates.pixelPos.x);
int y = (int)(coordinates.pixelPos.y);
//iterate through a block of pixels that goes fro
//Y and X and go #brushHeight Pixels up
// and #brushWeight Pixels right
for (int tmpY = y; tmpY<y+brushHeight; tmpY++) {
for (int tmpX = x; tmpX<x+brushWidth; tmpX++) {
//check if the current pixel is different from the target pixel
if (tmpTexture.GetPixel (tmpX, tmpY) != targetTexture.GetPixel (tmpX, tmpY)) {
//create a temporary color from the target pixel at the given coordinates
Color tmpCol = targetTexture.GetPixel (tmpX, tmpY);
//change the alpha of that pixel based on the brush alpha
//myBrushAlpha is a 2 Dimensional array that contain
//the different Alpha values of the brush
//the substractions are to keep the index in range
if (myBrushAlpha [tmpY - y, tmpX - x].a > 0) {
tmpCol.a = myBrushAlpha [tmpY - y, tmpX - x].a;
}
//set the new pixel to the current texture
tmpTexture.SetPixel (tmpX, tmpY, tmpCol);
}
}
}
//Apply
tmpTexture.Apply ();
//change the object main texture
theObject.renderer.material.mainTexture = tmpTexture;
}
Now the fun (and bad) part is the code did exactly what i asked for, but there is something that i didn't think of and i couldn't solve after spend the whole night trying,
the thing is that by asking to draw anytime with the brush alpha i found myself create a very weird effect which is decreasing the alpha value of an "old" pixel, so i tried to fix that by adding an if statement that check if the current alpha of the pixel is less than the equivalent brush alpha pixel, if it is, then augment the alpha to be equal to the brush, and if the pixel alpha is bigger, then keep adding the brush alpha value to it in order to have that "soft brushing" effect, and in code it become this :
if (myBrushAlpha [tmpY - y, tmpX - x].a > tmpCol.a) {
tmpCol.a = myBrushAlpha [tmpY - y, tmpX - x].a;
} else {
tmpCol.a += myBrushAlpha [tmpY - y, tmpX - x].a;
}
But after i've done that, i got the "pixelized brush" effect back, am not sure but i think maybe it's because am making these conditions inside a for loop so everything is executed before the end of the current frame so i don't see the effect, could it be that ?
Am really lost here and hope that you can put me in the right direction,
Thank you very much and have a great day

How do I repeat sprite horizontally ?

I have got the code to repeat X- and Y- which is:
bg = [CCSprite spriteWithFile:#"ipadbgpattern.png" rect:CGRectMake(0, 0, 3000, 3000)];
bg.position = ccp(500,500);
ccTexParams params = {GL_LINEAR,GL_LINEAR,GL_REPEAT,GL_REPEAT};
[bg.texture setTexParameters:&params];
[self addChild:bg];
However, I do not know how to change the params in order for the background to repeat along the horizontal axis.
There's no parameter for that. Just make sure the CGRect spans the region where you want the texture to repeat, and the texture itself must be a power of two (ie 1024x1024).
I'm guessing that maybe you're using a 1024x768 texture and then you'll see a gap between texture repeats.
This cannot be achieved at the GL level, since GL_REPEAT expects textures with power-of-two dimensions.
Take a look at my TiledSprite class for a rather unoptimized, but functional means of arbitrarily repeating an arbitrarily-sized texture or subtexture:
https://gist.github.com/Nolithius/6694990
Here's a brief look at its results and usage:
http://www.nolithius.com/game-development/cocos2d-iphone-repeating-sprite

Is there a gridview in cocos2d of a battleship game?

I've using cocos2d for a while and I want to make a battleship game.
The thing is I can probably do a battleship with UiKit(UIButtons and UIImageView) easier and faster than in cocos2d but I want to take full advantage of cocos2d because I think it's better for games. The problem is that I need a grid for the battleship or something to separate the touches in quadrants. Is there something like a gridview in cocos2d? If not I think I would have to create my own quadrants by programming?
What do you think is the best method?
Thanks a lot
Carlos Vargas
There's not a base class in Cocos2d to do that, but you could easily make a Class specifically designed to handle touches, and mapping them to the correct quadrants.
So if you have a 480x320 screen, and quadrant size is 32, you can get the correct quadrant for a touch like:
With a configuration like this you would have 480/32 = 15 , 320/32 = 10, 10*15 = 150; a 150 quadrants grid.
e.g: To get the quadrant for a touch
// Defined the Quadrant size for your grid
CGPoint quadrantSize = CGPointMake(32.0, 32.0)
// Obtain the quadrant X, Y coordinates for a user touch (assume touchPoint is CGPoint)
int quadrant_x = (int)ceilf(touchPoint.x/quadrantSize.x);
int quadrant_y = (int)ceilf(touchPoint.y/quadrantSize.y);
// Access a Quadrant
quadrantArray[quadrant_x][quadrant_y].touched = YES;