Skip to content

Objects

vitellaryjr edited this page Nov 16, 2021 · 49 revisions

Using Objects

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 details). The highest object is called the stage, and it is what most essential objects are parented to.

Variables

x, y: Position of the object, relative to its parent.
width, height: Size of the object.
color: Table of 3 numbers between 0 and 1, representing the RGB of the object's color (by default, it's {1, 1, 1}, which is white).
alpha: Number between 0 and 1, representing the transparency of the object.
scale_x, scale_y: Visual scale of the object. Does not affect width or height.
rotation: Visual rotation of the object, in radians.
flip_x, flip_y: Boolean variables that flip the visuals of the object horizontally and vertically. Always flips it around its center.
inherit_color: Whether the object multiplies its own color by that of its parent.
origin_x, origin_y: Numbers between 0 and 1 usually, representing where the origin of the object is relative to its width and height. 0, 0 means its origin is the topleft of the object, 1, 1 means it's at the bottomright, and 0.5, 0.5 means the origin is centered. 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.
scale_origin_x, scale_origin_y, rotation_origin_x, rotation_origin_y: Same rules as origin_x and origin_y, 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 sprite cut off.
physics: A table of values that will be automatically used to move the object when it updates. 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 in direction per frame at 30fps.
  • direction: The direction the object will move in if speed is defined, in radians.
  • friction: The amount the object's speed_x, speed_y, and speed will be reduced by per frame at 30fps.
  • gravity: The amount the object's will accelerate towards gravity_direction per frame at 30fps. If speed is defined, then gravity will affect it; otherwise, gravity affects speed_x and speed_y.
  • gravity_direction: The direction the object will accelerate towards, in radians. If speed is defined, then direction will approach gravity_direction (or be set directly if it isn't yet defined); otherwise, speed_x and speed_y will accelerate towards the angle defined.

layer: Visual order the object is rendered in. The higher this number is, the later it will render (appearing in front of 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.
fade_speed: How much the object's alpha will approach target_fade per frame at 30fps. By default, it is 0, and thus target_fade will not be approached.
target_fade: The alpha that the object's alpha will approach.
fade_callback: A function, taking in self as an argument, that will be called when the object's alpha reaches its target_fade value.
collider: Specifies how other objects collide with this object. See Collision for more detail.
collidable: Determines whether other objects can collide with this object. See Collision for more detail.
active: Whether the object updates.
visible: Whether the object renders.
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.

Functions

All functions for objects require that you pass the object into them. While this could be done by doing Object.move(self, x, y, speed), Lua has simpler syntax for this, in the form of Object: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.
collidesWith(other): Whether the object collides with the other object specified.
setPosition(x, y), setSize(width, height), setScale(x, y), setColor(r, g, b, a), setOrigin(x, y), setScaleOrigin(x, y), setRotationOrigin(x, y), setParallax(x, y), setCutout(left, top, right, bottom), setSpeed(x, y): Functions used to set multiple values at once.
getPosition(), getSize(), getScale(), getColor(), getOrigin(), getScaleOrigin(), getRotationOrigin(), getParallax(), getCutout(), getSpeed(): Functions used to get multiple values at once. 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).
shiftOrigin(x, y): Moves the origin of the object while not moving the object itself.
setLayer(layer): Sets the layer of the object. Must be used instead of changing layer directly.
getLayer(): Gets the layer of the object.
fadeTo(target, speed, callback): Sets the object's target_fade, fade_speed, and fade_callback respectively.
fadeOutAndRemove(speed): Set's the object's target_fade to 0 and fade_speed to the specified speed. When the object's alpha reaches 0, the object is removed.
setHitbox(x, y, width, height): Sets the object's collider to a new Hitbox with the provided values. See Collision for more detail.
getHitbox(): Returns the coordinates and dimensions of the object's Hitbox if it exists.
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(other, x, y): Sets the position of the object x units horizontally and y units vertically from another object.
getRelativePos(other, x, y): 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 for more detail.
remove(): Removes the object.
explode()
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.

Creating New Objects

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(dt)
  -- 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, dt)
  -- By default, update() also handles moving the object by its speed_x and speed_y,
  -- and making its alpha approach its target_fade (calling fade_callback when reached)
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.
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)).

Extra Notes

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:addChild(object) -- someParent is an already existing object that's been added to something else

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.
Clone this wiki locally