in the init-method I initialize a NSMutableArray holding 4 images. I use this code to radomly place out the sprites (images):
_obstacles = [[NSMutableArray alloc] initWithCapacity:TOTAL_OBSTACLES_PER_WALL];
for (int i = 0; i < TOTAL_OBSTACLES_PER_WALL; i++)
{
obstacle = [CCSprite spriteWithTexture:obstaclesTxt];
int minX = obstacle.contentSize.width/2;
int maxX = winSize.width-obstacle.contentSize.width/2;
int xRange = maxX-minX;
int minY = obstacle.contentSize.height/2;
int maxY = winSize.height-obstacle.contentSize.height/2;
int yRange = maxY - minY;
randomXloc = (arc4random() % xRange) + minX;
randomYloc = (arc4random() % yRange) + minY;
obstacle.position = ccp(randomXloc, randomYloc);
[_wall2 addChild:obstacle];
}
Then, in an update-method, if _wall2 leaves screen to the left (it is continously scrolling from right to left) the obstacles should be removed.
if (_wall2.position.x+_wall2.boundingBox.size.width <- 0)
{
_wall2.position = ccp(_wall.boundingBox.origin.x+_wall.boundingBox.size.width+1, 0);
[obstacle removeFromParentAndCleanup:YES];
}
When I run the app, the images are placed out randomly, but when the _Wall2 leaves the screen the app crashes. My question is if it is anything wrong with this code?
Related
I know how to add UIButton to a UIView programmatically. But I'm stuck in adding the UIButton in the new YPosition after a certain number of UIButtons are added in the previous YPosition.
Here is my case:
Number of UIButtons to be added comes from NSArray - Let's take 20
UIView is already added in the UIViewController - Let's call
'buttonView'
I'm creating UIButton using the loop (up to 20). I have set the
buttonWidth as 70 and buttonHeight as 45
I'm getting the screen size and dividing this by the buttonWith, so
as to calculate the number of items that can be accommodated per line
or per Y position.
If the screen width is 414, then 414/70 = ~5.9 and I'm taking it as
First 5 UIButton's YPosition as 0 and XPosition starts from 0 and adding buttonWidth for subsequent buttons.
Next 5 UIButtons (6-10) should have the new YPosition as 1-5 UIButton
Yposition(0)+buttonHeight(45)+somespace(10)= 55 and XPostion should
start with 0.
For the next set of UIButtons(11-15), the YPosition should be
Yposition(55)+buttonHeight(45)+somespace(10)= 100 and XPosition
starts with 0
How to achieve this? Below is my code
xPos = 8.0f;
yPos = 0.0f;
totalSlots =timeslots.Count - //Total Number UIButtons to be creted
buttonWidth = 70;
buttonHeight = 45;
buttonViewWidth = this.view.frame.size.width // I'm getting the screen
buttonPerLine = scrollViewWidth / (buttonWidth + 10); // This calculates no.of.buttons per line/Y Position. I'm rounding off as said before
numberOfLine = totalSlots / buttonPerLine // This gives how many lines needed
for (int i = 0; i < totalSlots; i++)
{
timeSlotbtn[i] = new UIButton();
timeSlotbtn[i] = new UIButton();
timeSlotbtn[i].Frame = new CGRect(xPos, yPos, buttonWidth, buttonHeight);
timeSlotbtn[i].SetTitle(buttonText, UIControlState.Normal);
timeSlotbtn[i].Layer.BorderWidth = 2.0f;
timeSlotbtn[i].Layer.CornerRadius = 3;
timeSlotbtn[i].Tag = i;
timeSlotbtn[i].TitleLabel.Font = UIFont.FromName("HelveticaNeue-bold", 14.0f);
xPos = timeSlotbtn[i].Frame.Location.X + buttonWidth + buttonSpace;
timeslotScrollView.AddSubview(timeSlotbtn[i]);
}
Pleas be noted the above code is written in Xamarin.iOS. If you know the solution, then probably you can write in Objective-c. Anyhow, the logic should be same.
int buttonWidth = 65;
int buttonSpace = 5;
int buttonHeight = 30;
int totalSlots = timeslots.Count;
nfloat screenSize = firstViewController.screenSize;
nfloat buttonPerLine = screenSize / (buttonWidth + buttonSpace );
int roundedButtonPerLine = Convert.ToInt32(Math.Floor(buttonPerLine));
nfloat totalLines = totalSlots / buttonPerLine;
int roundedTotalLines = Convert.ToInt32(Math.Ceiling(totalLines));
nfloat determineXPosition = (screenSize - (8 + (buttonWidth * roundedButtonPerLine) + (buttonSpace*(roundedButtonPerLine-1))))/2;
nfloat xPos;
if (roundedTotalLines > 1)
{
xPos = determineXPosition;
}
else
{
xPos = 8.0f;
}
nfloat yPos = 0.0f;
int currentLine = 1;
int loopCount = 1;
for (int i = 0; i < room.timeslots.Count; i++)
{
var buttonText = room.timeslots[i].startDate.ConvertDateToStanfordLocalTime();//hour + ":" + minute + "p";
timeSlotbtn[i] = new UIButton();
timeSlotbtn[i].Frame = new CGRect(xPos, yPos, buttonWidth, buttonHeight);
timeSlotbtn[i].SetTitle(buttonText, UIControlState.Normal);
timeSlotbtn[i].Layer.BorderWidth = 2.0f;
timeSlotbtn[i].Layer.CornerRadius = 3;
timeSlotbtn[i].Tag = i;
timeSlotbtn[i].TitleLabel.Font = UIFont.FromName("HelveticaNeue-bold", 14.0f);
xPos = timeSlotbtn[i].Frame.Location.X + buttonWidth + buttonSpace;
timeslotScrollView.AddSubview(timeSlotbtn[i]);
if (loopCount == roundedButtonPerLine)
{
if (roundedTotalLines > 1)
{
xPos = determineXPosition;
}
else
{
xPos = 8.0f;
}
currentLine++;
yPos = timeSlotbtn[i].Frame.Location.Y + buttonHeight + buttonSpace;
loopCount = 0;
}
loopCount++;
}
I am using a for loop to make 7 rope link sprites, can't figure out how to make rope out of them with SKPhysicsJointLimit. :'(
-(void)ropeStuff {
int i ;
int y;
SKSpriteNode *ropes;
SKPhysicsJointLimit * ropeLink;
NSMutableArray *ropeArray;
for (i = 0 ; i < 7; ++i) {
if (i) {
int x = 16;
y = (x * i);
ropes.position = CGPointMake(_cat.position.x, _cat.position.y + (x * i) );
}
ropes = [SKSpriteNode node];
ropes = [SKSpriteNode spriteNodeWithImageNamed:#"rope link.png"];
ropes.position = CGPointMake(_cat.position.x, _cat.position.y +5);
ropes.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:1];
ropes.physicsBody.affectedByGravity = YES;
ropes.physicsBody.dynamic = YES;
ropes.name = #"rope";
[_worldNode addChild:ropes];
if (i) {
ropeLink = [SKPhysicsJointLimit jointWithBodyA:ropes.physicsBody
bodyB:ropes.physicsBody anchorA:ropes.position anchorB:ropes.position];
[_worldNode.scene.physicsWorld addJoint:ropeLink];
}
}
}
Thank you all for the help! :D
Why are you using SKPhysicsJointLimit? The rope is a group of segments that rotate relatively each other. You should use SKPhysicsJointPin with or without rotation limits.
I am creating a rubber band in Box2d. Here is my code.
// init physics
[self initPhysics];
// Create ball body
CCSprite *ball = [CCSprite spriteWithFile:#"rubberband.png"];
ball.position = ccp(100, 100);
ball.tag = 1;
// [self addChild:ball];
//=======Params
// Position and size
b2Vec2 lastPos = b2Vec2(154.0/PTM_RATIO,65.0/PTM_RATIO); //set position first body
float widthBody = 2.0/PTM_RATIO;
float heightBody = 2.0/PTM_RATIO;
// Body params
float density = 0.0;
float restitution = 0.5;
float friction = 0.5;
// Distance joint
float dampingRatio = 0.85;
float frequencyHz = 10;
// Rope joint
float kMaxWidth = 50.0/PTM_RATIO;
// Bodies
int countBodyInChain = 68;
b2Body* prevBody;
//========Create bodies and joints
for (int k = 0; k < countBodyInChain; k++) {
b2BodyDef bodyDef;
if(k==0 || k==countBodyInChain-1) bodyDef.type = b2_staticBody; //first and last bodies are static
else bodyDef.type = b2_dynamicBody;
bodyDef.position = lastPos;
bodyDef.fixedRotation = YES;
b2Body* body = world->CreateBody(&bodyDef);
b2PolygonShape distBodyBox;
distBodyBox.SetAsBox(widthBody, heightBody);
b2FixtureDef fixDef;
fixDef.density = density;
fixDef.restitution = restitution;
fixDef.friction = friction;
fixDef.shape = &distBodyBox;
body->CreateFixture(&fixDef);
if(k>0) {
b2RevoluteJointDef armJointDef;
armJointDef.Initialize(prevBody, body, lastPos);
armJointDef.enableMotor = true;
armJointDef.enableLimit = true;
armJointDef.maxMotorTorque = 1;
world->CreateJoint(&armJointDef);
//Create rope joint
b2RopeJointDef rDef;
rDef.maxLength = (body->GetPosition() - prevBody->GetPosition()).Length() * kMaxWidth;
rDef.localAnchorA = rDef.localAnchorB = b2Vec2_zero;
rDef.bodyA = prevBody;
rDef.bodyB = body;
rDef.collideConnected = false;
world->CreateJoint(&rDef);
} //if k>0
lastPos += b2Vec2(widthBody, 0); //modify b2Vect for next body
prevBody = body;
} //for -loop
[self scheduleUpdate];
}
return self;
}
Problem is that when the app starts, rubber band appears in stretched form in U shape and then it gradually start contracting and coming to become straight horizontally. Can anyone please tell me why it is happening? I want the rubber band to be without being stretched in the beginning.
Best Regards
You don't update lastPos so all bodies occupy the same position initially. Box2D will force them apart and this could lead to the problem.
So I need help figuring out what code I am missing here. I have checked all over the place, but I need specifics on wether its the formulas used or a typo that i haven't noticed yet.
Here is the polygon class. I am trying to create random polygons with 8 vertices and then of course fill with a plain color. But I want them to continue to generate random position but leave them fixed. In a better way the poly's are my terrain.Ok revise: the polygons are there and my character interacts with them, but I cannot see them, and yes they are on the same layer. Oh but they don't keep generating at the bottom, which i am guessing i just need to delete the old ones once they go off the screen and it should make a new poly.
-(void) genBody:(b2World *)world pos:(CGPoint *)pos {
//Here we generate a somewhat random convex polygon by sampling
//the "eccentric anomaly" of an ellipse with randomly generated
//x and y scaling constants (a,b). The algorithm is limited by
//the parameter max_verts, and has a number of tunable minimal
//and scaling values.
// I need to change this to randomly choosing teh number of vertices between 3-8,
// then choosing random offsets from equally distributed t values.
// This will eliminate teh while loop.
screen_pos = ccp(pos->x, pos->y);
float cur_t;
float new_t;
float delta_t;
float min_delta_t = 0.5;
float t_scale = 1.5;
b2Vec2 *verts= new b2Vec2[m_maxVerts]; // this should be replaced by a private verts ... maybe ... hmm that will consume more ram though
float t_vec[m_maxVerts];
// Generate random vertices
int vec_len;
while (true) {
cur_t = 0.0;
for (vec_len=0; vec_len<m_maxVerts; vec_len++) {
//delta_t = t_scale*(float)rand()/(float)RAND_MAX; // wish they just had a randf method :/
delta_t = t_scale*floorf((double)arc4random()/ARC4RANDOM_MAX);
#ifdef POLY_DEBUG
CCLOG(#"delta_t %0.2f", delta_t);
#endif
if (delta_t < min_delta_t) {
delta_t = min_delta_t;
}
new_t = cur_t + delta_t;
if (new_t > 2*PI) {
break;
}
t_vec[vec_len] = new_t;
cur_t = new_t;
}
// We need at least three points for a triangle
if ( vec_len > 3 ) {
break;
}
}
At least where the body is being generated.
then...
float num_verts = vec_len;
b2BodyDef BodyDef;
BodyDef.type = b2_staticBody;
BodyDef.position.Set(pos->x/PTM_RATIO, pos->y/PTM_RATIO);
BodyDef.userData = self; // hope this is correct
m_polyBody = world->CreateBody(&BodyDef);
b2PolygonShape polyShape;
int32 polyVert = num_verts;
polyShape.Set(verts, polyVert);
b2FixtureDef FixtureDef;
FixtureDef.shape = &polyShape;
FixtureDef.userData = self; // hope this is correct
FixtureDef.density = 1.6f;
FixtureDef.friction = 0.4f;
FixtureDef.restitution = 0.5f;
m_polyBody->CreateFixture(&FixtureDef);
for (int i=0; i < num_verts; i++) {
// Convert from b2Vec2 to CCPoint and from physics units to pixels
m_verts[i] = ccp(verts[i].x*PTM_RATIO, verts[i].y*PTM_RATIO);
}
m_numVerts = num_verts;
delete verts;
}
-(void) setColor:(ccColor4F) color {
m_color = color;
}
-(BOOL) dirty {
return true;
}
-(void) draw {
//[super draw];
ccDrawPoly(m_verts, m_numVerts, YES);
CCLOG(#"Drawing?");
}
-(CGAffineTransform) nodeToParentTransform {
b2Vec2 pos = m_polyBody->GetPosition();
float x = pos.x * PTM_RATIO;
float y = pos.y * PTM_RATIO;
/*if ( ignoreAnchorPointForPosition_ ) {
x += anchorPointInPixels_.x;
y += anchorPointInPixels_.y;
}*/
// Make matrix
float radians = m_polyBody->GetAngle();
float c = cosf(radians);
float s = sinf(radians);
if( ! CGPointEqualToPoint(anchorPointInPixels_, CGPointZero) ){
x += c*-anchorPointInPixels_.x + -s*-anchorPointInPixels_.y;
y += s*-anchorPointInPixels_.x + c*-anchorPointInPixels_.y;
}
// Rot, Translate Matrix
transform_ = CGAffineTransformMake( c, s,
-s, c,
x, y );
return transform_;
}
there is some stuff in between but its less important. I can post it if asked.
Then the update function, which is based in my game scene class.
-(void)updateObstacles
{
//CCLOG(#"updating obstacles");
int xpos;
int ypos;
CGPoint pos;
for (int i=0; i<MAX_OBSTACLES; i++ ) {
// If there is no obstacle generate a new one
if ( obstacles[i] == NULL ) {
polyObstacleSprite *sprite = [[polyObstacleSprite alloc] init];
ypos = int(_winSize.width/2*(double)arc4random()/ARC4RANDOM_MAX) - _winSize.width/2;
xpos = int(_winSize.height/2*(double)arc4random()/ARC4RANDOM_MAX) - _winSize.height/2;
//CCLOG(#"generating obstacle at %d,%d", xpos, ypos);
pos = ccp(xpos, ypos);
[sprite genBody:_world pos:&pos];
[self addChild:sprite z:1];
obstacles[i] = sprite;
}
//CCLOG(#"position: %d, %d", obstacles[i]->screen, obstacles[i]->position.y); FINISH
}
}
Sorry if its sort of a mess I set this up quick, but pretty much what I want to do is have randomly generated polygons appear at the bottom of my iphone screen as my character moves down with gravity. I got everything else but the polygons working.
Thanks in advance for spending the time to read this.
I'm a little confused at the moment, first time poster here on stack overflow. I'm brand new to objective C but have learned a lot from my coworkers. What I'm trying to do is traverse a bmContext vertically shifting horizontally by 1 pixel after every vertical loop. Heres some code:
NSUInteger width = image.size.width;
NSUInteger height = image.size.height;
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = width * bytesPerPixel;
NSUInteger bytesPerColumn = height * bytesPerPixel;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = height}, image.CGImage);
UInt8* data = (UInt8*)CGBitmapContextGetData(bmContext);
const size_t bitmapByteCount = bytesPerRow * height;
struct Color {
UInt8 r;
UInt8 g;
UInt8 b;
};
for (size_t i = 0; i < bytesPerRow; i += 4) //shift 1 pixel
{
for (size_t j = 0; j < bitmapByteCount; j += bytesPerRow) //check every pixel in column
{
struct Color thisColor = {data[j + i + 1], data[j + i + 2], data[j + i + 3]};
}
}
in java it looks something like this, but I have no interest in the java version it's just to emphasis my true question. I only care about the objective c code.
for (int x = 0; x = image.getWidth(); x++)
{
for (int y = 0; y = image.getHeight(); y++)
{
int rgb = image.getRGB(x, y);
//do something with pixel
}
}
Am I really shifting one unit horizontally and then checking all vertical pixels and then shifting again horizontally? I thought I was but my results seem to be a little off. In java and c# achieving a task was rather simple, if anyone knows a simpler way to do this in Objective C please let me know. Thanks in advance!
The way you are getting at the pixels seems to be off.
If I'm understanding correctly, you just want to iterate through every pixel in the image, column by column. Right?
This should work:
for (size_t i = 0; i < CGBitmapContextGetWidth(bmContext); i++)
{
for (size_t j = 0; j < CGBitmapContextGetHeight(bmContext); j++)
{
int pixel = j * CGBitmapContextGetWidth(bmContext) + i;
struct Color thisColor = {data[pixel + 1], data[pixel + 2], data[pixel + 3]};
}
}