I tried to shoot an object towards cursor position, but it has a problem - godot

I'm a beginner in Godot I want to shoot an object that is already in the game towards where the cursor's position is, and the method I created for it works fine but depending on the distance between the object and the cursor the speed changes. can anyone please help me make the speed constant?
I used this:
func _process(_delta):
if Input.is_action_just_released("tap"):
var mousepos = get_viewport().get_mouse_position()
var ballpos = self.get_position()
var x = mousepos.x - ballpos.x
var y = mousepos.y - ballpos.y
velocity = Vector2(x,y)

You can normalize your vector, which gives you a vector of unit length:
velocity = Vector2(x,y).normalize()
And then scale it by the speed you want:
velocity = Vector2(x,y).normalize() * speed
Where speed is a previously defined variable or constant. Something like this will do:
var speed := 100.0
You, of course, will want to tweak the value. So perhaps you want to export it so you can set it form the inspector:
export var speed := 100.0
By the way, you can rewrite the code you have to this:
var mousepos = get_viewport().get_mouse_position()
var ballpos = self.get_position()
velocity = mousepos - ballpos
Adding the changes suggested above we have:
var mousepos = get_viewport().get_mouse_position()
var ballpos = self.get_position()
velocity = (mousepos - ballpos).normalize() * speed
Which you can rewrite to this:
var mousepos = get_viewport().get_mouse_position()
var ballpos = self.get_position()
velocity = ballpos.direction_to(mousepos) * speed

Related

Godot apply_central_force direction is changing after the rigidbody2d is rotated

Simple top down mini golf game. I'm using a rigidbody2d as a ball, and a ray that points from the ball to the mouse. I use apply_central_force towards the mouse position (normalized) * speed. you can see this works fine at first. the ball goes in the direction of the ray. once it gets rotated it doesn't.
Gif of the issue
I tried changing the rigidbody mode to character but it sticks to the wall to much. I tried having a position node be the beginning of the ray and setting its rotation to 0 every frame but that didnt work either. Here is my scene tree and code. all code is in the "Planet" which is the rigidbody ball.
Scene Tree
extends RigidBody2D
const max_length = 2000
onready var beam = $Beam
onready var end = $end
onready var ray = $RayCast2D
onready var begin = $begin
onready var my_line = $Line2D
export var shot_speed = 10
export var default_speed = 10
func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
shot_speed = default_speed
func _physics_process(delta):
_handle_ray()
func _handle_ray():
var mouse_pos = get_local_mouse_position()
var max_cast_to = mouse_pos.normalized() * max_length
ray.cast_to = max_cast_to
if ray.is_colliding():
end.global_position = ray.get_collision_point()
else:
end.global_position = ray.cast_to
beam.rotation = ray.cast_to.angle()
beam.region_rect.end.x = end.position.length()
if Input.is_action_pressed("Fire"):
shot_speed += 10
if Input.is_action_just_released("Fire"):
apply_central_impulse(ray.cast_to.normalized() * shot_speed)
shot_speed = default_speed

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.

Kinematic Body 2D not moving

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.

How to tween Linear Velocity in rigidbody2d godot

trying this code but it moves object diagonally(down-right)
func _ready():
tween = get_node("Tween")
pass
func _physics_process(_delta):
tween.interpolate_property(self,"linear_velocity",null,Vector2(0,0.1),1,Tween.TRANS_LINEAR,Tween.EASE_IN_OUT)
tween.start()
pass```
It's hard to figure out what you are trying to accomplish and with which types of Node, however you can try something like this:
var TARGET_VELOCITY = Vector2(0,0.1)
var LERP_SPEED = 1
func _physics_process(_delta):
var newVelocity = self.linear_velocity.linear_interpolate(TARGET_VELOCITY , delta * LERP_SPEED)
self.linear_velocity = newVelocity
From the interpolation tutorial:
https://docs.godotengine.org/en/stable/tutorials/math/interpolation.html

Godot - Change tiles within an area

I'm trying to make it so if a function is called an area covered by a Collisionshape2D gets its tiles removed in a TileMap node. My problem is the area deleted doesn't match the Collisionshape2D's. Any insight is appreciated! Thank you.
My code:
func changeArea(collionshape):
var corridorTile = $CorridorTiles
var rect = Rect2(collionshape.position, collionshape.shape.extents*2)
var topleft = corridorTile.world_to_map(rect.position)
var bottomright = corridorTile.world_to_map(rect.end)
for x in range(topleft.x, bottomright.x):
for y in range(topleft.y, bottomright.y):
corridorTile.set_cell(x, y, -1)
Edit1*
Upon changing the code to:
func changeCorridorTile(collionshape):
var corridorTile = $CorridorTiles
var extents:Vector2 = collionshape.shape.extents
var topleft = corridorTile.world_to_map(collionshape.position - extents)
var bottomright = corridorTile.world_to_map(collionshape.position + extents)
for x in range(topleft.x, bottomright.x):
for y in range(topleft.y, bottomright.y):
corridorTile.set_cell(x, y, -1)
corridorTile.update_bitmask_region()
The cells in the tileMap which the collisionShape2D area covers get deleted. And I update them using .bitmask_region() method.
First thing I notice, from the top of my head: The Rect2 position is a corner, but the CollisionShape position is the center.
You would have to do it like this:
var extents:Vector2 = collionshape.shape.extents
var rect := Rect2(collionshape.position - extents, extents * 2)
Now, on a second look, you don't need the Rect2 at all:
var extents:Vector2 = collionshape.shape.extents
var topleft = corridorTile.world_to_map(collionshape.position - extents)
var bottomright = corridorTile.world_to_map(collionshape.position + extents)
One more thing: I believe that is in local space of the parent of the CollisionShape2D (an Area2D, I guess). So, if that is not working, it might be because you need to do it in global space. Hopefully you don't have any rotation (which would just mess the whole thing up) or scaling, so that would only be a matter of using global_position.
Addendum: I forgot something, world_to_map does not take global coordinates. Try this instead (assuming no rotation or scaling):
var extents:Vector2 = collionshape.shape.extents
var position := corridorTile.to_local(collionshape.global_position)
var topleft = corridorTile.world_to_map(position - extents)
var bottomright = corridorTile.world_to_map(position + extents)

Resources