UIKit Collision Detection and actions - swift

I am developing an iOS app with swift and i ran into a problem. Using solely UIKit, I have a square that falls onto a platform, bounces back to its original position, and keeps going. I want the platform to change color every time the square hits it but i don't know how to detect that the square has come into contact with the platform. Please help. Here is the the code
import UIKit
import SpriteKit
class PlayScreen : UIViewController {
#IBOutlet var ScreenBack: UIImageView!
#IBOutlet var Platform: UIImageView!
var squareView: UIImageView!
var gravity: UIGravityBehavior!
var animator: UIDynamicAnimator!
var collision: UICollisionBehavior!
var itemBehaviour: UIDynamicItemBehavior!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
// Creating a bouncing Ball with the barrier of the platform
squareView = UIImageView(frame: CGRect(x: ScreenBack.frame.width/2, y: ScreenBack.frame.height/4, width: 40, height: 40))
squareView.frame.origin.x-=squareView.frame.width/2
squareView.image = redBall
view.addSubview(squareView)
animator = UIDynamicAnimator(referenceView: view)
gravity = UIGravityBehavior(items: [squareView])
animator.addBehavior(gravity)
collision = UICollisionBehavior(items: [squareView])
collision.translatesReferenceBoundsIntoBoundary = true
collision.addBoundaryWithIdentifier("barrier", fromPoint: CGPointMake(self.Platform.frame.origin.x, self.Platform.frame.origin.y), toPoint: CGPointMake(self.Platform.frame.origin.x + self.Platform.frame.width, Platform.frame.origin.y))
animator.addBehavior(collision)
itemBehaviour = UIDynamicItemBehavior(items: [squareView])
itemBehaviour.elasticity = 1.0
itemBehaviour.resistance = 0.0
animator.addBehavior(itemBehaviour)
}
}

to detect collision use UICollisionBehaviorDelegate
class ViewController: UIViewController, UICollisionBehaviorDelegate {
Set your collision behavior object delegate to self
collision.collisionDelegate=self
Add add the following function
func collisionBehavior(behavior: UICollisionBehavior, beganContactForItem item: UIDynamicItem, withBoundaryIdentifier identifier: NSCopying, atPoint p: CGPoint) {
println("Contact - \(identifier)")
}

Related

RealityKit – Which Entity is intersecting with other Entity

let height: Float = 1
let width: Float = 0.5
let box = MeshResource.generateBox(width: 0.02, height: height, depth: width)
This box will have a real-time position same as the current camera position, In AR World I would have multiple boxes with different shapes, I want to identify which object is intersecting with the current real-time box.
I can not do this with position matching (The nearest one). I literally want to know the object which is touching/intersecting the real-time box.
Thanks in advance.
You can easily do that using subscribe() method. The following code is a reference:
(physics for both objects was enabled in Reality Composer)
import UIKit
import RealityKit
import Combine
class ViewController: UIViewController {
#IBOutlet var arView: ARView!
var subscriptions: [Cancellable] = []
override func viewDidLoad() {
super.viewDidLoad()
let boxScene = try! Experience.loadBox()
arView.scene.anchors.append(boxScene)
let floorEntity = boxScene.children[0].children[1]
let subscribe = arView.scene.subscribe(to: CollisionEvents.Began.self,
on: floorEntity) { (event) in
print("Collision Occured")
print(event.entityA.name)
print(event.entityB.name)
}
self.subscriptions += [subscribe]
}
}

Swift UIImage cant be animated with gravity

I've looked into everything on Google, and that is not much. Is the community for Swift really this small???
I have an image, and on a long-press, I want it to fall down with gravity and hit the bottom of the screen.
The error I get is
Cannot convert value of type 'UIView' to expected argument type
'[UIDynamicItem]'
I have tried UILabel, UIImage, UIImageView, Rect, UIView i get this error on what ever i do.
My goal is to use UIImage or UIImageView.
This is the code I'm using for the animation:
var animator: UIDynamicAnimator!
var gravity: UIDynamicBehavior!
var collision : UICollisionBehavior!
var redBoxView: UIView?
#IBOutlet weak var detailsImageWeather: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
animator = UIDynamicAnimator(referenceView: self.view)
let imageTap = UILongPressGestureRecognizer(target: self, action: #selector(imageTapped))
detailsImageWeather.addGestureRecognizer(imageTap)
}
#objc func imageTapped() {
var frameRect = CGRect(x: 150, y: 20, width: 60, height: 60)
redBoxView = UIView(frame: frameRect)
redBoxView?.backgroundColor = UIColor.red
self.view.addSubview(redBoxView!)
let image = detailsImageWeather.image // This is what i want to use instead of redBoxView
gravity = UIGravityBehavior(items: redBoxView!)
animator.addBehavior(gravity)
collision = UICollisionBehavior (items: redBoxView!)
collision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(collision)
let behavior = UIDynamicItemBehavior(items: [redBoxView!])
behavior.elasticity = 2
}
What am i doing wrong? cant find any more things to try on google
The error
Cannot convert value of type 'UIView' to expected argument type '[UIDynamicItem]'
tells that you need an array of UIDynamicItem. It's easy to miss the little square brackets.
You're actually configuring your UIGravityBehavior and UICollisionBehavior with redBoxView (an object) instead of [redBoxView] (an array). That's why you get the error.
You need to change your configurations to this
gravity = UIGravityBehavior(items: [redBoxView!]) //redBoxView passed in an array
and this
collision = UICollisionBehavior (items: [redBoxView!]) //redBoxView passed in an array

