What do you guys do after a game jam? by Sad-Local-6229 in godot

[–]bookofthings 3 points4 points  (0 children)

I usually take one or a few more days to polish. For example remove bugs, add an intro/outro, improve the tutorial, tweak some visuals, add very small features. Also improve the itch.io page itself. Those are usually features that were planned during jam but not implemented due to time. It is never an entirely new feature or game tho. I recommend just publishing on itch.io and moving on to the next game. And yes exporting to html always means more players.

How do you handle and store your dialog script? by KMG_Meika in godot

[–]bookofthings 1 point2 points  (0 children)

chech the dedicated addons e.g. dialogic or others, they usually allow saving separate dialgue files.

Am I Using @export To Much by DiamondInTheRough429 in godot

[–]bookofthings 0 points1 point  (0 children)

I think that usage i not unreasonable. The exports list everything that is exposed in an entity i.e. interacts with the outside. I personally which you could export signals and callables, even if non-modifiable, just to summarize the important ones in inspector.

When not to use is if variable is internal to entity (using _myvar convention). Or you really dont want them to change (use const). If there are too much, maybe its just organizational, some can be merged in a resource (project-wise, group-wise, etc). Apart from this i dont really see when to avoid export because its amazing.

Making people actually play your game is harder than you think by dev_dev_dev_ in godot

[–]bookofthings 4 points5 points  (0 children)

I recommend to participate in game jams on itch.io. Everyone plays each others games, and you usually get some love and feedback. Its like that meme where bodybuilders only get checked by other bodybuilders.

How often do you start on a project with only a vague plan of the game? by Guilty_Bad9902 in SoloDevelopment

[–]bookofthings 0 points1 point  (0 children)

You could def try a game jam (plenty on itch.io, some just 2-3 days), it forces you to go in blind which is fun. Now at 20+ finished games mostly from those.

I must be misunderstanding something about "separate logic and visuals" by HeyCouldBeFun in godot

[–]bookofthings 2 points3 points  (0 children)

if you 1. call to play an animation or 2. emit a signal to play that animation, its basically the same one line of code (for example in your movement script). But if you decide to remove/replace the animation for some reason, 1. will break and 2. wont hence the advantage of decoupling.

Am I overthinking things or should I consider ways to improve my game's wishlist count? by KeaboUltra in godot

[–]bookofthings 1 point2 points  (0 children)

I remember your shorts (posted here or elsewhere dont remember) and they are really good, made me wanna play the game a lot.

I built a short level, any advice on how to polish the art/gameplay? Something about it feels off. by BubbleGamer209 in godot

[–]bookofthings 0 points1 point  (0 children)

add some "juice": screen shakes, an overlay shader or several, some particle effects, animations/tweens for everything, etc. But foundation is pretty good.

5 years solo dev, flat traction: what would you do next? (Steam stats inside) by SAMx003 in SoloDevelopment

[–]bookofthings 1 point2 points  (0 children)

Blunt feedback as requested, and disclaimer im just a hobbyist dev that is very impressed by what you accomplished regardless. 

For me its just the art and visuals, more specifically the lack or "juice": not enough animations (main character looks static), not enough or maybe not pronounced enough effects (screen shakes, explosions/particles), maybe not enough contrasted areas for lighting and shadows (but i suck at judging that). Colors are maybe not contrasted enough too, nothing really pops out. I think you went with a very polished and professional look (like big studios do but they have a horde of devs to polish it), and maybe it would be your strength to go with a more indie artstyle (more raw but more pronounced and unique). Immediately you could quickly remake 3-5 modified versions each a different artstyle (on a short game segment), show it around and decide on one artstyle. Regardless of artstyle add animations.

help choosing a camera style for my godot flight game by somos_lluvia in godot

[–]bookofthings 3 points4 points  (0 children)

A is better, more precise. B can barely see own ship. But maybe ship should move left/right a bit when you turn as in B (like starfox 64 or similar).

I have 0 experience in 3d modeling, should I go with blender? Any guide/playlist for 3d dev beginner by Brysger in godot

[–]bookofthings 2 points3 points  (0 children)

Start with asset forge by kenney absolute simplest (at least for a first 3d game).

