Motion.y not working when making func _on_Area2D_body_entered(body):

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Sidoku

I’m making a game for a school project when I stumbled upon an error. When I wrote a function that makes Nodes collide with the water physics that i’ve implemented, the variable “speed = body.motion.y * motion_factor” didn’t work and the Debugger said “Invalid get index ‘motion’ (on base:‘StaticBody2D’).”.

func _on_Area2D_body_entered(body):

if body == collided_with:
	return

collided_with = body


var speed = body.motion.y * motion_factor
emit_signal("splash",index,speed)




pass # Replace with function body.

I watched a youtube tutorial on how to make water physics and basically repeated the way he did it: https://www.youtube.com/watch?v=RXIRkou021U
As he was making that function at 21:51, there was no error.

What did I do wrong? Was there something I missed? Please let me know, thanks.

:bust_in_silhouette: Reply From: Marco-

It is pretty hard to grasp the context from so little code however this time it is enough.

The error message states that you are calling for motion on body which does not exist. Why doesn’t it exist? It seems like you have chosen the wrong node for your object. It is a StaticBody2D which is, as the name states, static. That means it is not intended to move around. Therefor it has no motion. Try changing its type to a KinematicBody2D instead and try again.

To add more context on the matter, I was using a Node2D on that script I posted and signalled an Area2D to the Node2D to make the function.

This is the full script from Node2D:

extends Node2D

var velocity = 0

var force = 0

var height = 0

var target_height = 0

onready var collision = $Area2D/CollisionShape2D

var index = 0 

var motion_factor = 0.02

var collided_with = null

signal splash

func water_update(spring_constant, dampening):
	
	height = position.y
	
	var x = height - target_height
	
	var loss = -dampening * velocity
	
	
	force = - spring_constant * x + loss
	
	velocity += force
	
	position.y += velocity
	pass

func initialize(x_position,id):
	height = position.y
	target_height = position.y
	velocity = 0
	position.x = x_position
	index = id

func set_collision_width(value):
	
	var extents = collision.shape.get_extents()
	var new_extents = Vector2(value/2, extents.y)
	collision.shape.set_extents(new_extents)
	
	pass


func _on_Area2D_body_entered(body):
	
	
	if body == collided_with:
		return
	
	collided_with = body
	
	
	var speed = body.motion.y * motion_factor
	emit_signal("splash",index,speed)
	
	
	
	
	pass # Replace with function body.

Problem is, there isn’t any StaticBody2D located in the scene. There’s only Node2D as a root, and inside there’s a Sprite, Area2D and a CollisionShape2D inside the Area2D Child Node.

Is there something else I can do instead? Is there something I should write in the script to fix this?

Sidoku | 2023-03-15 21:03

Ok so you have to look at the Object that is colliding with your Area2D. That is what is send as body to your _on_Area2D_body_entered(body). Has this object a script attached? Is the property motion defined?

Marco- | 2023-03-15 21:43

The object I was planning to collide with Area2D is a KinematicBody2D. It has gravity and motion:

extends KinematicBody2D

var gravity = 35

var motion = Vector2.ZERO

var max_speed = 450

func _physics_process(delta):
	
	motion.y += gravity
	motion.y = clamp(motion.y, -max_speed, max_speed)
	motion = move_and_slide(motion)

func initialize(pos):
	global_position = pos

I have some other scripts which is also for the water physics;

This is for the water body:

extends Node2D

export var k = 0.015
export var d = 0.03
export var spread = 0.0002

var springs = []
var passes = 8

export var distance_between_springs = 32
export var spring_number = 6

var water_length = distance_between_springs * spring_number

onready var water_spring = preload("res://physics/water_spring.tscn")

export var depth = 1000
var target_height = global_position.y
var bottom = target_height + depth

onready var water_polygon = $Water_Polygon

onready var water_border = $Water_Border
export var border_thickness = 1.1

func _ready():
	water_border.width = border_thickness
	
	spread = spread / 1000
	
	for i in range(spring_number): 
		var x_position = distance_between_springs * i
		var w = water_spring.instance()
		add_child(w)
		springs.append(w)
		w.initialize(x_position, i)
		w.set_collision_width(distance_between_springs)
		w.connect("splash", self, "splash")
	
	splash(2,5)

