How do I make the player spawn next to car here - godot

extends KinematicBody2D
var active = false
var car_zone = false
#car driving
func get_car_input():
var velocity = Vector2.ZERO
var speed = 200
if Input.is_action_pressed("forward"):
velocity.y = -1
if Input.is_action_pressed("backward"):
velocity.y = 1
if Input.is_action_pressed("left"):
velocity.x = -1
if Input.is_action_pressed("right"):
velocity.x = 1
move_and_slide(velocity*speed)
func _physics_process(_delta):
if active:
get_car_input()
leaving_car()
if !active:
entering_car()
pass
#entering/exiting car
func _on_player_detect_body_entered(body):
if body.name == "player":
car_zone = true
func _on_player_detect_body_exited(body):
if body.name == "player":
car_zone = false
func entering_car():
if Input.is_action_just_pressed("interact") && car_zone == true:
var hidden_player = get_parent().get_node("player")
hidden_player.active = false
#$Camera.make_current()
active = true
print("car entered")
func leaving_car():
var vehicle = $"."
var hidden_player = get_parent().get_node("player")
#spawn player to car HERE
if car_zone == false && Input.is_action_just_pressed("interact"):
hidden_player.active = true
active = false
#hidden_player.global_transform.origin = newLoc
I followed this tutorial: https://www.youtube.com/watch?v=7VzBHbG8sqo, and at 14:41, it shows how to do it in godot 3d, but I need it in godot 2d. He used "var newLoc = vehicle.global_transform.origin - 2*vehicle.transform.basis.x" to do that, but it doesn't work in 2d

There is a pretty simple solution for your problem, which does not even contain any math to work.
There is a Node called Position2D, which you can add to your Car Scene. Place it, where you want your character should stand after leaving the vehicle (so as a driver on the left side of your car)
Because the node is in your car scene it will move along with the car and rotate as well, so its always right next to your car.
All we need to do now is getting the global_position of the Position2D and setting the global_position of our player to it.
To make it easier to receive the global_position of the Position2D Node, we can add a function to the car which returns exactly that. Saying your Car Scene looks like this:
Vehicle
Sprite
ExitPosition (Our Position2D node. Renamed for clearity)
The function in our vehicle.gd could be like this:
func get_exit_location() -> Vector2:
return $ExitPosition.global_position
As I see it you have a variable named vehicle in your player code, which points to your car. So now, when you want to leave the car you can set the player position like this:
## Calling inside player code
global_position = vehicle.get_exit_location()
Keep in mind, that both ways (the one in the video and this one here) will make problems if there is something at the point your trying to place your player. So always check if your player can be at that position.

Related

Raycast2D end not detecting collision

I have a Raycast2D where I want to detect collision with the enemy, but it does not collide at the end. What I'm saying is that it only detects collision at the place where it originates. Here is my code:
extends KinematicBody2D
export var speed = 200
var velocity = Vector2.ZERO
var enemy = 0
onready var navigation_agent = $NavigationAgent2D
onready var bullet = preload("res://Bullet.tscn").instance()
func _ready():
navigation_agent.connect("velocity_computed", self, "move")
$RayCast2D.global_rotation = self.global_rotation - 90
func _input(event):
if event.is_action_pressed("mouse_right"):
navigation_agent.set_target_location(event.get_global_position())
func _process(_delta):
if $RayCast2D.is_colliding():
if $RayCast2D.get_collider().is_in_group("enemy_ground_troop"):
enemy = $RayCast2D.get_collider()
velocity = Vector2.ZERO
ranged_attack()
if navigation_agent.is_navigation_finished():
return
velocity = global_position.direction_to(navigation_agent.get_next_location()) * speed
look_at(navigation_agent.get_next_location())
navigation_agent.set_velocity(velocity)
func move(velocity):
velocity = move_and_slide(velocity)
func ranged_attack():
add_child(bullet)
bullet.global_position = self.global_position
bullet.target = enemy.global_position
Could someone help me fix this?
are you debugging the physics collisions during runtime? you should be able to see if the line is intersecting or not.
look under Debug > Visible Collision Shapes
also try
$RayCast2D.force_raycast_update() inside of _process and see if that makes some difference.
Are you sure the raycast is enabled under the inspector?

