Swift: comparing 2 object's positions in if statement not working? - swift

Alright, so I'm trying to do something simple here and I think I've overcomplicated it- I need an if statement saying if this object goes off the screen (into negative y coordinates), have something happen. I can't get it.
I've tried a number of things, including if statements that compare to numbers like this, having it be equal and then trying greater/less than:
if block1.position.y == -50 {
savior.hidden = true
}
I've tried having the object be less than the size of the self.size.height :
if block1.position.y < self.size.height {
savior.hidden = true
}
And I've tried placing an object at the point off the screen and having an if statement comparing the 2 object's y positions:
if block1.position.y == ptBlock1.position.y {
savior.hidden = true
}
And nothing's working. Block1, the object I'm working with, is being sent to the specific point in an SKAction, so I know that it's getting there:
var moveDownLeft = SKAction.moveTo(CGPointMake(self.size.width * 0.35,-50), duration:5.5)
block1.runAction(moveDownLeft)
Why won't the if statement work?
EDIT:
I have tried this, and even when block1 visibly has a y position lower than ptBlock1, nothing happens:
if block1.position.y < ptBlock1.position.y {
savior.hidden = true
}
else if block1.position.y > ptBlock1.position.y {
savior.hidden = false
}

this object goes off the screen (into negative y coordinates)
You're making a false assumption there. Off the screen is not necessarily negative y coordinates.
The position of an SKNode is not measured with respect to screen; it is measured with respect to its superview, which is the SKScene. And the SKScene is much bigger than the screen! You need to convert from those coordinates to screen coordinates if you want to know what's happening relative to the screen.
(Just to give an example, if you make a new SpriteKit project from the template and log on touchesBegan to show the tap position, you will discover that a tap in the top left corner is at about {303,758}. So in that coordinate system an object is off the screen to the top if its y is greater than about 760. Contrast that with screen coordinates, where you are off the screen to the top if you are less than 0. These are very different coordinate systems!)

Related

How to adjust rotation of a SKSpriteNode