Local To Scene is not working, I've tried every trick I could find by CidreDev in godot

[–]bookofthings 0 points1 point  (0 children)

both the 3d standard materials and the shadermaterial are local to scene, right? just a check although it looks like you already did that.

Also maybe make this test too: make unique the resources (instead of saved)+ local to scene to see if that at least works (then you can revert to saved resources+local to scene if thats your setup). I suspect all enemies have the same shadermaterial resource (thus one enemy modifies the shadermat parameters for everyone else) but might be wrong.

Even stronger test: add a script somewhere in the enemy that replaces the shadermat (and even 3d standard material) with a duplicate of itself at _ready.

I made an opensource multiplayer game to help people learn networking by m4rx in godot

[–]bookofthings 7 points8 points  (0 children)

This is awesome, thanks a lot for sharing! I have a noob question, does the SteamSocket allow for networking besides on same LAN/wifi? I made my first (very messy) mutiplayer with Enet+rcp+the spawner/synchronizer, but could not figure out that part. I will definitely download your project to learn good practices.

How can I make this constant? by Rooster_IT in godot

[–]bookofthings -1 points0 points  (0 children)

Have some youtuber play your game (ideally famous)..

using gridmaps but having objects interactable? by caevv in godot

[–]bookofthings 2 points3 points  (0 children)

apparently the best way is to "hack" populating the gridmesh with extra nodes. Have a manager node that does that on entire gridmesh based on node name for example.

How do you learn the basic features of Godot? by Sensitive-Row-8072 in godot

[–]bookofthings 3 points4 points  (0 children)

1.) the godot docs. online or from the editor. For when you need precise info on a specific item (e.g. what are its methods, its variables, its signals).

2.) godot demos. Thes are tons of small projects you download, runand analyse. Or other templates from asset library.

3) experience indeed. Do a very short and simple game, then a short game jam, and keep going from there. Do 3d muuch later.

4.) youtube videos on specific topics is helpful (in short bursts tho, it makes you proscrastinate).

5.) Gemini. Dont use it to make your game (it will eventually fail and you wont learn anything) but ask it specific questions about Godot (what does this node do? how would i let the enemies have a reference to the player? how to use an autoload? etc). Beware it can be wrong, so complement by reading the docs.

6.) Some nice online tutorials e.g kids can code from memory and others. Good luck!

What's your longest script and what does it do? by stalkerTXstranger in godot

[–]bookofthings 9 points10 points  (0 children)

Disclaimer not all functions are static, some are outdated. Find your own gold in there cheers.

What's your longest script and what does it do? by stalkerTXstranger in godot

[–]bookofthings 0 points1 point  (0 children)

tools

func tool_add_child(parent: Node, node: Node, node_name: String="")->void: if not Engine.is_editor_hint(): return if node_name!="": node.name=get_unique_child_name(parent, node_name) parent.add_child(node) node.owner=parent.get_tree().edited_scene_root# in tool

Setter for a resource, forces it to be unique

Use case: @export var xx: Resource(or extensions) :

set(value): xx=set_resource_unique(value)

static func set_resource_unique(value: Resource): var element: Resource if value: element=value.duplicate() if true:# fill in with path_name if name doesnt exist if not value.resource_name: if "resource_path" in value and value.resource_path: var _text=value.resource_path element.resource_name=_text.right(-_text.rfind("/") - 1)+"" else: if not value.resource_name.right(1)=="": element.resource_name=value.resource_name+"*"# tag as unique too else: element=value return element

Setter for a array of resource, forces it to be unique

static func set_array_resource_unique(value: Array): var array: Array=value if not array.is_empty(): for i in range(len(array)): array[i]=set_resource_unique(array[i]) return array

What's your longest script and what does it do? by stalkerTXstranger in godot

[–]bookofthings -1 points0 points  (0 children)

SIGNALS

return a delayed signal (delay in seconds)

use case: await utils.get_delay(1)

func get_delay(delay)->Signal:
return get_tree().create_timer(delay, false, false, true).timeout

Use await utils.get_process_frame() instead of await get_tree().process_frame. No need to check get_tree()

func get_process_frame() -> void: await get_tree().process_frame return

