Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A dictionary for people moving from GM:S to Godot

License

NotificationsYou must be signed in to change notification settings

coppolaemilio/gamemaker-godot-dictionary

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cover

This document is for game maker devs like me that are moving their games or engine from GM:S to Godot. The first section gives a brief overview of the framework differences. The rest gives an API comparison for specific GML functions and their GDScript equivalent. You can use your browser's search functionality to find particular GML functions.


Index

  1. Framework
    1. Objects
    2. Scenes
    3. Inheritance
  2. Events
  3. Scripts
  4. Globals
  5. Grouping objects
  6. Instance functions
  7. Drawing functions
  8. Image variables
  9. Direction functions
  10. Strings
  11. Random functions
  12. Math functions
  13. Game functions
  14. Room functions
  15. Window functions
  16. Other functions
  17. Data Structures
  18. Collision functions

Framework

Below is a list of basic framework differences between the two engines. Understanding these will help you more quickly adapt to Godot's workflow.

Objects

In Game Maker, you create aroom filled with a list ofobjects that each may hold asprite and a series ofevents which in turn trigger a series ofactions.Your scripted behavior exists in theactions portion. To reproduce this behavior multiple times between objects, you create ascript that can be executed as a singleaction.

In Godot, you create ascene filled with a hierarchy of specialObjects calledNodes. Rather than having you specify logic attached to a generic object though, Godot providesa variety of customized objects for you. When you create aScript, you are in factextending an existingObject type with custom features.

Objects in Godot can have any combination of...

  • properties (like defining a variable during the Create Event)
  • constants (same, but they cannot be changed)
  • methods (like an action or series of actions)
    • Note that some methods are "notifications", triggered by the engine automatically. These are often preceded with an underscore '_'.
  • signals (like custom events that other objects can react to)

Many of the code comparisons you see will illustrate a method, a.k.a. function, in place of an event's logic. Rather than having several scripts that each supply the logic for a single event's action(s), Godot has you define a single script per object with multiple functions defined for each "event" (perhaps even one for multiple).

Scenes

Game Maker's rooms provide a flat list of the different types of assets that exist in the room. In order to have multiple sprites or physical objects come together to form the same object, you have to manually position them all during a step event by globally accessing them from within the room.

Godot's scenes are more small scale and self-contained. Your scenes can effectively be an object unto themselves as you add all of the necessary Sprites, PhysicsBody2Ds, and other Nodes to your scene's hierarchy to build up your object. That scene can then beinstanced within a larger scene, similar to creating an object in a room. What's more, the nodes lower in the hierarchy will automatically move relative to their parent, so there is no need to manually position them.

Inheritance

In Game Maker, there is a concept of having a "parent" object. Child objects then inherit properties and functions from the parent. However, in Godot there are two distinct concepts: Inheritance and Ownership.

When you construct a scene, you are creating a hierarchy of nodes with parent-child relationships. The node at the top, i.e. the "root of the scene", provides a single point of contact between this scene and others. However, the child nodes do not inherit its functionality. The parent merely "owns" each child node and may pass on information to it that it can use.

This is why a child Node2D will move relative to its parent. The parent tells the child where the parent exists, and the Node2D object will take that into account when positioning itself.

To implement inheritance, you create a script and place it on a "base" object. You may then define custom features for this new type. These scripts will know the properties, constants, methods, and signals of the base object they are extending.


Events

In Game Maker, when you need to code logic inside an object, you use Events. There are many kinds of events but the most used ones are:create,step,draw.

Create Event

When you need to declare variables for an object in GMS you do it inside theCreate Event. The equivalent in Godot is a function called_ready(). The main difference here is that on GMS, theCreate Event declares variables that are accessible from everywhere. In Godot if you want your variables to be exposed to other functions or Nodes (objects) you need to declare them outside of the_ready() function at the top of the document.

Imagine that we want to set the variableplayer_speed to10 but if there are monsters present, you want it to be5.In Game Maker you can code all this inside theCreate Event:

GMLCreate Event

