turbotutone Posted May 10, 2014 Share Posted May 10, 2014 Creating and Manipulating World Objects Seen questions pop a few times regarding placing objects on the map so decided to make a little tutorial on it. Most of the tutorial is written in a single file included in a mod you can download below. The code is commented so you can see whats going on. I recommend loading the lua file in your favorite editor and starting a custom game without zombies with the mod activated in windowed mode so you can play with the mod ingame and read the stuff in the lua file. How it works?The mod allows you to place a red cube on a empty tile, every time you click that tile again the code will do some stuff with the object, you can all see it in the code comments. Target audience.The mod is written for beginning modders, however it might be that there's some stuff useful for more experienced modders here and there. You'll have to judge it yourself. Code.The code is written so that one can follow the tutorial line by line, as such it does not reflect proper implementation but rather serves as a showcase of things you can do and implement properly yourself. You can also build uppon the code supplied in the mod to use it as a testbase for experimenting with objects and their methods. I suggest also digging in TIS lua files regarding buildable objects and their context menu's. About sprites.To create a graphic for your object you'll need to make a transparent image of 64 width and 128 height. This covers one tile and one layer of height in the game.Included in the mod are a few sprites, i suppose you could use "cube_floor.png" as a template: About java.It's highly recommended you have some way of looking up java source classes & methods. The javadocs can be used, personally i've used JDGUI up until now. With JDGUI you can open any class file in <root>/zombie/ directory and it opens up the entire project space as such: Many of these classes are made available in lua to work with. Often they require to be constructed first. To do so you can look up the constructors:In lua you'll have to use the 'new' method like so:local myObj = IsoObject.new("parameters here");By matching the set of parameters in .new() to the ones found in the java constructors you can call the appropriate one. All other methods can then be called on that instance of the IsoObject like so:myObj:setSprite("test");local sprite = myObj:getSprite();The lua file for reference--[[ World Object Tutorial by TurboTuTone--]]-- table with names related to textures.-- full path: media/textures/cube_<spriteName>.pnglocal spriteNames = { "green", "red", "blue", "purple", "yellow", "plain", "overlay", "floor",}local function maskLoad( _path ) local tex = getTexture( _path ); tex:createMask( tex:getData() ); return tex;endCubes = {};Cubes.sprites = {};Cubes.LoadTextures = function() for _,name in pairs(spriteNames) do Cubes.sprites[name] = {}; Cubes.sprites[name].path = "media/textures/cube_" .. name .. ".png"; Cubes.sprites[name].tex = maskLoad( Cubes.sprites[name].path ); endend-- this function gets called with event: OnLoadedTileDefinitions-- this events triggers before the map data is loaded and supplies spritemanager which you have to use instead of getSprite.Cubes.LoadSprites = function( _sprMngr ) for _,t in pairs(Cubes.sprites) do print(t.path); t.sprite = _sprMngr:getSprite(t.path); endend-- Main function of interest, linked to mouseup event.Cubes.doSquare = function( _x, _y ) -- convert mouse coordinates to world. local mX, mY = ISCoordConversion.ToWorld(getMouseX(), getMouseY(), 0); mX = math.floor( mX ); mY = math.floor( mY ); -- get the cell local cell = getWorld():getCell(); -- get grid square (tile) local sq = cell:getGridSquare(mX, mY, 0); -- get list of objects on square local objs = sq:getObjects(); -- get size of list local objs_size = objs:size(); print("Objecs on square:", objs_size) -- if there are no objects on the gridsquare (counts 1 for tile), place red cube. if objs_size <= 1 then --[[ RED CUBE --]] print("Adding RedCube"); -- create instance of object with redquare sprite local obj = IsoObject.new(cell, sq, Cubes.sprites.red.sprite); -- set the objects name. obj:setName("RedCube") -- add object to square sq:AddTileObject(obj); else -- if there are objects, see if we can find cubes to do stuff with. for i=objs_size-1, 0, -1 do if objs:get(i):getName() == "RedCube" then --[[ GREEN CUBE --]] -- we found red cube, lets remove it and place a green objs:remove(i); -- create new instance of isoobject with greenquare sprite local obj = IsoObject.new(cell, sq, Cubes.sprites.green.sprite); -- set the objects name obj:setName("GreenCube"); -- add object to square sq:AddTileObject(obj); -- we are done, break break; elseif objs:get(i):getName() == "GreenCube" then --[[ PURPLE CUBE --]] -- found green cube, changing its sprite and name to purple local obj = objs:get(i); -- change sprite obj:setSprite( Cubes.sprites.purple.sprite ); -- set the objects name obj:setName("PurpleCube") -- we are done, break break; elseif objs:get(i):getName() == "PurpleCube" then --[[ RANDOM COLORED CUBE --]] -- found purple cube, lets change texture to plain to play with tintmods local obj = objs:get(i); -- change sprite obj:setSprite( Cubes.sprites.plain.sprite ); -- set the objects name obj:setName("PlainCube"); -- the plain cube is a white schemed version so we can apply tintmod on the object to randomize its color. -- make a tintmod local customcol = ColorInfo.new( ZombRand(100)/100, ZombRand(100)/100, ZombRand(100)/100, 1.0 ); -- apply tintmod to object obj:setCustomColor(customcol); -- we are done, break break; elseif objs:get(i):getName() == "PlainCube" then --[[ BLUE CUBE (with white dots overlay sprite) --]] -- found plain cube, remove it objs:remove(i); -- adding blue cube local obj = IsoObject.new(cell, sq, Cubes.sprites.blue.sprite); -- set the objects name obj:setName("BlueCube"); -- in this section we add a sprite to the objects childsprite list, the childsprites are drawn over the -- object, first in the list gets drawn first etc. Ingame childsprites are for example smudges on walls. -- get the childsprite arraylist, if none found create one local childList = obj:getChildSprites() or ArrayList.new(); -- get a spriteinstance of the overlay sprite local overlay = Cubes.sprites.overlay.sprite:newInstance(); -- add it to the childsprite list childList:add( overlay ); -- set childsprites to object obj:setChildSprites( childList ); -- add object to square sq:AddTileObject(obj); -- we are done, break break; elseif objs:get(i):getName() == "BlueCube" then --[[ YELLOW CUBE --]] -- found blue cube, remove it objs:remove(i); -- A thing you can do with sprites is set properties, for example we can make it function like a bed. -- zombie/iso/SpriteDetails/IsoFlagType.class -- try right clicking the yellow cube, youll notice you can use it to sleep. -- get the yellow sprite (IsoSprite) local yellow = Cubes.sprites.yellow.sprite; -- get property container local props = yellow:getProperties(); -- Set the bed flag props:Set( IsoFlagType.bed ); -- set property container yellow:setProperties( props ); -- creating yellow cube -- until now the player has been able to pass through our object -- we create it as IsoThumpable this time which allow us to use some additional functionallity. local obj = IsoThumpable.new(cell, sq, Cubes.sprites.yellow.path, true, {}); -- set the objects name obj:setName("YellowCube"); -- block all the square, i suspect this is to block it for pathfinding/item placement? not sure obj:setBlockAllTheSquare(true); -- make it unable to pass through obj:setCanPassThrough(false); -- NOTE: this object is added as special object, otherwise the block and passthrough settings wont work. sq:AddSpecialObject(obj); -- we are done, break break; elseif objs:get(i):getName() == "YellowCube" then --[[ REMOVAL --]] -- found yellow cube, remove procedure. local obj = objs:get(i); -- since last object was added as special object, remove it from objects & special objects list. sq:getSpecialObjects():remove(obj); sq:getObjects():remove(obj); break; --[[ That's it. You could modify this piece of code to add more objects and/or play around with more stuff you find in the java. It's allot of fun experimenting with objects and theres loads of stuff to be found not yet covered in this tutorial. Good luck! Important java classes to investigate: - zombie/iso/IsoGridSquare.class - zombie/iso/IsoObject.class - zombie/iso/objects/*.class (all these extend IsoObject) - zombie/iso/sprite/IsoSprite.class - zombie/iso/SpriteDetails/IsoFlagType.class - zombie/iso/SpriteDetails/IsoObjectType.class --]] end end endendCubes.GameStart = function() Events.OnMouseUp.Add(Cubes.doSquare);endEvents.OnLoadedTileDefinitions.Add(Cubes.LoadSprites);Events.OnGameStart.Add( Cubes.GameStart );Events.OnGameBoot.Add( Cubes.LoadTextures ); Download Regards,Turbo Viceroy, Dr_Cox1911, Sieben and 4 others 7 Link to comment Share on other sites More sharing options...
Viceroy Posted May 10, 2014 Share Posted May 10, 2014 Very useful Turbs, me likey. Link to comment Share on other sites More sharing options...
Ivan Posted July 2, 2014 Share Posted July 2, 2014 I am trying this tutorials method. The object is added, and detected. However it is not showing up graphically. -----------------------------------------STACK TRACE-----------------------------------------Callframe at: getDatafunction: maskLoad -- file: SecureContainer.lua line # 20function: loadTextures -- file: SecureContainer.lua line # 38function: onLoadedTileDefinitions -- file: SecureContainer.lua line # 120java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at se.krka.kahlua.integration.expose.caller.MethodCaller.call(MethodCaller.java:61) at se.krka.kahlua.integration.expose.LuaJavaInvoker.call(LuaJavaInvoker.java:199) at se.krka.kahlua.integration.expose.LuaJavaInvoker.call(LuaJavaInvoker.java:189) at se.krka.kahlua.vm.KahluaThread.callJava(KahluaThread.java:181) at se.krka.kahlua.vm.KahluaThread.luaMainloop(KahluaThread.java:981) at se.krka.kahlua.vm.KahluaThread.call(KahluaThread.java:162) at se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1721) at se.krka.kahlua.vm.KahluaThread.pcallvoid(KahluaThread.java:1666) at se.krka.kahlua.integration.LuaCaller.pcallvoid(LuaCaller.java:53) at se.krka.kahlua.integration.LuaCaller.protectedCallVoid(LuaCaller.java:81) at zombie.Lua.Event.trigger(Event.java:37) at zombie.Lua.LuaEventManager.triggerEvent(LuaEventManager.java:83) at zombie.iso.IsoWorld.init(IsoWorld.java:979) at zombie.gameStates.GameLoadingState$1.run(GameLoadingState.java:237) at java.lang.Thread.run(Thread.java:724)Caused by: java.lang.RuntimeException: No OpenGL context found in the current thread. at org.lwjgl.opengl.GLContext.getCapabilities(GLContext.java:124) at org.lwjgl.opengl.GL11.glGetTexImage(GL11.java:1637) at zombie.core.textures.TextureID.getData(TextureID.java:325) at zombie.core.textures.Texture.getData(Texture.java:705) ... 19 more[Z cannot be cast to [Ljava.lang.Object;Is the console output I see. *EDIT* Fixed. Was calling loadTextures in OnLoadedTileDefinitions instead of OnGameBoot turbotutone 1 Link to comment Share on other sites More sharing options...
turbotutone Posted July 2, 2014 Author Share Posted July 2, 2014 Hehe yes that loadtextures function is a bit ugly, only used to set masks perhaps theres a better way to do this for single file sprites...Anyhow, youre probably better of using texturepacks. EasyP recently added a tut on how to set them up:http://theindiestone.com/forums/index.php/topic/8790-custom-texture-packs-and-tile-definitions/ With a texture pack for example you could put all the cubes in one tilesheet, that automatically loads the masks properly and the bonus is that you can set some properties for the sprites in the editor which might come in handy if you need those. instead of grabbing the sprites with:getTexture( "media/textures/cube_red.png" );with a texture pack you grab them like the game sprites, say if your sheet is called "cubes" its that plus "_indexnumber".getTexture( "cubes_0" );Regards,Turbo Ivan 1 Link to comment Share on other sites More sharing options...
Ivan Posted July 3, 2014 Share Posted July 3, 2014 Thanks! I saw that method of loading sprites earlier this morning when trying to make a build menu that fit in structure with the current lua build menus. Once I get more familiar with the innards of this game I'll definately branch out on the art front. For now Im just using the same texture everywhere Link to comment Share on other sites More sharing options...
Dr_Cox1911 Posted March 15, 2016 Share Posted March 15, 2016 How can I spawn anything on a cell that is not loaded? I try to spawn a crate, here is my test-code so far: CLDmain = {}; CLDmain.spawnCrate = function() local mX, mY = ISCoordConversion.ToWorld(getMouseX(), getMouseY(), 0); mX = math.floor( mX ); mY = math.floor( mY ); --mX = 11795; --mY = 6671; -- get the cell local cell = getWorld():getCell(); -- get grid square (tile) local sq = cell:getGridSquare(mX, mY, 0); -- get list of objects on square local objs = sq:getObjects(); -- get size of list local objs_size = objs:size(); print("Objecs on square:", objs_size) -- if there are no objects on the gridsquare (counts 1 for tile), place red cube. if objs_size <= 1 then -- create instance of object with redquare sprite local obj = IsoCrate.new(cell, sq, 8989); -- add object to square sq:AddSpecialTileObject(obj); end end CLDmain.GameStart = function() Events.OnMouseUp.Add(CLDmain.spawnCrate); end Events.OnGameStart.Add( CLDmain.GameStart ); It spawns something, but I can´t see it. Just notice it when I run around and suddenly can´t run any further (hitting the crate I suppose). Link to comment Share on other sites More sharing options...
ShuiYin Posted March 16, 2016 Share Posted March 16, 2016 i tried the mod in this topic but its broken. I really hope this gets updated or fixed since this is very helpfull in teaching us how to mod Link to comment Share on other sites More sharing options...
Dr_Cox1911 Posted March 16, 2016 Share Posted March 16, 2016 Do you mean the exception in line 21 that get´s thrown after activating the mod? After restarting the game the mod works fine, just not very accurate with the mouse coords (cubes spawn anywhere near the player, not where you clicked). I skimmed the class files some more and kinda found my first problem, with "getWorld():getCell()" I only get the current loaded cell. I didn´t find anything that let´s me get a specific cell (e.g. getCell(_x. _y)). Hm, kinda lost right now. What I also don´t quite understand is the last parameter from "IsoCrate.new((IsoCell cell, IsoGridSquare gridSquare, int gid)", I reckon the "gid" is a global ID, but how would I guess which gid is still available? So many questions, so little knowledge Link to comment Share on other sites More sharing options...
ZombiesLoveBrainiacs Posted March 16, 2016 Share Posted March 16, 2016 3 hours ago, Dr_Cox1911 said: just not very accurate with the mouse coords (cubes spawn anywhere near the player, not where you clicked). this is because it wasn't possible to zoom at the time. At a certain zoom level, the objects appear where they're supposed to. You'd have to factor in the current zoom level when getting the tile to fix this. Link to comment Share on other sites More sharing options...
ZombiesLoveBrainiacs Posted March 16, 2016 Share Posted March 16, 2016 18 hours ago, Dr_Cox1911 said: -- create instance of object with redquare sprite local obj = IsoCrate.new(cell, sq, 8989); What's "8989"? Your sprite name is supposed to go in there - and you gotta load the sprite before using it. Link to comment Share on other sites More sharing options...
wintermuteai1 Posted March 16, 2016 Share Posted March 16, 2016 (edited) I've been experimenting with this too and in mine changed it to only spawn the yellow bed block as I want to create sleeping bags, unfortunately I cannot figure out how to have this be an inventory item and be able to drop it and sleep on it. As well I do not like the line 21 error when exiting the game. It would be really nice if the devs would put together some tutorials on how to create a completely custom item and be able to assign it a property while using a custom image like in this old tut but without the errors. I'm looking at the camping tent code to see how it was done there but this is all very frustrating... Edited March 16, 2016 by wintermuteai1 Geras 1 Link to comment Share on other sites More sharing options...
Dr_Cox1911 Posted March 17, 2016 Share Posted March 17, 2016 On 16.3.2016 at 6:31 PM, ZombiesLoveBrainiacs said: What's "8989"? Your sprite name is supposed to go in there - and you gotta load the sprite before using it. I don´t think so. If you look at the constructor for the IsoCrate it has only one with just the cell in it and another one with a mysterious Integer named "gid". 8989 is just a random number, didn´t find a way to retrieve a valid gid (whatever that gid is). Or is a loaded sprite just a Integer (seems kinda strange, from my experience it should be some kind of pointer to the actual sprite/tex). Just for clarification: I can spawn the blocks just fine, so the IsoObject is working, just can´t get the IsoCrate to show. Link to comment Share on other sites More sharing options...
Morry Posted October 27, 2017 Share Posted October 27, 2017 Calling the 'new' method seems to only work in debug mode now... Link to comment Share on other sites More sharing options...
Rubix3 Posted June 17, 2018 Share Posted June 17, 2018 Great tutorial! Helped me dip my toes in and get started on my concept and idea! Having a small issue though, or concern/wondering... Creating my World Object works wonderfully - but it does not persist between world loads? is there any reason for this. Second, the objs:remove(i) doesnt ever work for me Code: objs = sq:getObjects() objs_size = objs:size(); for i=objs_size-1, 0, -1 do local _shaft = objs:get(i); --get the object itself. if(tostring(_shaft:getName()) == 'AMC_Transporter') --is it this kind of object? objs:remove(i) --*** does not seem to work? *** else --I do some logic, maybe manipulate the object - primarily just setting the Table (setTable()) end end the logic is all sound, no errors, no issues, everything else works. except the remove(i) on objs (again no errors). Can anyone explain why? Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now