func _physics_process(_delta):
	for i in springs:
		i.water_update(k,d)
	
	var left_deltas = []
	var right_deltas = []
	
	for _j in range(passes):
		
		for _i in range (springs.size()):
			left_deltas.append(0)
			right_deltas.append(0)
			pass
		
		for i in range(springs.size()):
			if i > 0:
				left_deltas[i] = spread * (springs[i].height - springs[i-1].height)
				springs[i-1].velocity += left_deltas[i]
			if i < springs.size()-1:
				right_deltas[i] = spread * (springs[i].height - springs[i+1].height)
				springs[i+1].velocity += right_deltas[i]
	new_border()
	draw_water_body()


func draw_water_body():
	
	var curve = water_border.curve
	
	var points = Array(curve.get_baked_points())
	
	var water_polygon_points = points
	
	
	var first_index = 0
	var last_index = water_polygon_points.size()-1
	
	
	water_polygon_points.append(Vector2(water_polygon_points[last_index].x, bottom))
	water_polygon_points.append(Vector2(water_polygon_points[first_index].x, bottom))
	
	water_polygon_points = PoolVector2Array(water_polygon_points)
	
	water_polygon.set_polygon(water_polygon_points)
	
	pass

func new_border():
	
	var curve = Curve2D.new().duplicate()
	
	var surface_points = []
	for i in range(springs.size()):
		surface_points.append(springs[i].position)
	
	for i in range(surface_points.size()):
		curve.add_point(surface_points[i])
	
	water_border.curve = curve
	water_border.smooth(true)
	water_border.update()
	
	
	pass

func splash(index, speed):
	if index >= 0 and index < springs.size():
		springs[index].velocity += speed
	
	pass

And this is for the Water Line Path:

class_name SmoothPath
extends Path2D

export(float) var spline_length = 100
export(bool) var _smooth setget smooth
export(bool) var _straighten setget straighten
export(Color) var color = Color(1,1,1,1)
export(float) var width = 8

func straighten(value):
	if not value: return
	for i in range(curve.get_point_count()):
		curve.set_point_in(i, Vector2())
		curve.set_point_out(i, Vector2())

func smooth(value):
	if not value: return

	var point_count = curve.get_point_count()
	for i in point_count:
		var spline = _get_spline(i)
		curve.set_point_in(i, -spline)
		curve.set_point_out(i, spline)

func _get_spline(i):
	var last_point = _get_point(i - 1)
	var next_point = _get_point(i + 1)
	var spline = last_point.direction_to(next_point) * spline_length
	return spline

func _get_point(i):
	var point_count = curve.get_point_count()
	i = wrapi(i, 0, point_count - 1)
	return curve.get_point_position(i)

func _draw():
	var points = curve.get_baked_points()
	if points:
		draw_polyline(points, Color.black, 8, true)

Since the object that I’m colliding with is a KinematicBody2D, should I change it to something else or not? I’m pretty new to this sort of thing so not sure if showing the other scripts help or not.

Sidoku | 2023-03-16 08:05

Ok, the problem is still that the engine is complaining that a colliding body doesn’t have the motion attribute. Go over your project and look whether there are other bodies or even extra colliders on your player that shouldn’t be there. Also check your collision layers maybe any of your object is set to the wrong layer.
If you still have trouble finding the culprit try printing out the name of the colliding body like this:

func _on_Area2D_body_entered(body):


if body == collided_with:
    return

collided_with = body
print(body.name)

var speed = body.motion.y * motion_factor
emit_signal("splash",index,speed)




pass # Replace with function body.

The print should show you the name of the object before the problem occurs.

Marco- | 2023-03-16 21:05

Good News. I figured out where the static body were located. When I wrote “print(body.name)” into the script, then I found where the staticbody was. It was In my other world scene. The water was 1 pixel next to the collison so it became an error. I just pushed it away from the staticbody2d collision and now everything works. Now the water moves when it meets a kinematicbody. Brilliant. Thanks for the help and have a good day!

Sidoku | 2023-03-17 10:04