| 07-01-2011, 12:21 AM | #1 | |||||
|
| 07-01-2011, 08:34 AM | #2 |
I think that CameraSetupSetField, like SetCameraField which I'm familiar with, uses degrees, not radians. I don't immediately see any other errors in your code, so maybe this was all that was wrong. Here are some other things I would change, they're not necessarily wrong but can be made shorter. JASS:if CamRotationDirection == true then set CamRotationDirection = false else set CamRotationDirection = true endif // This can be replaced with: set CamRotationDirection = not CamRotationDirection JASS:if GetRandomInt(0, 1) == 0 then set CamRotationDirection = true else set CamRotationDirection = false endif // This can be replaced with: set CamRotationDirection = (GetRandomInt(0, 1) == 0) |
| 07-01-2011, 11:35 AM | #3 |
Oppicam can do that, isn't it?? |
| 07-01-2011, 01:46 PM | #4 | ||
JASS:set CamRotationDirection = not CamRotationDirection im beginning to doubt the particular guide that i read - so far some other stuff has been wrong (like why locals need to be nulled) Quote:
i tried changing it to degrees and the rotation was completely wacky even when it did work Quote:
oppicam seems really useful, and this is the type of thing which is super useless except for this one rare purpose even still thats not really the point cant learn a language just by looking at other peoples code i noticed something else the camera only seems to stop rotating at 0,90,180,270 degrees which would make sense for the times it didnt ran at all (since it starts at 0... or whatever default is) is there some default which automatically snaps cameras? |
| 07-01-2011, 02:48 PM | #5 | |
Quote:
Anyway, I tested the thing in an empty map. To get it to work, I had to remove the conversion from degrees to radians, reactivate the bounds checking and fix it so it didn't limit the value between -360 and 360, but between 0 and 360. Camera setups that have values outside these bounds do not work. By the way, the code is not very import friendly, I had to add a lot of missing things like the periodic timer which should have been encapsulated in your code already, however you apparently do it from outside somewhere; it is possible there are additional bugs in that code, I can't help you with that because you haven't posted it. Here is the code I ended up using for testing, I used ListModule in it: JASS:library cameratest requires ListModule globals //CONFIGURABLES //should this run in debug mode? //only for testing (debug messages leak) private constant boolean CAMDEBUG = true //should the rotation direction alternate or be random? private constant boolean CAMALTERNATEDIR = true //how many people play (at most) private constant integer NumberPlayers = 10 //how often the periodic trigger is run, higher means less memory intensive but choppier movement private constant real HowOften = .05 //bounds for cam rotation speed private constant real LeastCamSpeed = 20 private constant real MostCamSpeed = 80 //bounds for rotation duration private constant integer LeastCamTicks = 50 private constant integer MostCamTicks = 200 //dont touch below here unless you know what you're doing //used to access the different cameras private RotationCamera array RotCameras[NumberPlayers] endglobals struct RotationCamera //an array that stores previous camera angles private real CurCamAngle //how many ticks are left going in this direction private integer CamNumTicks //true == clockwise, false == counterclockwise private boolean CamRotationDirection //the speed for the camera private real CamRotationSpeed //the current camera private camerasetup CurCam //who does this camera belong to private player CamOwner //which unit does the camera center on private unit CamUnit private method CamRandGenerate takes nothing returns nothing //generates a new random set of paramaters which replace the previous ones set CamNumTicks = GetRandomInt(LeastCamTicks, MostCamTicks) set CamRotationSpeed = GetRandomReal(LeastCamSpeed, MostCamSpeed) static if CAMALTERNATEDIR then if CamRotationDirection == true then set CamRotationDirection = false else set CamRotationDirection = true endif else if GetRandomInt(0, 1) == 0 then set CamRotationDirection = true else set CamRotationDirection = false endif endif //debug stuff static if CAMDEBUG then call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(CamUnit))], "New Parameters") call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(CamUnit))], "Num Ticks: " + I2S(CamNumTicks)) call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(CamUnit))], "Rotation Speed: " + R2S(CamRotationSpeed)) if CamRotationDirection then call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(CamUnit))], "Rotate Clockwise") else call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(CamUnit))], "Rotate Counter-Clockwise") endif endif endmethod private method CamRotate takes nothing returns nothing //if the camera has finished its rotation period then its time to generate a new set of parameters if CamNumTicks < 1 then call CamRandGenerate() //otherwise keep rotating the camera with the existing parameters else //clockwise or counterclockwise? might be easier for CamRotationDirection to just be -1 or 1. if CamRotationDirection then set CurCamAngle = CurCamAngle - CamRotationSpeed else set CurCamAngle = CurCamAngle + CamRotationSpeed endif //prevents super big reals //for some reason this breaks it - actually, this makes it work if CurCamAngle > 360 then set CurCamAngle = CurCamAngle - 360 elseif CurCamAngle < 0 then set CurCamAngle = CurCamAngle + 360 endif //set the angle for the camera field call CameraSetupSetField(CurCam, CAMERA_FIELD_ROTATION, CurCamAngle, HowOften) // degrees are correct, not radians call CameraSetupSetDestPosition(CurCam, GetUnitX(CamUnit), GetUnitY(CamUnit), HowOften) //apply the new angle/camera for the specified person if GetLocalPlayer() == CamOwner then call CameraSetupApply(CurCam, false, false) call PanCameraToTimed(GetUnitX(CamUnit), GetUnitY(CamUnit), HowOften) endif //decrement the number of ticks remaining for these parameters set CamNumTicks = CamNumTicks - 1 endif endmethod implement List private static method periodic takes nothing returns nothing local thistype e = .first loop exitwhen e == 0 call e.CamRotate() set e = e.next endloop endmethod //initializes all the data fields for the rotating camera object //no rotation is actually done here public static method create takes integer WhosCamId returns RotationCamera local RotationCamera new = RotationCamera.allocate() set RotCameras[WhosCamId] = new set new.CamOwner = Player(WhosCamId) set new.CamUnit = CreateUnit(Player(WhosCamId), 'hfoo', 0,0,0) set new.CurCamAngle = 0 set new.CurCam = CreateCameraSetup() call new.CamRandGenerate() call new.listAdd() return new endmethod private static method onInit takes nothing returns nothing call TimerStart(CreateTimer(), HowOften, true, function thistype.periodic) call thistype.create(0) endmethod private method onDestroy takes nothing returns nothing call .listRemove() set CamOwner = null set CurCam = null endmethod endstruct endlibrary |
| 07-02-2011, 04:28 AM | #6 | ||||
Quote:
this would have saved so much time on the last thing i made i had 30 nested if statements because i thought or leaked (and the function was called periodically) not only that but i didnt close one of the ifs so i had to spend like 15 minutes counting spaces, since i didn't notice the indenting was off till the very end Quote:
when i did it, it had no limit for bounds so that must have been why it seemed even glitchier when i tried it as degrees that was a really good catch though, i'd have never thought of changing the lower limit from -360 to 0 (cuz they're equivalent and all that) thank you (maybe i should just make "thank you" my signature) Quote:
i had posted the test map (in my first post) i'd been using so you wouldn't have to do stuff like this even still i really appreciate that you actually did all that extra stuff, tyvm for the help Quote:
every way so far has run into a dead end i dont completely understand why exactly what you did works as it does so if you don't mind i'll ask one or two questions about it (and see if i understand it correctly) 1. list module is a (well done) doubly linked list 1b. thistype is the JASS version of generics 1c. each type gets its own list devoted to that type (although i guess you could give a type more than 1 list if necessary) 2. JASS:private static method onInit takes nothing returns nothing 3. JASS:call TimerStart(CreateTimer(), HowOften, true, function thistype.periodic) does that mean the .periodic that is defined in this library as opposed to .periodic in other structs or is it a short hand way to say function RotationCamera.periodic and why isn't it written as .periodic() i guess my question is can you explain thistype.periodic a bit, please? 4. despite not really knowing how #3 works, a timer is attached to the .periodic function, which in turn iterates through the list of RotationCameras calling the .rotate function |
| 07-02-2011, 09:22 AM | #7 | |||||
Quote:
Quote:
Quote:
Quote:
Quote:
|
| 07-03-2011, 03:19 AM | #8 | ||
Quote:
good to know, ill keep that in mind next time Quote:
especially since most of my coding is done in LISP all i need now is car and cdr haha ok so ive taken your suggestions and then reevaluated a few other things that might be useful and have a newer version if you have time to take a quick look (mostly for glaring leaks or baaad syntax) i've got 3 specific questions on top of that JASS:library CameraLibrary requires ListModule //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Rotation Camera // credit to Grim001 for ListModule // // Purpose: // Creates a structure which rotates "randomly" around a given unit for a given player //==================================================================================== // Configuration: // Change the values of the global variables to be as you want, recommended values are given // descriptions of what each variable does is given by the comment directly above the variable //============================================================================================ // Importing: // This library requires ListModule. Either import ListModule manually, or copy and paste the Libraries folder in the test map // located in the test map. // All global variables must have a value. Some must be set in a separate trigger at map init (like CamUnit) // If being used in a maze, you most likely have an array which contains all the mazers - if this is the case // you should replace the CamUnit array with your own. // Because this uses libraries and structs, this requires JASS newGen editor to compile. //====================================================================================== // Expanded API: (functions available to this struct) + explanations // // .create(integer i, unit u) -> RotationCamera // creates a camera for Player(i) centering around unit u // if ROTATEONCREATE in the configurables section is set to true, then the camera will begin rotation immediately // // .destroy() -> nothing // deallocates the RotationCamera object as well as: // nulling member variables, resetting default camera for owning player, stopping camera rotation. // // .CamStart() -> nothing // resumes rotation for a previously created camera. camera MUST exist already. // // .CamStop() -> nothing // stops rotation for an existing camera. however this does not destroy the camera. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// globals //CONFIGURABLES //should this run in debug mode? //only for testing (debug messages leak) private constant boolean CAMDEBUG = true //the timer used for the periodic function private timer CamTimer = CreateTimer() //should the rotation direction alternate or be random? private constant boolean CAMALTERNATEDIR = true //should cameras start rotating as soon as they are created? private constant boolean ROTATEONCREATE = true //how often the periodic trigger is run, higher means less memory intensive but choppier movement private constant real HowOften = .05 //bounds for cam rotation speed private constant real LeastCamSpeed = .5 private constant real MostCamSpeed = 5 //bounds for rotation duration private constant integer LeastCamTicks = 50 private constant integer MostCamTicks = 200 endglobals struct RotationCamera //an array that stores previous camera angles private real CurCamAngle //how many ticks are left going in this direction private integer CamNumTicks //true == clockwise, false == counterclockwise private boolean CamRotationDirection //the speed for the camera private real CamRotationSpeed //the current camera private camerasetup CurCam //who does this camera belong to private player CamOwner //which unit does the camera center on private unit CamUnit private method CamRandGenerate takes nothing returns nothing //generates a new random set of paramaters which replace the previous ones set CamNumTicks = GetRandomInt(LeastCamTicks, MostCamTicks) set CamRotationSpeed = GetRandomReal(LeastCamSpeed, MostCamSpeed) static if CAMALTERNATEDIR then set CamRotationDirection = not CamRotationDirection else set CamRotationDirection = (GetRandomInt(0, 1) == 0) endif //debug stuff static if CAMDEBUG then call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(CamUnit))], "New Parameters") call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(CamUnit))], "Num Ticks: " + I2S(CamNumTicks)) call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(CamUnit))], "Rotation Speed: " + R2S(CamRotationSpeed)) if CamRotationDirection then call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(CamUnit))], "Rotate Clockwise") else call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(CamUnit))], "Rotate Counter-Clockwise") endif endif endmethod private method CamRotate takes nothing returns nothing //if the camera has finished its rotation period then its time to generate a new set of parameters if CamNumTicks < 1 then call CamRandGenerate() //otherwise keep rotating the camera with the existing parameters else //clockwise or counterclockwise? might be easier for CamRotationDirection to just be -1 or 1. if CamRotationDirection then set CurCamAngle = CurCamAngle - CamRotationSpeed else set CurCamAngle = CurCamAngle + CamRotationSpeed endif //prevents super big reals if CurCamAngle > 360 then set CurCamAngle = CurCamAngle - 360 elseif CurCamAngle < 0 then set CurCamAngle = CurCamAngle + 360 endif //set the angle for the camera field call CameraSetupSetField(CurCam, CAMERA_FIELD_ROTATION, CurCamAngle, HowOften) call CameraSetupSetDestPosition(CurCam, GetUnitX(CamUnit), GetUnitY(CamUnit), HowOften) //apply the new angle/camera for the specified person if GetLocalPlayer() == CamOwner then call CameraSetupApply(CurCam, false, false) call PanCameraToTimed(GetUnitX(CamUnit), GetUnitY(CamUnit), HowOften) endif //decrement the number of ticks remaining for these parameters set CamNumTicks = CamNumTicks - 1 endif endmethod implement List //iterates through the list of cameras calling the rotation function private static method periodic takes nothing returns nothing local RotationCamera e = .first loop exitwhen e == 0 call e.CamRotate() set e = e.next endloop endmethod //start a camera given a previously stopped camera. //Cannot start a destroyed camera, if you destroy a camera you need to .create a new one to replace it public method CamStart takes nothing returns nothing call .listAdd() endmethod //stops a camera while leaving the RotationCamera object intact public method CamStop takes nothing returns nothing call .listRemove() endmethod //start the timer and pause it, as its not needed until a camera object is made /* private static method onInit takes nothing returns nothing call TimerStart(CamTimer, HowOften, true, function RotationCamera.periodic) call PauseTimer(CamTimer) endmethod */ //initializes all the data fields for the rotating camera object //no rotation is actually done here public static method create takes integer WhosCamId, unit whichCamUnit returns RotationCamera local RotationCamera new = RotationCamera.allocate() set new.CamOwner = Player(WhosCamId) set new.CamUnit = whichCamUnit set new.CurCamAngle = 0 set new.CurCam = CreateCameraSetup() //generates and sets the parameters for the camera call new.CamRandGenerate() //if true, the camera will begin rotating immediately for the given player static if ROTATEONCREATE then call new.listAdd() endif //always assume the timer is paused, and needs to be started //my attempts to save memory on timer runs: // //call ResumeTimer(CamTimer) // //if .count == 0 then // call TimerStart(CamTimer, HowOften, true, function RotationCamera.periodic) //endif call TimerStart(CamTimer, HowOften, true, function RotationCamera.periodic) return new endmethod private method onDestroy takes nothing returns nothing //remove this camera from the list call .listRemove() //if no camera is being rotated, then pause the timer if .count == 0 then call PauseTimer(CamTimer) endif //resets the game camera to default for given player if GetLocalPlayer() == CamOwner then call ResetToGameCamera(3.00) endif //null handle member variables set CamOwner = null set CurCam = null endmethod endstruct endlibrary the test function looked like this JASS:globals //how many people play (at most) constant integer NumberPlayers = 10 //used to access the different cameras RotationCamera array RotCameras[NumberPlayers] //array for all the units which are "attached" to the camera unit array CamUnit[NumberPlayers] endglobals //=========================================================================== function InitTrig_CamTest takes nothing returns nothing local integer i = 0 set CamUnit[0] = gg_unit_Hblm_0000 set CamUnit[1] = gg_unit_Hblm_0003 set gg_trg_CamTest = CreateTrigger( ) loop exitwhen i > NumberPlayers - 1 if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then set RotCameras[i] = RotationCamera.create(i, CamUnit[i]) endif set i = i + 1 endloop endfunction question 1: theres no error protection whatsoever if someone were to create a camera twice without destroying the old camera, everything goes to hell turning a camera that doesnt exist on then creating a new camera also causes baaaad stuff basically the problem is i need to be able to check if a camera is already in a list for a person this should be easy but i'm not totally sure if the way i want to do it is correct JASS:private static method containsPlayer takes integer i returns RotationCamera local RotationCamera e = .first loop exitwhen e == 0 if GetPlayerId(e.CamOwner) == i then return e endif set e = e.next endloop return -1 endmethod then I check if the value is -1 (i wanted to use null but JASS won't let you do that for atoms) otherwise I call .destroy() on the returned RotationCamera. if the value is -1, than the given player doesn't already have a rotating camera. question 2: so now that the timer is built into the structure, there is the small problem that it is always running my first attempt at fixing this used PauseTimer and ResumeTimer for a global timer var I made, but for whatever reason this didn't work I left what I tried in the code, but commented it out, there are 2 parts to it the onInit code and the .create() code (end of .create) in the end, pausing the timer when the struct is destroyed and the .count of the list is 0 and then starting the timer every time .create() is called worked see the commented out code for more information on what I tried that didn't work question 3: is there an easy way to recycle things? the last project I did, I used a hashtable within each data struct but because I couldn't figure out how to destroy hashtables, there was no support for destroying the struct it wasn't such a big deal as the struct wasn't ever meant to be destroyed, but adding such support to it (last project) would certainly help question 4 (yeah i lied): I read in the ListModule description to implement list at the very top of the struct to avoid unnecessary trigger evaluate calls. does this make a noticeable difference/is this no longer the case? |
| 07-03-2011, 06:52 AM | #9 | ||||
Quote:
BTW, structs start at 1 so we usually use 0 as a null return, not -1. Quote:
Quote:
JASS:group g static method create takes nothing returns thistype local thistype this=thistype.allocate() if .g==null then set .g=CreateGroup() endif return this endmethod method onDestroy takes nothing returns nothing call GroupClear(.g) endmethod Quote:
|
| 07-03-2011, 07:06 PM | #10 | ||||
Quote:
I'm going to release several libraries for mazes after I finish my map, and this rotation theme is surprisingly common in mazes But I'm also going to make a maze maker map after I finish the current maze (where you build the maze in game using super-gui) after I finish my own. For that, i'll need to be able to create things in the most general manner possible. Quote:
why doesn't it work to do what I did I start the timer at map init and immediately paused it then every time .create() was called, I also resumed the timer (regardless of knowing whether it was paused or not) and then when the list was empty I paused the timer once again But for some reason, unpause never worked, so I had to call TimerStart instead of unpause I don't fully understand how to use timers yet, but this seems bad. Quote:
I'll ask a bit more about group utils in a few days when I've got something to show for unit collision but is there some sort of hashtable utils? or should I just use stack to hold and pop unused hashes, releasing them back into the stack onDestroy() Quote:
would you mind giving me a crash course lesson on correct ordering? once again thank you very much for all the help |
| 07-03-2011, 09:01 PM | #11 | |||
Quote:
Quote:
Quote:
|
| 07-04-2011, 04:15 PM | #12 | |||
Quote:
ok I tried a few other things to see if ResumeTimer had any effect, but it didn't do anything at all just kinda strange Quote:
ohhhh I never realized objects got recycled like that that's really cool I'm guessing this applies to hashtables as well Quote:
its way off topic to just post here so i'll make a new one here i had a few questions about it anyways |