player_speed =10;monsters = instance_number(obj_monster);if (monsters) {    player_speed =5;}

In Godot you will have to code it like this:

GDScript_ready()

extendsNodevarplayer_speed=10func_ready():varmonsters=get_tree().get_nodes_in_group("MONSTERS").size();ifmonsters:player_speed=5

Step Event

SimpleStep Event function for moving an object.

GMLStep Event

x += player_speed;

GDScript_process()

func_process(delta):position.x+=player_speed

Draw Event

SimpleDraw Event function for drawing a rectangle.

GMLDraw Event

draw_rectangle(100,120,132,152,false);

GDScript_draw()

func_draw():draw_rect(Rect2,Color,boolfilled=true)

Destroy event

Godot does not provide an equivalent notification function for theDestroy Event but it can be accessed through the actual notification callback.

GDScript_notification(what)

func_notification(what):matchp_what:NOTIFICATION_PREDELETE:# execute logic before deleting the object.

Another option is to easily code up your own in GDScript. Instead of destroying that node with the usualqueue_free() you create a function calleddestroy() and execute some code before self deleting.

GDScriptdestroy()

funcdestroy():# Here you write whatever you want to# run before removing the nodequeue_free()

Scripts

In game maker you can create scripts that you can call from any object in your project. In Godot, the so called "scripts" are called functions and you can declare all the customfunctions that you want inside any node.

To compare between the two you can see this simple "script" that will add two numbers:

GML: Create new script called add_numbers

return argument0 + argument1;

GDScript: Inside a node's code

funcadd_numbers(argument0,argument1):returnargument0+argument1

In Godot instead of using the namesargumentX it is recommended that you use a more descriptive name. Every argument named when you declare the function will create a variable that you can use from inside of it.

funcadd_numbers(number_one,number_two):returnnumber_one+number_two

Globals

In Game Maker you can declare globals very easy by just addingglobal. at the start of a variable. In Godot you can create a similar kind of variables via theSingletons (AutoLoad) feature.

I recommend you to read the entry of the Godot documentation but to get a quick equivalent you can do the following:

  1. First of all, create aglobal.gd script.

  2. Then, Select Project > Project Settings from the menu, switch to the AutoLoad tab

  3. Add a new entry with name “global” that points to this file:

Autoload menu screenshot

Now, whenever you run any of your scenes, the script is always loaded. The variables declared insideglobal.gd can be accesed or modified the same way you would do in GML:global.variable_name.

The cool thing about godot is that you can also declare functions inside theglobal.gd file that you can use from any other instance inside your game.


Grouping objects

In Game Maker objects are automatically grouped by object_index. This process is not automatic for Godot, so you will need to manually add your nodes to a group to be able to refer to them and perform group actions on them as conveniently as you would in Game Maker. You can add nodes to groups either through code or the editor IDE. Generally you will only want to add your scene's root-node to the group, not all the attached Sprites and CollisionShapes. When the node is deleted it is automatically removed from groups.

Example:

Create a new scene in the editor called Tree.tscn, then attach a script to the scene's root-node with the following code:

func_ready():add_to_group("Tree")

Now every Tree scene you place will be a part of that grouping, which has a variety of uses.

object_index

GML