How can I reduce the opacity of the shadows in RealityKit?

I composed a scene in Reality Composer and added 3 objects in it. The problem is that the shadows are too intense (dark).
I tried using the Directional Light in RealityKit from this answer rather than a default light from Reality Composer (since you don't have an option to adjust light in it).
Update
I implemented the spotlight Lighting as explained by #AndyFedo in the answer. The shadow is still so dark.
In case you need soft and semi-transparent shadows in your scene, use SpotLight lighting fixture which is available when you use a SpotLight class or implement HasSpotLight protocol. By default SpotLight is north-oriented. At the moment there's no opacity instance property for shadows in RealityKit.
outerAngleInDegrees instance property must be not more than 179 degrees.
import RealityKit
class Lighting: Entity, HasSpotLight {
required init() {
super.init()
self.light = SpotLightComponent(color: .yellow,
intensity: 50000,
innerAngleInDegrees: 90,
outerAngleInDegrees: 179, // greater angle – softer shadows
attenuationRadius: 10) // can't be Zero
}
}
Then create shadow instance:
class ViewController: NSViewController {
#IBOutlet var arView: ARView!
override func awakeFromNib() {
arView.environment.background = .color(.black)
let spotLight = Lighting().light
let shadow = Lighting().shadow
let boxAndCurlAnchor = try! Experience.loadBoxAndCurl()
boxAndCurlAnchor.components.set(shadow!)
boxAndCurlAnchor.components.set(spotLight)
arView.scene.anchors.append(boxAndCurlAnchor)
}
}
Here's an image produced without this line: boxAnchor.components.set(shadow!).
Here's an image produced with the following value outerAngleInDegrees = 140:
Here's an image produced with the following value outerAngleInDegrees = 179:
In a room keep SpotLight fixture at a height of 2...4 meters from a model.
For bigger objects you must use higher values for intensity and attenuationRadius:
self.light = SpotLightComponent(color: .white,
intensity: 625000,
innerAngleInDegrees: 10,
outerAngleInDegrees: 120,
attenuationRadius: 10000)
Also you can read my STORY about RealityKit lights on Medium.
The shadows appear darker when I use "Hide" action sequence on "Scene Start" and post a notification to call "Show" action sequence on tap gesture.
The shadows were fixed when I scaled the Object to 0% and post Notification to call "Move,Rotate,Scale to" action sequence on tap gesture.
Scaled Image
Unhide Image
Object Difference with hidden and scaled actions
import UIKit
import RealityKit
import ARKit
class Lighting: Entity, HasDirectionalLight {
required init() {
super.init()
self.light = DirectionalLightComponent(color: .red, intensity: 1000, isRealWorldProxy: true)
}
}
class SpotLight: Entity, HasSpotLight {
required init() {
super.init()
self.light = SpotLightComponent(color: .yellow,
intensity: 50000,
innerAngleInDegrees: 90,
outerAngleInDegrees: 179, // greater angle – softer shadows
attenuationRadius: 10) // can't be Zero
}
}
class ViewController: UIViewController {
#IBOutlet var arView: ARView!
enum TapObjects {
case None
case HiddenChair
case ScaledChair
}
var furnitureAnchor : Furniture._Furniture!
var tapObjects : TapObjects = .None
override func viewDidLoad() {
super.viewDidLoad()
furnitureAnchor = try! Furniture.load_Furniture()
arView.scene.anchors.append(furnitureAnchor)
addTapGesture()
}
func addTapGesture() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onTap))
arView.addGestureRecognizer(tapGesture)
}
#objc func onTap(_ sender: UITapGestureRecognizer) {
switch tapObjects {
case .None:
furnitureAnchor.notifications.unhideChair.post()
tapObjects = .HiddenChair
case .HiddenChair:
furnitureAnchor.notifications.scaleChair.post()
tapObjects = .ScaledChair
default:
break
}
}
}

