• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Looking for tips: Cinematic System

Status
Not open for further replies.
Level 19
Joined
Oct 12, 2007
Messages
1,821
Hey there,

I was wondering if some people would like to share their opinions on what kind of a cinematic system I might need.

I'm making a turn based map, so units never cast spells at the same time. Because of this I want to code some camera movement + unit animations + special effects to happen whenever a unit casts a spell. During this time the unit will be paused, but the UI won't go into cinematic mode.
(So Camera functions, Unit animations and special effects have to be able to put into a certain order, while adding other functions like setting variables and dealing damage also has to happen at specific times.)

What would be a good system to support me in doing this?
The only system I could find was Anitarf's Cinematic System from back in 2006, but have betters been released ever since?
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
To be honest, I don't think there is such a system out there.

As I understand it, it's quite simple though.
Unit casts spell
enter cinematic mode
disable unit control
do stuff depending on spell
end cinematic mode after X seconds
enable unit control

is that correct?

Basically:
- Unit Casts Spell
- Disable unit control (but don't start cinematic mode)
- Force camera stuff for all players, like camera point changing from Camera Object X to Object Y over time.
- During the camera movement do spell stuff (a very important part of that is special effects and unit animations that are timed in a good way. Maybe even changing unit animation speed and stuff like that)
- Go back to the normal camera mode and enable unit control again.


Let's say I use Breath of Fire on this. Then a unit casts a dummy spell that has no target. After that he will be paused and face towards an enemy over X seconds. During this time the camera zooms in on the unit and starts to turn 180 degrees. After the X seconds he will play his Spell Slam animation while at the same time a Fire Breath special effect pops up. Units hit by the fire breath (so after maybe 0.4 seconds of the animation) will take damage which needs to be coded with certain variables. After the animation is done the camera will possibly be done with turning 180 degrees and the camera will go back to the normal game view while the unit will be unpaused.
 
To me, the easiest way to do this would be using a combination of TimerUtils and a unit indexer (such as AutoDex). Basically, you have a set of functions which does stuff like turning a unit, dealing damage to a target, etc. When the cinematic starts, you start a set of timers, and attach the unit ID (from the indexer) to the timer (using NewTimerEx from TimerUtils). Once the timer expires, the function can load the unit using:
JASS:
local unit u = GetUnitById(GetTimerData(GetExpiredTimer()))  //after which you release the timer.

Now, if you want to attach multiple units to a timer, you can use a struct instead of a unit id. Actually, you can base the whole system around a struct and just use different "event ids" for the different types of actions you want to apply. This is a VERY sketchy version of what you might do:

JASS:
globals
    private constant integer EVENT_TYPE_FACING = 1
    private constant integer EVENT_TYPE_DAMAGE = 2
    private constant integer EVENT_TYPE_ANIM = 3
endglobals

struct CineEvent
    unit caster
    unit target
    real duration
    string txt
    //....etc for all the variables you might need to transfer
    integer eventtype

    static method expire takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        
        if this == 0 then //Check if struct is valid
            return
        endif

        if .eventtype = EVENT_TYPE_FACING then
            call SetUnitFacingToFaceUnitTimed(.caster, .target, .duration) //Sorry for BJ
        elseif .eventtype = EVENT_TYPE_DAMAGE then
            call UnitDamageTarget(.caster, .target, etc...)
        elseif .eventtype = EVENT_TYPE_ANIM then
            call SetUnitAnimation(.caster, .txt)
        endif

        call .destroy()
        call ReleaseTimer(GetExpiredTimer())
    endmethod

    static method create takes unit caster, unit target, integer eventtype, real timeout returns thistype
        local thistype this = thistype.allocate()

        set .target = target
        set .caster = caster
        set .eventtype = eventtype

        call TimerStart(NewTimerEx(this), timeout, false, function thistype.expire)

        return this    
    endmethod
endstruct

If you end up with an awful lot of parameters for the constructor, you might want to simplify it and instead run the timer in a separate method, kinda like this:

JASS:
static method create takes nothing returns thistype
    local thistype this = thistype.allocate()

    return this
endmethod

method run takes real timeout returns nothing
    call TimerStart(NewTimerEx(this), timeout, false, function thistype.expire)
    //You might need some kind of check to make sure that all necessary values are filled (such as caster).
endmethod

//Then you can run an event like this:
function TestFunction takes unit whichunit returns nothing
    local CineEvent MyEvent = CineEvent.create()
    set MyEvent.eventtype = EVENT_TYPE_ANIM
    set MyEvent.txt = "Stand - 1"
    set MyEvent.caster = whichunit
    //And then run it:
    call MyEvent.run(10.)
endfunction
 
Status
Not open for further replies.
Top