GodotФорумДемонстрируем наработки

Godot4 :: Царство и капитаны (2 стр)

Страницы: 1 2 3 Следующая »
#15
21:15, 23 мая 2024

Я пока буксую ...

Люди слухают музон..
https://www.youtube.com/watch?v=ORuMA7C0j3A

Люди что-то делают..

3D Action RPG Remastered Tutorial in Godot 4.2! 8 Hour Free Course!
https://www.youtube.com/watch?v=1m6UXCtw2Pg
Мистер "Coding Quests" учит - как сделать игру (видюшка на 8 часов).

Первые 20 минут - заряжаем набор три-мерных тайлов для GridMap.
Модельки взяты отсюда..
https://kaylousberg.itch.io/kaykit-adventurers
Под видео, есть подробный набор линков на ресурсы.

#16
23:25, 23 мая 2024

slatazan
А я ведь надо признаться, хоть мало что понимаю из твоих сообщений, но вдохновился твоей игрой.

И делаю походовую стратегию. Правда у меня сайфай.
Хотя тоже, на уровне мин прототипа подвис. Времени совсем нет.

#17
0:53, 24 мая 2024

Der FlugSimulator
// делаю походовую стратегию
Если есть тема - напечатай линк.
Если есть демо - могу поиграть-покритиковать.

Вот есть пошаговая игра..
Примерно с 10-й минуты идёт казуальная игра - вроде-бы, игроку понравилось.
https://www.youtube.com/watch?v=X2MYkCyQn7c
Как-минимум с 20-й по 30-ю минуту - можно посмотреть на трудный стартовый бой.

#18
11:55, 24 мая 2024

slatazan
> Если есть тема - напечатай линк.

Пока нет. Я вначале начал делать хексагонами, как у тебя, потом немного переделал.
Потом переделал еще и с очередностью ходов, создав тему.
В общем у меня пока всё в зачаточной стадии и даже не совсем собирается.

Но как только будет - сразу создам тему.

#19
23:38, 11 июня 2024

Кое-как собрал скрипт _игрока - некие базовые возможности.

ESC переключает курсор, и если курсор виден, то клик для указания _куда_бежать,
по полигонам нав-меша. Если не видно курсора - жмём кнопки, чтобы двигать
персонажа - ему мешаются ноды колизий, которые принимали участие в запеканиях
двух слоёв нав-меша (где пехота проходит, и где низкий полёт пролетает).

Надо напечатать код на форум, для сохранки :)

extends CharacterBody3D

# player
# ../Shape3D
# ../Knight[ ... AnimationPlayer]
# ../camera_base.h.v.Camera3D
# ../AnimationTree
# ../NavigationAgent3D

@onready var anim_tree = get_node( "AnimationTree")
@onready var playback = anim_tree.get( "parameters/playback")
@onready var pl_mesh = get_node( "Knight")
@onready var pl_mesh_cape = get_node( "Knight/Rig/Skeleton3D/Knight_Cape")
@onready var camera_h = get_node( "camera_base/h")
@onready var nav: NavigationAgent3D = get_node("NavigationAgent3D")


@export var gravity := 9.8
@export var jump_force: int = 9
@export var walk_speed: int = 8
@export var run_speed: int = 12


# state machine
var is_atk: bool = false # атакуем
var is_walk: bool = false
var is_run: bool = false # бежым
var is_death: bool = false # подыхаем

# anim Node Names
var nod_nam_idle : String = "Idle"
var nod_nam_walk : String = "Walk"
var nod_nam_run : String = "Run"
var nod_nam_jump : String = "Jump"
var nod_nam_atk1 : String = "Attack1"
var nod_nam_death : String = "Death_A"


# ---
const RAY_LENGTH = 1000
const JUMP_VELOCITY = 5.0


var movement_speed := 4.0 # сюда ставить скорость бега, или скорость шага.

var try_find_way := false
var test_is_fly := false
var klik_mouse_mode := 0

var ray_ignor_scn = null # test
var pillar_gltf = null




func _ready() -> void:
  nav.velocity_computed.connect( Callable( _on_velocity_computed))
  #ray_ignor_scn = get_node( "... /GridMap2")
  #pillar_gltf = get_node( "... /pillar/StaticBody3D")

  if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
    klik_mouse_mode = 1
#---------


func _on_velocity_computed( safe_velocity: Vector3):
  velocity = safe_velocity
  move_and_slide()
