Jump to content


  • Posts

  • Joined

  • Last visited

Everything posted by TorqueFan

  1. No problem. It's tutorials and resources like this that inspire others in the community to follow suit. As usual, I'm staying pretty busy lately but I DO plan on releasing a whole heap of resources when I'm closer to a 'relaxing' period. I've got all sorts of goodies to share, if only I could find time to get it all uploaded... Ah yes, I remember that about your scripts now! For my purposes, though, it's a bit harder in this regard since all the AI will spawn in groups randomly about the map. All of it will need to happen on the server's end, probably by use of Events or something...not really sure, hadn't tackled that fully just yet =)
  2. Just wanted to post here and give a big "Thank you" to Richard for this and all of the works he's shared in the past. I remember when you mentioned this AI stuff in a post a while back ( might have been the old GG boards ) and I've studied the scripts a lot since then. I've built other systems with Managers and so on based off of the concepts put in place here - using a 'Manager' to add/remove objects or even entire new SimGroups! In case you've forgotten the details, one of the best additions you made was the 'throttling' of AI think routines based on the AI's proximity to Players. Basically making the AI call a think() function but only when Players were near enough. Otherwise, it could go into a 'sleep' mode and not waste any precious resources thinking about nothing =) The biggest thing here is the 'when Players are near enough' bit. It's been awhile since I've looked at that stuff, but I think what needs to happen is this: Server keeps a list of SpawnSpheres.If a Player gets within range of a SpawnSphere, set an 'awake' flag to true on the SpawnSphere. Have a ScriptTickObject( or something similar, anything that 'ticks' ) that constantly runs a function iterating the list of SpawnSpheres searching for 'awake' flags. For each one that's awake, activate the think() routine for the spawned AI belonging to that SpawnSphere. Could have an early out in the function so it won't do the iterations if none are awake( or even not run the function in the first place ). Just thinking out loud but that's a direction I was looking into going soon. In my current project, I am VERY near to setting up AI spawnGroups, think functions, and so on. I will be revisiting this stuff and use it much as a reference guide while building the map's AI. It is likely that I could end up porting those Managers you speak of and if that happens I will definitely let you know =) I do agree that with the Sim lookups going on it could be in the best interest of the resource. For my goals the largest obstacle is figuring out how to approach the adding/removing of the AI units as Players travel across the rather large map. Currently I plan to use the actual Manager object already in Torque ( the one that fires off NetEvents ) that will activate SpawnSpheres - all based on distance from the Player object. Maybe it'll work, maybe it won't?
  3. @Jolinar Man thank you! This exporter right here just saved me so much time! I had a very case-specific issue importing certain meshes attached to a rig from Blender to Torque. The problem was the sub-meshes had multiple modifiers in the stack ( i.e. mirror, armature, etc. ) and upon import into Torque some of the meshes could distort when animating. Anyhow, with this tool I was able to export the Armature data separately and all of the modifier data was properly preserved!! Looking at hooking in 100's of animations across several meshes, this is a must have for me right now! Thank you so much for posting!
  4. This can be a very long and involved path to travel down, especially if this is planned to be a multiplayer world. Personally I pursued this very goal off and on for a couple years. I spent a month here there discovering exactly why Torque seemed to choke on a world filled with geometry that the rendering code has no problem chewing up and spitting out. I did finally find a couple solid solutions, neither of which I consider 'easy' to implement. As all things Torque, a solution for any given project is going to require taking it by the horns, wrestling it down, and beating it to submission. The first thing you're going to find is the biggest cause of performance drop is the network ghosts. Run your mission, push 'N' and then watch your active ghost count go up when you add the statics. As it goes up, your performance goes down. This is because Torque has a client and a server active on your machine and actually ghosts client versions of the data you change in the mission. You are correct to assume an object to hold many sub-objects can be helpful - but only to a certain degree, depending on the ultimate goal. I ended up creating a class from scratch that rendered out several mesh cubes within one object by building all the vertexBuffer data manually in engine functions. In my case the whole thing was cubes, so I could specify the grid size, had the whole she-bang using multiple indexed materials (for different faces and extended player class footstep sounds), much neighbor detection code, added EngineFunctions, Callbacks... altogether the code for that class is spread out across about 9 or so new engine files =) On top of all of that, I hadn't mentioned the most important part: back to networking. Even in a singleplayer mission, the way that Torque is going to handle adding and removing objects from the scene is going to impact performance if you aren't careful about how you handle the ghosts. Exactly how to handle the ghosts is a huge can of worms that can be dissected in several ways( again, each solution is going to be project specific of course ). I wrote NetEvent code for my 'object of many objects' that would allow users to send and receive data only about the 'sub-object' within the main object when adding/removing blocks. After all that's ironed out, you'll want to be considering how all of those objects are going to be ghosted / unghosted from each client depending on distance from that object. Can't stress enough how many different ways this can be approached, but more recently I've found a system similar to the existing TerrainCell or ForestCell engine code( don't quote me on exact names! ) can be extremely effective if you're willing to fight the dragon there. He's a bit scary, but a solid attempt at making custom functions that hook into those indexes could be a good solution. About mounting, depending on how many objects are being attached to build things it could be required the mount code be extended a bit. There are resources out there on this iirc. A bit of work moreso with models and adding the proper mount0, mount1 nodes etc. I hadn't done much testing with the effect of mounted objects on ghosting and so on but it could be worth a look =) Anyhow, perhaps some information here is helpful, I wish you luck with Torque!
  5. @Timmy - Wanted to post just to say thanks a lot for tackling this. I look forward to seeing this completed!
  6. Thanks man, I'll try to get around to this before vacation next week ;)
  7. Of course the nodes are 'supposed' to use node IDs!!! That's why I commented specifically that it still isn't 100% 'correct'... My reference to using a string above served to illustrate that, for whatever reason, it doesn't matter which ID or String you use(which you shouldn't). In any case, the camera will mount to a generic position to the Player. I'll quote myself: See, no matter which mount0, mount1 node I mount the camera to it will result in the same transform for the camera as if I named the node with a string(which again technically shouldn't be possible). But, no matter, it works as intended for my purposes. If I get some time this week, I'd be more than happy to PR it but will need to be sure I can do it properly since I hadn't had to do a PR before :)
  8. Okay, I have tracked down a fix for the issue. Credit goes to Adam Beer for spotting the problem area and starting to fix it, and Ivan Mandzhukov for ultimately solving it. In this thread Adam and Ivan unknowingly solved the bulk of this problem while tuning the camera for a different purpose. I didn't have to do any heavy lifting, really, just mainly some detective work and then I cleaned up the code and updated the 'delta' variable. Basically this code allows the camera to be rotated instead of just hitting the if(isMounted()) statement and having the transform explicitly set without taking any pitch or yaw into account. I've tested this code with a tiny view distance of 10, orbitCamera, and the camera mounted to the Player. Gloriously enough the Player can travel freely taking the camera with him while scoping within viewDistance correctly. • In camera.cpp find the processTick(). Within this function, replace the isMounted() bit with: if (isMounted()) { MatrixF mat; VectorF rotVec(0, 0, 0); if (move) { rotVec.x = move->pitch; rotVec.z = move->yaw; mRot.x += rotVec.x; mRot.z += rotVec.z; } MatrixF xRot, zRot, fmat; xRot.set(EulerF(rotVec.x, 0, 0)); zRot.set(EulerF(0, 0, rotVec.z)); // let's combine the euler rotation fmat.mul(zRot, xRot); // this will pull the transform and translate to world space // we need only the world position,we discard rotation values mMount.object->getMountTransform(mMount.node, mMount.xfm, &mat); Point3F position; mat.getColumn(3, &position); fmat.setColumn(3, position); Parent::setTransform(fmat); updateContainer(); return; } • Next up, in camera.cpp find the interpolateTick(). Within this function, replace the isMounted() bit with: if (isMounted()) { MatrixF mat; Point3F rot = mDelta.rot + mDelta.rotVec * dt; MatrixF xRot, zRot, fmat; xRot.set(EulerF(rot.x, 0, 0)); zRot.set(EulerF(0, 0, rot.z)); // let's combine the euler rotation fmat.mul(zRot, xRot); // this will pull the transform and translate to world space // we need only the world position,we discard rotation values mMount.object->getRenderMountTransform(dt, mMount.node, mMount.xfm, &mat); Point3F position; mat.getColumn(3, &position); fmat.setColumn(3, position); Parent::setRenderTransform(fmat); return; } Note: This solves the wacky transform when setting the camera to orbitObject mode and then mounting it to the Player. So this allows the camera to be mounted in a useful way. What this doesn't do is allow the camera to be mounted properly to any designated node. The node name declared in the mount(%target, %node) function could just as well be named "Tom's Cat". The camera will always be mounted to what appears to be the Player's root node. This should be only a small inconvenience given the optional transform settings for the mount() function, although I hadn't tested this to be sure it is indeed applying the optional transform.
  9. Gotcha, makes sense. Thank you for your input - it's good to know that this is an issue that's been noticed by others. I hadn't had the time to dig into camera mounting code yet, for now I can live with having a larger visibleDistance. I'm unsure whether this will matter or not, given a fixed camera angle. From what I've been able to deduce, if an object's bounding box is outside the camera's viewing frustum the object isn't rendered. Unfortunately not rendered doesn't mean not scoped. If I had to hazard a guess I would assume anything within the visibleDistance is being scoped. Which is a pretty big deal if you really think about it. Take, for instance, an isometric styled game. The camera is angled downwards so all you see is a small area around the player. If there are objects clear across the scene not in that viewing frustum being scoped that's really inefficient. Then if you try to set the visibleDistance lower so that doesn't happen, your player can only move like 20 feet. If a camera could be mounted properly this would be solved, you are 100% correct! The visibleDistance could be set to just outside the viewable frustum, and that visibleDistance culling would travel with the player. Hmm, looks like it's time to give the orbitObject functions a good look-over to implement mounting...
  10. That's the same conclusion I came to, thanks for the confirmation. I also thought it was odd that the mountObject accepted the 'cam' string and still mounted the camera, which is why I included it as well - it could be related to the problem. Go ahead and try that mountObject command though, it does 'work' with the node name. Only 'works' though because it gives the same result as mounting the camera to any other node(number or otherwise). But regardless of whether a name or an int are used, the mounted camera ends up with a transform that's completely off. On the stock soldier model the camera will be pointing straight up, on my custom model it's near-isometric(with the orbitObject bit plugged in as well).
  11. I've found a game specific problem that only appears if you are using orbitObject mode for the camera. I was hoping someone may be able to give some advice as to how to get this issue resolved. It's super easy to replicate the problem with a stock build: • Open up scripts/gameCore.cs and setup the camera for sideview. Here's a sample script (personally I dropped this near the bottom of the spawnPlayer() function): %client.setFirstPerson(false); %client.setCameraObject(%client.camera); %client.camera.setOrbitObject(%client.player, "0 0 0", 10, 20, 20, false, "0 0 0", false); %client.camera.camDist = 10; • Next, just open up an example level (EmptyRoom.mis) and set the visibleDistance fairly low (to see the problem without having to run far): visibleDistance = "20"; • If you run off with the Player, he will disappear once you reach the distance set by "visibleDistance". C++ Now, I did a good bit of digging and found the root of the issue. It stems from some changes to the engine sometime after 3.6(ish). At some point, quite a few files were updated to include a new field: mVisibleGhostDistance. A quick search for 'mVisibleGhostDistance' will reveal the field being used in levelInfo.h/.cpp, gameConnection.cpp, sceneObject.cpp, and sceneManager.h/.cpp. Most importantly, in sceneObject.cpp: if (conn && (query->visibleDistance = conn->getVisibleGhostDistance()) == 0.0f) if ((query->visibleDistance = sceneManager->getVisibleGhostDistance()) == 0.0f) query->visibleDistance = sceneManager->getVisibleDistance(); So here the mVisibleGhostDistance is going to be set to the VisibleDistance. By the description in the EngineMethod, the mVisibleGhostDistance is the distance from the camera at which Players are no longer ghosted. So why, then, is the Player being un-ghosted when the camera is (supposedly) orbiting the player? Because, in truth, when the camera is set to orbit the Player it isn't actually mounted to the Player object. When the camera is set to orbit the Player, for some unknown reason if the Player moves off to the side someplace the 'real' camera object stays back where he left it originally. So if the Player travels out of the 'real' camera's 'visibleGhostDistance' ....poof! he's gone! I thought it would be easy, so I tried to just mount the camera to the player. LOL, give that a try and then get back to me...I'll even provide a sample script: %player.mountObject(%client.camera, "cam"); Anyways, ultimately, if all of the mVisibleGhostDistance stuff is removed from the engine code the problem is gone. But that isn't a real solution now is it? Not when the goal of the field in the first place was to unghost the Player objects not within range. What I do think is a 'true' solution is finding a way to have the camera's orbitObject() function actually mount the 'real' camera to the Player object so that the camera actually travels with the Player in orbitObject mode. Any comments or suggestions?
  12. • Navigate to art/datablocks/player.cs • In the datablock PlayerData(DefaultPlayerData) (this is the player datablock...), find the line: boundingBox = "0.65 0.75 1.85"; • Adjust to your heart's content. The first number is the x value (from the center), the second the y, and lastly the z. • Profit Of course not, since you'd want a different datablock for every different model!
  13. The bounding box and the collision meshes are 2 different things, and each serves a different purpose. What Duion says is true, in a way, but only when dealing with the actual player character that the client controls. As I recommended in your other posting @saindd you should setup the player's bounding box dimensions in the player's datablock file. There are fields there for the bounding box and crouching bounding box, etc. The player is an exception to the rule, in that the bounding box dimensions setup in the player's datablock will also be the player's collision box. Other objects actually use bounding boxes and collision meshes as they 'normally' should be - The bounding box determines visible bounds and the collision meshes determine actual collision. You can see how this works pretty easily: • Create a large cube taller than the player in size. • Create a bounds box for the cube, say half the size of the cube so that the bounds box is too small and fits inside the cube. Toss the cube into a scene and look at it. If you turn the camera to the side, the cube will disappear when the bounds box goes out of view. This is totally incorrect because you'll notice when the cube is not in view and you turn to look at it again it won't render until the bounds box is on screen again. So you end up with a cube that should be rendered but isn't until you're looking closer to its center. Collision meshes are pretty self explanatory, quite simply they are what you actually collide with. I just wanted to point out the functional differences between the two.
  14. The bounding box should be large enough so that any animations don't extend out of its boundaries. Like if you had a character that did a jump animation which actually adjusted its position on the 'z' axis upwards, you would want the bounding box to be taller than the character so that the player fit even at the highest point in the jump. That all being said, though, it's a better idea to just make the jump 'look' like a jump but leave the character in one position and apply impulse in Torque for the actual jump. This prevents issues that can arise with too big of bounding boxes. To answer your direct question, though, nah the bounding box should just be hanging out in the model. Here's a tried and true example of how to set up the nodes: | |_° Bip01 | |_ • CharacterModel | |_ • Bounds To be honest, though, if it's a player that will be controlled by the client I'd recommend to just leave the bounds box alone in the actual art and just set the dimensions for the bounds box in the player's datablock.
  15. Thanks for all the time and energy put into the update! Currently enjoying development using Torque and looking forward to what's to come!
  16. Dude, that's just me trippin' all around trying to figure out the way some of these things work in Torque source. There I had added a bool to the player class (before I discovered the details I'm about to describe). I finally did find a much more 'solid' solution, after poking around and digging to find out exactly what pieces I was missing. I ended up extending the collision struct with some extra fields I needed to pass the data from my custom object. In my object's castRay I added the pointers to the new fields as part of the rInfo result. Then, ultimately, and without needing a callback I just ended up plugging this in: // Stepped on MyObject if (rInfo.object->getTypeMask() & MyObjectType) myCustomFunction(rInfo.myNewField); Oh, I also had to setup a new TypeMask for the custom object. Works like a charm!
  17. Well I believe I found what I need for #2. Tracked down the SceneContainer and SimpleQueryList which I think will meet my needs fine for indexing objects. For #1 I've implemented a custom callback, so I can call the functions to the other class via script...which is kinda what I was trying to avoid but oh well.
  18. I've been messing with a custom class in C++ for T3D and ran into a couple snags that, hopefully, might be cleared up by someone with a bit more knowledge around the engine and the use of its source. 1 - The first thing I'm having problems with is when the Player performs a rayCast onto the object he's stepping on. What I'd like to do is 'grab ahold' of the object the player has stepped on and then call to functions within that object's class. For example: if (&Player::steppedOnMyObject) { Con::printf("Stepped on my Object"); } Using the above I can have the console echo come through, no problems there. But what if I wanted to do this: if (&Player::steppedOnMyObject) { MyObject* myObject = getMyObject(); myObject.doStuff(); } How could this be accomplished? The rayInfo from the sceneContainer's rayCast() is only returning a sceneObject in the rInfo.object data field, so I can't just use something like: SceneObject* myObject = getMyObject(); I guess what I'm looking for is how would I write the 'getMyObject()' function from within the Player class to retrieve the other class object? 2- The next issue I'm trying to figure out is how players present in the scene are retrieved or indexed. Consider this, in 'myObject.h': Player* mActivePlayer; VectorPtr<Player*> mPlayers; How could that list of players be filled? Or is there some already existing way to retrieve players from the scene? Thanks to anyone who can enlighten me a bit.
  19. Nice, that's got it sorted. Thanks Az!
  20. Gosh, my bad man, totally misread your OP and thought you were interested in weapons... The bones go like this: -Bip01 -Bip01 Pelvis -Bip01 Spine -Bip01 Spine1 -Bip01 Spine2 -Bip01 Neck -Bip01 Head Bip01 HeadNub -Bip01 L Clavicle -Bip01 L UpperArm -Bip01 L Forearm -Bip01 L Hand -Bip01 R Clavicle -Bip01 R UpperArm -Bip01 R Forearm -Bip01 R Hand -Bip01 L Thigh -Bip01 L Calf -Bip01 L Foot -Bip01 L Toe0 -Bip01 L ToeNub -Bip01 R Thigh -Bip01 R Calf -Bip01 R Foot -Bip01 R Toe0 -Bip01 R ToeNub That's pretty much the basic layout, I didn't include finger bones which are unimportant for the example anyways. Some of the nodes are rarely used but here's a list of those as well in case: AltEye -GunCam Eye -Cam -FollowCam mount0 I've heard of an 'ear' node as well but haven't ever seen it in any of the source art. The important bones deal with the player code resolving the spine - in player.cpp: // Resolve spine spineNode[0] = mShape->findNode("Bip01 Pelvis"); spineNode[1] = mShape->findNode("Bip01 Spine"); spineNode[2] = mShape->findNode("Bip01 Spine1"); spineNode[3] = mShape->findNode("Bip01 Spine2"); spineNode[4] = mShape->findNode("Bip01 Neck"); spineNode[5] = mShape->findNode("Bip01 Head"); These bones are important for the player's 'look' animation, which you can define in the player model's .cs file. Hope this is helpful.
  21. A weapon image is the model. As an example, open up art/datablocks/weapons/Ryder.cs: datablock ShapeBaseImageData(RyderWeaponImage) { // Basic Item properties shapeFile = "art/shapes/weapons/Ryder/TP_Ryder.DAE"; shapeFileFP = "art/shapes/weapons/Ryder/FP_Ryder.DAE"; emap = true; ... } Here the 'RyderWeaponImage' datablock uses the 'shapeFile' field to designate where the new weapon model is located. Is this what you are after, just trying to import a new model for a weapon? If you were to change that above to point to another .DAE file, when the Soldier tried to equip the Ryder weapon it would instead equip the new weapon model. There are optional nodes that can be added to the model's art for things like the muzzlepoint, ejectpoint, etc. but none of that is required and nothing in the player code will prevent any shape from being used as a weapon. Otherwise, if you are needing to implement an entirely new weapon class that has a different functionality you would need to create a new weapon class in source (probably based off of ShapeBaseImageData).
  22. I haven't had time to dig deeper into the source to find out what's caused this dedicated server breakage when saving with the World Editor. I do, however, have a couple updates: The issue isn't present in T3D 3.6.2. The issue doesn't occur if there is no terrain in the level being saved. Currently I'm making alterations using the World Editor, saving the mission, then just copying the changes over with a text editor to a backup copy of the .mis file. As you can imagine, this is rather cumbersome but it gets the job done for now until the issue is sorted. I hadn't been using terrain on these particular levels, although I am almost certain any terrain I am going to have to generate using a T3D build earlier than 3.7rc or else the resulting saved terrain will cause a problem when trying to launch a dedicated server.
  23. I just got back to look at this and, yes, as a matter of fact I did finally discover the real origin of the problem. Throw all of that above out the window, it matters not. The problem originates if you open a .mis file with the Torque World Editor and then save the .mis file from within the editor. To replicate it: Launch stock Torque3D 3.7 (64 bit build) Launch the 'Empty Terrain' mission (any mission should work). Once in the mission, hit F11 to go into the World Editor. Alter or change anything in the mission, and then click File -> Save Level. Exit Torque. Setup a .bat file to launch the executable with the -dedicated parameter and for the -mission parameter use the 'Empty Terrain.mis' file you just saved in the World Editor. The cmd window should give the error about not supporting the GFX formats (tested in Windows 8.1 and 7 so far). So now we know the 'why' of what's causing it, now just to find the 'how' to fix it :) I can take the same .mis file, open it with a text editor, alter any fields and save the file without the dedicated launch problem. So it does certainly appear that something in the World Editor's save function is presenting a problem. That all being said, is there perhaps a 'best practice' for building dedicated builds to avoid any issues that could arise from the Editor tools? I mean, after all, when it's all said and done the tools wouldn't be included with the dedicated build of course.
  24. Okay after much trial and error, I assumed it was the terrain...then I assumed it was a script error...then I was going to blame the billboards again... It is the spawn position! If the spawn position is anything other than 0, 0 on x,y the dedicated server will crash! I'm not sure how this relates to the shapes in the scene (more testing is required). Perhaps different view angles/distances trigger certain billboards to show that otherwise would not? @LukasPJ It's a stock feature. The source art uses the bb prefix for the LOD node to create billboards. You can see this in the defaulttree.DAE example model.
  25. Thanks for the reply Lukas. You forced me to examine the source art, and as a result I have a new lead on this problem. I'll get back to you here when I finish tracking it down :D
  • Create New...