Найти в Дзене
Indie Alone

Как я делал простую игру №4(разбираем сцену игрока)

Итак sprite это целый spritesheets, то есть несколько анимаций на одном спрайте. Дальше все по старой схеме Animation Player(анимации персонажа), Collision Shape (коллизия персонажа). Audio Listener не помню зачем я его сюда воткнул(что то тестировал), теперь какой то баг все звуки теперь только в центре локации, если отходить от центра звуки все тише и тише. Sound - все звуки тут которые привязаны к персонажу. Спрайт pricel отвечает за спрайт прицела . Кстати вместе DeepSeek сделали разброс пуль и прицел увеличивается когда разброс увеличивается. Но когда делал с нейросетью, то какие то несложные механики еще все хорошо, но стоит только проекту увеличиться, то проект начинается сыпаться и исправляешь какие то моменты и в итоге делаешь своими руками так как надо. Я все таки решил что не буду пользоваться нейросетью. TimerLight-это таймер вспышки от выстрела. PointLight-сам свет от выстрела. Marker - с помощью этого нода указываю начальную точку для патронов. Bullet Empty-пустой

Итак sprite это целый spritesheets, то есть несколько анимаций на одном спрайте.

Дальше все по старой схеме Animation Player(анимации персонажа), Collision Shape (коллизия персонажа).

Audio Listener не помню зачем я его сюда воткнул(что то тестировал), теперь какой то баг все звуки теперь только в центре локации, если отходить от центра звуки все тише и тише.

Sound - все звуки тут которые привязаны к персонажу.

Спрайт pricel отвечает за спрайт прицела . Кстати вместе DeepSeek сделали разброс пуль и прицел увеличивается когда разброс увеличивается. Но когда делал с нейросетью, то какие то несложные механики еще все хорошо, но стоит только проекту увеличиться, то проект начинается сыпаться и исправляешь какие то моменты и в итоге делаешь своими руками так как надо. Я все таки решил что не буду пользоваться нейросетью.

TimerLight-это таймер вспышки от выстрела.

PointLight-сам свет от выстрела.

Marker - с помощью этого нода указываю начальную точку для патронов.

-2

Bullet Empty-пустой нод в котором собираются все отстреленные патроны.

А дальше пошли кулдауны для выстрела и перезарядки пистолета.

Может кому то пригодиться сам скрипт игрока. Этот скрипт еще в процессе разработки, что то там лишнее что то нужное.

_______________________________________________________

extends CharacterBody2D

var speed_forward = 600 # Быстрая скорость вперёд

var speed_backward = 500 # Медленная скорость назад

var current_speed = 500.0 # Текущая скорость (для плавности)

var acceleration = 30 # Плавность изменения скорости

var can_sprint=true

var stamina=100

var max_stamina=100

var recovery_stamina=0.5

var rashod_stamina=1

#var speed = 400

var current_spread = 0.0

var max_spread = deg_to_rad(15)

var spread_recovery_speed = 0.3

var spread_increase_per_shot = deg_to_rad(10)

var can_shot = true

var reload_pistols =false

var degrees_per_sec = 540

@onready var crosshair = $pricel

@onready var bullet_tscn = preload("res://scene/laser.tscn")

func _ready() -> void:
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)

func _physics_process(delta: float) -> void:
handle_movement(delta)
handle_rotation(delta)
handle_shooting()
update_spread(delta)
move_and_slide()
sprint()
stamina_sprint(delta)
Globals.stamina=stamina
update_crosshair()
hand_reload()

func sprint():
if Input.is_action_pressed("shift")&& can_sprint==true:
speed_forward=1000
speed_backward=800
$AnimationPlayer.play("sprint")
else:
speed_forward=600
speed_backward=500

func stamina_sprint(delta):
var direction=Input.get_vector("left", "right", "forwrd", "back")
# Трата стамины при спринте и движении
if Input.is_action_pressed("shift") && can_sprint && direction != Vector2.ZERO:
stamina -= rashod_stamina * delta * 60 # Нормализация к FPS
stamina = max(stamina, 0) # Не даем уйти ниже 0

# Автоматическое восстановление
else:
var recovery_multiplier = 12.0 if direction == Vector2.ZERO else 1.0 # Быстрее восстанавливаем при стоянии
stamina += recovery_stamina * recovery_multiplier * delta * 60
stamina = min(stamina, max_stamina) # Не даем превысить максимум

# Управление возможностью спринта
if stamina <= 0:
can_sprint = false
elif stamina >= max_stamina * 0.3: # Порог для возобновления спринта
can_sprint = true

func handle_movement(delta):
var direction = Input.get_vector("left", "right", "forwrd", "back")

if direction.length() > 0:
var move_angle = direction.angle()
var face_angle = rotation
var angle_diff = wrapf(move_angle - face_angle, -PI, PI)

var is_moving_forward = abs(angle_diff) < PI / 2
var target_speed = speed_forward if is_moving_forward else speed_backward

# ИЗМЕНЕНО: Улучшенное плавное изменение скорости
current_speed = lerp(current_speed, float(target_speed), acceleration * delta * (2.0 if is_moving_forward else 1.5)) # Быстрее ускоряемся вперед

velocity = direction.normalized() * current_speed # ДОБАВЛЕНО: normalize для сохранения скорости по диагонали
else:
# ИЗМЕНЕНО: Плавное замедление при остановке
current_speed = lerp(current_speed, 0.0, acceleration * delta * 2)
velocity = velocity.normalized() * current_speed if current_speed > 10 else Vector2.ZERO

if velocity == Vector2.ZERO:
$AnimationPlayer.play("idle")
$sound/foot.play()
else:
$AnimationPlayer.play("walk")

func handle_rotation(delta):
var mouse_direction = (get_global_mouse_position() - global_position).normalized()
var target_angle = mouse_direction.angle()

# Более точный расчет угла поворота
var angle_diff = wrapf(target_angle - rotation, -PI, PI)
var rotation_step = deg_to_rad(degrees_per_sec) * delta

if abs(angle_diff) > rotation_step:
rotation += sign(angle_diff) * rotation_step
else:
rotation = target_angle

crosshair.position = get_global_mouse_position()

func handle_shooting():
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) && can_shot==true && reload_pistols==false:
# Логика стрельбы с разбросом
var fire_direction = (crosshair.position - global_position).normalized()
fire_direction = fire_direction.rotated(randf_range(-current_spread, current_spread))


$timerLight.start()
$PointLight2D.enabled=true
var bullet = bullet_tscn.instantiate()
bullet.position = $Marker2D.global_position
bullet.rotation = fire_direction.angle()+80
bullet.direction = fire_direction
$bullet_empty.add_child(bullet)
$sound/shot.play()
Globals.amountBullet-=1

current_spread = min(current_spread + spread_increase_per_shot, max_spread)
can_shot = false
$shotCooldown.start()
if Globals.amountBullet==0:
reload_p()

func update_spread(delta):
current_spread = move_toward(current_spread, 0, spread_recovery_speed * delta)

func _on_shot_timer_timeout() -> void:
can_shot = true

func _on_timer_light_timeout() -> void:
$PointLight2D.enabled=false

func update_crosshair():
$pricel.scale.x=max(4,current_spread*40)
$pricel.scale.y=max(4,current_spread*40)

func reload_p():
$sound/reloadPistolsSound.play()
$reloadPistos.start()
reload_pistols=true

func _on_reload_pistos_timeout() -> void:
Globals.amountBullet=10
reload_pistols=false

func hand_reload():
if Input.is_action_just_pressed("reload_p"):
reload_p()

func _on_shot_cooldown_timeout() -> void:
can_shot = true