Конкретный режим спарринга вызывает неправильное перенаправление узлаIOS

Программируем под IOS
Ответить
Anonymous
 Конкретный режим спарринга вызывает неправильное перенаправление узла

Сообщение Anonymous »

Я работаю над приложением для iOS, используя данные UIKIT и основные данные, которые включают навигацию на основе графиков, где узлы представляют различные движения в системе боевых искусств. Пользователи могут перемещаться по этим узлам в разных режимах, включая конкретный режим спарринга, который вводит случайность при выборе узлов. На данный момент: < /p>
Нормальный узел начинает неправильно перенаправляться на первичный узел сбоя, а не предполагаемые подключения.
Эта проблема сохраняется до тех пор, пока пользователь не освежает страницу.
Стоимость сами узлы никогда не перенаправляют неправильно, то есть только нормальные узлы повреждены. < /P>
Ожидаемое поведение -< /p>
Только вторичные узлы должны перенаправить на соответствующие их первичные узлы.
узлы сбоев не должны мешать логике навигации нормальных узлов. Переплата. .
подтвердил, что сбочные узлы отображались правильно, но некоторые нормальные узлы исчезали или неправильно перенаправляли. Между узлами после встречи с обалке retrypecificsparring (), чтобы увидеть, решила ли проблема в попытке повторного. Основные данные были сохранены неверные отношения.
подтвердил, что проблема исчезает после освежения, что означает, что это, вероятно, не основная проблема хранения данных, а что -то происходит динамически во время навигации.
Что я ожидал < /p>
Вторичные узлы должны перенаправляться только на их соответствующие первичные узлы.
Отказы сбоев не должны мешать нормальным узлам.
После отказа нормальные узлы должны продолжать функционировать, как и ожидалось. Спарринг должен правильно сбросить поведение узла. УЗО. Это все мои относительные кусочки кода. < /P>
func navigateToPrimaryNode(for node: DragableNode) -> DragableNode {
// ✅ If node is already primary, return it immediately
if node.type == .primary {
return node
}

// ✅ If node is secondary, find its correct primary node
if node.type == .secondary, let primaryNode = findPrimaryNode(for: node) {
print("🔄 Navigating Secondary \(node.text ?? "Unnamed") to Primary \(primaryNode.text ?? "Unnamed")")
return primaryNode
}

// ✅ If it's a fail node, check if it has a primary fail node
if node.entity.nodeType == .fail, let primaryFailNode = findPrimaryNode(for: node) {
print("⚠️ Redirecting Fail Node \(node.text ?? "Unnamed") to Primary \(primaryFailNode.text ?? "Unnamed")")
return primaryFailNode
}

// 🔴 Special Case: Prevent fail nodes from overriding normal node redirects
if node.entity.nodeType != .fail {
if let cachedPrimary = findPrimaryNode(for: node) {
print("✅ Ensuring normal node \(node.text ?? "Unnamed") stays mapped to its actual primary \(cachedPrimary.text ?? "Unnamed")")
return cachedPrimary
}
}

print("⚠️ No primary found for \(node.text ?? "Unnamed"), returning original node")
return node
}
< /code>
Piece 2 < /p>
func findPrimaryNode(for node: DragableNode) -\> DragableNode? {
guard node.type == .secondary else { return nil }

let primaryCandidates = textFields.filter {
$0.type == .primary && $0.text == node.text
}

if primaryCandidates.isEmpty {
print("⚠️ No primary node found for secondary node: \(node.text ?? "Unnamed")")
return nil
}

if primaryCandidates.count == 1 {
print("✅ Found single primary node: \(primaryCandidates.first!.text ?? "Unnamed")")
return primaryCandidates.first
}

// 🔥 If multiple primary nodes exist, use the entity relationship as a backup check
for primary in primaryCandidates {
if primary.entity.children?.contains(node.entity) == true {
print("✅ Selected correct primary node: \(primary.text ?? "Unnamed") for secondary node: \(node.text ?? "Unnamed")")
return primary
}
}

print("⚠️ Multiple matching primary nodes found, defaulting to first: \(primaryCandidates.first!.text ?? "Unnamed")")
return primaryCandidates.first
}
< /code>
Piece 3 < /p>
// Helper function to find the primary text field with a specific name
func findPrimaryTextField(named name: String) -\> DragableNode? {
return textFields.first { $0.text == name && $0.type == .primary }
}
< /code>
Piece 4 < /p>
@objc func handleNodeTap(\_ sender: UITapGestureRecognizer) {
guard let tappedNode = sender.view as? DragableNode else { return }

// ✅ If tapped node is a Secondary Node, redirect to the Primary Node
if tappedNode.type == .secondary, let primaryNode = findPrimaryNode(for: tappedNode) {
print("🔄 Redirecting from Secondary \(tappedNode.text ?? "Unnamed") to Primary \(primaryNode.text ?? "Unnamed")")
enterViewMode(for: primaryNode)
return
}

if isInViewMode {
enterViewMode(for: tappedNode)
return
}

if isInSpecificSparring {
print("🔥 Specific Sparring: Moving to Next Stage from \(tappedNode.text ?? "Unnamed Node")")
startSpecificSparring(for: tappedNode, difficulty: currentSparringDifficulty)

// ✅ Recenter and zoom to fit new nodes after selecting one
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
let visibleNodes = self.contentView.subviews.compactMap { $0 as? DragableNode }.filter { !$0.isHidden }
self.recenterAndZoomToFit(nodes: visibleNodes)
}
return
}