if object_index = obj_monster {// Object is obj_monster}

GDScript

ifis_in_group("obj_monster"):# Node is obj_monster

With

GML

with object {    y +=1;}

GDScript

foriinget_tree().get_nodes_in_group("groupname"):i.position.y+=1

Alternatively, you can run a function that's inside all members of the group:

get_tree().call_group("groupname","function",argument0,argument1,etc)

Instance functions

Instance number

GML

instance_number(obj);

GDScript

get_tree().get_nodes_in_group("obj").size()

Instance create

GML

instance_create(x, y, obj);

GDScript

varscene=load("res://scenefilename.tscn")varid=scene.instance()add_child(id)id.position=Vector2(x,y)

Instance destroy

GML

instance_destroy();

GDScript

queue_free()# for Nodes, waits until next frame to delete all queued Nodes at oncefree()# for all Objects, deletes immediately

Note that deleting a Node will also delete all of its attached children automatically.


Drawing functions

On game maker you can only use the drawing functions inside the draw event of an instance. On Godot you have to call the drawing functions inside afunc _draw() of aCanvasItem.

Generally in Godot, you don't really need to call draws all the time since you can use pre-built scenes with everything for your UI. Things like text, panels, buttons and so on are already built-in and ready for you to use without any need to code the entire logic from scratch like you would have to do in Game Maker. Please search for any "Control Nodes" tutorials online and you will find how good this part of Godot is.

This guide will get you started with UI design:Design interfaces with the Control nodes

If you still want to torture yourself with individual draw calls, here you have some references:

Making colors

GML

// These values are taken as being between 0 and 255make_colour_rgb(red, green, blue);

And you also have the colors likec_white,c_blue, etc..

GDScript

# Constructs a color from an RGB profile using values between 0 and 1 (float)Color(0.2,1.0,.7)# You can also set the color alpha by adding an aditional valueColor(0.2,1.0,.7,0.5)

You can also create a color from standardised color names withColorN. See the full listhere.

Drawing a rectangle

GML

draw_rectangle(x1, y1, x2, y2, outline);

GDScript

draw_rect(Rect2,Color,boolfilled=true)

Example:

To draw the same rectangle on both engines:

GML

draw_set_color(c_red);draw_rectangle(100,120,132,152,false);

GDScript

draw_rect(Rect2(Vector2(100,120),Vector2(32,32)),Color("red"),true)

Drawing text

Drawing text is a bit more tricky in Godot. Make sure you declare the font resource outside of the_draw() function.

GML

draw_text(x, y, string);

GDScript

draw_string(font,Vector2(x,y),string,color,separation)

Example:

To draw the same rectangle on both engines:

GML

draw_set_font(fn_bitter);draw_set_font(make_color_rgb(0,0,0));draw_text(140,100,"Hello world");

GDScript

varfont=load('res://fonts/Bitter.tres')func_draw():draw_string(Bitter,Vector2(140,100),"Hello world",Color(0,0,0,1),-1)

Image variables

image_blend

GML

image_blend = c_red;

GDScript

modulate=Color.red

image_angle

Godot rotates clockwise while Game Maker rotates counter-clockwise.

GML

image_angle =90;

GDScript

rotation_degrees=-90

Visibility

GML

visible =true;visible =false;

GDScript

show()hide()visible=truevisible=falseset_visibility(true)set_visibility(false)

Direction functions

All rotation functions in Godot will rotate clockwise as the variable increases (GameMaker rotates counter-clockwise) and most functions take radians and output radians, not degrees. It's best to get used to these differences, thoughdeg2rad() andrad2deg() can help out. If you want to adjust a radian by degrees you can simply do:+deg2rad(180).

Point Direction

GML

degrees = point_direction(x1, y1, x2, y2)

GDScript

varradians=Vector2.angle_to_point(Vector2)

point_direction returns degrees, whileangle_to_point returns radians. Another difference is the order the coordinates are taken, if a backwards angle is returned you may want to swap the Vector2s.

Length Direction

GML

move_x = lengthdir_x(len, dir);move_y = lengthdir_y(len, dir);

lengthdir_x/y returns individual X or Y vector components, while the Godot equivalent will store both of those floats in a Vector2.

GDScript

varmove_xy=Vector2(1,0).rotated(radians_var)*length

Alternative:

varmove_xy=Vector2(cos(radians_var),sin(radians_var))*length

In place ofradians_var we can use our earlierangle_to_point output variable (which is in radians), or maybe writedeg2rad() for something else.


Strings

String functions are a little bit different because in game maker everything is a function but in Godot they are methods. You can also treat Strings in godot like arrays.

String Length

GML

string_length(string);

GDScript

string.length()

String Char At

GML

string_char_at(string, index);

GDScript

string[index]

String Upper/Lower

GML

string_upper(string);string_lower(string);

GDScript

string.to_upper()string.to_lower()

String Delete

GML

string_delete(string, index, count);

GDScript

string.erase(index,count)

Random functions

Choose

GML

var value = choose(1,2,3);

In order to achieve something similar in Godot you have to first create an array with all the options and then get a random value from that array.

GDScript

varoptions= [1,2,3]varvalue=options[randi()%options.size()])

