iOS game moving object up and down - ios

I am trying to create a game, something slightly similar to Jetpack Joyride. At certain points it will have an object that the player has to fly between - like the pipes on flappy birds. I have managed to create the pipe objects however I wish for the objects to move up and down on the screen, making it harder for the player to jump between. My code for placing the objects is:
// Maths
float availableSpace = HEIGHT(self) - HEIGHT(floor);
float maxVariance = availableSpace - (2*OBSTACLE_MIN_HEIGHT) - VERTICAL_GAP_SIZE;
float variance = [Math randomFloatBetween:0 and:maxVariance];
// Bottom object placement
float minBottomPosY = HEIGHT(floor) + OBSTACLE_MIN_HEIGHT - HEIGHT(self);
float bottomPosY = minBottomPosY + variance;
bottomPipe.position = CGPointMake(xPos,bottomPosY);
bottomPipe.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(0,0, WIDTH(bottomPipe) , HEIGHT(bottomPipe))];
bottomPipe.physicsBody.categoryBitMask = blockBitMask;
bottomPipe.physicsBody.contactTestBitMask = playerBitMask;
// Top object placement
topPipe.position = CGPointMake(xPos,bottomPosY + HEIGHT(bottomPipe) + VERTICAL_GAP_SIZE);
topPipe.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(0,0, WIDTH(topPipe), HEIGHT(topPipe))];
topPipe.physicsBody.categoryBitMask = blockBitMask;
topPipe.physicsBody.contactTestBitMask = playerBitMask;
How would I go about moving the objects up and down?
Thanks for any help :)

