Why is my elif statement always executing in Godot? - if-statement

I'm new to Godot programming, just to preface this. I'm trying to make it so that when you fall off of a platform without jumping you start accelerating downwards rather than just going down at a fixed speed. I almost have that, but my elif statement is happening every frame rather than the frame you leave the ground.
I've tried changing things, but I'm stuck at a logical dead end where any option I think of or find has resulted in the same or worse behavior.
extends KinematicBody2D
const UP_DIRECTION = Vector2.UP #up is up and down is down
# Declare member variables here.
var speed = 200 #speed of walk
var velocity = Vector2() #movement Vectors
var gravity = 1000 #gravity, it's real
var jump = 0 #jumping speed
var canjump = 0 #jumps left
var jumpcount = 1 #times you can jump
var nojump = false #did you fall or did you jump?
# Called every physics update.
func _physics_process(delta):
#jumping
if (canjump > 0 && Input.is_action_just_pressed("Jump") || is_on_floor() && canjump > 0 && Input.is_action_pressed("Jump")):
jump = -2000
canjump -= 1
nojump = false
#falling without jumping first
elif not (is_on_floor() && Input.is_action_just_pressed("Jump") && nojump == false):
jump = -gravity
canjump -= 1
nojump = false
#decelerating jumps
if (jump < 0):
jump += 45
#grounding jump variables
if(is_on_floor()):
canjump = jumpcount
nojump = true
#setting x and y
velocity.x = (Input.get_action_strength("Right") - Input.get_action_strength("Left")) * speed
velocity.y = gravity + jump
#using found inputs
velocity = move_and_slide(velocity, UP_DIRECTION)
pass
Here's my code, it tried commenting in the tdlr of what things are supposed to do. Again all I'm looking for is the reason why my elif statement is being applied every frame and how to fix that.

