| 02-19-2010, 04:50 AM | #1 |
Well to start this off, I'm just starting to learn VJASS. I know Java and am sort of using it as how I would use that, so I hope its presentable enough :). If not let me know what I should fix to make it more readable. Anyway the struct I made stores data for multiple paintballs for each player with methods inside it. I am not using physics, and of course the paintballs are acting like missiles. The problem is with the move method. There is a trigger that I made that runs every .03 seconds and checks to see if a struct is not null and if there are units in the group, if so it runs the move method. I commented it a lot to help anyone that would read it. I also created a library with some math functions and ForGroup functions. I would appreciate any help with why the game would be lagging so bad :/. JASS:library paintballFunctions function Distance takes real x, real y, real x2, real y2 returns real return SquareRoot((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)) endfunction function Angle takes real x, real y, real x2, real y2 returns real return bj_RADTODEG * Atan2(y2 - y, x2 - x) endfunction function paint takes string color, unit u returns nothing if color == "red" then call SetUnitVertexColor(u, 255, 0, 0, 255) elseif color == "blue" then call SetUnitVertexColor(u, 0, 0, 255, 255) elseif color == "teal" then call SetUnitVertexColor(u, 0, 200, 255, 255) elseif color == "purple" then call SetUnitVertexColor(u, 100, 0, 255, 255) elseif color == "yellow" then call SetUnitVertexColor(u, 100, 0, 255, 255) elseif color == "orange" then call SetUnitVertexColor(u, 255, 100, 0, 255) elseif color == "green" then call SetUnitVertexColor(u, 0, 255, 0, 255) elseif color == "pink" then call SetUnitVertexColor(u, 255, 0, 255, 255) elseif color == "gray" then call SetUnitVertexColor(u, 100, 100, 100, 255) elseif color == "light blue" then call SetUnitVertexColor(u, 75, 75, 255, 255) endif endfunction function enumUnit takes nothing returns nothing if(GetUnitState(GetEnumUnit(), UNIT_STATE_LIFE) > 0) then //Check to see if not dead call tempStruct.splat(GetEnumUnit(), null) endif endfunction function enumDestructable takes nothing returns nothing if GetDestructableTypeId(GetEnumDestructable()) != 'B000' then //Check to see if not mini barrel call tempStruct.splat(null, GetEnumDestructable()) endif endfunction endlibrary JASS:struct paintball private real array x[8] //Keeps track of x coordinates private real array y[8] //Keeps track of y coordinates private real array angle[8] //Keeps track of angle when shot private unit array paintballs[8] //Keeps track of untis private unit owner //The unit casting the spell private integer id //The player's id private integer inGroup = 0 //Quick response to counting units in group private string color //Color of paintball private group onField //Units that are not hidden and are being used (I attempt to recycle) private integer array movements[8] //The amount of movements the paintball has moved private integer maxMovements = 40 //The max amount of movements till kill is called static method create takes real x, real y, real angle, unit owner, string color returns paintball //Sets everything up local paintball newBall = paintball.allocate() local integer i = 0 set newBall.owner = owner set newBall.id = GetPlayerId(GetOwningPlayer(owner)) set newBall.color = color set newBall.onField = CreateGroup() loop set newBall.x[i] = x set newBall.y[i] = y call newBall.createBalls(i) call ShowUnit(newBall.paintballs[i], false) set newBall.angle[i] = angle call paint(newBall.color, newBall.paintballs[i]) set i = i + 1 exitwhen i > 7 endloop set owner = null return newBall endmethod private method createBalls takes integer i returns nothing //Creates the paintballs, would not work in create set this.paintballs[i] = CreateUnit(Player(this.id), 'h000', this.x[i], this.y[i], this.angle[i]) endmethod method shootPaintball takes real angle returns nothing //Fake creating of paintballs local integer i = 0 loop if( IsUnitInGroup(this.paintballs[i], this.onField) == false ) then //Check to see if already used set this.movements[i] = 0 set this.angle[i] = angle set this.inGroup = this.inGroup + 1 call GroupAddUnit(this.onField, this.paintballs[i]) //Add to moving units ////////////Move to caster/////////// set this.x[i] = GetUnitX(this.owner) set this.y[i] = GetUnitY(this.owner) call SetUnitX(this.paintballs[i], this.x[i]) call SetUnitY(this.paintballs[i], this.y[i]) ///////////////////////////////////// call ShowUnit(this.paintballs[i], true) call UnitAddAbility(this.paintballs[i], 'Aloc') set i = 10 endif set i = i + 1 exitwhen i > 7 endloop endmethod method kill takes unit u, integer i returns nothing //Fake kill of paintballs call GroupRemoveUnit(this.onField, u) set this.inGroup = this.inGroup - 1 set this.x[i] = 3945 set this.y[i] = -3468 call SetUnitX(this.paintballs[i], this.x[i]) call SetUnitY(this.paintballs[i], this.y[i]) call ShowUnit(this.paintballs[i], false) endmethod method count takes nothing returns integer //Quick return of count units in group return this.inGroup endmethod method move takes nothing returns nothing //Moves the paintball local real dist = 30 local integer i = 0 loop //Move all units if(IsUnitInGroup(this.paintballs[i], this.onField) == true) then //Move only onField units set this.x[i] = this.x[i] + dist * Cos(this.angle[i] * bj_DEGTORAD) set this.y[i] = this.y[i] + dist * Sin(this.angle[i] * bj_DEGTORAD) call SetUnitX(this.paintballs[i], this.x[i]) call SetUnitY(this.paintballs[i], this.y[i]) set this.movements[i] = this.movements[i] + 1 if this.movements[i] == this.maxMovements then //Check to see when done moving. call this.kill(this.paintballs[i], i) endif endif set i = i + 1 exitwhen i > 7 endloop set tempStruct = this call ForGroup(allPlayers, function enumUnit) //Check Distance Units call EnumDestructablesInRect(bj_mapInitialPlayableArea, null, function enumDestructable) //Check Distance Destructables endmethod method changeColor takes string color returns nothing //Change color of paintball local integer i = 0 set this.color = color loop call paint(this.color, this.paintballs[i]) set i = i + 1 exitwhen i > 7 endloop endmethod method splat takes unit u, destructable d returns nothing //Checks to see if paintball hits a unit local integer i = 0 if u == null then //Checks to see if destructable loop if Distance(this.x[i], this.y[i], GetDestructableX(d), GetDestructableY(d)) <= 70 then //Check Distance //////////Sound Effects/////////// if GetDestructableTypeId(d) == 'LTbr' then //If barrel call StartSound( gg_snd_wood ) elseif GetDestructableTypeId(d) == 'B001' then //If tree call StartSound( gg_snd_tree ) endif ///////////////////////////////// call this.kill(this.paintballs[i], i) endif set i = i + 1 exitwhen i > 7 endloop elseif GetUnitTypeId(u) != 'h000' and u != this.owner then //Checks to see if unit and not a paintball and not owner loop if Distance(this.x[i], this.y[i], GetUnitX(u), GetUnitY(u)) <= 65 then //Check Distance call paint(this.color, u) call SetUnitState(u, UNIT_STATE_LIFE, GetUnitState(u, UNIT_STATE_LIFE) - 1) //////////Sound Effect/////////// call StartSound( gg_snd_flesh ) ////////////////////////////////// call this.kill(this.paintballs[i], i) endif set i = i + 1 exitwhen i > 7 endloop endif set u = null set d = null endmethod endstruct |
| 02-22-2010, 03:32 PM | #2 |
Does anyone happen to know, or do I need to explain my problem better? |
| 02-22-2010, 03:50 PM | #3 |
Function calls in JASS are slow. (vJass method calls compile down to function calls.) Avoid them at all costs in code that needs to be optimized. Only optimize code that needs to be optimized. (Don't heavily optimize shit like stuff that runs on map init or a few times a minute or the like. That is almost completely pointless, and very insane.) Don't use periodic triggers. Use timers. The best way to do a lot of stuff on a very quick periodic timer is to build a list of active objects, and iterate through that list in a single periodic timer using one giant ass function to do all the heavy lifting. Avoid using unit groups for the most part, as there are much quicker (and often times better) ways to do something without them. (There are some exceptions to this, of course.) I'm really too lazy to heavily look over your code and give more specific examples, but this should be enough information to hopefully get you more on the right track to optimized JASS. If you need more help, do ask. |
| 02-22-2010, 10:05 PM | #4 |
Also, strings are quite slow in Jass, you might want to replace your paint string arguments with integers or maybe ARGB objects. okay, since you call it only 1 time in the create method, it should be insignificant |
| 02-23-2010, 02:31 PM | #5 |
By looking at your code it seems to me that whenever your "move" method is called, you iterate over all units in a group "allPlayers", and for all living units in that group you call the "splat" method of a paintball from above it's declaration. Such calls are implemented in jasshelper by using TriggerEvaluate among other things, which is even slower than normally calling a function in jass. You also seem to do the same thing for presumably almost all destructables on the map. However, out of all of those units, you act only on the ones in a 70.0 radius of any of the paintball units of the paintball struct in question. What you should do, is to enumerate only the units or destructables in that radius (or a bit larger) in the first place with GroupEnumUnitsInRange and whatever destructable counterpart comes closest to that. You should also try to move around your code to avoid unnecessary TriggerEvaluates. Also you might want to store values such as dist * Cos(this.angle[i] * bj_DEGTORAD) in fields instead of computing them at every occasion anew. Finally, you should probably have a single struct for every paintball unit instead of multiple ones, in order to avoid all of those IsUnitInGroup checks. @Kueken He has only a small set of different color strings so leaks shouldn't be a problem if that was what you meant with "strings are quite slow in Jass". |
| 03-04-2010, 03:01 AM | #6 |
Ok sorry been busy lately. I fixed it up a bit, and so far it is a lot better. I will rep you all since you all helped in ways. I have not made each paintball an instance yet, want to get everything running smoothly first before I make drastic changes like that. How exactly would I be using a timer instead of using the event, could someone care to explain? Like would I create one and have it run periodically at the beginning of the game? |
