みなさん、こんにちは。私の名前はVyacheslavで、プログラマーですが、具体的には現在、GodotEngineでゲーム開発に従事していると同時に、このエンジンで独自のゲームを作成するためのメモを書く電報チャンネルを運営しています。 Godotを勉強するための初心者向けの資料を提供します。
さて、ビジネスに取り掛かりましょう。なぜドラッグアンドドロップと私からのボーナスで簡単な在庫を作るのでしょうか?
はじめましょう。私はデザイナーではないので、機能的なバージョンがあります。後で自分でやってください。
まず、プロジェクトを作成し、作業に必要なノードを最小バージョンで追加します。
PanelContainerをコントロールにスローし、レイアウトボタン(表示)を介してコントロール全体に拡大し、すぐに高さと幅の拡張にフラグをスローします。
子と一緒にGridContainer(グリッド)をその中にスローします。すでに要素をその中にスローします。デバッグの便宜のために、アイテムを「ピックアップ」するボタンを追加します。ランダムな要素をランダムに生成します。数。
在庫には8列、4行あり、必要な種類のアイテムアイコンを用意しました。
Googleからフォントをダウンロードし、コントロールにドロップして、フォントサイズを変更できるようにします。
次に、インベントリのように見えるように少しスタイルを設定し、1つのスロットを作成して、別のファイルに保存します。スロットを動的に作成します。
次に、次のスクリプトをメインシーンにスローします。
extends Control
export (int, 1, 20) var columns = 8
export (int, 1, 20) var rows = 4
onready var inv = $InvContainer/InvContent
const slot_scene = preload("res://Slot.tscn")
func _ready():
inv.columns = columns
for i in range(columns*rows):
var slot = slot_scene.instance()
inv.add_child(slot)
中間オプションは次のようなものです。
, , , TextureRect Label - :
, , , , :
:
Slot , :
extends PanelContainer
onready var item = $Item
onready var icon = $Item/Icon
onready var count = $Item/Count
var item_type = null
var item_count = 0
func _ready():
update_data({"type": "item_type_1", "count": 0})
func update_data(data = null):
item.visible = data != null
if data:
icon.texture = load("res://graphics/%s.png" % data.type) #
count.text = str(data.count)
:
:
:
extends Control
export (int, 1, 20) var columns = 8
export (int, 1, 20) var rows = 4
onready var inv = $InvContainer/InvContent
const slot_scene = preload("res://Slot.tscn")
func _ready():
$InvContainer/HBoxContainer/Clear.connect("pressed", self, "clear_inventory")
inv.columns = columns
for i in range(columns*rows):
var slot = slot_scene.instance()
inv.add_child(slot)
func clear_inventory():
for child in inv.get_children(): #
child.update_data() #
, .
.
:
extends PanelContainer
onready var item = $Item
onready var icon = $Item/Icon
onready var count = $Item/Count
var item_data = null
func _ready():
update_data()
func empty():
return item_data == null
func update_data(data = null):
item.visible = data != null
item_data = data
if item:
icon.texture = load("res://graphics/%s.png" % item_data.type) #
count.text = str(item_data.count)
return true
:
func has_empty_slot(): #
for child in inv.get_children(): #
if child.empty():
return true
return false
func get_empty_slot(): #
var slot = null
if has_empty_slot():
# ,
#
while slot == null: # ,
var temp_slot = inv.get_child(rng.randi_range(0, columns*rows-1))
if temp_slot.empty():
slot = temp_slot
break
return slot
func add_item(): # ,
var slot = get_empty_slot()
if slot:
var data = {"type":"", "count": 0}
data.type = "item_type_" + str(rng.randi_range(1, 8))
data.count = rng.randi_range(1, 999)
slot.update_data(data)
“add_item”, .
D&D(Drag&Drop).
, , .. .
:
, , .
extends PanelContainer
onready var icon = $Icon
onready var count = $Count
const path_to_items_icons = "res://graphics/%s.png"
func set_data(item_data):
icon.texture = load(path_to_items_icons % item_data.type) #
count.text = str(item_data.count)
:
, “Num”, , , . , :
, ( ), )
, , , :
extends Control
export (int, 1, 20) var columns = 8 #-
export (int, 1, 20) var rows = 4 #-
const slot_scene = preload("res://Slot.tscn") #
onready var inv = $InvContainer/InvContent #
onready var titem = $TempItem # ,
onready var rng = RandomNumberGenerator.new() #
onready var item_dragging = null #
onready var prev_slot = null #
func ready():
titem.visible = false #
rng.randomize() #
$InvContainer/HBoxContainer/Clear.connect("pressed", self, "clear_inventory")
$InvContainer/HBoxContainer/Add.connect("pressed", self, "add_item")
inv.columns = columns # -
for i in range(columns*rows): #
var slot = slot_scene.instance() #
slot.name = "Slot%d" % i # , ,
slot.get_node("Num").text = str(i) # ,
,
inv.add_child(slot) #
func clear_inventory(): #
for child in inv.get_children(): #
child.update_data() #
func has_empty_slot(): #
for child in inv.get_children(): #
if child.empty():
return true
return false
func get_empty_slot(): #
var slot = null
if has_empty_slot():
# ,
#
while slot == null: # ,
var temp_slot = inv.get_child(rng.randi_range(0, columns*rows-1))
if temp_slot.empty():
slot = temp_slot
break
return slot
func add_item(): # ,
var slot = get_empty_slot()
if slot:
var data = {"type":"", "count": 0}
data.type = "item_type_" + str(rng.randi_range(1, 8))
data.count = rng.randi_range(1, 999)
slot.update_data(data)
func find_slot(pos:Vector2, need_data = false): #
# - ,
for c in inv.get_children(): #
if (need_data and not c.empty()) or (not need_data):
if Rect2(c.rect_position, c.rect_size).has_point(pos):
# ,
#
return c
return null
func _process(delta):
var mouse_pos = get_viewport().get_mouse_position() #
if Input.get_mouse_button_mask() == BUTTON_LEFT: #
if not item_dragging: #
var slot = find_slot(mouse_pos, true)#
if slot: #
item_dragging = slot.item_data #
titem.set_data(item_dragging) #
titem.visible = true #
titem.rect_position = slot.rect_position #
prev_slot = slot #
slot.update_data() #
else: # , , ( )
titem.rect_position = lerp(titem.rect_position, mouse_pos - titem.rect_size/2, 0.3)
else: #
if item_dragging: #
var slot = find_slot(mouse_pos, false) #
if slot: # ,
if not slot.update_data(item_dragging): # ,
prev_slot.update_data(item_dragging)
prev_slot = null #
item_dragging = null #
titem.visible = false #
, :
? , )
func check_data(data):
return "all" in available_types or data.type in available_types
func update_data(data = null):
item.visible = data != null
item_data = data
if item_data:
if check_data(data):
item.set_data(item_data)
return true
return false
return true
, _process:
func _process(delta):
var mouse_pos = get_viewport().get_mouse_position() #
if Input.get_mouse_button_mask() == BUTTON_LEFT: #
if not item_dragging: #
var slot = find_slot(mouse_pos, true)#
if slot: #
item_dragging = slot.item_data #
titem.set_data(item_dragging) #
titem.visible = true #
titem.rect_position = slot.rect_position #
prev_slot = slot #
slot.update_data() #
else: # , , ( )
titem.rect_position = lerp(titem.rect_position, mouse_pos - titem.rect_size/2, 0.3)
else: #
if item_dragging: #
var slot = find_slot(mouse_pos) #
# №1
#if slot: # ,
#if slot.empty(): #
#if slot.check_data(item_dragging): # ,
#slot.update_data(item_dragging)
#else: # ,
#prev_slot.update_data(item_dragging)
#else: # , ,
#if slot.check_data(item_dragging) and prev_slot.check_data(slot.item_data):
#prev_slot.update_data(slot.item_data)
#slot.update_data(item_dragging)
#else: # ,
#prev_slot.update_data(item_dragging)
# №2
if slot: #
if slot.check_data(item_dragging): # ,
if slot.empty(): #
slot.update_data(item_dragging)
else: # ,
if prev_slot.check_data(slot.item_data): # ,
prev_slot.update_data(slot.item_data)
slot.update_data(item_dragging)
else:
prev_slot.update_data(item_dragging)
prev_slot = null #
item_dragging = null #
titem.visible = false #
, , , , , , , , , , , , , 100 , , , , , )
, , -, , - , , .
:
extends PanelContainer
signal dropped(data)
export (Array) var available_types = ["all"]
#
enum Actions {NONE, TRASH} #
var cur_act = Actions.NONE #
onready var item = $Item
var item_data = null #
func _ready():
update_data()
func set_action(new_value):
cur_act = new_value
$Item.visible = false
$Trash.visible = false
match cur_act:
Actions.NONE:
$Item.visible = true
Actions.TRASH:
$Trash.visible = true
func empty():
return item_data == null
func check_data(data):
if cur_act:
return true
return "all" in available_types or data.type in available_types
func update_data(data = null):
if data and cur_act:
emit_signal("dropped", data)
return true
item.visible = data != null
item_data = data
if item_data:
if check_data(data):
item.set_data(item_data)
return true
return false
return true
:
func ready():
titem.visible = false #
rng.randomize() #
$InvContainer/HBoxContainer/Clear.connect("pressed", self, "clear_inventory")
$InvContainer/HBoxContainer/Add.connect("pressed", self, "add_item")
inv.columns = columns # -
for i in range(columns*rows): #
var slot = slot_scene.instance() #
slot.name = "Slot%d" % i # , ,
slot.get_node("Num").text = str(i) # , ,
slot.set_action(slot.Actions.NONE)
if i == columns*rows-1:
slot.set_action(slot.Actions.TRASH)
slot.connect("dropped", self, "trash_dropped")
inv.add_child(slot) #
func trash_dropped(data):
print("dropped ", data)
_ready, , .
, .
:
Helmet , , .
:
extends PanelContainer
signal dropped(path, data) #
signal accepted(path, data) #
export (Array) var available_types = ["all"]
#
enum Actions {NONE, TRASH} #
var cur_act = Actions.NONE #
onready var item = $Item
var item_data = null #
func _ready():
set_action()
update_data()
func set_action(new_value = Actions.NONE):
cur_act = new_value
$Item.visible = false
$Trash.visible = false
$Num.visible = false
match cur_act:
Actions.NONE:
$Item.visible = true
$Num.visible = true
Actions.TRASH:
$Trash.visible = true
func empty():
return item_data == null
func check_data(data):
if cur_act:
return true
return "all" in available_types or data.type in available_types
func update_data(data = null):
if data and cur_act:
emit_signal("dropped", get_path(), data)
return true
item.visible = data != null
item_data = data
if item_data:
if check_data(data):
item.set_data(item_data)
emit_signal("accepted", get_path(), data)
return true
return false
return true
, :
extends Control
export (int, 1, 20) var columns = 8 #-
export (int, 1, 20) var rows = 4 #-
export (Array, NodePath) var slots_containers #
onready var slots = [] #
const slot_scene = preload("res://scenes/Slot.tscn") #
onready var inv = $PlayerInv/Inv/InvContent #
onready var titem = $TempItem # ,
onready var clearButton = $PlayerInv/Inv/Button/Clear
onready var addButton = $PlayerInv/Inv/Button/Add
onready var rng = RandomNumberGenerator.new() #
onready var item_dragging = null #
onready var prev_slot = null #
func ready():
titem.visible = false #
rng.randomize() #
clearButton.connect("pressed", self, "clear_inventory")
addButton.connect("pressed", self, "add_item")
inv.columns = columns # -
for i in range(columns*rows): #
var slot = slot_scene.instance() #
slot.name = "Slot%d" % i # , ,
slot.get_node("Num").text = str(i) # , ,
inv.add_child(slot) #
if i == columns*rows-1:
slot.set_action(slot.Actions.TRASH)
slots.push_back(slot)
for slots_node in slots_containers: #
for slot in get_node(slots_node).get_children():
slots.push_back(slot)
for slot in slots:
slot.connect("accepted", self, "slot_accepted")
slot.connect("dropped", self, "trash_dropped")
func slot_accepted(path, data):
print("accepted ", path, " ", data)
func trash_dropped(path, data):
print("dropped ", path, " ", data)
func clear_inventory(): #
for child in slots: #
child.update_data() #
func has_empty_slot(): #
for child in slots: #
if child.empty() and child.cur_act != child.Actions.TRASH:
return true
return false
func get_empty_slot(): #
var rand_slot = null
if has_empty_slot():
var empty_slots = [] #
for slot in slots: #
if slot.empty() and slot.cur_act != slot.Actions.TRASH:
empty_slots.push_back(slot)
rand_slot = empty_slots[(rng.randi_range(0, empty_slots.size()-1))] #
return rand_slot
func add_item(): # ,
var slot = get_empty_slot()
if slot:
var data = {"type":"", "count": 0}
data.type = "item_type_" + str(rng.randi_range(1, 8))
data.count = rng.randi_range(1, 999)
slot.update_data(data)
func find_slot(pos:Vector2, need_data = false): #
# - ,
for c in slots: #
if (need_data and not c.empty()) or (not need_data):
if c.get_global_rect().has_point(pos):
# ,
#
return c
return null
func _process(delta):
var mouse_pos = get_viewport().get_mouse_position() #
if Input.get_mouse_button_mask() == BUTTON_LEFT: #
if not item_dragging: #
var slot = find_slot(mouse_pos, true)#
if slot: #
item_dragging = slot.item_data #
titem.set_data(item_dragging) #
titem.visible = true #
titem.rect_position = slot.get_global_rect().position #
prev_slot = slot #
slot.update_data() #
else: # , , ( )
titem.rect_position = lerp(titem.rect_position, mouse_pos - titem.rect_size/2, 0.3)
else: #
if item_dragging: #
var slot = find_slot(mouse_pos) #
if slot: #
if slot.check_data(item_dragging): # ,
if slot.empty(): #
slot.update_data(item_dragging)
else: # ,
if prev_slot.check_data(slot.item_data): # ,
prev_slot.update_data(slot.item_data)
slot.update_data(item_dragging)
else:
prev_slot.update_data(item_dragging)
prev_slot = null #
item_dragging = null #
実際、ここにはまだ改善すべき点があります。スロットの配列を放棄して、Godotの組み込みツールを使用してすべてを実行することは可能ですが、それについては次の記事の1つで詳しく説明します。
UPD:get_empty_slot
最後のリストの関数を修正して、無限ループに入る可能性を排除しました。ギーターも更新されます。
また、私の電報チャンネルでは、以前の記事を読むことができ、次の記事を最初に読むことができます-https://t.me/holydevlog