I am creating a small space shooter game with asteroids set up as Rigid Bodies. They just fall past the bottom of the screen and are then meant to be deleted and that's the part I am having trouble with. I have a print function to let me know when they are deleted that will say "Object Terminated". I have no errors when running it, but they do not get deleted when they fall past 560 on the Y-Axis.
I tried switching things around to see what would happen and I switched ">" to "<". This deleted
them immediately since they are lower than 560 on the y-axis, so why does it not work the other way round when they are higher than 560 on the y-axis? Is it because the get_position function does not get an updated value for the position? If so how do I get that?
extends RigidBody2D
func _ready():
var posY = get_position().y #gets y-axis position
randomize()
add_torque(rand_range(20,60))
if posY > 560:
queue_free()
print("Object Terminated") #checks that they are removed
The _ready() function is only called once when the node is added to the scene. You should put the check on the Y position in the _process() function which is called every frame.
Cedric's answer is correct (so I've up-voted it). Godot will only call the _ready function once (unless you tell Godot to call it again). And you would want to check your conditional periodically… Which you could do in _process which Godot will call once per graphics frame (unless you tell Godot to disable it).
However since we are talking about a RigidBody2D I would suggest _physics_process which runs once per physics frame (unless tell Godot to disable it). Or you can use _integrate_forces which will only run if the RigidBody2D moved (so it won't run on sleeping rigid bodies).
Related
So if i try to resize my Window with the same button back and forth just the one on the bottom will work but it wont go back to '384x470' as if the Window wasnt '500x500'
def sizeWindow():
if root.geometry('500x500'):
root.geometry('384x470')
else:
root.geometry('500x500')
buttonWinSize.configure(text="<<")```
You seem to misunderstand several things here. Tkinter has relatively cool feature that allows you to use some methods for different things. Either you get or you set with the same method. To get you leave the interface empty (e.g. root.geometry()) or you set with the required argument (e.g. root.geometry('500x500+0+0')). You should be aware that you get the current value(s) in the same format as you set them.
Therefore you retrieve a geometry string by root.geometry() and this has the form of width x height +x +y.
However, not every time this feature is the right tool to achieve the overall goal. In your case you want to check for the width and height. Tkinter provides another feature for exactly this task. It lets you ask for the width and height via winfo_width() and winfo_height().
In addition you should know that every function in python needs to return something and if nothing is specified None is returned by this function. Since you use the setter variant of root.geometry('500x500') you receive None and None equals to False in python, therefore your else block will always be executed instead of your if block.
Suggested change:
def sizeWindow():
if root.winfo_width() == 500 and root.winfo_height() == 500:
root.geometry('384x470')
else:
root.geometry('500x500')
Your if-statement is wrong. You are actually setting the size with your first root.geometry('500x500'). This does (AFAIK) not return a boolean. So you need to check the actual current dimensions:
if root.winfo_width() == 500 and root.winfo_height() == 500:
root.geometry('384x470')
else:
root.geometry('500x500')
buttonWinSize.configure(text="<<")
I would like to check with code like this:
func _input(event):
if event is InputEventMouseButton:
if event.button_index == BUTTON_LEFT and event.pressed:
spawnTower(event.position)
if there is something at the current mouse position, eg. enemies, other towers, terrain etc. and only if the point of interest has no collision, spawn a tower.
I did try to tackle this from the opposite site: have each collision shape signal when mouse enters/leaves the collision shape.
Wanting to add maybe up to 20 towers and potentially 100ish enemies this seems to be rather wasteful.
A hint for a better approach would be highly appreciated.
Kind regards, Jan Martin
Well, I am sorry, maybe this is helpful for other or at least a future me.
So here is my solution:
First: add a RayCast2D, no code in script required, make sure to check "Collide With: Areas" in the Inspector.
Second: Add some code to main script like:
func checkForCollision(position: Vector2):
get_node("RayCast2D").position = position
get_node("RayCast2D").cast_to = Vector2(0,0) # sets the length of the ray to 0
get_node("RayCast2D").force_raycast_update()
print($RayCast2D.is_colliding())
print($RayCast2D.get_collider ( ))
return $RayCast2D.is_colliding()
this returns a boolean and prints some additional info.
To verify activate "Visible Collision Shapes" in the "Debug" drowdown.
Regards Martin
I'm writing a program in Godot with GDscript that aims to change the position of multiple bones in an armature. The bone gets translated by a value calculated by the point I want the bone to move to minus the current position of the bone. translateValue = endPoint - currentPoint However, all values must be in world coordinates or global position for the code to work. Godot has various methods to retrieve the bone Transform in order to access the position such as : skeleton.get_bone_pose() , skeleton.get_bone_global_pose , skeleton.get_bone_rest . I tried using skeleton.get_bone_global_pose but it didn't give the global position and seemed to still be relative to something. There's also the to_global() method, but i'm not entirely sure what it does. Could someone explain the differences between these methods and how to get global position? Thanks!
I'll start with these methods:
get_bone_rest
get_bone_custom_pose
get_bone_pose
First of all, get_bone_rest gives you the default transform of the bone, relative to its parent bone. Then the other transform are stacked, in the above order.
Then we have:
get_bone_global_pose
This method gives you the final transform of the bone. And it is relative to the Skeleton. That is, this transform already includes the previously mentioned transforms, combined from parent to child bone.
Thus, converting its result to world space is a matter of composing the transform of the Skeleton:
$Skeleton.global_transform * $Skeleton.get_bone_global_pose(bone_index)
And we have:
get_bone_global_pose_no_override
As the name suggest get_bone_global_pose_no_override ignores any global pose override. That's right, you you can override the global pose. To do that, use set_bone_global_pose_override. See also clear_bones_global_pose_override. These are all, of course, relative to the Skeleton.
The method Spatial.to_global(vector3) is unrelated to the Skeleton. It transforms a vector from the local space of the node on which you call it, to world space. Which might also be useful:
$Skeleton.to_global($Skeleton.get_bone_global_pose(bone_index).origin)
I made a simple game with python using the Pygame library but when I finished I just noticed that I forgot something. LIMITS
I am pretty new at python and I tried with
if player_pos[1] <= 600:
pygame.K_DOWN = None
*player_pos[1] is the y player's position
*600 is the display's limit
But then, the "down" key just stopped working so I just erased that lines.
You can't (or shouldn't try at least) to turn the input into None. Just use a logical test to decide if you want to move further...
if key_pressed == 'K_RIGHT': (or whatever syntax you use to catch keypress..)
if player_pos[1] < limit:
# update the player position
else:
pass
#JeffH has already suggested the a way to fix your code. I just wanted to make sure you understood why what you did caused problems and to point out the convention for constants. Not understanding and using that naming convention will make it more difficult for you to understand other code, and will complicate others trying to read your code.
pygame.K_DOWN is intended to be a defined constant, it is not an input or a control variable. You should absolutely not change it.
Python does not have true constants that enforce not being able to change them, so it is handled by convention. Variables that are intended to be constants by convention use all uppercase names, like K_DOWN and you are just not supposed to change them. As you discovered things may break or behave weirdly if you do.
In your case 'the down key stopped working' because the constant used to check it no longer contained the right value anymore. Pygame will give you the keycode for the down arrow key (the number 274 when I print it on my system) but you have assigned None to the constant that you are supposed to compare that value with to determine if it is the down arrow key, so that comparison will now fail.
That is why it stopped things working.
sprite (attack) is not working in case :
if Input.is_action_just_pressed("ui_attack"):
$Sprite.play("attack")
but in case:
if Input.is_action_pressed("ui_attack"):
$Sprite.play("attack")
it's working !!!!
what is the solution code pleas?!! Because I want one click on the keyboard to work of sprite...
Have you tried using if event.is_action_pressed("ui_attack"): instead?
I've found that event works better than Input if I only want one action after a button press and not multiple.
If it still doesn't work, try adding if event.is_action_released("ui_attack"): afterwards. You may have to put an additional command afterward to make the code acceptable to the engine, such as print("Key Released"). In my case, it never ended up printing anything to console, but it did only give me one action per button press.
I am assuming this is the question you were looking for an answer to. If not, please disregard, I have been awake all night and am prone to confusion.
EDIT: I forgot to add that it must be in a func _input(event) function to work properly. I've included a simple example that prints text to the console once per press of the left button. See below:
extends Node2D
var text = PrintText()
func PrintText():
return("Print Text Once")
func _ready():
pass
func _input(event):
if event.is_action_pressed("ui_left"):
print(text)
(P.S. I only discovered Godot in the last week or so, but have been crash-coursing myself ever since. I love the engine, but if my understanding comes off as "basic", forgive me.)