#---------



func _physics_process( delta):
  
  var on_floor = is_on_floor() # узнать - есть-ли контакт, с поверхностью.
  if not on_floor: # Если персонаж подвис, тогда..
    velocity.y -= gravity * delta # Add the gravity. // гравитация давит.

  #if not is_death -> pass

  if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
    if not klik_mouse_mode:
      klik_mouse_mode = 1
      # первый кадр, после переключения - сбросим старый путь..
      if not nav.is_navigation_finished():
        nav_target( self.position) # чтобы обнулить пре-поиск.
    #
    move_klik( delta) # тэстируем поинт-клик
  else:
    klik_mouse_mode = 0
    move_wasd( delta) # рулим движуху ... стрелочками


  if( nod_nam_atk1 in playback.get_current_node() ):
    is_atk = true
  else:
    is_atk = false
  attack1()

  anim_tree[ "parameters/conditions/IsOnFloor"] = on_floor
  anim_tree[ "parameters/conditions/IsInAir"] = ! on_floor
  anim_tree[ "parameters/conditions/IsWalk"] = is_walk
  anim_tree[ "parameters/conditions/IsNotWalk"] = ! is_walk
  anim_tree[ "parameters/conditions/IsRun"] = is_run
  anim_tree[ "parameters/conditions/IsNotRun"] = ! is_run
  anim_tree[ "parameters/conditions/IsDeath"] = is_death
#---------




func nav_target( movement_target: Vector3):
  nav.set_target_position( movement_target)
#---------


func nav_set_land( also_collision: int = 0):
  nav.set_navigation_layer_value( 1, true)
  nav.set_navigation_layer_value( 2, false)
  if also_collision:
    set_collision_mask_value( 1, true)
    set_collision_mask_value( 2, false)
#---------

func nav_set_fly( also_collision: int = 0):
  nav.set_navigation_layer_value( 1, false)
  nav.set_navigation_layer_value( 2, true)
  if also_collision:
    set_collision_mask_value( 1, false)
    set_collision_mask_value( 2, true)
#---------


func priv_may_toggle__alt_path() -> int:
  # Вызываем процу от сигнала - попытка сменить полёт-пехоту.
  # Сбрасываем нынешний путь - он сам сбросится.

  # Псевдо-клик, как будто под персонажа, и get_final_position(),
  # по хикс-зэд, должна быть совсем близко - тогда return 1;
  # Иначе - точка в другом слое плохо досягаема - сместись,
  # и снова переключай полёт-пехоту.

  if test_is_fly: # Сейчас - в полёте,
    nav_set_land() # и нужно проверить место посадки, в первом слое.
  else:
    nav_set_fly()
  nav_target( self.position)

  var v3 = nav.get_final_position()
  v3.y = self.position.y # выровним, чтобы в двумерке была дистанция..
  var a = v3.distance_to( self.position)
  #print( "alt_path dist: ", a)

  if test_is_fly: # Сейчас - в полёте, вернуть полётный слой..
    nav_set_fly()
  else:
    nav_set_land()
  nav_target( self.position) # чтобы обнулить пре-поиск.
  # Не знаю, как сбрасывать старый путь.

  #if a > 0.5:
  if a > 0.4: # слишком большой допуск,
    return 0 # и блокируем смену слоя.

  return 1 # разрешаем смену слоя - капсулу игрока авто-подвинут.
#---------




func attack1():

  if( nod_nam_idle in playback.get_current_node() ) or(
  nod_nam_walk in playback.get_current_node() ): # or(
  #nod_nam_run in playback.get_current_node() ): // нет атаки, при спринте.
    pass
    if Input.is_action_just_pressed( "attack1"):
      # Эту аниму можно назначить: кастинг сбора простой травы-руды.
      #print( "strike")
      if ! is_atk: # Если персонаж не занят атакой - пусть атакует.
        playback.travel( nod_nam_atk1) # включить аниму _атаки.

        # --- в целях тэста, добавка для переключения полёт-пехота..
        toggle_nav_land_fly()
#---------


func toggle_nav_land_fly():
  if priv_may_toggle__alt_path(): # Если можно переключать, тогда..
    if test_is_fly: # смотри старое // new --> пехота // первый слой.
      nav_set_land( 1)
      test_is_fly = false
      pl_mesh.position.y = 0.0
      pl_mesh_cape.hide()

    else: # // new --> полёт // ставим второй слой.
      nav_set_fly( 1)
      test_is_fly = true
      pl_mesh.position.y = 1.0
      pl_mesh_cape.show()
