System Configuerable Sliding System - CSS

Dr.Jack

That's Cap'n to you!
Reaction score
109
Configuerable Sliding System - CSS

Well I needed a sliding system. Simple one. Up to date one. Comfortable one. Flexible enough to fit almost all my needs. And so SSS was born. Originally made for personal use. And then I noticed we don't have any up to data sliding systems here on TH.net. So with a small "what the heck" I posted it. After that with slight improvement I posted ASS (advanced sliding system) that basically did the same thing but used one timer instead of one timer per instance.

Well, SSS and ASS were really basic. Purely made to save some typing time. And I didn't like that. I wanted to create a system that could do more than that but still save its simplicity, lightness and user-friendlieness. So CSS was created instead of S/ASS.

It works similarly to ASS. CSS as hinted in its name is more configuerable. There are more function, more options and it is more optimized.

So what is CSS?

  • A simple sliding system able to slide a unit to a certain point - calculated by distance and angle, by coordinates or by unit's facing (updated).
  • Speed is configurable.
  • One timer controls the whole system.
  • A very light, simple, user-friendly system.
  • Requires NewGen version 1.5 or better.
  • Can be used easily by GUI users.
  • MUI of course, if there was any doubt.
  • Any slide can be stopped at any moment.
  • Slide's parameter can be changed while its execution.
  • Can execute a trigger at the end of the slide. (Added by request)
  • Can check terminate slides if unit reach unpathable location.
  • Includes documentation and comments.
  • Uses PUI. Thanks Cohadar!
  • Uses Events. Thanks Jesus4Lyf

JASS:
library CSS initializer init needs PUI, Event

globals
    private real PERIOD = 0.025 // How often the timer runs
    private boolean PATHCHECK = true // False if you don't want to check pathability
    private pathingtype PATH = PATHING_TYPE_WALKABILITY // What kind of pathability to check?
    
    // DO NOT MESS WITH
    private timer CORE
    private group LIST // *Shrug* Groups are comfortable.
endglobals

struct CSS
    real ang
    real tck
    real ts
    real x
    real y
    real cX
    real cY
    Event e
    unit u
    boolean fac = false // Facing based?
endstruct

private function coreFunc takes nothing returns nothing
    local CSS data
    local real x
    local real y
    local real tx
    local real ty
    local real tck
    local real fac
    
    local unit u
    local group l = CreateGroup()
    
    call GroupAddGroup(LIST, l) // *GASP* a BJ
    
    loop
        set u = FirstOfGroup(l)
        exitwhen u == null

        set data = GetUnitIndex(u)
        set tck = data.tck
        if data.fac then // Need to update angle.
            set fac = GetUnitFacing(u)
            if (data.ang != fac) then
                set data.cX = data.ts * Cos(fac * bj_DEGTORAD)
                set data.cY = data.ts * Sin(fac * bj_DEGTORAD)
            endif
        endif
        set tx = data.x + data.cX
        set ty = data.y + data.cY
        
        if PATHCHECK and IsTerrainPathable(tx,ty, PATH) then
            set tck = 0
        else        
            call SetUnitPosition(u,tx,ty)
        endif
        
        set tck = tck -1
    
        if tck <= 0 then // Unit reached its destinatin.
            call GroupRemoveUnit(LIST, u)
            set data.fac = false
            call data.destroy()
            call data.e.fire()
            call data.e.chainDestroy()
        endif
    
        set data.x = tx
        set data.y = ty
        set data.tck = tck
        
        call GroupRemoveUnit(l, u)
    endloop
    
    // No leaks KTHXBYE.
    call DestroyGroup(l)
    set l = null
    set u = null
endfunction