Math Functions

Arc Sine

These functions take in a single float and return the arc sin

GML

arcsin();

GDScript

asin()

Arc Cosine

These functions take in a single float and return the arc cos

GML

arccos();

GDScript

acos()

Arc Tangent

These functions take in a single float and return the arc tan

GML

arctan();

GDScript

atan()

Game functions

Game end

With this function you can quit the game.

GML

game_end();

GDScript

get_tree().quit()

Room functions

Change room

GML

room_goto(room_name)

GDScript

get_tree().change_scene("res://nameofthescene.tscn")

Room restart

GML

room_restart();

GDScript

get_tree().reload_current_scene()

Window functions

Set caption

GML

window_set_caption(string);

GDScript

OS.set_window_title(string)

Other functions

Open website on browser

This will open the specified URL on the browser.

GML

url_open('http://yoyogames.com' );

GDScript

OS.shell_open('http://godotengine.org/')

Distance to object

This is a similar way of calculating the distance from an instance to another. On gdscript all the variables have to be Vector2. Also, be mindful that not all nodes have theposition variable.

distance_to_object(obj_Player)
position.distance_to(Player.position)

Data Structures

Stack, Queue, List, Serialization

Godot's Array doubles as the stack and queue data structure. Unfortunately, Godot has no Lists for the scripting API (although the engine itself has them).

GMLglobal Stack functions

stack = ds_stack_create();// ...do various insertionsifds_stack_empty(stack) {// is empty}elseifds_stack_size(stack) == 3 {// there are 3 items on the stack    stack2 =ds_stack_create();ds_stack_copy(stack2, stack);    top =ds_stack_top(stack2); /top is the item at index2ds_stack_pop(stack2);//top's value is no longer in stack2ds_stack_push(stack2,5);//top's previous index now has value 5    serialized_data =ds_stack_write(stack2);//converts stack2 into a data string    stack3 =ds_stack_read(serialized_data);//deserializes the data string into another stack object.}ds_stack_clear(stack);ds_stack_destroy(stack);

GDScriptArray type as "stack"

vararr= []ifarr.empty():# if not arr: also workspasselseifarr.size():# else if arr: also worksvararr2=arr.duplicate()vartop=arr2.back()arr2.pop_back()arr2.push_back(5)# a stringified version of the array, but not actually serialized datavararr_str=str(arr2)# all serialized data is stored on Resource objects which automatically serializes all properties of any kind.varres_script=GDScript.new()res_script.source_code="extends Resource\n"res_script.source_code+="var array"res_script.reload()# ^ you could also just create an actual script and load it, e.g.res_script=load("res://res_script.gd")varres=res_script.new()res.array=arr2ResourceSaver.save("res://my_array.tres",res)# serializes all properties on res for youvarres2=load("res://my_array.tres")arr.clear()# because Arrays are allocated with a reference counter, they automatically delete themselves when no references to them exist anymore.

In addition topush_back() andpop_back() to simulate a stack, Godot's arrays also havepush_front() andpop_front(). The combination ofpush_front() andpop_back() gives you a queue's features.

Maps

Godot's Dictionary object is the equivalent of GML's DS Map. They can be inlined into GDScript code just like Arrays by using curly brackets.

Unlike DS Maps however, Arrays, Dictionaries, and other data (even custom Objects!) can be made into a keyor value in a Dictionary (or a value in an Array). This is contrary to what the Yoyo Games docs have to say about DS Maps:

NOTE: While these functions permit you to add lists and maps within a map, they are useless for anything other than JSON, and nested maps and lists will not be read correctly if written to disk or accessed in any other way.

GMLglobal Map functions