I've been working on a top view game, where there're two virtual joysticks present to control a character. For the joysticks, I've used Spritekit-Joystick. The character shoots automatically. The right Joystick is used for changing direction, and I have implemented this function to move the character:
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
if (self.imageJoystick.velocity.x != 0 || self.imageJoystick.velocity.y != 0)
{
myCharacter.zRotation = self.imageJoystick.angularVelocity;
}
}
For the self.imageJoystick.angularVelocity, the Joystick library uses this code (the code is available from the link above, but just for the sake of making things easier and more readily available):
angularVelocity = -atan2(thumbNode.position.x - self.anchorPointInPoints.x, thumbNode.position.y - self.anchorPointInPoints.y);
There' a problem with the rotation. When I push the joystick (thumbnode) up, the rotation points to the right. I've used NSLog to get the value, and it shows around 0. When I push the joystic (thumbnode above) to the left, the character points upwards, and I get around 1.5 reading for angularVelocity. Pushing it down points the character to left and gives a -3 reading. Finally, when I push right, I point the character to South, and geta reading of around 1.5.
The same thing happens with the 'bullets' I shoot out. For now I'm using beams, which I found the answer in this [POST] on here2. I have added it below for your convenience (Not my answer, but I've changed it to be used in my game):
[[self childNodeWithName:#"RayBeam"]removeFromParent];
int x = myCharacter.position.x + 1000 * cos(myCharacter.zRotation);
int y = myCharacter.position.y + 1000 * sin(myCharacter.zRotation);
SKShapeNode* beam1 = [SKShapeNode node];
CGMutablePathRef pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(pathToDraw, NULL, myCharacter.position.x, myCharacter.position.y);
CGPathAddLineToPoint(pathToDraw, NULL, x, y);
beam1.path = pathToDraw;
[beam1 setStrokeColor:[UIColor redColor]];
[beam1 setName:#"RayBeam"];
[self addChild:beam1];
The exact same thing happens. When I 1) push the joystick up, I shoot to right. 2) push the joystick to the left, I shoot Upward. 3) push downward, I shoot left, and 4) when I push the joystick to the right, I shoot downward.
I think I need to tweek the math and trigonometry equations, but maths isn't my forte, and I'm relatively new to this.
The image below is the image of the game (it's not completed at all), and you can see I'm pushing up but I'm pointing, and shooting to right.
Note: my sprite is also point to the right by default. I tried rotating all my sprites counter clockwise, and that works with the sprites, but not with the beam.
I really appreciate your help.
Thank you in advance.
If up is 0 radians then you should be calculating your beam's x and y with:
int x = myCharacter.position.x - 1000 * sin(myCharacter.zRotation);
int y = myCharacter.position.y + 1000 * cos(myCharacter.zRotation);

How can I get my sprite to move up and down the screen in FANG? Right now it's just moving back and forth across the screen

Right now it's just bouncing back and forth across the screen
def moveTriangleTwo {
triTwo.translateX(triTwoDX)
if (triTwo.getX < 0.0) {
// It hit the left wall - go other direction
triTwo.setX(0.0) // Place it on left wall
triTwoDX = -triTwoDX // Move in opposite direction
} else if (triTwo.getX > -1) {
// It hit the right wall - go other direction
triTwo.setX(-1.0) // Place it on right wall
triTwoDX = -triTwoDX // Move in opposite directinectin
}
}
Perhaps you should read about vectors and coordinate systems.
The short answer is, on a computer screen, coordinate Y is the vertical axis, starting with 0 on top. The X coordinate is horizontal, starting at 0 on the left and increasing to the right.
For horizontal movement you need to change X, for vertical you change Y, for any diagonal you change both at once.

Check when an SKSpriteNode passes a certain point or line

In my game, there is an SKSpriteNode, which we will call a "gate," that is moving upwards in the scene. When the gate reaches the top of the screen, it moves back down to the bottom and begins traveling upwards again.
The way the player loses is if the character, which is located at a constant y position towards the top of the scene, collides with the gate. I have the collision and 'death' all worked out, but now I need to check if the character successfully passed 'through' the gate (meaning the gate moved past the character without hitting him). Basically, I need to know how to check when one moving node crosses a certain y position (in this case, that position is the character's y position). If this occurs, I want to increase the score by one.
Here is a rough sketch of the situation:
(click here for the rough sketch)
One thing I have tried is in the update method, if the gate's y position ever equals the character's y position, I know the two nodes have crossed, so I should increase the score. It looks like this:
override func update(currentTime: CFTimeInterval) {
if gate.position.y == character.position.y {
print("score")
score++
}
}
but doesn't seem to work. Is there any other way to check when the gate crosses the character's y position?
Thanks!
What may be happening is that the y coordinates aren't the same. For example if gate.position.y = 100, and character. position.y = 101, it won't work. Try this:
override func update(currentTime: CFTimeInterval) {
let minY = gate.position.y - 10
let maxY = gate.position.y + 10
if character.position.y > minY && character.position.y < maxY {
print("score")
score++
}
}
You can adjust the number 10 to see what works best. Hope this helps

object stop falling when reach a specific point in unity3d

I am making a game in which the balls are falling down on a plane one ball fall over the other ball and they make a line, which goes from bottom to top. I want that at certain point on y axis the ball stop falling. Don't know how to do it the code I used until now for balls to fall down is:
function calling(){
functionsRandom.Range(0, functions.Length);
}
function sphereA() {
var go = Instantiate(sphere,new Vector3(Random.Range(-3, 3),Random.Range(-3,3),-12.78451),Quaternion.identity);
go.renderer.material.color = Color(Random.value, Random.value, Random.value);
}
function sphereB() {
var go = Instantiate(sphere1,new Vector3(Random.Range(-3, 3),Random.Range(-3,3),-12.78451),Quaternion.identity);
go.renderer.material.color = Color(Random.value, Random.value, Random.value);
}
I used random.range, so that the ball falls from points between it both in x and y, for x it is working, but it is not working for y.
Add all the instantiated spheres to an array go[] instead of go. which are in line. Now at certain point where you want to stop generating other spheres, take the count of the sphere in the array. If the count is equal to the max limit. Then DON'T instantiate the spheres. If any doubts, come to unity3d chatroom.

Two-finger rotation gesture on the iPhone?

I'm working on an iPhone app with a lot of different gesture inputs that you can do. Currently there is single finger select / drag, two finger scroll, and two finger pinch zoom-in / zoom-out. I want to add in two finger rotation (your fingers rotate a point in between them), but I can't figure out how to get it to work right. All the other gestures were linear so they were only a matter of using the dot or cross product, pretty much.
I'm thinking I've got to store the slope between the previous two points of each finger, and if the angle between the vectors is near 90, then there is the possibility of a rotation. If the next finger movement angle is also near 90, and the direction of the vector on one finger changed positively and changed negatively, then you've got a rotation. The problem is, I need a really clean distinction between this gesture and the other ones - and the above isn't far enough removed.
Any suggestions?
EDIT: Here's how I did it in a vector analysis manner (as opposed to the suggestion below about matching pixels, note that I use my Vector struct in here, you should be able to guess what each function does):
//First, find the vector formed by the first touch's previous and current positions.
struct Vector2f firstChange = getSubtractedVector([theseTouches get:0], [lastTouches get:0]);
//We're going to store whether or not we should scroll.
BOOL scroll = NO;
//If there was only one touch, then we'll scroll no matter what.
if ([theseTouches count] <= 1)
{
scroll = YES;
}
//Otherwise, we might scroll, scale, or rotate.
else
{
//In the case of multiple touches, we need to test the slope between the two touches.
//If they're going in roughly the same direction, we should scroll. If not, zoom.
struct Vector2f secondChange = getSubtractedVector([theseTouches get:1], [lastTouches get:1]);
//Get the dot product of the two change vectors.
float dotChanges = getDotProduct(&firstChange, &secondChange);
//Get the 2D cross product of the two normalized change vectors.
struct Vector2f normalFirst = getNormalizedVector(&firstChange);
struct Vector2f normalSecond = getNormalizedVector(&secondChange);
float crossChanges = getCrossProduct(&normalFirst, &normalSecond);
//If the two vectors have a cross product that is less than cosf(30), then we know the angle between them is 30 degrees or less.
if (fabsf(crossChanges) <= SCROLL_MAX_CROSS && dotChanges > 0)
{
scroll = YES;
}
//Otherwise, they're in different directions so we should zoom or rotate.
else
{
//Store the vectors represented by the two sets of touches.
struct Vector2f previousDifference = getSubtractedVector([lastTouches get:1], [lastTouches get:0]);
struct Vector2f currentDifference = getSubtractedVector([theseTouches get:1], [theseTouches get:0]);
//Also find the normals of the two vectors.
struct Vector2f previousNormal = getNormalizedVector(&previousDifference);
struct Vector2f currentNormal = getNormalizedVector(&currentDifference );
//Find the distance between the two previous points and the two current points.
float previousDistance = getMagnitudeOfVector(&previousDifference);
float currentDistance = getMagnitudeOfVector(&currentDifference );
//Find the angles between the two previous points and the two current points.
float angleBetween = atan2(previousNormal.y,previousNormal.x) - atan2(currentNormal.y,currentNormal.x);
//If we had a short change in distance and the angle between touches is a big one, rotate.
if ( fabsf(previousDistance - currentDistance) <= ROTATE_MIN_DISTANCE && fabsf(angleBetween) >= ROTATE_MAX_ANGLE)
{
if (angleBetween > 0)
{
printf("Rotate right.\n");
}
else
{
printf("Rotate left.\n");
}
}
else
{
//Get the dot product of the differences of the two points and the two vectors.
struct Vector2f differenceChange = getSubtracted(&secondChange, &firstChange);
float dotDifference = getDot(&previousDifference, &differenceChange);
if (dotDifference > 0)
{
printf("Zoom in.\n");
}
else
{
printf("Zoom out.\n");
}
}
}
}
if (scroll)
{
prinf("Scroll.\n");
}
You should note that if you're just doing image manipulation or direct rotation / zooming, then the above approach should be fine. However, if you're like me and you're using a gesture to cause something that takes time to load, then it's likely that you'll want to avoid doing the action until that gesture has been activated a few times in a row. The difference between each with my code is still not perfectly separate, so occasionally in a bunch of zooms you'll get a rotation, or vise versa.
I've done that before by finding the previous and current distances between the two fingers, and the angle between the previous and current lines.
Then I picked some empirical thresholds for that distance delta and angle theta, and that has worked out pretty well for me.
If the distance was greater than my threshold, and the angle was less than my threshold, I scaled the image. Otherwise I rotated it.
2 finger scroll seems easy to distinguish.
BTW in case you are actually storing the values, the touches have previous point values already stored.
CGPoint previousPoint1 = [self scalePoint:[touch1 previousLocationInView:nil]];
CGPoint previousPoint2 = [self scalePoint:[touch2 previousLocationInView:nil]];
CGPoint currentPoint1 = [self scalePoint:[touch1 locationInView:nil]];
CGPoint currentPoint2 = [self scalePoint:[touch2 locationInView:nil]];
Two fingers, both moving, opposit(ish) directions. What gesture conflicts with this?
Pinch/zoom I guess comes close, but whereas pinch/zoom will start off moving away from a center point (if you trace backwards from each line, your lines will be parallel and close), rotate will initially have parallel lines (tracing backwards) that will be far away from each other and those lines will constantly change slope (while retaining distance).
edit: You know--both of these could be solved with the same algorithm.
Rather than calculating lines, calculate the pixel under each finger. If the fingers move, translate the image so that the two initial pixels are still under the two fingers.
This solves all two-finger actions including scroll.
Two-finger scroll or Zoom might look a little wobbly at times since it will do other operations as well, but this is how the map app seems to work (excluding the rotate which it doesn't have).