// Start a slide based on distance & angle.
public function Start takes real dis, real ang, real spd, unit unt returns integer
    local CSS data = GetUnitIndex(unt) // Structs are integer so we can safely use
    // PUI to create the struct.
    
    set data.ang = ang // Ang is just for easier calculations, not really needed.
    set data.ts = spd * PERIOD // Distance the unit will move every timer run
    set data.tck = (dis/spd)/PERIOD // How many timer runs before the process ends.
    set data.x = GetUnitX(unt)
    set data.y = GetUnitY(unt)
    set data.cX = data.ts * Cos(ang * bj_DEGTORAD) // Shortens calculations
    set data.cY = data.ts * Sin(ang * bj_DEGTORAD)
    set data.u = unt
    
    call GroupAddUnit(LIST, unt)
    
    return GetUnitIndex(unt)
endfunction

// Start a slide based on unit's facing.
public function FacingStart takes real dis, real spd, unit unt returns integer
    local CSS data = GetUnitIndex(unt)
    
    set data.fac = true
    call Start(dis, GetUnitFacing(unt), spd, unt)
    
    return GetUnitIndex(unt)
endfunction

// Start a slide by giving coords.
public function CoordsStart takes real x, real y, real spd, unit unt returns integer
    local real ux = GetUnitX(unt)
    local real uy = GetUnitY(unt)
    local real ang = bj_RADTODEG * Atan2(y - uy, x - ux)
    local real dis
    
    set dis = SquareRoot((ux - x) * (ux - x) + (uy - y) * (uy-y))
    
    call Start(dis, ang, spd, unt)
    
    return GetUnitIndex(unt)
endfunction

// Terminate current slide
public function Stop takes integer i returns nothing
    local CSS data = i
    set data.fac = false
    call GroupRemoveUnit(LIST, data.u)
    call data.destroy()
endfunction

// Modify Speed
public function ModSpeed takes integer i, real spd returns nothing
    local CSS data = i
    set data.ts = spd * PERIOD
    set data.cX = data.ts * Cos(data.ang * bj_DEGTORAD)
    set data.cY = data.ts * Sin(data.ang * bj_DEGTORAD)
endfunction

// Disables unit facing. Modifies sliding angle.
public function ModAngle takes integer i, real ang returns nothing
    local CSS data = i
    set data.ang = ang
    set data.cX = data.ts * Cos(data.ang * bj_DEGTORAD)
    set data.cY = data.ts * Sin(data.ang * bj_DEGTORAD)
    set data.fac = false
endfunction

// Modify the distance (new one from current position)
public function ModDistance takes integer i, real dis returns nothing
    local CSS data = i
    local real spd = data.ts / PERIOD
    set data.tck = (dis/spd)/PERIOD
endfunction

// Executes and trigger at the end of the slide.
public function SetEvent takes integer i, trigger t returns nothing
    local Event e = Event.create()
    local CSS data = i
    set data.e = e
    call e.register(t)
endfunction

// In case you don't want to deal with PUI...
public function U2I takes unit u returns integer
    return GetUnitIndex(u)
endfunction
    
// Create timer and group.
private function init takes nothing returns nothing
    set CORE = CreateTimer()
    set LIST = CreateGroup()
    
    call TimerStart(CORE, PERIOD, true, function coreFunc)
endfunction

endlibrary


How does it work? Quite simply. There is one timer and one group creates. The timer is executed every so much time. Every unit that slides is added to the group that is looped through every time execution. The code calculates where the unit should go to and moves it to that location. That's it.

Enjoy. I would love to hear comments. :thup:
 

Attachments

  • CSS.w3x
    40.1 KB · Views: 198

cleeezzz

The Undead Ranger.
Reaction score
268
hmm nice and short system +rep

but i have a question, what if the user wanted to make it slide based on unit facing (such as sliding on ice maps)

as far as i can see, the user would probably have to do a 0.03 (or something low) and repeatedly slide the unit a short distance in front of the unit
 

Dr.Jack

That's Cap'n to you!
Reaction score
109
hmm nice and short system

but i have a question, what if the user wanted to make it slide based on unit facing (such as sliding on ice maps)

as far as i can see, the user would probably have to do a 0.03 (or something low) and repeatedly slide the unit a short distance in front of the unit

Are you talking about the situation that the unit while sliding changes its facing angle and the user would want to change the direction accordingly?

If so you have a point the system currently doesn't allow that. I will be sure to add it in the next version which will probably be uploaded tomorrow.

