Domanda

Sto lavorando su un paio di base Applicazioni / Utility / giochi con l'iPhone per ottenere una migliore presa su di esso.

Al momento ho una configurazione in cui un CGRect muove ovunque i movimenti delle dita, ma io non voglio la CGRect di andare al di fuori della bounds del view.

Metodo Originale

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    startLocation = [touch locationInView:self];
    if (startLocation.x < 33){
        touchLocation.x = 33;
            //NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
        [self setNeedsDisplay];
    }
    if (startLocation.x > 288){
        touchLocation.x = 288;
            //NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
        [self setNeedsDisplay];
    }
    if (startLocation.y < 84){
        touchLocation.y = 84;
            //NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
        [self setNeedsDisplay];
    }
    if (startLocation.y > 460){
        touchLocation.y = 460;
            //NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
        [self setNeedsDisplay];
    }
    else {
        touchLocation = startLocation;
        [self setNeedsDisplay];
    }
}

Problema

Ho provato un paio di metodi diversi di questo, anche utilizzando && e rendendolo una sola dichiarazione. Il boundaries sono ovviamente difficile codificato, e io non sono sicuro che l'impostazione manuale del touchLocation è il modo migliore per tenerlo in bounds.

Tutto questo sembra sciocco a me quando posso facilmente self.view.bounds e ottenere il delimitazione CGRect. Come faccio a fare uso di bounds per fare questo? C'è un modo migliore per evitare che accada di diversa impostazione di touchLocation manualmente? Posso in qualche modo posto un limite rigido su di esso, invece?

Che dire di una dichiarazione switch? Vorrei che funziona meglio di the-ifs tentate?


Tentativo

Ora sto cercando di utilizzare il metodo di @Brad Goss postato qui sotto, ma non funziona?

Touch Started: (319.000000,350.000000)
Touch Result: (319.000000,350.000000)
Boundaries calculated: X:(0.000000,288.000000) Y(0.000000,328.000000)

tocco introduttiva è il tocco reale di partenza. Tocco risultato dovrebbe essere il risultato modificato.

Il registro sopra sta mostrando al di fuori del bounds definito, alias non funziona. Io non ho intenzione di ripubblicare il codice che ha scritto, perché è esattamente la stessa.


Tentativo Problema

ho scoperto il problema. Questa è la stessa situazione tipo come sopra, ma con la registrazione per i singoli valori sono impostati.

Touch Started: (293.000000,341.000000)
min x:288.000000
max x:293.000000
min y:328.000000
max y:341.000000
Touch Result: (293.000000,341.000000)
Boundaries calculated: X:(0.000000,288.000000) Y(0.000000,328.000000)

Non ho capito, ho postato qui, non appena l'ho scoperto. Altrimenti sarei dimenticato di aggiornare a tutti, ADD eh.

ho intenzione di tornare indietro e vedere esattamente cosa sta succedendo in ciascuna delle possibili situazioni.


Errore

Trovato un altro problema, il codice che calcola la boundaries subtracts dal maximums, ma non add al minimums. Questo è importante perché questo è ciò che il boundary è per, per fermare il rect di andare fuori dallo schermo.

maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
minX = b.origin.x/* + [box bounds].size.width */;
maxY = b.origin.y + b.size.height/* - [box bounds].size.height */;
minY = b.origin.y?/* + [box bounds].size.height */;

Con questo riparato, posso continuare a lavorare sul problema originale.


Errore 2

Va bene, ho messo a posto un altro problema. Stavo aggiungendo al valore y quando è stato visualizzato. Ho dimenticato di aggiungere in questo nuovo codice / parlarne. Il codice ora assomiglia a questo:

maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
minX = b.origin.x/* + [box bounds].size.width */;
maxY = b.origin.y + b.size.height/* - [box bounds].size.height + 20*/;
minY = b.origin.y/* + [box bounds].size.height + 20*/;

La dimensione del cerchio viene visualizzata è all'interno di un 64px CGRect, quindi 20px era sufficiente per visualizzare il cerchio appena sopra il pollice. Anche se questo è fisso, ancora non ha contribuito a risolvere il nostro problema originale.

in alto a sinistra:

Touch Started: (14.000000,20.000000)
min x:14.000000
max x:32.000000
min y:20.000000
max y:84.000000
Touch Result: (32.000000,84.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)

E 'funziona come dovrebbe, ma sono confuso sul motivo per cui i valori corretti stanno uscendo MAX invece di MIN. Qualcosa si confonde qui.

Alta a destra:

Touch Started: (303.000000,21.000000)
min x:288.000000
max x:303.000000
min y:21.000000
max y:84.000000
Touch Result: (303.000000,84.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)

E 'che mi impedisce di andare fuori dallo superiore dello schermo, sempre da MAX invece di MIN. Sono ancora in grado di volare via sulla destra, come indicato sopra.

nell'angolo in basso a destra:

Touch Started: (317.000000,358.000000)
min x:288.000000
max x:317.000000
min y:276.000000
max y:358.000000
Touch Result: (317.000000,358.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)

E 'mancato in entrambe le direzioni. Ora i valori reali sono provenienti da MAX, ei valori massimi sono provenienti da MIN. WTF?

in basso a sinistra:

Touch Started: (8.000000,354.000000)
min x:8.000000
max x:32.000000
min y:276.000000
max y:354.000000
Touch Result: (32.000000,354.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)

Come prevedibile, ha funzionato solo per il valore minimo. Sono ancora molto confuso su ciò che si suppone queste funzioni a che fare. Insight sarebbe molto apprezzato!


risolto!