#---------
#20
23:39, 11 июня 2024
func move_wasd( delta):

  if Input.is_action_just_pressed( "ui_accept") and is_on_floor():
    velocity.y = JUMP_VELOCITY # прыгаем, если сигнал, и чувствуем опору.

  # Get the input direction and handle the movement/deceleration.
  # As good practice, you should replace UI actions with custom gameplay actions.
  var input_dir = Input.get_vector( "ui_left", "ui_right", "ui_up", "ui_down")
  var direction = (transform.basis * Vector3( input_dir.x, 0, input_dir.y)).normalized()
  if direction:
    #velocity.x = direction.x * SPEED
    #velocity.z = direction.z * SPEED
    # OR
    #var v1 = direction.rotated( Vector3( 0, 1.0, 0), deg_to_rad( camera_h.rotation.y))
    # оказалось, что не нужно конвертировать градусы в радианы ...
    # Почитал подсказку - действительно, градусная постановка - для удобства,
    # а свойство несёт радианы, когда работает.
    var v1 = direction.rotated( Vector3( 0, 1.0, 0), camera_h.rotation.y)
    velocity.x = v1.x * movement_speed
    velocity.z = v1.z * movement_speed
    var nt = get_node_or_null( "../CanvasLayer/Label")
    if nt:
      nt.text = "%1.1f  %1.1f  rot%1.1f" % [ v1.x, v1.z, camera_h.rotation.y]
    
    pl_mesh.rotation.y = camera_h.rotation.y + deg_to_rad( -180.0)

    walk_run( 1)
  else:
    walk_run( 0)
    velocity.x = move_toward( velocity.x, 0, movement_speed)
    velocity.z = move_toward( velocity.z, 0, movement_speed)

  move_and_slide()
#---------




var auto_shift := 0 # мало знаний про Анимашн, но хакнуть можно быстро.

func walk_run( move: int):
  var run_mode := false # выяснить (галочка или прижатый шыфт).
  #if Input.is_key_pressed( KEY_SHIFT): ...
  # Вероятно, персонаж всегда будет бегать. // но бег не анимируется _сразу,
  # и надо начинать с шага, чтобы анима бега подхватилась ...
  if auto_shift == 2:
    run_mode = true
  if move  and( auto_shift < 1): # 0
    auto_shift = 1
  else:
    auto_shift = 2
  #
  if Input.is_key_pressed( KEY_SHIFT): # чтобы шаг был доступен.
    run_mode = false


  is_walk = false
  is_run = false
  if run_mode:
    if move:
      is_run = true
    else:
      auto_shift = 0
    movement_speed = run_speed
  else:
    if move:
      is_walk = true
    else:
      auto_shift = 0
    movement_speed = walk_speed
  #
#---------




func _unhandled_input( event):
  if event is InputEventMouseButton and event.pressed and event.button_index == 1:
    try_find_way = true # оформить зацепку, которую перехватят в _physics_process
#---------