Thanks for the critique!
 

Tru_Power22

You can change this now in User CP.
Reaction score
144
That's a nice ASS. Seriously, this looks to be quite easy to use. Unfortunately, I don't have any projects on the go that need this.
 

quraji

zap
Reaction score
144
Haven't really looked at the code, but I suggest naming the functions in a more friendly and explicit way. And you could use a few more.
Maybe: StartSlide(), StopSlide(), StartSlideFacing (for updating w/ unit facing).

I also suggest just taking the better of the two and naming it SSS, having two that do the same thing is confusing. Base the 'simple' and 'advanced' on the features, not the implementation. It may be more advanced to you, but to someone not concerned with the code itself, it would be the same.

Also a tiny description on how to use the function would be nice in a comment inside the system (at the top).

Other than that, nice code. Very simple, which is good.
 

Dr.Jack

That's Cap'n to you!
Reaction score
109
Version 2. will be posted today including!...

  • A new mini-system CSS includes many more customized options.
  • Comments inside the code.
  • Improved documentation
  • MAY include pathing checks and include functions execution.
 

Trollvottel

never aging title
Reaction score
262
Actually the Coding is awful.

JASS:
set ts = data.ts
        set ang = data.ang
        set tck = data.tck
        set tx = x + ts * Cos(ang * bj_DEGTORAD)
        set ty = y + ts * Sin(ang * bj_DEGTORAD)
        
        call SetUnitPosition(u,tx,ty)


-Why do you always pass the struct members to locals?
-Why do you always call these trigonometric functions instead of just storing this ts*Cos(ang) in a variable
-Why du you use this bj_DEGTORAD, you convert everything at the beginning.

JASS:
globals
    private real PERIOD = 0.025
    private timer CORE
    private group LIST // *Shrug* Groups are comfortable.
endglobals


CORE and LIST arent configurables, why are they in the same globals block?


Also this group enumeration is crap. If you have 100 units sliding you have to loop 100 times to add all units to the group and then loop 100 times again just to move them.


Good thing is that you use ticks.

And Imo this isnt really an advanced sliding system, i mean you cant configure much. What if i want to have friction, what if i want units to fall down, when they slide over cliffs or bounce off etc. Actually both are really basic and need much coding improvement.
 

Dr.Jack

That's Cap'n to you!
Reaction score
109
Actually the Coding is awful.

As for the coding being awful, that made true, however I tested the system with multiple instances and I saw no effect on the gameplay. I will be sure to improve it the best I can! My apologies if I have some basic mistakes, as said it has been a while since I dealt with Jass.

Thanks for the critique! Those are the best kind I appreciate you being straight forward.

-Why do you always pass the struct members to locals?
-Why do you always call these trigonometric functions instead of just storing this ts*Cos(ang) in a variable
-Why du you use this bj_DEGTORAD, you convert everything at the beginning.

I think I stated it again and again this system is meant to be simple. The new CSS will be more optimize. Passing struct members to hardly slows down and code and it makes it cleaner. As for storing it on the struct you are probably right, it will be a good idea to do that. Thanks.

CORE and LIST arent configurables, why are they in the same globals block?

Pfft I don't think anyone will deal with those but I'll be sure to mention it in the next version.

Also this group enumeration is crap. If you have 100 units sliding you have to loop 100 times to add all units to the group and then loop 100 times again just to move them.

As stated this system has been tested and I saw no effect on the gameplay. Doing the same thing without groups is really not worth the effort. If anyone reports it to be a problem I'll see if I can find away around it.

Good thing is that you use ticks.
;)


And Imo this isnt really an advanced sliding system, i mean you cant configure much. What if i want to have friction, what if i want units to fall down, when they slide over cliffs or bounce off etc. Actually both are really basic and need much coding improvement.

Ok way too many people complained on the naming. A name is just a name. I'll change it but really since when does it really matter? The system as it is is not meant to allow these kind of things. Why? It is just not what I'm looking for. As stated it was built for personal use and then when seeing there is no simple, easy-to-use, up do date system I decided to post it.