La nostra lunga strada volge al termine, per fortuna. Quindi, perché non avevo idea, ecco cosa MIN e MAX fanno. Non era initially ovvio per me a causa della confusione che aveva avuto luogo.

MAX(x,y) will output the larger of the two numbers
// MAX(13,37) = 37
MIN(x,y) will output the smallest of the two numbers
// MIN(13,37) = 13

Quindi questo è quello che devi fare per fare uso di queste funzioni in modo corretto in questa situazione:

1. Calcolare la massima & Valori minimi per X e Y.

Il valore più basso per ciascun viene calcolato come

view.origin + keepOnScreenRect.width  

Il valore più alto di ciascuno è calcolato come

view.origin + view.size.height/width - keepOnScreenRect.height/width

Non dimenticare l'offset per il dito!
Se si sta facendo quello che ho fatto, e avete la keepOnScreenRect posizionata leggermente sopra il dito dell'utente, si dovrebbe aggiungere solo l'offset al valore massimo di Y in più, come il valore minimo di Y è la parte inferiore dello schermo / vista, che si è fisicamente in grado di andare inferiore a 0 a.

Se vi state chiedendo il motivo per cui questo è fatto, è perché l'utente non può vedere attraverso la sua / il suo dito.

2. Ottenere la posizione del tocco sulla touchesBegan:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    startTouchLocation = [touch locationInView:self];
    NSLog(@"Touch Started: (%f,%f)", startTouchLocation.x, startTouchLocation.y);

3. Applicare i vincoli matematici:

In primo luogo, si ottiene il MAX, o valore più alto, sia del valore più basso possibile secondo i nostri limiti, minX, e startTouchLocation, per X. Questo calcola il limite per il lato sinistro dello schermo. Il risultato di questo è impostato su currentTouchLocation.

currentTouchLocation.x = MAX(minX, startTouchLocation.x);

In secondo luogo, si ottiene il MIN, o il valore più basso, sia del valore più alto possibile secondo i nostri limiti, maxX, e currentTouchLocation, per X. Si noti che non stiamo usando la posizione del tocco originale, ma invece la posizione risultante della funzione MAX abbiamo usato solo. Questo valore è già stato controllato per il lato sinistro dello schermo, in modo da controllare la destra.

currentTouchLocation.x = MIN(maxX, currentTouchLocation.x);

Questo ci dà una posizione X che è garantito per essere entro i nostri limiti. Abbiamo quindi eseguire lo stesso su Y.

currentTouchLocation.y = MAX(minY, startTouchLocation.y);
currentTouchLocation.y = MIN(maxY, currentTouchLocation.y);

Con tutto questo finito, possiamo ora dire al fine di ridisegnare se stessa e non più temere avere il nostro piccolo rettangolo bella tagliata in alcun modo.

[self setNeedsDisplay];

Prodotto Finito

/* Generates the limits based on the view's size, taking into account 
   the width/height of the rect being displayed in it. This should only
   be run once, unless the size of the view changes, in which case limits
   would have to be recalculated. The same goes for if you were to change
   the size of the displaying rect after calculation */

- (void)boundsCalculation {
    CGRect viewBounds = [self bounds];

        // calculate constraints
    maxX = viewBounds.origin.x + viewBounds.size.width - 32;
    minX = viewBounds.origin.x + 32;
    maxY = viewBounds.origin.y + viewBounds.size.height - 32;
    minY = viewBounds.origin.y + 84;
    NSLog(@"Boundaries calculated: X:(%f,%f) Y(%f,%f)", minX, maxX, minY, maxY);
}

/* Magic goodness that happens when the user touches the screen.
   Note that we don't calculate the bounds every time the user touches
   the screen, that would be silly. */

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    startTouchLocation = [touch locationInView:self];
    NSLog(@"Touch Started: (%f,%f)", startTouchLocation.x, startTouchLocation.y);

        // apply constraints
            // highest x value between the lowest allotted x value and touch
    currentTouchLocation.x = MAX(minX, startTouchLocation.x);
            // lowest x value between the highest allotted x value and touch
    currentTouchLocation.x = MIN(maxX, currentTouchLocation.x);
            // highest y value between the lowest allotted y value and touch
    currentTouchLocation.y = MAX(minY, startTouchLocation.y);
            // lowest y value between the highest allotted y value and touch
    currentTouchLocation.y = MIN(maxY, currentTouchLocation.y);
           // NSLog(@"Touch Result: (%f,%f)", currentTouchLocation.x, currentTouchLocation.y);

           // If you don't do this you won't see anything
    [self setNeedsDisplay];
}

Oggi è stata una buona giornata per l'apprendimento.

È stato utile?

Soluzione

Sicuramente si desidera utilizzare i limiti del suo superview per vincolare è movimento.

Non chiamare setNeedsDisplay che spesso. Chiamatela una volta alla fine del metodo. Si sono potenzialmente ridisegnare inutilmente.

userei qualcosa di simile a quanto segue per raggiungere questo obiettivo.

// define these variables where ever you'd like
static float maxX = 0.;
static float maxY = 0.;
static float minX = 0.;
static float minY = 0.;

- (void)setupView {
    CGRect b = [self bounds];

    // calculate constraints
    maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
    minX = b.origin.x;
    maxY = b.origin.y + b.size.height/* - [box bounds].size.height */;
    minY = b.origin.y;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    startLocation = [touch locationInView:self];

    // apply constraints
    touchLocation.x = MIN(maxX, startLocation.x);
    touchLocation.x = MAX(minX, startLocation.x);
    touchLocation.y = MIN(maxY, startLocation.y);
    touchLocation.y = MAX(minY, startLocation.y);

    [self setNeedsDisplay];
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top