Kinematic body 2d won't do anything when entering area 2d - godot

I made a kinematic body2d for my boss battle in godot and made it so that when the bullet which is an area 2d has a body entered it checks for the name then does something. This is my code:
This is my boss code:
extends KinematicBody2D
const ATTACK_THRESHOLD = 1
const ATTACKS = ["movingL", "movingR", "plus", "cross", "horizon"]
var _idle_count = 0
var _attack_set = ATTACKS
signal startin
var health = 1
onready var _anim_tree = $boostree
func increase_idle_count():
_idle_count += 1
if health == 0:
death()
if _idle_count > ATTACK_THRESHOLD:
_idle_count = 0
attack()
func _on_bosstrigger_start():
_anim_tree.set_condition("starting", true)
emit_signal("startin")
$boossoo.play()
func _ready():
randomize()
func attack():
var attack = _attack_set[randi()%_attack_set.size()]
_anim_tree.set_condition(attack, true)
func death():
_anim_tree.set_condition("die", true)
func _on_area2DE_area_entered(area):
if "bullet2" in area.name:
health -= 1
I used "area2DE" which was an area2d that was a child of the boss.
the "increase_idle_count()" function was put at the end of my idle animation.
.
I would think that the boss would do the death animation after getting shot but absolutely nothing happens. all the other animations work normally and will happen except for the death animation. I had spent the entire day trying different solutions and nothing had worked. Please help.

enemy follow player my "player" when it enters the "enemy" detection zone the enemy continues forward (to the left)

what is happening is that my "enemy" is not following the "player", when my player enters the detection area the "enemy" continues straight ahead (to the left).
thank you, if you understand something or need more information let me know
detection zone
enemy code
enemy code:
const EnemyDeathEffect = preload("res://Bots/EnemyDeathEffect.tscn")
export var MAX_SPEED = 60
export var ACCELERATION= 25
export var FRICTION = 700
enum {
IDLE,
WANDER,
CHASE
}
var velocity = Vector2.ZERO
var knockback = Vector2.ZERO
var state = CHASE
var path: PoolVector2Array
onready var sprite = $AnimatedSprite
onready var stats = $Stats
onready var playerDetectionZone = $PlayerDetectionZone
func _physics_process(delta):
knockback = knockback.move_toward(Vector2.ZERO, FRICTION * delta)
knockback = move_and_slide(knockback)
match state:
IDLE:
velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)
seek_player()
WANDER:
pass
CHASE:
var player = playerDetectionZone.player
if player != null:
var direction = (player.position - global_position).normalized()
velocity = velocity.move_toward(direction * MAX_SPEED , ACCELERATION * delta)
print(direction)
else:
state = IDLE
sprite.flip_h = velocity.x > 0
velocity = move_and_slide(velocity)
func seek_player():
if playerDetectionZone.can_see_player():
state = CHASE
func _on_Hurtbox_area_entered(area):
stats.health -= area.damage
knockback = area.knockback_vector * 100
func _on_Stats_no_health():
queue_free()
var enemyDeathEffect = EnemyDeathEffect.instance()
get_parent().add_child(enemyDeathEffect)
enemyDeathEffect.global_position = global_position
I only possible culprit I see is this line:
var direction = (player.position - global_position).normalized()
Here player.position is in its parent local coordinates, while global_position as the name says is in global coordinates. You want this instead:
var direction = (player.global_position - global_position).normalized()
I see this is the way you have on the linked image.
Or if you prefer:
var direction = global_position.direction_to(player.global_position)
Aside from that, it could be that it is changing direction too slowly. Which - given the code - is the same as saying that the ACCELERATION is low, but that is for you to tweak.
I guess it is worth debugging that playerDetectionZone is getting the player, and the CHASE is working correctly.
Common approaches include using a breakpoint, or print. You already have a print for direction. Try also printing player to check the enemy is chasing what you expect it to chase.
For this particular case I also suggest to go to the run the project from the editor, and then go to the Scene panel on the Remote tab, and select the enemy. That would allow you to the properties of the enemy on real time on the Inspector. You should see the state change to CHASE (which would have the value 2), and velocity should also steadily change.
Enabling "Visible Collision Shapes" form the debug menu may also help debugging.
If it is not working, double check the playerDetectionZone has monitoring enabled. Also check that the collision_mask of the playerDetectionZone and the collision_layer of the player are correct.