map = ds_map_create();ds_map_add(map,"level",100);ds_map_add(map,5.2,"hello");map[?"super"] ="awesome";ds_map_add(map,"super","goodbye");// fails because key "super" already existsifds_map_exists("super") {// "super" is a keyds_map_replace(map,"super","goodbye");//succeeds because this is a "replace" operationds_map_delete(map,"super");// now key "super" is gone}ifds_map_empty(map) {// it is empty}elseifds_map_size(map) == 2 {// has 3 key-value pairs}// iterationvar size, key, i;size = ds_map_size(inventory);key = ds_map_find_first(inventory);for (i =0; i < size; i++;) {if key !="level" {        key =ds_map_find_next(inventory, key)    }else {break;    }}map2 = ds_map_copy(map);// map2 is now a copy of map3serialized_data = ds_map_write(map);//converts map into a data stringmap3 = ds_map_read(serialized_data);//deserializes the data string into another map object.ds_map_clear(map);// it is now emptyds_map_destroy(map);// memory is freed

GDScriptDictionary type

vardict= {"hello":"world"}# initialization, just like an array, could be empty with '{}'dict["level"]=100dict[self]= {3.4:"PI",    [1,2,3]:GDScript.new(),}ifdict.has(self):dict[self]="testing"# just deleted all of those objects because their references disappeared by overwriting the valuedict.erase(self)# the key-value pair is now gone.ifdict.empty():pass# it is emptyifnotdict:pass# sameifdict.size():# if dict: also workspass# the Dictionary is non-emptyifdict.size()==2:pass# there are 2 key-value pairs that exist# iterationfora_keyindict:print(dict[a_key])# Iterate over first 3 key-value pairs.# Safely exit early if it isn't that largevari=0fora_keyindict:varvalue=dict[a_key]i+=1ifi==3:break# string keys can be directly accessed as if properties on an objectvarvalue=dict.level# copy the Dictionaryvardict2=dict.duplicate()# serialization is the samevarres_script=load("res://res_script.gd")varres=res_script.new()# res_script.gd needs to define a property, in this case called 'foo'res.foo=dict2ResourceSaver.save("res://res.tres",res)varres2=load("res://res.tres")# these print the same thingprint(dict2)print(res2.foo)dict.clear()# going out of scope means that the local variables 'dict', 'dict2', 'res_script', 'res', etc. disappear and all references to them end.# Because they either an Array, a Dictionary, or a Reference object, they are freed automatically when all references to them vanish.

For JSON manipulation, you can also freely translate a combination of Arrays, Dictionaries, and other data from GDScript into a JSON string and back by using the JSON global.

JSONparse(string)

varp=JSON.parse('{"hello": "world"}')ifpandp.error==OK:iftypeof(p.result)==TYPE_DICTIONARY:print(p.result["hello"])# prints "world"iftypeof(p>result)==TYPE_ARRAY:pass# could be possible, with a different JSON stringelse:print("parse error")

Priority Queue

Godot does not provide its own Priority Queue object. Instead, to accomplish its functionality, you must either implement your own special Node class that handles its own sub-hierarchy of nodes, or you must use an Array in which you sort it after every mutable operation. Array comes with a built-insort function for simple types and the option to specify your own sorting algorithm with asort_custom method.

Arraysort_custom(script, static_function_name)

classMyCustomSorter:staticfuncsort(a,b):ifa[0]<b[0]:returntruereturnfalsevarmy_items= [[5,"Potato"], [9,"Rice"], [4,"Tomato"]]my_items.sort_custom(MyCustomSorter,"sort")

The "min" and "max" are then always located atfront() andback(), respectively.

Grid

Godot does not provide its own grid class (the TileMap and GridMap nodes are purely for visualization purposes). To create a 2D array, you need to create an array of arrays:

GDScriptArray of Arrays

vararr= [    [0,1,2],    [3,4,5],    [6,7,8],]print(arr[1][2])# prints 5

There are no special utilities methods to assist in 2D array operations. You will have to code those manually, perhaps with a script extendingReference.

