I'm making a prototype for my 2d top-down space game and I'm using area2d for my *ship object since most of its mechanics rely only in collisions. Is there a way i can slow down then stop my ship after it is launched, because as for now it just fly continuously.
Here is my basic code:
var jump_speed = 500
var velocity = Vector2()
func get_input(delta):
if Input.is_action_pressed("click"):
look_at(get_global_mouse_position())
if Input.is_action_just_released("click"):
velocity = transform.x * jump_speed
func _physics_process(delta):
get_input(delta)
position -= velocity * delta```
In general the idea is to reduce the length of the velocity vector over time. We could define a deceleration for that (this is not the only way to go about it):
var deceleration := 10.0
And then in _physics_process we can compute by how much the velocity would be reduced:
var speed_reduction := deceleration * delta
Compare it with the magnitud of velocity, if it is more, just set the velocity to Vector2.ZERO otherwise we want to scale velocity appropriately:
var current_speed := velocity.length()
if current_speed > speed_reduction:
velocity = Vector2.ZERO
else:
velocity = velocity * (current_speed - speed_reduction) / current_speed
By the way, from Godot 3.5 onward there is a limit_length method in Vector2 and Vector3 that can make this simpler to implement.
Related
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?
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.
I'm trying to game a game using the Godot Engine but I'm stuck at the beginning! I can't make my KinematicBody2D move!
This is my Player.GD script
extends KinematicBody2D
var velocity = Vector2.ZERO
var move_speed = 480
var gravity = 1200
var jump_force = -720
var right = Input.is_action_pressed("move_right")
var left = Input.is_action_pressed("move_left")
var jump = Input.is_action_pressed("jump")
func _ready():
pass
func _physics_process(_delta):
var move_direction = int(right) - int(left)
velocity.x = move_speed * move_direction
move_and_collide(velocity)
Can someone, please, help me?
All this code will run when the KinematicBody2D is initialized:
var velocity = Vector2.ZERO
var move_speed = 480
var gravity = 1200
var jump_force = -720
var right = Input.is_action_pressed("move_right")
var left = Input.is_action_pressed("move_left")
var jump = Input.is_action_pressed("jump")
In consequence, it will not be taking input in real time. Instead you want the last three lines here:
func _physics_process(_delta):
var right = Input.is_action_pressed("move_right")
var left = Input.is_action_pressed("move_left")
var jump = Input.is_action_pressed("jump")
# …
Those are boolean, by the way. You can get a float from 0.0 to 1.0 if you use Input.get_action_strength instead. Which will also let your code ready for analog input.
I also want to point out that move_and_collide does not take a velocity, but a displacement vector. So to call it correctly, you want to multiply the velocity by delta:
func _physics_process(delta):
# …
move_and_collide(velocity * delta)
Or use move_and_slide, which does take a velocity. By the way, the up parameter that move_and_slide takes is to discern between floor, ceiling, and walls. Without, everything is considered a wall.
I'm beginning a new project and just started coding the movement script. I'm using the same old method I use every time but for some reason I cant move forward and backwards(z-axis). This is odd because left and right (x-axis) uses functionally identical code and works fine. Here's my code:
func _physics_process(delta):
velocity += gravity * delta
_get_input()
velocity = move_and_slide(velocity, Vector3.UP)
func _get_input():
var vy = velocity.y
var dir = Vector3()
velocity = Vector3()
if Input.is_action_pressed("forward"):
dir += -transform.basis.z * speed
if Input.is_action_pressed("back"):
dir += transform.basis.z * speed
if Input.is_action_pressed("left"):
dir += -transform.basis.x * speed
if Input.is_action_pressed("right"):
dir += transform.basis.x * speed
velocity.y = vy
velocity.x = dir.x
velocity.z = dir.z
What is wrong?
Here is an alternative approach based on the following assumptions:
Gravity direction is global.
The KinematicBody can be oriented freely.
The controls follow that orientation.
The speed is global (this would only matter if the physics body is scaled, and you should avoid scaling physic bodies anyway).
We start by building a local direction vector:
var local_direction:Vector3
if Input.is_action_pressed("forward"):
local_direction += Vector3.FORWARD
if Input.is_action_pressed("back"):
local_direction += Vector3.BACK
if Input.is_action_pressed("left"):
local_direction += Vector3.LEFT
if Input.is_action_pressed("right"):
local_direction += Vector3.RIGHT
In fact, we can do that better than that:
var local_direction := Vector3(
Input.get_action_strength("right") - Input.get_action_strength("left"),
0.0,
Input.get_action_strength("back") - Input.get_action_strength("forward")
)
Then we transform it with the global basis:
var direction := global_transform.basis.xform(local_direction).normalize()
Then we can get rid of the y component:
direction.y = 0.0
And scale it, so it is a velocity:
velocity = direction * speed
And, of course, you would set the y component of the velocity we have, because the gravity computation handles care of that:
var v_velocity := velocity.y
velocity = direction * speed
velocity.y = v_velocity
All toghether:
var local_direction := Vector3(
Input.get_action_strength("right") - Input.get_action_strength("left"),
0.0,
Input.get_action_strength("back") - Input.get_action_strength("forward")
)
var direction := global_transform.basis.xform(local_direction)
direction.y = 0.0
var v_velocity := velocity.y
velocity = direction * speed
velocity.y = v_velocity
I wanted to create a game similar to this (Slyway), but I had a problem with the child's movement, so I don't know what to use to do the movement during the draw. Is InputEventScreenTouch Or InputEventScreenDrag, all I come up with is this code that isn't working
extends KinematicBody2D
var velocity = Vector2.ZERO
var direction = Vector2.ZERO
var speed = 200
func input(event):
if event is InputEventScreenTouch:
if event.ispressed():
direction.x -= 1
func physicsprocess(delta):
if velocity.length() == 0:
_input(event)
velocity = Vector2.ZERO
velocity += direction * speed
velocity = moveand_slide (velocity)