Godot Version
4
Question
Hello. I have a problem. I’m making a 2D soccer game (bird view) and I’m creating a CPU that calculates how to kick the ball so that it scores a goal. This works by predicting the ball’s position from 0.6, 0.7, 0.8 … 2.0 seconds in the future. So, if the ball is too far away, the CPU won’t move because it detects that he won’t achieve the certain position to kick the ball accurately. That’s why I want to make the CPU move directly to the ball if it detects that he is not able to kick the ball. The problem is that I use a for to calculate the balls position in every time in seconds in the future. If I want to move the CPU directly to the ball when the CPU says that he can’t kick the ball, the CPU won’t move constantly because it waits for the for to finish.
Was my explanation clear? Let me know if more details are needed.
extends RigidBody2D
var functionCallable=true
# Radius of the bot's collision = 24.69
# Radius of the ball's collision = 17.06
var AOPPSWS=111.06275 # Amount Of Pixels Per Second Walk Speed - En un segundo avanza 111.06275
@export var walkSpeed=int()
@export var turboSpeed=int()
@export var hyperTurboSpeed=float()
@export var turboRemaining=float()
var direction=Vector2()
var velocity=Vector2()
var BTBV #Bot to Ball Vector
@export var MDTT=int() #La distancia máxima entre el bot y la pelota para usar el Turbo-- Max Distance To Turbo
@export var mDTT=int() #La distancia minima entre el bot y la pelota para usar el Turbo-- Min Distance To Turbo
@export var MDTHT=int() #La distancia máxima entre el bot y la pelota para usar el HyperTurbo-- Max Distance To HyperTurbo
@export var player: RigidBody2D
@export var ball: RigidBody2D
var ballFP=Vector2(0,0) # Ball Future Position
@onready var bot_2_ray_cast = $Bot2RayCast
@onready var bot_2_ray_cast_pts = $Bot2RayCastPTS
@export var upCorner: Node2D
@export var downCorner: Node2D
@export var DTBBS=float() #Distance To Ball Before Shot
@export var timePrediction: Array=[
0.6, 0.7, 0.8, 0.9, 1.0,
1.1, 1.2, 1.3, 1.4, 1.5,
1.6, 1.7, 1.8, 1.9, 2.0]
var move=true
#Obtiene la magnitud de un vector dado
func GetMagnitude(vector):
var distance=sqrt(vector.x**2+vector.y**2)
return distance
#Obtiene el vector normalizado del vector dado
func hypotenuseNormalized(vector):
var hyp=sqrt(vector.x**2+vector.y**2)
var vectorNormalized=vector/hyp
return vectorNormalized
func FuturePositionBounce():
var collisionPoint=ball.ball_ray_cast.get_collision_point()
var ballVelocityNormalized=hypotenuseNormalized(ball.linear_velocity)
# Collision Point To Ball Position Magnitude
var CPTBPM = GetMagnitude(ball.position-collisionPoint)
# The remaining part of the raycast after the wall
var magnitudeRemaining=GetMagnitude(ball.ball_ray_cast.target_position)-CPTBPM
var wallNormal= ball.ball_ray_cast.get_collision_normal()
var unitVector = GetOpositeUnitVector(ballVelocityNormalized,wallNormal)
var localballFP=collisionPoint+unitVector*magnitudeRemaining
# print(localballFP)
ball.ball_ray_cast.target_position=localballFP-ball.position
return localballFP
func GetOpositeUnitVector(ballVelocityNormalized,wallNormal):
if wallNormal.x==1:
ballVelocityNormalized.x*=-1
return ballVelocityNormalized
elif wallNormal.x==-1:
ballVelocityNormalized.x*=-1
return ballVelocityNormalized
elif wallNormal.y==1:
ballVelocityNormalized.y*=-1
return ballVelocityNormalized
elif wallNormal.y==-1:
ballVelocityNormalized.y*=-1
return ballVelocityNormalized
func _physics_process(delta):
bot_2_ray_cast.global_rotation=0
bot_2_ray_cast_pts.global_rotation=0
if Input.is_action_just_pressed("ui_focus_next"):
position=Vector2(893.952,364.697)
if functionCallable==true:
hitBall()
functionCallable=false
# if move==true:
# if get_parent().get_node("Ball")!=null:
# BTBV=ball.global_position-global_position
# # Soluciona que el bot atrape la pelota contra la pared
# #Si su velocidad es poca (Porque su velocidad es mínima al encerrar a la pelota)
# if GetMagnitude(linear_velocity)<3.1:
# #Mientras su distancia contra la pelota no sea mayor a 100 px
# while GetMagnitude(BTBV)<100:
# #Se mueve para el lado opuesto con respecto BTBV
# apply_central_force(-velocity)
# #Para que no deje de responder se espera un poco
# await get_tree().create_timer(0.01).timeout
func hitBall():
# ballFP= ball future position
for time in timePrediction:
ballFP=ball.position+(ball.linear_velocity*time)
ball.ball_ray_cast.target_position=ballFP-ball.position
await get_tree().create_timer(0.0000000001).timeout
if ball.ball_ray_cast.is_colliding():
if ball.ball_ray_cast.get_collider().is_in_group("Player"):
break
elif ball.ball_ray_cast.get_collider().get_parent().name=="WallContainer":
ballFP=FuturePositionBounce()
# Down Corner To Ball Future Position Vector
var DCTBFPV=ballFP-downCorner.position
# Up Coner To Ball Future Position Vector
var UCTBFPV=ballFP-upCorner.position
var maxAngleToShot=hypotenuseNormalized(DCTBFPV)
var minAngleToShot=hypotenuseNormalized(UCTBFPV)
var randomAngleToShotX=randf_range(minAngleToShot.x,maxAngleToShot.x)
var randomAngleToShotY=randf_range(minAngleToShot.y,maxAngleToShot.y)
var randomAngleToShot=Vector2(randomAngleToShotX,randomAngleToShotY)
var positionToShot=ballFP+randomAngleToShot*DTBBS # Distance To Ball Before Shot
bot_2_ray_cast.target_position=ballFP-position
if bot_2_ray_cast.is_colliding():
if bot_2_ray_cast.get_collider().name!="Ball":
break
bot_2_ray_cast_pts.target_position=positionToShot-position
if bot_2_ray_cast_pts.is_colliding():
break
# Se fija si al distancia que puede recorrer el bot en función de time es suficiente para llegar a positionToShot
if GetMagnitude(positionToShot-position)<AOPPSWS*time*0.76:
var timer2=2.2
while positionToShot.distance_to(position)>2:
var direction=hypotenuseNormalized(positionToShot-position)
apply_central_force(walkSpeed*direction)
await get_tree().create_timer(get_physics_process_delta_time()).timeout
timer2-=get_process_delta_time()
if timer2<=0:
break
linear_velocity=Vector2(0,0)
position=positionToShot
var timer1=2.2
while true:
if GetMagnitude(ball.position-ballFP)/GetMagnitude(ball.linear_velocity)<=0.5934353098:
var timer=0.3
while timer>0:
apply_central_force(hyperTurboSpeed*hypotenuseNormalized(ballFP-position))
timer-=get_physics_process_delta_time()
await get_tree().create_timer(get_physics_process_delta_time()).timeout
# apply_central_impulse(walkSpeed*hypotenuseNormalized(ballFP-position))
break
await get_tree().create_timer(0.00001).timeout
timer1-=get_process_delta_time()
if timer1<=0:
break
break
functionCallable=true
That’s all my code but the important thing is the function hitBall(). If after time=2 the bot says that it can’t kick the ball, I want to move the bot directly to the ball’s position but if I do that it happens that the bot moves in intervals.