Welcome to the Torque3D Game engine documentation! Your one-stop-shop for all your learning needs!
No problem at all! This knowledgebase is designed to walk you through all the skills and tasks you'll need to get your dream game made. All you need to do is jump into the Getting Started section and follow along. By the time you reach the end of the list, you'll be a lean, mean, game developing machine!
Getting StartedSay no more, friend. You can find several pages labeled as Deep Dive (convenient!) which get into the nitty-gritty how-tos and why-fors of how the engine works. At the bottom of the directory is also the Engine section which goes into the structure of the engine, how the guts works, and how you can expand and change it to fit your needs!
For ProgrammersThis page provides a listing(and where applicable, cross-linking to other docs pages) of all the major features of the Torque3D Game Engine
Torque3D includes both a high-performance forward-rendering basic lighting engine, and a deferred-rendering advanced lighting mode so you can tailor your game to meet the needs of different customers. The modern rendering system includes per-pixel lighting, normal and parallax mapping, and materials generated by a high-level editor, or written from scratch in GLSL/HLSL. The engine comes with shaders for water, sky and sun, and many common material types.
The engine also has a powerful PostFX system allowing you to create custom post-processing effects. It ships with buit-in effects including:
HDR/light adaptation
Depth of field
Lens flare and sun rays
Screen-space ambient occlusion and FXAA
Refraction, reflection and glow
Torque3D comes with everything you need to construct environments and levels from your assets. Shapes are imported in Collada DAE format and placed in the in-game editor. Switch to playing through your level with one press of a button.
Powerful terrain editor that allows you to import terrains or sculpt them by hand.
The shape editor provides tools for previewing and touching up your shapes after import.
The road and river editor modes make it simple to place paths that become solid roads, flowing rivers or decal tracks across the terrain.
A fully-featured material editor means you don't have to touch a line of shader code to create great-looking visuals.
The GUI editor lets you place HUD and menu elements in an easy-to-use WYSIWYG environment.
Torque3D will automatically reload assets that are changed outside the editing environment, enabling speedy development iteration.
Editor modes are implemented as plugins, so you can add your own custom modes.
Since its inception as the engine behind the online shooter Tribes 2, Torque has consistently provided high performance, reliable networking for fast-paced online games. The engine has networking built into its core, allowing you to quickly get up and running with networked games.
Torque uses a server authoritative networking model that helps you to reduce cheating and exploitation. At the same time, the game state is predicted and interpolated locally so each client experiences a smooth view of the action. Time-invarying data is transferred via datablocks at client join time, reducing the amount of data that needs to be networked during gameplay.
Torque3D provides a plugin system for physics. There is a simple built-in implementation which can be easily swapped out for PhysX or Bullet libraries. They enable features like:
Cloth dynamics
Rigid body dynamics
Destructible objects
Destroyable joints
Fluid buoyancy
When you get Torque, you get everything. The entire source code is yours to modify under the permissive MIT license. The codebase is mature and extensible with a plugin system, allowing you to easily add features of your own, or from other libraries, to each project.
If you're not the recompiling type, Torque provides a scripting engine using a custom C-like language called TorqueScript. You can create whole games without touching a line of C++. Check this out:
$minion = new AIPlayer(Fubar) {
datablock = MinionData;
};
$minion.setMoveDestination("50 0 0");
function Fubar::onReachDestination(%self) {
echo("I made it! Says" SPC %self.name);
}
inspector cleanups #951
Alpha403/hdr fixes #949
probe code review #946
misc fixes #942
Fix for build #928
bloom fix fallback #925
3adds wetness #923
parseArgs() followup #914
Update assimp 5.2.5 #911
kill console spam #910
Monitor Id fixes #906
conform gl to dx #904
Editor GUI Update #890
bloom gl compile fix #885
fix playerbot mounts #883
remove leftover #872
Mac OpenAL 1.1 #868
OpenAL Mac #867
Switched engine over to utilize Assets and Modules
Switched lighting and materials to utilize PBR rendering
Made BaseGame template the main/only template
Added Assimp shape importer library
Added Legacy Project Importer
Updated to D3D11 from D3D9
Updated GL to be 4.0
Updated TorqueScript compiler for better performance
Alpha40/ts static cleanup #840
tsstatic aug cleanups #839
Re-enables reimport of assets #838
Cmake DEBUG/RELEASE flag standardization #837
targeted fix for #45 #836
pathshape cleanups and callbacks #835
soundAsset profile and description getter fixes #834
particle emission safeties #833
Update TORQUE_GAME_ENGINE_VERSION_STRING version number 4.0.0 #832
Misc FIxes 2022/07/24 #831
fix bounds box display #830
DBEditor callback fix for asset fields #828
Misc Fixes 2022/07/02 #827
make sure the volfog manager is dead before we kill scene #825
fix unspecified storage location mangle for new asset creation #824
fix a pair of taml typos #823
BugFix: Correct a missing asset for filling the background of the console #822
Misc Fixes 2022/06/20 #821
fix shape errorcodes #820
you want the higher number, not the lower #819
fix computeForwardProbes shadergen gl side #818
fix out of bounds reference in arrayobject #817
fix TORQUE_TOOLS = off compilation #815
fix vectorlight visualizer varnames #814
Fix Misc ConvexShape Tooling Issues #813
BugFix: Remove the GCC Workaround #812
Misc Fixes 2022/06/09 #811
allow ambient light injection into ibl #809
Misc Fixes 2022/06/05 #808
Disconnect and Shutdown fixes #807
Uncomments networking lines that ensure client has the particle's textures #806
Sound Networking Fixes #805
Misc Fixes 2022/06/01 #804
proper player head rot clamp #802
constrain player mRot.z reguardless of translation #800
Misc Fixes for 2022/05/30 #799
Use screen space coordinates for mouse pointer position #798
BaseGame Template: Fix script assert on canceling game options changes #797
fix particle emitter asset browser spawning #796
lower min brushsize for forest to sub-meter levels #795
set convexshape to use a standard vertex type #794
fix on-RPC-command explosion sounds not playing the first time #793
BugFix: Correct MacOS not responding to various hotkeys #792
BugFix: Correct invalid fall-through behavior in sdlInputManager.cpp. #791
Misc Fixes for 2022/05/24 #790
Overhaul on CPU detection for Windows, Mac (x64/arm64) & Linux #789
Fixes issue where creating a new ForestItem wouldn't have it show in the ForestItemData dropdown on brushes until you restart. #788
Fix edgecase where empty string was not being explicitly set to 0 in … #787
Better allocator for TorqueScript temp conversions during interpretation #786
Adjustment: Update libsdl to address a bug in compilation on MacOS #785
fix sDefaultAmbience intialization. #783
Misc Fixes for 2022/05/10 #781
Implements a more standardized way to format usual UI pages by having the ability to utilize the UINavigation namespace for page stack navigation #780
Make the Console Sane Again #779
Fix weird ternary operator in torquescript regression #778
update assimp to 5.2.3 Bugfix-Release #777
Adds a conditional to the github workflow file so it only runs on the main repo #776
update sdl to release 2.0.22 #775
Github actions CI #774
Removes the BGRA inversion when displaying vertex colors on materials #773
Cleanup: Resolve several compiler warnings associated with TORQUE_DEBUG #772
correct mac compilation #771
add .vs directory to gitignore #770
Misc Fixes 2022/04/23 #769
drop the prior requirement for a createcomposite to have a minimum of… #768
Fix TAML schema for array groups #767
requested feature: large number display #766
bump down saveScaledImage default to 256 #765
getAssetIdByFilename loaded state fix #764
Misc FIxes for 2022/04/09 #763
Updated readme with new links #762
Add funding/sponsor options for support #761
Fixes tooling of Forest Editor to be module-friendly #760
Misc Fixes 2022/04/05 #759
display the item to be spawned #758
Misc Fixes 2022/04/04 #757
Misc Fixes 2022/04/03 #756
Misc Fixes for terrain material editing, creation and usage #755
Fixes issue where nested callOnModules would thrash the queued exec lists from other invokes #754
Misc Fixes for 2022/03/27 #753
Misc Bugfixes for 2022/03/26 #752
update sdl to https://github.com/libsdl-org/SDL 22March 2022 #751
Misc tool fixes20220320 #750
Misc Tool and Asset Import fixes and improvements #748
extended callonModules hooks for baseline playgui #747
fix compilation flaws #746
Fixes handling of the setEditor commands so that the dropdown Editors menubar entry properly works #745
Fixes and cleans up various issues and error spam for core and tools folders #744
Changes the creation of new materials in the material editor process #743
Tweaks handling of "invisible" files #742
Adds a systemCommand console utility function #741
crashfix and projection fix for spotlights with cookies #740
point baseline fog color at the right target hen in deferred mode #738
ensure MissionCleanup exists before .mis load #737
Sky improvements #736 by marauder2k7 was merged on Mar 9
Fixes handling of loading non-DDS images to better handle pointer references with the GBitmap resources. #735
fix probe baking typo #734
Fixes saveScaledImage to handle DDS format files, since DDS's go through a separate resource loader #733
Misc importer improvements to handle importing in-place more predictably #732
Fixes some mishandled cases when preprocessing objects and functions for project import #731
Base UI module standardize pr #730
template mixins need this-> specified #729
doublesided material renderfix #728
Probe Bake Capturing flag toggle fix #727
Improves logical checks for the default value so it's more sane and stable #726
Rework of the Probes and Probe Bin #725
Shifts handling of material and terrain material definitions to be written into the asset definition taml file instead of having an extra loose file #723
clean up ambiguous reference #722
GuiBitmapCtrl named texture fixes. #721
Changes the -> syntax check from exclusively checking simgroups to checking simsets, allowing both to be used #720
Updated project importer #719
Sound Asset Fleshout #718
Improve tinyXml2 output formatting #717
Fixes creation of convex shapes via editor #715
Updates the handling of the baking of shape asset previews #714
Feature: VFS Security #713
fix ServerPlaySound #711
fix opengl device not returning the correct anisotropic value #709
BugFix: Correct a windows-only pathing issue in terrMaterial #708
WIP: BugFix: Correct 'make install' not working on MacOS #707
augments playSoundAsset #705
A clean implementation of Lukas' Fix side projection #684 PR with Az's addendum fix rolled in #704
BugFix: Fix a Windows ASAN reported allocation/deallocation mismatch error. #703
Fixes mapping of imposter images to be packed as part of the shape asset, and fixes paths to be formatted more sanely. #702
Fix console warning when calling void functions in console #701
Cleans up some core execution behavior #699
Removes the Library tabs from the World and GUI editors to avoid confusion #698
BugFix: Correct compilation for MacOS #696
Minor cmake corrections #694
fix metal sound entry for playerdata #692
use internalname for terrain layers #691
TSStatic::updateMaterials() crashfix #690
cleanups for sound assets #689
adds colorization to GuiBitmapButtonCtrl #688
Misc QOL and Bugfixes for 2021/11/26 #687
modular source work #686
BugFix: Correct data corruption potential in GuiInspectorField #685
BugFix: Correct the inability to build on MacOS #681
make use of folder properties in cmake #680
set cubemapsaver profile to one that preserves sizes #679
Fixed a leak with console stack in the interpreter. #678
Fix extension case handling when looking up assimp importer #
Optionally allow to treat script assert as warning #676
fix reported ASAN crash #675
Adjustment: Generalization of platformX86UNIX to platformPOSIX #674
Shifts utilization of gui elements in editors that point to 'normal' image assets to utilize generated previews instead. #673
Misc fixes2021114 #672
brdf handling corrections #671
Add Object Inheritence Acceptance Test #670
BugFix: Correct the vehicle types double-tapping onAdd and onRemove #669
Feature: Implement a TurretObjectType bit for typemasks #668
fix fbx importer lookup for setting formatScaleFactor #667
BugFix: Correct ASAN reported out of bounds reads in AssetImporter #666
fill out a %this variable for trigger callbacks #665
Better Architecture detection strategy if compiling on Apple Silicon #664
[Tokenizer] BugFix: Correct a malloc/delete mismatch #663
Misc asset import QOL and bugfix changes #662
better handle old style references to named texture targets #661
new method tsstatic.getNodeTransform #660
[TAML] BugFix: Correct a delete and new[] mismatch in tamlWriteNode #659
imageasset array profile fixes #658
Updates asset importer and project importer to output to separate log files into tools/logs #657
BugFix: Correct Module deinitialization Ordering #656
BugFix: Correct an ASAN reported memory error caused by incorrect usage of __sync_fetch_and_add #655
BugFix: Correction for compiling on x86 Unix devices. #654
BugFix: Correct an invalid memory access error caused by the tab autocomplete #653
BugFix: Correct a crash in the variable inspector #652
BugFix: Correct an ASAN use-after-free Error in TSShapeEdit #651
BugFix: Correct an ASAN reported memory access error in GuiGameListMenuCtrl #649
BugFix: ARM Compilation #648
clean up more texture profile refs to kill spam #647
fix material scrolling #646
Misc QOL and Bugfixes for 2021/10/28 #645
Adjustment: Update Assimp version to 5.0.1. #644
BugFix: Don't assume a tooltip profile is going to be set when waking and sleeping #643
BugFix: Correct the usage of a local variable in a non-function scope #642
Feature: Properly detect ARM32/ARM64 in the CMake build process #641
Alpha40/ibl cleanups #640
typofix for impoerter #639
BugFix: Correct usage of mkdir in posixVolume.cpp #638
blatantly ganked from T2D; adds rotation as an option for drawbitmap #637
addsa material.setAnimflags(LAYER,TAGS STRING); method #636
BugFix: Address an error where deleting directories may result in an infinite loop #635
BugFix: Correct the inability to use function keys F1-F10 #634
BugFix: Allow the asset browser tree view to use a horizontal scroll bar #633
BugFix: Correct a crash caused by sfxProfile #632
adress gl spotlights disapearing for deferred #631
This one slipped through - nextToken can't use local variable for its… #630
BugFix: Correct GLSL Pathing Errors in Light Rays Shader #629
BugFix: Correct a case where creator categories may get populated Incorrectly #628
sound asset followups #627
BugFix: Correct a few memory leaks #626
BugFix: Correct a fatal error that may be thrown in case insensitive Unix IO #625
BugFix: Correct CMake errors on Windows #623
partial rollback of #620 to stop win-side pop ups #622
update lpng #621
BugFix: Clear several CMake warnings. #620
fix opengl cubemap display #619
BugFix: Correct the inability to spawn assorted objects #618
Adjustment: POSIX Case Insensitivty #617
Sound asset implements #616
OpenGL Memory Info Extensions #615
BugFix: Correct the SelectAssetPath Window not Listing any Paths #614
followups to #582 #613
Added more tests for torquescript #612
Tweaks the MaterialAsset loading logic #611
simplify callOnModules #610
BugFix: Correct a Windows compilation error in the endian swap code #609
BugFix: Correct MSVC Compiler Warnings #608
Adjustment: Utilize native compiler intrinsics for endian swapping when available #607
[Linux] BugFix: Free the mouse cursor when triggering SIGTRAP #606
don't try and sort ribbon particles #605
BugFix: Clear a lot of warnings #604
item->importStatus cleanup for asset importer #603
fix groundplane material reference in examplelevel #602
BugFix: Fix AL device listing #601
BugFix: Correct tags in the asset browser not filtering correctly #600
Add handling to RotationF's addRotation function to ensure formatted return #599
uiCanvas keyboard mode callbacks. #598
Adjusted handling of field converts in the project importer to deal with fields that didn't contain quotation marks #597
GuiGameListMenuCtrl Update #596
inputTest Module Update #595
Fix specific usage of Con::executef where it was not being assigned t… #594
Material editor fixes from eval cleanup. #593
BugFix: Correct an object spawning error #592
BugFix: Fix a crash that sometimes occurs when groups of of objects are deleted #591
BugFix: Correct the onAdd callback not being raised for Projectiles #590
BugFix: Corrections to allow the Linux win console to work #589
kill splashscreen on nonwindows #588
Allow local variables to be used in eval. #587
particle cleanups #586
Misc QOL and Bugfixes 2021/09/19 #584
[OpenGL] BugFix: Correct shader errors being thrown during load #583
BugFix: Correct function call Error that causes the engine to crash #581
Converts precipitationData to use sound asset macros #579
dedicated gfx device suppression #578
Reimplement object copy failures. #577
Clean up more evals that have local variables are not working correctly. #576
Misc QOL and bugfixes for 2021/09/12 #575
Updates Prototyping module #574
Fixes initial indexing of the tool palette widgets #573
Fix local variable being eval'd in materialEditor #572
Forgot to null out the datablock after being deleted when it fails to preload #571
remove FMODex from Torque3D #570
%guiContent importer compliance fix #569
fix PhysicsShapeData upconvert entry #568
BugFix: Correct an error where the GUI editor cannot be opened #567
don't try to generate mipmaps for images that aren't n^2 dureing prev… #566
Bugfix qol 20210909 #565
macro cleanup #564
replace new with singleton to fix cannot re-declare object log file … #563
followup to #531. fixes the same issue on mac #562
Sound asset initial rollin #561
BugFix: Correct placement of the TORQUE_NOINLINE statements #560
Workaround: GCC Release mode Runtime Errors #559
Misc Fixes and QOL improvements #558
mini cleanups for ab #556
Update thread ids for 64bit support. #555
account for the possiblity of _set##name(StringTableEntry _in entries somehow getting punted nulls #554
sanity check nodelist presence #553
ensure new (foo) lines being converted are valid according to findObj… #552
DiffuseRenderPassManager.addManager "cleanups" #551
Misc Quality of Life and Bug fixes #550
be clear where we're referencing gbuffer render targets #549
kill off glowchan leftovers #548
fixes for copypastas that somehow slipped in #547
Converts most of AFX classes to utilize assets #546
Enforces filename string case sensitivity for assets' internal filenames #545
[PLEASE TEST BEFORE MERGE] Mac font stuff #544
MacOS fixes #543
tooltip work #542
Fixes new emitter button bitmap to proper fieldname #540
crash fixes #539
[Shape Editor] BugFix: Correct a bad octahedron.dts reference when using the mount viewer. #535
Importer sanitizing #534
Bugfix linux release builds for Clang #533
Linux BugFix: OpenAL Loading #532
Asset Browser on Linux Fixes #531
[Material Editor] BugFix: Correct case sensitivity errors on the model previews when running on case sensitive systems (Ie. Linux). #530
get the splash screen on linux to stop corrupting the main window #529
suppress deletion of temp material created by the editor #527
ensure the asset browser is executed prior to other pseudo-modules that may need bits #526
report if SDL_CreateWindow is unable to create a window at all #523
bad constructor usage! bad! GCC no like! #522
give useful data when not finding a given shader var #521
Engine Asset Update #520
Update TinyXML to TinyXML2 #517
partly address #502 #515
adress #510 - missing GFXFormatR11G11B10 macrohook #514
template index file review #513
adress #508 - fix postfxmanager default initialization #509
adress #501 - thread oversight. #507
adress #504 - typo leading to broken $origin reference #506
typofix in getScreenResolutionList #500
mac compilation and standarization fixes #499
Script extension assignment. #498
particle emitter bounds box fix #497
Fix buffer overflow issue in StringUnit::getWords bug #496
TorqueScript Interpreter 2.0 C++ Script #495
Fix return value conversion when using SimObject::call() method #494
shadowmap validator tweaks #493
report simset names for add/remove errors #492
augment bitstream write error reporting #491
connects staticshape::unmount to the parent chain so it can actually do so #490
expose a zip file password cmake config option #489
Window resolution options bug [Mac] Test Needed #488
Add support for Apple Silicon #487
Update TORQUE_GAME_ENGINE version number to reflect current version 4.0 #486
make string to char* conversion automatic #485
form steve yorkshire: mat editor save extension fix #484
Updates the masterserver domain referenced in the default scripts, pointing it to the new torque3d master server #483
add additional chars to the flatfile->asset->objectID name santizatio… #482
report which profile usages are conflicting (was,is) C++ QoL Enhancement #481
adds binary to decimal and vice versa methods QoL Enhancement Script #480
Implement Unit Test Suite for TorqueScript. C++ enhancement Script #479
Fixes a resolution switching issue when the game uses only OpenGL… bug C++ Script #478
Updates the torsion.in file to properly be configured to handle tscript extension C++ Script #477
reset emissive to show 0,0,0,0 for local/vector lights in a manner th… #476
Adds import config settings for forcefully adding configurable suffixes for shapes, materials and images #475
Fixes display of internal names on objects shown in guiTreeViewCtrl #474
Misc. minor AB fixes #473
Makes the DB creation process better jive with modules #472
Adjusts Forest object creation and forest item data creation/management to work with asset/module workflows #471
fix emissive #470
Missed a function where similar to previous was needed for the shape editor list fix to ensure it works both ways #468
Fixes the constructor path compare logic in the shape editor so the lists can populate correctly. #467
set prefab and makemesh origins to the biggest model #466
ribbon particle resource port #464
terrain brush dragging cleanups #463
Re-fixes terrain edit dragging without breaking paint actions #462
Implements shape preview caching for shape assets #461
re-fix file exclusivity, readd callonmodules variable extension #460
update openal-soft #459
Integrates object creator logic into the AB #458
augment datablock file handling to include references with no suffixes #457
Fix for transparency in splash images #456
version is not provided by current vendor api making it pointless to … #455
Added fix for #365 from PR #367 - buffer overrun bug #454
Corrects missed asset script file references in asset definitions when swapping to the tscript extension #453
Add Discord badge to README #452
Fixes some minor errors on MacOS regarding compiling in clang #451
provides a general Playgui_onWake callback for modules #450
Loading from zipped game directories. #449
general spawnspheres #448
Cmake allow non-source project directory #447
add parameter handling to callonmodule callbacks. #446
revert #401 as while it does surpress hieght painting touching the ce… #443
Removed old fixed function code from GFX. #442
D3d11 texture lock #441
Improve terrain rendering, handle bug with no detail #438
Assetifies MeshRoad, Decal Road, and the material slot of GroundCover #436
Adjusts handling of C++ asset types #434
moar asset errorhandling #433
sdl usage standards proposal 3 #432
mac fixes #430
High resolution timer fixes #429
Consolidates and standardizes terrain creation between the editor, asset browser and creator panel #428
membervar compile fix #426
Initial pass at implementing MaterialAsset macromagic utility functions #425
Height based terrain texture blending #424
OpenGL: Access viewtangent "DX" style for gbNormal in terrain textures #421
update sdl2 to release 2.0.14 #418
corrected and implemented a usage of shapeasset macros #417
Converts GroundPlane to utilize assets #415
Misc various improvements for noted issues with the Asset Importer #414
add validation flagging for server objects #413
Fixes a few bugs/issues on Linux #412
asset pipe cleanups #409
Fixes for AA toggle and GFX Device reporting for options menu #408
Wraps material animation floats to sane values. #407
Parametrize script extension, default to 'tscript' enhancement #406
Correct bump map in waterObject.cpp being in sRGB space #403
Fixing bug Terrain Editor bug #91 #401
Fixes logic that checks if a postFX was enabled so the PostFX Editor works properly #400
Misc Editor and editor GUI fixups/improvements #399
mMipCount was never being filled out. just use mPrefilterArray->getMi… #398
Removes unneeded redundant asserts when the functions already have range sanity checks #397
Adds handling so the pause menu has a button to exit the editor as a quick shortcut #396
WIP of marking active scene in the scenetree #395
Fixes Datablock and Prefab DragnDrop behavior with the AB #394
Adds ability to delete a module #393
Cleanup of some log errors and spam with assets #392
Better handling for finding modules by file path. Mainly used in asset importer #391
variation on #387 that also introduces errorcodes #390
hooks up shapebase children breadcrumb #388
adress #385 #386
get shapeassetID read. TODO: find further flaws and unrem the filter #383
Pause Menu toggle fix #381
light review (hdr and metalness vs direct lighting) #379
shader preprocessor fixes #378
mac compile fixes #377
be sure to executte defaults prior to clientprefs #376
Adds handling to the path manager so it can deal with both looping and non-looping paths #375
Misc fixes to ensure that the default postFX save, load and editing process is valid #374
get gl side HDR compiling, attempt clamp to keep bloom in range #373
Misc. probe bake/load fixups #372
Adds a sanity check so asset names cannot start with a number #371
Misc. BaseGame UI fixes #370
Added date/timestamp option to console log #369
fix #365 #367
Overhauls the handling of probes to utilize an active probe list #364
Improves default suffix handling for asset importer on image assets under a material asset #363
Basic prototyping module initial upload #362
Updates some level asset functions and script handling #361
clip ./ when doing pattern matching #360
Move slider to core and add opacity slider to console gui in BaseGame #359
Updates macromagic to properly set up for init'ing when image assets are set in material and terrain materials #357
sceneobject mountchain enable/disable collision aug #356
fix gl compilation #355
fix for empty r channel creation of composites crashing out #354
fix GCC compile #353
followup #352
replicate exec signatures for queueExec #351
EngineExportScope(){} can't be initialized by default, aparantly #350
Fix paths in caustics shader bug Script #349
Use string.compare instead of String::compare when comparing strings bug C++ #348
fix terrain compilation #347
gl needs OUT_col filled out to return anything #346
pathshape gravity suppression injection #345
Profile editor for the meshRoad object C++ enhancement Script #343
Replace uses of dStrCmp with new String::compare C++ QoL Enhancement #342
breakShape() - remove parts created with invalid object box . C++ QoL Enhancement #341
ForceFOV is not working on GuiTSControl. bug C++ help wanted question #339
extra option for terrain block to disable the update of the basetexture #337
Remove old and not needed torqueconfig files #336
SFX Player fixes #74 #334
Add NavMesh to World Editor #332
Temporary fix for the geometry feed in spotlights #329
Implementation of guiRenderTargetVizCtrl #328
Fix global variables not being able to be used inside of a foreach$ loop bug C++ #327
Feature/improve cinterface C++ help wanted QoL Enhancement #326
code review: #324
shift pbrconfig to ORM in keeping with the prepoderance of industry standards #323
minor cleanups: #321
memleak fix #320
Implements new shape fadeout and lighting fade/max lights/shadows pref options into the options menu #319
Implements hook-look-up logic for shape assets to ShapeBaseData including autoimport handling #317
Updated version of OTHGMars' updated window and resolution options modes. #316
Various misc. tweaks and fixes targeting memleaks and crashes #315
Fixes the hook-ins so when a shape asset is changed, tsstatics now are correctly triggered for a reload #314
fix chooseleveldlg #313
Reorgs the layout and editing of PostFX with some supplemental level save/load changes #312
Re-implements the dynamic cubemap mode option for reflection probes #311
Misc asset browser/asset creation fixes #310
new trigger features: triponce, tripcondition, and trippedby. #309
Misc fixes for Asset Browser navigation, scene asset utilization and editor settings #308
Misc editor settings fixes and additions #307
Misc Fixes for level saving and selecting asset paths #306
Fixes logic when opening shapeEditor with a TSStatic selected #305
Misc. Fixes and cleanup for lights #304
Miscellaneous small issue fixes #303
Integrates sound and shapeAnimation assets into the importer #302
Material Asset import lookups and initial re-integration of sis files. #301
Adds sorting to the settings class so when it saves out to file #300
Level Asset Dependency handling and various level fixes #299
fix for trigger::testobjects vector population #298
Adds a notes object that only displays in the editor #297
Fix compilation with shipping flag #295
Adds a pref to dictate if local lights can cast shadows or not. #294
Expands AB tooltips with file info #293
Adds image variances for the menuGrid image #292
Adds in the missing materials used for the Convex Proxies for triggers, zones, etc. #291
Standardizes the tooltip profile colors to match the rest of the themeing stuff #290
Adds logical check to skip animated statics when baking selection to mesh. #289
Misc. Image Asset improvements #288
More misc. fixes #287
Updates SDL to 2.0.12 #286
Followup commit to switch to engine conventions #285
Basic Platform::openWebBrowser implementation for linux #284
mouse display for keybinds #283
Even more misc asset fixes #280
More various Asset Browser and importer fixes #279
from @OTHGMars: AssetImporter type and path for material look-ups. #277
Queue exec order #276
Fixes the backend logic for setting/creating 3DTextures in D3D11 #275
Various fixes for both asset importing and some workflowy bits relating to assets stuffs #274
Fix gamepad binds on non-windows. #273
inputTest Module Initialization #272
Alpha40 shader gen cleanups #271
Some cleanup and adjusting of local light fields and default settings. #270
Adds additional light preferences #269
Adds some console preference variables for object fade overriding on TSStatics #268
ribbon shader variable order fix from @steve_yorkshire #267
Adds a default value to the lodType of the asset importer #266
proper variation on the datablock file list erasure #265
crashfix: const U32 numVerts = curEntry.vertBuffer-> is invalid for vectorlights #264
crashfix: decal report when missing the DB entry was malformed #263
fix reverb out of bound initializations #262
groundframe generation cleanup work #261
Moves the BaseUI module to utilize the queuedExec function #260
Captures secondary window close events #259
Updates the BaseGame UI theme #258
Fix GCC9 complaints #257
Fix GCC9 complaints #256
Fixes issue with Drag-and-drop asset import action #255
Moves the delta-based rounding function Verve used up into the engine #254
from jeff and tim: review of lighting impacts #252
Added slider to consoleDlg for bg alpha (Needs refinement) #251
from @rextimmy new isbackground shader feature. #250
Adds additional functions for inserting inspectorGroups #249
cleanup singlechannel glowmask leftovers (we use a full rgb map now) #248
Various improvements, fixes and enhancements to Asset editor stuffs #247
Various improvements, fixes and expansions for Asset Importing #246
Minor additions to popup menus #245
Adds logic to guiTextEditCtrl to have placeholder text when the control is empty. #244
from @practicing01: trigger mounting #243 by Azaezel was merged on Jul 10, 2020
from practicing: aiplayer onstuck correction #242 by Azaezel was merged on Jul 10, 2020
comparison flaw in spotlight animation check. #241 by Azaezel was merged on Jul 8, 2020
fixed cpu detection on 64bit windows #240 by JeffProgrammer was merged on Jul 7, 2020 1
#include "console/typeValidators.h" #239 by Azaezel was merged on Jul 5, 2020
fix cubemap capture for gl #238 by Azaezel was merged on Jul 5, 2020
safety check #237 by Azaezel was merged on Oct 9, 2020 1
client cleanups #236 by Azaezel was merged on Jul 26, 2020 1
Fix crash due to GuiEditCanvas::save() #235
Implements missing _captureBackBuffer method for GL gfx layer. #234
Fix for crash in _onZoningChanged methods when called by hidden objects. #233
Reworks the terrain loader code to work with the assets. #229
adress #116 and #179 (shaderside) #227
adress #225 #226
Removal of old font files from basegame template #223
adress #221 crash surpress macromap #222
adress #16 - don't need to swizzle vert colors #218
groundcover requested augs #216
fixes for trigger onenter/onleave #215
adds an animspeed and animoffset to tsstatic instances #214
typofix in opengl terrain shadergen #213
export rounds LODs to the nearest power of 2 #212
Updated links, added info from torque3d.org #211
adress #162 based on work by Chad Hall #210
adress #203 #209
Linux Slash compatability #208
adress #205 #206
D3D-only compile fix DirectX #204
implement copyResource, fix copyToBmp #202
Remove trailing whitespaces from simObject.cpp and fix pointer format #2382
fixed texture call which reported as a missing image #2378
Updates SDL to 2.0.10 #23699
OpenAL efx fixes for macOS/Linux #2362
Modification of #2145 Improvement #2354
adress #2344 #2352
Full template Scene conversion Bugfix Improvement #2345
fix(es) for volumetric fog when dealing with dedicated servers. #2342
Makes the popups correctly operate anywhere in the space of the canvas Bugfix #2340
Adds logic to temporarily disable collisions of mounted objects on Players Bugfix #2339
Fixes some outstanding menubar problems. Bugfix #2338
Fixes artifacts in Cloud Layer. Bugfix #2336
rewrite of NavMeshUpdateAll/NavMeshUpdateAroundObject Bugfix Improvement #2335
Cleanup and minor tweaks to the core dir structure. Improvement #2334
Fixes a crash that occurs on linux headless servers Bugfix #2332
Set contrsaints for Player Z rotation Bugfix #2331
Adds a filter for materials to never import when importing a shape New feature #2328
Adds ability to skip loading of cached dts in enumColladaForImport New feature #2327
Adds visualizers for various types of colorblindness Improvement New feature #2326
Moves the path return from fileDialog through the returnBuffer Bugfix #2325
Tweaks some object handling of guiTreeViewObj Improvement #2324
Sanity check for calling getFieldValue Bugfix #2323
Adds gui3DProjectionCtrl New feature #2322
Updates TextEdit value when focus is lost. Improvement #2321
Allows special inspectorFields to override their height Improvement #2320
Initial implementation of the Scene object Improvement New feature #2319
Tweaks to the Asset/Module info echo behavior to spam the console less. Improvement #2318
Adds ability to set the split point of a guiSplitContainer #2317
corrects a parity flaw between wireframe and non wireframe box display #2315
Switches to absolute position for mouse tracking. #2313
Snap to terrain Z offset. #2311
Vert color correction #2310
Remove redundant variables and clean up C4312 and C4305 warnings #2309
nextfreemask does nothing for proximity mines as there are no subclas… #2307
corrects a copy-corruption flaw with GuiSwatchButtonCtrl::onMouseDragged #2305
Sdl joystick2 #2300
Sqlite Console refactor, #2299
Travis Compile #2298
Fix SDL Input::getKeyCode on software keyboard layouts #2296
Add a .editorconfig file #2295
Adds features to GuiInputCtrl #2294
afxRenderHighlightMgr: account for hardware skinning #2292
corrects compilation errors on non-mac unix derivatives #2288
corrects compilation errors on mac #2287
Nfd update #2286
corrects a pair of conversions. one object oriented, one not. #2285
Fills in monitor functions in PlatformWindowManagerSDL #2284
Adds handlers for sdl focus events. Final review Improvement #228
Fixes CanvasSizeChangeSignal and Canvas::onResize() under SDL Final review Improvement #2282
OpenALEffects New feature #2281
Approved Improved BitStream writeQuat/readQuat methods. Improvement #2277
filter out pixel shader normalmap calcs when not in deferred mode. Bugfix Final review #2276
Adds Clamp to QuatF::dot() Bugfix #2275
Core module-ification Improvement #2272
micro patch to the nativefiledialogues library to mirror file type name #2270
alternative to #2268 : remove secondary profiling #2269
Network Code Fixes Improvement #2267
Resolves #1721 - ScatterSky zOffset Bugfix #2266
Fix for bug in GFXVideoMode::parseFromString() Bugfix #2265
Resolves #740 - Remove redundant code in _GFXInitGetInitialRes() Bugfix #2264
member var conversion error that oddly didn't crop up till mac testing. Bugfix #2262
Changes TSStatic::castRayRendered to use passed texcoord argument. Bugfix #2259
Fixes the front/back ortho views in the editors Bugfix #2258
Particles should go downwind (while windCoefficient >0) Bugfix #2255
SDL 2.0.8 Bugfix Improvement #2254
It's almost imposible to change direction of wind. Reseting mCurrentT… Bugfix #2252
openal-soft updates Bugfix Improvement #2251
Fixes various incorrect popup menu behaviors. Bugfix Improvement #2250
Updates PlatformCursorController to use full set of SDL cursors. Improvement #2249
New cinterface #2248
Corrects a problem with the D3D11 texture lock/unlock mechanism #2247
Update CInterface #2246
Clean-up uses of ConsoleFunction etc. #2245
Higher resolution app icon #2243
Interpreter Hotfix: Check for NULL on the thisObject before using it. #2242
This is a hotfix release. The main purpose was to correct the issues that had appeared with Visual Studio 2017 preventing 3.10 from compiling, but several other fixes were rolled in as well.
#2030 VS2017 compiler workaround #2123 Fix forest editor failing to load forest #2002 VolumetricFog memory leak fix #2014 Solves issue with getDesktopResolution and Windows 10 Creator update #1959 Does better sanity checking on cleanup for the splash screen closing in SDL #2106 Fixed a typo where the value of outBytesWritten was being clamped incorrectly #2238 Makes it so the SDL directory files aren't copied during a template install
More to add
#1688 Basic OpenVR Support code #1690 fix create datablock for physicsshapes. #1692 CMake support for VS_STARTUP_PROJECT #1695 Tidy up unnecessary #define #1705 3.9 fix: corrects improperly applied specularpower #1706 Tweaks the detail textures for the terrain #1710 adresses #1704: partial reversion to 3.8 specs regarding layer blending. #1711 Hardware Skinning Support #1713 adresses C4189 warnings #1714 addresses C4101 warnings ('identifier' : unreferenced local variable) #1715 Change back "enabled" values to lowercase #1716 changes "Rotation" instead of "rotation" #1702 #1717 fixes footsteps missing when no impactSoundId #1718 file name reporting for 'sampler not defined' and rtParams error reports. #1719 dx9 samplernames for fixed function replication shaders #1720 navmesh file load error-fix #1725 Fix to include a needed include for the accumulation volume stuffs #1726 added path @dottools #1730 accutex was left out of the copy constructor for TSRenderState. #1732 vec3 variants for toLinear and toGamma #1743 replace fix #1736 for add physicShape datablock from the editor #1749 adds toLinear and toGamma helper functions for ColorF, uses the former in adjusting lights. #1750 short term LOD correction #1754 Removes the unnecessary include of altbase in nativefiledialogs #1755 Implements the splash screen window to the SDL platform stuff. #1756 Fix load with DTS shapes introduced with HW skinning changes #1761 Intrinsicsfix #1762 lightbuffer (aka brightness and shadow) always comes last as a mul #1763 banding: conforms misbehaving postfx to the hdr buffer format #1764 linearizes fog color #1765 Correctly copy mipmap sub resources for DX11 cubemap. #1766 Replace Epoxy with Glad #1768 Added a missed a preprocessor for when not using openVR. #1769 Fixes the Toggle Children Lock and Toggle Children Hidden options #1770 Makes sure the key modifiers are passed along with mouse actions. #1772 Fix crash when saving NavMesh file without Links #1773 GuiInspector's findByObject method fix. #1774 embeds blendtotal into the low bit for the normal|depth buffer #1777 Update libogg to 1.3.2 #1778 Libpng update to 1.6.25 (fixes x64 crashing on exit) #1779 Revert TORQUE_CPU_X64 changes to oggTheoraDecoder #1780 .gitignore to exclude cmake generated config_types for libogg #1782 Fixes AbstractPolyList::addBox(). Complete each face with missing 2nd triangle. #1784 Gui speedometer hud #1785 MacOS platform support #1786 Reduce the amount of blocks of memory DataChunker uses #1787 Fix redundant memcpy in swizzle ToBuffer method #1790 GuitHealthBarHud flip fill #1795 ai: distance needs to be returned as a float. #1796 retooled circular ease methods #1798 clang: format_token string format correction #1799 clang catch: pragma note. (no longer needed) #1800 clang reports: unclear || + && and &+| mixes #1801 clang: register type modifier deprecated #1802 unused variable cleanup #1803 clang: trailing else #1804 clang: unsigned>0 checks #1805 clang: constructor initialization order #1806 more unused variable cleanups #1807 clang catch: boxBase's getPlanePointIndex method wasn't returning values in all cases. #1808 clang: consistent callbacks #1809 refactor: spacing on function call parameters #1810 Force enums using unsigned values to actually hard type to U32 #1811 filters false flags from clang compilation #1812 clang: The unit test suite doesn't play nice with -wundef #1813 clang catch: garbage in line directives #1814 garbage char in string #1816 OpenAL-soft for windows #1817 Preliminary IPV6 Support #1818 Fixes up some erroneous behavior with Simgroup parentage. #1819 Fixes prefabs in root dirs having extra folders in creator. #1820 Updates SDL to 2.0.5 #1821 Sanity check for if the GuiPlatformGenericMenuBar class #1822 Corrects the specular handling as per Richard's suggestion in #1783 #1824 Hides the light's dynamic refresh rate field in the editor #1828 fix issue #696 #1829 Adding depth option to the texture of guiOffscreenCanvas #1830 Fix for NavPath is not updated when navMesh has change. #1831 fix ColladaExporter #1834 Also adds a sanity check in the event a splash image isn't found. #1835 Adds some helpful utility math functions. #1836 motion based updates for shadow caching #1838 re-enable face culling for the terrain #1839 directional coloration for pathnodes, #1840 FIELD_ComponentInspectors inspector hook up #1843 Update version.h #1846 Fix SDL/Mac report going into the background #1847 factoring in tangentW causes parallax to swap specular highlight directions. #1848 [workaround] pinches parallax steps so the 0-1 range has minimal artifacting #1850 Change VS to use the default fp:precise #1851 remove dml file #1852 Adds some bake-to-collada functions #1854 fix SDL text events from generating a ~ key when opening the console #1855 Updated recast to 1.5.1 #1856 uts bitangent direction determinant back #1858 flips dx11, opengl, and sdl2 on by default now that those are no long… #1859 Multiple canvas support for GL and DX11 #1868 GL::Workaround::noCompressedNPoTTextures profile is no longer used #1874 readme update #1876 Fixes Bullet not supporting holes in terrain. #1877 Default port fix #1878 Fixes window icons with SDL #1879 colorPicker/swatch srgb display. #1882 OpenGL vsync fixes. #1883 DX11 updates #1885 update libvorbis 135 #1886 looks like getsockname needs a slightly different signature for crossplat support #1887 HDR review: remove from reflections, kill depth check, order of ops #1888 brings empty up to date for core and shader dirs #1889 Bullet 2.85 update #1890 added torque SimView tool #1891 D3D11 shadermodel version fix #1894 enable video recording #1895 Unused preDemoRecord() #1896 PhysicsShapeData examples #1897 Physx3.3 updates #1898 PhysicsShape applyTorque function #1899 Physx 2.8 removal #1901 Physics timing #1903 PhysicsShape applyForce function #1904 Fix net tests #1907 OSX de-deprecation (profiler and macFileIO) #1908 Removed deprecated use of register keyword from the TorqueScript lexer/parser #1915 Fixed semaphore struct to class #1916 SFX Variance Overflow #1919 Fixed StaticShape onUnmount #1920 Variadic console templates #1921 address #1914 #1922 Optionally include a CMake configurations file from the project directory #1923 String table empty string #1925 Sdl update fix #1926 Call the correct system rename #1928 Cleanup when deactivating light manager instead of reinitializing #1929 Make RenderPassManager call Parent::InitPersistFields #1930 Texture crash #1931 Fixes some issues with lightning #1932 Cleans up a few cmake options and flags #1933 Fixes editor handling of menubars when opening/closing. #1934 SDL Menubar accelerator fix #1935 Adds a check to the record movie call #1937 fix warningFlashes() of lightning class #1938 added strikeObject lightning feature #1939 Hotfix to re-add the prior static function fix in platformNet #1942 Fixes some issues with forest editor.
Release announcement
#1685 Precipitation maxVBDrops correction #1678 Fix a few more case sensitivity issues #1677 Flips the i386 flag to i386 #1676 Removes an extraneous Namespace usage #1675 adds bitmap coloration to: #1674 new: guiAnimBitmapCtrl #1673 Removes the body for the physicsBody's findContact #1672 Sdl popup menus #1671 Fix bug #1664 by @Areloch #1670 GFXD3D9Device generic shader support. #1669 New: GuiBitmapBarCtrl #1668 revised torque_nsight_workaround #1667 raycast division safety #1663 corrects corruption in precipitation class #1661 Enable demo rec #1660 suppresses a leak potentially caused by Knot::mType||Knot::mPath entr… #1659 Linux vix shader fixes #1658 Corrected "Pref::Server::ConnectionError" description. #1657 Correct AIPlayer aim. #1654 Shape mounting #1653 Corrects culling of point/spot lights #1652 Cleanup unused functions #1647 typo "tomove" to "to move" #1645 New object pointer cleanup #1644 Fixed compile errors on linux (obvious programming faults). #1643 corrects https://github.com/GarageGames/Torque3D/issues/1273 #1641 DX11 accumulation shadergen fix. #1640 fallback - dynamic shadow cache nuking (static refresh delay preserved) #1639 corrects safety check for Stream::readLongString #1637 Fix for Issue #1415Move::Move() is not properly initializing bool tri… #1634 Fix for "Crash on 'add a new mesh' Forest Editor action" #1633 #1632 localization augmentations via rlranft RE: #1631 Fix for rapid firing setImageTrigger(0,1); issue #1630 #1629 Makes vehicles work with the physics plugins. #1625 Fixes some bullet physics issues with the player class #1623 add loop playback to GuiTheoraCtrl #1622 Fixes vertcolor code insertion order, and #1621 Fixes the drawUtil rendering of polyhedrons #1620 Bug space folder in scene tree 2 #1617 removes w=z trick (was causing fisheye, effectively) #1615 Entity/Component implementation #1613 missing samplerstate configurations with empty #1611 Fix axis check in Box3F::extend method #1609 Adds the RotationF utility math class. #1608 Set textures as bitmapctrl in script #1607 Select camera when in material editor crashfix. #1605 corrects native file dialogue return values #1604 alternate to https://github.com/GarageGames/Torque3D/pull/1602 #1603 updated empty template … #1599 Added missing OpenGL profiling blocks. #1598 replaces GL_PIXEL_UNPACK_BUFFER_ARB with GL_PIXEL_UNPACK_BUFFER #1597 OpenGL Extension Caching #1596 removes FrameAllocatorMarker usage from GL side _fastTextureLoad #1595 Rolls back OGL Projection correction. #1594 Fixes the cmake blacklist filter it not using SDL #1593 Native File Dialogs #1591 Re-enable destruction of PhysicsShapes. #1590 missing samplerstate configurations #1589 GFXDynamicTextureProfile #1587 Profiler toggle and World Editor menu entry. #1586 Expose Network Sim fields on NetGraph gui #1583 exposes several datablock entries to the particle editor gui subsystem #1582 Reimplements a form of subsurface scattering #1578 Fix up GL formats to comply with core profile. #1577 DX11/GL border offset fix for GFXDrawUtil::drawRect #1576 Updates SDL to version 2.0.4, which makes it compatible with VS2015. #1575 CMake SDL Option #1574 corrects projection matricies for opengl #1573 allows navmeshes to generate for most scene objects, #1571 ScreenShotD3D11 delete fix #1570 Roll back the changes to simPath temporarily in order to merge in DX11 #1569 Fix for SimPath to make DX11 compatible. #1568 case sensitivity typofix #1567 Added Epoxy in favor of GLEW #1566 Fix release build compile with MSVC 2015 (finally) #1560 GL floating point format fix. #1559 Direct3D11 Support #1558 Spacial update for Px3 character controller #1556 Path editor display augmentations. #1555 fix for broken caustics reference #1554 from @rextimmy automatically adds a sky feature to skies. (render so… #1553 turns out independent sized render targets was causing lighting artif… #1552 should actually let HDR have a say for glows. #1550 new method: ResetGFX(); #1548 alpha masking for buttons. original attribution @dottools #1541 Fix crash callonchildren #1540 Fix zipped dts loading #1539 addresses https://github.com/GarageGames/Torque3D/issues/1537 via the… #1536 opengl crashfix pow(x,y) needed to be passed matching vartypes. #1535 [CLONE] Add support for abstract ConObjects #1533 New color picker - #1334 clone #1532 [CLONE] More consolefunctions #1143 #1530 Steve Acaster's Ai Poses #1529 Asserts cleanup PR with conflicts resolved. #1528 New script function to edit script-created decals #1527 Fix for TerrainFeatGLSL getProcessIndex() signed mismatch #1526 Corrected signed mismatches in featureSet & shaderFeature #1525 Added immutable vertex and index buffers. #1519 Deferred shading #1518 http://stackoverflow.com/questions/8461832/explicit-qualification-in-… #1517 namespace conflict resolution #1516 vsprintf replacement with engine vairant #1512 [OpenGL - Win32] This fix a bug during resolution change. #1507 Fix for collision issues with scaled players #1506 setDetailFromDistance aspect ratio friendly adjustment #1505 courtessy @Lopuska: opengl occlusion query fix #1504 ResourceLeakFix for OpenGL #1502 Glow buffer graphic corruption fix on OpenGL. #1497 footstep and impact enum extension support #1496 Fix case sensitivity and Platform::fileDelete #1490 Fix for OpenGL/D3D11 bottom border offset #1484 Updated paths for collada tdictionary.h #1481 Extacted AI tweaks: #1480 Fix NULL pointer Crashes in WorldEditor::selectObject & unselectObject #1478 Volumetric Fog Take 2 #1475 NavMeshUpdateAll leak suppression (not 100% preventative) #1474 mDirtyTiles changed from std::queue to a vector #1473 Fix TinyXML Build errors #1470 removes StaticObjectType flag from water objects. #1469 Recurse dump directories fix #1464 bullet module #1463 missed a convexSweepTest early-out check. #1461 diffuse/albedo texture linearization #1460 fillin for fallbacks for filesystem funcs #1459 corrects ghosted decal datablock lookup flaw #1457 hooks meshroads up to the material system for castrays #1453 playJournal fix and removed depcrecated command line options #1452 Corrected SkyBox vertex format #1447 improved radio button #1446 Removed unused vertex colors from GFXWaterVertex #1444 Removed unused vertex formats from ScatterSky #1443 TAML, Assets and Modules implementation #1442 shadow caching #1439 ensures opengl texSpaceMat is initialized from the get-go #1438 explosion cover miscalc #1436 missing ribbon shaders, empty template #1435 missing empty template glow pass debug tool #1434 fullscreen and windowed mode cli fix #1433 The TypeCommand type brings up a full notepad-esque interface. #1432 Backend correction for the rigid vs rigid collision resolver: #1431 SfxCompareProvider fix
Release announcement
Release candidate announcement
You'll need to regenerate projects thanks to Oculus file changes, even projects which don't use OR.
One remaining issue that we tried to get wrapped up, but was unable to was native file dialogs.
There's a few niggling issues causing a crash somewhere with Areloch's implementation. There's a branch concerning it here and if anyone can either tell him how to get Codeblocks to properly debug, or can figure out the crash themselves, it can PR'd right away and get a hotfix out to re-enable file dialogs for the Linux build.
#1426 Backend correction for #1425 #1423 SDL Menubar accelerator fix #1421 CMake NMake fix to place exe in game directory #1418 Remove GL_EXT_gpu_shader4 #1416 SDL Textbox bleedthrough inputs fix #1411 void GuiTextEditCtrl::execConsoleCallback() reversion #1410 Light animation brightness fix #1409 U32 MRandomLCG::randI() was using longs #1407 Companion PR to 1398 #1406 Monkey PR w/ mergefix #1404 Companion PR to #719 #1402 Files caught by https://github.com/GarageGames/Torque3D/pull/1401 #1401 Adds a verifyCompatibility method to the Win32FileSystem to report case-sensitivity issues #1377 From Dušan Jocić: convexDecomp vs2015+ compatibility patch #1376 From Dušan Jocić: early out of treeview entries to prevent crashes #1375 Redux of Winterleaf's PR 1001, with the suggested updated values #1374 "AL: PSSM Cascade Viz" tool-button #1373 Ribbons in the editors #1371 Random VS warnings #1370 Stop precipitation from processing ticks when it's hidden #1369 Fix NaNs in Collada files #1366 Overrides the default CMAKE_INSTALL_PREFIX #1365 Removing pointless null-pointer tests for objects created with new #1363 Allowplayerstep lets folks run up sharper angles than normal. #1390 Case sensitivity fix for linux #1388 SDL mouse wheel speed fix #1387 Fixes the menubar functionality when using SDL #1385 -wall leads to incredibly long compile times #1383 SDL2 mouse wheel scrolling #1382 Fatality Fix: need to account for 64 bit windows as well. #1380 Partly addresses C4946 warnings #1379 C4189 warning cleanups #1378 Properly testing pointer vars aren't null before using them. #1400 Case sensitivity script fixes #1399 Adds a debug visualization mode for the active physics world #1398 Update messageBox.ed.cs #1397 From @LuisAntonRebollo -stops infinite loop on exit with SDL2+OGL on Win #1396 Adds data to vector out of bounds reports #1394 Release the mouse from window constraints when poping up a window prompt #1392 Warning C4005: 'WIN32' : macro redefinition #1391 Warning C4706: assignment within conditional expression #1362 Removes fatal assertion on duplicated object collisions (meshroads, primarily) #1361 Adds minimum displacement check prior to convexSweepTest to avoid NaNs #1358 Reduces rotation transmission size #1357 Followobject position caching #1356 Convert un-modified function arguments to const references #1354 Cleanup of ease functions operations #1353 Utilize ++iter rather than iter++ to improve iterator performance #1352 Unnecessarily repeated expressions #1350 Fills in profiler timer fallback #1346 Allow using ThreadPool synchronously #1344 Fix -Wreorder warnings from ShapeBase #1343 Fixed some random gcc's -Wreorder warnings #1342 Offsetof is actually a standard thing nowadays it would seem #1341 Fixed warning #1339 Remove demo and trial checks #1336 Fixed some minor compiler warnings on Linux #1333 Plugging Memory Leaks #1330 Basic fix for stereo rendering without a display device
Most uses of ConsoleMethod have been changed to use DefineEngineMethod. The old macros haven't been removed, and are in fact still used for variadic script functions, which aren't currently possible with the DefineEngineMethod macros. But be warned that there are a lot of changes in this area, which may cause conflicts if you've modified any of the console methods.
James Urquhart's major console function call refactor has finally found its way in, which has meant significant refactoring to the way TorqueScript works under the hood, including new wrappers for console types. This has introduced some subtle bugs we've managed to find, but if you're relying on custom console methods and behaviour, we urge you to double-check those and make sure they still behave exactly as expected.
A bug in quaternion math has been fixed, but you might find that code relying on the broken behaviour needs to be changed.
There's a new version of the SimDictionary based on the C++11 STL hashmap. You'll find a commented-out #define in torqueConfig.h which you can enable if you like. According to the contributors, it's worth doing if you have a lot of SimObjects about at the same time.
The projects.xml file is now part of the main repo, instead of being part of the Project Manager repo. Just so you know, and don't go looking for it there.
isObject is now stricter about what's actually an object. Where before, the string "3.14" would be cast to the integer "3" and resolved to object ID 3, the whole string is now validated first, and if it's not a valid integer, it won't count as an object ID. (Note that the method still also accepts object names as usual.) This logic expands to other types of object resolution as well - so "3.14".getClassName() now won't work.
#1327 GFXGLDevice setShader fix.
#1326 GFXGLDevice setShader fix
#1324 Fixed a issue with the terrain blending having hard-edges.
#1321 No need for server-only aps to generate visible textures.
#1316 Fix for rendering particles to the glow buffer
#1315 particle glow bug
#1316 Fix for rendering particles to the glow buffer
#1292 Editor ribbon cannot be expanded once collapsed
#1303 Add workaround for issue #1292
#1302 Vignette PostFX does not save
#1305 Apply vignette settings properly for #1302
#1313 Added toolbar expand button images.
#1301 setExtent now takes Strings instead of leaving args as pointers.
#1287 Forest in Outpost level not appearing in Ubuntu
#1307 tsForestItemData: default to no bounds instead of crazy bounds
#1310 Corrected another filename case
#1309 Add more info to fatal assert in SceneContainer
#1308 Case-sensitive filenames for Linux
#1270 terrain texturecache prior functionality preservation
#1294 opengl crashfix: cannot self-multiply a uniform. use a temp-variable.
#1277 Level save with populated forest results in "FileStream::open::empty filename"
#1290 Patch to fix no-sound in Linux
#920 Fix for fuzzy borders between textures
#1289 Dedicated server crashes
#1298 Remove value constructors for ConsoleValueRef & fix callbacks
#1290 Patch to fix no-sound in Linux
#1289 Dedicated server crashes
#1288 Issue 1277
#1283 corrects getrandom to behave as documented.
#1279 Fixes issue #1277
#1278 Tweak Vagrant
#1277 Level save with populated forest results in "FileStream::open::empty filename"
#1269 Added missing VS2012 template files to Empty template
#1268 Removed main.cs.in files
#1252 Fix bug on DefineConsoleMethod GuiCanvas::setVideoMode.
#1250 fullscreen alt+tab erorrs
#1246 Fix GuiTreeViewCtrl::getParentItem incorrent use in ShapeEditor script files.
#1245 Fix GLSL include when file is empty.
#1244 Fix waterBasicP.glsl for HDR.
#1243 Simplify readme
#1242 Fix Linux rpath.
#1241 vignette_final
#1236 Revert recent style cleanup changes
#1234 typofix for void ColladaAppMesh::lockMesh
#1232 Level Output crash (development branch)
#1230 removal of un-implemented ShockwaveData entries from explosion.
#1227 Con::executef trampoline had mismatched argc values for the high end
#1226 fix preprocessor directive
#1225 Vignette updated for OpenGL
#1223 DeferredBumpFeat order of operations corrections
#1220 Fix #396
#1218 Revert "PR for issue #748"
#1216 Fix VS2008 again again
#1215 Default to background navmesh builds
#1214 Fix some issues flagged by cppcheck
#1212 Fixed SDL related header includes for linux
#1204 little typo
#1203 Fix shadows on Basic Lighting.
#1202 proper fix for https://github.com/GarageGames/Torque3D/issues/1197
#1200 Fix for minidump support
#1199 Added NULL check in function findItemByName.
#1198 Fix Bullet compilation.
#1197 unit tests for matrixf_X_matrixF causing non-compilation.
#1196 return the result value of scrollVisible
#1195 Projects from 3.6 do not work with 3.7 executable
#1192 MiniDump support doesnt get defined when checked off in the project manager
#1191 #define TORQUE_RELEASE doesnt get defined for release builds
#1190 nvidia nsight debugger support.
#1183 Documentation
#1181 Crash 3.6.3 GUI Editor Locks Up
#1180 Add math control state functions for intel
#1176 Fix VS2008 again
#1175 feedback for *which* namespace is already linked.
#1171 extra entry in DefineConsoleFunction( queryMasterServer
#1170 Fix VS2008
#1169 Add Vagrant config
#1167 Remove default web deployment
#1165 Fix for console stack
#1164 Remove some dead code from OpenGL shadergen.
#1161 More x64 fixes - 2
#1159 Include navigation and testing modules by default
#1157 Show the canvas immediately in unix because the splash doesn't work
#1156 Fix issue 396
#1149 More x64 fixes
#1145 Make CMake project load all .cmake files from the module folder Updated.
#1141 Changed type to NetSocket
#1140 ambient normal on GLSL
#1137 Fix changes to moveSelection API
#1136 Bullet build is broken by linux changes
#1135 Object editor lod alteration fails
#1134 Pull Request #1026 broke the console stack
#1133 Rename netTest.cpp to netExamples.cpp
#1131 Two netTest.CPP files write to same place
#1130 Remove a get* OpenGL function causing CPU-GPU sync point.
#1128 cloudlayer hdr packing
#1127 OpenGL Basic Lighting rendering issues
#1124 Forest wind emitter
#1121 Fix buffer overflows
#1119 OpenGL fix - fixed a crash when you activate Alpha Threshold checkbox wi…
#1118 fix #1117
#1117 OpenGL bug - removing diffuse from a skybox cause shadergen error
#1115 Jeff faust fix also on openGL.
#1100 Fixed define bug for OpenGL shadergen.
#1098 OpenGL basic lighting no shadows on player
#1097 GUI Editor moveSelection
#1096 Fix include guards
#1093 Fix setExtent
#1092 Walkabout navigation editor
#1090 Anonymous functions
#1089 Add profiler regions for StringTable functions
#1085 cubemap Mip retrieval-DX
#1084 OpenGL: Add project define for GLEW with php generator.
#1083 Fix/walkaround for OpenGL on Intel
#1082 OpenGL debug crash on Intel HD4000
#1081 Added OpenGL to projects.xml
#1080 Use a strong reference instead of more manual reference counting
#1077 Fix persistent underwater effect.
#1074 cleaned up variant of Accumulation volumes #768
#1072 Make more use of DefineConsoleMethod
#1067 bugfix #1066
#1065 winTime month fix
#1064 CMake fixes
#1061 Glow particles
#1056 mipmap support on OpenGL cubemap
#1055 Fix ShaderGen cubemap feature.
#1054 Style cleanup
#1053 development - opengl cubemap display wrong on scaled objects
#1049 Add VS2012 support to projectgenerator
#1048 missing texture format.
#1040 Fix spaces in TSStatic fied names.
#1035 Memfixes
#1030 Volumetric Fog Resource by Richard Marrevee.
#1029 Intel graphics bugfix
#1027 Allow normals on shadowed surfaces
#1026 Fix issue where console stack values were getting overwritten
#1025 Fix AMD render problem with missed meshes.
#1023 soft snapping makes systematic crash on x64
#1020 SimDictionary improvement
#1018 Ghost scoping
#1014 vSync on opengl
#1013 Fix testimg ppm
#1011 Fix GLCircularVolatileBuffer incorrect binding.
#1007 Added scriptable move triggers for AIPlayers. Fixes an issue where AIPla…
#1006 Fix lighting errors when all lights are disabled.
#1005 Revert terrain opengl
#1004 Fixed a crash and memory leak on the ribbon code
#1003 Ribbon port for opengl
#1002 Z Offset for Scattersky to fix the rendering issue at high altitudes.
#1000 FMod switching DLLS if 64 bit.
#999 Fix so it compiles correctly on Visual Studio 2013
#998 Fixed issue where physx3 cpu dispatcher was created multiple times
#997 This just adds some console spam if the PostEffect Texture isn't found. …
#996 Added support for AMD Chips
#995 Just cleaned up some code
#991 Bit Alignment of variables in serverQuery.cpp
#981 Fix x64 builds.
#980 opengl error reporting formatting
#977 Support for physx3 in projects.xml
#976 Parameters to callback being overwritten by method call inside callback
#974 re-orders sound device provider wieghting
#971 turret tracking correction, again
#970 clamp value fix on vorbis decoding
#969 Improved God Ray PostFX
#967 Add support for rendering particles to the glow buffer
#955 Eval return issue 953 and trace buffer 952
#923 turret tracking correction
#922 Make HTTPObject::post work
#921 Remove warning
#920 Fix for fuzzy borders between textures
#919 BaseTexFormat was not networked properly.
#918 HTTPObject's post method doesn't work
#917 Fix bug where console stack was incorrectly used to print audio devices
#916 Re-enable MixedParticleRendering warning.
#915 sfxGetAvailableDevices breaks after console changes
#910 Added Alpha LOD to tsStatic objects.
#908 This adds limiting the ghost data to a specific area around the client.
#905 Lens flare effect rendering over objects
#903 WaypointTeam never worked and if you look at the code you can see its no…
#902 Cleaning up and streamlining Types.h,
#896 Dev forest wind emitter improvement
#895 So the problem is that when your inside the sphere it won't render so it…
#894 Added Sanity Check for out of memory
#892 Improvements to SimDictionary for when you have a large number of object…
#890 Minor Improvement to depthSortList.cpp
#889 Improvements to the math in mEase
#887 Replaced a ton of ConsoleMethods with the DefineConsoleMethod Macro.
#886 Reduce minimum tab width in PostFX manager
#882 Update README and Github wiki
#877 Revert "Euler to quat reversion"
#876 Turret uses quaternion and euler angles incorrectly
#871 Added a setPosition function
#869 Fix omissions in astNodes.cpp
#853 Fix console func refactor
#845 dynamic cubemapped statics
#843 Added projects.xml from Project Manager
#842 jamesu's console function refactor
#841 Underwater fog/caustics/turbulence effects don't disappear when they should
#832 Move projects.xml here from project manager repo
#829 Add console function to link namespaces
#828 Provide direct script access to namespace functions
#827 Make CMake project load all .cmake files from the module folder
#816 CMake does not name debug executables with _DEBUG
#806 PostFX presets do not reset between missions
#793 Terrain basetex formats
#788 Allow return status to be specified using quitWithStatus
#784 NavMesh scale does not make sense in script
#774 TorqueScript anonymous functions
#770 Fatal error-Shader quality lowest with lighting quality above lowest
#768 Accumulation volumes
#761 -added Vignette PostFx
#751 Script API: no setPosition
#749 Re-enable Mixed particle rendering
#744 Ribbon implementation
#726 Sahara
#721 deprecated functionality. T3D handles this in the reflector class.
#715 Fix to allow parallax mapping with dxtnm textures via the red channel.
#705 Fix for unexpected behavior described in issue #704
#704 Return values from TS functions not handled correctly.
#690 Bullet Physics Library 2.82 update
#685 Physx3 Physics Plugin
#667 MeshRoad does not collide with physics objects
#664 Consoleargfix
#663 "Unused" TS arguments being optimised out
#658 Add send queue to TCPObject
#637 Change all member vars to use mMemberName naming
#623 CMake generated solution has ALL_BUILD as startup project
#592 TorqueScript unit test
#587 Add OpenGL 3.2 renderer
#479 Custom GUI Profile/Files issue
#396 Using LF (\n) instead of CRLF (\r\n) causes some parsing errors.
#199 GuiObjectView camera transform and object orbit distance problem.
#164 Euler to Quaternion conversion is incorrect
#148 Prevented looking up incorrect object handles
#81 Improve Console Function Calls
#990 Fix CI server.
#989 Fix OpenGL changes formating.
#988 Clean GLSL fragment shader out.
#986 Fix GLSL out fragment shader color.
#985 Clean PlaneReflector member variables declaration.
#984 const U64 maxValPerChannel = (U64)1 << mBitsPerChannel;
#983 DeferredMinnaert feautre was missing samplernames
#982 Fix PHP ProjectGenerator for OpenGL.
#965 Added OpenGL module with some additions to the project generator
#962 Fix OpenGL new terrain blend
#961 Fix OpenGL fullscreen on win32
#940 Add/Activate OpenGL render.
#939 Templates changes for OpenGL shaders.
#938 Remove old/unused OpenGL files.
#937 Increase FrameBuffer size for use on OpenGL.
#936 GLEW library for OpenGL.
#935 Fix imposter capture on OpenGL.
#934 Changes on PostFX for OpenGL.
#933 Changes on ShaderGen for generate GLSL shaders.
#932 Reduce innecesary changes on Render Target textures.
#931 Set correct terrain layer texture format.
#930 Separate OpenGL code from Linux or Mac.
#929 Remove unnecesary code for handle OpenGL.
#928 Change RenderParticleMgr for use sampler names
#927 Add GFXDevice::setupGenericShader for fix render on non FFP.
#926 Fix PrimBuild with non Fixed Function Pipeline.
#925 Add sampler names to ShaderData
#924 Remove GFXDevice::disableShader
#622 Handle texel-pixel offset with diferents graphics APIs.
#621 Update GLSL Shadergen.
#620 Add RenderPassData::mSamplerNames for OpenGL code. Not used on DX9.
#619 Add GFXShader::init with support for ordered vector of sampler names for shader.
#618 Use shader data for get sampler register in CloudLayer and BasicClouds.
#617 Fix ScatterSkyVertex::color declaration.
#616 Fix WaterObject TODO: Retrieve sampler numbers from parameter handles, see r22631.
#611 Add sampler names to Templates ShaderData declarations necesary for OpenGL.
#610 Changes to Templates GLSL files for OpenGL
#608 Use GFXDevice::setupGenericShaders for support non Fixed Fuction Pipelines.
#883 Update readme and version
#880 Improve documentation on getCursorPos and fix cursorInControl
#879 Increment vertex pointer by 3, not 1.
#878 Prevent crash when loading Player with no shape
#875 Use existing methods instead of incorrect maths
#874 Enable gamepad input when the startup GUI wakes
#870 Andrew's fix for ear transform with detached camera
#868 Contributing doc
#854 New Physics doc group
#851 Create contributing.md
#846 guiobjectview corrections
#840 Disable all post effects by default
#839 Some engine fixes
#836 Update info in README
#834 Some engine fixes.
#833 Fix: Null'ed pointer usage, possible access violation.
#831 Ear transform does not match camera transform
#825 TSMesh::castRayRendered triangle iteration error
#824 TSStatic bounds collision normals seem wrong
#765 RigidShape is in the Platform doc group
#703 Cloned Dynamic Cubemaps bad.
#701 Fix: Null'ed pointer usage, possible access violation.
#693 Binds the full metrics display to CTRL+F2 while in-game. Escape Closes.
#262 Gamepad input not working until you get into the game.
#180 GuiCanvas::getCursorPos() broken
#98 Crash in TSShapeInstance::setSequence in tsThread.cpp.
Add a call to closeSplashWindow somewhere if you don't want it sticking around in the background. Template main.cs files now do this.
If you manage Project Generator modules, the Generator class has been renamed T3D_Generator.
If you were relying on Projectile impact decals being aligned vertically, sorry, but they will now rotate randomly on placement. We thought this was better default behavior.
Player now makes use of PlayerData::swimForce while submerged, where previously it ignored this value and used only runForce.
ShapeBase::Thread::sound and associated functions have been removed because they were not actually used. If you made them useful in your own code, we apologise for any merge conflicts.
#808 Version 3.6
#807 Added Outpost testing level by Azaezel
#795 Support for Windows x64 builds
#737 Query Stall Prevention
#723 Light ray cleanup
#772 Outpost testbed.
#775 player triggers.
#728 Port existing unit tests to googletest
#796 Bump version numbers
#801 Googletest tests
#233 Editor crashes when painting a forest in the scene in debug mode physx on stock T3D
#689 Physx 2.8 actor release fix
#794 Euler to quat reversion
#781 Removed annoying warning
#763 - Added check in tsMesh::createTangents to check size of incoming normal…
#739 Fix Vehicle crash on change Datablock's shape.
#779 Fixed Vehicle crash on changing datablock shape in editor for #189
#722 implicit truncation warning cleanup.
#616 Fix WaterObject TODO: Retrieve sampler numbers from parameter handles, see r22631.
#800 Fix compiler warnings with CMAKE and TORQUE_DISABLE_MEMORY_MANAGER.
#559 Torque3D x64
#791 Bumped minimum CMake version
#792 Link against librt
#776 Simplify compiler ast
#81 Improve Console Function Calls
#658 Add send queue to TCPObject
#716 EventManager is actually case-sensitive
#789 Make mSubscribers case-insensitive
#682 Extended onend sequence
#459 Non-Cyclic animations don't propagate to new clients.
#780 Fixed ShapeBase animation networking
#783 chat under GNU/Linux does not catch all typing focus
#754 requested correction
#769 Adds material definitions for groundcover referencing.
#717 Make NavPath::alwaysRender work the same as NavMesh::alwaysRender
#773 Removed ShapeBase::Thread::sound
#645 Ridgidshape update forces
#649 Ai player utility
#650 Ejection offset variance defaults
#742 Improving CMake build system for power users
#641 Projectile decal
#554 Fixed some warnings L4 on the VS2012.
#766 Deferred Shading
#747 WaterObject loose reflection.
#567 Natural (without 2-km limitations) heights of terrain.
#760 Fixed thread statics
#636 Fix cmake mayor
#755 Fix splashscreen
#735 Splash screen fix
#756 Load new DLL first so existing projects don't see odd behavior
#621 Update GLSL Shadergen.
#590 cmake - version 2
#603 simple alteration to allow for negative damage (repair).
#416 error splitting mesh and image filenames
#662 Fixes #625 - Cmake missing modules
#647 Debris collision
#659 Bouncy bullets
#495 action tactics template
#605 Player hitboxes
#548 More fixes
#601 Rename enum GFXTextureProfile::None for avoid conficts on Linux.
#612 Platform type consistency
#738 Add GG(c) and MIT license to CMake files.
#727 Add MIT header to all CMake files
#661 Grenade decal
#665 Support for large lists of shape formats.
#455 Platform type consistency
#600 Rename Status enum for avoid conficts on Linux.
#732 Revert #540
#729 Fix #224 Memory corruption on Precipitation::destroySplash.
#224 modifyStorm bug in precipitation.cpp
#731 Fix CMake testing module.
#544 Update bundled PHP to 5.5.6
#542 Update to latest smarty to fix problems with PHP 5
#595 Move unit tests to their own module
#626 Use gtest framework for unit tests
#706 Add Google test library
#698 Append ' DLL' to DLL name to fix linker times
#72 Long linker times on Torque3D.dll (VS2010)
#558 Fixed errors vs2013
#718 Fixed Euler to Quaternion conversion
#164 Euler to Quaternion conversion is incorrect
#277 Bug in GFXDrawUtil::draw2DSquare
#724 Allow drawing 2D squares with 0 rotation angle
#201 Engine - Bad quad UV mapping (THREED-1482)
#697 Added string functions from T2D
#711 Make use of PlayerData::swimForce
#570 Fixed Box3F::overlap
#425 fixed memory checking in volume
#687 Add coverage option to procedural terrain generator
#597 Fix VS2008
#674 Fix SignalBase constructor shenanigans
#699 Prevent call to dStrlen(NULL)
#632 Added a better example of using Explosion in a client/server fashion
#715 Fix to allow parallax mapping with dxtnm textures via the red channel.
#475 A few fixes for generating projects on *nix platform.
#538 Tangent Basis Cleanup
#563 Fixed issue #256: "$pref::TS::smallestVisiblePixelSize doesn't work".
#580 fixes problems for newer php version
#547 Fix potential crashes
#593 Added build status icon to README.
#556 When setting the field on a GuiInspectorField, check if the field is null before setting the docs
#675 Fix assertfatal/TORQUE_UNUSED release performance
#676 Fix dedicated Linux build.
#609 Case-sensitive fixes on template script files for Linux.
#465 Fix bug in HTTPObject (Fixed)
#568 clipping the lighting result via ciel was causing banding issues with sp…
#543 PHP 5.5 doesn't want us to use the class name "Generator"
#596 VS2013 compatibility patch.
#630 FIX RenderMeshExample not having a material on mission start…
#631 FIX RenderMeshExample not having a material on mission start even if one…
#629 FIX RenderMeshExample not having a material on mission start…
#540 Added a default keyboard layout for launching the game.
#614 Removed unnecessary parameter in a simObject getter method
#635 Various engine fixes
#670 Fix Dereference of null pointer on String::operator+=
#671 Fix cmake dependencies
#591 revised #568. abs and max.
#581 Visual Studio 2012 32Bit Level 4 Warning fixes
#569 Added the script Utils::landing() for the simplest work with a level
#602 removes non-functional shield and invincibility functionality.
#561 Corrected docs for scripts in the group FileSystem: fileBase() and fileName().
#594 Increased stability Torque3D: unit-tests running without a crash.
#599 Errors during global ThreadPool destruction.
#634 Commit to add "Coverage" option to procedural terrain generator
#562 Unit tests without crashes.
#613 T2D style 'Stock colors'
#646 Ejection offest variance defaults
#583 windows 64 bit basics
#673 SignalBase constructor causes warnings in GCC
#681 Fix CMake linux dedicated on gcc and Clang
#582 RenderInstType default constructor improvements
#666 CMake linux fixes
#557 Add a 'Coverage' option to the procedural terrain generator
#669 Fix ALDeviceList::GetDeviceVersion incorrect check of valid pointer.
#668 Fix for avoid a zero division on _StringTable::resize.
#617 Fix ScatterSkyVertex::color declaration.
#551 Minor fixes
#628 Fix crash on exit T3D when build with CMake.
#566 Action for solder edges of nearest terrains.
#633 Coverage option for procedural terrain painter
#604 Particle Accumulation on Damage (Yet another one-liner)
#652 Use fixed buffer size variable for allocating return buffer
#688 Vehicle gamepad fix for full template.
#367 Vehicle out of control when entering with a gamepad.
#672 Cmake improvements
#638 Fix for avoid a zero division on _StringTable::resize.
#640 Fix ALDeviceList::GetDeviceVersion incorrect check of valid pointer.
#639 Fix Dereference of null pointer on String::operator+=
#610 Changes to Templates GLSL files for OpenGL
#619 Add GFXShader::init with support for ordered vector of sampler names for shader.
#625 CMake has no option for Rift, Hydra or Recast
#660 Grenade Launcher Projectile Missing Decal
#656 Missing parameter in FixedSizeVector
#627 Explosion is not networked properly
#624 CMake generates solutions in project root
#437 Ground Cover Material Issue
#615 Fixed the crash when using glow material on billboard groundcover
#598 Issue 437
#493 Ubuntu 64 compile Error
#79 Add TorqueScript Prefab methods
#143 ClientMissionCleanup not found
#553 Added method Vector::reverse().
#586 CMake Buildsystem Basics
#578 improved gitignore for VS2012
#589 further cleanup for error splitting mesh and image filenames #416
#584 Copy of PR #551 changed to target development.
#577 main working on unicode systems
#473 PHP class name clash with Generator class.
#428 Sprinting is not a pose
#546 Minor cleanups
#256 $pref::TS::smallestVisiblePixelSize doesn't work
Project Manager
Torque 3D was created by GarageGames to make the development of games easier, faster, and more affordable. It is a professional Software Development Kit ("SDK") that will save you the effort required to build a rendering system, high speed multiplayer networking, real time editors, a scripting system, and much more.
As part of Torque 3D, you receive full access to 100% of our engine source code. This means that you can add to, alter, or optimize any component of the engine down to the lowest level C++ rendering calls. That being said, you don't need to be an experienced C++ programmer to use Torque 3D. In fact, you do not need to know C++ at all. Using TorqueScript and the collection of tools that are included with Torque 3D, you can build complete games (of many different genres) without ever touching a single line of C++ code.
To understand the basics of how the engine is setup and the tools available, a short reference is included below. Further sections in the documentation explain these tools in more depth.
OS: Windows 7, MacOS Catalina, Ubuntu LTS or equivalent Processor: 1.6 GHz Processor or better Memory: 3GB RAM Graphics: DirectX 11+ or OpenGL 4.3 supported Hard Drive: 3GB free disk space (less for binary only solutions)
The engine handles all of the elements of a game that run in real time on your computer. The Torque 3D engine is written entirely in C++ and is fully accessible to you as a developer. This means you have access to the inner workings of the code to customize it for your needs. The end result is that Torque 3D allows developers to add functionality, increase optimization, and learn how everything works. Alternatively, you can build a game from scratch to release without delving into the source code. The choice of how to develop your game is up to you.
For example, if you wish to add MYSQL database functionality or integrate the Havok SDK to enhance your game, those paths are open to you. Another benefit of source code access is the ability to read through the comments and data structures to gain a better understanding of how the entire system is set up.
Do not be intimidated. This documentation will show you how to create games without touching the source code at all. There is no need to start working with the engine's C++ code until you feel comfortable. In the meantime, you can get going with Torque 3D right away!
The first place to start using Torque 3D is the Project manager. This is the main application that downloads Torque3D and launches Torque Projects. The Project Manager is the central hub of T3D game development.
The Project Manager allows you to download existing Torque engines from the official repositories, or you can add your own fork or local folder as the engine build.
One important part of the Project Manager is to Add or download Torque modules, which can be as large as full game templates and as small as a small graphics asset pack.
This allows you to create new projects based on Templates and Modules, which may also come in the form of Genre Kits. From inside the Project Manager, you can launch the demos that can be downloaded with the engine. The Project Manager also provides a direct link to access the documentation included with the engine.
Much of your game play logic, camera controls, and user interface will be written in TorqueScript. It is a powerful and flexible scripting language with syntax similar to C++. The key benefit of TorqueScript is that you do not need to be a code guru or know the nitty-gritty specifics of a particular language like C++. If you are already familiar with basic programming concepts, you will have a head start on building your own game.
Another benefit of using TorqueScript, as opposed to editing the engine's underlying C++ source code, is that you do not have to recompile your executable to see changes in your game. You simply create or modify a script, save, and then run the game from the Toolbox.
There are several TorqueScript articles for new developers that will help you learn the syntax, functionality, and how to use the language with the engine and editors.
Learning to work with Torque 3D editors is a large part of your initial experience. The key is to remember that the editors work in real-time and are WYSIWYG (What You See Is What You Get). When you use the editors to modify your level, you will see the changes immediately in the game.
World Editor - The World Editor is a tool that will help you assemble your game levels. With this tool, you will add and position terrain, game objects, models, environmental effects, lighting, and more.
GUI Editor - GUI stands for Graphical User Interface. Some examples of GUIs include: splash screens, your main menu, options dialogs and in game Heads Up Displays ("HUDs"). With the GUI Editor, you can design and create your menus, player inventory system, health bars, loading screens, and so on.
You would not have much of a game without models, textures, and other art assets. For Torque 3D, one of the preferred file format for 3D art assets is COLLADA, however Torque use the Open Asset Import Library so other formats such as FBX also work, many other formats have been less tested but many work for simple models quickly and easily.
For those of you familiar with previous Torque engines, you can still import DTS (static models) and DSQ (animation data) files for your 3D objects. This includes static shapes, players, buildings, and props. If you already have a library of DTS and DSQs, feel free to use them in Torque 3D. From this point on however we recommend you transition to the new formats for new art assets going forward.
Now that you have read though this article, you are familiar with some of the most important aspects of Torque 3D. As you familiarize yourself with Torque 3D, you may also want to take a look at the various Torque add-ons and community resources available on our site.
The Torque Project Manager, or Project Manager, or PM, is a simple utility application built in Torque3D to help you manage your projects.
It does this by letting you manage builds of the engine, optional modules that can be installed in your projects, and the projects themselves. By default, you can point it at any engine builds, modules and projects you have on your computer's harddrive.
If you have git installed, it can download and update engine builds and modules from the internet from a curated list, and if you have cmake installed, you can utilize source code builds of the engine to generate new projects instead of needing to only utilize precompiled binaries.
Naturally, the first step in working with Torque and the Project Manager is to download the PM. Fortunately it's easy to get. You can acquire a copy from the releases on the github repository for your respective platform here:
Once it's been downloaded, you can place it wherever you feel most comfortable on your machine. We would generally recommend having a sort of "gamedev" folder for organizing all your game development stuff, but ultimately what's most important is you putting it somewhere that works for you.
Once it's been installed, you can get cracking utilizing it immediately, but to maximize it's efficacy, we'll want to do some prepwork on your machine to make it a fully functional development environment
While this sounds intense, really it's just installing a few common programs that help you get and use builds of the engine, namely, git and cmake.
The Project Manager utilizes git for cloning and pulling from online repositories to your local machine, and uses CMake for generating Source projects. While not strictly required, lacking either or both of these will drastically limit the functionality of the Project Manager.
You can learn more about installing each of these here:
GitCmakeOnce you have these downloaded and installed, that's good enough for running the Project Manager, and you can continue below.
Once you launch the Torque Project Manager, you'll find a view like this:
While generally simple to navigate, we can do a quick go-over of the layout.
On the left side, at the top, you'll find the navigation 'breadcrumbs'. It'll show you what page you're on and the navigation stack if you're in sub-pages.
Below that is the primary navigation panel. The buttons are largely self explanatory, allowing you to quickly move page-to-page to let you get your work done.
To the right is the main panel, which will show the primary content of whatever page you're on. In the above screenshot, we're on the Engine Builds page.
Above that are the Action Buttons, which are contextual to the page you're on, as well as a search bar for filtering contents of the main panel.
Engine Builds are, as the name suggests for builds of the engine. To create projects, you must have a build of the engine to copy from. There are several builds listed by default which are pulled from the Torque3D website. You can also add new Engine Builds to the listing from git URLs or local directories on your computer.
There are two 'types' of Engine Builds:
Denoted by the Source tag, these are Engine Builds that have the full source code with them. To utilize these you'll need Cmake and do the full generation and compile process.
Denoted by the Binary tag, these utilize precompiled binary files, and do not provide the source code. While these are less flexible, there are no additional setup steps needed. You can just create a project with them and immediately launch into the application and begin working.
By default, Engine Builds download to the /EngineBuilds/ directory in the Project Manager's folder. You can change the default download target in the Settings page.
Once you have a Engine Build downloaded, you can create a Project, but first we'll stop over in the Modules page.
For a full explination of what Modules(and the Assets they contain) are, you can check the Modules section of the documentation. But for the purposes of the Project Manager, Modules are self-contained chunks of content and code that are easily installed and managed for your projects.
Like Engine Builds, there are a number of default modules that are provided from the Torque3D website the Manager fetches info for. You can download any or all of them, as well as add new ones from local directories or git repositories.
Also like Engine Builds, they are by default downloaded to /Modules/ but this can be changed in the Settings.
Once you have downloaded modules, they are "Available", which will be important for when we go to make a project.
A project is, ultimately, your game. When creating a new one, you'll not only define the name and destination, but the Engine Build as well. If the build is a Source build, then you'll have additional prompts for for the Generator(what IDE/code platform Cmake uses to generate) as well as various Cmake flags.
Normally you can leave the flags as-is, but they do provide additional features and functions.
Likewise, if you've installed any Modules, you'll see a list of Available ones as well. While you can, at any time, install new Modules to an existing Project, you can quickly get a Project up to speed during creation by selecting some modules here. They will be installed as part of the setup process, making getting your game rolling even faster.
Get familiarised with Torque3D by following a step-by-step guide to create a coin collection game.
To me there is no better way of learning something than to throw yourself into it and get dirty. So we will start right away with the first project. I will not go in depth with how the editors works in this tutorial but I will link you to places where you can get help to a specific task.
The goal of this task is to teach you all of the parts that goes into setting up a really simple gameplay loop. The resulting game will be a very simple multiplayer coin-collecting game where the player who collects the most coins will win:
This guide will cover scripting and logic, not the editors and how to work with Torque3D in general. It’s assumed that you:
Are able to run Torque3D
Are able to create a new empty level
Have familiarized yourself with the editors to some degree
Please read Introduction To The Engine in order to get a quick overview of the engine and getting your development environment setup.
So for a start I will ask you to create an empty project based on the basegame template. If you don’t know how to, take a look at this guide. Now enter the game, press F11 to enter the editor and play around with the terrain editing tools. Launching the Game covers these topics
This guide does not focus on the editors, so if you can’t figure out how to create a terrain, you should seek information somewhere else.
Torque is a game engine, it is not based on graphical drag ‘n’ drop elements like Unity thus it is not as easy to get into and understand. There is no ‘make game button’ in Torque; you need to have an understanding of how to code, so if you are an absolute beginner at programming and have never written even a simple program then this might not be the right guide to start with.
Apart from the advanced deferred rendering model and the physics and all the other great stuff Torque can ‘do’. What you are thinking of here is more likely what can you do if you load up the engine and start walking around? Actually, T3D has a lot of gameplay features out of the box. You can try the FPS modules and you will be able to run around, shoot, throw mines etc without making a single change to the engine. There is a lot of FPS features built into the engine as well, including multiplayer support! So if you want to make a FPS you can probably (at first) treat the development as modding a game.
TorqueScript (TS) is a C-like language. It is very basic. There are no ‘types’ in TorqueScript, everything is handled as strings or ints. One of the most interesting things about scripting in TS is that it is event driven. The engine runs the game and sends the necessary callbacks to the script interface which in turn reacts to the events and vice versa.
A good way to think about it is that you'd probably create a Projectile
class in C++ and from there you'd control it's trajectory, detect collisions, render the mesh etc.
However, the creation of the projectile and figuring out what to do when it collides is handled quite well by script.
Nothing special is necessary in order to script with Torque3D, if the engine is running you should be good to go. However you might want an IDE for scripting, I suggest taking a look at either Torsion or IntelliJ Community with the TorqueScript plugin.
Modules were introduced in Torque3D 4.0, by using modules you can easily isolate your changes in a dedicated package. Module system also gives you a nice way of load/unloading packages of scripts and distribute it for others to use.
Before we can begin writing our game scripts, we need to set up a module. The process is simple, create a new folder data/CoinCollection
and inside that folder add two files.
data/CoinCollection/CoinCollection.module
<ModuleDefinition
ModuleId="CoinCollection"
VersionId="1"
Description="Starter module for CoinCollection gameplay."
scriptFile="CoinCollection"
CreateFunction="onCreate"
DestroyFunction="onDestroy"
Group="Game"
Dependencies="UI=1">
<!-- UI dependency is needed for the Scoreboard later on -->
<DeclaredAssets
canSave="true"
canSaveDynamicFields="true"
Extension="asset.taml"
Recurse="true" />
</ModuleDefinition>
Most of this, you don’t need to concern yourself with at this moment. It’s mainly metadata about the module. The most significant pieces right now is that the Group
is set to Game
, this means that it will be automatically by our main.tscript
file, the game’s entrypoinnt.
Furthermore, the scriptFile
, DestroyFunction
and CreateFunction
specify how our module is initialized. Let’s go ahead and add this file now:
data/CoinCollection/CoinCollection.tscript
/// Module life-cycle
function CoinCollection::onCreate(%this) {
}
function CoinCollection::onDestroy(%this) {
}
/// Server life-cycle
function CoinCollection::initServer(%this) {
}
function CoinCollection::onCreateGameServer(%this) {
}
function CoinCollection::onDestroyGameServer(%this) {
}
/// Client life-cycle
function CoinCollection::initClient(%this) {
}
function CoinCollection::onCreateClientConnection(%this) {
}
function CoinCollection::onDestroyClientConnection(%this) {
}
This is all the life-cycle hooks we get for our module, the Module life-cycle hooks are general for all modules, while the Server and Client life-cycle hooks are specific for Game
modules.
That is actually the basis of creating a module, the next thing we will look at is how to create a specific gamemode and tie it into a level.
A gamemode is a feature provided by the core
modules, as part of the normal level load and initialization process. It means you can attach a game mode to specific levels and then whenever you load that level, the gamemode will be activated.
Before you dive into this part of the tutorial, make sure to create an empty level in the CoinCollection module. Open the World Editor, click on File
in the top-left toolbar and choose New Level
then click Save Level
and make sure to place it in our CoinCollection module like this:
We need to be able to initialise the game mode, create a new file in data/CoinCollection/server/gamemode.tscript
with the following contents:
function CoinCollectionGameMode::onCreateGame() {
// Note: The Game object will be cleaned up by MissionCleanup.
// Therefore its lifetime is limited to that of the mission.
new ScriptObject(CoinCollectionGameMode) {
};
return CoinCollectionGameMode;
}
This is a static method and it is called from the core
scripts.
Add the following piece of code to the end of gamemode.tscript
:
function CoinCollectionGameMode::onMissionStart(%this) {
echo("CoinCollection mission has been loaded");
}
This does what it says on the tin, it's a method on the CoinCollectionGameMode
object that is triggered when the mission starts, after the mission finish loading.
Since we added a new script file, we'll need to execute it, in the file data/CoinCollection/CoinCollection.tscript
, change the function initServer
to the following:
function CoinCollection::initServer(%this) {
%this.queueExec("./server/gamemode.tscript");
}
Now, we need to associate our gamemode with the level. First select the scene object in the scene tree:
Then set the gameModeName of the scene object to CoinCollectionGameMode
:
Remember to save your level.
Finally, go back to the main menu, click Single Player
, choose your level and run it. Then look in the Console (tilde on US-layouts, for me it's the ½ key), and see if the message "CoinCollection mission has been loaded" is printed.
If it is, then awesome! Your gamemode is working! However, it's a rather boring game, you can't really move around in the game or do anything really.
In Torque3D we call the object that you are moving when you press keys the ControlObject
and the Player
is one instance of such a ControlObject. So, let's define a PlayerData
datablock, place the following in the file data/CoinCollection/datablocks/player.tscript
:
datablock PlayerData( CoinCollectorPlayer ) {
// Third person shape
ShapeAsset = "Prototyping:Playerbot_shape";
// Set distance from camera to player
cameraMaxDist = 3.0;
};
datablock
this is very similar to a struct, basically in a datablock you define a set of default values which will get referenced by the spawned objects upon creation.
PlayerData(
CoinCollectorPlayer )
here we state that we want to create a datablock of the type PlayerData, for creating new Players. We call this new datablock CoinCollectorPlayer .
ShapeAsset
here it is a reference to the asset Playerbot_shape
in the Prototyping module. But it could be set to any ShapeAsset in any module. We'll cover assets later in the tutorial.
cameraMaxDist
defines the maximum distance from the Player shape to the Camera
this will essentially allow us to zoom out a bit.
And we need to register this datablock, do this in the onCreateGameServer
function in data/CoinCollection/CoinCollection.tscript
:
function CoinCollection::onCreateGameServer(%this) {
%this.registerDatablock("./datablocks/player.tscript");
}
Now we have a PlayerData
that we can use, but in order to actually use it, we have to create a Player
instance whenever a player enters the game. We do that in data/CoinCollection/server/gamemode.tscript
, first let's create a helper method that creates the Player
using the CoinCollectorPlayer
datablock and assigns it as the client's Control Object:
function CoinCollectionGameMode::spawnControlObject(%this, %client) {
// First spawn the actual Player object
%player = spawnObject(Player, CoinCollectorPlayer);
if (!isObject(%player)) {
return;
}
MissionCleanup.add(%player);
// Place it at the center of the world with a default rotation,
// this is a pretty simple "spawn placement"
%spawnTransform = "0 0 1 0 0 0 0 0";
%player.setTransform(%spawnTransform);
// Couple the player to the client and set it as the control object
%player.client = %client;
%client.setControlObject(%player);
%client.player = %player;
// Tell the client that we expect it to be in third person
%client.setFirstPerson(false);
}
Now that's just a helper method, in order to actually activate it we should call it from the onClientEnterGame
function that we will add in that same file:
function CoinCollectionGameMode::onClientEnterGame(%this, %client) {
// Set the player name based on the client's connection data
%client.setPlayerName(%client.connectData);
// Call the helper function
%this.spawnControlObject(%client);
}
And let's make sure to delete the player object when they leave:
function CoinCollectionGameMode::onClientLeaveGame(%this, %client) {
// Remove the player object
%client.player.delete();
}
Now, run the level again and see that you can move around and jump with your newly created Player
object!
Let's create some coins that we can pick up!
First we need a datablock for the Coin objects, we'll use a simple StaticShape
type of objects, create the file data/CoinCollection/datablocks/coin.tscript
with the following contents:
datablock StaticShapeData( Coin ) {
ShapeAsset = "Prototyping:TorusPrimitive_shape";
category = "CoinCollectionObjects";
};
And as usual, remember to register the datablock in data/CoinCollection/CoinCollection.tscript
:
function CoinCollection::onCreateGameServer(%this) {
%this.registerDatablock("./datablocks/coin.tscript");
%this.registerDatablock("./datablocks/player.tscript");
}
Now open the Level Editor, and place a few coins, you do that by opening the Asset Editor
And then drag in the Datablock
called "coin" (inside data/CoinCollection/datablocks
) into the 3d scene window:
The Coins will show up in the Scene Tree, group them inside a SimGroup
called Coins
, right click the level object and select Add SimGroup
:
And then just drag-and-drop the
StaticShape
objects into that folder:
A SimGroup
is a collection of objects. If you delete a Simgroup
all objects inside it will be deleted as well.
We want our coins to have some logic, namely we want them to get picked up when the player runs into them. Let's create file called data/CoinCollection/server/coin.tscript
and put the following function inside it:
function Coin::onCollision(%this, %obj, %col, %vec, %len) {
%obj.delete();
}
Now what can we make of this? For all static shapes that are using the datablock Coin, hence all our Coin objects, we define a function for the onCollision callback. The engine calls this callback when two objects collide. The parameters it gets is:
%this
refers to the datablock.
%obj
refers to the coin object.
%col
refers to the object colliding with the coin.
%vec
is the inverse direction of the impact vector, which tells you the direction of the impact itself.
%len
is the length of the impact vector, hence the force of the impact.
When an object collides with the coin, it deletes itself. That was pretty easy huh? This is one of the benefits of an event driven language, it can be incredibly easy to create something cool!
And let's exec it in initServer
in the data/CoinCollection/CoinCollection.tscript
file:
function CoinCollection::initServer(%this) {
%this.queueExec("./server/coin.tscript");
%this.queueExec("./server/gamemode.tscript");
}
Now run the level again and check that the coins disappear when the Player
touches them
Our game wouldn't be particularly interesting if we couldn't win it. Let's make it so that when all coins are picked up we tell the player it has won.
Since we gathered all of our coins inside the SimGroup
called Coins
we can check if there's any left after a coin has been picked and if not tell the client they have won.
Implement this logic in the onCollision
callback in the file data/CoinCollection/server/coin.tscript:
function Coin::onCollision(%this, %obj, %col, %vec, %len) {
%obj.delete();
if (Coins.getCount() <= 0) {
commandToClient(%col.client, 'ShowVictory');
}
}
Do you remember that we set the client
variable on the Player object when we spawned it in spawnControlObject
? We had the line %player.client = %client
which we can use now to get the client from the player (%col
) object.
So what's happening here? if (Coins.getCount() <=0)
, if there are no more coins commandToClient(%col.client, 'ShowVictory')
instruct the client to show the victory screen. Please read Client and Server Commandsfor more information about the commandToClient
system, but the gist of it is we want to call the command 'ShowVictory'
on the %col.client
client. The 'ShowVictory'
is not a regular string, it is a "tag" and writing "ShowVictory"
instead won't work. Tag's are essentially strings that are stored in a networked database with an ID such that we don't have to send the full "ShowVictory"
string to the client but instead can send e.g. 42
.
Now we need to add our first client-side script! Create a file in a new client
folder called data/CoinCollection/client/commands.tscript
with the contents:
function clientCmdShowVictory()
{
MessageBoxOK("You Win!",
"Congratulations you found all the coins!",
"disconnect();" );
}
We indicate that it's a network-command by prefixing it with clientCmd
and then all it does is it shows a message box and when the player clicks OK we will run disconnect();
which will end the game.
There is no requirement that all server-side scripts are placed in the server
folder and all client-side scripts are placed in the client
folder. So why make the distinction?
Well in Torque3D, the server and client are actually completely separate instances so it helps to keep an overview if we split the scripts into different folders as well. If you want to release a multiplayer game in the future, you might want to avoid delivering the server scripts to your players because you don't want them create private servers. In this case you can simply delete the server
folder before zip'ing and sending the file to your players.
Also, since it's completely separate instances it helps keep an overview of what objects you have created on the server on what objects you created on the client. It's a very common source of mistakes that developers try to access server objects from the client and vice versa.
Let's say you have a model, that has been prepared for Torque, and some textures and now you want to use that instead of the boring torus primitive.
We will do a step-by step of how to import these files first download this zip file:
And extract it into data/CoinCollection/objects/korkCoin
such that you get the following four files inside that directory:
data/CoinCollection/objects/korkCoin
korkCoin.fbx
korkCoin_albedo.png
korkCoin_n.png
korkCoin_orm.png
Then open up the World Editor and find the Asset Browser:
Navigate to
data/CoinCollection/objects/korkCoin
and click on the exclamation mark:
This will load all the files in as separate assets:
Now we need to tie them together, right-click the material asset and click on
Edit Asset
In the Material Editor, set the Diffuse Map
to the albedo image asset, the Normal Map
to the normal image asset and the ORM Map
to the orm image asset.
Then click the save button, and confirm that everything looks right by dragging a "korkCoin_shape" asset into the scene.
Finally, open up data/CoinCollection/datablocks/coin.tscript
and change the ShapeAsset
of your Coin datablock to this newly imported shape:
datablock StaticShapeData( Coin ) {
ShapeAsset = "CoinCollection:korkCoin_shape";
category = "CoinCollectionObjects";
};
The korkCoin.fbx
file has a simple animation built in. It simply rotates the coin around once. Let's play this on our coins. The animation is called korkCoin|ambient
.
First open up data/CoinCollection/objects/korkCoin/korkCoin.tscript
and add the following function to the end of the file:
function korkCoinfbx::onLoad(%this)
{
%this.setSequenceCyclic("korkCoin|ambient", "1");
}
This will make sure that our animation plays on a loop.
Now we need to play this animation on all coins that are spawned, we can do that on the onAdd
callback for each Coin
in data/CoinCollection/server/coin.tscript
:
function Coin::onAdd(%this, %obj) {
%obj.playThread( 0, "korkCoin|ambient" );
}
Remember here that Coin
is the datablock, so the second parameter %obj
is the actual Coin instance itself.
If we want the game to be a bit competitive, we need a scoring system. In a coin collection game, it makes sense that whoever picks up the most coins wins. Let's count how many coins we have picked up!
In data/CoinCollection/server/coin.tscript
first add a global variable that counts the number of coins we've found at the top of the file:
$CoinsFound = 0;
And then increment that number in the onCollision
callback:
function Coin::onCollision(%this, %obj, %col, %vec, %len) {
%obj.delete();
$CoinsFound++;
if (Coins.getCount() <= 0) {
commandToClient(%col.client, 'ShowVictory');
}
}
And finally edit data/CoinCollection/client/commands.tscript
to show the number of coins found in the message box using the $CoinsFound
global:
function clientCmdShowVictory()
{
MessageBoxOK("You Win!",
"Congratulation you found" SPC $CoinsFound SPC "coins!",
"disconnect();" );
}
The easiest way to make the game POP is to add some particle effects when we pick up the coins. Let's add the basic skeleton of a particle effect to the data/CoinCollection/datablocks/coin.tscript
file:
datablock ParticleData(CoinParticle : DefaultParticle)
{
};
datablock ParticleEmitterData(CoinEmitter : DefaultEmitter)
{
particles = CoinParticle;
};
datablock ParticleEmitterNodeData(CoinNode : DefaultEmitterNodeData)
{
timeMultiple = 1.0;
};
As you can see we define two new datablocks in this file, a ParticleEmitterDatablock
for creating a new particle emitter. Particle emitters does not have a place in the world by themselves tho, they only emit particles they need a node to know where to emit particles from. Therefore we need a datablock for a particle emitter node aswell. What you probably will notice here is when we define the name of the datablocks, we write a colon and then another name. What does this mean?
This means that our new datablock, inherits values from another datablock. It makes a copy of the other datablock and lets you edit the values which will only affect the new datablock.
Another thing that is important to note, is that CoinEmitter
references CoinParticle
. Which is why it is important that CoinParticle
is defined before CoinEmitter
.
Lets put these new datablocks to good use. We want some visual feedback to tell us that we have picked up a coin.
To spawn a new Emitter we will use the new
operator. It works like this:
%emitterNode = new ParticleEmitterNode(){
datablock = CoinNode;
emitter = CoinEmitter;
};
Remember it is the node not emitter we want to spawn, then we set the emitter inside the “initialiser”. (What i call the initialiser is the variable definitions inside the two brackets { and }.)
This is where we define what datablock to use, the emitter and anything else we want to do with the newly created object.
We need to give this new object a position in the world. To get the position of an object you would call
%obj.getPosition();
And to set the position of an object you would assign it, like this
%obj.position = "x y z";
So now, let's utilise this to spawn emitters when we pickup coins, in data/CoinCollection/server/coin.tscript
add the instancing to the onCollision
callback:
function Coin::onCollision(%this, %obj, %col, %vec, %len) {
%emitterNode = new ParticleEmitterNode(){
datablock = CoinNode;
emitter = CoinEmitter;
position = %obj.getPosition();
};
%obj.delete();
$CoinsFound++;
if (Coins.getCount() <= 0) {
commandToClient(%col.client, 'ShowVictory', $CoinsFound);
}
}
If you run into a couple of Coins, and it is all working properly, then if you open the world editor you will notice that the emitters is still there even tho they stopped emitting particles (given that you gave the ParticleEmitter
a lifetime) if you didn’t you will see that they keep emitting particles.
We want to fix that! So I will introduce you to a very important feature in TorqueScript: schedules.
You can use a schedule to delete the emitter after some time.
The schedule syntax is:
%obj.schedule(int timeMS, string method, string args...);
Or if you are not calling it on an object:
schedule(int timeMS, int objectID, string method, string args...);
We can use this to delete the emitter after we spawn it:
%emitterNode = new ParticleEmitterNode(){
datablock = CoinNode;
emitter = CoinEmitter;
position = obj.getPosition();
};
%emitterNode.schedule(200, "delete");
Let's start by filling out the ParticleData
datablock
datablock ParticleData(CoinParticle : DefaultParticle)
{
lifetimeMS = 1000;
gravityCoefficient = 0;
dragCoefficient = "2";
sizes[0] = 1;
sizes[1] = 1;
sizes[2] = 1;
sizes[3] = 1;
};
The particles is the billboards we are emitting, these are all cosmetic values, I won't dive into them here.
datablock ParticleEmitterData(CoinEmitter : DefaultEmitter)
{
particles = CoinParticle;
ejectionPeriodMS = 10;
ejectionVelocity = 4.167;
ejectionOffset = 0.625;
thetaMax = 180;
softnessDistance = 1;
};
In this tutorial, I have deliberately made some pit-falls that I have seen new developers falling in which prevents multiplayer gameplay from working.
So let's clean up in this mess, the first thing we want to address is the $CoinsFound
global variable. We set it in the callback in data/CoinCollection/server/coin.tscript
so how can we just use it directly in data/CoinCollection/client/commands.tscript
? When we play in single-player mode the player and the host is the same process, this means we can use the global variable $CoinsFound
in both client and server simultaneous. However this is an anti-pattern because this won't work for other clients in a multi-player scenario.
We can fix this using dynamic variables. TorqueScript has something called dynamic variables which is a very simple but very smart concept. Basically you can define any variable on any object by assigning it a value.
%obj.somedynVar = 2;
echo(%obj.somedynVar); //outputs "2"
%obj.TSisSpecial = "Is it now?";
echo(%obj.TSisSpecial); //outputs "Is it now?"
echo(%obj.tsisspecial); //outputs "Is it now?"
//(TorqueScript is not case sensitive either by default..)
We can use this to keep track on how many coins each client has picked up!
Remove the $CoinsFound
global, and change the onCollision
callback by adding %col.client.coinsFound++;
instead in data/CoinCollection/server/coin.tscript
so it looks like this:
function Coin::onCollision(%this, %obj, %col, %vec, %len) {
%emitterNode = new ParticleEmitterNode(){
datablock = CoinNode;
emitter = CoinEmitter;
position = %obj.getPosition();
};
%obj.delete();
%col.client.coinsFound++; // Automatically starts at 0
if (Coins.getCount() <= 0) {
commandToClient(%col.client, 'ShowVictory', %col.client.coinsFound);
}
}
However, there is still an issue here. We are currently showing the player that picks up the last coin that they won. We should show the one with most coins that they won and all others should be told they've lost. We can solve that by looping over the ClientGroup
SimGroup. The ClientGroup is a collection of all the clients who have joined the game.
So change the onCollision
callback to the following:
function Coin::onCollision(%this, %obj, %col, %vec, %len) {
%emitterNode = new ParticleEmitterNode(){
datablock = CoinNode;
emitter = CoinEmitter;
position = %obj.getPosition();
};
%emitterNode.schedule(200, "delete");
%obj.delete();
%col.client.coinsFound++; // Automatically starts at 0
if(Coins.getCount() <= 0)
{
%winnerClient = %col.client;
foreach(%idxClient in ClientGroup)
{
// If we are looking at the current winner, skip forward
if (%idxClient == %winnerClient) {
continue;
}
// If the current client has more coins than the current winner
if(%idxClient.coinsfound > %winnerClient.coinsfound) {
// The current winner has lost
commandToClient(%winnerClient, 'ShowDefeat', %winnerClient.coinsfound);
// All hail the new winnner
%winnerClient = %idxClient;
} else {
// Current client has lost, winner stays the same
commandToClient(%idxClient, 'ShowDefeat', %idxClient.coinsfound);
}
}
// %winnerClient has the highest number of coins!
commandToClient(%winnerClient,
'ShowVictory', %winnerClient.coinsFound);
}
}
Now the last thing we need to do is to change the data/CoinCollection/client/commands.tscript
file, first of all we want to add a %score
parameter to the clientCmdShowVictory
function:
function clientCmdShowVictory(%score) {
MessageBoxOK("You Win!",
"Congratulation you found" SPC %score SPC "coins!",
"disconnect();" );
}
And then we need to add another function for when we lose:
function clientCmdShowDefeat(%score)
{
MessageBoxOK("You Lost!",
"You lost with" SPC %score SPC "coins",
"disconnect();" );
}
Now your first multiplayer game should actually be working! Try opening two instances of Torque, in one of the instances you press “play” then you tick the “host” check box to the left of the Go
button. In the other instance you press join
, "Query LAN"
select the server that comes forth and join the game. Now you can compete with yourself about collecting most coins! Even better, you can host a LAN and let all your friends play your coin collection game with you! Give it a cool name and brag about it a little!
When creating objects we are able to define an initialiser. This initialiser has an interesting feature. If you were to create an object like a SimGroup
, which contains more objects you could do this:
%obj = new SimGroup(){};
%obj.addObject(new SimObject(){});
%obj.addObject(new SimObject(){});
//etc..
But the constructor allows us to instantiate the child objects inside the constructor:
%obj = new SimGroup(theGroup){
new SimObject(){};
new SimObject(){};
};
We often utilize this feature when writing new .gui files:
%guiContent = new GuiControl(ScoreBoardGui){
new GuiBitmapBorderControl(){
new GuiBitmapControl(){
};
};
};
This code will create a new control with a bitmap border inside, and a bitmap inside the border.
I prefer writing GUIs in script because the editor feels a bit clumsy to me. Let's start by creating the baseline GUI file in data/CoinCollection/client/gui/scoreBoard.gui
:
new GuiControl(ScoreBoardGUI) {
position = "0 0";
extent = "1024 768";
profile = "GuiModelessDialogProfile";
tooltipProfile = "GuiToolTipProfile";
isContainer = "1";
canSaveDynamicFields = "1";
enabled = "1";
noCursor = "1";
};
This is a simple control that basically fills the whole screen (starts at top left corner, scales down to the top right corner and it is anchored to the right and bottom sides).
Now we'll add the content inside of it piece by piece.
Now we will need to center the content inside the ScoreBoardGUI
so it is centered on the screen. Add this to the GuiControl
ScoreBoardGUI
, (Remember how we did it? Read “Objects and childobjects again.").
new GuiPanel() {
docking = "None";
position = "370 271";
extent = "283 226";
horizSizing = "center";
vertSizing = "height";
profile = "ScoreBoardProfile";
tooltipProfile = "GuiToolTipProfile";
};
This creates a new panel in the center of the screen. Extent means the size of the panel. This panel is 283px
wide and 226px
tall.
We make sure it is centered by letting position be (screenwidth/2)-(extent/2)
. In this case it is (1024/2)-(283/2)
, (Likewise for height).
We set vertSizing
to height
, which means that it will follow the height of the screen and thus scale vertically.
We set horizSizing
to center
, so that it wont scale horizontally. This is because a horizontal scaling would corrupt the design of the scoreboard.
We will be using a GuiTextListCtrl
to list the players. We can consider it like a table. Since every new Text
in the list is a row, and we can specify columns by tabs.
Therefore we need some headers for the values “Coins, Kills, Deaths” (yes we will add in some ‘kill each other’ feature in a later tutorial).
So put this inside the GuiPanel you just created:
new GuiTextCtrl() {
text = "Coins";
maxLength = "255";
position = "104 2";
extent = "33 18";
profile = "ScoreBoardTextBoldProfile";
tooltipProfile = "GuiToolTipProfile";
};
new GuiTextCtrl() {
text = "Kills";
maxLength = "255";
position = "158 2";
extent = "30 18";
profile = "ScoreBoardTextBoldProfile";
tooltipProfile = "GuiToolTipProfile";
};
new GuiTextCtrl() {
text = "Deaths";
maxLength = "255";
position = "206 2";
extent = "37 18";
profile = "ScoreBoardTextBoldProfile";
tooltipProfile = "GuiToolTipProfile";
};
As you can see the position value is not very high on these elements, that’s because their parent is the GuiPanel
so their position is relative to the panel!
If alot of players is joining, we will need some scrollbars. For this we need a GuiScrollCtrl
placed inside of the GuiPanel
.
new GuiScrollCtrl() {
willFirstRespond = "1";
hScrollBar = "alwaysOff";
vScrollBar = "dynamic";
lockHorizScroll = "1";
lockVertScroll = "0";
constantThumbHeight = "0";
childMargin = "0 0";
mouseWheelScrollSpeed = "-1";
position = "0 24";
extent = "228 202";
horizSizing = "width";
vertSizing = "height";
profile = "ScoreBoardScrollProfile";
tooltipProfile = "GuiToolTipProfile";
isContainer = "1";
};
As you might be able to see, we don’t want a horizontal scrollbar so it is always off (hScrollBar = "alwaysOff"
) and the vertical scrollbar only shows if it is necessary (vScrollBar = "dynamic"
) beside from that, all these settings should be fairly straight forward.
Now last but not least we need the aforementioned GuiTextListCtrl
placed inside the GuiScrollCtrl
:
new GuiTextListCtrl(ScoreBoardGUIList) {
columns = "0 98 153 200";
fitParentWidth = "1";
clipColumnText = "0";
position = "0 0";
extent = "228 8";
horizSizing = "width";
vertSizing = "height";
profile = "ScoreBoardTextNormalProfile";
tooltipProfile = "GuiToolTipProfile";
isContainer = "1";
};
The important things to note here is the columns
attribute, the fitParentWidth
attribute and the clipColumnText
attribute.
columns
specifies where the columns will be (on the x-axis relative to the GuiTextListCtrl
). As you might have noticed this matches the positions of the GuiText
controls!
fitParentWidth
this makes the TextListCtrl
fill the scroll horizontally.
clipColumnText
this makes sure that the columns don’t break or overwrite each other. If the string in this column is longer than the column it will be cut out.
When you are done your structure for the GUI should look something like this:
GuiControl
“ScoreboardGUI”
GuiPanel
GuiTextCtrl
“Coins”
GuiTextCtrl
“Kills”
GuiTextCtrl
“Deaths”
GuiScrollCtrl
GuiTextListCtrl
“ScoreBoardGUIList”
Here is one thing that you may have noticed and that I haven’t explained!
The profiles! The profile is to GUI objects what CSS is to HTML. They define the style of the GUI’s
I wont spend a lot of time with the profiles even tho they are quite important. Therefore we will use alot of the stock profiles and only create a single custom one.
In data/CoinCollection/client/gui/customProfiles.cs
add the following snippet:
singleton GuiControlProfile(ScoreBoardProfile : GuiDefaultProfile) {
opaque = "1";
fillColor = "0 0 0 200";
fillColorHL = "0 0 0 200";
borderColor = "0 0 0 255";
borderThickness = "5";
border = "1";
};
singleton GuiControlProfile(ScoreBoardTextBoldProfile : GuiDefaultProfile) {
fontType = "Arial Bold";
fontColor = "255 255 255 255";
};
singleton GuiControlProfile(ScoreBoardTextNormalProfile : GuiDefaultProfile) {
fontType = "Arial";
fontColor = "255 255 255 255";
};
singleton GuiControlProfile(ScoreBoardScrollProfile : GuiDefaultProfile) {
fontType = "Arial Bold";
fontColor = "255 255 255 255";
};
This should be pretty easy to understand. All controls using the "ScoreBoardProfile" has a black background which is transparent and the border is 5 px wide, black and not transparent.
There is alot more settings that can be played with, for setting text color bevel etc.. This is not within the scope of this tutorial unfortunately!
Now we need to add some functionality to the scoreboard!
First we should be able to see it shouldn’t we?
At the bottom of data/CoinCollection/client/gui/scoreBoard.tscript
add the following code:
//-----------------------------------------------------------------------------
// ScoreBoardGUI utility methods
//-----------------------------------------------------------------------------
function ScoreBoardGUI::toggle(%this)
{
if (%this.isAwake())
Canvas.popDialog(%this);
else
Canvas.pushDialog(%this);
}
function ScoreBoardGUI::clear(%this)
{
// Override to clear the list.
ScoreBoardGUIList.clear();
}
This toggles the ScoreBoardGUI
so a call to ScoreBoardGUI.toggle()
will make it pop up on the screen. If we then call toggle()
again it will hide itself.
Now, this is just a function we need a way to call it. And calling it through the console is quite.. Clumsy.. So lets add a keybinding!
An ActionMap is a way to bind actions to inputs. We can push ActionMaps so that we can change keybindings temporarily and then pop them so we revert to whatever the bindings were previously.
In data/CoinCollection/client/actionMap.tscript
add the following:
if (isObject( CoinCollectionMoveMap ))
CoinCollectionMoveMap.delete();
new ActionMap(CoinCollectionMoveMap);
CoinCollectionMoveMap.humanReadableName = "Coin Collection Move Map";
CoinCollectionMoveMap.bind(keyboard, f, showScoreBoard);
And then add another file in data/CoinCollection/client/inputCommands.tscript
with the showScoreBoard
function:
function showScoreBoard(%val) {
// %val == 1 on key down and 0 on key up
if (%val) {
ScoreBoardGUI.toggle();
}
}
Now, we need to push this ActionMap on top of what keybinds we already have. We can do that in data/CoinCollection/CoinCollection.tscript
, whenever a client connects or disconnects to a server:
function CoinCollection::onCreateClientConnection(%this) {
CoinCollectionMoveMap.push();
}
function CoinCollection::onDestroyClientConnection(%this) {
CoinCollectionMoveMap.pop();
}
Now the final thing is we need to execute all of these scripts we added if you haven't already, in data/CoinCollection/CoinCollection.tscript
:
function CoinCollection::initClient(%this) {
%this.queueExec("./client/gui/customProfiles.tscript");
%this.queueExec("./client/gui/scoreBoard.gui");
%this.queueExec("./client/gui/scoreBoard.tscript");
%this.queueExec("./client/inputCommands.tscript");
%this.queueExec("./client/actionMap.tscript");
%this.queueExec("./client/commands.tscript");
}
In order to update scoreboard we need to do two things:
Write the logic for updating the UI
Adding hooks to trigger this logic where necessary
We want to be able to add/update a player in the scoreboard when they join and remove a player when they leave.
In data/CoinCollection/client/gui/scoreBoard.tscript
add the following section to the bottom:
//-----------------------------------------------------------------------------
// ScoreBoardGUI data handler methods
//-----------------------------------------------------------------------------
function ScoreBoardGUI::upsertPlayer(%this, %clientID, %name, %score, %kills, %deaths) {
%text = StripMLControlChars(%name);
if (%score !$= "null")
%text = setField(%text, 1, %score);
%text = setField(%text, 2, %kills);
%text = setField(%text, 3, %deaths);
// Update or add the player to the control
if (ScoreBoardGUIList.getRowNumById(%clientId) == -1)
ScoreBoardGUIList.addRow(%clientId, %text);
else ScoreBoardGUIList.setRowById(%clientId, %text);
// Sorts by score
ScoreBoardGUIList.sortNumerical(1, false);
ScoreBoardGUIList.clearSelection();
}
function ScoreBoardGUI::removePlayer(%this, %clientId) {
PlayerListGuiList.removeRowById(%clientId);
}
So lets see what this does. The upsertPlayer
function first creates a new variable %text
which stores name, score, kills and deaths with columns seperated by tabs. Then we check if there is already stored a row with that id. If not, then we add a new row else we update the row with that id. Finally we sort the list by column 1 (the second column because it starts at 0).
The removePlayer
function simply removes the row with the player's ID.
In order to trigger these two functions we will use the network message system. Let's add the client-side listeners right away in the top of the scoreBoard.tscript
file:
//-----------------------------------------------------------------------------
// Callbacks
//-----------------------------------------------------------------------------
addMessageCallback('MsgClientWelcome', SBGUIWelcome);
addMessageCallback('MsgClientJoin', SBGUIPlayerJoined);
addMessageCallback('MsgClientDrop', SBGUIPlayerLeft);
addMessageCallback('MsgClientScoreChanged', SBGUIScoreChanged);
function SBGUIWelcome(%msgType, %msgString, %clientName, %clientId,
%isAI, %isAdmin, %isSuperAdmin) {
ScoreBoardGUI.clear();
ScoreBoardGUI.upsertPlayer(%clientId, detag(%clientName), 0, 0, 0);
}
function SBGUIPlayerJoined(%msgType, %msgString, %clientName,
%clientId, %score, %kills,
%deaths, %isAI, %isAdmin, %isSuperAdmin) {
ScoreBoardGUI.upsertPlayer(%clientId, detag(%clientName), %score, %kills, %deaths);
}
function SBGUIPlayerLeft(%msgType, %msgString, %clientName, %clientId) {
ScoreBoardGUI.removePlayer(%clientId);
}
function SBGUIScoreChanged(%msgType, %msgString, %clientName,
%clientId, %score, %kills, %deaths) {
ScoreBoardGUI.upsertPlayer(%clientId, detag(%clientName), %score, %kills, %deaths);
}
We have four different callbacks we need to implement. Let's start with the callback MsgClientScoreChanged
, we will trigger that one whenever we pick up a coin. In data/CoinCollection/server/coin.tscript
add:
messageAll('MsgClientScoreChanged', -1, %col.client.playername,
%col.client, %col.client.coinsFound,
%col.client.kills, %col.client.deaths);
Right after:
%col.client.coinsFound++; // Automatically starts at 0
The three other hooks should happen whenever a client enters or leaves the game. So let's open up data/CoinCollection/gamemode.tscript
and change onClientEnterGame
and add onClientLeaveGame
:
function CoinCollectionGameMode::onClientEnterGame(%this, %client) {
//Set the player name based on the client's connection data
%client.setPlayerName(%client.connectData);
%this.spawnControlObject(%client);
// Welcome the client
messageClient(
%client, 'MsgClientWelcome',
"\c2Welcome to the Torque demo app %1.",
%client.playername,
%client,
%client.isAiControlled()
);
// Inform the client about everyone else
foreach(%other in ClientGroup) {
if (%other == %client) {
continue;
}
messageClient(%client, 'MsgClientJoin', -1,
%other.playername,
%other, %other.coinsFound,
%other.kills, %other.deaths);
}
// Inform everyone else about the client
messageAllExcept(
%client,
"-1",
'MsgClientJoin',
"\c1 % 1 joined the game.",
%client.playername,
%client,
%client.coinsFound,
%client.kills, %client.deaths,
%client.isAiControlled()
);
}
function CoinCollectionGameMode::onClientLeaveGame(%this, %client) {
// Inform everyone that the client left
messageAllExcept(
%client,
"-1",
'MsgClientDrop',
"\c1 % 1 left the game.",
%client.playername,
%client,
%client.isAiControlled()
);
}
One of the major changes is the shift to the module-based BaseGame template as opposed to the preconfigured Full or Empty templates from before. While most changes won't impact a given project unless there was heavy modifications in a wide area of the scripts, some things - such as adopting the module system to help compartmentalize and organize your game's scripts and content - are important.
The big one, as mentioned, is converting your game's scripts and content to a module, or modules, for compartmentalization and organizational purposes.
The easiest way, but doesn't see much of a shift in organization or compartmentalization. The first thing you'll want to do is create a new folder in the data directory of the BaseGame template, calling it something relevent, and convenient. For our example's case, we'll call it MyGame.
Setting up the module
Inside it, you'll want to make 2 files: a <ModuleName>.cs and a <ModuleName>.module. The module file is a TAML file, but generally is XML.
Once those are made, the directory should look like this:
We'll want to make the *.module file to look something like this:
<ModuleDefinition
ModuleId="MyGame"
VersionId="1"
Description="This contains all of my game's scripts and content."
ScriptFile="MyGame.cs"
CreateFunction="onCreate"
DestroyFunction="onDestroy"
Dependencies="clientServer=1,ui=1"
Group="Game">
</ModuleDefinition>
With the MyGame parts and description obviously changed to apply as needed. The script file similarly should be set up like this:
function MyGame::onCreate( %this )
{
}
function MyGame::onDestroy( %this )
{
}
Save the files, and the basics are in place. Important parts to note:
ModuleID is the unique module name
Version ID is the particular version number(which is usually used in dependencies checks)
Description is the description
ScriptFile is the name of the initialization script file
CreateFunction is the function called in our initialization script file when the module is loaded. It's used to set up the common stuff for the module, such as loading datablocks, exec'ing scripts and guis, etc. It uses the ModuleID for the namespace.
DestroyFunction is the function called when we unload the module, used for cleanup. Similarly used the ModuleID namespace.
Dependencies is any modules we need to load before this one so we can use their functionality. It's done as <ModuleID>=<VersionNumber>. For multiple dependencies, it's separated by a comma. In our case, because we'll be loading datablocks and have client/server scripts, we'll want the clientServer module and ui module as dependencies so we can properly load everything up in a multiplayer context.
Group is the group - if any - this module is a part of. This is a convenience feature that allows you to load and unload groups of modules at once automatically. The BaseGame template is designed to automatically load any modules in the Game group during initialization. This can be expanded upon or changed in the main.cs file.
Porting the content to the module
Obviously, we want to move our content over into our new module, so we'll do that now. While you can organize it in any way you want, a way that was done for the FPSGameplay and SpectatorGameplay modules(that replicate the gameplay of the full and empty templates, respectively) is organized like so:
Art, unsurprisingly, would contain your art files - shapes, animations, textures, particles, skies, decals, etc
Levels, naturally, contain the *.mis files and any level-specific files such as the posteffect config, preview image, decals file, forest file and so on.
Scripts contain anything script-based - gameplay scripts, guis, datablocks, etc
Sounds are your sound files.
The FPSGameplay and EmptyGameplay modules structured the scripts folder as such:
client - Any client-side specific scripts
datablocks - Any files that contain your datablocks for all your objects
gui - Any *.gui files
server - Any server-side specific scripts
It should be fairly self explanatory with that, but if you want a good comparison example, you can check the FPSGameplay module to compare, but this organization model should be relatively straightforward.
Ensure that your datablocks, gui files, level files, and script files' various paths have been updated to point to the respective folder inside the data/<ModuleName>/ directory. This ensures that it's properly compartmentalized and contained in the module dir. Any content utilized from other modules should also be paired with adding that module's dependency to the module definition as mentioned above.
Initializing the module's scripts and content
Once you've moved your content over to the module folder, we'll want to initialize everything.
Following the FPSGameplay example - assuming you want to take advantage of the clientServer module's functionality, we'll want to make sure to initialize the client and server content appropriately.
Using the FPSGameplay initialization script file as an example, lets look at it:
function FPSGameplay::create( %this )
{
//server scripts
exec("./scripts/server/aiPlayer.cs");
exec("./scripts/server/camera.cs");
exec("./scripts/server/chat.cs");
exec("./scripts/server/cheetah.cs");
exec("./scripts/server/commands.cs");
exec("./scripts/server/deathMatchGame.cs");
exec("./scripts/server/health.cs");
exec("./scripts/server/inventory.cs");
exec("./scripts/server/item.cs");
exec("./scripts/server/player.cs");
exec("./scripts/server/projectile.cs");
exec("./scripts/server/proximityMine.cs");
exec("./scripts/server/radiusDamage.cs");
exec("./scripts/server/shapeBase.cs");
exec("./scripts/server/spawn.cs");
exec("./scripts/server/teleporter.cs");
exec("./scripts/server/triggers.cs");
exec("./scripts/server/turret.cs");
exec("./scripts/server/vehicle.cs");
exec("./scripts/server/vehicleWheeled.cs");
exec("./scripts/server/VolumetricFog.cs");
exec("./scripts/server/weapon.cs");
//add DBs
if(isObject(DatablockFilesList))
{
for( %file = findFirstFile( "data/FPSGameplay/scripts/datablocks/*.cs.dso" );
%file !$= "";
%file = findNextFile( "data/FPSGameplay/scripts/datablocks/*.cs.dso" ))
{
// Only execute, if we don't have the source file.
%csFileName = getSubStr( %file, 0, strlen( %file ) - 4 );
if( !isFile( %csFileName ) )
DatablockFilesList.add(%csFileName);
}
// Load all source material files.
for( %file = findFirstFile( "data/FPSGameplay/scripts/datablocks/*.cs" );
%file !$= "";
%file = findNextFile( "data/FPSGameplay/scripts/datablocks/*.cs" ))
{
DatablockFilesList.add(%file);
}
}
if(isObject(LevelFilesList))
{
for( %file = findFirstFile( "data/FPSGameplay/levels/*.mis" );
%file !$= "";
%file = findNextFile( "data/FPSGameplay/levels/*.mis" ))
{
LevelFilesList.add(%file);
}
}
if (!$Server::Dedicated)
{
exec("data/FPSGameplay/scripts/client/gameProfiles.cs");
//client scripts
$KeybindPath = "data/FPSGameplay/scripts/client/default.keybinds.cs";
exec($KeybindPath);
%prefPath = getPrefpath();
if(isFile(%prefPath @ "/keybinds.cs"))
exec(%prefPath @ "/keybinds.cs");
exec("data/FPSGameplay/scripts/client/inputCommands.cs");
//guis
exec("./scripts/gui/chatHud.gui");
exec("./scripts/gui/playerList.gui");
exec("./scripts/gui/playGui.gui");
exec("./scripts/gui/playGui.cs");
exec("data/FPSGameplay/scripts/client/message.cs");
exec("data/FPSGameplay/scripts/client/chatHud.cs");
exec("data/FPSGameplay/scripts/client/clientCommands.cs");
exec("data/FPSGameplay/scripts/client/messageHud.cs");
exec("data/FPSGameplay/scripts/client/playerList.cs");
}
}
function FPSGameplay::destroy( %this )
{
}
As we can see, the first thing that happens is we exec our server scripts. This is done because unless you're fully separating the client and server side, a singleplayer game still sets up a server instance, so we'll need to exec the server-side scripts for all the gameplay stuff. It's done first, because in the event this is a dedicated server OR a client, we'll always need these scripts executed, but we may not need to execute the client-side scripts if we're a dedicated server.
Next, we'll iterate through our data/<ModuleName>/scripts/datablocks folder - where we put all our datablock script files - and add them to DatablockFilesList.
This is where our utilization of the clientServer module comes in. This is an array that it set up in the initialization of the clientServer module, and is used to transmit datablocks to the client on connection. All modules can input datablocks into the array to ensure they all get properly transmitted to the client. As this is set up in the clientServer module, we have our dependency to the module so its always ready for us to use because we init after it.
Once we've iterated our datablock files and added them to that list, we want to iterate our data/<ModuleName/levels folder to get any *.mis files to add to the LevelFilesList. This is set up by the UI module, to give us a common list to add any level files from our modules and display that list on our ChooseLevel gui. Obviously, if you've got a different UI configuration, you may not need to do this, and can just reference the directory specifically if you don't have other level directories.
Next, we execute any client-side scripts. We filter this as being a client by checking that this process isn't running as a dedicated server - which means we'll be a client in some capacity. Then just exec the scripts, client preferences and any keybind files you set up for the client.
And you should be good! If your levels and datablocks have had their paths properly loaded, and you hooked the levels list to the UI, then calling StartGame(which is done in the UI module already, but needs to be done by any custom UI work you have) will kick off the creation of the game session!
In the event your project's seen a good deal of custom work, obviously just piggybacking off the FPSGameplay or SpectatorGameplay modules for the baseline isn't sufficient, and you'll need to port your work.
However, given that a fair bit of trimming and re-organization was done to clean up the templates, trying to figure what functions moved where(and even worse, if they were renamed) it can be a bit of a slog to sort through - not insurmountable, but a timesink that we'd rather avoid. So, below is a master list of functions that were moved around, removed or renamed, as well as when other stuff like datablocks got moved around. This way, you can easily look up what's where and port over your custom modifications to the appropriate spot without having to track everything down yourself.
Changes to functions in the template
/main.cs
createCanvas() moved to core/canvas.cs
isScriptFile() moved to core/helperFunctions.cs
onStart() empty function removed
parseArgs() empty function removed
core/main.cs
onStart() replaced by direct execution, sidestepping the package initialization.
onExit deprecated
loadKeybindings() currently deprecated
parseArgs() moved to core/parseArgs.cs
core/scripts/client/commands.cs
clientCmdSyncEditorGui => tools/worldEditor/scripts/cameraCommands.ed.cs
Relocated Files
core/scripts/client/audio.cs
core/audio.cs
core/scripts/client/audioAmbiences.cs
core/sfx/audioAmbiences.cs
core/scripts/client/audioData.cs
core/sfx/audioData.cs
core/scripts/client/audioDescriptioncs.cs
core/sfx/audioDescriptions.cs
core/scripts/client/audioEnvironments.cs
core/sfx/audioEnvironments.cs
core/scripts/client/audioStates.cs
core/sfx/audioStates.cs
core/scripts/client/canvas.cs
core/canvas.cs
core/scripts/client/centerPrint.cs
[FPSGameplay Module]/scripts/client/centerPrint.cs
core/scripts/client/clouds.cs
core/gfxData/clouds.cs
core/scripts/client/commonMaterialData.cs
core/gfxData/commonMaterialData.cs
core/scripts/client/cursor.cs
core/cursor.cs
core/scripts/client/lighting.cs
core/lighting.cs
core/scripts/client/message.cs
[FPSGameplay module]/scripts/client/message.cs
core/scripts/client/metrics.cs
[UI Module]/scripts/ui/profiler.gui
core/scripts/client/postFx.cs
core/postFx.cs
core/scripts/client/scatterSky.cs
core/gfxData/scatterSky.cs
core/scripts/client/shaders.cs
core/gfxData/shaders.cs
core/scripts/client/terrainBlock.cs
core/gfxData/terrainBlock.cs
core/scripts/client/water.cs
core/gfxData/water.cs
core/scripts/client/lighting/advanced/deferredShading.cs
core/lighting/advanced/deferredShading.cs
core/scripts/client/lighting/advanced/depthViz.png
tools/worldEditor/images/depthviz.png
core/scripts/client/lighting/advanced/depthViz.png
tools/worldEditor/images/depthviz.png
core/scripts/client/lighting/advanced/init.cs
core/lighting/advanced/init.cs
core/scripts/client/lighting/advanced/lightViz.cs
tools/worldEditor/scripts/lightViz.cs
core/scripts/client/lighting/advanced/shaders.cs
core/lighting/advanced/shaders.cs
core/scripts/client/lighting/advanced/shadowViz.cs
tools/worldEditor/scripts/shadowViz.cs
core/scripts/client/lighting/advanced/shadowViz.gui
tools/worldEditor/gui/shadowViz.gui
core/scripts/client/lighting/basic/init.cs
core/lighting/advanced/init.cs
core/scripts/client/lighting/basic/shadowFilter.cs
core/lighting/basic/shadowFilter.cs
core/scripts/client/lighting/shadowMaps/init.cs
core/lighting/shadowMaps/init.cs
core/scripts/client/postFx/textures/caustics_1.png
core/images/caustics_1.png
core/scripts/client/postFx/textures/caustics_2.png
core/images/caustics_2.png
core/scripts/client/postFx/AreaMap33.dds
core/images/AreaMap33.dds
core/scripts/client/postFx/caustics.cs
core/postFX/caustics.cs
core/scripts/client/postFx/chromaticLens.cs
core/postFX/chromaticLens.cs
core/scripts/client/postFx/default.postfxpreset.cs
core/postFX/default.postfxpreset.cs
core/scripts/client/postFx/dof.cs
core/postFX/dof.cs
core/scripts/client/postFx/edgeAA.cs
core/postFX/edgeAA.cs
core/scripts/client/postFx/flash.cs
core/postFX/flash.cs
core/scripts/client/postFx/fog.cs
core/postFX/fog.cs
core/scripts/client/postFx/fxaa.cs
core/postFX/fxaa.cs
core/scripts/client/postFx/GammaPostFX.cs
core/postFX/GammaPostFX.cs
core/scripts/client/postFx/glow.cs
core/postFX/glow.cs
core/scripts/client/postFx/hdr.cs
core/postFX/hdr.cs
core/scripts/client/postFx/lightRay.cs
core/postFX/lightRay.cs
core/scripts/client/postFx/MLAA.cs
core/postFX/MLAA.cs
core/scripts/client/postFx/MotionBlurFx.cs
core/postFX/MotionBlurFx.cs
core/scripts/client/postFx/noise.png
core/images/noise.png
core/scripts/client/postFx/null_color_ramp.png
core/images/null_color_ramp.cs
core/scripts/client/postFx/ovrBarrelDistortion.cs
core/postFX/ovrBarrelDistortion.cs
core/scripts/client/postFx/postFXManager.gui
core/postFX/postFXManager.gui
core/scripts/client/postFx/postFXManager.gui.cs
core/postFX/postFXManager.gui.cs
core/scripts/client/postFx/postFXManager.gui.settings.cs
core/postFX/postFXManager.gui.settings.cs
core/scripts/client/postFx/postFXManager.persistance.cs
core/postFX/postFXManager.persistance.cs
core/scripts/client/postFx/ssao.cs
core/postFX/ssao.cs
core/scripts/client/postFx/turbulence.cs
core/postFX/turbulence.cs
core/scripts/client/postFx/vignette.cs
core/postFX/vignette.cs
core/scripts/gui/messageBoxes/IODropdownDlg.ed.gui
tools/gui/messageBoxes/IODropdownDlg.ed.gui
core/scripts/gui/messageBoxes/messageBox.ed.cs
tools/gui/messageBoxes/messageBox.ed.cs
core/scripts/gui/messageBoxes/messageBoxOK.ed.gui
tools/gui/messageBoxes/messageBoxOK.ed.gui
core/scripts/gui/messageBoxes/messageBoxOKBuy.ed.gui
tools/gui/messageBoxes/messageBoxOKBuy.ed.gui
core/scripts/gui/messageBoxes/messageBoxOKCancel.ed.gui
tools/gui/messageBoxes/messageBoxOKCancel.ed.gui
core/scripts/gui/messageBoxes/messageBoxOKCancelDetailsDlg.ed.gui
tools/gui/messageBoxes/messageBoxOKCancelDetailsDlg.ed.gui
core/scripts/gui/messageBoxes/messageBoxOKYesNo.ed.gui
tools/gui/messageBoxes/messageBoxOKYesNo.ed.gui
core/scripts/gui/messageBoxes/messageBoxOKYesNoCancel.ed.gui
tools/gui/messageBoxes/messageBoxOKYesNoCancel.ed.gui
core/scripts/gui/messageBoxes/messagePopup.ed.gui
tools/gui/messageBoxes/messagePopup.ed.gui
core/scripts/gui/cursors.cs
[UI Module]scripts/cursors.cs
core/scripts/gui/FileDialog.cs
[UI Module]/scripts/gui/FileDialog.cs
core/scripts/gui/FileDialog.gui
[UI Module]/scripts/gui/FileDialog.gui
core/scripts/gui/guiMusicPlayer.cs
[UI Module]/scripts/gui/guiMusicPlayer.cs
core/scripts/gui/guiMusicPlayer.gui
[UI Module]/scripts/gui/guiMusicPlayer.gui
core/scripts/gui/guiTreeViewCtrl.cs
[UI Module]/scripts/gui/guiTreeViewCtrl.cs
core/scripts/gui/help.cs
[UI Module]/scripts/gui/help.cs
core/scripts/server/audio.cs
[clientServer Module]/scripts/server/audio.cs
core/scripts/server/camera.cs
[FPSGameplay Module]/scripts/server/camera.cs
core/scripts/server/centerPrint.cs
[FPSGameplay Module]/scripts/server/centerPrint.cs
core/scripts/server/clientConnection.cs
[clientServer Module]/scripts/server/connectionToClient.cs
core/scripts/server/defaults.cs
[clientServer Module]/scripts/server/defaults.cs
core/scripts/server/kickban.cs
[clientServer Module]/scripts/server/kickban.cs
core/scripts/server/levelInfo.cs
[clientServer Module]/scripts/server/levelInfo.cs
core/scripts/server/message.cs
[clientServer Module]/scripts/server/message.cs
core/scripts/server/missionDownload.cs
[clientServer Module]/scripts/server/levelDownload.cs
core/scripts/server/missionLoad.cs
[clientServer Module]/scripts/server/levelLoad.cs
core/scripts/server/server.cs
[clientServer Module]/scripts/server/server.cs
core/scripts/server/spawn.cs
[FPSGameplay Module]/scripts/server/spawn.cs
scripts/client/audioData.cs
[FPSGameplay Module]/scripts/datablocks/audioData.cs
scripts/client/chatHud.cs
[FPSGameplay Module]/scripts/client/chatHud.cs
scripts/client/client.cs
[FPSGameplay Module]/scripts/client/clientCommands.cs
scripts/client/default.bind.cs.cs
[FPSGameplay Module]/scripts/client/default.keybinds.cs
scripts/client/messageHud.cs
[FPSGameplay Module]/scripts/client/messageHud.cs
scripts/client/missionDownload.cs
[clientServer Module]/scripts/client/levelDownload.cs
scripts/client/playerList.cs
[FPSGameplay Module]/scripts/client/playerList.cs
scripts/client/serverConnection.cs
[clientServer Module]/scripts/client/connectionToServer.cs
scripts/client/messageHud.cs
[FPSGameplay Module]/scripts/client/messageHud.cs
scripts/gui/chooseLevelDlg.cs
[UI Module]/scripts/chooseLevelDlg.cs
scripts/gui/optionsDlg.cs
[UI Module]/scripts/optionsMenu.cs
scripts/gui/playGui.cs
[FPSGameplay Module]/scripts/gui/playGui.cs
scripts/gui/startupGui.cs
[UI Module]/scripts/startupGui.cs
scripts/server/aiPlayer.cs
[FPSGameplay Module]/scripts/server/aiPlayer.cs
scripts/server/camera.cs
[FPSGameplay Module]/scripts/server/camera.cs
scripts/server/cheetah.cs
[FPSGameplay Module]/scripts/server/cheetah.cs
scripts/server/commands.cs
[FPSGameplay Module]/scripts/server/commands.cs
scripts/server/gameDM.cs
[FPSGameplay Module]/scripts/server/deathMatchGame.cs
scripts/server/health.cs
[FPSGameplay Module]/scripts/server/health.cs
scripts/server/inventory.cs
[FPSGameplay Module]/scripts/server/inventory.cs
scripts/server/item.cs
[FPSGameplay Module]/scripts/server/item.cs
scripts/server/physicsShape.cs
[FPSGameplay Module]/scripts/server/physicsShape.cs
scripts/server/player.cs
[FPSGameplay Module]/scripts/server/player.cs
scripts/server/projectile.cs
[FPSGameplay Module]/scripts/server/projectile.cs
scripts/server/proximityMine.cs
[FPSGameplay Module]/scripts/server/proximityMine.cs
scripts/server/radiusDamage.cs
[FPSGameplay Module]/scripts/server/radiusDamage.cs
scripts/server/shapeBase.cs
[FPSGameplay Module]/scripts/server/shapeBase.cs
scripts/server/teleporter.cs
[FPSGameplay Module]/scripts/server/teleporter.cs
scripts/server/triggers.cs
[FPSGameplay Module]/scripts/server/triggers.cs
scripts/server/turret.cs
[FPSGameplay Module]/scripts/server/turret.cs
scripts/server/vehicle.cs
[FPSGameplay Module]/scripts/server/vehicle.cs
scripts/server/vehicleWheeled.cs
[FPSGameplay Module]/scripts/server/vehicleWheeled.cs
scripts/server/VolumetricFog.cs
[FPSGameplay Module]/scripts/server/VolumetricFog.cs
scripts/server/weapon.cs
[FPSGameplay Module]/scripts/server/weapon.cs
art/datablocks/vehicles/cheetaCar.cs
[FPSGameplay Module]/scripts/datablocks/vehicles/cheetaCar.cs
art/datablocks/weapons/grenadefx.cs
[FPSGameplay Module]/scripts/datablocks/weapons/grenadefx.cs
art/datablocks/weapons/Lurker.cs
[FPSGameplay Module]/scripts/datablocks/weapons/Lurker.cs
art/datablocks/weapons/NewWeaponTemplate.cs
[FPSGameplay Module]/scripts/datablocks/weapons/NewWeaponTemplate.cs
art/datablocks/weapons/ProxMine.cs
[FPSGameplay Module]/scripts/datablocks/weapons/ProxMine.cs
art/datablocks/weapons/rocketfx.cs
[FPSGameplay Module]/scripts/datablocks/weapons/rocketfx.cs
art/datablocks/weapons/Ryder.cs
[FPSGameplay Module]/scripts/datablocks/weapons/Ryder.cs
art/datablocks/weapons/Turret.cs
[FPSGameplay Module]/scripts/datablocks/weapons/Turret.cs
art/datablocks/aiPlayer.cs
[FPSGameplay Module]/scripts/datablocks/aiPlayer.cs
art/datablocks/audioProfiles.cs
[FPSGameplay Module]/scripts/datablocks/audioProfiles.cs
art/datablocks/environment.cs
[FPSGameplay Module]/scripts/datablocks/environment.cs
art/datablocks/health.cs
[FPSGameplay Module]/scripts/datablocks/health.cs
art/datablocks/lights.cs
[FPSGameplay Module]/scripts/datablocks/lights.cs
art/datablocks/managedDatablocks.cs
[FPSGameplay Module]/scripts/datablocks/managedDatablocks.cs
art/datablocks/particles.cs
[FPSGameplay Module]/scripts/datablocks/particles.cs
art/datablocks/physics.cs
[FPSGameplay Module]/scripts/datablocks/physics.cs
art/datablocks/player.cs
[FPSGameplay Module]/scripts/datablocks/player.cs
art/datablocks/rigidShape.cs
[FPSGameplay Module]/scripts/datablocks/rigidShape.cs
art/datablocks/teleporter.cs
[FPSGameplay Module]/scripts/datablocks/teleporter.cs
art/datablocks/triggers.cs
[FPSGameplay Module]/scripts/datablocks/triggers.cs
art/datablocks/weapon.cs
[FPSGameplay Module]/scripts/datablocks/weapon.cs
art/decals/Bullet Holes/BulletHole_Glass.dds
[FPSGameplay Module]/art/decals/Bullet Holes/BulletHole_Glass.dds
art/decals/Bullet Holes/BulletHole_Walls.dds
[FPSGameplay Module]/art/decals/Bullet Holes/BulletHole_Walls.dds
art/decals/bullet_hole.png
[FPSGameplay Module]/art/decals/bullet_hole.png
art/decals/defaultBlobShadow.png
[FPSGameplay Module]/art/decals/defaultBlobShadow.png
art/decals/managedDecalData.cs
[FPSGameplay Module]/scripts/datablocks/managedDecalData.cs
art/decals/materials.cs
[FPSGameplay Module]/art/decals/materials.cs
art/decals/rBlast.png
[FPSGameplay Module]/art/decals/rBlast.png
art/decals/scorch_decal.png
[FPSGameplay Module]/art/decals/scorch_decal.png
art/environment/precipitation/rain.png
[FPSGameplay Module]/art/environment/precipitation/rain.png
art/environment/precipitation/water_splash.png
[FPSGameplay Module]/art/environment/precipitation/water_splash.png
art/environment/Fog_Cube.cs
[FPSGameplay Module]/art/environment/Fog_Cube.cs
art/environment/Fog_Cube.DAE
[FPSGameplay Module]/art/environment/Fog_Cube.DAE
art/environment/FogMod_heavy.dds
[FPSGameplay Module]/art/environment/FogMod_heavy.dds
art/environment/FogMod_light.dds
[FPSGameplay Module]/art/environment/FogMod_light.dds
art/environment/FogMod_med.dds
[FPSGameplay Module]/art/environment/FogMod_med.dds
art/environment/grass1.png
[FPSGameplay Module]/art/environment/grass1.png
art/environment/grass2.png
[FPSGameplay Module]/art/environment/grass2.png
art/environment/grass3.png
[FPSGameplay Module]/art/environment/grass3.png
art/environment/lightning.png
[FPSGameplay Module]/art/environment/lightning.png
art/environment/LightVolume_Sphere.cs
[FPSGameplay Module]/art/environment/LightVolume_Sphere.cs
art/environment/LightVolume_Sphere.DAE
[FPSGameplay Module]/art/environment/LightVolume_Sphere.DAE
art/environment/LightVolume_Sphere.dts
[FPSGameplay Module]/art/environment/LightVolume_Sphere.dts
art/environment/materials.cs
[FPSGameplay Module]/art/environment/materials.cs
art/environment/plant1.png
[FPSGameplay Module]/art/environment/plant1.png
art/gui/weaponHud/bino.png
[FPSGameplay Module]/art/gui/weaponHud/bino.png
art/gui/weaponHud/blank.png
[FPSGameplay Module]/art/gui/weaponHud/blank.png
art/gui/weaponHud/crossHair.png
[FPSGameplay Module]/art/gui/weaponHud/crossHair.png
art/gui/weaponHud/lurker.png
[FPSGameplay Module]/art/gui/weaponHud/lurker.png
art/gui/weaponHud/mine.png
[FPSGameplay Module]/art/gui/weaponHud/mine.png
art/gui/weaponHud/reticle_rocketlauncher.png
[FPSGameplay Module]/art/gui/weaponHud/reticle_rocketlauncher.png
art/gui/weaponHud/ryder.png
[FPSGameplay Module]/art/gui/weaponHud/ryder.png
art/gui/weaponHud/swarmer.png
[FPSGameplay Module]/art/gui/weaponHud/swarmer.png
art/gui/weaponHud/turret.png
[FPSGameplay Module]/art/gui/weaponHud/turret.png
art/gui/background.png
[FPSGameplay Module]/art/gui/background.png
art/gui/chatHud.gui
[FPSGameplay Module]/scripts/gui/chatHud.gui
art/gui/chooseLevelDlg.gui
[UI Module]/scripts/guis/chooseLevelDlg.gui
art/gui/damageBottom.png
[FPSGameplay Module]/art/gui/damageBottom.png
art/gui/damageFront.png
[FPSGameplay Module]/art/gui/damageFront.png
art/gui/damageLeft.png
[FPSGameplay Module]/art/gui/damageLeft.png
art/gui/damageRight.png
[FPSGameplay Module]/art/gui/damageRight.png
art/gui/damageTop.png
[FPSGameplay Module]/art/gui/damageTop.png
art/gui/hudfill.png
[FPSGameplay Module]/art/gui/hudfill.png
art/gui/hudlessGui.gui
[FPSGameplay Module]/scripts/gui/hudlessGui.gui
art/gui/joinServerDlg.gui
[UIModule]/scripts/gui/joinServerDlg.gui
art/gui/lagIcon.png
[UI Module]/art/lagIcon.png
art/gui/loadingGui.gui
[FPSGameplay Module]/scripts/gui/loadingGui.gui
art/gui/mainMenuGui.gui
[UI Module]/scripts/guis/mainMenuGui.gui
art/gui/next-button_d.png
[UI Module]/art/next-button_d.png
art/gui/next-button_h.png
[UI Module]/art/next-button_h.png
art/gui/next-button_n.png
[UI Module]/art/next-button_n.png
art/gui/no-preview.png
[UI Module]/art/no-preview.png
art/gui/optionsDlg.gui
[UI Module]/scripts/guis/optionsMenu.gui
art/gui/playerList.gui
[FPSGameplay Module]/scripts/gui/playerList.gui
art/gui/playGui.gui
[FPSGameplay Module]/scripts/gui/playGui.gui
art/gui/previous-button_d.png
[UI Module]/art/previous-button_d.png
art/gui/previous-button_h.png
[UI Module]/art/previous-button_h.png
art/gui/previous-button_n.png
[UI Module]/art/previous-button_n.png
art/gui/remapDlg.gui
[UI Module]/scripts/guis/remapDlg.gui
art/gui/splash.png
data/splash.png
art/gui/StartupGui.gui
[UI Module]/scripts/guis/StartupGui.gui
art/gui/Torque-3D-logo-w.png
[UI Module]/art/Torque-3D-logo-w.png
art/gui/Torque-3D-logo.png
[UI Module]/art/Torque-3D-logo.png
art/gui/Torque-3D-logo_alt.png
[UI Module]/art/Torque-3D-logo_alt.png
art/particles/bubble.png
[FPSGameplay Module]/art/particles/bubble.png
art/particles/droplet.png
[FPSGameplay Module]/art/particles/droplet.png
art/particles/Dust.png
[FPSGameplay Module]/art/particles/Dust.png
art/particles/dustParticle.png
[FPSGameplay Module]/art/particles/dustParticle.png
art/particles/ember.png
[FPSGameplay Module]/art/particles/ember.png
art/particles/fire.png
[FPSGameplay Module]/art/particles/fire.png
art/particles/fireball.png
[FPSGameplay Module]/art/particles/fireball.png
art/particles/firefly.png
[FPSGameplay Module]/art/particles/firefly.png
art/particles/flame.png
[FPSGameplay Module]/art/particles/flame.png
art/particles/flare.png
[FPSGameplay Module]/art/particles/flare.png
art/particles/impact.png
[FPSGameplay Module]/art/particles/impact.png
art/particles/managedParticleData.cs
[FPSGameplay Module]/scripts/datablocks/managedParticleData.cs
art/particles/managedEmitterData.cs
[FPSGameplay Module]/scripts/datablocks/managedEmitterData.cs
art/particles/millsplash01.png
[FPSGameplay Module]/art/particles/millsplash01.png
art/particles/ricochet.png
[FPSGameplay Module]/art/particles/ricochet.png
art/particles/smoke.png
[FPSGameplay Module]/art/particles/smoke.png
art/particles/spark.png
[FPSGameplay Module]/art/particles/spark.png
art/particles/spark_wet.png
[FPSGameplay Module]/art/particles/spark_wet.png
art/particles/Sparkparticle.png
[FPSGameplay Module]/art/particles/Sparkparticle.png
art/particles/splash.png
[FPSGameplay Module]/art/particles/splash.png
art/particles/steam.png
[FPSGameplay Module]/art/particles/steam.png
art/particles/Steak.png
[FPSGameplay Module]/art/particles/Streak.png
art/particles/wake.png
[FPSGameplay Module]/art/particles/wake.png
art/particles/waterDrip.png
[FPSGameplay Module]/art/particles/waterDrip.png
art/prefabs/fire.prefab
[FPSGameplay Module]/art/prefabs/fire.prefab
art/ribbons/materials.cs
[FPSGameplay Module]/art/particles/ribbons/materials.cs
art/ribbons/ribbons.cs
[FPSGameplay Module]/scripts/datablocks/ribbons.cs
art/ribbons/ribTex.png
[FPSGameplay Module]/art/particles/ribbons/ribTex.png
art/roads/defaultpath.png
[FPSGameplay Module]/art/roads/defaultpath.png
art/roads/defaultpath_normal.png
[FPSGameplay Module]/art/roads/defaultpath_normal.png
art/roads/defaultRoadTextureOther.png
[FPSGameplay Module]/art/roads/defaultRoadTextureOther.png
art/roads/defaultRoadTextureTop.png
[FPSGameplay Module]/art/roads/defaultRoadTextureTop.png
art/roads/materials.cs
[FPSGameplay Module]/art/roads/materials.cs
art/shapes/actors/common/*
[FPSGameplay Module]/art/shapes/actors/common/*
art/shapes/actors/Soldier/Anims/*
[FPSGameplay Module]/art/shapes/actors/Soldier/Anims/*
art/shapes/actors/Soldier/FP/*
[FPSGameplay Module]/art/shapes/actors/Soldier/FP/*
art/shapes/Cheetah/*
[FPSGameplay Module]/art/shapes/Cheetah/*
art/shapes/cube/*
[FPSGameplay Module]/art/shapes/cube/*
art/shapes/groundCover/*
[FPSGameplay Module]/art/shapes/groundCover/*
art/shapes/items/kit/*
[FPSGameplay Module]/art/shapes/items/kit/*
art/shapes/items/patch/*
[FPSGameplay Module]/art/shapes/items/patch/*
art/shapes/rocks/*
[FPSGameplay Module]/art/shapes/rocks/*
art/shapes/station/*
[FPSGameplay Module]/art/shapes/station/*
art/shapes/teleporter/*
[FPSGameplay Module]/art/shapes/teleporter/*
art/shapes/trees/defaultTree/*
[FPSGameplay Module]/art/shapes/trees/defaultTree/*
art/shapes/weapons/Grenade/*
[FPSGameplay Module]/art/shapes/weapons/Grenade/*
art/shapes/weapons/Lurker/*
[FPSGameplay Module]/art/shapes/weapons/Lurker/*
art/shapes/weapons/ProxMine/PlayerAnims/*
[FPSGameplay Module]/art/shapes/weapons/ProxMine/PlayerAnims/*
art/shapes/weapons/ProxMine/*
[FPSGameplay Module]/art/shapes/weapons/ProxMine/*
art/shapes/weapons/Ryder/PlayerAnims/*
[FPSGameplay Module]/art/shapes/weapons/Ryder/PlayerAnims/*
art/shapes/weapons/Ryder/*
[FPSGameplay Module]/art/shapes/weapons/Ryder/*
art/shapes/weapons/shared/*
[FPSGameplay Module]/art/shapes/weapons/shared/*
art/shapes/weapons/Turret/PlayerAnims/*
[FPSGameplay Module]/art/shapes/weapons/Turret/PlayerAnims/*
art/shapes/weapons/Turret/*
[FPSGameplay Module]/art/shapes/weapons/Turret/*
art/skies/clouds/*
[FPSGameplay Module]/art/skies/clouds/*
art/skies/Desert_Sky/cubemap/*
[FPSGameplay Module]/art/skies/Desert_Sky/cubemap/*
art/skies/Desert_Sky/*
[FPSGameplay Module]/art/skies/Desert_Sky/*
art/skies/night/*
[FPSGameplay Module]/art/skies/night/*
art/sound/cheetah/*
[FPSGameplay Module]/sound/cheetah/*
art/sound/environment/*
[FPSGameplay Module]/sound/environment/*
art/sound/turret/*
[FPSGameplay Module]/sound/turret/*
art/sound/ui/*
[FPSGameplay Module]/sound/ui/*
art/sound/weapons/*
[FPSGameplay Module]/sound/weapons/*
art/sound/*
[FPSGameplay Module]/sound/*
art/terrains/Example/*
[FPSGameplay Module]/art/terrains/Example/*
art/terrains/*
[FPSGameplay Module]/art/terrains/*
art/water/*
[FPSGameplay Module]/art/water/*
Assets, as far as Torque3D 4.0 is concerned, is a means of tracking a game’s content via metadata. There are many types of assets: shapes, materials, images, levels, sounds and so on. Unlike a simple file path reference, the metadata an asset provides gives a litany of supporting data and utility.
Classically, engine assets such as shape files were simply the literal files themselves. A class or object that would want to use said shape file would have a filepath field that would point to it, and the class would process it. In a few special cases, like shape files, the loader logic for the shape would run some logic during load to generate secondary files. For shapes, you’d have your engine-formatted *.cached.dts data, the shape constructor script file, etc.
Loading resources the classical way An example of when the shape is loaded can be seen here. We pass in the filepath into the resource loader, and in the case of Shape resources, would generate the *.cached.dts file if it didn’t exist, and load it if/when it did, returning the shape resource.
One of the problems, however, was it relied on a direct file reference.
If for any reason - a typo, the file was moved or deleted or so on - the file was not found at the file path, it broke.
When this happened, the object would fail to load, and then would not exist in the scene. This made the level editor particularly dangerous, as if the objects failed to load their shape files, they wouldn’t be added to the scene at all, and if the mapper failed to notice missing objects and saved, they were gone for good.
The asset system sidesteps this issue by instead utilizing unique id names to reference, similar to referencing an object by name. The asset itself handles the path info, and game objects themselves need only request the unique id name.
This means that if the shape’s file path was spelt incorrectly, or was moved, then as long as it’s correct in the asset metadata, any object with the assetId will get the correct path.
Another useful aspect is how assets handle fallbacks. In the event an asset isn’t found, or something is not loaded correctly preventing the asset from being used, it can safely fall back to a placeholder asset without ‘damaging’ the original data. As previously noted, the old way, this meant that the object did not load at all, causing problems with the map.
Instead, the asset system can realize it failed to find or load the requested asset, and provide a placeholder fallback. This allows the level to load as normal, and present obvious indicator content to the level editor or testers that something did not load as was expected, without harming the level file as it’s otherwise being worked on. This prevents the problem from holding up other team members’ tasks.
Other issues often faced in the legacy, path-based resources were order of operations and dependencies loading. To ensure materials were loaded before they were needed(as there was no way to associate materials to what used them), the game template would just scan all material.tscript files and bruteforce load everything ahead of time. This could lead to longer startup times, and could be an exploitable vulnerability, as well as often loading a ton of additional material into memory that wasn’t needed.
It could also suffer from similar path unreliability issues if paths the materials relied on for image maps or the like were invalid due to misspellings, or being moved.
Assets, however, allow integrated dependency tracking. When an asset, such as a shape, is loaded, it has its own list of dependencies.
Because asset loading is reference-based. Only assets that are actually called get loaded. When they go to load, it checks for any dependencies in the asset metadata, and loads them first. Those assets load in a similar way, continuing until the dependency chain is complete.
In the above example, the shapeAsset is loaded, but it relies on 2 material assets. It loads those, but those themselves have dependencies to image assets, so those are loaded. Once the entire dependency chain is loaded and valid, the shapeAsset is ready and passed back to the game object that wanted to use it. If anything goes wrong, each can provide a fallback placeholder to ensure things load correctly, while still indicating what and how it failed to provide more info for debugging.
Because assets’ loading is reference-based, when all the references are removed, such as when a level is unloaded, the asset can too be unloaded. This makes post-level cleanup easy, and goes a long way to ensure only memory and resources in use actually get consumed.
This document provides an overview of some of the concepts involved in creating art for Torque. The table below summarizes the file formats used for Torque texture and shape resources.
dts
DTS is the native, binary file format used by Torque to store shape (geometry, LOD, bone, and animation) data. DTS exporters exist for several 3D modeling packages such as 3ds Max, Maya, XSI, Blender, and Milkshape3D.
dsq
DSQ is the native, binary file format used by Torque to store animation data separately from the shape data. This is most often used to share animations between a set of shapes with the same skeleton.
dae, kmz
COLLADA is an XML based model interchange format. Many 3D modeling packages support COLLADA import and export.
bmp, gif, jpeg, jpg, jng, mng, png, tga, dds
Supported texture file formats. Note that texture dimensions should be powers of 2 wherever possible such as 16, 32, 64, 128, 256, so forth, although they need not be square. Some older hardware is unable to process non-power-of-2 textures at all, and even modern hardware will pad such textures up to the next largest power of 2 when loaded which wastes VRAM.
Torque supports two different formats for 3D geometry and animation data: COLLADA (model.dae) and DTS (model.dts). The two formats have different strengths and most teams will find an appropriate mix of both to be the best practice. Models in either format can be further customized after loading into Torque using TSShapeConstructor (see the TorqueScript reference documentation for more details). This TorqueScript accessible class allows nodes, sequences and detail levels to be examined and modified at runtime. Common uses are to define and split animation sequences embedded within a COLLADA file, and to share animations between characters with the same skeleton.
It should be noted that all changes applied by a TSShapeConstructor script occur to the in-memory model; nothing is cached to disk, so the transformations will occur every time the shape is loaded by Torque. In some cases therefore it may make sense to 'bake' transformations by using the dae2dts tool as part of a custom import/export pipeline or release packaging script.
COLLADA is intended to be the primary model format during development of a Torque game; there are COLLADA importers and exporters for almost every 3D modeling application around, and in a pinch you can even edit the XML dae file manually - handy if a programmer or level designer needs to test a minor tweak without bothering the artists.
DTS is generally the model format of choice when releasing a game. It is an optimized, binary format that loads much faster than COLLADA, and also provides a small measure of protection for art assets (most applications can import DAE, but very few can import DTS). The normal workflow is to use COLLADA during development, then make sure all models are converted to DTS for release.
There are several different approaches available to achieve this:
1. Use the autogenerated cached.dts files
When Torque imports a COLLADA model it saves the resulting 3-space shape to a DTS file in the same folder as the DAE (model.cached.dts). The next time the DAE file would be loaded, Torque first checks if there is a newer cached.dts file in the same folder and if so, loads that instead. For simple models, this means you can simply strip the DAEs from the released version of the game, leaving only the cached.dts files. All datablocks and mission files still refer to the DAE model, but Torque will automatically load the cached.dts in its place.
Note that the cached.dts file represents the converted DAE model only - changes applied using a TSShapeConstructor script are only made to the in-memory shape, so are not included in this file.
2. Use the dae2dts tool
The dae2dts tool can be used to convert COLLADA files to DTS as needed. If using this approach, datablocks and mission files should refer to the coverted DTS output file, not the original DAE file. The dae2dts tool bakes any model transformations made using TSShapeConstructor into the final DTS model, so make sure that the TSShapeConstructor script used with dae2dts is not run when loading the DTS output file into T3D (by making the filenames different, or keeping the output DTS file in a different folder) or the changes will be applied twice!
Of course, there is no reason you could not use one TSShapeConstructor script with dae2dts to bake changes, then use another TSShapeConstructor script when loading the baked DTS file into T3D to apply dynamic changes (like auto-loading all sequence files within a folder for example).
3. Export directly to DTS
If using a modeling program with DTS export support, it may make sense to export certain models directly to DTS; although current DTS exporters have several limitations (single UV set, no vertex colors, limited to around 11000 triangles per mesh) compared to COLLADA.
LOD is an extremely important concept to master in order to produce a great looking game that plays smoothly on low/mid-range hardware. Essentially, it involves rendering successively less complex versions of a shape in order to improve performance. The metric used in Torque to control LOD is the estimated size of the shape on screen; as the shape gets further from the camera it will become smaller on screen, and a simpler version of the mesh may be rendered without loss of fidelity.
A Torque 3D shape (sometimes called a 3space or more commonly DTS shape) consists of the following elements:
node
A node is a place-holder for transform (position and rotation) information. Nodes are arranged in a parent/child hierarchy allowing complex skeleton structures to be built up.
sequence
A sequence is a set of key-framed node transforms and object states (e.g,. visibility).
mesh
A mesh is a piece of triangulated geometry, and may be a normal mesh or a skin (vertex weighted mesh). Each mesh is associated with an object and a detail level.
object
An object is a set of meshes, each at a different detail level. Each object is attached to a single node, and is rendered at that node's current transform. Note: the transform may or may not be animated. When the object is rendered, only the mesh associated with the active detail level will be rendered. Objects do not need to define a mesh at every detail level. For example, some parts of a shape could be made visible only when near to the camera.
detail
A detail level is a set of meshes (one from each object) that will be rendered when the detail level is active.
With those definitions in mind, a 3space shape can be visualized in a hierarchy as follows:
+-base01
+-start01
+-Torso Object Torso with details: 256 64 32
+-Head Object Head with details: 256 64 32
+-Armor Object Armor with details: 256 64
+-ColBox Object ColBox with details: -1
Or in table form as:
Torso
Head
Armor
ColBox
256
Torso256
Head256
Armor256
64
Torso64
Head64
Armor64
32
Torso32
Head32
-1
ColBox-1
The shape contains 4 objects (Torso, Head, Armor, ColBox), each of which have one or more meshes at different detail levels. Before rendering the shape, Torque estimates how large it would appear on-screen, and determines the appropriate detail level to render. Only the meshes in that detail level (a 'row' in the table above) are rendered. The estimated size is based on the shape's bounds, the camera distance and Field-of-View (FOV). The following table shows how the shape will be rendered as it moves further from the camera:
>= 256
0 (size=256)
Torso256, Head256, Armor256
>= 64 and < 256
1 (size=64)
Torso64, Head64, Armor64
>= 32 and < 64
2 (size=32)
Torso32, Head32
< 32
none
none
Note that detail levels with negative sizes will never be chosen for rendering. Once the estimated size is less than the smallest positive detail size, no geometry will be rendered for the shape. You can force a shape to always render something by making the smallest positive detail level have size=0. Negative detail level sizes are used to store non-rendered geometry such as collision meshes. In the shape above, the ColBox object defines a single mesh to be used for collision detection and will never be rendered due to its detail size of -1.
See also
Every 3D shape includes an axis-aligned bounding box. This box appears around the shape when it is selected in the World Editor, and can be used for simple collision detection or mouse-hit picking. The bounding box is also used to determine which shape detail level to render (see LOD). The size of the bounding box is not fixed to the shape geometry. The modeler is free to define a custom bounding box extent for an object. This is normally done prior to DTS/DAE export by creating a cube mesh called "bounds" with the appropriate dimensions.
See also
Collision geometry is a special minimal version of the shape which is used in the game engine's collision system. In general, if there are fewer polygons in a collision volume then the collision detection will be faster. Collision geometry is stored in a shape within one or more detail levels with negative size values (indicating that the detail level is not to be rendered). Collision detail levels must be named Collision-X or LOS-X for collision or line-of-sight (raycast) collision respectively. LOS collision meshes are only used in raycast tests for things like projectile collision. X is a number from 1 to 8 for collision meshes, or 9 to 16 for LOS collision meshes. If your modeling application does not support hyphens in names, use an underscore instead (e.g. Collision_1).
The name of the collision mesh for a given detail level can give a hint to the Torque engine about what type of geometry to use. This allows for significant performance improvement in the case of the box, sphere and capsule primitives, or for non-convex geometry to be used for collision detection. Any mesh that does not match one of the names below will be interpreted as a generic convex hull (i.e. the same as ColConvex). In this case, the vertices of the mesh are used to construct a convex hull when the shape is loaded.
ColBoxThis will be converted to a box primitive (that bounds the mesh) when the shape is loaded.ColSphereThis will be converted to a true sphere primitive (that bounds the mesh) when the shape is loaded.ColCapsuleThis will be converted to a true capsule primitive (that bounds the mesh) when the shape is loaded.ColConvexA generic convex mesh, converted to a true convex hull when the shape is loaded.ColMeshA generic triangular mesh that does not need to be convex. This type of geometry is the most expensive for collision testing, and should be kept as simple (fewest triangles) as possible.
Prior to export, you should add the size of the particular detail level to the mesh names above. When Torque 3D encounters one of the primitive mesh types (Box, Sphere, Capsule), it uses the mesh bounding box to quickly calculate the dimensions (length, radius etc) of the box, sphere, or capsule. For this reason, the mesh should be aligned to the local coordinates of the node that instantiates it as shown below. This ensures the axis-aligned bounding box is a tight fit and that the calculated primitive dimensions are accurate.
See also
A 3D mesh may be marked as a billboard before export to DTS/DAE, or directly in the Torque 3D Shape Editor. When a billboard mesh is rendered, it is rotated such that it always faces the camera (technically, the rotation is such that the mesh forward (+Y) axis points out of the screen). A shape may contain a mix of billboard and non-billboard meshes. For example, you could have an explosion shape in which shrapnel flies out from the center and also have little explosion balls fly out that are just flat polygons that always face you. A second type of billboard is the Z billboard, which rotates the mesh to face the camera only around the Z (up) axis as shown below:
The billboard mesh's center of rotation is the position of the node to which that mesh is attached. For example, a tree model might have multiple branches set up as billboards, all attached to different nodes such that each branch is rotated around its own node, rather than the center of the tree.
The exact details of how to export billboards to a DTS shape will depend on the modeling package, but in general it is done by prefixing the name of the mesh with BB:: (or BB_ if the modeling app does not support colons in names) for a normal billboard, or BBZ:: (or BBZ_) for Z billboards.
See also
Imposters (also known as AutoBillboards) are commonly used as the last visible detail level for when the model is far away from the camera. These detail levels are special in that Torque generates a series of low-resolution snapshots (both diffuse and normal maps) of the model at different camera angles and stores these in two DDS files in the same folder as the model. When the imposter detail level is active, Torque selects one of these snapshots to render instead of the 3D geometry. With appropriate settings, this can give a significant performance increase with negligible loss in visual quality. As the camera moves around the shape, the Torque engine displays the appropriate snapshot. Imposters are often used as the smallest detail level since they are very efficient to render being composed of only two triangles.
Imposters may be configured using the following settings (note: polar billboards are the two billboards that face straight up and straight down, i.e. the ones at the poles):
BB::DL
integer
Index of the detail level used to generate the snapshots (usually 0).
=0 samples the highest LOD
=1 samples the second-highest LOD
=2 samples the third-highest LOD
BB::DIM
integer
Size (width and height) of each snapshot in pixels. Use powers of 2 such as 32, 64, 128 etc.
BB::EQUATOR_STEPS
integer
Number of snapshots around the horizontal axis of the model.
BB::POLAR_STEPS
integer
Number of longitudinal steps between the polar billboards. Polar steps do not include or calculate imposters created for the top or bottom of the shape, only the billboards in between. The numbering of this setting may seem counterintiutive, but here's how it works:
A setting of 0 will give 1 polar step between the polar billboards
A setting of 1 will give 3 polar steps between the polar billboards
A setting of 2 will give 5 polar steps between the polar billboards
A setting of 3 will give 7 polar steps between the polar billboards
A setting of 4 will give 9 polar steps between the polar billboards
BB::INCLUDE_POLES
boolean
Flag indicating whether to generate snapshots of the poles (top and bottom) of the model. When this is off the BB::POLAR_ANGLE setting is irrelevant.
BB::POLAR_ANGLE
float
Angle (in degrees) from the equator that acts as the threshold between the polar billboards and the rest of the billboards.
When Torque loads a shape with an imposter detail level, it automatically generates the files that contain the billboard images. The files are titled shapename.imposter.dds and shapename.imposter_normals.dds.
Carefully select step settings to optimize your imposters to boost quality and reduce use of disk space. For example, BB::EQUATOR_STEPS=5 and BB::POLAR_STEPS=2 with no polar billboards will give 25 imposters. Each being 256x256, that will result in two imposter files (one for diffuse/transparency maps, and one for normal map) that are 1024x2048:
In fact, there is a lot of unused white space at the bottom of these textures. You could increase BB::EQUATOR_STEP to 6 adding five more billboards without increasing the overall imposter texture size. Thats a fifth more imposter textures at almost no cost. Also, make sure your bounding box is as tight on your shape as possible to reduce the whitespace between billboards and maximize the resolution of each billboard with their size limits (256x256 in the example above).
With proper settings your meshes will automatically billboard in-game.
See also
Torque uses the same coordinate system as 3ds Max. Characters and vehicles should be exported facing the +Y axis (or the equivalent "into the screen" axis if the modeling app uses a different coordinate system).
When exporting to DTS, one modeling-app unit equals one unit in Torque. When exporting to COLLADA, you are free to work in whatever units you like. They will be scaled appropriately when importing the model into Torque.
Objects in Torque may be mounted to other objects, such as a Player riding a WheeledVehicle or a weapon placed in the player's hands. Usually the object to be mounted has a node named mountPoint. For example, a weapon will be mounted in the player model's hand at node mount0. The mountPoint node is not essential however. If not present, the mounted object's origin is used as the mount point. Objects can be mounted from script at runtime, or in the Torque 3D Shape Editor.
function PlayerData::onAdd(%this, %obj)
{
// put the crossbow in the player's hand
%obj.mountImage(CrossBowImage, 0);
};
See also
Animation threads allow multiple sequences to play at the same time on a single shape. For example, a 'headside' animation could rotate the player's head to look at something at the same time as a running animation is playing. Each animation sequence is played using a thread. Threads for non-blend sequences are applied first (in order of increasing priority), then blend sequence threads are applied on top (in order of increasing priority). The following rules determine what happens when more than one thread controls the same node in the shape:
If two non-blend sequences control the same node, the sequence with higher priority will animate it.
If two non-blend sequences with the same priority control the same node, the thread that was created last will animate it.
Blend sequences are applied on top of any previous thread, so if two blend sequences control the same node, both will animate it (applied in order of increasing priority, or thread creation order if priority is the same).
Threads can be initiated from script as follows:
%obj.playThread( 0, "run" ); // play the "run" animation in thread slot 0
See also
Animation sequences that move the character should include a ground transform. This tells the engine how fast the character would move along the ground when the animation is played back at normal speed. In the case of a Player object, this allows Torque to scale the animation playback speed to match the in-game speed that the Player is moving. For example, if the model was animated such that it would normally move at 3 units per second, but in-game was moving at 6 units per second, then the animation can be played back at double speed so the feet do not look like they are skating along the ground. Another use for ground transforms is to automatically switch between walking and running animations based on the in-game velocity of the Player.
The exact details of how to export ground transforms will depend on the modeling package. In general, the animation should be created so the character moves through space, rather than running or walking in-place. Animate the bounds node to move with the character so there is no translation relative to the bounds node. On export, the ground transform is determined by subtracting the movement of the bounds node from the walking or running animation so that it will play in-place in Torque 3D.
See also
Triggers are arbitrary markers that can be used to call events on specific frames in a sequence. For example, a trigger can be responsible for generating footstep sounds and footprints when the feet hit the ground during walk and run animations. There can be up to 30 independent trigger states each with their respective on (1 to 30) and off (-1 to -30) states. You decide what each of those trigger states means. You should work with your programmer to define what the trigger states mean and how you should use them.
For example, you could have one trigger for each foot of a character that creates a footprint when the foot is down on the ground. Let's say that a triggerState of 1 is the left foot down and a triggerState of 2 is the right foot down. When the sequence plays the frame during which the left foot touches the ground, you could have a trigger on that frame that has a triggerState of 1 to create a footprint. You would then create another trigger with a triggerState of 2 for the right foot. You don't necessarily need to turn off the footprints (let's assume that the programmer will turn them off when it is necessary), but you could by creating two more triggers with triggerStates -1 and -2.
See also
Blend animations allow additive animation on the node structure of the shape. These will not conflict with other threads, and can be played on top of the node animation contained in other threads; such animations are relative. Blends only store the changes that occur over the course of the animation and not the absolute position of the nodes. This means that if a node is transformed by a blend animation, it includes only the transform information for that node, and it will add that transformation on top of the existing position in the base shape. Common uses for blend animations are facial expressions, head turning or nodding, and arm aiming.
Bear in mind that a blend can be played as a normal sequence, or it can be played on top of other sequences. When another sequence is playing, it will alter the root position, and the blend will be applied on top of that.
If you try to do a blend sequence where the root position is different than the 'normal' root (in the default root animation), you might expect that the blend will blend it to the new root (the position the character is positioned in during the blend animation). However, it does not work this way. Since nothing would actually be animating, it doesn't move the bones to the new position. What is contained in the blend sequence is only transform offsets from the blend sequence root position.
It is not a good idea to have a different root position in your 'normal' animations and your blends, as they can easily get out of sync.
The values added from the blend animation are based on the root position in the DAE/DTS/DSQ file. This root position does not have to be the beginning of the animation. You can pick any position for the blend animation to reference.
This is useful, because you can have a blend animation that can have a reference position that is the 'root' position. For animation like hip twists and arm movements (as in the 'look' animation), the character can be in a natural default state. In this way, you can have one animation control the character through the base pose to an extreme in either direction while referencing the default 'base' state, which will exist somewhere in the middle of the blend animation.
See also
Characters in T3D can be setup to use different weapon animations and share those animations between different skinned meshes with the same skeleton hierarchy. So a standard T3D character would have COLLADA files for the character’s skinned mesh and skinned skeleton as well as for the character’s animations with just the skeleton for each weapon pose. The animations can be exported individually or combined in one .dae file that is split up through the shape editor.
Third Person Weapon Player Animation Names
Back: (Loops)
Run backward
Crouch_Back: (Loops)
Crouch walk backward
Crouch_Forward: (Loops)
Crouch walk forward
Crouch_Root: (Loops)
Crouch idle
Crouch_Side: (Loops)
Crouch move right
Death#:
Where ‘#’ is can be a number for multiple death sequences that will be picked randomly. So Death1, Death2, etc.
Fall: (Loops)
Character is falling
Head: (Blend)
Usually a 9 frame animation that only affects the neck and head and works in conjunction with the “Look” animation. Frame 1 is looking straight up, frame 5 is looking straight forward and 9 is looking down
Jump:
Character jumping
Land:
Character landing
Look: (Blend)
Usually a 9 frame animation that only affects the spine and works in conjunction with the “Head” animation. Frame 1 is looking straight up, frame 5 is looking straight forward and 9 is looking down
Reload: (Blend)
Reloading the weapon
Root: (Loops)
More commonly known as the idle animation in most parts of the industry. Just the character standing and breathing
Run: (Loops)
Character running
Side: (Loops)
Character side stepping to the right. This animation will be played in reverse when moving to the left
Sitting: (Loops)
Character sitting in a vehicle
Swim_Back: (Loops)
Swimming backward
Swim_Forward: (Loops)
Swimming forward
Swim_Idle: (Loops)
Treading water
Swim_Left: (Loops)
swimming left
Swim_Right: (Loops)
Swimming right
After that you add the animations through the shape editor by going to sequence tab (labeled “Seq”). Click on the new sequence icon and a file browsing dialog will open. Select the sequence COLLADA file you want. Now define the time range that you want by changing the numbers at the beginning and end of the timeline. Complete this process for each sequence that you wish to add.
Optionally you can define an object called “BOUNDS” that can be used to define the object's origin (as opposed to your 3d content application’s origin) and is used to define the speed that the object is intended to be moving at. Such as during a run sequence, if you had a character running forward at 1 meter a second in your 3d application’s scene and had the “BOUNDS” object follow your character then when you bring it into Torque 3D and assigned to the player’s run animation then the playback speed of the animation can be adjusted depending on the speed that the player is moving through the game world. What this means is that animations don’t have any sliding issues caused by the character's in game speed not matching with the designed animation speed.
Currently, the player's hitbox defined by their bounding box. In order to get damage locations we have cut the player's world box up into pieces as defined by the following sections in the Player's datablock:
boundingBox
boxHeadPercentage
boxTorsoPercentage
boxHeadLeftPercentage
boxHeadRightPercentage
boxHeadBackPercentage
boxHeadFrontPercentage
The player's boundingBox determines the length in each dimension the bounding box should encompass. From the standard player datablock, its sections would look like the following:
It may be easiest to come up with these numbers by taking a render of the player, and using an imaging program to determine what percentage of the player makes up their legs/head/torso.
In order to take advantage of these damage locations we use the function Player::getDamageLocation(). One of the best places to call this is from the Projectile:onCollision or Armor::Damage() as we'll have the position of the projectile, the player to call getDamageLocation() and a good place to modify the damage if we wanted to do extra damage on a headshot or less damage to the legs.
GetDamageLocation() will return a string using the defined boundingbox percentages from the player datablock. In C++ it more or less transforms the projectile's location form world space to object space, multiplies the player's bounding box by its percentages, then checks to see if the hit location is greater than, or less than the bounding box dimension multiplied by the percentage. For example, if the bounding box's dimension was 1, it will multiply 1 by 0.43, and check if the bullet's location is less than or equal to this value. If it's less than the torso, then it counts as a leg shot. The system then does the same test in the other dimensions to see if the front/back or left/right was hit.
The string returned will be one of the following:
Possible locations:
legs
torso
head
Head modifiers:
left_back
middle_back
right_back
left_middle
middle_middle
right_middle
left_front
middle_front
right_front
Legs/Torso modifiers:
front_left
front_right
back_left
back_right
For example, a perfect headshot would be “head_middle_front”, head_middle_back, or “head_middle_middle”. A shot to the front left leg would be “legs_left_front”.
As we can see in the picture, there are situations where we can register a hit from the headbox that actually wouldn't “hit” the player. Such as shooting a bullet in the boxHeadRightPercentage area from the front of the player would fly over the player shoulder, but register a hit in the engine. It may be necessary to do some math to see if the bullet will actually pass through the center of the player's head box to get realistic results.
This page will describe how to create a simple 3d asset in Blender3D and bake all textures to an ORM map for use in Torque 3D
Before we get started we need to setup a few things in Blender.
First go to Edit Preferences -> Add-ons and Enable the Node Wrangler addon
Then go to System and make sure you are setup properly for rendering in cycles
Next save your preferences and close the preferences window.
After this head to the render tab and setup the render settings as follows
Clear your scene and save this file in your Modules Shapes folder (if a shapes folder does not exist yet create one )
For this tutorial we are going to create a simple coin shape.
Add a cylinder
Scale it along the Z axis with S + Z and then apply the scale with Ctrl + A and select Scale.
Rotate the cylinder by 90 degrees on the X Axis so one of the faces at the top are now facing along the positive Y Axis by pressing R + X + 90
Next press TAB to enter edit mode, switch to face edit by pressing 3 or selecting the face symbol at the top . Select and delete the 2 faces.
Next switch to edge edit mode and press Alt and select anywhere in the edge left by deleting those face. Press Ctrl + F and select Grid Fill.
Repeat for the other side.
To finish off our modelling phase, right click the object and choose Auto Smooth.
Next navigate to the top corner and drag over a new window and open up the UV Editor. Be sure to turn on UV Sync Selection
You should see a similar layout to this.
Press the Y axis on the view gizmo so we are looking straight down the Y Axis
Next select all the faces created by the Grid Fill and Press U to unwrap. Select Project from view.
A new selection should appear in the UV Editor window. Move this selection and scale it so it fits in the bottom left corner of our uv space like so.
Repeat this procedure for the other side so you end up with something similar to this
Next Select the Faces in the UV editor for the side of our cylinder and select the top menu UV and choose Average Island Scale
Scale these UVs now to fit inside our UV Space.
Now we can TAB out of edit mode and go to the materials tab.
Add a new material and name it coin_Mat
Next set our 3D Viewport to viewport shading and change our UV Editor window to the Shader Editor
In Torque, Materials (note capital M) are TorqueScript objects that define properties used when rendering a surface. Each Material object is mapped to a single material (note lowercase m) target. These targets are the names of the materials defined in the model itself (DTS, DAE etc), and are usually the same as the material names in the application that exported the model.
For example, a model containing a single material target soldier might have a Material defined as follows:
singleton Material( Mat_Soldier ) // Object name is arbitrary (though must be unique)
{
mapTo = "soldier"; // This is the material target name
diffuseMap[0] = "soldier_armor.jpg"; // Texture name is arbitrary
};
For Materials that consist of only a diffuse texture, the Material object definition can be omitted entirely and Torque will automatically create and map a simple Material. For this to work, the diffuse texture must be in the same folder as the model, and must have the same name as the material target. In this case, the diffuse texture would have to be named soldier.png (extension is not important, only the base filename).
Torque's Material system requires artists to be careful when naming materials in their modeling application prior to export; any models that share the same material target names will also share the same script Materials.
Target names are also important if the model is to support skin swapping.
There are two ways to change the Materials used by a model. The first is by remapping the Material object itself (ie. changing the 'mapTo' field). This will change the mapping for all models that use that material target. This is most easily done in the Material Editor; just select the shape and target to swap and choose a new Material using the Material Selector GUI .
Generally this is only done during level editing and is not the recommended way to dynamically change Materials on an object at runtime.
Skinning
IFL (image file list) and UV keyframed animations are deprecated in Torque 3D, but in most cases you can achieve an equivalent effect using Torque 3D animated materials.
UV animation
Simple UV animations can be achieved using the Rotate, Scroll and Wave animation features of Torque 3D Materials. The best place to experiment with these settings is in the Material Editor.
UV Rotate
UV Scroll
UV Wave (Scroll)
UV Wave (Scale)
Image Sequence animation
Earlier Torque engines used IFL text files to specify a set of images with an optional number of frames to display each image. In Torque 3D, a similar effect can be achieved by putting all of the frames into a single texture, then setting the sequenceFramePerSec and sequenceSegmentSize fields of the Material (either manually, or via the Material Editor). For example, a 6-frame sequence, each frame sized 128x128 would be packed into a single texture of size 768x128.
The Material definition to display each frame for 1 second is shown below:
singleton Material(
{
diffuseMap[0] = "art/shapes/examples/image_sequence";
sequenceSegmentSize = 1 / 6; // 1 / numFrames
sequenceFramePerSec = 1;
};
There are two options available when UV mapping the model prior to export; neither work with tiled UVs.
UV map a single frame within the packed texture, and do not set the Scale bit in the Material animFlags. In the packed texture above, the U coordinate would be from 0.0 - 0.167. With this approach, the same packed texture can be used for UV mapping, however, the model will need to be remapped to change the number of frames in the sequence.
UV map the texture of a single frame only (or the entire packed texture), and set the Scale bit in the Material animFlags. In this case, the U coordinate would be from 0.0 - 1.0, and will be automatically scaled by Torque 3D to match the size of each frame in the packed texture. The advantage of this approach is that the number and size of the frames can be changed (by editing the texture, and modifying the Material parameters accordingly) without having to remap the model UVs. Note: If you map the full 0.0-1.0 UV range but forget to set the Scale animFlag bit, the material will appear to scroll instead of flip between the image frames.
The SimObject "Simulation Object" is the most basic class used in Torque and TorqueScript. It implements all of the functionality for an object to "exist" in both C++ and in script (in the Console). You'd generally always subclass SimObject rather than it's superclasses ConsoleObject
and EngineObject
.
In TorqueScript, all you have to do when you create a new object is calling the new
operator.
$obj = new SimObject() {
someDynamicVariable = "2.0";
};
However, this is actually a three-step process behind the scenes which becomes evident if you try to create a SimObject in C++.
// Step 1 - Initialize the object
SimObject* obj = new SimObject();
// Step 2 - Apply the fields inside the initializer
obj->setFieldValue("someDynamicVariable", "2.0");
// Step 3 - Call "registerObject"
obj->registerObject();
Registering a SimObject performs these tasks:
Marks the object as not cleared and not removed.
Assigns the object a unique SimObjectID if it does not have one already.
Adds the object to the global name and ID dictionaries so it can be found again.
Calls the object's onAdd() method. Note: SimObject::onAdd() performs some important initialization steps. See here for details on how to properly subclass SimObject.
If onAdd() fails (returns false), it calls unregisterObject().
Checks to make sure that the SimObject was properly initialized (and asserts if not).
Calling registerObject() and passing an ID or a name will cause the object to be assigned that name and/or ID before it is registered.
There are a two ways a SimObject can die.
First, the game can be shut down. This causes the root SimGroup be unregistered and deleted. When a SimGroup is unregistered, it unregisters all of its member SimObjects; this results in everything that has been registered with Sim being unregistered, as everything registered with Sim is in the root group.
Second, you can manually kill it off, either by calling unregisterObject() or by calling deleteObject().
When you unregister a SimObject, the following tasks are performed:
The object is flagged as removed.
Notifications are cleaned up.
If the object is in a group, then it removes itself from the group.
Delete notifications are sent out.
If you call deleteObject(), all of the above tasks are performed, in addition to some sanity checking to make sure the object was previously added properly, and isn't in the process of being deleted. After the object is unregistered, it deallocates itself.
In Torque3D, SimGroup
objects are used to organize and manage collections of other objects in the game engine. They act as containers for other objects, allowing developers to group objects together and manipulate them like an array.
SimGroup
objects are special objects in Torque3D that act as a container for other objects. By creating a SimGroup
object, developers can group together any number of other objects and manage them as a single entity. This allows for better organization of objects in the game engine and provides a convenient way to perform operations on groups of objects.
To use a SimGroup
object, you first need to create an instance of the SimGroup
class, either through script or through the World Editor. Once you have a SimGroup
object, you can then add other objects to it as child objects.
To add a child object to a SimGroup
object, you can use the add
method, as follows:
%group.add(%childObject);
where %group
is the SimGroup
object and %childObject
is the object you want to add as a child.
To remove a child object from a SimGroup
, you can use the remove
method, as follows:
%group.remove(%childObject);
where %group
is the SimGroup
object and %childObject
is the child object you want to remove.
You can also use the clear
method to remove all child objects from a SimGroup
object:
%group.clear();
Using SimGroup
objects in Torque3D provides several benefits, including:
Improved organization of objects in the game engine.
The ability to manipulate groups of objects as a single entity, making it easier to perform operations on multiple objects at once via utility functions like callOnChildren().
In Torque3D, SceneObject
is the base class for all objects that exist in a 3D scene. It provides a number of features and functions that can be used to create objects with specific behaviors and characteristics.
A SceneObject
is a type of object in Torque3D that represents a 3D object in a scene. It is the base class for all objects that exist in a scene and provides a number of features and functions for controlling the position, orientation, and other properties of objects.
SceneObject
objects have several key features, including:
Position and orientation: The SceneObject
class provides properties for controlling the position and orientation of objects in the scene. This allows you to control the position of objects relative to one another and determine how they are facing.
Transformation: The SceneObject
class provides functions for transforming objects in the scene, including translation, rotation, and scaling.
Collision detection: The SceneObject
class provides functionality for detecting collisions between objects in the scene. This allows you to create objects that can interact with one another in meaningful ways.
A scene graph (in the Zones and Portals sections), allowing efficient and robust rendering of the game scene.
Various helper functions, including functions to get bounding information and momentum/velocity.
Lighting: SceneObjects can register dynamic lights at runtime (for special effects, such as from flame or a projectile, or from an explosion), or scene lighting such as the sun.
To use a SceneObject
in Torque3D, you need to create an instance of the SceneObject
class, either through script or through the Torque3D World Editor. While you cannot create a SceneObject directly, all spawnable object types are derived from SceneObject and can be used similarly. Once you have a SceneObject
object, you can use its properties and functions to control its behavior and characteristics.
For example, to set the position of a SceneObject
in the scene, you can use the setPosition
method, as follows:
%object.setPosition(%x, %y, %z);
where %object
is the SceneObject
object, and %x
, %y
, and %z
are the x, y, and z coordinates of the object's position.
To rotate a SceneObject
in the scene, you can use the rotation
variable, as follows:
%object.rotation = %x SPC %y SPC %z SPC %angle;
where %object
is the SceneObject
object, and %x
, %y
, and %z
are the x, y, and z rotation axis for the object, and %angle
is the applied angle on the axis.
In Torque3D, Datablocks
are a way to store data that can be shared among multiple instances of a class. They allow you to define common properties and behaviors that can be shared by multiple objects, making it easier to manage and maintain your objects in a scene and minimizing data duplication and networking overhead.
A Datablock
is a type of object in Torque3D that stores data that can be shared by multiple instances of a class. They are defined as separate objects from the objects that use them, and they contain data that can be used by multiple instances of a class to define their properties and behaviors.
Datablocks
have several key features, including:
Reusability: Datablocks
can be used by multiple instances of a class, which makes it easier to manage and maintain your objects in a scene. You can define a Datablock
once, and then reuse it for multiple instances of a class, which saves time and reduces the risk of errors.
Flexibility: Datablocks
can be changed, and the changes will be reflected in all instances of a class that use the Datablock
. This allows you to make global changes to the properties and behaviors of objects in your gane, without having to make changes to each object individually.
Performance: By using Datablocks
, you can reduce the amount of memory and processing power required to manage and maintain your objects in a scene.
Networking: Because Datablocks
are sent from server to client, the game can be assured that the client has the same data as the server. Additionally, because they're sent during initial connection, it's data that doesn't need to be re-sent during normal network updates, keeping data transmission as low as possible.
To use a Datablock
in Torque3D, you need to create a Datablock
object and define its properties. Then, you can reference the Datablock
from multiple instances of a class to share its properties and behaviors.
For example, let's say you have a Player
class, it has a variable, health
, that can be used for all instances of the Player
class. To use this, you would create a PlayerDatablock
object, and define the health property. Then, you would reference the PlayerDatablock
from each instance of the Player
class to share its health property.
datablock PlayerDatablock(PlayerDB)
{
health = 100;
};
// Use the datablock for the player
%player = new Player() {
datablock = PlayerDB;
};
In this example, the PlayerDatablock
object is defined with a property named health
, which is set to 100. The Player
class references the PlayerDatablock
by calling the setDatablock
method and passing in the PlayerDB
object.
For a breakdown of how to create your own classes utilizing datablocks, you can go to this page: