Shinigami Posted August 27, 2015 Share Posted August 27, 2015 I have a problem: I can't figure out how to move a sprite with multiple keys pressed at once.A little more explanation:Button W moves the sprite UpButton S moves the sprite DownWhen pressed separately, it works just fine. The problems begin when I try to press several buttons at once.Problems:1. Player presses W, and then S.What happens:W is ignored, S is processed. Sprite moves down. What is supposed to happen:Both W and S are processed. Sprite remains stationary (because both "UP" and "DOWN" buttons are pressed at once). 2. Player presses W, and then S, and then releases W.What happens:After the button is released, all the movement stops. What is supposed to happen:After W is released, sprite should move down as long as S is still held down. I tried to solve this using my own keypress handlers, but end up with either "infinite speedup while pressed" or the problem described above. I managed to do in with Python and Python - to - Javascript converter (basically a JS library that converts Python code into JS), but can't figure out how to do this using Phaser. Any help will be appreciated. The code I currently have (complicated): keyUP = this.input.keyboard.addKey(Phaser.Keyboard.W); keyUP.onDown.add(function() { this.movePlayer("left", "up", "pressed") }, this); keyUP.onUp.add(function() { this.movePlayer("left", "up", "released") }, this); keyDN = this.input.keyboard.addKey(Phaser.Keyboard.S); keyDN.onDown.add(function() { this.movePlayer("left", "down", "pressed") }, this); keyDN.onUp.add(function() { this.movePlayer("left", "down", "released") }, this);and movePlayer: function(player, direction, state) { var speedX = 0; var speedY = 0; if(player == "left") { if(direction == "up") { if(state == "pressed") { speedY = -175; } else if(state == "released") { //speedY -= -175; } } else if(direction == "down") { if(state == "pressed") { speedY = 175; } else if(state == "released") { //speedY -= 175; } } } else if(player == "right") { var addLater; } //this.playerLeft.body.velocity.y += -175; this.playerLeft.body.velocity.y = speedY; //console.log("total x:",speedX,"y:",speedY); }But it works absolutely the same as explained in tutorials - when W is pressed, set velocity to a fixed value, when W is released, set velocity to zero. I tried directly adding positive and negative values to velocity when a corresponding to key is pressed, but this leads to acceleration of the sprite (it goes faster and faster). And when I release the key, the sprite keeps moving in opposite direction (console.log made me realize there were more keyUp events than keyDown events, which is weird). What I'm trying to do:When W is pressed, increase velocity ONCE by a fixed value.When W is released, decrease velocity ONCE by same fixed value, thus stopping sprite. When both W and S are pressed, the total speed of sprite is 0 (because both add velocity in opposite directions but of same value). When one key is released and the other stays pressed, sprite is moving in that respective direction. And I can't figure out how to make this happen. I am using "onDown" because it was recommended here:http://www.html5gamedevs.com/topic/3803-question-about-keys-pressed-vs-isdown/as the "happens once" solution. This post:http://www.html5gamedevs.com/topic/1922-justpressed-only-once/#entry35563Makes me thing I'm making a horrible mistake here by using "movePlayer: function" instead of "function movePlayer(param){}" syntax somewhere else... but I haven't been able to figure out where the function goes. Outside of state curly brackets, maybe?When I add console.log to this function, it gets executed first 30+ times per second while button is pressed for a short period, and then thousands of times per second... does this mean that using "add" I keep adding more and more and more functions to be executed every time I press a button, leading to thousands of functions executed instead of one? If so, how do I solve this? I'm new to programming on Phaser, so any help is much appreciated. Trying to figure out how stuff works. My old code: if(this.keyboard.isDown(Phaser.Keyboard.W)) { this.playerLeft.body.velocity.y += -175; } else if(this.keyboard.isDown(Phaser.Keyboard.S)) { this.playerLeft.body.velocity.y += 175; } else { this.playerLeft.body.velocity.y = 0; }This leads to acceleration, not constant speed, and old problem with simultaneous presses remains. Using equals instead of incrementing fixes acceleration, but doesn't fix my main problem with simultaneous presses. Link to comment Share on other sites More sharing options...
Shinigami Posted August 27, 2015 Author Share Posted August 27, 2015 Figured it out by myself while re-thinking all the posts I've read. Solution is simple - remember the state (true/false) of the button press, and remember last known state before it:if(this.keyboard.isDown(Phaser.Keyboard.W)) { //this.playerLeft.body.velocity.y += -175; up_pressed = true; } else { up_pressed = false; } if(this.keyboard.isDown(Phaser.Keyboard.S)) { //this.playerLeft.body.velocity.y += 175; down_pressed = true; } else { down_pressed = false; } if(up_pressed && !up_pressed_last) { // is pressed, was released total_speed += -175; up_pressed_last = true; } else if(!up_pressed && up_pressed_last) { // is released, was pressed total_speed -= -175; up_pressed_last = false; } if(down_pressed && !down_pressed_last) { // is pressed, was released total_speed += 175; down_pressed_last = true; } else if(!down_pressed && down_pressed_last) { // is released, was pressed total_speed -= 175; down_pressed_last = false; } this.playerLeft.body.velocity.y = total_speed;If you have a better solution, or know problems with current one, please do let me know. I put this in update and now my sprite is only moving when one keys is pressed. Pressing two keys stops it, releasing one of the keys (while holding the other) correctly moves it. Just the way I wanted it. If anyone answers the questions I had in the first post about executing a function multiple times when I put it into "add", I'll be very grateful. A more elegant solution by drhayes: You could track the two values independently, then sum them at the end:var upVel = 0;var downVel = 0;if(this.keyboard.isDown(Phaser.Keyboard.W)) {upVel = -175;} else {upVel = 0;}if(this.keyboard.isDown(Phaser.Keyboard.S)) {downVel = 175;} else {downVel = 0;}this.playerLeft.body.velocity.y = upVel + downVel; Link to comment Share on other sites More sharing options...
drhayes Posted August 27, 2015 Share Posted August 27, 2015 You could track the two values independently, then sum them at the end:var upVel = 0;var downVel = 0;if(this.keyboard.isDown(Phaser.Keyboard.W)) { upVel = -175;} else { upVel = 0;}if(this.keyboard.isDown(Phaser.Keyboard.S)) { downVel = 175;} else { downVel = 0;}this.playerLeft.body.velocity.y = upVel + downVel; jdnichollsc and Shinigami 2 Link to comment Share on other sites More sharing options...
Shinigami Posted August 28, 2015 Author Share Posted August 28, 2015 You could track the two values independently, then sum them at the end:var upVel = 0;var downVel = 0;if(this.keyboard.isDown(Phaser.Keyboard.W)) { upVel = -175;} else { upVel = 0;}if(this.keyboard.isDown(Phaser.Keyboard.S)) { downVel = 175;} else { downVel = 0;}this.playerLeft.body.velocity.y = upVel + downVel; Thanks! This is a good idea! Considering the logics of my program, I can cut down the "else" statements, as downVel will be 0 anyways when "else" is executed. I can also keep both velocities in the same variable, as long as I add velocity to them (instead of assigning). This is my final code:var velocityLeft = 0;if(this.keyboard.isDown(Phaser.Keyboard.W)) { velocityLeft += -175;}if(this.keyboard.isDown(Phaser.Keyboard.S)) { velocityLeft += 175;}this.playerLeft.body.velocity.y = velocityLeft;And it works just the way I want it to! Thanks for the idea! Link to comment Share on other sites More sharing options...
Recommended Posts