// Animate the current node scaling up
UIView.animate(withDuration: 0.3, animations: {
tappedNode.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
tappedNode.alpha = 1.0
}, completion: { _ in
// Reset the scaling back to normal
UIView.animate(withDuration: 0.2) {
tappedNode.transform = CGAffineTransform.identity
}

// 🔥 Transition to the new node
self.enterViewMode(for: tappedNode)
})
}
< /code>
Piece 5 < /p>
@objc private func retrySpecificSparring() {
guard let firstNode = firstViewModeNode else {
print("⚠️ No firstViewModeNode found! Restarting from the last used node.")

if let lastUsedNode = textFields.first(where: { !$0.isHidden }) {
firstViewModeNode = lastUsedNode
startSpecificSparring(for: lastUsedNode, difficulty: currentSparringDifficulty)
}
return
}

print("🔄 Retrying Specific Sparring from \(firstNode.text ?? "Unnamed")")

// ✅ Resetting the View
DispatchQueue.main.async {
for subview in self.contentView.subviews {
if let textNode = subview as? DragableNode {
textNode.isHidden = true
textNode.alpha = 0.0
}
}

// ✅ Removing old lines
self.contentView.layer.sublayers?.removeAll(where: { $0 is CAShapeLayer })

// ✅ Restart sparring
self.startSpecificSparring(for: firstNode, difficulty: self.currentSparringDifficulty)
}
}
< /code>
Piece 6 < /p>
func startSpecificSparring(for node: DragableNode, difficulty: Int) {
guard let superview = self.contentView else { return }

var targetNode: DragableNode = navigateToPrimaryNode(for: node)

// Debugging
print("🔥 Starting Specific Sparring - Node: \(node.text ?? "Unnamed") (Type: \(node.type))")
print("🔄 Redirecting to Primary Node: \(targetNode.text ?? "Unnamed") (Type: \(targetNode.type))")

if firstViewModeNode == nil {
firstViewModeNode = targetNode
print("✅ Setting firstViewModeNode to \(targetNode.text ?? "Unnamed Node")")
}

// ✅ Ensure the correct node is visible and updated immediately
DispatchQueue.main.async {
targetNode.isHidden = false
targetNode.alpha = 1.0
self.contentView.bringSubviewToFront(targetNode)
}

// 🔥 Ensure primary nodes are brought to the front to avoid touch interference
for subview in contentView.subviews {
if let primaryNode = subview as? DragableNode, primaryNode.type == .primary {
contentView.bringSubviewToFront(primaryNode)
}
}

isInSpecificSparring = true
currentSparringDifficulty = difficulty

// ✅ Ensure firstViewModeNode is set when entering sparring mode
if firstViewModeNode == nil {
firstViewModeNode = targetNode
}

// ✅ Roll a random number (1-10)
let winChance = Int.random(in: 1...10)

// ✅ Determine winning/losing numbers based on difficulty
let (winningNumbers, losingNumbers) = getWinningLosingNumbers(for: difficulty)

let didWin = winningNumbers.contains(winChance)

print("🎲 Random Roll: \(winChance) → \(didWin ? "SUCCESS" : "FAIL")")

// ✅ Hide all nodes initially
for subview in superview.subviews {
if let textNode = subview as? DragableNode {
textNode.isHidden = true
}
}

// ✅ Always keep the selected node visible
targetNode.isHidden = false
targetNode.alpha = 1.0
superview.bringSubviewToFront(targetNode)

// ✅ Remove all existing lines
for sublayer in superview.layer.sublayers ?? [] {
if let line = sublayer as? CAShapeLayer {
line.removeFromSuperlayer()
}
}

var nodesToShow: [DragableNode] = []

// ✅ Determine which nodes should be visible
for subview in superview.subviews {
if let textNode = subview as? DragableNode, textNode !== targetNode {
let isConnected = targetNode.entity.children?.contains(where: { ($0 as? TextFieldsEntity) == textNode.entity }) == true
let isParent = textNode.entity.parent == targetNode.entity
let isFailNode = textNode.entity.nodeType == .fail
let isAllowedSuccessType = textNode.entity.nodeType == .progression ||
textNode.entity.nodeType == .transition ||
textNode.entity.nodeType == .submission

print("🟢 Checking node: \(textNode.text ?? "Unnamed") - Type: \(textNode.entity.nodeType)")

if didWin {
// ✅ Hide all fail nodes on success
if isFailNode {
textNode.isHidden = true
print("❌ Hiding Fail Node: \(textNode.text ?? "Unnamed") (Success Path)")
}
// ✅ Only show success nodes
else if isConnected && isAllowedSuccessType {
print("✅ Showing: \(textNode.text ?? "Unnamed") (Success Path)")
nodesToShow.append(textNode)
}
} else {
// ✅ Only show fail nodes
if isConnected && isFailNode {
print("✅ Showing Fail Node: \(textNode.text ?? "Unnamed") (Fail Path)")
nodesToShow.append(textNode)
}
}
}
}

// ✅ Ensure only the correct nodes are visible
for node in nodesToShow {
node.isHidden = false
node.alpha = 1.0
}

// ✅ Fade in connected nodes smoothly
fadeInConnectedNodes(nodesToShow)

// ✅ Position nodes properly
positionNodesRelativeTo(targetNode, connectedNodes: nodesToShow)

// ✅ Auto-recenter the view to fit all visible nodes
recenterAndZoomToFit(nodes: [targetNode] + nodesToShow)

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
let visibleNodes = [targetNode] + nodesToShow
self.recenterAndZoomToFit(nodes: visibleNodes)
}

