.removeFromParent() not working - cocoa-touch

This is the code that is involved. What is suppose to happen is when the bullet hits and enemy or vice versa they disappear. Not working out at all :(
func didBeginContact(contact: SKPhysicsContact) {
var firstBody : SKPhysicsBody = contact.bodyA
var secondBody : SKPhysicsBody = contact.bodyB
if ((firstBody.categoryBitMask == PhysicsCatagory.Enemy) && (secondBody.categoryBitMask == PhysicsCatagory.Bullet) || (firstBody.categoryBitMask == PhysicsCatagory.Bullet) && (secondBody.categoryBitMask == PhysicsCatagory.Enemy)) {
CollisionWithBullet(firstBody.node as! SKSpriteNode, Bullet: secondBody.node as! SKSpriteNode)
}
}
func CollisionWithBullet(Enemy: SKSpriteNode, Bullet: SKSpriteNode) {
Enemy.removeFromParent()
Bullet.removeFromParent()
}
Here is what the game looks like:

It seems like you're calling it to the class, it doesn't work that way.
You need to have an array of enemies or a single enemy instance and than call
removeFromParent()
Referencing the specific instances that have been added, not the class itself.
Example:
firstBody.removeFromParent()
secondBody.removeFromParent()

Related

SwiftUI: Is it possible to automatically move to the next textfield after 1 character is entered?

I trying to make a SwiftUI app where after entering one letter in a TextField the cursor automatically moves to the next TextField. The UI is pretty much like this.
In Swift/IB, it looks like this was done with delegates and adding a target like in this post:
How to move to the next UITextField automatically in Swift
But can't find any documentation for using delegates/targets in SwiftUI.
I tried following this post:
SwiftUI TextField max length
But this has not worked for me. Setting the .prefix(1) does not seem to make a difference. The TextField still accepts any amount of characters and when moved to the next TextField does not reduce the characters entered to only the first character.
In SwiftUI's current state, is it possible to automatically move to the next TextField after 1 character is entered?
Thanks for any help!
It can be done in iOS 15 with FocusState
import SwiftUI
///Sample usage
#available(iOS 15.0, *)
struct PinParentView: View {
#State var pin: Int = 12356
var body: some View {
VStack{
Text(pin.description)
PinView(pin: $pin)
}
}
}
#available(iOS 15.0, *)
struct PinView: View {
#Binding var pin: Int
#State var pinDict: [UniqueCharacter] = []
#FocusState private var focusedField: UniqueCharacter?
var body: some View{
HStack{
ForEach($pinDict, id: \.id, content: { $char in
TextField("pin digit", text:
Binding(get: {
char.char.description
}, set: { newValue in
let newest: Character = newValue.last ?? "0"
//This check is only needed if you only want numbers
if Int(newest.description) != nil{
char.char = newest
}
//Set the new focus
DispatchQueue.main.async {
setFocus()
}
})
).textFieldStyle(.roundedBorder)
.focused($focusedField, equals: char)
})
}.onAppear(perform: {
//Set the initial value of the text fields
//By using unique characters you can keep the order
pinDict = pin.description.uniqueCharacters()
})
}
func setFocus(){
//Default to the first box when focus is not set or the user reaches the last box
if focusedField == nil || focusedField == pinDict.last{
focusedField = pinDict.first
}else{
//find the index of the current character
let idx = pinDict.firstIndex(of: focusedField!)
//Another safety check for the index
if idx == nil || pinDict.last == pinDict[idx!]{
focusedField = pinDict.first
}else{
focusedField = pinDict[idx! + 1]
}
}
//Update the Binding that came from the parent
setPinBinding()
}
///Updates the binding from the parent
func setPinBinding(){
var newPinInt = 0
for n in pinDict{
if n == pinDict.first{
newPinInt = Int(n.char.description) ?? 0
}else{
newPinInt = Int(String(newPinInt) + n.char.description) ?? 0
}
}
pin = newPinInt
}
}
//Convert String to Unique characers
extension String{
func uniqueCharacters() -> [UniqueCharacter]{
let array: [Character] = Array(self)
return array.uniqueCharacters()
}
func numberOnly() -> String {
self.trimmingCharacters(in: CharacterSet(charactersIn: "-0123456789.").inverted)
}
}
extension Array where Element == Character {
func uniqueCharacters() -> [UniqueCharacter]{
var array: [UniqueCharacter] = []
for char in self{
array.append(UniqueCharacter(char: char))
}
return array
}
}
//String/Characters can be repeating so yu have to make them a unique value
struct UniqueCharacter: Identifiable, Equatable, Hashable{
var char: Character
var id: UUID = UUID()
}
#available(iOS 15.0, *)
struct PinView_Previews: PreviewProvider {
static var previews: some View {
PinParentView()
}
}

Animate the drawing of an MKPolyline on MKMapView

I’ve got an MKMapView to animate a line by adding a line, removing it, adding a minor segment and re-adding it to the map. However, this puts a lot of overhead on the phone and doesn’t look the best. I noticed Google Maps and Uber have cleanly animated lines for showing routes that run smoothly no matter what the length or route type. Does anyone have any suggestions for a solution which is less energy-draining and looks cleaner?
Thanks, SebO.
An array of coordinates will be needed. If you have only beginning and end coordinates, get array of coordinates using below code
func getPointsOnRoute(from: CLLocation?, to: CLLocation?, on mapView: MKMapView?) -> [CLLocation]? {
let NUMBER_OF_PIXELS_TO_SKIP: Int = 120
//lower number will give a more smooth animation, but will result in more layers
var ret = [Any]()
var fromPoint: CGPoint? = nil
if let aCoordinate = from?.coordinate {
fromPoint = mapView?.convert(aCoordinate, toPointTo: mapView)
}
var toPoint: CGPoint? = nil
if let aCoordinate = to?.coordinate {
toPoint = mapView?.convert(aCoordinate, toPointTo: mapView)
}
let allPixels = getAllPoints(from: fromPoint!, to: toPoint!)
var i = 0
while i < (allPixels?.count)! {
let pointVal = allPixels![i] as? NSValue
ret.append(point(toLocation: mapView, from: (pointVal?.cgPointValue)!)!)
i += NUMBER_OF_PIXELS_TO_SKIP
}
ret.append(point(toLocation: mapView, from: toPoint!)!)
return ret as? [CLLocation] }
Having array of coordinates add rendering of the overlays in MKMapViewDelegate’s delegate method — mapView(_:rendererFor:).
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
guard let polyline = overlay as? MKPolyline else {
return MKOverlayRenderer()
}
let polylineRenderer = MKPolylineRenderer(overlay: polyline)
polylineRenderer.strokeColor = .black
polylineRenderer.lineWidth = 2
return polylineRenderer
}
mapView.addOverlay(polyline) // add it to mapview
render the polyline in small segments to create the animation effect
var drawingTimer: Timer?
// ....// Somewhere in your View Controller
func animate(route: [CLLocationCoordinate2D], duration: TimeInterval, completion: (() -> Void)?) {
guard route.count > 0 else { return }
var currentStep = 1
let totalSteps = route.count
let stepDrawDuration = duration/TimeInterval(totalSteps)
var previousSegment: MKPolyline?
drawingTimer = Timer.scheduledTimer(withTimeInterval: stepDrawDuration, repeats: true) { [weak self] timer in
guard let self = self else {
// Invalidate animation if we can't retain self
timer.invalidate()
completion?()
return
}
if let previous = previousSegment {
// Remove last drawn segment if needed.
self.mapView.removeOverlay(previous)
previousSegment = nil
}
guard currentStep < totalSteps else {
// If this is the last animation step...
let finalPolyline = MKPolyline(coordinates: route, count: route.count)
self.mapView.addOverlay(finalPolyline)
// Assign the final polyline instance to the class property.
self.polyline = finalPolyline
timer.invalidate()
completion?()
return
}
// Animation step.
// The current segment to draw consists of a coordinate array from 0 to the 'currentStep' taken from the route.
let subCoordinates = Array(route.prefix(upTo: currentStep))
let currentSegment = MKPolyline(coordinates: subCoordinates, count: subCoordinates.count)
self.mapView.addOverlay(currentSegment)
previousSegment = currentSegment
currentStep += 1
}
}