Thanks again for the critique all is taken to consideration and I hope you will find version 2 more satisfying.
 

RaiJin

New Member
Reaction score
40
JASS:
exitwhen u==null
should be right after set u=FirstOfGroup() because the whole loop will run even if u==null and you don't have to set u=null at the end because its already null'd when you exit the loop
 

Trollvottel

never aging title
Reaction score
262
Okay, i see you changed the code a lot. I will look through it later.

As stated this system has been tested and I saw no effect on the gameplay.

In which map did you test it? Mention that you have to test it on big maps where about 50 Triggers/Timers are running at the same time and where a lot of units are moving.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
Cos(<real>) and Sin(<real>) are not that slow, in fact they are as fast as reading a real array variable.
Benchmark it if you don't believe it.

So in a real game it shouldn't be noticeable.
 

quraji

zap
Reaction score
144
Cos(<real>) and Sin(<real>) are not that slow, in fact they are as fast as reading a real array variable.
Benchmark it if you don't believe it.

So in a real game it shouldn't be noticeable.

If true, that's a majorly good thing for all the projectile/slide/whatever systems using polar projection :p

Anyways, I like the look of the new one, the function names are much better this time :thup:
Too lazy to look at the code right now though, but good job at reconstructing this.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
It's true, or al least that was true few patchs before this one.
We don't have japi Stopwatch native for this patch for the moment, but i'm sure we will get them, and then you will be able to test it.
 

Trollvottel

never aging title
Reaction score
262
still we should use the MOST performant way. it wasnt only the Cos/Sin but also 2 multiplications. This doesnt seem much but a system should be as performant as possible. So he shouldnt use groups just because it is more handy, a system should be easy to use but also be very effective. filling and emptying a group each interval is not effective. Even if it doesnt cause laggs, it is bad to do this.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
still we should use the MOST performant way. it wasnt only the Cos/Sin but also 2 multiplications. This doesnt seem much but a system should be as performant as possible. So he shouldnt use groups just because it is more handy, a system should be easy to use but also be very effective. filling and emptying a group each interval is not effective. Even if it doesnt cause laggs, it is bad to do this.
Yes ofc i'm agree, i just wanted to say that trigonometric functions are pretty fast (for jass2)
 

Jesus4Lyf

Good Idea™
Reaction score
397
>_<

Hate to say it, Jack, but I think you're doing it wrong. :(

My feedback...

A new Event should only be attached if one doesn't exist on the unit. So knocking a unit twice, and adding a different trigger from each knockback should result in the knockbacks being merged and both triggers being added to the one event.

Personally I'd make the knocks overwrite if you knock a knocked unit (which I believe you have done). I think that's the best for gameplay (my opinion). Also, I think you'll find this is less efficient since you removed KT2 and used a group instead, because of the O(n) group add group call. You'd be better off using globals and a ForGroup call, otherwise I don't recommend you use groups.

The purpose of Event is that you can register any number of triggers on the one Event. So, for example, for a knockback, let's say at the end of one knockback you're meant to damage all units in an AoE (some ability). Then, you get hit by another knockback spell that is meant to slow you at the end. Using Event, you could use your knockback system to make the second knockback override the first, but STILL keep the damage on AoE at the end (also, chainDestroy the event once the knockback is finished). So you can have the slow and the AoE damage by registering two triggers on the one Event for the unit.

I don't know if you had it, but there should be an event response provided for getting the knocked unit for triggers registered on the Event, and maybe even expose EventReg style data attachment. Seems to have a use here (for example, dealing damage to the knocked unit at the end of the slide - you need to store the source).

Hm!
 

Dr.Jack

That's Cap'n to you!
Reaction score
109
Thanks for the critique guys! Seems I forgot much more than I thought I did, and my apologies for posting a system that is obviously not optimized. I was sure it is! :eek:

All your critique is taken to consideration as you saw and I do appreciate it! I hope to post a new version soon taking everything to consideration and optimizing the system.

Until then, thanks for the reviews! :thup:
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +1
  • V-SNES V-SNES:
    Happy Friday!
    +1

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top