Trying to make a 2D destructable box in godot

i suck at coding. I am currently trying to make a 2D box that can be destroyed when the player attacks, however (like i said before) i suck at coding. I managed to get it working somewhat (and by somewhat i mean not at all) the box has an animation that plays when the player attacks when in range, but the animation almost never plays (sometimes it does but idk why)
code for box
extends Area2D
var inside = false
var attacking = false
func _physics_process(delta):
pass
func _on_Area2D_body_entered(body):
if Input.is_action_just_pressed("Attack"):
$AnimationPlayer.play("box_hit")
$boxdeathtimer.set_wait_time(0.5)
$boxdeathtimer.start()
func _on_boxdeathtimer_timeout():
queue_free()
code for weapon (if needed)
extends RigidBody2D
var picked = false
func _ready():
Global.weapon = self
func _exit_tree():
Global.weapon = null
var attacking = false
func _physics_process(delta):
if picked == true:
self.position = get_node("../player/Position2D").global_position
func _input(event):
if Input.is_action_just_pressed("e"): #picks up weapon when in range
var bodies = $detector.get_overlapping_bodies()
for b in bodies:
if (b.get_name() == "player"):
picked = true
sleeping = true
rotation_degrees = 90
if Input.is_action_just_pressed("Attack"):
if picked == true && Global.player.facing_right == true:
$AnimationPlayer.play("attack")
attacking = true
if picked == true && Global.player.facing_right == false:
$AnimationPlayer.play("attack2")
attacking = true
The body_entered signal notifies you when a physics body enters the area. The method is_action_just_pressed tells you if the (key associated with the) action were pressed the same (graphics, by default) frame.
So, in your code, everything inside here (Presuming the signal is properly connected):
func _on_Area2D_body_entered(body):
if Input.is_action_just_pressed("Attack"):
# CODE HERE
Can only run if the player pressed (the keys associated with the) action the same (graphics, by default) frame that a body entered the area, which is very hard to manage.
My suggestion is to give a "range of attack" area to the weapon. Then when the player attacks, you can use the signals of that area as it moves.
By the way, Avoid using is_action_just_pressed in _input. It is not intended for that. See Godot - Input.is_action_just_pressed() runs twice. In fact, I would argue to just use Input in _physics_process, unless you really need _input. See the link for what to replace is_action_just_pressed with, if you are working in _input.
So, it can look like this:
On the player side:
func _physics_process(delta):
# … some other code …
if Input.is_action_just_pressed("Attack"):
if picked == true && Global.player.facing_right == true:
$AnimationPlayer.play("attack")
attacking = true
if picked == true && Global.player.facing_right == false:
$AnimationPlayer.play("attack2")
attacking = true
if attacking:
$RangeOfAttack.monitoring = true
yield($AnimationPlayer, "animation_finished")
$RangeOfAttack.monitoring = false
# attacking = false # ?
func _on_RangeOfAttack_area_entered(area):
if area.has_method("attacked"):
area.attacked()
Where:
yield($AnimationPlayer, "animation_finished") is telling Godot to continue the execution after the $AnimationPlayer emits the "animation_finished"signal.
$RangeOfAttack refers to te range of attack area. Child node of the weapon.
_on_RangeOfAttack_area_entered is connected to the "area_entered" signal of the range of attack area. The reason I'm using "area_entered" instead of "body_entered" is that you made the box an area. If box weren't an area but some physics body, you could use the "body_entered" signal of the weapon (which is a RigidBody2D), and you would have no need for $RangeOfAttack.
On the target side:
func attacked():
$AnimationPlayer.play("box_hit")
yield($AnimationPlayer, "animation_finished")
queue_free()

