• What Do You Need Help With? V6
    7,544 replies, posted
Set X/Y accelerations separately on Left, Right/Up, Down button presses. [editline]1st November 2014[/editline] I should throw something together, a moment please.
[QUOTE=cartman300;46385417]Set X/Y accelerations separately on Left, Right/Up, Down button presses.[/QUOTE] That seems like it would fix it, but how would I implement that? Here's my code: [code] @Override public void update(float dt) { vx += (targetX - vx) * dt; vy += (targetY - vy) * dt; x += vx * dt; y += vy * dt; targetX *= 0.95; targetY *= 0.95; // other stuff... } public static void moveUp() { targetY = -moveSpeed; } public static void moveDown() { targetY = moveSpeed; } public static void moveLeft() { targetX = -moveSpeed; } public static void moveRight() { targetX = moveSpeed; }[/code] [editline]1st November 2014[/editline] moveSpeed is 150.
I've got this in one of my projects, it moves the view but in theory it should be the same for object movement. [code] // Runs every frame float SpeedX = 0; float SpeedY = 0; float Speed = 200; if (W) SpeedY -= Speed; if (S) SpeedY += Speed; if (A) SpeedX -= Speed; if (D) SpeedX += Speed; View.Move(new Vector2f(SpeedX * FrameTime, SpeedY * FrameTime)); [/code] View.Move would basically be this [code] void Move(Vector2f DeltaPos) { this.Position.X += DeltaPos.X; this.Position.Y += DeltaPos.Y; } [/code]
Eww, that way your character moves faster when you go diagonal. Do this [code] Vector2 direction; if (W) direction.y -= 1; if (S) direction.y += 1; if (A) direction.x -= 1; if (D) direction.x += 1; Vector2 movement = normalize(direction) * movementspeed; playerPosition += movement; [/code]
Unless you want it to move in the direction the character is facing when you accelerate, then you would do [code] ActualAccelX = cos(Angle) * AccelX; ActualAccelY = sin(Angle) * AccelY; [/code]
I don't know how to apply that to my current setup. [editline]1st November 2014[/editline] How would I do that with what I have now? Should I just remove the lerp process? [code]@Override public void update(float dt) { vx += (targetX - vx) * dt; vy += (targetY - vy) * dt; x += vx * dt; y += vy * dt; // more stuff... } public static void moveUp() { targetY = -moveSpeed; } public static void moveDown() { targetY = moveSpeed; } public static void moveLeft() { targetX = -moveSpeed; } public static void moveRight() { targetX = moveSpeed; }[/code]
[QUOTE=NixNax123;46385496]I don't know how to apply that to my current setup. [editline]1st November 2014[/editline] How would I do that with what I have now? Should I just remove the lerp process? [code]@Override public void update(float dt) { vx += (targetX - vx) * dt; vy += (targetY - vy) * dt; x += vx * dt; y += vy * dt; // more stuff... } public static void moveUp() { targetY = -moveSpeed; } public static void moveDown() { targetY = moveSpeed; } public static void moveLeft() { targetX = -moveSpeed; } public static void moveRight() { targetX = moveSpeed; }[/code][/QUOTE] Firstly, you really need to set up a vec2d class. Working with X and Y values separately is just... ew. But anyways, try this code. I've commented it explained what each part does. [code]@Override public void update(float dt) { // First, let's just copy our targets values, so we can do some maths on them. desiredX = targetX; desiredY = targetY; // Now find the true velocity by getting the length of the vector using simple trigonometry. This is just Pythagora's theorem, with desiredX and desiredY instead of a and b! length = sqrt((desiredX * desiredX) + (desiredY * desiredY)); // Normalize the vector - that is, set it's length to 1. You do this by dividing each component of the vector by it's length - be careful to make sure you don't divide by 0! if (length > 0) { desiredX /= length; desiredY /= length; } // Now set the vectors length to your desired velocity. Because the vector is normalized (a length of 1), you can just multiply by it! desiredX *= moveSpeed; desiredY *= moveSpeed; // Now do your other stuff... vx += (desiredX - vx) * dt; vy += (desiredY - vy) * dt; x += vx * dt; y += vy * dt; // more stuff... } public static void moveUp() { targetY = 1; } public static void moveDown() { targetY = -1; } public static void moveLeft() { targetX = 1; } public static void moveRight() { targetX = -1; }[/code] I would note that your velocities constantly increase if you don't clamp your velocity values. You may want to fix that.
That doesn't work, the sprite just flies off screen.
[QUOTE=NixNax123;46386965]That doesn't work, the sprite just flies off screen.[/QUOTE] That's probably because of that end weird code. Try replacing this: [CODE] vx += (desiredX - vx) * dt; vy += (desiredY - vy) * dt; x += vx * dt; y += vy * dt;[/CODE] With this: [CODE] x += desiredX * dt; y += desiredY * dt;[/CODE] It'll make the velocity sharply increase unnaturally, but we can fix that later - I think your above code is a incorrectly used linear interpolation, which doesn't make much sense here.
[code] public void update(float dt){ targetX = (isKeyPressed(Key.A) ? -1 : 0) + (isKeyPressed(Key.D) ? 1 : 0); targetY = (isKeyPressed(Key.S) ? -1 : 0) + (isKeyPressed(Key.W) ? 1 : 0); vx += (targetX - vx) * dt * 10; vy += (targetY - vy) * dt * 10; float length = sqrt(vx*vx + vy*vy); if(length){ vx /= length; vy /= length; } x += vx * dt * 10; y += vy * dt * 10; }[/code] by the way this is not linear interpolation
Ah yeah, the issue is that the controls were doing += instead of =. Replace it with the fixed code I just edited into the post and it'd work. Welt: what's with the magical numbers? That's not something good to be teaching! And yes, it's not linear interpolation. I just imagined it was a broken implementation of it, misusing and/or misunderstanding dt.
[QUOTE=Tommyx50;46387367]Welt: what's with the magical numbers? That's not something good to be teaching! And yes, it's not linear interpolation. I just imagined it was a broken implementation of it, misusing and/or misunderstanding dt.[/QUOTE] The first pair of tens controls how fast the target is approached, the second the end velocity. I call it 'smooth approach' :v:
Still flying off the screen. [code] public void update(float dt) { float desiredX = targetX; float desiredY = targetY; // Now find true velocity by getting the length of the vector using simple trigonometry. This is just Pythagora's theorem, with desiredX and desiredY instead of a and b! double length = Math.sqrt((desiredX * desiredX) + (desiredY * desiredY)); // Normalize the vector - that is, set it's length to 1. You do this by dividing each component of the vector by it's length - be careful to make sure you don't divide by 0! desiredX /= length; desiredY /= length; // Now set the vectors length to your desired velocity. Because the vector is normalized (a length of 1), you can just multiply by it! desiredX *= moveSpeed; desiredY *= moveSpeed; // Now do your other stuff... //vx += (desiredX - vx) * dt; //vy += (desiredY - vy) * dt; x += desiredX * dt; y += desiredY * dt; // go from one side of the map to another if (x > Window.getWidth()) { x = 0; } else if (x < 0) { x = Window.getWidth(); } if (y > Window.getHeight()) { y = 0; } else if (y < 0) { y = Window.getHeight(); } playerSprite.setPosition(x, y); // set player angle based on mouse position angle = Math.atan2( Input.getMousePos().y - playerSprite.getPosition().y, Input.getMousePos().x - playerSprite.getPosition().x); angle *= (180/Math.PI); if(angle < 0) { angle = 360 + angle; } playerSprite.setRotation(90 + (float)angle); } public static void moveUp() { targetY = -1; } public static void moveDown() { targetY = 1; } public static void moveLeft() { targetX = -1; } public static void moveRight() { targetX = 1; }[/code]
[QUOTE=NixNax123;46387414]Still flying off the screen. [code] public void update(float dt) { float desiredX = targetX; float desiredY = targetY; // Now find true velocity by getting the length of the vector using simple trigonometry. This is just Pythagora's theorem, with desiredX and desiredY instead of a and b! double length = Math.sqrt((desiredX * desiredX) + (desiredY * desiredY)); // Normalize the vector - that is, set it's length to 1. You do this by dividing each component of the vector by it's length - be careful to make sure you don't divide by 0! desiredX /= length; desiredY /= length; // Now set the vectors length to your desired velocity. Because the vector is normalized (a length of 1), you can just multiply by it! desiredX *= moveSpeed; desiredY *= moveSpeed; // Now do your other stuff... //vx += (desiredX - vx) * dt; //vy += (desiredY - vy) * dt; x += desiredX * dt; y += desiredY * dt; // go from one side of the map to another if (x > Window.getWidth()) { x = 0; } else if (x < 0) { x = Window.getWidth(); } if (y > Window.getHeight()) { y = 0; } else if (y < 0) { y = Window.getHeight(); } playerSprite.setPosition(x, y); // set player angle based on mouse position angle = Math.atan2( Input.getMousePos().y - playerSprite.getPosition().y, Input.getMousePos().x - playerSprite.getPosition().x); angle *= (180/Math.PI); if(angle < 0) { angle = 360 + angle; } playerSprite.setRotation(90 + (float)angle); } public static void moveUp() { targetY = -1; } public static void moveDown() { targetY = 1; } public static void moveLeft() { targetX = -1; } public static void moveRight() { targetX = 1; }[/code][/QUOTE] Might sound stupid, but have you tried decreasing the moveSpeed variable? It might be too high.
Even when I set it to 1 it still flies off. Why can't I solve such a simple problem? I feel so dumb.
[QUOTE=NixNax123;46387485]Even when I set it to 1 it still flies off. Why can't I solve such a simple problem? I feel so dumb.[/QUOTE] Happens to all programmers; feeling dumb is part of the job! I notice that you aren't checking if length > 0 at the start. The reason it may fly off is because doing dividing anything by 0 sets the velocities to infinity, meaning it disappears in practically a single frame.
[QUOTE=NixNax123;46387485]Even when I set it to 1 it still flies off. Why can't I solve such a simple problem? I feel so dumb.[/QUOTE] Don't beat yourself up over stuff like this, I just spent half an hour trying to figure out why my color conversion from an integer value to 3 separate values didn't work, ended up being something completely retarded. [code] float red = (color && REDMASK >> 16); float green = (color && GREENMASK >> 8); float blue = (color && BLUEMASK); [/code] It was because && is not a bitwise operator but a comparison... It should be [code] float red = (color & REDMASK >> 16); float green = (color & GREENMASK >> 8); float blue = (color & BLUEMASK); [/code]
Now it doesn't fly off, but it also never stops moving. My closest attempt was by multiplying targetX and targetY by 0.95 each update(), but that only let me move in cardinal directions +/- a few degrees, and made the movement really slow at some points for some reason. UGH I JUST WANT DIRECTIONAL MOVEMENT.
[QUOTE=NixNax123;46387552]Now it doesn't fly off, but it also never stops moving. My closest attempt was by multiplying targetX and targetY by 0.95 each update(), but that only let me move in cardinal directions +/- a few degrees, and made the movement really slow at some points for some reason. UGH I JUST WANT DIRECTIONAL MOVEMENT.[/QUOTE] You still don't handle key releases, try my first two lines and remove the four input handlers.
[QUOTE=NixNax123;46387552]Now it doesn't fly off, but it also never stops moving. My closest attempt was by multiplying targetX and targetY by 0.95 each update(), but that only let me move in cardinal directions +/- a few degrees, and made the movement really slow at some points for some reason. UGH I JUST WANT DIRECTIONAL MOVEMENT.[/QUOTE] Calm down. You can get really annoyed, especially when learning programming, but getting annoyed causes a lot of mental fatigue which is something really, really bad when programming. Here's the issue, I suspect - you are setting the targetX and targetY whenever you press a button, but not resetting it (meaning you keep moving even with your finger off the button). THe easiest way is just to put: [CODE] targetX = 0; targetY = 0;[/CODE] at the end of your update() function.
[QUOTE=Tommyx50;46387568]Calm down. You can get really annoyed, especially when learning programming, but getting annoyed causes a lot of mental fatigue which is something really, really bad when programming. Here's the issue, I suspect - you are setting the targetX and targetY whenever you press a button, but not resetting it (meaning you keep moving even with your finger off the button). THe easiest way is just to put: [CODE] targetX = 0; targetY = 0;[/CODE] at the end of your update() function.[/QUOTE] That still doesn't work. It just makes it move slower, it still stops, but it's very slow to get moving (and still goes slow) and also can't move in non-cardinal directions.
[QUOTE=NixNax123;46387605]That still doesn't work. It just makes it move slower, it still stops, but it's very slow to get moving (and still goes slow) and also can't move in non-cardinal directions.[/QUOTE] Are the vx and xy lines commented out? Also, have you re-increased moveSpeed, after setting it to 1? You should in theory be able to move in 8 directions.
How does separate compilation work in C? My books doesn't use a specific compiler and I can't find any examples online to try. if I make a file called separate1.c which has: [code] #include <stdio.h> int main(){ a = 22; printf("%d",a); } [/code] and another one called separate2.c which simply says: [code] extern int a; [/code] I can compile separate2 into separate2.o, but when I try to link it with [code] gcc -o separate separate1.c separate2.o [/code] i get [code] collin@collin-HP-15-Notebook-PC:~/Documents/C Stuff$ gcc -o separate separate1.c separate2.o separate1.c: In function ‘main’: separate1.c:5:3: error: ‘a’ undeclared (first use in this function) a=2; ^ separate1.c:5:3: note: each undeclared identifier is reported only once for each function it appears in collin@collin-HP-15-Notebook-PC:~/Documents/C Stuff$ [/code]
[QUOTE=Tommyx50;46387633]Are the vx and xy lines commented out? Also, have you re-increased moveSpeed, after setting it to 1? You should in theory be able to move in 8 directions.[/QUOTE] With this code:[code] vx += (targetX - vx) * dt; vy += (targetY - vy) * dt; x += vx * dt; y += vy * dt; // go from one side of the map to another if (x > Window.getWidth()) { x = 0; } else if (x < 0) { x = Window.getWidth(); } if (y > Window.getHeight()) { y = 0; } else if (y < 0) { y = Window.getHeight(); } playerSprite.setPosition(x, y); // set player angle based on mouse position angle = Math.atan2( Input.getMousePos().y - playerSprite.getPosition().y, Input.getMousePos().x - playerSprite.getPosition().x); angle *= (180/Math.PI); if(angle < 0) { angle = 360 + angle; } playerSprite.setRotation(90 + (float)angle); } public static void moveUp() { targetY = -moveSpeed; } public static void moveDown() { targetY = moveSpeed; } public static void moveLeft() { targetX = -moveSpeed; } public static void moveRight() { targetX = moveSpeed; }[/code] I achieve this: [vid]http://a.pomf.se/hbzhun.webm[/vid] It controls perfectly. As you can see near the end of the video, the player keeps moving and never stops. I love this movement and this is the ONLY bug with it. If I fix that, the movement is perfect. [editline]1st November 2014[/editline] That happens when a key is pressed but nothing else after that. The player just keeps moving in that direction.
[QUOTE=proboardslol;46387646]How does separate compilation work in C? My books doesn't use a specific compiler and I can't find any examples online to try. if I make a file called separate1.c which has: [code] #include <stdio.h> int main(){ a = 22; printf("%d",a); } [/code] and another one called separate2.c which simply says: [code] extern int a; [/code] I can compile separate2 into separate2.o, but when I try to link it with [code] gcc -o separate separate1.c separate2.o [/code] i get [code] collin@collin-HP-15-Notebook-PC:~/Documents/C Stuff$ gcc -o separate separate1.c separate2.o separate1.c: In function ‘main’: separate1.c:5:3: error: ‘a’ undeclared (first use in this function) a=2; ^ separate1.c:5:3: note: each undeclared identifier is reported only once for each function it appears in collin@collin-HP-15-Notebook-PC:~/Documents/C Stuff$ [/code][/QUOTE] I think you are using extern wrong. Try changing the files to this: [code] #include <stdio.h> extern int a; int main(){ a = 22; printf("%d",a); } [/code] [code] int a; [/code] Before, what you were doing was declaring the variable in one file (but not defining it), meaning that it both couldn't be seen by the file with main() and the memory was never actually allocated for it. In the code I show, I use extern to declare the int a (meaning the compiler creates the variable "token", but doesn't allocate any memory) and then actually defining (and thus having the memory allocated) in the second file. [editline]2nd November 2014[/editline] [QUOTE=NixNax123;46387755]With this code:[code] vx += (targetX - vx) * dt; vy += (targetY - vy) * dt; x += vx * dt; y += vy * dt; // go from one side of the map to another if (x > Window.getWidth()) { x = 0; } else if (x < 0) { x = Window.getWidth(); } if (y > Window.getHeight()) { y = 0; } else if (y < 0) { y = Window.getHeight(); } playerSprite.setPosition(x, y); // set player angle based on mouse position angle = Math.atan2( Input.getMousePos().y - playerSprite.getPosition().y, Input.getMousePos().x - playerSprite.getPosition().x); angle *= (180/Math.PI); if(angle < 0) { angle = 360 + angle; } playerSprite.setRotation(90 + (float)angle); } public static void moveUp() { targetY = -moveSpeed; } public static void moveDown() { targetY = moveSpeed; } public static void moveLeft() { targetX = -moveSpeed; } public static void moveRight() { targetX = moveSpeed; }[/code] I achieve this: It controls perfectly. As you can see near the end of the video, the player keeps moving and never stops. I love this movement and this is the ONLY bug with it. If I fix that, the movement is perfect. [editline]1st November 2014[/editline] That happens when a key is pressed but nothing else after that. The player just keeps moving in that direction.[/QUOTE] That code may give "almost" desired functionality, but it's broken in terms of the fact that there's nothing to slow it down. It doesn't matter if you are "almost" there if it's based on broken foundations. You need to build up slowly- I'll get to the smooth acceleration and deceleration afterwards. Have you gotten the code I showed before working? It'll give a sharp increase in velocity, but we can make it smooth afterwards (and allow you to tweak exactly how smooth it is easily).
[QUOTE=Tommyx50;46387779] I'll get to the smooth acceleration and deceleration afterwards. Have you gotten the code I showed before working? It'll give a sharp increase in velocity, but we can make it smooth afterwards (and allow you to tweak exactly how smooth it is easily).[/QUOTE] The code works, but it's choppy; here's a gif: [img]http://i.imgur.com/ZY65hjI.gif[/img] And here's the code: [code]public void update(float dt) { float desiredX = targetX; float desiredY = targetY; // Now find true velocity by getting the length of the vector using simple trigonometry. This is just Pythagora's theorem, with desiredX and desiredY instead of a and b! double length = Math.sqrt((desiredX * desiredX) + (desiredY * desiredY)); // Normalize the vector - that is, set it's length to 1. You do this by dividing each component of the vector by it's length - be careful to make sure you don't divide by 0! if (length > 0) { desiredX /= length; desiredY /= length; } // Now set the vectors length to your desired velocity. Because the vector is normalized (a length of 1), you can just multiply by it! desiredX *= moveSpeed; desiredY *= moveSpeed; // Now do your other stuff... x += desiredX * dt; y += desiredY * dt; targetX = 0; targetY = 0; // other stuff } public static void moveUp() { targetY = -1; } public static void moveDown() { targetY = 1; } public static void moveLeft() { targetX = -1; } public static void moveRight() { targetX = 1; }[/code] With moveSpeed set at 200.
[QUOTE=NixNax123;46388537]The code works, but it's choppy; here's a gif: [img]http://i.imgur.com/ZY65hjI.gif[/img] And here's the code: [code]public void update(float dt) { float desiredX = targetX; float desiredY = targetY; // Now find true velocity by getting the length of the vector using simple trigonometry. This is just Pythagora's theorem, with desiredX and desiredY instead of a and b! double length = Math.sqrt((desiredX * desiredX) + (desiredY * desiredY)); // Normalize the vector - that is, set it's length to 1. You do this by dividing each component of the vector by it's length - be careful to make sure you don't divide by 0! if (length > 0) { desiredX /= length; desiredY /= length; } // Now set the vectors length to your desired velocity. Because the vector is normalized (a length of 1), you can just multiply by it! desiredX *= moveSpeed; desiredY *= moveSpeed; // Now do your other stuff... x += desiredX * dt; y += desiredY * dt; targetX = 0; targetY = 0; // other stuff } public static void moveUp() { targetY = -1; } public static void moveDown() { targetY = 1; } public static void moveLeft() { targetX = -1; } public static void moveRight() { targetX = 1; }[/code] With moveSpeed set at 200.[/QUOTE] It's a little strange that it should be choppy (the movements should be very sharp and unnatural, but while moving already it should be smooth). Are you reading in the inputs every frame? Or is it smooth when holding a key down, but the video framerate makes it look a little choppy? Anyways, aside from that, it's time to get the smooth acceleration behaviour back in. How do we do that? Essentially, instead if directly setting the velocity when we press a key, instead it indirectly affects the velocity by going through an acceleration value. This gives us a lot of control - we can define how quickly the player can accelerate! Consider this code: [code]public void update(float dt) { float desiredX = targetX; float desiredY = targetY; // Now find true velocity by getting the length of the vector using simple trigonometry. This is just Pythagora's theorem, with desiredX and desiredY instead of a and b! double length = Math.sqrt((desiredX * desiredX) + (desiredY * desiredY)); // Normalize the vector - that is, set it's length to 1. You do this by dividing each component of the vector by it's length - be careful to make sure you don't divide by 0! if (length > 0) { desiredX /= length; desiredY /= length; } // Now set the vectors length to your desired velocity. Because the vector is normalized (a length of 1), you can just multiply by it! // Increasing the accelRate should make movements more sharp and dramatic desiredX *= accelRate; desiredY *= accelRate; // Now we set the acceleration to our input ax = desiredX; // a for acceleration ay = desiredY; // Now lets do the euler integration! vx += ax * dt vy += ay * dt x += vx y += vy // And zero out the inputs targetX = 0; targetY = 0; // other stuff }[/code] This code, through only indirectly setting the velocity and adding the acceleration to it instead of directly setting it, means the movement will feel very weighty and take a little bit of time to actually get up to speed, depending on the values. However, there's 2 main issues - firstly, the player can keep accelerating until they reach ludicrous speeds! Let's fix that first: [code] // Now lets do the euler integration! vx += ax * dt vy += ay * dt // Now lets limit our velocity vector to our moveSpeed, using the same method we use to normalize our input speed = sqrt((vx * vx) + (vy * vy)) if (speed > moveSpeed) { vx /= speed // If moveSpeed is always > 0, we don't need to worry about diving by 0! vy /= speed vx *= moveSpeed vy *= moveSpeed } x += vx y += vy [/code] Now our player can't go over our max speed! But they still don't stop when you let go of the input. That's however, an easy fix now, using the trick you tried earlier. We just need to add this code after we've added our velocity to our position: [code] vx *= 0.95 // Fake friction. Perhaps we should move this into it's own variable? vy *= 0.95 [/code] And you should have nice smooth movement! If the player slows down to slowly or quickly, you can change that 0.95 number there. You might have an issue where the player slows down weirdly, but we can fix that by removing a constant number from the velocities instead of multiplying it, if needs be.
Thank you for all the help! This is it right now: [img]http://i.imgur.com/ZJMmb88.gif[/img] Still only moves in cardinal directions (along with going moving a little at first, then once it registers that the key is being held down it starts moving proper) but I guess there's no way to get past that. I guess I can't have what I wanted with friction, it's either this or that.
[QUOTE=NixNax123;46388826]Thank you for all the help! This is it right now: [img]http://i.imgur.com/ZJMmb88.gif[/img] Still only moves in cardinal directions (along with going moving a little at first, then once it registers that the key is being held down it starts moving proper) but I guess there's no way to get past that.[/QUOTE] Can you not hold W and D at the same time to move diagonally?
[QUOTE=Tommyx50;46388856]Can you not hold W and D at the same time to move diagonally?[/QUOTE] No.
Sorry, you need to Log In to post a reply to this thread.