How can I add gravity to UIButton SWIFT

So I am trying to add gravity to 4 UIButtons but they are not falling, I added this code to the view did load, I don't why this isn't working well.
Here is the code:
//initialize the animator
var animator = UIDynamicAnimator(referenceView: self.view)
//add gravity
let gravity = UIGravityBehavior(items: [redButton!, greenButton!, blueButton!, cameraButton!])
let direction = CGVectorMake(0.0, 1.0)
gravity.gravityDirection = direction
animator.addBehavior(gravity)
My buttons are the redButton, greenButton, blueButton, and the cameraButton, also I have applied the direction of the fall but when I run the app they are just static. So is it possible to add gravity to the UIButtons?
You are declaring your animator locally to the function. When the function returns, the animator is released from memory, and all animation stops (actually viewDidLoad() returns so early in the lifecycle that animation never gets started).
Declare it as:
var animator: UIDynamicAnimator!
at class scope
Class scope means put it within the curly braces of the class:
class Foo {
var thisVariableIsAtClassScopeAndPersistsAcrossMethods: Int
func bar() {
var thisVariableIsAtLocalScopeAndDisappearsWhenFunctionReturns: String
}
}
And only initialize it in viewDidLoad():
animator = UIDynamicAnimator(referenceView: self.view)
(You cannot initialize it at class scope without lazy trickiness, because self is not yet available.)
** EDIT FINAL ANSWER **
After chat, we resolved the misunderstood answer and now we have:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var redButton: UIButton!
#IBOutlet weak var greenButton: UIButton!
#IBOutlet weak var blueButton: UIButton!
#IBOutlet weak var cameraButton: UIButton!
// Declare the animator at class scope so it doesn't get released prematurely.
var animator: UIDynamicAnimator!
override func viewDidLoad() {
super.viewDidLoad()
//add gravity
let gravity = UIGravityBehavior(items: [redButton, greenButton, blueButton, cameraButton])
let direction = CGVectorMake(0.0, 1.0)
gravity.gravityDirection = direction
animator.addBehavior(gravity)
// other viewDidLoad setup code to set attributes of buttons
}
}

How do I change the CGRect to buttons?

I originally used rectangles to test out the program but now I need to make them buttons. How would I do that programmatically?
import UIKit
class interestViewController: UIViewController {
var squareView: UIView!
var square: UIView!
var frogs: UIView!
var colson: UIView!
var wwdc: UIView!
var gravity: UIGravityBehavior!
var animator: UIDynamicAnimator!
var collision: UICollisionBehavior!
override func viewDidLoad() {
super.viewDidLoad()
squareView = UIView(frame: CGRectMake(100, 100, 100, 100))
view.addSubview(squareView)
animator = UIDynamicAnimator(referenceView: view)
squareView.backgroundColor = UIColor.blackColor()
gravity = UIGravityBehavior(items: [squareView])
animator.addBehavior(gravity)
collision = UICollisionBehavior(items: [squareView])
collision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(collision)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Question: How would I do that programmatically?
Short answer: Don't. Create your buttons in IB. It's easier than code the first time, and way, waaaaay easier to update and maintain. Learn to use IB. It's a huge timesaver.
If you are bound and determined to do things the hard way, then you'll need to use one of the UIButton class initializers, like buttonWithType. Then you'd set the frame and other attributes like you're doing with your squareView.