my get_viewport().get_mouse_position() isn't working right godot GDscript

I'm trying to make a 2d platformer where you spawn an object and try to jump on it in the air before it falls.
the problem is when I try to spawn the tile it doesn't spawn where Is the cursor at
it adds a relative value to the position that I don't know how to get rid of it.
you see when I try to instance a scene it takes the cursor position and viewport value into account but then something happens and I fount the object spawning way too far.
see where is the cursor at and where did the tile spawn
, same thing here
, and here
-here is how I'm grouping the nodes and scenes-
and this is the script I'm using, it's in the player1 scene
extends KinematicBody2D
#
var score : int = 0
export var speed : int = 200
export var jumpforce : int = 600
export var gravity : int = 800
onready var AB1 = preload("res://player1AB.tscn")
var vel :Vector2 = Vector2()
onready var sprite : Sprite = get_node("sprite_idile")
onready var ui : Node = get_node("/root/mainscene1/CanvasLayer/ui")
onready var audioplayer : Node = get_node("/root/mainscene1/Camera2D/audio_player")
func _physics_process(delta):
vel.x = 0
# movement inputs
if Input.is_action_pressed("move_left"):
vel.x -= speed
if Input.is_action_pressed("move_right"):
vel.x += speed
# applying the velcoty
vel = move_and_slide(vel,Vector2.UP)
#apllying gravty
vel.y += gravity * delta
#jump input
if Input.is_action_just_pressed("jump") and is_on_floor():
vel.y -= jumpforce
# where the sprite facing
if vel.x < 0:
sprite.flip_h = true
if vel.x > 0:
sprite.flip_h = false
if Input.is_action_just_pressed("restart"):
death()
func death ():
get_tree().reload_current_scene()
func collect_coin (value):
score += value
ui.set_score_text(score)
audioplayer.play_coin_sfx()
func _input(event):
if event.is_action_pressed("click"):
var ABT1 = AB1.instance()
add_child(ABT1)
var XN = null
XN = get_viewport().get_mouse_position()
ABT1.position = XN
important stuff
onready var AB1 = preload("res://player1AB.tscn")
func _input(event):
if event.is_action_pressed("click"):
var ABT1 = AB1.instance()
add_child(ABT1)
var XN = null
XN = get_viewport().get_mouse_position()
ABT1.position = XN
this the same problem in Godot form check it out if possible in case someone answered there
https://godotforums.org/discussion/27007/my-get-viewport-get-mouse-position-isnt-working-right#latest
If you don't have an extra Viewport
My first intuition is to get get_global_mouse_position and set global_position. That way you don't have to deal with any relative positioning:
ABT1.global_position = get_global_mouse_position()
Alternatively, you can check if the event is InputEventMouse, make it local with make_input_local, and get InputEventMouse.position from it:
func _input(event):
if event is InputEventMouse and event.is_action_pressed("click"):
var ABT1 = AB1.instance()
add_child(ABT1)
event = make_input_local(event)
ABT1.position = event.position
This approach would make it easier to then add touch support, because it does not rely on any function that gives you the mouse position. See my answer for Holding screen touch in godot.
If you have an extra Viewport
First of all, make sure you put your Viewport inside a ViewportContainer (otherwise it does not get input, see _input not called for a node inside a Viewport). Then we can use that ViewportContainer to get our coordinates.
Something like this:
func _input(event):
if event is InputEventMouse and event.is_action_pressed("click"):
var ABT1 = AB1.instance()
add_child(ABT1)
var container = find_parent("ViewportContainer") as ViewportContainer
if container != null:
event = container.make_input_local(event)
event = make_input_local(event)
ABT1.position = event.position
Notice there I'm using the function find_parent. It matches by name of the Node, not by type. Another approach you can try is using get_viewport().get_parent().
And yes, that should work regardless of stretch mode.

Resources