I found this code to push a rigidbody with a kinematic body in godot:
for index in get_slide_count():
var collision = get_slide_collision(index)
if collision.collider.is_in_group("bodies"):
collision.collider.apply_central_impulse(-collision.normal * push)
This code works but when the player stand on rigidbody can't jump!!
P.S. I have set the infinite_inertia to false. All code is this:
extends KinematicBody2D
onready var animation = $AnimationPlayer
export (int, 0, 200) var push = 30
var velocity :=Vector2.ZERO
var gravity := 30
var speed := 50
var jumpforce = 300
func _physics_process(delta) -> void:
#Push()
if Input.is_action_pressed("right"):
$Sprite.flip_h=false
velocity.x += speed
animation.play("Walk")
elif Input.is_action_pressed("left"):
$Sprite.flip_h=true
velocity.x -= speed
animation.play("Walk")
else:
animation.play("Idle")
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y =- jumpforce
animation.play("Idle")
velocity.y += gravity
Push()
velocity=move_and_slide(velocity,Vector2.UP, false, 4, PI/4, false)
velocity.x= lerp(velocity.x,0,0.2)
func Push():
for index in get_slide_count():
var collision = get_slide_collision(index)
if collision.collider.is_in_group("bodies"):
collision.collider.apply_central_impulse(-collision.normal * push)
I found the solution to this problem!!! I set the rigitbody 's mass property from editor to 2 instead 1 . Is working now :)
Related
I have a game I'm making in Godot, 2D
I have a progres sbar called "Healthbar"
I'm trying to set it's value to the players HP value
the full code is as follows
extends KinematicBody2D
var health: float = 100
func ready():
pass
export var movespeed : int
export var batteryspeed: int
var battery = preload("res://Bullet.tscn")
func _physics_process(delta):
get_tree().get_root().find_node("HealthBar").value = health
var motion = Vector2()
if (health <= 0):
gameover()
if(Input.is_action_pressed("MoveUp")):
motion.y -= 1
if(Input.is_action_pressed("MoveLeft")):
motion.x -= 1
if(Input.is_action_pressed("MoveDown")):
motion.y += 1
if(Input.is_action_pressed("MoveRight")):
motion.x += 1
motion = motion.normalized()
motion = move_and_slide(motion * movespeed)
if(Input.is_action_just_pressed("Fire")):
fire()
look_at(get_global_mouse_position())
func fire():
var batteryInstance = battery.instance()
batteryInstance.position = position
batteryInstance.rotation_degrees = rotation_degrees
batteryInstance.apply_impulse(Vector2(), Vector2(batteryspeed, 0).rotated(rotation))
get_tree().get_root().call_deferred("add_child", batteryInstance)
func gameover():
get_tree().reload_current_scene()
func _on_Area2D_body_entered(body):
if "Enemy" in body.name:
health -= 10
and the part I'm having issues with, I suspect is
get_tree().get_root().find_node("HealthBar").value = health
What do I do to set the progressbar value to the health variable?
It turns out you must use the function
{Progress Bar}.set_value({value})
Basicly this is my first time using godot and writing code int it and i dont have any past expirience so i wanna says sorry in advance if the problem sounds very stupid.My movment is almost compleated and i have one last probelem that was if there is any way to make the engine knows when i colide with the ground i searched up a bit and i found the is_on_floor method but when i tyed to use it it gave me this eror(18,41) misplaced and but evrything seems fine to me please help if you can and also here is the code if it will be useful to find the problem.
extends KinematicBody2D
var velocity = Vector2(0,0)
const wspeed = 195
const GRAVITY = 30
var JUMPHIGHT = -600
func _physics_process(idle):
velocity.y = velocity.y + GRAVITY
if Input.is_action_pressed("right"):
velocity.x = wspeed
if Input.is_action_pressed("left"):
velocity.x = -wspeed
velocity.y = velocity.y + GRAVITY
if Input.is_action_just_pressed("up"): and is_on_floor():
velocity.y = JUMPHIGHT
move_and_slide(velocity,Vector2.UP)
The answer is simple. You have put : before and is_on_floor(). Also i want to change a little bit your code to be more efficient
extends KinematicBody2D
var velocity = Vector2(0,0)
const wspeed = 195
const GRAVITY = 30
var JUMPHIGHT = -600
func _physics_process(_delta):
if Input.is_action_pressed("right"):
velocity.x += wspeed
if Input.is_action_pressed("left"):
velocity.x =-wspeed
if Input.is_action_just_pressed("up") and is_on_floor():
velocity.y = JUMPHIGHT
velocity.y = velocity.y + GRAVITY
move_and_slide(velocity,Vector2.UP)
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'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.