# grid.gdextendsReferencevardata= []func_init(width=0,height=0):resize(width,height)funcget_width():varmax=0forarrindata:ifarr.size()>max:max=arr.size()returnmaxfuncget_height():returndata.size()funcresize(width,height):data.resize(height)forarrindata:arr.resize(width)# ...etc.# node.gdextendsNodeconstGrid=preload("res://grid.gd")func_ready():vargrid=Grid.new(3,5)# initializes Grid with width=3, height=5# end of scope, local variable 'grid' exits, no references to the Grid object. It inherits Reference, therefore it is freed.

Collision functions

Note that there are many ways to detect collisions in Godot such as:is_on_floor(),is_on_wall(),is_on_ceiling(),move_and_slide(), RayCast2D and signals. In many cases those may be preferable to the methods shown below.

Instance Position

As a reminder, in GM this function checks a single point position and then returns the instance ID of the colliding object.

GML

instance_id = instance_position(x, y, obj);

GDScript

Feed this function a local position Vector2 and group name string like so:instance_position(position + Vector2(32,16), "obj")

Setroom_node to the node you want the coordinates of this check to be relative to, which is typically the "level" node that you're spawning all your scenes under. (The reason we useroom_node.global_position is if we have any parents or grand-parents that have offset positions then the checked position won't be correct.)

onreadyvarroom_node=$'..'funcinstance_position(pos,group):varspace=get_world_2d().direct_space_stateforiinspace.intersect_point(room_node.global_transform.translated(pos).get_origin(),32, [],0x7FFFFFFF,true,true):ifi["collider"].is_in_group(group):returni["collider"]returnnull

Position Meeting

In GM this function checks a single point position and then returns true or false depending on whether there was a collision.

GML

boolean = position_meeting(x, y, obj);

GDScript

Same code as Instance Position but replace the last two lines withreturn true andreturn false.

Place Meeting

In GM this function uses the collision mask of the instance that runs the code to check a position for a collision, then returns true or false depending on whether there was a collision.

GML

boolean = place_meeting(x+32, y+16, obj);

GDScript

test_move works a little differently thanplace_meeting, it involves the X and Y position of the current node by default and will return true if it finds anything along the entire vector, while GM's function will check one specific position only. (This function is exclusive to KinematicBody and KinematicBody2D.)

varboolean=test_move(global_transform,Vector2(32,16))

The line below will check only one specific position like GM's function, without checking along the entire vector:

varboolean=test_move(global_transform.translated(Vector2(32,16)),Vector2(0,0))

The line below will check only one specific position like GM's and without involving the current node's X and Y position. This is equivalent toplace_meeting(100, 200, obj). Setroom_node to the node you want the coordinates of this check to be relative to:

varboolean=test_move(room_node.global_transform.translated(Vector2(100,200)),Vector2(0,0))

Instance Place

In GM this function uses the collision mask of the instance that runs the code to check a position for a collision, then returns the instance ID of the colliding object.

GML

instance_id = instance_place(x+32, y+16, obj);

GDScript

If we setmove_and_collide's last argumenttest_only to true, then it will behave exactly liketest_move except it will return collision data and not just a boolean:

varcollision_data=move_and_collide(Vector2(32,16),true,true,true)varid=collision_data.collider

If we want to avoid checking along the entire Vector and check only one specific position like GM's functions, then we'll need to useintersect_shape. Setroom_node to the node you want the coordinates of this check to be relative to. Setshape to whatever CollisionShape2D node you want to use:

onreadyvarroom_node=$'..'onreadyvarcolshape_node=shape_owner_get_owner(0)# Returns the first child node which contains a collision shapefuncinstance_place(pos,group):varspace=get_world_2d().direct_space_statevarquery=Physics2DShapeQueryParameters.new()query.shape_rid=colshape_node.shapequery.transform=room_node.global_transform.translated(pos)*colshape_node.transformforiinspace.intersect_shape(query):ifi["collider"].is_in_group(group):returni["collider"]returnnull

Sources

Special thanks to a lot of poor souls that helped me answering questions on Discord, Reddit and Twitter.

About

A dictionary for people moving from GM:S to Godot

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp