Spawning sprites randomly on x-axis - ios

Hi I need to spawn balloons which are my sprites along the bottom of the x axis out of the screen randomly. I used this code from Ray Wenderliches website but when i click the button that starts the spawning they don't spawn?
#implementation MyScene2
- (void)addMonster {
// Create sprite
SKSpriteNode * monster = [SKSpriteNode spriteNodeWithImageNamed:#"balloon11.png"];
// Determine where to spawn the monster along the X axis
int minX = monster.size.height / 2;
int maxX = self.frame.size.height - monster.size.height / 2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) + minX;
// Create the monster slightly off-screen along the right edge,
// and along a random position along the X axis as calculated above
monster.position = CGPointMake(self.frame.size.width + monster.size.width/2, actualX);
[self addChild:monster];
// Determine speed of the monster
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
SKAction * actionMove = [SKAction moveTo:CGPointMake(-monster.size.width/2, actualX)
duration:actualDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
[monster runAction:[SKAction sequence:#[actionMove, actionMoveDone]]];
}
- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {
self.lastSpawnTimeInterval += timeSinceLast;
if (self.lastSpawnTimeInterval > 1) {
self.lastSpawnTimeInterval = 0;
[self addMonster];
}
}
- (void)update:(NSTimeInterval)currentTime {
// Handle time delta.
// If we drop below 60fps, we still want everything to move the same distance.
CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval;
self.lastUpdateTimeInterval = currentTime;
if (timeSinceLast > 1) { // more than a second since last update
timeSinceLast = 1.0 / 60.0;
self.lastUpdateTimeInterval = currentTime;
}
[self updateWithTimeSinceLastUpdate:timeSinceLast];
}

Your main problem lies in this lines of code:
monster.position = CGPointMake(self.frame.size.width + monster.size.width/2 , actualX);
That method works like this: CGPointMake( x_coord , y_coord );.
Right now, you are setting the x value to width of the frame plus the width of the sprite, so this will cause the sprite to be spawned off the screen. You are giving the y coordinate the randomized value. Instead, use
CGPointMake(actualX , self.frame.size.height);
Now there is another problem with this code. These coordinates are based on the view, but monster.position is based on the SKScene. The SKScene origin usually does not match up with the origin for the view. So you have to do it like this:
monster.position = [CGPointMake(actualX , self.frame.size.height); locationInNode: self];
Also, I noticed that you are using frame.size.width for intended Y axis coordinates and frame.size.height for intended X axis coordinates. Width is for x and height is for y, so make sure you are using those properly.

Related

Best way to randomly move sprite forever in Sprite Kit

I have a sprite and I want to move it to random points forever. I have written this code, but I don't think it is efficient.
-(void)addBoss {
SKSpriteNode *boss = [SKSpriteNode spriteNodeWithImageNamed:#"Spaceship"];
boss.position = CGPointMake(self.size.width + boss.size.width / 2.0, self.size.height / 2.0);
boss.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:boss.size];
boss.physicsBody.dynamic = YES;
boss.physicsBody.categoryBitMask = bossCategory;
boss.physicsBody.contactTestBitMask = bossContact;
boss.physicsBody.collisionBitMask = 0;
boss.zPosition = 1;
self.boss = boss;
self.bossHealth = bossHP;
CGPoint destination = CGPointMake(self.size.width - boss.size.width / 2.0, boss.position.y);
float time = length(boss.position, destination) / bossSpeed;
SKAction *move = [SKAction moveTo:destination duration:time];
[self addChild:boss];
[self.boss runAction:[SKAction sequence:#[move, [SKAction runBlock:^{
[self artificialIntelligence];
}]]]];
}
- (void)moveBoss {
float minimumX = self.size.width / 2.0 + self.boss.size.width / 2.0;
float maximumX = self.size.width - self.boss.size.width / 2.0;
float minimumY = self.boss.size.height / 2.0;
float maximumY = self.size.height - self.boss.size.height / 2.0;
int rangeX = maximumX - minimumX;
int rangeY = maximumY - minimumY;
float x = arc4random() % rangeX + minimumX;
float y = arc4random() % rangeY + minimumY;
CGPoint dest = CGPointMake(x, y);
float duration = length(self.boss.position, dest) / putinSpeed;
[self.boss runAction:[SKAction moveTo:dest duration:duration] completion:^{
[self moveBoss];
}];
}
-(void)artificialIntelligence {
[self moveBoss];
}
This code works fine, but I don't think that calling the move method recursively after movement finished is not the best solution.
What is the best way to solve this kind of problem?
This is a quick and dirty way to do what you asked:
-(void)moveCharacter {
SKNode *playerNode;
// get random position
CGPoint destination = [self randomPosition];
if(!CGPointEqualToPoint(playerNode.position, destination)) {
// check xPos
if(playerNode.position.x > destination.x) {
playerNode.position = CGPointMake(playerNode.position.x-1, playerNode.position.y);
}
if(playerNode.position.x < destination.x) {
playerNode.position = CGPointMake(playerNode.position.x+1, playerNode.position.y);
}
// check yPos
if(playerNode.position.y > destination.y) {
playerNode.position = CGPointMake(playerNode.position.x, playerNode.position.y-1);
}
if(playerNode.position.y < destination.y) {
playerNode.position = CGPointMake(playerNode.position.x, playerNode.position.y+1);
}
} else {
destinationReached = YES;
}
}
-(CGPoint)randomPosition {
CGRect screenRect = [[UIScreen mainScreen] bounds];
int xPos = arc4random() % (int)screenRect.size.width;
int yPos = arc4random() % (int)screenRect.size.height;
return CGPointMake(xPos, yPos);
}
There are many different variations on how to move your character. You could for example divide the difference of x,y into a fixed number of movements as to have the player move in a smooth line from point A to B. If you are physics to move your player, you would have to use CGVector instead of directly changing his x,y position.

How do i keep falling spritenodes within the view?

i am trying to make an iphone game similar to the raywenderlich : sprite Kit tutorial for Beginners Turorial. I am trying to make this in portait mode however, instead of the landscape mode which is used in the tutorial. I used this code and adjusted it so that the sprites fall from the top of the screen to the bottom, but sometimes the sprite are half outside the view or even more.
http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners
This is what i got:
SKSpriteNode * monster = [SKSpriteNode spriteNodeWithImageNamed:#"AcornFinal.png"];
// Determine where to spawn the monster along the X axis
int minX = self.frame.size.width;
int maxX = self.frame.size.width - monster.size.width;
int rangeX = maxX + minX;
int actualX = (arc4random() % + rangeX);
// Random position along the X axis as calculated above
// This describe from which way the acorns move
// - means moving from top to the right and + means moving from the top to the left
monster.position = CGPointMake(actualX,self.frame.size.height);
[self addChild:monster];
// Determine speed of the monster
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
SKAction * actionMove = [SKAction moveTo:CGPointMake(actualX,-monster.size.height) duration:actualDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
[monster runAction:[SKAction sequence:#[actionMove, actionMoveDone]]];
So I believe that the problem probably is in these four lines of code :
// Determine where to spawn the monster along the X axis
int minX = self.frame.size.width;
int maxX = self.frame.size.width - monster.size.width;
int rangeX = maxX + minX;
int actualX = (arc4random() % + rangeX);
How can i fix this error>?
EDIT
solution was to change the first four lines into
int minX = monster.size.width;
int maxX = self.frame.size.width - monster.size.width;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX)+minX;
If the idea is to keep the monsters within the horizontal-bounds of the screen your math seems somewhat of. If the anchor point of the sprite is 0.5, 0.5 and the scene-size equals the screen I believe it should be:
int minX = monster.size.width / 2;
int maxX = self.frame.size.width - monster.size.width;
int x = (arc4random() % + maxX) + minX;

How to make sprites come down from top of screen?

I'm making a simple iOS game where the goal is to fire arrows from a bow at the bottom of the screen to destroy monsters coming from the top of the screen. I have this bit of code, but it only makes monsters spawn and move left from the right side of the screen. Here's the code:
- (void) spawnMonster
{
SKSpriteNode *monster = [SKSpriteNode spriteNodeWithImageNamed: #"Monster"];
monster.xScale = 0.5;
monster.yScale = 0.5;
int minY = monster.size.height / 2;
int maxY = self.frame.size.height - monster.size.height / 2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
monster.position = CGPointMake(self.frame.size.width + monster.size.width / 2, actualY);
[self addChild: monster];
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
SKAction *actionMove = [SKAction moveTo: CGPointMake(-monster.size.width / 2, actualY) duration: actualDuration];
SKAction *actionMoveDone = [SKAction removeFromParent];
[monster runAction: [SKAction sequence: #[actionMove, actionMoveDone]]];
}
Suggestions? Thanks.
If you want objects falling from the top then you should set the arc4random function to the monster sprite's X and not Y. The Y should always be the top of your view. Remember x is the left/right axis and y is the up/down axis.

Animate Sprite Vertically

I am having real trouble getting a sprite to spawn on the screen at the top and then animate it from the top to the bottom. I have been following Ray Wenderlich’s tutorial on creating a simple game however that moves the sprite from right to left, I would like it to move from top to bottom and now I’m tremendously stuck! Below is my current code:
- (void)addComet:(CCTime)dt
{
// Make sprite
CCSprite *comet = [CCSprite spriteWithImageNamed:#"PlayerSprite.png"];
// Verticle spawn range
int minY = comet.contentSize.width;
int maxY = self.contentSize.height - comet.contentSize.height / 2;
int rangeY = maxY - minY;
int randomY = (arc4random() % rangeY) + minY;
// Position comets slightly off the screen
comet.position = CGPointMake(self.contentSize.width + comet.contentSize.width, randomY);
[self addChild:comet];
// Duration range comets take to fly across screen
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int randomDuration = (arc4random() % rangeDuration) + minDuration;
// Give comet animation
CCAction *actionMove = [CCActionMoveTo actionWithDuration:randomDuration position:CGPointMake(0, 500)];
CCAction *actionRemove = [CCActionRemove action];
[comet runAction:[CCActionSequence actionWithArray:#[actionMove,actionRemove]]];
}
If anyone could point me in the right direction because I’ve been stuck on this for quite a while and just cannot get the sprite to spawn randomly at the top of the screen and then animate down to the bottom. I have also looked at sample code such as tweejump but have had no luck.
Now, I haven't got Cocos2D in any of my projects, so don't know if there are any typos, but generally it should probably look a little something like the below. The idea is that all the comets should start at the same Y-position (off-screen) but have a randomized horizontal (x) position...
- (void)addComet:(CCTime)dt
{
// Make sprite
CCSprite *comet = [CCSprite spriteWithImageNamed:#"PlayerSprite.png"];
NSInteger y = self.contentSize.height; // perhaps + comet.contentSize.height / 2, if the anchorPoint is 0.5, 0.5
// Random horizontal position
NSInteger maxX = self.contentSize.width;
NSInteger randomX = (arc4random() % maxX);
// Position comets slightly off the screen
comet.position = CGPointMake(randomX, y);
[self addChild:comet];
// Duration range comets take to fly across screen
NSInteger minDuration = 2.0;
NSInteger maxDuration = 4.0;
NSInteger rangeDuration = maxDuration - minDuration;
NSInteger randomDuration = (arc4random() % rangeDuration) + minDuration;
// Give comet animation
CCAction *actionMove = [CCActionMoveTo actionWithDuration:randomDuration position:CGPointMake(randomX, 0)]; // Moving it in a straight line vertically
CCAction *actionRemove = [CCActionRemove action];
[comet runAction:[CCActionSequence actionWithArray:#[actionMove,actionRemove]]];
}

Changing Sprite Spawns

Here is my code that I m using below and i want it to spawn from the bottom of the x-axis in portrait mode right now in spawns from the top in portrait mode how do i edit the code to do this?
- (void)addBalloon {
// Create sprite
SKSpriteNode * monster = [SKSpriteNode spriteNodeWithImageNamed:#"balloon"];
// Determine where to spawn the monster along the X axis
int minX = monster.size.width / 2;
int maxX = self.frame.size.width - monster.size.width / 2;
int rangeX = maxX - minX;
int actualX = (arc4random_uniform(rangeX)) + minX;
// Create the monster slightly off-screen along the top,
// and along a random position along the X axis as calculated above
monster.position = CGPointMake(actualX, self.frame.size.height +
monster.size.height/2);
[self addChild:monster];
// Determine speed of the monster
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
SKAction * actionMove = [SKAction moveTo:CGPointMake(actualX, -
monster.size.height/2) duration:actualDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
[monster runAction:[SKAction sequence:#[actionMove, actionMoveDone]]];
}
I'm not sure what you are asking here. You want to spawn a sprite on the bottom of the X-axis?
In case it is what I think you are asking, you only have to switch:
monster.position = CGPointMake(actualX, self.frame.size.height + monster.size.height/2);
&&
SKAction * actionMove = [SKAction moveTo:CGPointMake(actualX, - monster.size.height/2) duration:actualDuration];
with:
monster.position = CGPointMake(actualX, - monster.size.height/2);
&&
SKAction * actionMove = [SKAction moveTo:CGPointMake(actualX, self.frame.size.height + monster.size.height/2) duration:actualDuration];

Resources