// ✅ Add Retry & Exit buttons
addRetryAndExitButtons(below: targetNode)
}
< /code>
А вот есть менеджер узлов и узел Draggable, если вам это нужно < /p>
import Foundation
import UIKit

class NodeManager {
static let shared = NodeManager()

var primaryNodes: [String: (node: DragableNode, viewController: UIViewController)] = [:]

func clearPrimaryNodes() {
print("🧹 Clearing cached primary nodes")
primaryNodes.removeAll()
}

func addPrimaryNode(_ node: DragableNode, viewController: UIViewController) {
primaryNodes[node.text ?? ""] = (node, viewController)
}

func findPrimaryNode(named name: String) -> (node: DragableNode, viewController: UIViewController)? {
return primaryNodes[name]
}

}

import UIKit

class DragableNode: UIView, UITextFieldDelegate {

var textField: UITextField
var entity: TextFieldsEntity
var lines: [CAShapeLayer] = []
private var panGesture: UIPanGestureRecognizer!
var isInEditMode = false
var isEditable: Bool = false {
didSet {
textField.isUserInteractionEnabled = isEditable
}
}

var identifier: UUID?
var isPrimary: Bool = false
var isSecondary: Bool = false

var text: String? {
get { return textField.text }
set { textField.text = newValue}
}

var attributedPlaceholder: NSAttributedString? {
get { return textField.attributedPlaceholder }
set { textField.attributedPlaceholder = newValue }
}

var type: TextFieldType = .none {
didSet {
typeChanged(type: type)
}
}
// END OF STAGE

init(size: CGSize, entity: TextFieldsEntity) {
let frame = CGRect(x: entity.xPosition, y: entity.yPosition, width: size.width, height: size.height)
self.textField = UITextField(frame: frame)
self.entity = entity
super.init(frame: frame)
self.type = entity.fieldType
typeChanged(type: type)
setupView()
setupGestures()
NotificationCenter.default.addObserver(self, selector: #selector(handleEditModeChanged(_:)), name: .editModeChanged, object: nil)
}

init(frame: CGRect, entity: TextFieldsEntity) {
self.textField = UITextField(frame: frame)
self.entity = entity
super.init(frame: frame)
self.type = entity.fieldType
typeChanged(type: type)
setupView()
setupGestures()
NotificationCenter.default.addObserver(self, selector: #selector(handleEditModeChanged(_:)), name: .editModeChanged, object: nil)
}

required init?(coder aDecoder: NSCoder) {
fatalError("Method not available")
}

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.selectAll(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}

private func setupView() {
textField.delegate = self
addSubview(textField)
textField.translatesAutoresizingMaskIntoConstraints = false

// ✅ Apply default background color (solid color for text fields)
backgroundColor = entity.nodeType.color.withAlphaComponent(0.3)

// ✅ Apply node styling including gradients, shadows, and animations
entity.nodeType.applyStyle(to: self)

layer.masksToBounds = false // Allows shadow visibility

topAnchor.constraint(equalTo: textField.topAnchor).isActive = true
bottomAnchor.constraint(equalTo: textField.bottomAnchor).isActive = true
leadingAnchor.constraint(equalTo: textField.leadingAnchor, constant: -8).isActive = true
trailingAnchor.constraint(equalTo: textField.trailingAnchor, constant: 8).isActive = true
}

private func setupGestures() {
panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
self.addGestureRecognizer(panGesture)
}

func startEditing() {
textField.becomeFirstResponder()
}

@objc private func handleEditModeChanged(_ notification: Notification) {
if let userInfo = notification.userInfo, let isInEditMode = userInfo["isInEditMode"] as? Bool {
self.isInEditMode = isInEditMode
}
}

@objc func handlePan(_ sender: UIPanGestureRecognizer) {
guard let superview = self.superview else { return }

// Calculate the translation
let translation = sender.translation(in: superview)

// Update the node's center position
self.center = CGPoint(x: self.center.x + translation.x, y: self.center.y + translation.y)
sender.setTranslation(.zero, in: superview)

// Update the entity's position in the data model
entity.xPosition = self.frame.origin.x
entity.yPosition = self.frame.origin.y

// Notify the parent view controller to handle additional updates (e.g., lines)
var nextResponder: UIResponder? = self
while nextResponder != nil {
if let scrollViewController = nextResponder as? ScrollViewController {
scrollViewController.updateLinePosition(for: self)
break
}
nextResponder = nextResponder?.next
}

// Handle the gesture state for further updates or actions
if sender.state == .ended {
// Optionally perform any cleanup or additional updates when the gesture ends
print("✅ Pan gesture ended. Node position: \(center)")
}
}

func findViewController() -> UIViewController? {
var nextResponder: UIResponder? = self
while nextResponder != nil {
if let viewController = nextResponder as? UIViewController {
return viewController
}
nextResponder = nextResponder?.next
}
return nil
}

private func typeChanged(type: TextFieldType) {
switch type {
case .primary:
self.layer.borderColor = UIColor.black.cgColor
case .secondary:
self.layer.borderColor = UIColor.white.cgColor
case .none:
self.layer.borderColor = UIColor.clear.cgColor
}
self.layer.borderWidth = 2
entity.type = type.rawValue
}

func textFieldDidEndEditing(_ textField: UITextField) {
entity.text = textField.text
}

}


Подробнее здесь: https://stackoverflow.com/questions/794 ... edirection
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»