All such operations on a node are done using SKAction objects. Read up on the SKAction class here.
In your case, using an SKAction to move the nodes up and down would go something like this:
SKAction *actionMoveUp = [SKAction moveByX:0 y:20 duration:0.5];
SKAction *actionMoveDown = [actionMoveUp reversedAction];
SKAction *actionMoveUpDown = [SKAction sequence:#[actionMoveUp, actionMoveDown]];
SKAction *actionMoveDownRepeat = [SKAction repeatActionForever:actionMoveUpDown];
[bottomPipe runAction:actionMoveDownRepeat];
[topPipe runAction:actionMoveDownRepeat];
The code given above will make your top and bottom pipe go up and down by a factor of 20 pixels repeatedly.

Related

SCNAction of scenekit only executing action once

I want objects that I created to "fall" down the view of the controller. I also want an infinite amount of objects to fall, so continuing the animation until the the user goes to another view controller. I used a for-loop to make up to 100 objects. Here is the code...
SCNMaterial *blackMaterial = [SCNMaterial material];
blackMaterial.diffuse.contents = [UIColor blackColor];
int xcoordinate = arc4random_uniform(20);
int xcoordinateTwo = arc4random_uniform(20);
for (int i = 0; i < 100; i++){
SCNText *x = [SCNText textWithString:#"X" extrusionDepth: 2.75];
SCNNode *xNode = [SCNNode nodeWithGeometry:x];
xNode.position = SCNVector3Make(xcoordinate, 15.0, -60.0);
xNode.scale = SCNVector3Make(2.0, 2.0, 0.45);
x.materials = #[blackMaterial];
x.chamferRadius = 5.0;
SCNAction *moveTo = [SCNAction moveTo:SCNVector3Make(xcoordinate, -100.0, -60.0)duration:10.0];
[xNode runAction:moveTo];
SCNTorus * torus = [SCNTorus torusWithRingRadius:6.30 pipeRadius:2.30];
SCNNode *torusNode = [SCNNode nodeWithGeometry:torus];
torusNode.position = SCNVector3Make(xcoordinateTwo, 15.0, -60.0);
torus.materials = #[blackMaterial];
torusNode.eulerAngles = SCNVector3Make(-1.5708, 0, 0);
[torusNode runAction:moveTo];
[scene.rootNode addChildNode:torusNode];
[scene.rootNode addChildNode:xNode];
}
The problem for me is that only one of each object is being created instead of a 100. Can I anyone help me with what the issue is.
You really are creating 100 of each object:
NSLog(#"%#", scene.rootNode.childNodes);
They all have the same origin and destination positions because your calls to arc4random_uniform are outside the loop. They're all in the same place so it looks like just one node.
Moving the random number calls inside will disperse your nodes but they'll all be created at the same simulation time. To generate them continuously, you can construct an [SCNAction sequence:[...]] with an array of actions: a block action to create a new node and add it to the tree, followed by a delay action. Wrap that in a repeatActionForever: and make your root node perform that action. You'll also want to remove nodes when they reach destination or go out of view.

Add Points to CGPath Loop

I am developing a game that requires a character SKNode *character to "randomly" move around an SKScene by following a randomly generated path. My question, is how can I effectively and efficiently edit or extend this path so that the character is always following a never ending path?
Here is an outline with some code snippets of how I am approaching this:
1. Create a CGMutablePathRef that will represent the path for the character to follow.
Here is the method that I am using to generate the path:
- (void)createPath {
// cgpath declared outside of this method to be retained
cgpath = CGPathCreateMutable();
// For simplicity, I am only dealing with positive random numbers for now
CGPoint s = CGPointMake(character.position.x, character.position.y);
CGPoint e = CGPointMake([self randomNumber] + character.position.x, [self randomNumber] + character.position.y);
CGPoint cp1 = CGPointMake([self randomNumber] + character.position.x, [self randomNumber] + character.position.y);
CGPoint cp2 = CGPointMake([self randomNumber] + character.position.x, [self randomNumber] + character.position.y);
CGPathMoveToPoint(cgpath, NULL, s.x, s.y);
CGPathAddCurveToPoint(cgpath, NULL, cp1.x, cp1.y, cp2.x, cp2.y, e.x, e.y);
SKAction *planeDestroy = [SKAction followPath:cgpath asOffset:NO orientToPath:NO duration:5];
[character runAction:planeDestroy];
CGPathRelease(cgpath);
}
- (int)randomNumber {
return (int)(arc4random_uniform(100) + randPointRad);
}
2. Run an SKAction in the scene to run this method and make the character follow the path.
Here is the code that I am using:
SKAction *wait = [SKAction waitForDuration:5];
SKAction *bla = [SKAction runBlock:^{
[self createPath];
}];
SKAction *randomMovement = [SKAction sequence:#[wait,bla]];
[self runAction:[SKAction repeatActionForever: randomMovement] withKey:#"randomMovementAction"];
3.* (This is step I am having trouble with) Edit / extend the current cgpath with newly generated random points to continuously move the character randomly around the scene.
I understand that the path that I am creating utilizes the logic shown in the below image
Providing Points of Control (POC), I am able to generate a path from defined starting and stopping points.
MY GOAL was to add new random control points to this path, in tern redefining the end point each addition (to some new random point some X distance from the previous point, giving some sense of continuity and coverage), then removing the previous control points (to conserve memory). I am trying to use the following method:
CGPathApply(<#CGPathRef _Nullable path#>, <#void * _Nullable info#>, <#CGPathApplierFunction _Nullable function#>)
to edit the path by adding new points, and extending the overall path, but I am having trouble since the path is being executed by an SKAction, so it's already been set.
Essentially, I am trying to repeat an action that adds a new POC to the already defined path, forcing the path to grow without demonstrating possible sharp turns, velocity changes, or direction changes.
Currently, the character does indeed float around the map randomly and continuously with the provided code I have shown, but at times the character has quite unnatural movements as cgpath(1) ends, and cgpath(2) begins, and so on to cgpath(n).
So does anyone know if there is some way to achieve what I am asking (extend and cgpath without having to stop, then start a completely new path)? OR at least prevent the character from performing any of these sharp unappealing movements. Thanks in advance for any help at all.
UPDATE: My only solution that I have been able to think of as of now is to track the angle between the last control point B1, and the current end point E1, then when creating the new path, make sure the angle between S2 and A2 are exact opposite (same direction of motion). Like such:

spritekit SKAction.resizeToHeight is not repeating

I want to increase the height of in touch events, it's same like stick hero is doing. I am trying following code
func changeHeight(){
let action = SKAction.resizeToHeight(self.leadherNode!.size.height+50, duration: 0.5);
let seq = SKAction.repeatActionForever(action)
self.leadherNode?.runAction(seq, withKey: "height")
}
but unfortunately it just increase the height of node for first time and it never repeats. How can I achieve this?
Changes to an argument of an SKAction after it has started will have no effect on the action. You will need to create a new action with the updated value at each step. Here's one way to do that:
Define and initialize the height and max height properties
var spriteHeight:CGFloat = 50.0;
let maxHeight:CGFloat = 500.0
Call this from didMoveToView
resizeToHeight()
This function creates an SKAction that resizes a sprite to a specific height. After the completion of the action, the function updates the height value and then calls itself.
func resizeToHeight() {
self.leadherNode?.runAction(
SKAction.resizeToHeight(self.spriteHeight, duration: 0.5),
completion:{
// Run only after the previous action has completed
self.spriteHeight += 50.0
if (self.spriteHeight <= self.maxHeight) {
self.resizeToHeight()
}
}
)
}
I dont know swift. But I can write objective-c version.
CGFloat currentSpriteSize;//Create private float
SKSpriteNode *sprite;//Create private sprite
currentSpriteSize = sprite.size.height;//Into your start method
//And your Action
SKAction *seq = [SKAction sequence:#[[SKAction runBlock:^{
currentSpriteSize += 50;
}], [SKAction resizeToHeight:currentSpriteSize duration:0.5]]];
[sprite runAction:[SKAction repeatActionForever:seq]];

Smooth motion of a SKSpriteNode on a random path

I am making a small SpriteKit game. I want the "enemies" in this game to move on random paths around the player (which is static).
If I just select a random point on the screen and animate a motion to there and then repeat (e.g.: every 2 seconds), this will give a very jagged feel to the motion.
How do I make this random motion to be very smooth (e.g.: if the enemy decides to turn around it will be on a smooth U turn path not a jagged sharp angle).
PS: The enemies must avoid both the player and each other.
You can create an SKAction with a CGPathRef that the node should follow.
Here is an example how to make a node make circles:
SKSpriteNode *myNode = ...
CGPathRef circlePath = CGPathCreateWithEllipseInRect(CGRectMake(0,
0,
400,
400), NULL);
SKAction *followTrack = [SKAction followPath:circle
asOffset:NO
orientToPath:YES
duration:1.0];
SKAction *forever = [SKAction repeatActionForever:followTrack];
[myNode runAction:forever];
You can also create a random UIBezierPath to define more sophisticated paths and make your objects follow them.
For example:
UIBezierPath *randomPath = [UIBezierPath bezierPath];
[randomPath moveToPoint:RandomPoint(bounds)];
[randomPath addCurveToPoint:RandomPoint(YourBounds)
controlPoint1:RandomPoint(YourBounds)
controlPoint2:RandomPoint(YourBounds)];
CGPoint RandomPoint(CGRect bounds)
{
return CGPointMake(CGRectGetMinX(bounds) + arc4random() % (int)CGRectGetWidth(bounds),
CGRectGetMinY(bounds) + arc4random() % (int)CGRectGetHeight(bounds));
}
You make a node follow the path using an SKAction and when the action completes (node is at the end of the path), you calculate a new path.
This should point you to the right direction.
If you want to generate random path, I highly suggest you to use "CGPathAddCurveToPoint", it is simple to understand and easy to use
Go to title 2. Add & Move Enemies
http://code.tutsplus.com/tutorials/build-an-airplane-game-with-sprite-kit-enemies-emitters--mobile-19916
It is coded by Jorge Costa and Orlando Pereira

How do you move an IOS SKSprite at a consistent speed

Playing around with SKSprites in the IOS SpriteKit, and I basically want to have a sprite randomly move a certain direction for a certain distance, then pick a new random direction and distance.. Simple enough, create a method that generates the random numbers then creates the animation and in the completion block of the animation have it callback the same routine.
THis does work, but it also keeps the animation from moving at the same velocity since the animations are all based on duration.. If the object has to move 100 it moves at 1/2 the speed it moves if the next random tells it to move 200... So how the heck do I have it move with a consistent speed?
#Noah Witherspoon is correct above - use Pythagorus to get a smooth speed:
//the node you want to move
SKNode *node = [self childNodeWithName:#"spaceShipNode"];
//get the distance between the destination position and the node's position
double distance = sqrt(pow((destination.x - node.position.x), 2.0) + pow((destination.y - node.position.y), 2.0));
//calculate your new duration based on the distance
float moveDuration = 0.001*distance;
//move the node
SKAction *move = [SKAction moveTo:CGPointMake(destination.x,destination.y) duration: moveDuration];
[node runAction: move];
Using Swift 2.x I've solved with this little method:
func getDuration(pointA:CGPoint,pointB:CGPoint,speed:CGFloat)->NSTimeInterval {
let xDist = (pointB.x - pointA.x)
let yDist = (pointB.y - pointA.y)
let distance = sqrt((xDist * xDist) + (yDist * yDist));
let duration : NSTimeInterval = NSTimeInterval(distance/speed)
return duration
}
With this method i can use an ivar myShipSpeed and directly call my actions for example :
let move = SKAction.moveTo(dest, duration: getDuration(self.myShip.position,pointB: dest,speed: myShipSpeed))
self.myShip.runAction(move,completion: {
// move action is ended
})
As an extension to #AndyOS's answer, if you're going to move only along one axis (X for example) you can simplify the math by doing this instead:
CGFloat distance = fabs(destination.x - node.position.x);

Resources