this is my example code i also have Debug (visible collision shapes on) and I still can't see anything in game, my goal is to add a circle collision shape and be able to see in game
func create_area(mouse_position):
var position = mouse_position
var _shared_Area = Area2D.new()
var _circle_shape = Physics2DServer.circle_shape_create()
#_circle_shape.visible = true
Physics2DServer.shape_set_data(_circle_shape, 128)
print(" physics server ",Physics2DServer.ray_shape_create())
Physics2DServer.area_add_shape(_shared_Area.get_rid(), _circle_shape, xform )
Physics2DServer.area_set_collision_layer(_shared_Area, 1)
Physics2DServer.area_set_collision_mask(_shared_Area, 1)
Physics2DServer.area_set_monitorable(_shared_Area, true)
Physics2DServer.area_set_space(_shared_Area, get_world_2d().space)
Physics2DServer.area_set_transform(_shared_Area, Transform2D(1.0 , position))
Physics2DServer.area_set_area_monitor_callback(_shared_Area, self, 'debug_overlap')
func debug_overlap(_1,_2,_3,_4,_5):
print('overlap!!')
Related
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.
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.
I have a "parent" player scene, and I inherit scenes for each player. The parent player scene has a camera. When the game switches between players, one player turns off its camera, and the other player turns its camera on:
if state != State.ACTIVE:
# If this player is becoming active, also
# set camera current
state = State.ACTIVE
camera.current = true
else:
# If player is not becoming active,
# disable this players camera
camera.current = false
But players can be in different positions, so the camera "jumps" from one to the other. Can we do something more sophisticated, like set the new camera to the current position so the smooth setting can be used to handle the transition?
One idea is to do get_viewport().get_camera() to find the current position of the camera to try and sync the position of the current camera with the new camera that is about to turn on, but appears to not work for 2D scenes. CF: https://github.com/godotengine/godot/pull/38317
Sadly, as you found out, there is no way to get the current Camera2D in Godot 3.x. And you found the pull request that adds the feature to Godot 4.0.
What I'm going to suggest is to have one sole Camera2D, so that one is always the current one. And you can define Position2D inside your scenes that can serve as interpolation targets to move the Camera2D.
I have an script that I think will be useful for you (I made it to be RemoteTransform2D but backwards, it does push a transform, it pulls it), I call it anchor_transform_2d.gd:
tool
class_name AnchorTransform2D
extends Node2D
export var anchor_path:NodePath setget set_anchor_path
export var reference_path:NodePath setget set_reference_path
export var set_local_transform:bool
export(int, FLAGS, "x", "y") var translation_mode:int
export(int, FLAGS, "x", "y") var scale_mode:int
export var rotation_mode:bool
var _anchor:Node2D
var _reference:Node2D
func _physics_process(_delta: float) -> void:
if not is_instance_valid(_anchor) or Engine.editor_hint:
set_physics_process(false)
return
#INPUT
var input := _anchor.global_transform
if is_instance_valid(_reference):
input = _reference.global_transform.affine_inverse() * input
#TRANSLATION
var origin := Vector2 (
input.origin.x if translation_mode & 1 else 0.0,
input.origin.y if translation_mode & 2 else 0.0
)
#ROTATION
var angle := 0.0
if rotation_mode:
angle = input.get_rotation()
#SCALE
var source_scale = input.get_scale()
var scaling := Vector2 (
source_scale.x if scale_mode & 16 else 1.0,
source_scale.y if scale_mode & 32 else 1.0
)
#RESULT
_set_target_transform(
Transform2D(angle, origin) * Transform2D.IDENTITY.scaled(scaling)
)
func set_anchor_path(new_value:NodePath) -> void:
anchor_path = new_value
if not is_inside_tree():
yield(self, "tree_entered")
_anchor = get_node_or_null(anchor_path) as Node2D
set_physics_process(is_instance_valid(_anchor) and not Engine.editor_hint)
if Engine.editor_hint:
update_configuration_warning()
func set_reference_path(new_value:NodePath) -> void:
reference_path = new_value
if not is_inside_tree():
yield(self, "tree_entered")
_reference = get_node_or_null(reference_path) as Node2D
func _set_target_transform(new_value:Transform2D) -> void:
if set_local_transform:
transform = new_value
return
global_transform = new_value
func _get_configuration_warning() -> String:
if _anchor == null:
return "Anchor not found"
return ""
Add this attached to a Node2D in anchor_path set the target from which you want to pull the transform (anchor_path is a NodePath, you can set to it something like $Position2D.get_path()). And set what do you want to copy (you can choose any combination of position x, position y, scaling x, scaling y, and rotation). Then put the Camera2D as a child of the AnchorTransform2D, and set smoothing_enabled to true.
Rundown of the properties:
anchor_path: A NodePath pointing to the Node2D you want to pull the transform from.
reference_path: A NodePath pointing to a Node2D used to make the transform relative (you will be taking the transform of what you put in anchor_path relative to what you put in reference_path).
set_local_transform: Set to true if you want to pull the transform as local (relative to the parent of AnchorTransform2D), leave to false to set the global transform instead.
translation_mode: Specifies if you are going to copy the x position, y position, both or neither.
scale_mode: Specifies if you are going to copy the x scale, y scale, both or neither.
rotation_mode: Specifies if you are going to copy the rotation or not.
The only reason the script is a tool script is to give you a warning in the editor if you forgot to set the anchor_path.
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.
I'm developing my first game with SpriteKit and I need to shoot a laser beam. I don't know how to do this since I don't know the size of the laser sprite, does it have to be with size of the screen height and crop the image when a collision is detected? can anyone point me to the right directions please? Have no idea about this XD
Thanks for your comments :D
This could be done by line-of-sight detection system described here in the section Searching for physics bodies :
Useful method would be enumerateBodiesAlongRayStart:end:usingBlock: from SKPhysicsWorld class which enumerates all the physics bodies in the scene that intersect a ray.
Basically you have to set start point and search for end point using the method above.When you know where is the intersection point(end point of laser beam) you can easily draw it.
This is a way late response, but I've got a really nice solution. Here's what it looks like (Swift 3):
In my code I'm calling this when I rotate the node I want the laser to shoot out of:
self.laser = SKShapeNode()
laser.lineWidth = 6
laser.glowWidth = 8
laser.strokeColor = .red
let _ = isTargetVisibleAtAngle(startPoint: startPoint, angle: selectedBeam!.zRotation + (CGFloat.pi / 2), distance: frame.size.height)
And this is the method. Obviously you put in whatever angle you want. The "foundOne" thing is so that it stops on the first object if that ray crosses through multiple targets
func isTargetVisibleAtAngle(startPoint: CGPoint, angle: CGFloat, distance: CGFloat) -> Bool {
let rayStart = startPoint
let rayEnd = CGPoint(x: rayStart.x + distance * cos(angle),
y: rayStart.y + distance * sin(angle))
let path = CGMutablePath()
path.move(to: rayStart)
path.addLine(to: rayEnd)
laser.path = path
var foundOne = false
let _ = physicsWorld.enumerateBodies(alongRayStart: rayStart, end: rayEnd) { (body, point, vector, stop) in
if !foundOne {
foundOne = true
let p = CGMutablePath()
p.move(to: rayStart)
p.addLine(to: point)
self.laser.path = p
}
}
return false
}