I am trying to teleport my player node(kinematicbody2d) when it hits my finish node (area2d) from the side of the Finish node
BTW I'm using godot 3
What I tried:Change the location using get_node("player").set_pos and get_node("player").location
code:
extends Area2D
func _on_Finish12_body_entered(body):
if body.get_name() == "player":
print("%s touched the finish on level %s" % [body.get_name(), get_tree().get_current_scene().get_name()])
get_node("player").position = Vector2(1504, 1896)
pass
So what I need:
The playing being teleported to 1504, 1896
There's a lot of unknowns here that can be the problem
Is the player's location updated in other parts of the code? and if so, could it be possible you did move to 1504, 1896 but then immediately get clobbered by said code?
What is the current behavior when you apply the new position? Does your player move at all? Does it go somewhere unintended?
Does your print statement execute?
Have you tried using move_and_slide/move_and_collide for the kinematicBody to check for collision?
Just a few ideas on how to go about figuring it out.
This is what works with Area and KinematicBody (i.e. 3D):
extends Area
func _on_Area_body_entered(body):
body.look_at_from_position(spawn, Vector3(0,0,0), Vector3(0,0,0))
with spawn being an empty spatial to define the point in space to teleport to.
Related
I want the inscription "hello" to be displayed in case of a collision with an object! How to do it? And what should be used?
I tried to do this using the Area2D node, but nothing worked :(
I tried to use the following code:
func print_msg():
print("Hello")
func _on_area_entered(): (I attached it)
print_msg()
Before that, I made a player using KinematicBody2D and made him move. And made blocks for walking
Since you've left things very ambiguous I'll try to explain it to the best of what I understood
Here I have the basic setup with a RigidBody2D and Area2D:
And here's the main script:
extends Node2D
func message_area(thing):
print("Hello! (Area Entered)")
func message_body(thing): # you were probably missing this
print("Hello! (Body Entered)")
func _ready():
$Area2D.connect("area_entered",self,"message_area")
$Area2D.connect("body_entered",self,"message_body")
Now when you press play the rigid body will fall into Area2D and when it does it will output this:
Hello! (Body Entered)
My best guess is you only connected the area_entered signal but not the body_entered which is why nothing was being printed when the object entered the Area2D
You can further follow on how to connect signals & How Area2D works
And I'd recommend you post code or explain what you've tried (preferably with images) so people can understand your problem better and help better :)
Edit:
If you want to change the visibility of the thing entered/collided you have 2 options:
...
func message_body(thing):
print("Hello! (Body Entered)")
thing.visible=true #option 1
thing.modulate.a=0.0 #option 2 (you can also use self_modulate)
Option 1 is the equivalent of pressing the eye icon
Option 2 changes the alpha value i.e. decides how much transparent your object should be and lies between 0 & 1 where 0=completely invisible, 1=completely visible, 0.5=50% visible and so on...
Equivalent of changing :
However, since you said "with a certain object" you can add a condition before toggling the visibility:
func message_body(thing):
print("Hello! (Body Entered)")
if(thing is KinematicBody2D): # or you can create a custom class and use it's `class_name`
thing.visible=true
thing.modulate.a=0.0
# or
if(thing.name =="Main Player"):
thing.visible=true
thing.modulate.a=0.0
# etc etc
I recommend you read this if you already haven't
I have a basic system for an RTS in place. I have a central manager and a drag select which works. I have it in place that if you right click on an enemy, whatever is selected will "hunt" the enemy. The enemy will transmit it's position to those selected troops and the troops will then constantly follow it. The problem that I have lies in my trying to create an attack system for the troops. I have an Area2D that if it comes in contact with an enemy it will print a debug for me, here is the code for that:
#on Area2D entered(body)
if body == target:
print_debug("attacked")
target is the enemy, and is set when you click on the enemy with:
for item in selected_list:
item.hunt
for enemy in enemy_list:
if enemy.hovering:
item.target = enemy
Now here is the problem. In the first code snippet, Godot is giving me an error, something about objects and ints. This happens because I am setting target to 0 at the start, before you click on the enemy, but the body is classified as an object. So, when the troop is instanced in the scene, this basically turns to
#on Area2D entered(object)
if object == 0:
print_debug("attacked")
So I understand what is wrong, I just don't know how to fix this. Can anyone help?
So, the problem i'm struggling with is making collectibles disappear properly and making it so the playable character doesn't collide with them at all. My guess (i'm still very new to the engine) is that either the stomp mechanic of the playable character is somehow colliding with the collectibles' hitbox or i messed up the collectibles' hitbox settings.
My guess for the animation is that i missed a step while coding the animation switch, i still now pretty much nothing of the AnimatedSprite node since i've used the AnimationPlayer so far (someone has suggested me to use the AnimatedSprite node to animate 2D sprites instead of the AnimationPlayer so i'm trying it out)
Here follows a portion of the playable character's code.
#Stomp mechanic
func calculate_stomp_velocity(linear_velocity: Vector2, impulse: float) -> Vector2: #Schiacciare i nemici
var output = linear_velocity
output.y = -impulse
return output
func _on_EnemyDetector_area_entered(area):
_velocity = calculate_stomp_velocity(_velocity, stomp_impulse)
#Death
func _on_EnemyDetector_body_entered(body):
_velocity.y = 0.0
queue_free()
Here is instead the collectibles' code (the collectible's name is "Leaf")
extends Area2D
onready var _animated_sprite = $AnimatedSprite
func _process(delta):
_animated_sprite.play("Floating")
func _on_Leaf_body_entered(KinematicBody2D) -> void:
_animated_sprite.stop()
_animated_sprite.play("Fade")
queue_free()
The function queue_free will delete the node between frames. Thus, in this code:
_animated_sprite.play("Fade")
queue_free()
The animation does not get a chance to be seen.
I suggest you yield to the "animation_finished" signal:
_animated_sprite.play("Fade")
yield(_animated_sprite, "animation_finished")
queue_free()
When Godot is executing the code and encounters yield, it will stop executing the function. And when the signal ("animation_finished") is emitted, the Godot will resume the exeution. That way the animation gets to play before the node is removed.
You may also want to disable the Area2D. For example: set_deferred("monitoring", false). So it does no longer trigger "body_entered". I will also mention that it is a common practice to use node groups to identify nodes on collision.
First of all, I'm new to programming in general so I'm kind of assuming there's a simple answer to this question, I just couldn't seem to find it anywhere.
I'm making a simple platformer game with enemies that move toward the player. I used this code in the enemy's script underneath the physics process to get the player position:
player_position = get_parent().get_node("Player").get_position
However, upon the player being queue_freed when health reaches 0, the game crashes immediately and I get a null error due to there being no Player node. How can I work around this?
You could just set $Player.visibility to false instead of freeing, or you could check if the player exists first using get_parent().has_node("Player")
When you destroy the player, the physics process function is still trying to get the player node, even though it doesn't exist. So, as Lucas said, you could replace:
player_position = get_parent().get_node("Player").get_position
with something like...
if get_parent().has_node("Player"):
player_position = get_parent().get_node("Player").get_position
(Before setting player_position, it will check if the player node even exists)
I think you could use weakref (documentation here).
If you declare a weak reference:
var player_ref: WeakRef = null
and store that reference:
func store_player_node():
var player_ref = weakref(get_parent().get_node("Player"))
Then you can access that reference later:
if player_ref.get_ref():
player_position = player_ref.get_ref().get_position
Weakref has advantage over using get_parent().get_node("Player"). Let's imagine the following scenario:
Player dies and its node is removed from the parent node's children.
New node is created with name Player and added to the scene tree at the same place as the dead Player.
get_parent().get_node("Player") will return a node and the code will not crash. However, it will be a new Player node, not the old one, and I think this is usually undesired.
I hope this helps!
Hi I am totally confused with CGAffineTransform animations. All I want to do is move a sprite from a position on the right to a position on the left. When it has stopped I want to "reset" it i.e. move it back to where it started. If the app exits (with multitasking) I want to reset the position again on start and repeat the animation.
This is what I am using to make the animation..
[UIImageView animateWithDuration:1.5
delay:0.0
options:(UIViewAnimationOptionAllowUserInteraction |
UIViewAnimationOptionCurveLinear
)
animations:^(void){
ufo.transform = CGAffineTransformTranslate(ufo.transform, -270, 100);
}
completion:^(BOOL finished){
if(finished){
NSLog(#"ufo finished");
[self ufoAnimationDidStop];
}
}];
As I understand it the CGAffineTransforms just visually makes the sprite look like it's moved but doesn't actually move it. Therefore when I try and "reset" the position using
ufo.center = CGPointMake(355, 70);
it doesn't do anything.
I do have something working, if I call
ufo.transform = CGAffineTransformTranslate(ufo.transform, 270, -100);
it resets. The problem is if I exit the app half way through the animation then when it restarts it doesn't necessarily start from the beginning and it doesn't go the the right place, it basically goes crazy!
Is there a way to just remove any transforms applied to it? I'm considering just using a timer but this seems silly when this method should work. I;ve been struggling with this for some time so any help would be much appreciated.
Thanks
Applying a transform to a view doesn't actually change the center or the bounds of the view; it just changes the way the view is shown on the screen. You want to set your transform back to CGAffineTransformIdentity to ensure that it looks like "normal." You can set it to that before you start your animation and set it to what you want it to animate to.