Garry's Mod Wiki

Revision Difference

BaseClasses#561733

<title>Concepts - BaseClasses</title> <cat>Dev.Lua</cat> # Terms and Definitions A **Class** is a collection of Functions and Variables defined in code that acts as a template. Examples include <page text="The Player">player</page>, <page text="Entities">Entity</page>, <page text="Gamemodes">Structures/GM</page>, <page text="VGUI Elements">VGUI_Element_List</page>, and more. An **Instance** is a copy of a Class that is active in the game. There can be multiple Instances of a single Class active at the same time. For example: When a prop is spawned from the Sandbox Spawn Menu, the game creates an Instance of the Class `prop_physics`. The Class `prop_physics` is only defined in code once but it can be used to create any number of Instances. To make efficient use of computer hardware, the logic of a Class is not duplicated to each Instance, but instead the Instances all refer back to the same definition in the Class. This is handled via <page text="Meta Tables">meta_tables</page>. A **Base Class** (or **Parent Class**) is the set of Functions and Variables that a Class (the Parent Class's **Child Class**) has by default. The behavior of the Parent Class is modified by overriding, replacing, and adding Functions and Variables to the Child Class. This allows a Class to copy the behavior of another Class without needing to re-create the other Class's logic from scratch. To prevent unnecessary duplication of logic, a Child Class refers to its Parent Class's Meta Table in situations where the Child Class doesn't have an override defined for a Function or Variable. A **Base Class** (or **Parent Class**) is the set of Functions and Variables that a Class (the Parent Class's **Child Class**) has by default. The behavior given by (or inherited from) the Parent Class is modified by overriding, replacing, and adding Functions and Variables to the Child Class. This allows a Class to copy the behavior of another Class without needing to re-create the other Class's logic from scratch. To prevent unnecessary duplication of logic, a Child Class refers to its Parent Class's Meta Table in situations where the Child Class doesn't have an override defined for a Function or Variable. **Note:** All Classes must have exactly one (1) Base Class, but can have any number of Child Classes. # How do you use Base Classes? <example> <description> The following example demonstrates how an <page text="Entity">Entity</page> can be used as a Base Class for multiple Child Entities. The Parent Class (`sent_parentclass.lua`) handles all of the logic for setting up the Entity's model and physics, as well as the logic behind the Entity's unique behavior. In this case, the unique behavior is that some arbitrary visual effect is enabled before the entity draws and is disabled after it draws. In the Parent Class, this visual effect simply turns the Entity blue. Because the Child Classes (`sent_childclass_1.lua` and `sent_childclass_2.lua`) retain the logic of their Base Class (`sent_parentclass.lua`), they only need to include a very small amount of code to create different visual effects. `sent_childclass_1.lua` overrides the function to enable the visual effects and replaces it with rainbow coloring. `sent_childclass_2.lua` overrides both of the visual effect's enable and the disable functions and replaces them with functions that make the Entity (Which now looks like a tire) appear to always be rolling. </description> <code name="sent_parentclass.lua"> AddCSLuaFile() -- All Entities must have a Base Class. -- In this case, the "base_anim" Class is being used. -- This is one of the default Entity Classes available in Garry's Mod. DEFINE_BASECLASS( "base_anim" ) ENT.PrintName = "Parent Class" ENT.Category = "BaseClass Example" ENT.RenderGroup = RENDERGROUP_TRANSLUCENT ENT.Spawnable = true -- This variable exists to demonstrate that a Base Class provides both -- functions and variables to their children. -- This is a regular-width crate model. ENT.ModelToSpawnWith = "models/props_junk/wood_crate001a_damaged.mdl" -- Set up the Entity function ENT:Initialize() if SERVER then self:SetModel( self.ModelToSpawnWith ) self:PhysicsInit( SOLID_VPHYSICS ) self:SetMoveType( MOVETYPE_VPHYSICS ) self:SetSolid( SOLID_VPHYSICS ) end end -- This is a custom function we'll be using to demonstrate that children can -- override functions from their Base Class. function ENT:EnableVisualEffects() -- Modify upcoming rendering to make it look blue. render.SetColorModulation( 0, 0, 1 ) end -- This custom function won't be overridden by the child Entity, but that is -- purely for demonstration purposes. Any function from the Base Class can -- be overridden by its children. function ENT:DisableVisualEffects() -- Reset the color of the rendering system. render.SetColorModulation( 1, 1, 1 ) end -- Here we use the custom functions above to change how the entity draws. -- Because we do not override this function in the child, this will be the -- Draw function for the child Entity. function ENT:Draw() self:EnableVisualEffects() self:DrawModel() self:DisableVisualEffects() end </code> <code name="sent_childclass_1.lua"> AddCSLuaFile() -- Set our Base Class to be the Class we want to inherit functions and values from. -- It would be equally valid to use DEFINE_BASECLASS. -- baseclass.Get() is being used here to demonstrate that both options are viable. ENT.BaseClass = baseclass.Get( "sent_parentclass" ) ENT.PrintName = "Rainbow Child Example" ENT.Category = "BaseClass Examples" ENT.Spawnable = true -- Override the variable in our Base Class that is used to set the Entity's model -- Because we haven't overridden the ENT:Initialize() function, that logic will run -- exactly as it appears in our Base Class, but with this value instead of the value -- defined in the Base Class. -- This is an extra-wide crate model. ENT.ModelToSpawnWith = "models/props_junk/wood_crate002a.mdl" -- Override the visual effects function to randomize the entity's color. function ENT:EnableVisualEffects() local red = math.Remap( math.sin( CurTime() * 2 + 1 ), -1, 1, 0, 1 ) local green = math.Remap( math.cos( CurTime() * 3 + 2 ), -1, 1, 0, 1 ) local blue = math.Remap( math.sin( CurTime() * 4 + 3 ), -1, 1, 0, 1 ) render.SetColorModulation( red, green, blue ) end </code> <code name="sent_childclass_2.lua"> AddCSLuaFile() ENT.BaseClass = baseclass.Get( "sent_parentclass" ) ENT.PrintName = "Perpetual Motion Child Example" ENT.Category = "BaseClass Examples" ENT.Spawnable = true ENT.ModelToSpawnWith = "models/props_vehicles/tire001c_car.mdl" -- Replace the Base Class's blue effect with one that makes it look like we're rolling function ENT:EnableVisualEffects() local matrix = Matrix( ) matrix:SetAngles( Angle( 0, 0, CurTime() * 200 ) ) self:EnableMatrix( "RenderMultiply", matrix ) end -- Because we're not changing the Entity's color like the Base Class does, we need to -- override this function to make sure we disable the effect appropriately. function ENT:DisableVisualEffects() self:DisableMatrix( "RenderMultiply" ) end </code> <output> Below you can see, in order from left to right: 1. The Parent Class `sent_parentclass` (The blue crate) 2. The first Child Class `sent_childclass_1` (The rainbow crate) 3. The second Child Class `sent_childclass_2` (The spinning tire) <upload src="b2b4c/8dc5cc35e090fb1.mp4" size="3716094" name="BaseClassExample.mp4" /> </output> </example>