Hi, I’m using Godot 4.3 and I’m updating my shootem up but I’m having a problem. I’d like to resize the elements on the screen. I’m testing my ship first but I’m not sure how to resize it all while keeping its base speed and position and limits so that it doesn’t go out of the screen. I’ve tested several scripts but without much success. When I resize the screen manually the ship changes position in x.
Test code for ship resizing.
extends Area2D
@export var speed: float = 300.0
@export var laser_scene: PackedScene
@export var laser_sound: AudioStream = preload("res://musiqueetson/amiral3000lasersound.wav")
@export var boom_texture: Texture = preload("res://alienminigames/boomtexture.png")
var can_fire: bool = true
var controls_enabled: bool = true # Contrôle local pour le traitement (mais on utilisera aussi le flag "frozen")
var frozen: bool = false # Nouvel indicateur pour forcer l'arrêt complet du traitement
var initial_y: float = 0.0 # Position Y initiale
# Variables pour la gestion du redimensionnement
var base_resolution := Vector2(1280, 720) # Résolution d'origine
var base_scale := Vector2(1.0, 1.0) # Échelle d'origine du sprite
var screen_size := Vector2.ZERO # Taille actuelle de l'écran
var left_boundary: float = 60 # Limite gauche à la résolution de base
var right_boundary: float = 1220 # Limite droite à la résolution de base
# Gestion des vies
var player_lives: int = 3
var life_sprites: Array = []
# Variables d'explosion
var is_exploding: bool = false
var original_texture: Texture # Pour sauvegarder le sprite normal
var original_scale: Vector2 # Pour sauvegarder l'échelle d'origine
func _ready() -> void:
# Tenter d'utiliser la méthode générique pour définir le mode pause (valeur 1 = STOP)
set("pause_mode", 1)
initial_y = position.y
if not laser_scene:
laser_scene = preload("res://lasertest.tscn")
var level_scene = get_tree().current_scene
life_sprites = [
level_scene.get_node("vievaisseau1"),
level_scene.get_node("vievaisseau2"),
level_scene.get_node("vievaisseau3")
]
original_texture = $Sprite2D.texture
original_scale = $Sprite2D.scale
base_scale = Vector2($Sprite2D.scale.x, $Sprite2D.scale.y) # Mémoriser l'échelle de base
connect("area_entered", Callable(self, "_on_area_entered"))
# Enregistrer la taille initiale de l'écran
screen_size = get_viewport_rect().size
# Se connecter au signal de redimensionnement de la fenêtre
get_tree().root.connect("size_changed", Callable(self, "_on_window_resize"))
# Adapter le vaisseau à la résolution initiale
adjust_to_screen_size()
print("Vaisseau prêt. Contrôles actifs =", controls_enabled, ", frozen =", frozen)
func _physics_process(delta: float) -> void:
# Si le vaisseau est figé, on ne fait rien.
if frozen:
return
if not is_exploding and controls_enabled:
var velocity: Vector2 = Vector2.ZERO
if Input.is_action_pressed("ui_left"):
velocity.x -= 1
if Input.is_action_pressed("ui_right"):
velocity.x += 1
if velocity.length() > 0:
# Adapter la vitesse à la résolution actuelle
var adjusted_speed = speed * (screen_size.x / base_resolution.x)
velocity = velocity.normalized() * adjusted_speed
position.x += velocity.x * delta
# Adapter les limites à la résolution actuelle
var scaled_left = left_boundary * (screen_size.x / base_resolution.x)
var scaled_right = right_boundary * (screen_size.x / base_resolution.x)
position.x = clamp(position.x, scaled_left, scaled_right)
# Maintenir la position Y fixe en bas de l'écran
position.y = initial_y
if Input.is_action_just_pressed("fire") and can_fire and controls_enabled:
fire_laser()
else:
# Débogage pour vérifier l'état
print("Vaisseau inactif: is_exploding =", is_exploding, ", controls_enabled =", controls_enabled)
func _on_window_resize() -> void:
screen_size = get_viewport_rect().size
adjust_to_screen_size()
func adjust_to_screen_size() -> void:
# Calculer le ratio par rapport à la résolution de base
var scale_ratio_x = screen_size.x / base_resolution.x
var scale_ratio_y = screen_size.y / base_resolution.y
# Appliquer l'échelle au sprite
$Sprite2D.scale = base_scale * min(scale_ratio_x, scale_ratio_y)
# IMPORTANT: Forcer la position Y en bas de l'écran (avec un décalage fixe)
# On suppose que le vaisseau est à ~90% de la hauteur de l'écran dans la conception originale
position.y = screen_size.y * 0.9
initial_y = position.y
# Redimensionner la collision si nécessaire
if has_node("CollisionShape2D"):
$CollisionShape2D.scale = Vector2(scale_ratio_x, scale_ratio_y)
# Ajuster la position du point d'émission des lasers
if has_node("Projectile"):
# Repositionner le point d'émission des lasers proportionnellement
var original_offset = $Projectile.position.y / base_resolution.y
$Projectile.position.y = original_offset * screen_size.y
func fire_laser() -> void:
var laser_instance = laser_scene.instantiate()
laser_instance.global_position = $Projectile.global_position
# Ajuster l'échelle du laser en fonction de la résolution
var scale_ratio = min(screen_size.x / base_resolution.x, screen_size.y / base_resolution.y)
if laser_instance.has_node("Sprite2D"):
laser_instance.get_node("Sprite2D").scale *= scale_ratio
if laser_instance.has_node("CollisionShape2D"):
laser_instance.get_node("CollisionShape2D").scale *= scale_ratio
get_tree().current_scene.add_child(laser_instance)
laser_instance.add_to_group("player_laser")
can_fire = false
laser_instance.connect("laser_removed", Callable(self, "_on_laser_removed"))
if laser_sound:
$AudioStreamPlayer.stream = laser_sound
print("Lecture du son du laser")
$AudioStreamPlayer.play()
else:
print("Aucun son de laser assigné!")
func _on_laser_removed() -> void:
can_fire = true
func _on_area_entered(area: Area2D) -> void:
if area.is_in_group("enemy_laser"):
if not is_exploding:
take_damage()
area.queue_free()
func take_damage() -> void:
if is_exploding:
return
if player_lives > 0:
player_lives -= 1
life_sprites[player_lives].hide()
print("Joueur touché ! Vies restantes :", player_lives)
start_explosion()
else:
die()
func start_explosion() -> void:
is_exploding = true
$Sprite2D.texture = boom_texture
$Sprite2D.scale = original_scale * 0.7 * (screen_size.x / base_resolution.x)
$ExplosionPlayer.play()
if not $ExplosionPlayer.is_connected("finished", Callable(self, "_on_explosion_finished")):
$ExplosionPlayer.connect("finished", Callable(self, "_on_explosion_finished"))
func _on_explosion_finished() -> void:
if player_lives == 0:
die()
else:
$Sprite2D.texture = original_texture
# Appliquer l'échelle adaptée à la résolution actuelle
var scale_ratio = min(screen_size.x / base_resolution.x, screen_size.y / base_resolution.y)
$Sprite2D.scale = base_scale * scale_ratio
is_exploding = false
func die() -> void:
get_tree().call_deferred("change_scene_to_file", "res://gameover.tscn")
# Fonction destinée à désactiver les contrôles du vaisseau.
# Cette fonction doit être appelée par le script de fin de niveau.
func disable_controls() -> void:
print("disable_controls() appelée - le vaisseau doit être figé.")
controls_enabled = false
can_fire = false
frozen = true # On active le flag pour stopper complètement _physics_process
# On désactive également les traitements de ce node (bien que le flag devrait suffire)
set_process(false)
set_physics_process(false)
set_process_input(false)
disable_all_lasers()
func disable_all_lasers() -> void:
for laser in get_tree().get_nodes_in_group("player_laser"):
laser.queue_free()
for laser in get_tree().get_nodes_in_group("enemy_laser"):
laser.queue_free()
The original code of the player’s ship without resizing
extends Area2D
@export var speed: float = 300.0
@export var laser_scene: PackedScene
@export var laser_sound: AudioStream = preload("res://musiqueetson/amiral3000lasersound.wav")
@export var boom_texture: Texture = preload("res://alienminigames/boomtexture.png")
var can_fire: bool = true
var controls_enabled: bool = true # Contrôle local pour le traitement (mais on utilisera aussi le flag "frozen")
var frozen: bool = false # Nouvel indicateur pour forcer l'arrêt complet du traitement
var initial_y: float = 0.0 # Position Y initiale
# Gestion des vies
var player_lives: int = 3
var life_sprites: Array = []
# Variables d'explosion
var is_exploding: bool = false
var original_texture: Texture # Pour sauvegarder le sprite normal
var original_scale: Vector2 # Pour sauvegarder l'échelle d'origine
func _ready() -> void:
# Tenter d'utiliser la méthode générique pour définir le mode pause (valeur 1 = STOP)
set("pause_mode", 1)
initial_y = position.y
if not laser_scene:
laser_scene = preload("res://lasertest.tscn")
var level_scene = get_tree().current_scene
life_sprites = [
level_scene.get_node("vievaisseau1"),
level_scene.get_node("vievaisseau2"),
level_scene.get_node("vievaisseau3")
]
original_texture = $Sprite2D.texture
original_scale = $Sprite2D.scale
connect("area_entered", Callable(self, "_on_area_entered"))
print("Vaisseau prêt. Contrôles actifs =", controls_enabled, ", frozen =", frozen)
func _physics_process(delta: float) -> void:
# Si le vaisseau est figé, on ne fait rien.
if frozen:
# Pour debug, on affiche une fois
# print("Vaisseau figé (frozen = true)")
return
if not is_exploding and controls_enabled:
var velocity: Vector2 = Vector2.ZERO
if Input.is_action_pressed("ui_left"):
velocity.x -= 1
if Input.is_action_pressed("ui_right"):
velocity.x += 1
if velocity.length() > 0:
velocity = velocity.normalized() * speed
position.x += velocity.x * delta
position.x = clamp(position.x, 60, 1220)
position.y = initial_y
if Input.is_action_just_pressed("fire") and can_fire and controls_enabled:
fire_laser()
else:
# Débogage pour vérifier l'état
print("Vaisseau inactif: is_exploding =", is_exploding, ", controls_enabled =", controls_enabled)
func fire_laser() -> void:
var laser_instance = laser_scene.instantiate()
laser_instance.global_position = $Projectile.global_position
get_tree().current_scene.add_child(laser_instance)
laser_instance.add_to_group("player_laser")
can_fire = false
laser_instance.connect("laser_removed", Callable(self, "_on_laser_removed"))
if laser_sound:
$AudioStreamPlayer.stream = laser_sound
print("Lecture du son du laser")
$AudioStreamPlayer.play()
else:
print("Aucun son de laser assigné!")
func _on_laser_removed() -> void:
can_fire = true
func _on_area_entered(area: Area2D) -> void:
if area.is_in_group("enemy_laser"):
if not is_exploding:
take_damage()
area.queue_free()
func take_damage() -> void:
if is_exploding:
return
if player_lives > 0:
player_lives -= 1
life_sprites[player_lives].hide()
print("Joueur touché ! Vies restantes :", player_lives)
start_explosion()
else:
die()
func start_explosion() -> void:
is_exploding = true
$Sprite2D.texture = boom_texture
$Sprite2D.scale = original_scale * 0.7
$ExplosionPlayer.play()
if not $ExplosionPlayer.is_connected("finished", Callable(self, "_on_explosion_finished")):
$ExplosionPlayer.connect("finished", Callable(self, "_on_explosion_finished"))
func _on_explosion_finished() -> void:
if player_lives == 0:
die()
else:
$Sprite2D.texture = original_texture
$Sprite2D.scale = original_scale
is_exploding = false
func die() -> void:
get_tree().call_deferred("change_scene_to_file", "res://gameover.tscn")
# Fonction destinée à désactiver les contrôles du vaisseau.
# Cette fonction doit être appelée par le script de fin de niveau.
func disable_controls() -> void:
print("disable_controls() appelée - le vaisseau doit être figé.")
controls_enabled = false
can_fire = false
frozen = true # On active le flag pour stopper complètement _physics_process
# On désactive également les traitements de ce node (bien que le flag devrait suffire)
set_process(false)
set_physics_process(false)
set_process_input(false)
disable_all_lasers()
func disable_all_lasers() -> void:
for laser in get_tree().get_nodes_in_group("player_laser"):
laser.queue_free()
for laser in get_tree().get_nodes_in_group("enemy_laser"):
laser.queue_free()