0 votes

If I want the player to enter a charge state by holding down a key, but while holding this key, any other key pressed will stop the charge state and return to normal state. How do I set up the if condition. I know to set if Input.is_action_pressed("ui_charge") &&: but not sure what to put as condition for the detection of other key press. Thank you.

asked Jul 9 in Engine by Idleman (111 points)

could you share some code of your current implementation so far?

Thanks for responding to my question here and in other threads. Here is the key part of my current code.

The design is to hold down a key and the player goes into a charge state, where a short charging animation will be play. Once the charge animation finish, 1 unit of power will be added to the player. If the player moves during the animation time frame, the charge state will be set to normal state and no power will be added.

I set the trigger in the player scene, I tried the isactionpress but it is not very reliable, so I use isactionjust_pressed to trigger the state and set a isactionpress in the instanced scene of PowerCharge scene.

So far, this code got me the result I want, only problem is that when the charge animation is playing, the player can be moved and the charge animation stay at the player's original position. Therefore, I thought if I add a if condition to detect when other key is pressed and the charging will stop.

Note: In the Player scene, I put the main function into a AnimationPlayer method track. The reason for that is if I run the function on its own, before getting the signal and return to normal state, the power_charge() function will run many times and cause the unpredictable outcomes such as adding more than 1 power at a time. However, I found that if the same function is called in a method track in AnimationPlayer, it only runs once with no repeat.

In my player scene

#Trigger the charge state
if Input.is_action_just_pressed("ui_charge"):
    state = CHARGE 

#Once in Charge state, perform function
func charge_state(delta):
    movement = Vector2.ZERO
    animationPlayer.play("Charge")

# This function was added and run in AnimationPlayer
func power_charge():
    var charge = POWER_CHARGE.instance()
    charge.connect("charge_finish", self, "set_animation_finish")
    charge.position = global_position
    get_parent().add_child(charge)

In the instance charge scene

    extends Node2D

    onready var animatedSprite = $AnimatedSprite

    signal charge_finish

    func _physics_process(delta):
        if Input.is_action_pressed("ui_charge"):
           animatedSprite.play("Effect")
        else:
           animatedSprite.stop()
           scene_finish()

    func _on_AnimatedSprite_animation_finished():
        if PlayerStats.power_count < 8:
            PlayerStats.power_count += 1
            print(PlayerStats.power_count)
            scene_finish()
       else:
            scene_finish()

    func scene_finish():
        queue_free()
        emit_signal("charge_finish")

If i understood you correctly, i think there are a few things you could do. If only movement will stop charging, and lets say you only have "moveleft" and "moveright" actions, you could inside charge state ask:

if Input.is_action_just_pressed("move_left") or Input.is_action_just_pressed("move_right"):
    #cancel charge
    state = IDLE

If you wan't any key to stop charging, you could use _input(event) method to set a flag:

func _input(event):
    if event.is_action_pressed("move_left") or ... #add all actions that could cancel charge
        #cancel charge or set flat to cancel it on process
        state = IDLE

Im putting this as a comment because idk if its the best way to do so.

Thanks for the suggestion, I think we are thinking on the same line, but instead of adding all keys, I feel an any key other than "ui_charge" pressed condition will cover all the grounds, so it will be simple. I am not sure if there is way to set an any other key pressed condition, I will do more research on this.

After doing some more exploring, I have found a way to set the if condition of detecting any other key input (the code it is in my comment to another answer). It works ok, but not working in game pad since the code is for key input. If there is something like Input.!isactioninput("ui_charge") that will be better, but I don't think Godot provides such a way for input handling at this moment. I will go with this solution for now, update it down the road for my project if something more efficient comes up. Thank you very much for your help.

1 Answer

+1 vote
Best answer

You could set up a "currentpressedkey" something like that, and say:

if current_key != "ui_charge":
      #change_state
answered Jul 9 by BrunoFreezee (78 points)
selected Jul 11 by Idleman

Thank you for providing feedbacks, could you explain a bit more about how to set up a current pressed key? I got the idea, but not sure how to do it in code.

I tried out the current_key idea but didn't work, I research and found this code, is the same idea, overwrite the last key pressed, worked on a simple script i've made with move and charge state, I hope works for you!

   func _input(event):
        if event is InputEventKey:
            if event.pressed:
                if event.is_action("ui_charge"):
                    state = charge
                else:
                    state = move

Thank you for show me the code, I also dig around and have tried out different ways of doing it. So far, this way works best for my project.

func _input(event):
    if event is InputEventKey and event.pressed:
       if event.scancode != KEY_SPACE:
           scene_finish()

This is very close to the result that I want to achieve. If the SPACE key ("ui_charge") is pressed, play is in a charge mode, once any key input(except for the SPACE key) happens like move or shot during the charging loop, the charge will stop.

The only problem with this method so far is that since it is a specific KEY_SPACE, if I use a game pad or game controller, it would not work. Other than that, it works fine. Thank you for your help.

That's great, I've never used this function before but I think is better than using If Input.isaction .. every time, I'm gonna try implementing in my project as well
About the problem, you could add space to a action on "input
map" setting, and use "event.isaction (" chargeaction "), just like you were doing with (" ui_charge "),

I did add SPACE key to the charge action in the input map, as well as a button in game pad. The game pad button works for most part, but since the if event.scancode != KEY_SPACE: only works for key board. I have been trying to find a != action instead of !=KEY for the detection of inputevent, but have not been able to find code to do that.

If you figure out that, please reply here, beacause now I'm having the same problem

Sure, but not sure when will that be. Since this is not a show stopper, I am moving on with other functions of my projects now, but if I come across any solution I will update it here.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.