-
Notifications
You must be signed in to change notification settings - Fork 55
Objects
Relevant files: object.lua, colliders, drawfx
Objects are the basic form of entity in Kristal. Everything in Kristal is an object: UI elements, characters, the overworld, bullets, everything. As such, understanding the basics of how they work is important to being able to use Kristal.
The essential properties of an object are its position, width and height, and parent. When an object is parented to another object, its position becomes relative to that object. All objects must be parented to something, otherwise the game will not recognize them (see Creating New Objects below for more detail). The highest object is Stage
, and it is what most essential objects are parented to, such as the World
and Battle
objects.
The following is a list of all variables and functions that objects can use. Every object will have all of these variables and functions, though some may override functions to change their behavior.
x
, y
: Numbers defining the position of the object, in pixels. Positive numbers will go right and down, and negative numbers will go left and up. An object's position will always be relative to its parent.
width
, height
: The size of the object, in pixels.
color
: A table of 3 numbers between 0 and 1, defining the RGB of the object's color. By default, it's {1,1,1}, which is white.
alpha
: A number between 0 and 1, representing the transparency of the object. Defaults to 1.
scale_x
, scale_y
: Numbers defining the scale of the object, multiplying. Does not affect the object's width
or height
variables.
rotation
: Number defining the rotation of the object, in radians.
flip_x
, flip_y
: Boolean variables that flip the object horizontally and vertically. Always flips it around its center.
inherit_color
: Whether the object multiplies its own color and alpha by that of its parent.
origin_x
, origin_y
: Numbers between 0 and 1 usually, representing where the topleft of the object is relative to its width and height. 0, 0
means its topleft is at the object's position, 1, 1
means its bottomright is at its position (meaning its topleft is width
pixels to the left of and height
pixels above its position), and 0.5, 0.5
means the object is centered at its position. By default, all origin values are 0. Origin values can be less than 0 or greater than 1, which puts the origin outside of the object's size.
origin_exact
: A boolean determining whether the object's origin values should be measured in pixels instead of a proportion. False by default.
scale_origin_x
, scale_origin_y
, scale_origin_exact
, rotation_origin_x
, rotation_origin_y
, rotation_origin_exact
: Same rules as origin_x
, origin_y
, and origin_exact
, affecting where scaling and rotation originates from.
parallax_x
, parallax_y
: Numbers between 0 and 1 usually, representing how much the object will be moved when the camera moves. 0 means the object is unaffected by camera movement, and will stay in the same position on-screen regardless of it, and 1 means it will move along with the camera. By default, it is 1.
cutout_left
, cutout_top
, cutout_right
, cutout_bottom
: Determines a visual cut from the object if specified, in number of pixels. For example, if cutout_top
is 5, then the object will have the top 5px of its rendering cut off. Note that these variables will not work properly if the object is rotated.
physics
: A table of values that will be automatically used to move the object when it updates. All values are 0 by default. The values that can be defined in it are:
-
speed_x
,speed_y
: How many pixels the object will move horizontally and vertically per frame at 30fps. -
speed
: How many pixels the object will move indirection
per frame at 30fps. -
direction
: The direction the object will move in ifspeed
is defined, in radians. -
spin
: How muchdirection
will change per frame at 30fps. -
match_rotation
: If set to true, thendirection
will be updated to match the object'srotation
. -
friction
: The amount the object'sspeed_x
,speed_y
, andspeed
will be reduced by per frame at 30fps. -
gravity
: The amount the object's will accelerate towardsgravity_direction
per frame at 30fps. Ifspeed
is defined, thengravity
will affect it; otherwise,gravity
affectsspeed_x
andspeed_y
. -
gravity_direction
: The direction the object will accelerate towards, in radians, ifgravity
is not 0. Ifspeed
is defined, thendirection
will approachgravity_direction
(or be set directly if it isn't yet defined); otherwise,speed_x
andspeed_y
will accelerate towards the angle defined. Defaults tomath.pi / 2
, which is directly downwards. -
move_target
: A table of data defining where the object is moving, ifslideTo()
orslideToSpeed()
is used. Should not be set directly, see the mentioned functions below; however, it can be set tonil
during a movement to cancel a movement. -
move_path
: A table of data defining the path the object is moving on, ifslidePath()
is used. Should not be set directly, see the mentioned function below; however, it can be set tonil
during a movement to cancel a movement.
graphics
: A table of values that will be automatically used to alter the object's visual properties when it updates. The values that can be defined in it are:
-
fade
: How much the object's alpha will approachfade_to
per frame at 30fps. By default, it is 0, and thusfade_to
will not be approached. -
fade_to
: The alpha that the object's alpha will approach. -
fade_callback
: A function, taking inself
as an argument, that will be called when the object's alpha reaches itsfade_to
value. -
grow_x
,grow_y
: How much the object'sscale_x
andscale_y
will change per frame at 30fps. -
grow
: How much the object's scale will change per frame at 30fps (affecting bothscale_x
andscale_y
simultaneously). -
remove_shrunk
: If set to true, the object will be removed if its scale becomes 0 or negative. -
spin
: How much the object'srotation
will change per frame at 30fps.
timescale
: A number that the object's updating will be multiplied by.
layer
: A number representing the order the object will be rendered and updated in. The higher this number is, the later it will render and update (appearing in front of and updating after objects with lower layer values). Should only be changed directly before it's added to a parent; for changing layer after being added to a parent, see setLayer()
below in Functions. A list of common layer values for objects can be found in the global variables list.
collider
: Specifies how other objects collide with this object. See Collision below for more detail.
collidable
: Determines whether other objects can collide with this object. See Collision below for more detail.
active
: Whether the object updates.
visible
: Whether the object renders.
draw_fx
: A table of visual effects to apply when rendering. See DrawFX below for more detail.
parent
: The parent of the object. Should not be changed directly, see addChild()
and removeChild()
below in Functions.
children
: A table of objects, if the object itself is a parent. Should not be changed directly, see addChild()
and removeChild()
below in Functions.
debug_select
: Whether the object can be selected by the Object Selection debug menu (see Debug Menus for more detail). Defaults to true.
debug_rect
: A table of 4 values, defining the x, y, width and height of a rectangle that will be used by the Object Selection debug menu.
All functions for objects require that you pass the object into them. While this could be done by doing obj.move(obj, x, y, speed)
, Lua has simpler syntax for this, in the form of obj:move(x, y, speed)
. Unless specified otherwise, all functions for any objects on this wiki should be called in this way.
move(x, y, speed)
: Moves the object x pixels horizontally and y pixels vertically, multiplied by speed
if speed is provided.
setPosition(x, y)
, setSize(width, height)
, setScale(x, y)
, setColor(r, g, b, a)
, setParallax(x, y)
, setCutout(left, top, right, bottom)
: Functions used to set multiple values at once.
setOrigin(x, y)
, setScaleOrigin(x, y)
, setRotationOrigin(x, y)
: Sets the origin values to the specified x
and y
values, and sets the associated origin_exact
variable to false.
setOriginExact(x, y)
, setScaleOriginExact(x, y)
, setRotationOriginExact(x, y)
: Sets the origin values to the specified x
and y
values, and sets the associated origin_exact
variable to true.
setSpeed(x, y)
: If x
and y
are defined, set the object's physics.speed_x
and physics.speed_y
values to x
and y
respectively; if only x
is defined, set the object's physics.speed
to x
; and if no variables are defined, set all of the object's physics speed variables to 0.
setHitbox(x, y, width, height)
: Sets the object's collider
to a new Hitbox with the provided values. See Collision below for more detail.
setLayer(layer)
: Sets the layer of the object. Must be used instead of changing layer
directly.
getPosition()
, getSize()
, getScale()
, getColor()
, getParallax()
, getCutout()
, getLayer()
, canDebugSelect()
: Functions used to get values for the object. When returning multiple values, these always returns each value individually, as opposed to a table of values (eg getColor() returns r, g, b, a
as opposed to {r,g,b}, a
).
getOrigin()
, getScaleOrigin()
, getRotationOrigin()
: If the associated origin_exact
is false, return the values as is; otherwise, returns values calculated from the exact origin values to get the relative proportional values.
getOriginExact()
, getScaleOriginExact()
, getRotationOriginExact()
: If the associated origin_exact
is true, return the values as is; otherwise, returns values calculates from the proportional origin values to get the relative pixel values.
setParallaxOrigin(x, y)
: Sets the object's parallax origin to the specified position, in pixels relative to its parent. Allows for accurately defining the starting position of an object's parallax.
getSpeed()
: Returns physics.speed
if it is defined, then physics.speed_x
and physics.speed_y
if those are defined and physics.speed
isn't, then 0 otherwise.
getHitbox()
: Returns the coordinates and dimensions of the object's Hitbox if it exists.
shiftOrigin(x, y)
: Moves the origin of the object while not moving the object itself.
fadeTo(target, speed, callback)
: Sets fade_to
, fade
, and fade_callback
respectively for the object's graphics
table.
fadeOutAndRemove(speed)
: Sets fade_to
to 0 and fade
to the specified speed for the object's graphics
table. When the object's alpha reaches 0, the object is removed.
slideTo(x, y, time, ease, after)
, slideTo(marker, time, ease, after)
: Moves the object to the specified position over a period of time. x
and y
are coordinates to move to, or marker
is a marker name to move to the position of; time
is the amount of time, in seconds, it will take to move to the destination, ease
is an optional string defining the ease type to use for the movement, and after
is an optional function that will be called once the object reaches its destination.
slideToSpeed(x, y, speed, after)
, slideToSpeed(marker, speed, after)
: Moves the object to the specified position by the specified speed. x
and y
are coordinates to move to, or marker
is a marker name to move to the position of; speed
is a number referring to how fast the object will approach its destination in pixels per frame at 30fps, and after
is an optional function that will be called once the object reaches its destination.
slidePath(path, options)
: Moves the object across a series of positions. path
is either a table of tables with 2 values each, defining the coordinates of a point, or a string referring to a map path, if the object is in the overworld. options
is a table of data, defining information the path should use. The following is a list of fields that can be defined:
-
time
: How long it should take the object to reach the end of the path, in seconds. -
speed
: How fast the object should move along the path. Overridestime
if defined. -
loop
: Whether the path should loop back to its first position infinitely. -
ease
: How the movement along the path should be eased. Defaults to linear. -
after
: A function that will be called when the object reaches the end of the path, if defined. Will not be called ifloop
is true. -
move_func
: A function that, if defined, will be responsible for handling the movement of the object along the path, receiving the object being moved and the x and y of the position being moved to per frame as arguments. -
relative
: If true, the specified path will be relative to the object's current position (eg. {0, 0} on the path will refer to the object's starting position). -
reverse
: If true, the path will be reversed. Only works ifrelative
is not true. -
skip
: A number defining how many of the positions in the path to skip over when starting. -
snap
: If true, the object's position will be immediately set to the first position of the path; otherwise, the object's current position will be added to the path. Automatically true ifloop
is true.
resetPhysics()
: Resets the physics
table for the object to its default values.
resetGraphicsTransform()
: Resets the graphics
table for the object to its default values.
setScreenPos(x, y)
: Sets the object's position relative to the topleft of the screen.
getScreenPos()
: Gets the object's position relative to the topleft of the screen.
localToScreenPos(x, y)
: Gets the screen position of a point specified, relative to the object.
screenToLocalPos(x, y)
: Gets the position relative to the object of a point on the screen.
A note for screen position functions: the screen position accounts for the window scale, such that any coordinates will be the same in-game position regardless of window size.
setRelativePos(x, y, other)
: Sets the position of the object x units horizontally and y units vertically from another object.
getRelativePos(x, y, other)
: Gets the position of the object x units horizontally and y units vertically from another object.
getStage()
: Gets the highest parent of the object. In other words, if the object's parent has its own parent, return parent:getStage()
instead.
getDrawColor()
: Gets the color of the object, multiplied by its parent's color if inherit_color
is true.
collidesWith(other)
: Returns whether the object is colliding with other
. other
can be either a Collider or an Object with collider
defined. See Collision below for more detail.
addFX(effect, id)
: Adds the specified visual effect to the object. effect
is an instance of a DrawFX class, and id
is an optional string that allows the player to define the effect's ID. See Effects below for more detail.
getFX(id)
: Returns the specified visual effect from the object if it has it. id
can either be a string, referring to an effect ID, or it can be an effect class (eg. ColorMaskFX
), returning a visual effect that extends the specified class. See Effects below for more detail.
removeFX(id)
: Removes the specified visual effect from the object if it has it. id
can either be a string, referring to an effect ID, or an effect instance. See Effects below for more detail.
remove()
: Removes the object.
explode(x, y, dont_remove)
: x
and y
are positions relative to the object, and dont_remove
is a boolean determining whether the object should be removed, defaulting to false.
addChild(child)
: Makes the object the parent of the specified child.
removeChild(child)
: Removes a child from an object.
setParent(parent)
: Makes the object the child of the specified parent, and, if it had a parent previously, removes itself from that parent.
isFullyActive()
: Returns whether the object and all of its parents are active
.
isFullyVisible()
: Returns whether the object and all of its parents are visible
.
getDebugRectangle()
: Returns a table of 4 values, defining the x, y, width and height of a rectangle that will be used by the Object Selection debug menu. By default, returns debug_rect
if defined, and a rectangle fitting the object's width and height otherwise.
Kristal uses a class-based coding structure implementation in Lua, similar to languages like C#. To create a new instance of an existing class, you call that class's name like a function, passing in values matching what that class's Init function requires. For example, creating a new instance of an Object would be done with Object(x, y, width, height)
. However, creating instances of just an Object is generally not helpful; instead, you'll generally want to make classes that extend Object.
To extend a class, you'll want to make a new .lua file in scripts/objects
. Object files in this folder get loaded automatically; you can place object files in other folders, but you'll have to require
them yourself. An example of a new class that extends Object:
-- Create a new class which extends Object
local MyObject, super = Class(Object)
-- A class that extends a different class contains all of the functions of the class it extends.
-- Class(classname) returns two values: the new class you'll be changing,
-- and a copy of the class you're extending.
-- By setting MyObject:init, we replace the function Object:init for this class.
-- This is called overriding a function, and it's important to understand for extending classes.
function MyObject:init(x, y, width, height)
-- This is what 'super' is used for: we need to still call the original function,
-- so we call super:init(self, ...) to call the original Object:init(...).
-- As mentioned earlier, majority of functions for Objects require self to be passed in.
-- Because of this, we always need to pass in the new object's self
-- into any super functions as the first argument, followed by the rest of the arguments.
super:init(self, x, y, width, height)
end
-- Called every frame by this object's parent
function MyObject:update()
-- Update code goes here, like moving the object
-- We're overriding Object:update, so again, we can call the original using 'super'
-- This calls update on all this object's children, so place it where you want!
super:update(self)
-- By default, update() also handles changing the object based on its 'physics'
-- and 'graphics' tables
end
-- Called every frame too, during rendering
function MyObject:draw()
-- Draw code goes here, you can draw textures and rectangles and whatever you want basically
-- Once more, we're overriding Object:draw, so we can call the original using 'super'
-- This calls draw on all this object's children, so placement is important!
-- Code before this line will be drawn below children, code after this line will be drawn above children
super:draw(self)
end
-- Returns the class, to be used later
return MyObject
Other overridable functions are:
onAdd(parent)
: Called when the object is added as a child to a parent. parent
is the Object instance that the object is being parented to.
onRemove(parent)
: Called when the object is no longer a child of a parent (either as a result of the object being removed via remove()
, or as a result of its parent being changed via a new addChild(object)
or removeChild(object)
). parent
is the Object instance that the object is being removed from.
onAddToStage(stage)
: Called when the object or any of its parents are added to a stage. stage
is the Stage object that the object or its parents are parented to.
onRemoveFromStage(stage)
: Called when the object or any of its parents stop being parented to a stage. stage
is the Stage object that the object or its parents are being removed from.
getDebugInfo()
: Returns a table of data that will be used by the Object Selection menu to display data about the object. Each value in this table is a string that will be displayed. When overriding this function, you will want to get the table used by the original instance of the function first, then insert values into it. For example, this is how the Character object extends getDebugInfo()
:
function Character:getDebugInfo()
local info = super:getDebugInfo(self)
table.insert(info, "Actor: " .. self.actor.name)
table.insert(info, "Noclip: " .. (self.noclip and "True" or "False"))
return info
end
Sometimes, extending classes will not work with the normal method of passing in the class itself. Circumstances like global variables not being created for a class, or indeterminate loading order of class files, can cause this. To extend a class from these circumstances, you'll want to pass the file path, relative to the current base folder for the class file, of the class you want to extend. For example, if you want an Object file to extend an object located at scripts/objects/ZObject.lua
, you would call Class("ZObject")
, since you can't guarantee that ZObject would load first.
When a class is made in scripts/objects
, a global variable named after the file name is created. This global variable is used to create instances of this new class. For example, with the above code at scripts/objects/MyObject.lua
, you can create new instances of MyObject by calling MyObject(x, y, width, height)
.
As mentioned earlier, in order for new instances of objects to be recognized by the game, they must be parented to another object. This parent will be responsible for updating and rendering its children. When creating a new object, your code will generally look something like this:
local object = MyObject(...)
-- someParent is an already existing object that's been added to something else
someParent:addChild(object)
-- OR
object:setParent(someParent)
When an object is parented to another object, its position and layer become relative to its parent's. This accounts for information like origin
from the parent, and thus, position will nearly always be relative to the parent's topleft. For example, when parenting an object at 40, 40
with a layer of 1 to Game.battle.arena
, its position will be 40 pixels to the right of and 40 pixels below the arena's topleft, and it will render above the arena, since its layer is effectively 301.
However, it is worth noting that children of an object cannot render above objects that render above its parent, since the parent renders its children directly, and so they inherit its render order overall. This means that an object A
with a layer of 200 parented to the arena will not render above an object B
parented to Game.battle
with a layer of 400, due to object B
and the arena both sharing a parent of Game.battle
; while object A
's layer is effectively 500, the arena's layer is 300, and thus it will render before object B
. This all applies to updating too; children of an object will update before any objects with a higher layer than its parent.
Common objects to be parents are:
-
Game.world
for objects in the overworld. Its position will be relative to the topleft of the room the player is in. -
Game.battle
for objects in battle. Its position will be relative to the topleft of the screen. -
Game.shop
for objects in shops. Its position will be relative to the topleft of the screen. -
Game.stage
for miscellaneous objects that should be parented higher than in those (eg. when making an object that should persist from the overworld into a battle). It is always present, and it's what the previous objects are parented to. Its position will be relative to the topleft of the screen. -
Kristal.stage
for objects that should persist into the main menu. Use carefully.
Objects can use Colliders to check whether they collide with each other. Colliders themselves are not objects, however, and thus, don't need to be added as a child to other objects. To set an object's collider, you only need the following code:
object.collider = Collider(object, ...)
Objects can have other variables defined as colliders as well, but only collider
will be checked by other code within Kristal; you'll have to manually collide check for anything else.
All colliders follow the same rules for their arguments: the first argument is the object the collider should be attached to, then it takes arguments correlating to the shape of the collider, then there's an optional final argument called data
which allows defining extra options for the collider. The following are the types of colliders available:
Hitbox(parent, x, y, width, height, data)
: Rectangular collision. x and y refer to the topleft of the rectangle.
CircleCollider(parent, x, y, radius, data)
: Circular collision. x and y refer to the center of the circle.
LineCollider(parent, x1, y1, x2, y2, data)
: Linear collision. x1, y1 and x2, y2 refer to the coordinates of the 2 points.
PointCollider(parent, x, y, data)
: Singular point collision. x and y refer to the coordinates of the point.
PolygonCollider(parent, points, data)
: Polygon collision. points
is a table of tables with 2 values each, referring to the coordinates of each point of the polygon.
ColliderGroup(parent, colliders, data)
: A group of colliders. colliders
is a table of other Collider instances.
The data
argument is a table that can define certain boolean fields to change how the collider works. Enabling multiple fields causes their effects to combine as one would expect. The following are fields that can be defined:
inverted
: Simply inverts the result of the collision, returning true
if it is not being collided with and vice versa.
inside
: Causes the collision to only return true if the checking collider is entirely within this collider. In other words, with this enabled, if any point of the checking collider is not colliding with this, the result is false.
Variables and functions that all colliders can use:
collidable
: If set to false, the collider will not collide with anything.
collidesWith(other)
: Returns whether the collider is colliding with other
. other
can be either a Collider, or an Object with collider
defined.
draw(r, g, b, a)
: Draws the bounds of the collider.
drawFill(r, g, b, a)
: Draws the filled shape of the collider.
Objects can be given special visual effects, internally called DrawFX, by using addFX()
. DrawFX can be used to apply code to an object's Canvas as it's being rendered. Objects can have multiple DrawFX at once, and they will render in priority order; every DrawFX takes a priority
argument, which is a number that defines how early an effect should be rendered when there are multiple, with larger priority values rendering before smaller ones.
Kristal implements multiple DrawFX for general usage. These effects are:
AlphaFX(alpha, priority)
: Renders the object at the specified alpha.
RecolorFX(r,g,b,a, priority)
: Renders the object multiplied by the specified color.
ColorMaskFX(color, amount, priority)
: Overlays color over the object. color
is a table of RGB (defaulting to white), and amount
is the alpha amount of the color (defaulting to 1).
MaskFX(mask, draw_children, priority)
: Masks the object to another object. mask
is either an instance of an Object or a function that returns an instance of an Object, and draw_children
is a boolean that determines whether the mask object should consider its children as part of the mask (defaulting to true). If mask
is not specified, then the object itself will be a mask for all of its children.
ShaderFX(shader, vars, priority)
: Renders the object with the specified shader. shader
is a string of OpenGL shader code, and vars
is a table of variables to be sent to the shader. If a value in vars
is a function, the shader will receive whatever the function returns every frame.
Custom DrawFX can also be defined in mods. Similar to custom Objects, the file name determines the name of the global class. DrawFX go in scripts/objects
, and should be made by extending the global FXBase
class.
The following variables should be defined in the init
function of the DrawFX:
priority
: As explained earlier, this determines the order in which DrawFX will render. DrawFX with a higher priority will render before others. Defaults to 0.
id
: The default ID for the DrawFX.
active
: Whether the DrawFX should be rendered. Defaults to true.
Additionally, the following functions can be overridden:
update()
: Called every frame.
draw(texture, object)
: Responsible for drawing the object with the effect desired. texture
is a Canvas of the object at its current draw state, and object
is the instance of the object being drawn. This function must call love.graphics.drawCanvas(texture)
, otherwise the object will not be drawn.
isActive()
: Returns whether the DrawFX should be rendered. Returns active
by default.
Downloading Kristal
Installing and playing mods
Game options
File structure
mod.json and mod.lua
Libraries
Save data
Game and Kristal variables and functions
Important tips
Using objects
Creating new objects
Extra notes
Collision
DrawFX
Sprites and the Sprite object
Custom fonts
Sounds and music
External libraries
Utility functions
Global variables
Debug shortcuts
Debug menus
Making an actor
ActorSprite
Default animations
Creating a party member
Using and overriding functions
Types of Items
Default items
Inventory
Defining a spell
Making rooms
Using rooms in your mod
The Map class
Game.world functions
Events and Controllers
Existing events
Characters
Types of Characters
Battle areas and World bullets
Making a cutscene
Starting cutscenes
The Text object
In-text modifiers
Creating a shop
Overridable functions
Shop states
Shopkeepers
Making an encounter
Game.battle functions
Battle and PartyBattler states
PartyBattlers and EnemyBattlers
Creating an enemy
Overridable functions
Misc. functions and variables