func move_klik( delta):

  if try_find_way:
    try_find_way = false
    var space_state = get_world_3d().direct_space_state
    var cam = get_node( "camera_base/h/v/Camera3D")
    var mousepos = get_viewport().get_mouse_position()

    var origin = cam.project_ray_origin( mousepos)
    var end = origin + cam.project_ray_normal( mousepos) * RAY_LENGTH
    var query = PhysicsRayQueryParameters3D.create( origin, end)
    query.collide_with_areas = true

    #query.exclude = self # [self, доп] # масив // игнорим свои колиз-шэйпы.
    #query.exclude = [ self, null] # так нельзя
    #query.exclude = [ self, ray_ignor_scn] # так не игнорят.
    # Попытки вытаскивать мешы в m_grid, и добавлять каждую вторую ячейку,
    # в масив ignor = игнор не работает по Мешам.
    # Зато стал работать по отдельному статик боди, который выташил
    # из отдельной заготовки. Значит, можно строить локацию хитрей,
    # чтобы столбы были отдельно (на снэпе - это повторит грид-мэп).
    # Можно делать почти плоские поляны-комнаты.
    # Есть кнопка PageDown для Node3D: ставит на пол - на первую опору.
    # Впрочем, кликать на стену, и думать о точке _за_стеной - это
    # не очевидно (для разных игроков). Класически - клик по стене - надо
    # бежать к основанию стены - так и происходит, если стену не игнорить.

    var ignor = []
    ignor.append( self) # игнорит, потому-что CharacterBody3D (тело).
    if pillar_gltf:
      ignor.append( pillar_gltf) # сработала указка на StaticBody3D (тело).
    query.exclude = ignor # передали масив игнорирований _тел.

    var result = space_state.intersect_ray( query) # узнали пересечение.

    nav_target( result.position) # приказали _навигатору найти путь.
    print( result.position) # Путь, примерно, к этой точке.

  elif nav.is_navigation_finished():
    walk_run( 0)
    return

  walk_run( 1)

  var next_p: Vector3 = nav.get_next_path_position()
  var new_v: Vector3 = global_position.direction_to( next_p) * movement_speed
  if nav.avoidance_enabled:
    nav.set_velocity( new_v)
    # Чуток потэстил - не хочу эту огибаловку использовать.
    # Пусть игроки и монстры пробегают сквозь друг-друга.
  else:
    _on_velocity_computed( new_v)

  var v1 = Vector3( 0, 0, 1) # позитивная единица, вместо негативной.
  var ug = v1.signed_angle_to( new_v, Vector3( 0, 1, 0))
  pl_mesh.rotation.y = ug
#---------

#.
#21
14:00, 12 июня 2024

slatazan
> Надо напечатать код на форум, для сохранки

Контроль версий не используешь что ли?
Я конечно не против, пиши, мог бы даже code review сделать, у тебя тут даже на поверхности совсем чудеса, но...

Всё таки это форум, тут бы лучше на человекопонятном языке писать ))

#22
23:58, 16 июня 2024

Der FlugSimulator
// Контроль версий
Угу, не использую. Считаю, что мне - повезёт :)

// совсем чудеса, в коде
Ну, не знаю. Геройчик бегает нормально.

Мини-скрипт, который для поворота камеры использую..

extends Node3D

var h_sens: float = 0.003 # 0.005 // карусель-поворот
var h_accel: float = 8.0 # малое значение - большая энэрция
var kh := 0.0
var kv := -35.0

func _ready():
  Input.set_mouse_mode( Input.MOUSE_MODE_CAPTURED)

func _input( e: InputEvent):

  if e is InputEventMouseMotion  and(
  Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED):
    kh += -e.relative.x * h_sens # карусель
    #kv += -e.relative.y * v_sens # кивок

  if e is InputEventKey:
    if e.is_action_pressed( "ui_cancel"):
      if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
        Input.set_mouse_mode( Input.MOUSE_MODE_CAPTURED)
      else:
        Input.set_mouse_mode( Input.MOUSE_MODE_VISIBLE)

func _physics_process( delta: float):
  var h = get_node( "h")
  h.rotation.y = lerpf( h.rotation.y, kh, h_accel * delta)
#23
22:34, 28 июня 2024

Добавка учитывания пустого поиска пересечения..

# player.gd :: move_klik
    var result = space_state.intersect_ray( query) # узнали пересечение.

    var r_pos = self.position # добавка кода.
    if result.is_empty():
      print( "ZERO intersect_ray")
    else:
      r_pos = result.position

    nav_target( r_pos) # приказали _навигатору найти путь.
    print( r_pos) # Путь, примерно, к этой точке.
#24
22:35, 28 июня 2024

// ---
Увлёкся гаражным декором. (изолента на руле ...)

Пытаюсь усвоить и адаптировать чужые заготовки полигонов.
У одного набора полигонов, зажатый цвет-материал.
Я не стал разбираться - сделал две добавочных папки,
где заменил все текстуры на тёмную, и на золотисто-блёклую.
В архиве, эти дубляжы полигонов - хорошо ужымаются - сойдёт подход.


Изображение

Обычная локация - маленькая, как зал-комната,
чтобы авто-оптимизация была.
Загружаем локацию - некоторые яшики бросают жребий,
чтобы сменить визуалку - некое разны-образие, и работа
заборчиками, и стенами. Накидать яшиков, везде ...
На скриншоте, перед серым рыцарем - большые яшики, как стена.

// Сумка и ярлыки - не работают.

Забавный шэйдэр мультяшного моря..
https://godotshaders.com/shader/wind-waker-water-no-textures-needed/

#25
22:36, 28 июня 2024
extends Node3D
# b_box_large_m_1 // сцена для создания стены.
# b_box_m_1 // сцена для заборчика.
#
# Внутри сцен, под этот скрипт, подразумеваю три пары яшиков - каждый
# из них, можно поворачивать по оси угрик.


@export var rot_deg_half := 0
# 0= не крутить карусель.
# 10= выбор градуса поворота, плюс-минус 10.
# Стараемся не ставить большых чисел.

@export var use_dekor := 0
# 0= random // умолчанка выставит разные визуальные кубики.
# 1= выставить пару первых яшиков.
# 2= вторая пара
# 3= третья пара
# else: невидимая колизия - не включаем визуалку яшиков.


var m1 = [ null, null, null]
var m2 = [ null, null, null]
var mr = [ 0, 90, 180, 270]

func _ready(): # при загрузке локаций

  if rot_deg_half < 0:
    rot_deg_half = 0
  if rot_deg_half > 30:
    rot_deg_half = 30

  m1[ 0] = get_node( "b1")
  m1[ 1] = get_node( "d1")
  m1[ 2] = get_node( "g1")

  m2[ 0] = get_node( "b2")
  m2[ 1] = get_node( "d2")
  m2[ 2] = get_node( "g2")

  var p1 = m1[ 0]
  var p2 = m2[ 0]
  p1.hide() # прячем изначальные яшики.
  p2.hide()

  if use_dekor == 0:
    p1 = m1[ g2.random( 0, 2)] # жребий от 0 до 2
    p2 = m2[ g2.random( 0, 2)]
  elif use_dekor == 2:
    p1 = m1[ 1]
    p2 = m2[ 1]
  elif use_dekor == 3:
    p1 = m1[ 2]
    p2 = m2[ 2]

  show_rot_box( p1, rot_deg_half)
  show_rot_box( p2, rot_deg_half)
#---------

func show_rot_box( a, do_r: int = 0):
  if do_r:
    var rot = mr[ g2.random( 0, 3)]
    if rot: # нуль оставляем без перемен, а остальное - шанс изменить.
      if g2.random( 0, 2):
        if g2.random( 0, 1):
          rot -= g2.random( 1, do_r)
        else:
          rot += g2.random( 1, do_r)
        #print( "box_rot: ", rot)
    a.rotation.y = deg_to_rad( rot)
  #
  if use_dekor < 4:
    a.show()
#---------
#26
15:33, 29 июня 2024

slatazan
> Забавный шэйдэр мультяшного моря..

Видел.
Мне он не очень. Я свой написал, сразу с плавучестью.

#27
(Правка: 29 янв 2025, 18:53) 1:20, 27 июля 2024

Стартовая локация, вид сверху.
Набор локаций "монастырь", шаманский - на острове мастеров.
Коридор, сверху - это путь в сад стихий, если экипированы какие-нибудь _крылья.

monk_sta | Godot4 :: Царство и капитаны


// - - -
Использую для создания плавных дуг. На картинке - справа.

@tool
#n3d_scn_klon.gd
extends Node3D


@export var init: bool = false:
  set( x): if x: re_init() # init остаётся пустой галочкой.


@export var klv: int = 0 # количество клонов.

# orig_child_begin
@export var child_beg: int = 0 # первый чилд-оригинал, начало жребия.
# Чилды-номера, для жребия, и для копирования - обязаны следовать
# друг за другом, впритык. Учитывая, что рабочая нода обязана
# получить "Make Local", можно передвинуть любого чилда
# вышэ-нижэ, в дереве сцены. // Ctrl + up or dn.

@export var child_end: int = 0 # заключительный чилд-оригинал, для жребия.
# Изначальный нуль, как игнор этого значения, в пользу повтора child_beg.
# Однако, выставив негатив, мы указываем количество пустых мест, когда
# вместо "второй" штамповки первого чилда, покидаем функцию - пустое место,
# чтобы сделать подобный круг фигур, чуть повернуть его, карусельно,
# и получить чередование двух клонов (1, 2, 1, 2).
#
# Спец-пробник..
# node1.klv = 7
# node1.child_beg = 0 # m1
# node1.child_end = -1
# node2.klv = 7
# node2.child_beg = 1 # m2
# node2.child_end = -3
# node2.position.x += 1 // сдвинем, и будет: m1 m2 m1 _ m1 m2 m1



@export var auto_rotate: int = 0 # доворачивать клоны, по дуге.
@export var after_angle_y: float = 0.0 # карусель-поворот, после каждого клона.

@export var after_move: Vector3 = Vector3( 1.0, 0.0, 0.0)
# сдвиг, после каждого клона.

@export var base_rotation: Vector3 = Vector3( 0.0, 0.0, 0.0)

var priv_skip := 0 # сколько пустых мест ужэ сделано, если они нужны.
var priv_ang := 0.0 # плавное добавление after_angle_y.
var priv_pos := Vector3.ZERO
var multi = null

# g2.random( 0, 2) нельзя использовать в тул-скрипте @tool
func random( min_i: int = 1, max_i: int = 6):
  if max_i <= min_i:
    return min_i
  return ( randi() % (max_i - min_i + 1) ) + min_i
#---------



func re_init():
  if klv < 1:
    print( "klv < 1")
    return
  multi = get_node_or_null( "multi")
  if not multi:
    #print( "not multi")
    #return
    var n3 = Node3D.new()
    if not n3:
      print( "not NEW multi")
      return
    n3.name = "multi"
    self.add_child( n3)
    n3.owner = get_tree().edited_scene_root
    multi = get_node_or_null( "multi")
  #

#  for a in range( multi.get_child_count() -1, -1, -1):
#    multi.get_child( a).free()
  for a in range( 0, multi.get_child_count()):
    #print( "multi clear %d" % a)
    multi.get_child( a).queue_free()

  priv_ang = 0.0
  priv_pos = Vector3.ZERO

# ---
  for i in range( 0, klv):
    #print( "(klv %d) re_init %d" % [ klv, i] )

    if child_beg < 0:
      child_beg = 0
    var x = get_child( random( child_beg, child_end) )
    dub_an1( x, base_rotation, after_angle_y, after_move)
  #for

  #await get_tree().create_timer( 0.1).timeout // микро-пауза
#---------



func dub_an1( orig, set_rot: Vector3, aft_ug: float, aft_move: Vector3):

  var skip := 0
  if child_end < 0:
    if not priv_skip:
      # будем делать клон.
      priv_skip = -child_end # назначаем колво будуших пропусков.
    else:
      skip = 1 # не клонируем
      priv_skip -= 1 # и пытаемся обнулить priv_skip
  #

  var n = null
  if not skip:
    #print( "orig name: %s" % orig.name)
    n = orig.duplicate() # duplicate(flags: int = 15) returning a new node
    if not n:
      print( "err duplicate")
      return
    multi.add_child( n)
    n.owner = get_tree().edited_scene_root # чтобы нода появилась в окне редактора.
    n.show()
    n.position = priv_pos
    #print( "duplicate name: %s" % n.name)
  else:
    pass
  #

  priv_ang += aft_ug # upd for next
  var d
  if aft_ug != 0:
    d = aft_move.rotated( Vector3( 0,1,0), deg_to_rad( priv_ang))
  else:
    #print( "zero priv_ang")
    d = aft_move
  #
  priv_pos += d

  if not skip:
    n.rotation.x = deg_to_rad( set_rot.x)
    n.rotation.y = deg_to_rad( set_rot.y)
    n.rotation.z = deg_to_rad( set_rot.z)
    if auto_rotate:
      n.rotation.y += deg_to_rad( priv_ang - (aft_ug * 0.5) )
#---------
#28
23:52, 15 авг 2024

Чтобы пере-заход в локацию, ставил кусты на новые места ...

extends Area3D # area_forest.gd
# обязательный нулевой чилд - колижн-шэйп "box".
# Другие чилды - элементы, спрятаные _под_землю,
# чтобы их копировать, и ставить на землю.

# Сохраняем эту заготовку, а когда загружаем её,
# то правый клик - строка меню "Editable Children".

# Габариты колиз-бокса, как область заполнения.
# Колиз-бокс должн иметь галочку local_to_scene.
# Если одна локация, и много подобных лесных зон,
# то нужно применять Make Uniq на ресурсе BoxShape.

@export var trig_surprize: int = 0
# Прибавка шанса появления мобов-нежданчиков.

var box_size_x: float = 0.0
var box_size_z: float = 0.0


@export var q_x: int = 0 # оставив меньшэ трёх - прерываем
# _создание_леса, чтобы, например, использовать зону для логики.
var step_x := 0.0

@export var q_z: int = 0 # нужное количество элементов, по оси зэд.
var step_z := 0.0

@export var step_shake: float = 0.5 # жребий сдвига хикс-зэд.
@export var scale_max: int = 0 # 7, как 0.7 увеличения для элементов.

@export var skip_rand: bool = true
# оставить-ли пустыми некоторые ячейки грида (q_x * q_z).

@export var skip_mid: int = 0
# 0, 1, 2, 3. // Пустота в середине - максимум, три на три.

@export var random_dent: float = 0.5 # вдавливание, от жребия.


var xh := 0
var zh := 0

var priv_ang := 0.0 # плавное добавление after_angle_y.
var priv_pos := Vector3.ZERO
var priv_ofs := Vector3.ZERO
var priv_use_y05 := 0

var srx := 0 # шаг_радиус для хикса
var srz := 0

var bg = null




func _ready():
  bg = get_node_or_null( "box")
  if not bg:
    return

  box_size_x = bg.shape.size.x
  box_size_z = bg.shape.size.z

  call_deferred( "forest2") # на всякий случий, в конце кадра
#---------




func forest2():

  var elem_q := 0
  elem_q = get_child_count() - 1 # минус нулевая коробка.
  if elem_q < 1:
    return # не заготовили шаблонов (валунов, кустов).
  #else: копируем чилда, забирая его, через get_child[ from1]


  if q_x < 3  or  q_z < 3:
    print( "area_forest ERR( q_x < 3  or  q_z < 3)")
    return

  step_x = box_size_x / float( q_x +1) # лишний, для зазора.
  step_z = box_size_z / float( q_z +1)

  if step_x < 1.0  or  step_z < 1.0:
    return


  if skip_mid < 0: skip_mid = 0
  if skip_mid > 3: skip_mid = 3
  if skip_mid:
    xh = int( (q_x +1) * 0.5)
    zh = int( (q_z +1) * 0.5)
    if xh < 2: # игнорим такой пропуск.
      xh = 0
    if zh < 2:
      zh = 0

  if step_shake < 0.0: step_shake = 0.0
  if step_shake > 1.0: step_shake = 1.0
  srx = int( step_x * step_shake)
  srz = int( step_z * step_shake)


  # --- квадратно-гнездовое..
  var skip1 := 0
  var elem = null
  var box_half_x = box_size_x * 0.5
  var box_half_z = box_size_z * 0.5

  for z in range( 0, q_z +1): # плюс пустышка, на нуле
    if z == 0:
      continue

    priv_ang = 0.0
    priv_pos = Vector3( -box_half_x + step_x,
    0, z * step_z - box_half_z)
    # Сразу ставим priv_pos.x учитывая пустой шаг.

    for x in range( 0, q_x +1): # плюс пустышка, на нуле.
      if x == 0:
        continue

      priv_ofs = priv_ofs_rand( 1)
      skip1 = get_skip( x, z)
      elem = get_child( g2.random( 1, elem_q))

      dub_an1( elem,
      Vector3( 0, g2.random( 1, 24) * 15, 0),
      0.0, Vector3( step_x, 0, 0),
      skip1 )
    # for x
  # for z
#---------


func priv_ofs_rand( use_y: int = 0) -> Vector3:
  priv_use_y05 = 0
  var v: Vector3 = Vector3.ZERO
  var ox := 0
  var oz := 0
  if srx:
    ox = g2.random( 0, srx)
    if ox:
      if g2.random( 0, 1):
        ox = -ox
  if srz:
    oz = g2.random( 0, srz)
    if oz:
      if g2.random( 0, 1):
        oz = -oz
  if ox  or  oz:
    v = Vector3( ox, 0, oz)
    if use_y:
      if g2.random( 0, 1):
        # уместно менять угрик после приземления.
        priv_use_y05 = 1
  #
  return v
#---------


