I am trying to make a UIImageView move when I tap a button. I have set a UIIAction to start an NSTimer. When tap the button, the character(UIImageView) moves fine. When I tap the same button again, the character speeds up and so forth so eventually he is moving a billion mph. How do I solve this? Here is the code:
-(void)animateCharRight:(NSTimer *)theTimer
{
float speed;
if (speed > 10.0f)
{
speed = 10.0f;
}
else
{
speed = 10.0f;
}
CGRect rect = [character frame];
rect.origin.x += speed;
[character setFrame:rect];
}
Also, when you press the opposite button after you already pressed one it bugs up because there is no cancelation of the other timer. How do I do that?
How do I access the key up event? I cant seem to find it.
Sounds like you might be starting a new timer on each button tap. So after 2 taps you now have 2 timers, each of which will call -animateCharRight: to move your view 10, for a total of 20. More taps, faster, and so on. Is that what's going on?
Well you declare speed in your method and do not set it to anything. So it is always going to the else setting the speed to 10.0f. Because in both your if and else you are setting it to 10, so what is the point of the if statement?
Then you rect.origin.x += speed; or add 10 the origin all the time, no exceptions. It is the same as doing rect.origin.x += 10; The image will constantly move.
The speed is always going to be 10, and always add to the rect.origin.x do you want to make speed a instance variable rather than just in the method?
EDIT
Because speed is declared in the method each time it has 0 as a value. Then it is set to 10. If you create speed as a member variable, then each time animateCharRight is called you can do something like
speed += speedIncrementAmount;
or
speed += 1.0f;
Meaning each time the speed is increased by 1 unit or what you need for your game.
Then the you would need a couple of checks depending on your logic.
if (speed > 10.0f)
{
// This will clamp the speed at 10.0f;
speed = 10.0f;
}
if (speed < - 10.0f)
{
// This will make sure you will never go left to quickly
speed = - 10.0f;
}
The above if statements may work or might not. Depends on the use. If the game is a side scooler and you only want to move to the right then you might want to make sure the speed is never less than 0.
Think about the design you want.
Since you are new to game programming I would start with a Tutorial and build upon the skills learned in the tutorial. Here is a link to one I found in a quick Google search.
Remember nobody makes Doom as there first game. Everybody starts with a Brick Breaker rip off or Tetris, it is the 'Hello World' of game programming.
I think you problem is that you are not setting the speed back to zero when you release the key to move. You should either reset as soon as the keyup event fires or if you'd like the character to keep moving for a little while after you release the key you can set the speed to zero after the time has expired with a timer.
That method will always move your character by 10. However, it seems that you are starting a new timer every time the button is pressed. So if you press the button 3 times, the character moves 3x10=30. You need to cancel the existing timer so there is always only one running.
You can cancel an NSTimer instance using [timer invalidate]. (See here)
Related
I have been programming a deeper version of Pong using skills.
One of the skills is that the player will make the other player's paddle stop, and instead the enemy will start moving its goal.
I start moving the goal with this method. The method is called in the FixedUpdate.
private void moveGoal(string vertical, Vector3 nextPosition)
{
nextPosition += speed * Time.fixedDeltaTime * Input.GetAxis(vertical) * Vector3.up;
nextPosition.y = Mathf.Clamp(nextPosition.y, goalMinY, goalMaxY);
rb.transform.position = nextPosition;
}
We have tried doing it in the Update and using the Time.deltaTime, but the result is the same.
We recently changed to "rb.transform.position" from "rb.MovePosition(nextPosition)" because the problem was way worse.
The position is reset with a method inside the skill's script where we have saved the base position of the goal, and once the skill gets deactivated it automatically reset the goal's position to its base position.
The problem is that if the goal starts in the Y position 1.4, after it has been reset the y position changes slightly, for example going from 1.4 to 1.25.
We do not understand why it is moving even though the position we set it to is always the same.
I am sorry if the post sounds confusing, but the problem itself is very confusing and very difficult to explain.
Sorry if I am misunderstanding your issue. Could it be that you reset the position of the goal but within the same frame it executes moveGoal() once, setting it slightly off your original position? Goodluck.
So, I'm trying to make my own movement script for Unity with a Rigidbody component attached to my character, and I'm using this code inside of the update function:
// Up above, in public scope, before Start and Update functions
public float speed = 1f;
public Rigidbody body;
void Update() {
if (Input.GetKey(KeyCode.LeftArrow())) { // Left arrow key
body.AddForce(transform.forward * speed * Time.deltaTime);
}
}
My problem is, since it's inside of the Update() function, it keeps going, it keeps turning, even if I don't have the key pressed.
Does anyone know how to fix this problem? I have tried taking away Time.deltaTime but Brackeys said you use it so that it's frame rate dependent, so if you have a higher frame rate it doesn't turn faster, and same with a low frame rate, you turn slower. Thanks in advance.
It keeps turning even after releasing the key? Yep that's what AddForce will do.
After you apply a force to an object it will continue to move based on that force uless it has drag or an opposing force is applied. Go into the rigidbody to set the drag or create a script that applies an opposing force once you stop pressing the button.
If you put a Debug.Log within the if statement you will see it is not called every frame but only when you have the button held down.
And last, I don't think that your keycode should have () after LeftArrow, does this not produce an error?
An object in motion stays in motion with the same speed and in the
same direction unless acted upon by an unbalanced force.
---- Isaac Newton
So if you want to stop the object, you can do:
Add an oppsite force
if (Input.GetKey(KeyCode.LeftArrow())) {
...
} else if (!body.IsSleeping()) {
body.AddForce(-body.velocity * factor);
}
Give a drag value
body.drag = dragValue;
You have two questions, one on the title and another one on the description.
For the title one:
The only way to stop/break Update() cycle is to disable the script, like this:
enabled = false;
For the description one:
You have to stop the force applied to the object (as the rest of the answers exemplify).
You can apply an opposite force, or just set velocity to 0.
rigidbody.velocity = Vector3.zero;
I am using SpriteKit, and my sprite is slowing as it approaches the touched point.
I would like the sprite to remain at a fixed speed as it moved from initial point to the touched point on the screen.
Currently, i have the duration set to 3.0
In the touchesEnded event, i gather the new point of the touch and save the value to a property.
In the scene update event, i perform a
float realMoveDuration = 3.0;
SKAction *actionMove = [SKAction moveTo:self.newPoint duration:realMoveDuration];
[self.player runAction:[SKAction sequence:#[actionMove]]];
So when the player sprite starts getting closer to the touch point, the movement slows down, and gradually reaches the touch point.
This is not the action I am looking for, i would like the player sprite to continue at a constant rate of travel to the touched point.
You should just run your SKAction in the touchesEnded event.
If you have that code in the update event, it's starting a new SKAction 60 times per second. You only ever need to run a new SKAction when there is a change in destination.
If there is a change in destination before you reach the original destination, you should remove the action from that node and then add a new one.
Also, not certain about the specifics of what you are doing, but how quickly an object moves is based on the distance and the time you have specified for it to get there. So if you want a node to move at a consistent speed, regardless of distance, you need to make a calculation to determine the right duration to set for your SKAction.
For example if speed represents pixels/units per second you might do this to calculate your duration :
duration = distance / speed;
If you are using an SKAction to move the sprite, use the timingMode property. The default is SKActionTimingLinear. So if you haven't changed it, the node should move at a constant speed.
Here's a link to the available Action Timing Modes.
i'm writing here cause i really need your help. i've created this script linked on a gameObject light (Directional).
var time : int= 0;
function Update () {
time+=1;
transform.Rotate(time*Time.deltaTime, 0 ,0);
yield WaitForSeconds(0.2);
if (time == 360){
time = 0;
}
}
when i start the game, the object don't rotate and if i remove the line:
yield WaitForSeconds(0.2);
the rotation starts slowly then increses its speed until (every 2 rounds) it returns to 0.
Jerdak is right. Update() is called every frame, and not every second. That way, time reaches 360 very fast. In order to get the elapsed time since last call to Update, use Time.deltaTime. Which basically means when you do transform.Rotate(Time.deltaTime * speed, 0, 0);, it'll rotate according to your speed. So use a speed measure rather than a time measure.
the rotation starts slowly then increses its speed until (every 2
rounds) it returns to 0.
This is expected behaviour. Like I said, you used time instead of speed. You increase the speed (named: time) every 0.2 seconds, thus increasing the rotation speed.
when i start the game, the object don't rotate
I am unsure why this happens but when you wait long enough, you'll see the rotation occuring anyway. It might be happening but very slowly.
I am developing a cocos2d based app with a space background in which I am exploiting a CCQuadParticleSystem to make blinking stars. I have generated this particle system with ParticleDesigner. As soon as I load the particle system white dots representing stars start appearing in the background and after a while they fade out so that, after few seconds in which the particle system reaches the regime state, a night sky full of stars comes out.
My problem is that I would like to know if there is a way to make the particle system starting from a specific time in the future (for instance t0 = 3sec) so that I do not have to wait to have all the starts blinking.
I hope I have clearly explained the problem
thank you in advance
Andrea
I did this and it worked exactly the way I wanted it to.
for (int i = 0 ; i < 300 ; i++)
[emitter update:.1];
Have you tried a
id actions = [CCSequence actions:[CCDelayTime actionWithDuration:3.0f],
[CCCallFunc actionWithTarget:self selector:#selector(onStallComplete)],
nil];
[self runAction:actions];
ok, granted it is probably abusing the original intent of the API's , but is useful
watch for re-entrancy in onStallComplete if you have multiple such delayed reactions.
note: newbie at SO, hope the code snippet comes out looking right
I assume you are using some kind of updateWithDelta: method in your game loop in order to update the particles. If you want the particles to start after a certain interval, make your own timer.
Edit: Based on your comment below, my method is still good, it just needs some tweaking. You need only remove the condition in the updateWithDelta: method on the particle system. That way, it will still update for those 3 seconds, but will not render, and therefore look the way you are describing.
In the .h file:
BOOL particleShouldUpdate;
float particleTimer;
In your init method:
particleShouldRender = NO;
particleTimer = 3.0f;
In your updateWithDelta: method:
if(!particleShouldRender){
particleTimer -= delta;
if(particleTimer < 0){
particleShouldRender = YES;
}
}
// update your particle.
Finally, in your render method:
if(particleShouldRender){
// render your particle.
}
Note that from this point, if you want to stop it rendering, you need only reset the 2 variables like as in the init method, and the same effect will occur.
EDIT2: Upon further clarification, we only need to adapt the init method of your particle. I will make 2 assumptions here, and you need only change them slightly to fit your needs. Suppose that your update cycle is 60 frames per second, the minimum particle lifespan is 1.01, and that you want 3 seconds of updates before you start the game. Then in the init method, try:
for(float delta = 0.0f; delta < 3.0f; delta += (1/60)){
[particle updateWithDelta:(float)(1/60)];
}
This will update your particle like it normally would, but without rendering at each interval, and before anything else gets updated. Alternatively, if you are worried about speed when updating your particle, you can try:
for(int i = 0; i < 3; i++){
[particle updateWithDelta:1];
[particle updateWithDelta:0.02];
}
This will be faster, but may have a few issues depending on your particles parameters.
EDIT3: So looking into this further, cocos2D does not let you do this for some reason. I found a similar question online to this, and they suggested you play with the posVar and speed to make them large enough while you are transitioning into the scene, and once you have fully transitioned into the scene, reset the values to normal. You may want to give that a try!
Hope that Helps!
I do not think there is a way to fast forward your particle system 3 seconds into the future. Alternatively I can imagine two different solutions depending on your circumstances:
Load the scene with the particle behind another scene (e.g. an empty black scene). After 3 seconds switch to the scene with the now nice looking particle effect. This could work f it is ok for you that the user needs to wait for 3 seconds and you only do not want them to see the particle system while everything is clunked together or if you have another scene before the scene with the particle system anyway.
Record the particle system, store it in a file then replay it in your scene. With recording I mean store the position and color of each of your particles. The drawback is, that it will look the same everytime and if you want to run it longer than what you recorded you need to make sure replaying it in a loop still looks good.
I can't think of a way to implement this directly, but could you try something like this as a workaround? I'm afraid I haven't been able to test this yet due to other errors, but working on it.
{
...
//This attempts to make 3 seconds pass 100 times quicker
[[CCScheduler sharedScheduler] setTimeScale:100];
[self schedule:#selector(cancelIncreasedTimeScale) interval:3];
...
}
int numberOfTimesCancelled = 0;
-(void) cancelIncreasedTimeScale
{
numberOfTimesCancelled ++;
//Two because the scheduler is also called straight away? Remove if it's only called after waiting an initial (3/100) seconds
if (numberOfTimesCancelled == 2) {
[self unschedule:#selector(cancelIncreasedTimeScale)];
[[CCScheduler sharedScheduler] setTimeScale:1];
}
}
The issue I do worry about is the other items on your scene would also run 100 times faster. Is that an issue?