swift UI "other"

Thread Starter

arduinolego611

Joined Jan 23, 2022
75
im writing a bouncing ball simulation in swift UI. I can't understand how to declare "other" so that this code I am showing below will detect and react to collisions with other balls.

If "self" is used to reference the current instance of a class, how do I manipulate the relationship with other instances?

I know "self" is part of swift, but how about "other"? how does one reference other balls in the simulation? how do I reference any / all other instances of my "Ball" class?

The error message says "cannot find "other" in scope"
vx and vy are velocities, dx and dy are distances
I am new to swift...

Code:
let dx: int = other.x - x
let dy: int = other.y - y
let distance: int = sqrt (dx * dx + dy * dy)
if distance < self.radius + other.radius
{
  self.vx = -self.vx
  self.vy = -self.vy
  other.vx = -other.vx
  other.vy = -other.vy
}
 
Last edited:

Ya’akov

Joined Jan 27, 2019
10,235
I do not write Swift but this is basic OOP.

"self" refers to the current instance of an object. It is meaningless unless there is an object (called something other than "self" with properties named whatever is is you want to get or set. (e.g. an object called myBall with a property called radius which would let you access myBall.radius or self.radius in the context of the object)

Apparently, in Swift you can define a class or struct to create and object.

Declaring a Class:
class Ball {
    var color: String
    var radius: Int

    init(color: String, radius: Int) {
        self.color = color
        self.radius = radius
}
Once you have a class (or struct) to work with you can instantiate an object.

Instantiation of an Object:
let myBall = Ball(color: "Red", radius: 10)
Now, myBall.radius will return 10. Obviously you need to make the class so it has all the properties you want to work with.
 

Thread Starter

arduinolego611

Joined Jan 23, 2022
75
I do not write Swift but this is basic OOP.

"self" refers to the current instance of an object. It is meaningless unless there is an object (called something other than "self" with properties named whatever is is you want to get or set. (e.g. an object called myBall with a property called radius which would let you access myBall.radius or self.radius in the context of the object)

Apparently, in Swift you can define a class or struct to create and object.

Declaring a Class:
class Ball {
    var color: String
    var radius: Int

    init(color: String, radius: Int) {
        self.color = color
        self.radius = radius
}
Once you have a class (or struct) to work with you can instantiate an object.

Instantiation of an Object:
let myBall = Ball(color: "Red", radius: 10)
Now, myBall.radius will return 10. Obviously you need to make the class so it has all the properties you want to work with.
I do know the basics of that, but my question is how do I reference all the other balls that are not the current ("self") instances of that class, and how do I manipulate behaviors that involve both the "self" instance and the other instances

My program is a bouncing ball simulation, and I am trying to manipulate other balls and the current ball at the same time so I can change their velocities / direction when they collide with each other
 

Ya’akov

Joined Jan 27, 2019
10,235
Instantiation. You shouldn't be using a method inside the ball object for collision detection.

You need instances of Ball: let myBall = Ball(color: "Red", radius: 10, xPos: 25, yPos: 32, ...) and let otherBall = Ball(color: "Red", radius: 10, xPos: 30, yPos: 52 ...) then you can use the objects in other code.

You could create an object that is the "field" with methods, or something similar. But you need the Ball objects to work with.
 

Thread Starter

arduinolego611

Joined Jan 23, 2022
75
Instantiation. You shouldn't be using a method inside the ball object for collision detection.

You need instances of Ball: let myBall = Ball(color: "Red", radius: 10, xPos: 25, yPos: 32, ...) and let otherBall = Ball(color: "Red", radius: 10, xPos: 30, yPos: 52 ...) then you can use the objects in other code.

You could create an object that is the "field" with methods, or something similar. But you need the Ball objects to work with.
Yeah that's only a snippet of the full code
 

Ya’akov

Joined Jan 27, 2019
10,235
Yeah that's only a snippet of the full code
There is no way to.understand what you are doing with a tiny piece of the code. If my answer doesn't address your problem than I don't understand your problem at all. I don't think that's the case, but without the actual code I have no way to know.
 

Art Vandelay

Joined Nov 1, 2024
140
Try this code. It defines two classes and instantiates 4 objects: a pool table and 3 balls. Notice how each coordinate of each ball can be found by calling the coordinates property inside PoolBall class with something like"ball2.coordinates.x" to get the x coordinate of ball 2. To get both coordinates for ball 2, call "ball2.coordinates".

I tried to make this example as clear as possible but feel free to ask questions about anything you don't understand.

Swift:
// Define a PoolTable class
class PoolTable {
    var cornerCoordinates: [String: (x: Int, y: Int)]

    init(corner1Coordinates: (x: Int, y: Int), corner2Coordinates: (x: Int, y: Int), corner3Coordinates: (x: Int, y: Int), corner4Coordinates: (x: Int, y: Int)) {
        cornerCoordinates = [
            "Corner 1 Coordinates": corner1Coordinates,
            "Corner 2 Coordinates": corner2Coordinates,
            "Corner 3 Coordinates": corner3Coordinates,
            "Corner 4 Coordinates": corner4Coordinates
        ]
    }

    func displayTable() {
        print("Pool Table Corners:")
        for (corner, coordinates) in cornerCoordinates {
            print("\(corner): \(coordinates)")
        }
    }
}

// Define a PoolBall class
class PoolBall {
    var number: Int
    var coordinates: (x: Int, y: Int)

    init(number: Int, coordinates: (x: Int, y: Int)) {
        self.number = number
        self.coordinates = coordinates
    }

    func displayBall() {
        print("Ball Number: \(number), Coordinates: \(coordinates)")
    }
}

// Create a pool table instance
let corner1Coordinates = (x: 0, y: 0)  // Bottom-left
let corner2Coordinates = (x: 0, y: 4)  // Top-left
let corner3Coordinates = (x: 8, y: 0)  // Bottom-right
let corner4Coordinates = (x: 8, y: 4)  // Top-right

let poolTable = PoolTable(corner1Coordinates: corner1Coordinates, corner2Coordinates: corner2Coordinates, corner3Coordinates: corner3Coordinates, corner4Coordinates: corner4Coordinates)

// Create three pool balls
let ball1 = PoolBall(number: 5, coordinates: (x: 1, y: 1))
let ball2 = PoolBall(number: 3, coordinates: (x: 4, y: 2))
let ball3 = PoolBall(number: 7, coordinates: (x: 5, y: 3))

// Display the pool table corners
poolTable.displayTable()

// Display the pool balls
ball1.displayBall()
ball2.displayBall()
ball3.displayBall()

print("3 Ball x Cordinate:", ball2.coordinates.x)
print("7 Ball y Cordinate:", ball3.coordinates.y)
print("5 Ball x and y Cordinates:", ball1.coordinates)
Output:

Pool Table Corners:
Corner 3 Coordinates: (x: 8, y: 0)
Corner 1 Coordinates: (x: 0, y: 0)
Corner 2 Coordinates: (x: 0, y: 4)
Corner 4 Coordinates: (x: 8, y: 4)
Ball Number: 5, Coordinates: (x: 1, y: 1)
Ball Number: 3, Coordinates: (x: 4, y: 2)
Ball Number: 7, Coordinates: (x: 5, y: 3)
3 Ball x Cordinate: 4
7 Ball y Cordinate: 3
5 Ball x and y Cordinates: (x: 1, y: 1)

=== Code Execution Successful ===
 
Last edited:

Thread Starter

arduinolego611

Joined Jan 23, 2022
75
There is no way to.understand what you are doing with a tiny piece of the code. If my answer doesn't address your problem than I don't understand your problem at all. I don't think that's the case, but without the actual code I have no way to know.
I don't want to (but will if forced to) post the code because i'm new with swift and there's probably a million errors. Right now, im just concerned with this program and (although its not the best strategy in the world) I am going to learn the language in depth at a later time and just focus on this program for today.

So anyway, the gist of it is as follows:

1. create a class of balls with properties (ball position, velocity, gravity, restitution / bounce factor)
2. set a time step / rate at which positions and velocities update
3. set up graphics properties for "circles" (balls) in swift

4. apply gravity to velocities of set of balls
5. update position based on gravity

5. create a function for when a ball bounces off the floor
6. create functions for when a ball bounces off left and right walls
7. create a function for when a ball bounces off another ball *this is the one im having trouble with

If you really need to see the code I will (reluctantly) post it :)
 

Ya’akov

Joined Jan 27, 2019
10,235
I am not sure how you expect anyone to debug code they aren't allowed to see.

I am not a Swift expert—or even a user—so I don't think is worth our mutual time for me to untangle your code. They only advice I have (since I don't know what you are doing that "isn't working") is to pay attention to the instantiation aspect.

When you create an instance of an object you tell the class to use the init{} portion of your code to create an object with the properties of the defined class and assign it to a variable. To access the properties (and methods) of that instance, you use the name you assigned to the object.

If you've done the instantiation and you are getting a scope error, it means that the object is not defined within the scope where you are operating. Scope is where in your program the variable will be defined.

In Swift, a global variable must be declared outside any class, struct, function, or block. Any of these things can limit scope, so a declaration inside a class but outside a method in the class will limit the scope to the code inside the class. The same is true for a structure, function, or block.

Global variables are "easy" because they won't have scope problems but scope is a powerful and important tool. So declaring your variables are the top of your program will "work" insofar as they will be accessible everywhere, but in real code, written correctly, scope is selected for various reasons including data integrity and efficiency.

Scope is a deliberate feature of modern languages, it's there for a reason. So if you use globals to avoid careful assignment of scope, you are making a mess and your code will not be scalable and could potentially have weird bugs you will find hard to track down. You should use globals only where they are really called for, but that requires learning the language and how to properly use it.

Last advice: you said your approach is a bad idea—and it is, but kludging together a program to see it run is fine, as long as you actually follow through with learning and don't start cargo culting your own code even as you make bigger and more complicated programs—that outcome is what makes it a bad idea.

Frustrating though it may be, actually trying to do it as correctly as possible from the start is going to pay dividends. But purity is not a particular merit, and so some shortcuts to get the dopamine spike of a running program can be good—so long as you really do go back to the more rigorous learning.

Good luck!
 

wayneh

Joined Sep 9, 2010
18,104
I would avoid using "self". This has a particular definition in Swift and to use it properly you'd have to clearly understand this definition and how to manipulate it. That's certainly doable but not always clear and simple.

If you have a set of balls you want to update, build a loop that cycles through them explicitly. A collision situation can be detected during that loop and handled either inside the loop or as a separate function with the appropriate variables passed in and back out. I'd probably prefer the latter for clarity.

Are you working in a "playground" or in an app?

You might also look into what's already available for built-in behaviors of sprites. I don't do much with animation but bouncing balls sounds pretty basic to me.
One of many links: https://stackoverflow.com/questions...he-movement-of-a-bouncing-ball-with-spritekit
 

Thread Starter

arduinolego611

Joined Jan 23, 2022
75
I am not sure how you expect anyone to debug code they aren't allowed to see.

I am not a Swift expert—or even a user—so I don't think is worth our mutual time for me to untangle your code. They only advice I have (since I don't know what you are doing that "isn't working") is to pay attention to the instantiation aspect.

When you create an instance of an object you tell the class to use the init{} portion of your code to create an object with the properties of the defined class and assign it to a variable. To access the properties (and methods) of that instance, you use the name you assigned to the object.

If you've done the instantiation and you are getting a scope error, it means that the object is not defined within the scope where you are operating. Scope is where in your program the variable will be defined.

In Swift, a global variable must be declared outside any class, struct, function, or block. Any of these things can limit scope, so a declaration inside a class but outside a method in the class will limit the scope to the code inside the class. The same is true for a structure, function, or block.

Global variables are "easy" because they won't have scope problems but scope is a powerful and important tool. So declaring your variables are the top of your program will "work" insofar as they will be accessible everywhere, but in real code, written correctly, scope is selected for various reasons including data integrity and efficiency.

Scope is a deliberate feature of modern languages, it's there for a reason. So if you use globals to avoid careful assignment of scope, you are making a mess and your code will not be scalable and could potentially have weird bugs you will find hard to track down. You should use globals only where they are really called for, but that requires learning the language and how to properly use it.

Last advice: you said your approach is a bad idea—and it is, but kludging together a program to see it run is fine, as long as you actually follow through with learning and don't start cargo culting your own code even as you make bigger and more complicated programs—that outcome is what makes it a bad idea.

Frustrating though it may be, actually trying to do it as correctly as possible from the start is going to pay dividends. But purity is not a particular merit, and so some shortcuts to get the dopamine spike of a running program can be good—so long as you really do go back to the more rigorous learning.

Good luck!
Thanks for responding.
I changed my strategy.
I don't need the question about "self" and "other" answered anymore...for now.
Here's the new pseudocode mock up, in case you want to see:
:)

