Ace_Gambit Posted February 15, 2009 Share Posted February 15, 2009 Some functions require DM 1.0 Nightly build. A lot of people have been wondering about scripted traffic and there is more than one way of doing it. With the new ped functions (DM 1.0 Nightly build) a convenient method is to set control states. However, setting control states is client-sided and no one except you will be able to see the vehicle moving unless you tell all clients to do the same. This code snippet will demonstrate how to move vehicles along scripted paths by using server-side velocity changes. It is very basic and probably not the most efficient way of moving vehicles but it may help people with their scripts. Also note that it is recommended to do all this client-side. Timers do not provide fast enough intervals to make the vehicle rotate smoothly. This sample is just to show how it could be done server-side. Server script: ROOT = getRootElement (); RES = getThisResource (); PATHS = "paths.xml"; local pPaths = {}; local iPath = 1; local bHandleSpawn = true; local bCreateMarkers = true; -- Just for testing. local pMover = nil; function getTargetAngle ( pSource, fTargetX, fTargetY, fTmp ) local fSourceX, fSourceY, fSourceZ = getElementPosition( pSource ); local _, _, fRot = getVehicleRotation ( pSource ); local fRelPosX = fTargetX - fSourceX; local fRelPosY = fTargetY - fSourceY; local fDist = math.sqrt ( ( fRelPosX * fRelPosX ) + ( fRelPosY * fRelPosY ) ); local fDot = 0; fRot = fRot + fTmp; fRelPosX = fRelPosX / fDist; fRelPosY = fRelPosY / fDist; fDot = ( ( math.sin ( math.rad ( 360 - fRot ) ) ) * fRelPosX ) + ( ( math.cos ( math.rad ( 360 - fRot ) ) ) * fRelPosY ); return math.deg ( math.acos ( fDot ) ); end; function onTimer () local fPosX, fPosY = 0, 0; local fRotZ = 0; local fVelX, fVelY, fVelZ = 0, 0, 0; local fPerc = 0; if ( pMover and #pPaths > 0 ) then fPosX, fPosY = getElementPosition ( pMover ); if ( getDistanceBetweenPoints2D ( fPosX, fPosY, pPaths[ iPath ].fPosX, pPaths[ iPath ].fPosY ) > pPaths[ iPath ].fMaxTargetDistance ) then _, _, fRotZ = getVehicleRotation ( pMover ); fVelX, fVelY, fVelZ = getElementVelocity ( pMover ); if ( fRotZ >= 0 and fRotZ <= 90 ) then fPerc = ( fRotZ / 90 ) * 100; if ( fPerc < 50 ) then fVelX = -( ( fPerc / pPaths[ iPath ].fSpeedDivision ) * 1 ); fVelY = ( ( 100 - fPerc ) / pPaths[ iPath ].fSpeedDivision ) * 1; else fVelX = -( ( fPerc / pPaths[ iPath ].fSpeedDivision ) * 1 ); fVelY = ( ( 100 - fPerc ) / pPaths[ iPath ].fSpeedDivision ) * 1; end; end; if ( fRotZ >= 90 and fRotZ <= 180 ) then fRotZ = fRotZ - 90; fPerc = ( fRotZ / 90 ) * 100; if ( fPerc < 50 ) then fVelX = -( ( ( 100 - fPerc ) / pPaths[ iPath ].fSpeedDivision ) * 1 ); fVelY = -( ( fPerc / pPaths[ iPath ].fSpeedDivision ) * 1 ); else fVelX = -( ( ( 100 - fPerc ) / pPaths[ iPath ].fSpeedDivision ) * 1 ); fVelY = -( ( fPerc / pPaths[ iPath ].fSpeedDivision ) * 1 ); end; end; if ( fRotZ >= 180 and fRotZ <= 270 ) then fRotZ = fRotZ - 180; fPerc = ( fRotZ / 90 ) * 100; if ( fPerc < 50 ) then fVelX = ( fPerc / pPaths[ iPath ].fSpeedDivision ) * 1; fVelY = -( ( ( 100 - fPerc ) / pPaths[ iPath ].fSpeedDivision ) * 1 ); else fVelX = ( fPerc / pPaths[ iPath ].fSpeedDivision ) * 1; fVelY = -( ( ( 100 - fPerc ) / pPaths[ iPath ].fSpeedDivision ) * 1 ); end; end; if ( fRotZ >= 270 and fRotZ <= 360 ) then fRotZ = fRotZ - 270; fPerc = ( fRotZ / 90 ) * 100; if ( fPerc < 50 ) then fVelX = ( ( 100 - fPerc ) / pPaths[ iPath ].fSpeedDivision ) * 1; fVelY = ( fPerc / pPaths[ iPath ].fSpeedDivision ) * 1; else fVelX = ( ( 100 - fPerc ) / pPaths[ iPath ].fSpeedDivision ) * 1; fVelY = ( fPerc / pPaths[ iPath ].fSpeedDivision ) * 1; end; end; setElementVelocity ( pMover, fVelX, fVelY, fVelZ ); if ( getTargetAngle ( pMover, pPaths[ iPath ].fPosX, pPaths[ iPath ].fPosY, 0 ) > pPaths[ iPath ].fMaxTargetAngle ) then if ( getTargetAngle ( pMover, pPaths[ iPath ].fPosX, pPaths[ iPath ].fPosY, -1 ) < getTargetAngle ( pMover, pPaths[ iPath ].fPosX, pPaths[ iPath ].fPosY, 1 ) ) then print ( "* Right turn." ); setVehicleTurnVelocity ( pMover, 0, 0, -( pPaths[ iPath ].fTurnVelocity ) ); else print ( "* Left turn." ); setVehicleTurnVelocity ( pMover, 0, 0, pPaths[ iPath ].fTurnVelocity ); end; else setVehicleTurnVelocity ( pMover, 0, 0, 0 ); end; else if ( iPath < #pPaths ) then iPath = iPath + 1; else iPath = 1; end; print ( "* Next path." ); end; end; setTimer ( onTimer, 50, 1 ); end; function onResourceStart ( pStartedResource ) local nRoot = false; if ( pStartedResource == RES ) then nRoot = xmlLoadFile ( PATHS, RES ); if ( nRoot ) then for _, nPath in pairs ( xmlNodeGetChildren ( nRoot ) or {} ) do table.insert ( pPaths, { fPosX = tonumber ( xmlNodeGetAttribute ( nPath, "posX" ) ) or -1, fPosY = tonumber ( xmlNodeGetAttribute ( nPath, "posY" ) ) or -1, fTurnVelocity = tonumber ( xmlNodeGetAttribute ( nPath, "turnVelocity" ) ) or -1, fMaxTargetDistance = tonumber ( xmlNodeGetAttribute ( nPath, "maxTargetDistance" ) ) or -1, fMaxTargetAngle = tonumber ( xmlNodeGetAttribute ( nPath, "maxTargetAngle" ) ) or -1, fSpeedDivision = tonumber ( xmlNodeGetAttribute ( nPath, "speedDivision" ) ) or -1 } ); end; if ( bCreateMarkers ) then for _, pPath in ipairs ( pPaths ) do createMarker ( pPath.fPosX, pPath.fPosY, 0, "checkpoint", 1.5, math.random ( 0, 255 ), math.random ( 0, 255 ), math.random ( 0, 255 ), 255 ); end; end; pMover = getElementByID ( "mover" ); end; end; end; function onKeyPressed ( pPlayer, szKey, szKeyState ) if ( szKey == "F1" and szKeyState == "down" ) then onTimer (); end; end; function onPlayerJoin () setCameraTarget ( source, source ); fadeCamera ( source, true ); spawnPlayer ( source, 0, 0, 2.5 ); bindKey ( source, "F1", "down", onKeyPressed ); end; addEventHandler ( "onResourceStart", ROOT, onResourceStart, true ); if ( bHandleSpawn ) then addEventHandler ( "onPlayerJoin", ROOT, onPlayerJoin, true ); end; In order to make this work you must place a data file with paths in the same folder as your server script. Example paths.xml data file: <paths> <path posX="45.761882781982" posY="-2.5386297702789" turnVelocity="0.01" maxTargetDistance="10" maxTargetAngle="10" speedDivision="1000" /> <path posX="132.56669616699" posY="78.492034912109" turnVelocity="0.01" maxTargetDistance="10" maxTargetAngle="10" speedDivision="1000" /> <path posX="228.1443939209" posY="50.259208679199" turnVelocity="0.01" maxTargetDistance="10" maxTargetAngle="10" speedDivision="1000" /> <path posX="233.02215576172" posY="-70.206611633301" turnVelocity="0.01" maxTargetDistance="10" maxTargetAngle="10" speedDivision="1000" /> <path posX="144.71810913086" posY="-71.875244140625" turnVelocity="0.01" maxTargetDistance="10" maxTargetAngle="10" speedDivision="1000" /> <path posX="80.65113067627" posY="-91.124290466309" turnVelocity="0.01" maxTargetDistance="10" maxTargetAngle="10" speedDivision="1000" /> </paths> And make sure there is a vehicle with ID "mover" in your map file (or create it on the fly). Example snippet.map file: <map> <info description="" type="map" gamemodes="snippet" author="" name="" version="1.0" /> <vehicle id="mover" model="427" posX="10" posY="0" posZ="5" rotX="0" rotY="0" rotZ="270" /> </map> I've attached all script files for quick reference. Link to comment
Scarface Posted February 15, 2009 Share Posted February 15, 2009 (edited) Very nice but too bad it's not server-side =/. Edited February 15, 2009 by Guest Link to comment
Ace_Gambit Posted February 15, 2009 Author Share Posted February 15, 2009 Very nice but too bad it's not server-side =/. Actually it is server-side. But like I said it runs more smoothly if you just do it client-side in onClientRender or onClientPreRender with the cost of not having it synchronized. Link to comment
Scarface Posted February 15, 2009 Share Posted February 15, 2009 Very nice but too bad it's not server-side =/. Actually it is server-side. But like I said it runs more smoothly if you just do it client-side in onClientRender or onClientPreRender with the cost of not having it synchronized. Ah I see very nice! Link to comment
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