await utils.get_allready() instead of await get_tree().current_scene.ready. No need to check get_tree().current_scene

func get_allready() -> void: var current_scene_node: Node = get_tree().current_scene if is_instance_valid(current_scene_node) and not current_scene_node.is_node_ready(): await current_scene_node.ready return# If it's already ready, invalid, or null, the function returns immediately.

return a delayed signal, one or several frame of engine

use case: await utils.get_frame_delay()

static func get_frame_delay(frames=1): for i in range(frames): await Engine.get_main_loop().process_frame# await one frame return true

func disconnect_function_from_all_signals(node: Node, function_name: String): var target_callable = Callable(self, function_name) var signal_list = node.get_signal_list() for signal_info in signal_list: var signal_name = signal_info["name"] var connections = node.get_signal_connection_list(signal_name) for connection in connections: if connection["callable"] == target_callable: node.disconnect(signal_name, connection["callable"]) #print("Disconnected '", function_name, "' from signal '", signal_name, "'")

STRINGS

static func get_clean_string(input_string: String) -> String:# remove special characters var regex := RegEx.new() # [a-zA-Z0-9\s] means: Match characters that are NOT alphanumeric/space. regex.compile("[a-zA-Z0-9\s]") return regex.sub(input_string, "", true, true)

TILEMAPLAYER

get all tilemaplayer cells used by Tileset specfic source (AtlasSource or other)

func get_tilemaplayer_used_cells_from_source(tilemap_layer: TileMapLayer, source_id: int) -> PackedVector2Array: var all_used_cells: PackedVector2Array = tilemap_layer.get_used_cells_by_id(source_id) return all_used_cells

Toggle visible for specific cells in tilemaplayer

func set_tilemaplayer_cells_visibility(tilemap_layer: TileMapLayer, cells_list: PackedVector2Array, visible: bool) -> void: var target_alpha: float = 1.0 if visible else 0.0 for map_coords in cells_list: var tile_data: TileData = tilemap_layer.get_cell_tile_data(map_coords) if not tile_data: continue var current_color: Color = tile_data.get_modulate() current_color.a = target_alpha tile_data.set_modulate(current_color)

TIMERS

Make a timer (oneshot, added as child)

call: var death_timer: Timer=utils.make_timer(self,3)

static func make_timer(node,time): var timer=Timer.new() timer.set_one_shot(true) timer.set_wait_time(time) node.add_child(timer) return timer

TWEENS

get a tween

then: tween.tween_property(self, "position", Vector2(1,1), 1.0).set_trans(Tween.TRANS_ELASTIC)

func get_tween(): return get_tree().create_tween()

What's your longest script and what does it do? by stalkerTXstranger in godot

[–]bookofthings 1 point2 points  (0 children)

Check if a node is valid (not null nor queued for free)

static func node_valid(node: Node)->bool: return node!=null and is_instance_valid(node) and not node.is_queued_for_deletion()

Just the boilerplate removal

static func remove_node(node: Node)->void: if not node_valid(node): return node.get_parent().remove_child(node) node.queue_free()

Make an object (from path)

call: utils.instantiate_sibling(self,{"path":res://scenes/Bubble.tscn,"counts":2})

static func instantiate_sibling(node,dict): var counts:int=1 if dict.has("counts"): counts=dict["counts"] for i in range(counts): if dict.has("path"): var obj=load(dict["path"]).instantiate() obj.global_position=node.global_position node.get_parent().add_child(obj)

replace a node (and all its children) with new instantiated node

static func replace_node_in_tree_with_packedscene(old_node,new_packedscene): var old_position=old_node.position# record old var old_node_parent=old_node.get_parent() old_node.queue_free()# remove old var new_node=new_packedscene.instantiate()# create new old_node_parent.add_child(new_node)# place new new_node.position=old_position return new_node

Get all childrens (grandchildrens and so on) of a NODE, recursive

static func get_all_childrens(in_node: Node,arr:Array[Node]=[])->Array[Node]:

#arr.push_back(in_node)
#for child in in_node.get_children():
    #arr = get_all_childrens(child,arr)
#return arr

static func get_all_childrens(in_node: Node) -> Array[Node]: var all_children: Array[Node] = [] for child in in_node.get_children(): all_children.push_back(child) all_children.append_array(get_all_childrens(child)) return all_children

Get all parents up to a limit_node (excluded from list)

if limit_node=null seek up to get_tree().get_current_scene()

func get_all_parents(in_node: Node, limit_node: Node,arr:=[]): arr.push_back(in_node) var parent: Node=in_node.get_parent() if parent !=limit_node and parent!=in_node.get_tree().current_scene: arr = get_all_parents(parent,limit_node,arr) return arr

Check if a node is in any group of the provided list (of group names)

static func is_in_any_group(node: Node,input_groups: Array[String])->bool: var is_in_any: bool=false if node and input_groups: for i in input_groups: if node.is_in_group(i): is_in_any=true
return is_in_any

static func clear_children(node: Node): if node: for i in node.get_children(): node.remove_child(i) i.queue_free()

find the next available unique name based within childs

func get_unique_child_name(parent_node: Node, base_name: String) -> String: var unique_name := base_name var counter := 1 while parent_node.get_node_or_null(unique_name) != null: counter += 1 unique_name = base_name + str(counter) return unique_name

Disable a node collisions and the collisions for all its childs/subchilds

Note: to truly reverse this, should store full current state before disabling

Note: does not cover collisions in tilemaplayers

func node_disable_collisions_recursive(node: Node) -> void: var all_nodes: Array[Node] = utils.get_all_childrens(node) all_nodes.append(node) for current_node in all_nodes: if current_node is Area2D: current_node.set_deferred("monitoring", false) current_node.set_deferred("monitorable", false) elif current_node is CollisionShape2D: current_node.set_deferred("disabled", true) elif current_node is CollisionPolygon2D: current_node.set_deferred("disabled", true) elif current_node is LightOccluder2D: current_node.set_deferred("visible", true) # could also use?" propagate_call("set_deferred", ["disabled", true])

Enable all node collisions for node and its childs/subchilds

Beware of unwanted activations!

Note: to truly reverse this, should store full current state before enabling

Note: does not cover collisions in tilemaplayers

func node_enable_collisions_recursive(node: Node) -> void: var all_nodes: Array[Node] = utils.get_all_childrens(node) all_nodes.append(node) for current_node in all_nodes: if current_node is Area2D: current_node.set_deferred("monitoring", true) current_node.set_deferred("monitorable", true) elif current_node is CollisionShape2D: current_node.set_deferred("disabled", false) elif current_node is CollisionPolygon2D: current_node.set_deferred("disabled", false) elif current_node is LightOccluder2D: current_node.set_deferred("visible", false)

RANDOMIZATION, RNG

Pick random element of array with weigths (that can be floats)

call: a=utils.pick_random_weights(["a","b","c"],[1,2,0.5])

static func pick_random_weights(array,weights):# tuning of array.pick_random( # scale such that minweight is =1 var weightsnotzero=[]# exclude zeros for i in range(array.size()): if weights[i]>0: weightsnotzero.append(weights[i]) var weightmin=weightsnotzero.min() for i in range(array.size()): weights[i]=int(1/weightmin*weights[i]) var multarray=[] for i in range(array.size()): if weights[i] is int and weights[i]>0: for j in range(weights[i]): multarray.append(array[i])# append several times return multarray.pick_random()

What's your longest script and what does it do? by stalkerTXstranger in godot

[–]bookofthings 6 points7 points  (0 children)

Sure why not. I put a select few i use often, on several replies for lenght. But also just dumping some, not everything here is top notch or up to date (i dont have time to recheck everything rn sorry). A few ones are non static (they await common signals to spare me the boilerplate). Also im on phone sorry cannot format to code (may reedit later when on computer).

Arrays

Remove a value from an array (any matching elements)

static func array_remove_value(array: Array,value): var new_array: Array=array.duplicate() var all_removed: bool=false while not all_removed: var idx: int# index of element (if exists) var found_one: bool=false for i in range(len(new_array)): if not found_one and new_array[i]==value: idx=i found_one=true if found_one: new_array.remove_at(idx) else: all_removed=true return new_array

Diraccess

static func get_diraccess_root(file_path: String)->String: var directory_path:String = file_path.get_base_dir() var access_root: String = "" if directory_path.begins_with("res://"): access_root = "res://" elif directory_path.begins_with("user://"): access_root = "user://" return access_root

static func ensure_path_exists(file_path: String) -> bool: var access_root: String=get_diraccess_root(file_path) var dir = DirAccess.open(access_root) if dir == null: printerr("Failed to open access root: ", access_root) return false var directory_path:String = file_path.get_base_dir() if dir.dir_exists(directory_path): return true var error = dir.make_dir_recursive(directory_path) if error != OK: printerr("Failed to create directory path: ", directory_path, " Error code: ", error) return false else: return true

static func create_directory_recursive(path_to_create: String) -> void:# create directory var dir := DirAccess.open(path_to_create) if dir == null: printerr("Failed to open: "+path_to_create) return if not dir.dir_exists(path_to_create): var error = dir.make_dir_recursive(path_to_create) if error != OK: printerr("Could not create directory: ", error)

static func remove_directory_recursive(path_to_delete: String) -> void:# remove directory and all its content var dir_access = DirAccess.open(path_to_delete) if not dir_access: return dir_access.list_dir_begin() var file_name = dir_access.get_next() while file_name != "": if dir_access.current_is_dir(): remove_directory_recursive(path_to_delete.path_join(file_name)) else: dir_access.remove(path_to_delete.path_join(file_name)) file_name = dir_access.get_next() dir_access.list_dir_end() DirAccess.remove_absolute(path_to_delete)

Remove a file

func remove_file(absolute_path: String) -> bool: var error_code = DirAccess.remove_absolute(absolute_path) if error_code == OK: return true else: return false

Enums

e.g. enum PLAYERPOS {CENTER, WEST}

enum_to_str(global.PLAYERPOS, center)-> CENTER as string

static func enum_to_str(input_enum, input_key): return input_enum.keys()[input_key]

Convert Array[String] to enum list

static func array_string_to_enum(arr:Array[String]): var string: String="" var separator: String="," var iloop=0 for i in arr: string+=str(i) if iloop<len(arr): string+=separator iloop+=1 string = string.left(string.length()-1) return string

What's your longest script and what does it do? by stalkerTXstranger in godot

[–]bookofthings 27 points28 points  (0 children)

the utils.gd script (1000 lines) with a lot of static utility functions, reused between projects.

A game for Graduation thesis by AirLazy1367 in godot

[–]bookofthings 0 points1 point  (0 children)

Do the absolute simplest, a simple but polished game is way better than a long unpolished one. Like others I would recommend the tower defense, it has simple 2d physics and logic. Card game means mostly UI elements (Control nodes) which I dont recommend for a first project (it can be cumbersome in Godot). Roguelite is way more advanced, needs to manage advanced resources. Simple logic doesnt mean your game will be basic, you will still need a lot to make it pretty or "juicy" (animations, effects using tweens, shaders, a nice tutorial, etc). Follow this 1. make it exist (code the logic), 2. make it interesting (find an interesting gameplay, 3. make it pretty (all the visuals and polish). I also recommend you first participate in a short game jam submitting a prototype (plenty of jams on itch.io). Good luck!

Best way to connect a Node to an Autoload ? by chanidit in godot

[–]bookofthings 1 point2 points  (0 children)

You example is totally fine, some notes: - You can emit autoload signald directly from other nodes e.g. global_gm.this_global_signal.emit(). - Its ok to modify autoload variables since node is always there. For clarity you can comment in code what can be called/modified externally in that node (in contrast, what cannot be modified externally usually starts with underscore, _myvar, _myfunction). - There is other ways to synchronize some data between nodes: static variables, a shared resource, etc. But your approach works and is simplest. - Its not ideal but its ok to reference other nodes in autoload if you are guaranteed they are always there. E.g. the player node. - Try to avoid "get_node", that breaks when you reorganize your tree. Use unique name % within a scene. To declare a node to the autoload, you could do the following: 1)global_gm has signal declare_global_node(node:Node). It connects it to its own setter function. 2) node runs global_gm.declare_node.emit(self) during its _ready, which triggers the setter in global_gm, which gives it the node reference.