Code:
import SwiftUI

Class Ball
{
    var color: String
    var xPosition: Int
    var yPosition: Int
    var xVelocity: Int
    var yVelocity: Int
    var radius: Int
    var gravity: CGFloat = 0.3
    var restitution: Int = 3
  
    let ballOne = ball1(color: black, xPosition: 100, yPosition: 100, xVelocity: 3, yVelocity: 0, radius 3)
    let ballTwo = ball2(color: black, xPosition: 200, yPosition: 50, xVelocity: -2, yVelocity: 2, radius 3)
    let ballThree = ball3(color: black, xPosition: 300, yPosition: 150, xVelocity: 4, yVelocity: -3, radius 3)
  
//I know this isn't the right syntax to create a class or object, its just a mock up for when I learn how to do that properly in Swift
//I also skipped the part where I would create graphics out of the "balls"  and background, etc.

    let timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect()

    .onReceive(timer)
    {
       for i in balls
            ball.yVelocity += gravity
            ball.xPosition = CGPoint(ball.xPosition + ball.xVelocity)
            ball.yPosition = CGPoint (ball.yPosition + ball.yVelocity)
                      
        //bounce off floor
                        if ball.yPosition >= 500 - 25
                        {
                            ball.yPosition = 500 - 25
                            ball.yVelocity = -ball.yVelocity * restitution
                        }
           //bounce off right wall      

                        if ball.xPosition <= 25
                        {
                            ball.xPosition = 25
                            ball.xVelocity = -ball.xVelocity
                        }
           //bounce off left wall            
                        if ball.xPosition >= 375
                        {
                            ball.xPosition = 375
                            ball.xVelocity = -ball.velocityX
                        }
                      
            //bounce off other balls
                        for balls in balls
                        {
                                let dx: int = balls[i].x - xPosition
                                let dy: int = balls[i].y - yPosition
                                let distance: int = sqrt (dx * dx + dy * dy)
                                if distance < balls[i].radius + radius
                                {
                                    yVelocity = -xVelocity * restitution
                                    yVelocity = -yVelocity * restitution
                                    balls[i].xVelocity = -balls[i].xVelocity * restitution
                                    balls[i].yVelocity = -balls[I].yVelocity * restitution
                                }
                        }
                }
 

Thread Starter

arduinolego611

Joined Jan 23, 2022
75
I would avoid using "self". This has a particular definition in Swift and to use it properly you'd have to clearly understand this definition and how to manipulate it. That's certainly doable but not always clear and simple.

If you have a set of balls you want to update, build a loop that cycles through them explicitly. A collision situation can be detected during that loop and handled either inside the loop or as a separate function with the appropriate variables passed in and back out. I'd probably prefer the latter for clarity.

Are you working in a "playground" or in an app?

You might also look into what's already available for built-in behaviors of sprites. I don't do much with animation but bouncing balls sounds pretty basic to me.
One of many links: https://stackoverflow.com/questions...he-movement-of-a-bouncing-ball-with-spritekit
Thanks for responding. I am going to use this strategy moving forward with my program.
 
Thread starter Similar threads Forum Replies Date
arduinolego611 Programming & Languages 6
strantor Off-Topic 16
Top