If you have a conditional that looks like this:
if condition:
prints("Something")
The execution flow would enter it when the condition is true.
Let us look at this as example:
if is_on_floor() && Input.is_action_just_pressed("Jump") && nojump == false:
prints("Something")
The above conditional requires three things:
is_on_floor() must be true.
Input.is_action_just_pressed("Jump") must be true.
nojump == false must be true. I mean, nojump must be false.
I think we can agree that does not happen all the time.
Now, if I negate the conditional:
if not condition:
prints("Something")
The execution flow would enter when the condition is false.
So, in a case like the one on your code:
if not (is_on_floor() && Input.is_action_just_pressed("Jump") && nojump == false):
prints("Something")
The conditional has one requirement:
not (is_on_floor() && Input.is_action_just_pressed("Jump") && nojump == false)`
Must be true. I mean:
is_on_floor() && Input.is_action_just_pressed("Jump") && nojump == false
Must be false. Double check D'Morgan's Law if you need to.
It is false when either:
is_on_floor() is false.
Or Input.is_action_just_pressed("Jump") is false.
Or nojump == false is false.
In other words, only one of these being false is sufficient.
To restate that. This condition:
not (is_on_floor() && Input.is_action_just_pressed("Jump") && nojump == false)`
Is equivalent to the following condition (by D'Morgan's law):
not is_on_floor() or not Input.is_action_just_pressed("Jump") or not nojump == false
By the way, using and and or is idiomatic in GDScript.
Wait, I can simplify that a bit:
not is_on_floor() or not Input.is_action_just_pressed("Jump") or nojump`
Thus, the execution flow will enter if either:
not is_on_floor() is true. I mean, if is_on_floor() is false.
not Input.is_action_just_pressed("Jump") is true. I mean, if Input.is_action_just_pressed("Jump") is false.
nojump is true.
And I reiterate that is either of them. Only one is sufficient. And I believe most of the time you haven't just pressed "Jump", also being on the air is enough. And I suspect nojump is false most of the time.
So, we can conclude that the execution flow will enter most of the time.
Write what you mean. You say in comments:
#falling without jumping first
Let us do that. What does falling mean? Does it mean on the air?
var falling := not is_on_floor()
Or do you also mean going down?
var falling := not is_on_floor() and velocity.dot(Vector2.DOWN) > 0.0
Alright, your pick. What does jumping first mean? Does it mean the player got in the air as a result of a jump? Ok... So you would do this when the player jumped:
jumped = true
Which I believe is this:
if canjump > 0 && Input.is_action_just_pressed("Jump"):
jumped = true
And reset it on the ground:
if is_on_floor():
jumped = false
Now we can say "falling without jumping first":
if falling and not jumped:
prints("something")
Almost as if it were the comment, but unlike the comment it can be executed.

Related

Pinescript - Simple if else

I am currently trying to get back into coding (its been some time) and for some reason I cant get my pinescipt to execute properly.
The intent is that
Condition for strategy execution is met, on the first candle a particular strategy.entry with alert_message is executed (3commas deal start).
On the next candle, or any subsequent candle WHILE the deal is open, if the same condition is met a second strategy.entry and alert_message is executed (3commas deal add funds)
If following these the event is NOT met, strategy close is triggered.
At the moment, for some reason its only triggering the deal start repeatedly, and not jumping to the add - I know its a dumb mistake - I just cant see it!!!
base_Long_Order_Placed = 0
message_long_entry = "3commas deal start"
message_long_addition = "3commas deal add funds"
message_long_exit = "3commas close all deals"
longCondition = SECRET_SAUCE
if (longCondition == true and base_Long_Order_Placed == 0)
strategy.entry('Long', strategy.long, when = longCondition ==true and barstate.isconfirmed, alert_message = message_long_entry) /
base_Long_Order_Placed := 1
else if (longCondition == true and base_Long_Order_Placed == 1)
strategy.entry('Long', strategy.long, when = base_Long_Order_Placed == 1 and longCondition ==true and barstate.isconfirmed, alert_message = message_long_addition)
else if (longCondition == false)
strategy.close('Long', when=longCondition == false and barstate.isconfirmed, alert_message = message_long_exit)
base_Long_Order_Placed := 0
else
na
Your script will be executed on every bar. When you define a variable like below
base_Long_Order_Placed = 0
It will be re-defined every time and base_Long_Order_Placed == 0 will always be true. If you want to keep its value between executions, you need to use the var keyword.
var base_Long_Order_Placed = 0
Edit
var is just a keyword that tells the compiler to keep its value for the next execution. It is just a regular variable otherwise. It will keep its value unless you overwrite. It will not iterate unless you do
base_Long_Order_Placed := base_Long_Order_Placed + 1
So, you can definitely reset it when your condition is met.
if (deal_closed)
base_Long_Order_Placed := 0

Pine script condition 1 and condition 2 fulfilled at up to n steps back

Say I have condition 1 and condition 2. If condition 1 and condition 2 was met within up to, say, 5 bars, then I want to perform some action. As an example let's say condition 1 was met at current close, and condition 2 was fulfilled 5 bars ago, then I want to perform some action. How do I formulate that in Pine?
condition1 = ...
condition2 = ...
if (condition1(close)==true or condition1(close-2)==true or
condition1(close-3)==true or condition1(close-4)==true or
condition1(close-5)==true)
and (condition2(close)==true or condition2(close-2)==true or
condition2(close-3)==true or condition2(close-4)==true or
condition2(close-5)==true)
then...
Could it perhaps be formulated something like:
if condition1(close:close-5)== true and condition2(close:close-5)== true then ...
I have read e.g. this thread:
Change background for only the last 5 bars: A Very Simple Problem I can't crack
It sounds like a similar problem, but I am unsure about how to implement it.
a) You would need to use ta.barssince() function.
https://www.tradingview.com/pine-script-reference/v5/#fun_ta%7Bdot%7Dbarssince
//#version=5
indicator("My Script")
/// let's say condition 1 was met at current close, and condition 2 was fulfilled 5 bars ago, then I want to perform some action
ema10 = ta.ema(close, 10)
condition1 = close > open
condition2 = ta.crossover(ema10, close)
x = false
if condition1 and ta.barssince(condition2) == 5
x := true
plot(ema10)
bgcolor(condition2? color.orange:na)
bgcolor(x?color.green:na)
b) Another approach is to use history-referencing operator [].
https://www.tradingview.com/pine-script-docs/en/v5/language/Operators.html#history-referencing-operator
//#version=5
indicator("My Script")
// lets say you want to check if condition2 if true for 5 bars, and condition1 is true in the current bar
ema10 = ta.ema(close, 10)
condition1 = ta.crossover(ema10, close)
condition2 = close > open
condition3 = condition2[1] and condition2[2] and condition2[3] and condition2[4] and condition2[5]
x = false
if condition1 and condition3
x := true
plot(ema10)
bgcolor(condition2? color.orange:na)
bgcolor(x?color.green:na)

how multiple OR's and AND evaluate

This is very simple question, but I can't get it. I have simple condition:
bool c = true || true || true && false;
Why this evaluation is true? As far as I know it evaluates like this:
true || true || true && false => true || true && false => true && false => false
But guess im wrong.
You just have to learn some few basic rules:
(a OR b) is true IF AND ONLY IF at least one of a or b is true.
(a AND b) is true IF AND ONLY IF both of a and b are true.
ORDER of Operators MATTERS: you can't just do the logic any way that you want. computer calculates the output of the a logical statement by an order. a simplified order is like this: First is Grouping (), Second is And, Third is OR.
so when you say bool c = true || true || true && false;. the computer says ok let's first calculate true && false. it is false! and then it calculates true || true || false which is true.
EDIT
Note 1: a complete list of logical operators and their precedence is heavily dependent on the language. you can refer to the documentation for that.
for C#
Note 2: the best practice is to use GROUPING like parenthesis because GROUPING is always of priority. for example it's better to say:
bool c = (true || true) || (true && false);
Think of OR || like addition and AND && as multiplication. There is a priority in there, in fact, you will sometimes see them written as such:
bool c = true + true + true + true * false
In this case, the first evaluation is true * false, then the rest of the ORs. In this particular case, the true order of evaluation of the ORs will depend on language/compiler.
If you want to force a particular order, you can always use parentheses.

if and else if do the same thing

I'm trying to refactor an if-else chain that doesn't look particularly good. My common sense is telling me that I should be able to call my method only once but I can't figure out an elegant way to do it. Currently what I have is:
if(condition1)
do method1;
else if(condition2)
do method1;
Which looks hideous. There's repeat code! The best I can come up with is:
if(condition1 || (!condition1 && condition2))
do method1;
But this also looks bad, since I'm negating condition1 after the or, which seems unnecessary...
I made a truth table for this:
c1| c2| r
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 1
And in case anyone is interested, the real-life problem I'm having is that I got 2 intances of Fancytree in javascript and I want to set some rules to transferring nodes between them. Tree A can only transfer lone nodes to Tree B, while Tree B can reorder itself freely, so I put this on Tree B's dragDrop event:
if(data.otherNode.tree === node.tree){
data.otherNode.moveTo(node, data.hitMode);
}
else if(!data.otherNode.hasChildren()){
data.otherNode.moveTo(node, data.hitMode);
}
You can simplify even more - if the first condition is true, the method should be invoked regardless of the second condition. So the !condition1 in your refactored code is redundant. Instead, you could just have:
if(condition1 || condition2)
do method1;
In modern programming languages the if condition will even short circuit. This means that when the first condition is evaluated as true, the second condition won't even get evaluated.
What you suggested,
if(condition1 || (!condition1 && condition2))
do method1;
Is logically the same as
if(condition1 || condition2)
do method1;
So I think that is your best answer.
It's not logically the same as your truth table though, so either your truth table or your current code is wrong, if truth table r is meant to do
do method1;
In writing
if (condition1 || condition2) {
//code1
}
if condition1 is correct code1 is executed and if condition1 is incorrect then only condition2 is checked and code proceeds accordingly. Hence it would be same as
if ( condition1 ) {
//method1
} else if ( condition2 ) {
//method1
}

C++ operators precedence

I am using this statement
if ((pm && pn) || (pm == false && pn == false))
it is supposed to return true only if both pm and pn are true or if both are false. But this is also returning true if only only first one (pm) is true.
So now it is acting like this:
0 0 = 1
0 1 = 0
1 0 = 1
1 1 = 1
but I need it to work like this:
0 0 = 1
0 1 = 0
1 0 = 0
1 1 = 1
can you tell me where am I making mistake?
What you want is simply:
if (pm == pn)
You are checking if pm is true twice. You also need to check if both are the same, not whether they are both true. So,
if ((pm == pn)
^^ ^^
pm && pm
should be
pm && pn
^
The whole expression can be simplified to
pm == pn
if the variables already have bool type.
Why not try xor?
if (!(pm ^ pn)) { /*...*/ }
Or simply equal?
if (pm == pn) { /*...*/ }
if ((pm && pm) || (pm == false && pn == false))
it is supposed to return true only if both pm and pn are true or if both are false. But this is also returning true if only only first one (pm) is true.
Because you made a typo. You meant pm && pn.
Instead just write if (pm == pn), which is equivalent along as the only semantic values are indeed true and false for both variables.
Plus, consider making your variable names clearer and more distinct.
Note that operator precedence has nothing to do with this.
Since the question's title asks about precedence, note that || has lower precedence than &&. So the two sets of inner parentheses are redundant, and the original expression is just a longer way of saying
if (pm && pm || pm == false && pn == false)
Now, fixing the obvious typo:
if (pm && pn || pm == false && pn == false)
Removing the unneeded explicit comparisons:
if (pm && pn || !pm && !pn)
And, finally, a less obvious transformation, which others have suggested:
if (pm == pn)