When left clicking in an Area2D, the message "Object has been clicked" will appear in the debug window. Create the following script to an Area2D node:
func _input_event(viewport, event, shape_idx):
if (event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed):
print("Object has been clicked") #debugging
Note that if we don't add "event.pressed", the event will detect both the press and the release. If you only want to detect the first click, add "event.pressed"
The most common input types are:
InputEvent (better used when a single event is needed, like showing the inventory, pausing the game, etc)
* is_action is specified by a name (such as "ui_right") defined in the Project->Project Settings->Input Map panel of the Editor. As well as the default actions, we may redefine them and add more of our own.
Inputs and InputEvents run in the following event/processes:
_input: This is the first input method that gets called
_gui_input Second input method to be called. It can only be used by Control nodes
_unhandled_input: Best input method to use for player controls. This way does not interfere with Control node input handlers.
_unhandled_key_input: The same as above, but mouse movements do not activate this function
extends Area2D
var clicked=false
func _draw():
var r = Rect2(Vector2(), Vector2(40,40))
if (clicked):
draw_rect(r, Color(1,0,0))
else:
draw_rect(r, Color(0,0,1))
set_process_input(true)
func _input(event):
if (event.is_action_pressed("mouse_left_button")):
clicked=!clicked
queue_redraw()
# For the left click to work, add "mouse_left_button" to Project Settings -> Input Map
In the above example, a square will switch colors between blue and red when the left mouse button in clicked.
We can use a bool variable as a switch. Check the example above and see how bool variable 'clicked' is used.
Add a camera node as children to the player and set the Current property to On" in the Inspector.
position = get_viewport_rect().size / 2
func _ready():
OS.set_window_size(Vector2(1024, 780))
# get device resolution
var max = OS.get_screen_size()
# adjust game resolution
OS.set_window_size(max)
OS.set_window_position(Vector2(0,0))
OS.set_window_fullscreen(true)
OS.set_borderless_window(true) #unable to move
$CollisionShape2D.set_deferred("disabled", true)
func _ready():
add_to_group("players")
http://docs.godotengine.org/en/latest/getting_started/step_by_step/scripting_continued.html#groups
$Label.text = message
yield(get_tree().create_timer(5.0), "timeout")
$Label.text = ""
The code above shows a message during 5 seconds
When autoloading the Player, always use the Player scene, and not the Player script. Otherwise, you will get get_node: "node not found" error when trying to call the children nodes from a script.
It is not possible to export ENUMs from a singleton. For instance, if Global is a singleton and has an ENUM called SlotType, this export won't work:
export(Global.SlotType) var slotType = Global.SlotType;
The workaround is to declare singleton in a separate script, add ENUMS there and declare as class. For instance, we create Global.gd:
extends Node
class_name Global
enum SlotType {
SLOT_DEFAULT = 0,
SLOT_HEAD,
SLOT_FEET
}
Example file: https://drive.google.com/file/d/1EngStPfZxbTGDxjVKbe7Zql3kBepNaq3/view?usp=sharing
JSON file is downloaded to Godot project at location res://Data/Creatures.json
A Global singleton script in created:
extends Node
var creatures: Dictionary = {}
func get_creatures_data() -> Dictionary:
var file = FileAccess.open("res://Data/creatures.json", FileAccess.READ)
var json = JSON.parse_string(file.get_as_text())
file.close()
return json
func _ready():
creatures = get_creatures_data()
# Testing
print (creatures.keys())
var type = "Goblin"
print ("%s stats are:" % [type])
for key in creatures[type]:
print ("%s : %s" % [key, creatures[type][key]])
print("%s strength is %d" % [type, creatures[type]["strength"]])
The above code will print:
["Player", "Human", "Orc", "Goblin", "Adivía", "Agoiru"]
Goblin stats are:
strength : 5
intelligence : 5
dexterity : 7
endurance : 5
health : 10
sprite_sheet : demon1.png
vframes : 9
hframes : 8
frame : 1
Goblin strength is 5
We can decouple the combat by creating a combat system. Remember that Player scene is autoloaded, so any of its properties can be accessed globally from any script.
extends KinematicBody2D
onready var combat = load("res://Scripts/Logic/combat.gd").new()
export (Dictionary) var stats = {
"strength" : 4,
"intelligence" : 4,
"dexterity" : 3,
"endurance" : 6,
"health" : 10,
}
func get_stat(stat):
return stats[stat]
func _ready():
add_child(combat)
# warning-ignore:return_value_discarded
$HitBox.body_entered.connect(_on_Orc_body_entered)
func _on_Orc_body_entered(body):
if body.get_name() == "Player":
combat.attack(self)
extends Node
func attack(enemy):
var health = enemy.get_stat("health")
randomize()
var percentage = randi() % 10
if percentage > Player.get_stat("dexterity"):
print("%s Missed" % [Player.get_name()])
else:
var damage = randi() % Player.get_stat("strength") + 1
health -= damage
print ("%s was hit by %s for %d hit points." % [enemy.get_name(), Player.get_name(), damage])
enemy.stats.health = health
status(enemy,health)
func status(enemy,health):
if health > 0:
print("%s health is %d" % [enemy.get_name(), health])
else:
print("%s died" % [enemy.get_name()])
enemy.queue_free()
Add this script to the parent node where the Sprite node is a child:
tool
extends Area2D
export(Texture) onready var texture setget texture_set, texture_get
func texture_set(newtexture):
$Sprite.texture = newtexture
func texture_get():
return $Sprite.texture
You will now be able to select a different texture for each node instance in the editor. This is great for level creation, as you will be able to differentiate between several types of potions, keys, etc.
func _ready():
var texture = load("%s" % creature_stats.Texture)
get_node("Sprite").texture = texture
func _ready():
var texture = preload("res://Images/Characters/orc.png")
get_node("Sprite").texture = texture
.new() is used to instantiate scripts and single nodes:
onready var data = load("res://Scripts/data.gd").new()
func _ready():
add_child(data)
Note that if you have defined the name of the class in the script data.gd by using the line class_name Data, you can instantiate the script like this:
onready var data = Data.new()
or inherits like this:
extends Data
Note that if you don't use onready and add_child(), all instance nodes will produce orphan nodes (stray nodes). You can check for stray nodes by using print_stray_nodes() and the Debugger->Monitors->Object->Orphan Nodes
More info in Godot Documentation
.instance() is used to instantiate scenes:
const Coin = preload("res://Coin.tscn")
some_function():
var coin = Coin.instance()
add_child(coin)
or
some_function():
var coin = load("res://Coin.tscn").instance()
add_child(coin)
The following code will instantiate 1 Gem in the player position.
foo.gd
const ItemObject = preload("res://scenes/item_object.tscn")
func bar():
var name = "Gem"
var quantity = 1
var item_object = ItemObject.instance()
item_object.initialize(name, quantity)
add_child(item_object)
item_object.position = Player.position
item_object.sd is used to instantiate scenes:
export (String) var item_name
export (int) var item_quantity = 1
func initialize(name: String, quantity: int):
item_name = name
item_quantity = quantity
Note the we can instantiate the item scene both via editor at compile time with the export variables, and via code at run time with the rest of the code.
Also note that you cannot instantiate an object from its own script (You cannot instantiate item_object from item_object.sd)
When importing a resource, you can use either load or preload.
load() is run at runtime
preload() is run at compile time
onready var data = load("res://Scripts/data.gd").new()
onready var data = preload("res://Scripts/data.gd").new()
If you prefer to use a constant:
onready const Data = preload("res://Scripts/data.gd")
var data = Data.new()
When importing a resource, you can use either load or preload.
free() deletes an object from memory immediately. Be cautious.
queue_free() deletes a node from memory when it's safe to do so.
remove_child() removes a node from the scene tree but it does not delete the node.
You can choose exactly when to free the queue by adding the following code in any method that you are gonna call:
if is_queued_for_deletion():
return
Holds an Object, but does not contribute to the reference count if the object is a reference.
If you want the GUI to be independent from the Viewport camera (the GUI will remain in screen regardless of camera movement), create/change the parent node of the GUI scene to CanvasLayer.
var is_paused: bool = false
func _ready():
pause_mode = Node.PAUSE_MODE_PROCESS # On player node, for instance
func _unhandled_input(event):
if (event.is_action_pressed("pause")):
is_paused = !is_paused
pause()
func pause():
if is_paused:
get_tree().paused = true
set_physics_process(false)
else:
get_tree().paused = false
set_physics_process(true)
var vars: Dictionary
var bonus_index := 9 # this is the value of the JSON file, starting in strength_bonus
for key in Player.stats:
# Dynamically creating variables of Player stats keys and assigning JSON file value
vars[key] = Data.item_data[item_name].values()[bonus_index]
if vars[key] != null:
$Label.text += "\n%s %s%d" % [key.capitalize(), vars[key]]
bonus_index += 1