func get_skip( x: int, z: int) -> int:

  if skip_rand:
    if g2.random( 0, 1):
      return 1 # не важно, что дальшэ - жребий ужэ порешал.

  # срезаем углы..
  if x == 1  and  z == 1:
    return 1
  elif x == q_x  and  z == 1:
    return 1
  elif x == 1  and  z == q_z:
    return 1
  elif x == q_x  and  z == q_z:
    return 1


  # --- Можно проверить проекцию к габаритам важных нод.
  # И вернуть единицу, если залезли в габариты домика.


  var skip1 := 0

  if skip_mid < 1:
    return skip1
  if xh < 2  or  zh < 2:
    return skip1

  if skip_mid == 1: # примерно средния клетка - пустая.
    if x == xh  and  z == zh:
      skip1 = 1

  elif skip_mid == 2: # 2х2 средние клетки.
    if (x == xh or x == xh + 1) and (z == zh or z == zh + 1):
      skip1 = 1

  elif skip_mid == 3: # 3х3, в середине.
    if x == xh  or  x == xh + 1  or  x == xh - 1:
      if z == zh  or  z == zh + 1  or  z == zh - 1:
        skip1 = 1

  return skip1
#---------




func dub_an1( orig, set_rot: Vector3, aft_ug: float, aft_move: Vector3,
skip: int = 0) -> void:

  var n = null
  if not skip:
    #print( "orig name: %s" % orig.name)
    n = orig.duplicate() # duplicate(flags: int = 15) returning a new node
    if not n:
      print( "err duplicate")
      return
    bg.add_child( n)
    #n.owner = get_tree().edited_scene_root # чтобы нода появилась в окне редактора.
    n.show()
    n.position = priv_pos
    #print( "duplicate name: %s" % n.name)
    n.position += priv_ofs
    if 1:
      n.global_position = find_floor( n.global_position)
      if priv_use_y05:
        n.position.y -= random_dent # чуть провалим
  else:
    pass
  #

  priv_ang += aft_ug # upd for next
  var d
  if aft_ug != 0:
    d = aft_move.rotated( Vector3( 0,1,0), deg_to_rad( priv_ang))
  else:
    d = aft_move
  #
  priv_pos += d

  if not skip:
    n.rotation.x = deg_to_rad( set_rot.x)
    n.rotation.y = deg_to_rad( set_rot.y)
    n.rotation.z = deg_to_rad( set_rot.z)
    if 1: #auto_rotate:
      n.rotation.y += deg_to_rad( priv_ang - (aft_ug * 0.5) )
    if scale_max > 0:
      var sc = float( g2.random( 0, scale_max)) * 0.1 + 1.0
      n.scale.x = sc
      n.scale.y = sc
      n.scale.z = sc
#---------



func find_floor( v: Vector3) -> Vector3:
  var space_state = get_world_3d().direct_space_state
  var end = v
  end.y -= 500.0 # луч вниз
  var query = PhysicsRayQueryParameters3D.create( v, end)
  query.collide_with_areas = false

  var result = space_state.intersect_ray( query)
  if result.is_empty():
    return v
  return result.position
#---------

#.
#29
22:12, 25 сен 2024

// --- сумка, травничество, тикалка

Игра стартует. Открываем сумку. Кликаем морковь несколько раз,
и счётчик становится нормальным: 99, вместо "9+".
Потому-что изначально, из кода, добавлен стак в 101 морковь.
Клики по предметам - тэстово отнимают единицу стака.

В локацию, выставлена нода _собираемый_куст - над ним кружочек.
Пробывал три-мерную надпись, вместо круга, но не понравилось.
Собираем куст - фиалка добавилась. // это отмечают в чате.

Персонаж устроен.. отдельный нодо-скрипт, внутри которого,
создан экзэмпляр rpg_u, как обше-деталь для игроков и монстров.

Жмём тэстовую кнопку _удара. Идёт анимация удара, и вдобавок,
пытаемся повесить на нутри-юнит персонажа - огне-тикалку..
player.gd::
unit.eff_set__tik( g1.r_ef_tik_flame, 10, 200, 1)
В индикаторе, видно, как считают секунды огне-тика (10 сек).
Но пока, нет оформления ранений.
При этом тэсте, я заметил, что функция "_physics_process",
у меня, иногда, вызывается по два раза, за один кадр.

# Лично мне пофигу на такое - не собираюсь вникать.
# Значит, всю "одно_кадровую" логику надо держать в _process,
# которая не связана с колизиями, и я верю - она один раз, в кадр.


// Переход в каркас шаговой игры.. Меню, Арсенал, кнопка СПЕЦ ИГРА.

Страницы: 1 2 3 Следующая »
GodotФорумДемонстрируем наработки