I have two UISlider called slider1
slider1.minimumValue = 0; slider1.maximumValue = 100;
i want to set a break point,such as 60, if the slider1 move to 60 from 0(left) to 60(right), it will stop here the thumb can not move to right, but it can move to left. so how can i do?
please take a look the following code, it doesn't work, thanks
-(IBAction)s1valuechanged:(id)sender{
if ((int)slider1.value > 60) {
slider1.userInteractionEnabled = FALSE;
}
else{
slider1.userInteractionEnabled =TRUE;
}
}
I'm having a bit of trouble understanding your question, so I'm going to assume that your slider looks like the following, and you want to prevent the user from moving the slider to a value greater than 60:
0 ----------60------100
|---valid----|-invalid-|
All you would need is the following:
-(IBAction)s1valuechanged:(id)sender{
if ((int)slider1.value > 60) {
slider.value = 60;
}
}
In other words, whenever the user tries to move the slider to a value greater than 60, move the slider back to 60.
Related
I want to create an eyeball that follows the user. In this sense, the eye should follow the position of the user but should only be able to move within certain bounds (The eye socket). The code I wrote below works, but its very choppy.
if(dist <= socketRadius - self.aEye.size.width/2.2){
lastPosition = self.aEye.position
self.aEye.physicsBody?.velocity = CGVector(dx:theVec.dx * eyeMoveSpeed, dy:theVec.dy * eyeMoveSpeed)
}
else{
let toCenterVector = normalizeVector( CGVector(dx:(self.socket.position.x - self.aEye.position.x), dy:(self.socket.position.y - self.aEye.position.y)*3 ))
self.aEye.physicsBody?.velocity = toCenterVector
print(toCenterVector)
print("Out")
}
(dist is the distance from the eyeball to the eyesocket center)
Is there a way to have a smooth flow of the eyeball around its socket to follow the user's position?
You can use SKConstraints to achieve this. Something like:
let rangeToCenterSprite = SKRange(lowerLimit: 80, upperLimit: 90)
var distanceConstraint: SKConstraint
distanceConstraint = SKConstraint.distance(rangeToCenterSprite, toNode: SpriteNodeInEyeCenter)
EyeBallSprite.constraints = [distanceConstraint]
In code below, I want to manage the amount of distance to travel when a left arrow key is pressed depending upon if it's half way down or not.
The object moves all the way to left on very first press instead of movement to be divided in 3 or 4 parts depending on the above mentioned condition, where am I doing it wrong?
var diff = Mathf.Abs(this.transform.position.x - r.renderer.bounds.min.x);
print("diff" + diff);
var lessdistancetotravel = diff/4;
var moredistancetotravel = diff/3;
if(this.transform.position.x > half)
{
print ("greater than half while moving left");
print("currentpos" + this.transform.position.x); //gives 0.6
print("moredistance " + moredistancetotravel);//gives 0.69
this.transform.position = new Vector3 (this.transform.position.x - moredistancetotravel,
this.transform.position.y,
this.transform.position.z);
print("updated" + (this.transform.position.x - moredistancetotravel)); //gives -0.78,How come?
}
Since you can't check how far down a key is pressed, as Jerdak mentioned in the comments. I would then just measure how long a key has been pressed. You can start counting how long the key has been down and stop counting once it is released. Then you can use that time to determine how far your object can travel.
How to count the time the key has been pressed:
float count = 0.0f;
void Update()
{
if(Input.GetKey("a"))
count += Time.deltaTime;
else if(Input.GetKeyUp("a"))
count = 0.0f;
}
Code resets count back to 0 once you release the key.
I am working with core audio using an AUFilePlayer to load a few mp3s into a mixer unit, everything plays great however I am unable to pause the music or rewind the music back to the start. I tried Starting and stopping the AudioGraph, but once the playback is stopped, I can't get it to restart. I also tried using AudioUnitSetProperty to set the file playback to 0
i.e something along these lines:
ScheduledAudioFileRegion rgn;
memset (&rgn.mTimeStamp, 0, sizeof(rgn.mTimeStamp));
rgn.mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
rgn.mTimeStamp.mSampleTime = 0;
rgn.mCompletionProc = NULL;
rgn.mCompletionProcUserData = NULL;
rgn.mAudioFile = inputFile;
rgn.mLoopCount = 1;
rgn.mStartFrame = 0;
rgn.mFramesToPlay = nPackets * inputFormat.mFramesPerPacket;
AudioUnitSetProperty(fileUnit, kAudioUnitProperty_ScheduledFileRegion,
kAudioUnitScope_Global, 0,&rgn, sizeof(rgn));
Any suggestions?
In case anyone else is dealing with a similar issue, which cost me several hours searching on google, here's what I've discovered on how to specifically retrieve and set the playhead.
To get the playhead from an AUFilePlayer unit:
AudioTimeStamp timestamp;
UInt32 size = sizeof(timestamp);
err = AudioUnitGetProperty(unit, kAudioUnitProperty_CurrentPlayTime, kAudioUnitScope_Global, 0, ×tamp, &size);
The timestamp.mSampleTime is the current playhead for that file. Cast mSampleTime to a float or a double and divide by the file's sample rate to convert to seconds.
For restarting the AUFilePlayer's playhead, I had a more complex scenario where multiple AUFilePlayers pass through a mixer and can be scheduled at different times, multiple times, and with varying loop counts. This is a real-world scenario, and getting them all to restart at the correct time took a little bit of code.
There are four scenarios for each AUFilePlayer and it's schedule:
The playhead is at the beginning, so can be scheduled normally.
The playhead is past the item's duration, and doesn't need to be scheduled at all.
The playhead is before the item has started, so the start time can be moved up.
The playhead is in the middle of playing an item, so the region playing within the file needs to be adjusted, and remaining loops need to be scheduled separately (so they play in full).
Here is some code which demonstrates this (some external structures are from my own code and not Core Audio, but the mechanism should be clear):
// Add each region
for(int iItem = 0; iItem < schedule.items.count; iItem++) {
AEFileScheduleItem *scheduleItem = [schedule.items objectAtIndex:iItem];
// Setup the region
ScheduledAudioFileRegion region;
[file setRegion:®ion schedule:scheduleItem];
// Compute where we are at in it
float playheadTime = schedule.playhead / file.sampleRate;
float endOfItem = scheduleItem.startTime + (file.duration*(1+scheduleItem.loopCount));
// There are four scenarios:
// 1. The playhead is -1
// In this case, we're all done
if(schedule.playhead == -1) {
}
// 2. The playhead is past the item start time and duration*loopCount
// In this case, just ignore it and move on
else if(playheadTime > endOfItem) {
continue;
}
// 3. The playhead is less than or equal to the start time
// In this case, simply subtract the playhead from the start time
else if(playheadTime <= scheduleItem.startTime) {
region.mTimeStamp.mSampleTime -= schedule.playhead;
}
// 4. The playhead is in the middle of the file duration*loopCount
// In this case, set the start time to zero, adjust the loopCount
// startFrame and framesToPlay
else {
// First remove the start time
region.mStartFrame = 0;
double offsetTime = playheadTime - scheduleItem.startTime;
// Next, take out any expired loops
int loopsExpired = floor(offsetTime/file.duration);
int fullLoops = region.mLoopCount - loopsExpired;
region.mLoopCount = 0;
offsetTime -= (loopsExpired * file.duration);
// Then, adjust this segment of a loop accordingly
region.mStartFrame = offsetTime * file.sampleRate;
region.mFramesToPlay = region.mFramesToPlay - region.mStartFrame;
// Finally, schedule any remaining loops separately
if(fullLoops > 0) {
ScheduledAudioFileRegion loops;
[file setRegion:&loops schedule:scheduleItem];
loops.mStartFrame = region.mFramesToPlay;
loops.mLoopCount = fullLoops-1;
if(![super.errors check:AudioUnitSetProperty(unit, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0, ®ion, sizeof(region))
location:#"AudioUnitSetProperty(ScheduledFileRegion)"])
return false;
}
}
// Set the region
if(![super.errors check:AudioUnitSetProperty(unit, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0, ®ion, sizeof(region))
location:#"AudioUnitSetProperty(ScheduledFileRegion)"])
return false;
}
I figured it out. In case any of you ever run into the same problem, here was my solution:
On startup, I initialize the AUGraph with an array of file player audio units. I set the play head of each track in the file player audio unit array to zero.
On “pause” , first I stop the AuGraph. Then I loop through the array of file player audio units and capture the current playhead position. Each time the pause button is pressed, I make sure I add the new current playhead position to the old playhead position to get its true position.
When the user hits play, I re initialize the AuGraph just as if I was starting the app for the very first time, only I set the playhead to the number I stored when the user hit “pause” instead of telling it to play at the start of the file.
If the user clicks stop, I set the stored playhead position to zero and then stop the AuGraph.
I have this game where i need to know if the ball has hit a wall on the side (to bounce back on the x-axis) or on the top (to bounce back on the y-axis, like a bounce on the ground). They work fine individually, but when I uncomment both of them, it dosen't work. (I think this is because the code is 'overlapping'?). Anyway, here is the code, and any help is fantastic:
if (CGRectIntersectsRect(guy.frame, wall_01.frame)) {
if (guy.frame.origin.y+guy.frame.size.height >= wall_01.frame.origin.y && guy.frame.origin.y <= wall_01.frame.origin.y+wall_01.frame.size.height) {
iJump *= kRestitution;
}
if (guy.frame.origin.x+guy.frame.size.width >= wall_01.frame.origin.x && guy.frame.origin.x <= wall_01.frame.origin.x+wall_01.frame.size.width) {
jJump *= kRestitution;
}
}
assuming wall is on the left side and the y increases from top to bottom
CGFloat leftWall = someXPosition;
CGFloat ground = someYPosition;
CGFloat ballLeft = CGRectGetMinX(guy.frame);
CGFloat ballRight = CGRectGetMaxX(guy.frame);
CGFloat ballBottom = CGRectGetMaxY(guy.frame);
if (ballLeft <= leftwall && ballBot >= ground){
//ball hit corner ?
} else if (ballLeft <= leftWall){
//passed or touched wall
} else if (ballBot >= ground){
//passed or touched ground
}
I am trying to run a "Walk" style animation on my main game sprite. The animations work fine, and my sprite is hooked up to my joystick all fine and dandy.
However, I think where I setup the call for my walk animations are wrong. Because everytime the sprite is moving, the animation stops.
I know putting the animation in such a weak if statement is probably bad, but please tell me how I could get my sprite to animate properly while it is being moved by the joystick.
The sprite faces the right direction, so I can tell the action's first frame is being called, however, it doesn't animate until I stop touching my joystick.
Here is How I call the action:
//WALK LEFT
if (joypadCap.position.x <= 69 /*&& joypadCap.position.y < && joypadCap.position.y > >40 */ )
{
[tjSprite runAction:walkLeft];
};
//WALK RIGHT
if ( joypadCap.position.x >= 71 /* && joypadCap.position.y < 100 && >joypadCap.position.y > 40 */)
{
[tjSprite runAction:walkRight];
};
THIS: is the how the joystick controls the character:
CGPoint newLocation = ccp(tjSprite.position.x - distance/8 * cosf(touchAngle),
tjSprite.position.y - distance/8 * sinf(touchAngle));
tjSprite.position = newLocation;
Please help. Any alternative ways to call the characters walk animation would be greatly appreciated!
int current_state;
if (current_state != 1 && joypadCap.position.x <= 69)
{
current_state = 1;
[tjSprite runAction:walkLeft];
}
else if (current_state != 1 && joypadCap.position.x >= 71)
{
current_state = 1;
[tjSprite runAction:walkRight];
}
else
{
current_state = 0;
//[tjSprite stopAllActions];
};
The sprite faces the right direction,
so I can tell the action's first frame
is being called, however, it doesn't
animate until I stop touching my
joystick.
Based on the code you have supplied this actually makes sense. What your if statement is saying is anytime the joypadCap position is greater than 71 or less than 69 play an animation. This means your animations will try to play over and over again from the beginning everytime joypadCap's position falls in these ranges. I assume joypadCap is a measure of how much the joystick is being pressed?
Looks like you could use some additional state logic to determine what your character should be doing. Here is some pseudocode...
state current_state;
if (current_state != walking and joypadCap.position.x <= 69)
{
current_state = walking;
[tjSprite runAction:walkLeft];
}
else if (current_state != walking and joypadCap.position.x >= 71)
{
current_state = walking;
[tjSprite runAction:walkRight];
}
else
{
current_state = idle;
[tjSprite stopAllActions];
}
Keep in mind that is loose pseudocode. Not everything is syntactically correct but logically the idea is that you have a state variable to keep track of the characters current state which allows you so have your animations play one time only. Let me know if this helps and if you have any questions about my answer.