I have a UIimage which I want to move according to X and Y given by certain equations ( physics projectile time equations) and I want it to move every 1 second so that it would appear to the user as if it's actually moving not just disappearing and reappearing at the last position, plus the positions given off are wrong I think. I would appreciate any help for either or both problems.
So far I tried this:
The movement function:
func moveCannonBall(toX:Int , toY:Int ){
var frm: CGRect = ballimageview.frame
frm.origin.x = frm.origin.x + CGFloat(toX)
frm.origin.y = frm.origin.y - CGFloat(toY)
ballimageview.frame = frm
}
On button click it's supposed to take the user's inputs (gravity, angle, and the initial speed)
#IBAction func getAlpha( sender:AnyObject){
gravity = Float(g[pickerView.selectedRow(inComponent: 0)])
xMax = ((V0*V0)*sin(2.0*angle))/gravity
It's supposed to stop every 1 second but only the calculations pause every 1 second and the UIimage just disappears and reappears just
while Int(toX) < Int(xMax) {
sleep(1)
t = t + 1
toX = V0*cos(angle)*t
toY = -0.5*gravity*t*t + V0*sin(angle)*t
moveCannonBall(toX: Int(toX), toY: Int(toY))
}
}
Any help is appreciated.
As Losiowaty said UIView.animationWithDuration is the way to go. Check out this answer to see how the syntax is: https://stackoverflow.com/a/30992214/5257729
Related
Hey so I am looking for something similar to in tennis when players challenge a point and the video shows whether the ball was in or out by zooming in really really close to the moment when the ball lands to see whether a fraction was on the line.
I have experimented with using transitions with xScale and yScale but the results I get is strange, almost as if the objects have moved during zooming in. If there was a way to lock in position and then zoom, that would work. The second method I tried is putting the graphics into a display group and then scaling the group. This also results in weird behaviour where the whole group begins moving diagonally across the screen.
Please help as this is confusing me
cheers.
Objects which will scale:
cloud = display.newImageRect("cloud.png", 419,273)
cloud.anchorY = 0
cloud.anchorX = 0.5
cloud.alpha = 1
cloud.x = display.contentCenterX
cloud.y = display.contentCenterY + 250
physics.addBody(cloud, {isSensor=true})
star = display.newImageRect("Star.png", 78,72)
star.anchorY = 0
star.anchorX = 0.5
star.alpha = 1
star.name = "Star"
physics.addBody(star, {isSensor=true})
star.x = display.contentCenterX
star.y = display.actualContentHeight - display.actualContentHeight - 100
Scale Function
function scale( event )
transition.to(star, {time=2000, xScale=1.5, yScale = 1.5})
transition.to(cloud, {time=2000, xScale=1.5, yScale=1.5})
end
When you scale an object, it may "move" due to its anchor position, which is the position of the object that is used to position it and also works as its 'anchor' during rotation or scale.
So, you have 2 options:
1) Set the anchor position (obj.anchorX = value , obj.anchorY = value ) to the one that will make your object stays in the position that you want;
2) During the transition, also change its x and y to compensate the moving.
So I am developing an Ipad app that allows the user to solve a jigsaw puzzle. I've worked out getting the panning motion for each piece, but getting them where I want to has not worked properly. I am trying to make a piece snap into it's final destination when it's within a small range, which is followed by a clicking sound.
Here is a bit of code for a single puzzle piece. When my new game button is pressed, an Image View gets set to the corresponding picture, and randomly placed on the canvas.
#IBAction func NewGameTapped(sender: UIButton){
let bounds = UIScreen.mainScreen().bounds
let height = bounds.size.height
let width = bounds.size.width
image1.image = UIImage(named:"puzzleImage1.png")
image1.center.x = CGFloat(100 + arc4random_uniform(UInt32(width)-300))
image1.center.y = CGFloat(100 + arc4random_uniform(UInt32(height)-300))
//Create Panning (Dragging) Gesture Recognizer for Image View 1
let panRecognizer1 = UIPanGestureRecognizer(target: self, action: "handlePanning1:")
// Add Panning (Dragging) Gesture Recognizer to Image View 1
image1.addGestureRecognizer(panRecognizer1)
}
This is where I am having some issues.
func handlePanning1(recognizer: UIPanGestureRecognizer) {
let center = dict1_image_coordinates["puzzleImage1"] as![Int]
let newTranslation: CGPoint = recognizer.translationInView(image1)
recognizer.view?.transform = CGAffineTransformMakeTranslation(lastTranslation1.x + newTranslation.x, lastTranslation1.y + newTranslation.y)
if recognizer.state == UIGestureRecognizerState.Ended {
lastTranslation1.x += newTranslation.x
lastTranslation1.y += newTranslation.y
}
checkPosition(image1, center: center)
}
func checkPosition(image: UIImageView, center: [Int]){
let distance: Double = sqrt(pow((Double(image.center.x) - Double(center[0])),2) + pow((Double(image.center.y) - Double(center[1])),2))
//if the distance is within range, set image to new location.
if distance <= 20{
image.center.x = CGFloat(center[0])
image.center.y = CGFloat(center[1])
AudioServicesPlaySystemSound(clickSoundID)
}
For whatever reason, the puzzle piece only wants to snap to it's spot when the piece begins the game within the acceptable snap distance. I have tried checking for the object position in various different parts of my program, but nothing has worked so far. Any help or other tips are greatly appreciated.
The issue is likely caused by this line
image1.addGestureRecognizer(panRecognizer1)
Usually people add gestureRecognizer on the parentView, or the rootView of the view controller instead of the image1 itself. The benefit is that the parentView never moves, where as the image1 is constantly being transformed, which may or may not affect the recognizer.translationInView(x) method return value.
do this instead:
self.view.addGestureRecognizer(panRecognizer1)
and change to this line in handlePanning1 function:
image1.transform = CGAffineTransformMakeTranslation(lastTranslation1.x + newTranslation.x, lastTranslation1.y + newTranslation.y)
I am new to swift a Sprite kit. In the app I am trying to make I have a submarine moving through the ocean. Every time the user clicks the screen the gravity starts pulling the sub in the opposite direction. My problem is that i can't find a way to keep the sub from leaving the screen. I have tried to solve it by making a physicsBody around the screen, but the sub still leaves the screen. I have also tried the following code in the updateCurrentTime fund.
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
self.physicsWorld.gravity = CGVectorMake(0,gravity)
if (sub.position.y >= self.size.height - sub.size.height / 2){
sub.position.y = self.size.height - self.sub.size.height / 2
}
if (sub.position.y <= sub.size.height / 2) {
sub.position.y = self.sub.size.height / 2
}
}
But this doesn't do anything either.
Any help would be greatly appreciated!!!!! thanks in advance!
P.S. I can't believe that it is that hard to keep things on the screen!!!
frustrating!
Try SKConstraint - it doesn't require a physicsBody. The code would look something like this, and would constrain the sub sprite to the scene:
let width2 = sub.size.width/2
let height2 = sub.size.height/2
let xRange = SKRange(lowerLimit:0+width2,upperLimit:size.width-width2)
let yRange = SKRange(lowerLimit:0+height2,upperLimit:size.height-height2)
sub.constraints = [SKConstraint.positionX(xRange,Y:yRange)]
Try this in the update:
if sub.frame.maxY >= view!.frame.height {
sub.position.y = view!.frame.height - sub.size.height / 2
sub.physicsBody!.affectedByGravity = false
}
if sub.frame.minY <= 0 {
sub.position.y = sub.size.height / 2
sub.physicsBody!.affectedByGravity = false
}
And then inside of the event where you want to reverse gravity don't forget to do this:
sub.physicsBody!.affectedByGravity = true
Alternatively, instead of using gravity you could use this which is a better option in my opinion:
// This moves the object to the top of the screen
let action = SKAction.moveToY(view!.frame.height - character.size.height / 2, duration: 5.0) // Or however much time you want to the action to run.
action.timingMode = .EaseInEaseOut // Or something else
character.runAction(action)
// Change view!.frame.height - character.size.height / 2 to just character.size.height / 2 to move to the bottom.
I am making an app in which I want to have some thing happen If an image moves over another point. such as
first I have an image moving horizontally across the screen,'
self.ball.center = CGPointMake(self.ball.center.x + self.gravity.x / 8.0 * 200.0, 9);
then when it gets to a certain place another image moves down from that spot.
CGPoint a = CGPointMake(9, 9);
if (CGPointEqualToPoint(ball.center,a)) {
balla.hidden = NO;
self.balla.center = CGPointMake(self.balla.center.x , (self.balla.center.y)- (self.gravity.y / 8.0 * 200.0));
}
the first time it works ok but when I put in the next statement to move another image down from another spot nothing happens.
CGPoint b = CGPointMake(86, 9);
if (CGPointEqualToPoint(ball.center,b)) {
ball2a.hidden = NO;
self.ball2a.center = CGPointMake(self.ball2a.center.x , (self.ball2a.center.y)- (self.gravity.y / 8.0 * 200.0));}
Any ideas as to why this isn't working
If you're moving the ball by adding some floating-point value offset, you might be "skipping over" the point b - you may never hit b, but rather appear slightly before it and then slightly after it.
Rather than testing if you're "equal" to the point, you could be better off comparing the distance between the ball and the point and seeing if it is inside some small radius. A simple euclidean distance could work.
CGFloat euclid_dist(CGPoint a, CGPoint b)
{
return sqrt((b.x-a.x)*(b.x-a.x) + (b.y-a.y)*(b.y-a.y));
}
You could then use this to see if you've "hit" the point:
if (euclid_dist(ball.center, b) < 0.1)
{
// React appropriately
}
In general it's problematic to test for equality between floating point numbers.
I have an image that the user can drag to the right and it will spring back when the user releases it. I want to execute some code when a user drags it quickly and releases it. Now I have a very awkward requirement that the user can drag the image, then keep it still for any length of time (for example 5 seconds), then drag it quickly and release it. As long as the image is moving above a certain speed when it is released, it will execute the code. If it falls below the minimum speed, it executes some different code. So that means I can't calculate the length of time between the beginning of the gesture and the end and execute the code depending on the length of time. What can I do? I guess I somehow need to know the speed at which the image is moving in it's last 500 milliseconds before the gesture ends. However I've hit a brick wall figuring out how to do that. Any help would be greatly appreciated.
Can you please include an explanation and possible example code with your answer as that would be a great help.
If you get the start X,Y coordinates of when the image is dragged, and the X,Y coordinates for when the mouse is released, you can use pythagoras' theorm to calculate the distance between the two points: http://en.wikipedia.org/wiki/Pythagorean_theorem
Also, if you start a timer when the mouse is moved (and mouse button is down), and stop it in the mouseup event, you can calculate the speed using the time and distance (speed = distance / time)
edit following comments:
point delayedMousePos;
point previousMousePos;
bool secondDrag = false;
bool isStopped = false;
var timeFirstStopped;
var positionCount = 0;
array previousMousePositions[3];
// timer which monitors mouse position (set to an interval of say, 10ms)
function timerMonitorMousePos_Elapsed() {
point currentMousePos = getMousePos();
if (isStopped == false) {
if (positionCount >= 2) {
array_shift(previousMousePositions); // remove the first element of the array and move everything down to reindex numerical array to start counting from zero
positionCount = 2; // keep positionCount within array bounds
}
previousMousePositions[positionCount] = currentMousePos; // add the new position to the end of the 'stack'
positionCount++;
}
if (currentMousePos == previousMousePos) { // start check for stationary
isStopped = true;
if (timeFirstStopped == null) {
timeFirstStopped = NOW();
} else {
if (NOW() - timeFirstStopped >= 500) { // we have been stopped for at least 500ms (assumes time is counted in milliseconds)
secondDrag = true;
// previousMousePositions[0] = the mouse position 30ms before the mouse stopped
}
}
} else {
isStopped = false;
timeFirstStopped = null;
}
previousMousePos = currentMousePos;
}
I wouldn't use a timer. I would just save the starting date/time along with x,y position when the dragging starts.
When the dragging has ended, save the ending date/time and position. From those information, I can calculate the distance in pixel and duration in milliseconds.
After searching some more on the internet, I finally answered my own question.
I worked out what I needed to do:
My UIPanGestureRecognizer:
- (IBAction)handlePan3:(UIPanGestureRecognizer *)recognizer3
Get the velocity of the users finger moving across the screen:
CGPoint vel = [recognizer velocityInView:self.myView];
Then:
if (vel.x > /*value*/) {
// Your code
}
I was about to give up, but no! I got there in the end. Thanks for everyones help. I've upvoted one or two answers because they were helpful. bobnoble actually gave the suggestion to use velocityInView and I found this other stack overflow question which gave me the info I needed: iOS - Making sense of velocityInView on UIPanGesture