removing last node linked list in objective -c

I am trying to implement a removeLast function for a linked list in objective-c. My add function property works well because I can see the node I created, but when I try to remove a node it does not work. I have tried looking up general solutions for this, but have not come up with anything. Is there something special with objective-c that I should take a look at?
-(void) removeLast{
Node *newNode = [[Node alloc]init];
Node *tail = [[Node alloc]init];
if (self.head == NULL){
NSLog(#"No items to remove");
}
else{
newNode = self.head;
tail= self.head;
while (tail != NULL) {
tail = tail.next;
if (tail != NULL){
newNode = tail;
}
}
newNode.next = NULL;
}
}
I believe you've overcomplicated the algorithm. You don't need to keep a reference to the previous link if you always look one step ahead:
- (void) removeLast {
if (self.head == NULL) {
NSLog(#"Empty list");
} else if (self.head.next == NULL) {
self.head = NULL;
} else {
Node* current = self.head;
while (current.next.next != NULL)
current = current.next;
current.next = NULL;
}
}
This iterates through until it reaches the next-to-last node when current.next.next will be null. Then it makes that the last node.

Merge connected UIBezierPaths

Is there some way (code or pseudo-code algorithm) to utilize UIBezierPath instance methods like appendPath to "merge" any number of connected, distinct UIBezierPaths into a single big path? In a document with many paths, I am trying to reduce the encoded file size by perhaps reducing the number of paths as there is surely some redundant information there. If I am barking up the wrong tree, let me know.
In my case, I had few logically connected paths that together form a closed shape and I wanted to fill this closed shape. This cannot be done if you just append(_:) them together as the fill would simply applied to each path. I looked at similar questions asked but none of them solved the problem. So I wrote this extension to merge logically connected paths together to form a single path.
If you have path1, path2 and path3 logically form a closed shape. Call them in the same order
let mergedPath = UIBezierPath()
mergedPath.merge(with: path1)
mergedPath.merge(with: path2)
mergedPath.merge(with: path3)
import UIKit
extension UIBezierPath {
func merge(with path: UIBezierPath) {
let currentPath = self.cgPath.mutableCopy()!
let lastPoint = self.lastPoint()
let firstPoint = path.firstPoint()
var index = -1
path.cgPath.applyWithBlock { block in
index += 1
let element = block.pointee
switch (element.type) {
case .moveToPoint:
if index != 0 && lastPoint != firstPoint || lastPoint == nil {
currentPath.move(to: element.points[0])
}
case .addLineToPoint:
currentPath.addLine(to: element.points[0])
case .addQuadCurveToPoint:
currentPath.addQuadCurve(to: element.points[1], control: element.points[0])
case .addCurveToPoint:
currentPath.addCurve(to: element.points[2], control1: element.points[0], control2: element.points[1])
case .closeSubpath:
currentPath.closeSubpath()
#unknown default:
fatalError()
}
}
self.cgPath = currentPath
}
func firstPoint() -> CGPoint? {
var firstPoint: CGPoint? = nil
var index = -1
self.cgPath.applyWithBlock { block in
index += 1
let element = block.pointee
if index == 0 {
if element.type == .moveToPoint || element.type == .addLineToPoint {
firstPoint = element.points[0]
} else if element.type == .addQuadCurveToPoint {
firstPoint = element.points[1]
} else if element.type == .addCurveToPoint {
firstPoint = element.points[2]
}
}
}
return firstPoint
}
func lastPoint() -> CGPoint? {
var lastPoint: CGPoint? = nil
var index = -1
self.reversing().cgPath.applyWithBlock { block in
index += 1
let element = block.pointee
if index == 0 {
if element.type == .moveToPoint || element.type == .addLineToPoint {
lastPoint = element.points[0]
} else if element.type == .addQuadCurveToPoint {
lastPoint = element.points[1]
} else if element.type == .addCurveToPoint {
lastPoint = element.points[2]
}
}
}
return lastPoint
}
}
well if its only an esthetically problem...just set the first point of the 2nd bezier curve as the last point of the 1st..and so on..
if its not i don't think there is a way to merge 2 or more bezier paths cuz ...well..they are bezier and it wont look right if you do
read more about bezier curves
bezier curves and see why it wont work

Cocos2d - compare two ccColor3B struct colors

I'm working on a game (Cocos2d + Obj-C) where I need to check if two colliding sprites has the same color or not. I've tried the following already:
if (ship.imageSprite.color == base.imageSprite.color)
{
{
NSLog(#"matching colors");
}
}
But I get compile time error: "invalid operands to binary expresson ('ccColor3B'(aka 'struct _ccColor3B') and 'ccColor3B')." What is the way to test two colors? Thanks.
-(BOOL)isccColor3B:(ccColor3B)color1 theSame:(ccColor3B)color2{
if ((color1.r == color2.r) && (color1.g == color2.g) && (color1.b == color2.b)){
return YES;
} else {
return NO;
}
}
You'll have to test the ccColor3B components individually:
ccColor3B col1 = ship.imageSprite.color;
ccColor3B col2 = base.imageSprite.color;
if (col1.r == col2.r && col1.g == col2.g && col1.b == col2.b)
{
NSLog(#"matching colors");
}