Dutchy3010 Geplaatst: 18 juli 2009 Auteur Rapport Geplaatst: 18 juli 2009 Cutscenes In deze tutorial ga ik de basis van een cutscene uitleggen. Het is moeilijk om te vertellen hoe je een cutscene moet maken, omdat elke cutscene anders is. Echter, ik denk dat je het kunt leren als ik uitleg hoe je een simpele cutscene kunt coden. Daarom heb ik zelf een kleine, simpele cutscene gemaakt, en ik zal uitleggen hoe. Onthoudt dat je bijna elke opcode die je erbij zet moet testen. Zo kan je bijvoorbeeld met waits ertussen alles veel mooier maken, moet je testen voor de camera, etcetera. Example cutscene Een cutscene is eigenlijk gewoon een hoop opcodes die draaien zonder input van de player. Wanneer de player niets akn doen, en gewoon moet kijken, is er een cutscene. Onthoudt dit in deze tutorial. We zullen starten met de volledige code van de cutscene die ik gescript heb: //--------------------- //Start Cutscene //--------------------- :CUTSCENE 03BC: $begin = create_sphere_at 2489.0088 -1658.4554 13.3519 radius 1.0 repeat wait 0 until 00FE: actor $PLAYER_ACTOR sphere 0 in_sphere 2489.0088 -1658.4554 13.3519 radius 1.0 1.0 1.0 Player.CanMove($PLAYER_CHAR, false) //--------------------- //Load Models //--------------------- model.Load(#army) model.Load(#patriot) model.load(#m4) 023C: load_special_actor 'SWEET' as 1 // models 290-299 023C: load_special_actor 'KENDL' as 2 // models 290-299 023C: load_special_actor 'CESAR' as 3 // models 290-299 038B: load_requested_models :load_check wait 0 if and model.available(#army) model.available(#patriot) model.available(#m4) 023D: special_actor 1 loaded 023D: special_actor 2 loaded 023D: special_actor 3 loaded else_jump @load_check //--------------------- //Spawn everything in fade //--------------------- fade 0 500 repeat wait 0 until 816B: not fading 02A3: enable_widescreen 1 03BD: destroy_sphere $begin Car.Create($car, #patriot, 2503.0217, -1672.2841, 13.3594) Car.Angle($car) = 82.3844 0129: 1@ = create_actor_pedtype 23 model #army in_car $car driverseat 01C8: 2@ = create_actor_pedtype 23 model #army in_car $car passenger_seat 0 01C8: 3@ = create_actor_pedtype 23 model #army in_car $car passenger_seat 1 01C8: 4@ = create_actor_pedtype 23 model #army in_car $car passenger_seat 2 01B2: give_actor 1@ weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor 2@ weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor 3@ weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor 4@ weapon 31 ammo 60 // Load the weapon model before using this 009A: 5@ = create_actor_pedtype 4 model #SPECIAL01 at 2479.1279 -1680.2635 13.338 Actor.Angle(5@) = 359.6866 009A: 6@ = create_actor_pedtype 4 model #SPECIAL02 at 2477.7996 -1678.5049 13.3386 Actor.Angle(6@) = 266.6259 009A: 7@ = create_actor_pedtype 4 model #SPECIAL03 at 2479.3577 -1676.2166 13.337 Actor.Angle(7@) = 176.3852 00A1: put_actor $PLAYER_ACTOR at 2480.9185 -1678.2045 13.3404 Actor.Angle($PLAYER_ACTOR) = 98.7008 04ED: load_animation "GANGS" repeat wait 0 until 04EE: animation "GANGS" loaded 0605: actor 5@ perform_animation_sequence "PRTIAL_GNGTLKA" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -1 0605: actor 6@ perform_animation_sequence "PRTIAL_GNGTLKB" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -1 0605: actor 7@ perform_animation_sequence "PRTIAL_GNGTLKC" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -1 0605: actor $PLAYER_ACTOR perform_animation_sequence "PRTIAL_GNGTLKC" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -1 Camera.SetPosition(2472.7151, -1681.5944, 16.9041, 0.0, 0.0, 0.0) Camera.PointAt(2494.2827, -1669.9541, 13.3359, 2) wait 2000 00A7: car $car drive_to 2487.1799 -1670.8324 13.3359 fade 1 500 repeat wait 0 until 816B: not fading //--------------------- //Behaviour after fade //--------------------- repeat wait 10 until 01AE: car $car sphere 0 near_point 2487.1799 -1670.8324 radius 3.0 3.0 stopped 0160: set_camera_point_at 2494.2827 -1669.9541 9.3359 mode 2 05CD: AS_actor 1@ exit_car $car 05CD: AS_actor 2@ exit_car $car 05CD: AS_actor 3@ exit_car $car 05CD: AS_actor 4@ exit_car $car 0635: AS_actor 1@ aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor 2@ aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor 3@ aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor 4@ aim_at_actor $PLAYER_ACTOR -1 ms 074D: AS_actor $PLAYER_ACTOR turns_to_and_look_at_actor 1@ timelimit -1 074D: AS_actor 5@ turns_to_and_look_at_actor 1@ timelimit -1 074D: AS_actor 6@ turns_to_and_look_at_actor 1@ timelimit -1 074D: AS_actor 7@ turns_to_and_look_at_actor 1@ timelimit -1 wait 2500 05C4: AS_actor $PLAYER_ACTOR hands_up -1 ms 05C4: AS_actor 5@ hands_up -1 ms 05C4: AS_actor 6@ hands_up -1 ms 05C4: AS_actor 7@ hands_up -1 ms wait 5000 //--------------------- //Cleanup //--------------------- fade 0 500 repeat wait 0 until 816B: not fading 00A6: destroy_car $car 009B: destroy_actor 1@ 009B: destroy_actor 2@ 009B: destroy_actor 3@ 009B: destroy_actor 4@ 009B: destroy_actor 5@ 009B: destroy_actor 6@ 009B: destroy_actor 7@ 0687: clear_actor $PLAYER_ACTOR task Player.CanMove($PLAYER_CHAR, true) 0373: set_camera_directly_behind_player 02EB: restore_camera_with_jumpcut 02A3: enable_widescreen 0 wait 2000 fade 1 500 repeat wait 0 until 816B: not fading Verhaal en begin Het verhaal is: er is een Patriot, met 4 army actors erin. Er zijn ook 4 special actors: Sweet, Kendl, Cesar en CJ. Deze actors praten met elkaar (met een animatie). De Patriot moet naar de 4 special actors rijden, en de army mannen moeten uit de auto gaan. Dan moeten de 4 special actors naar de army mannen draaien. Deze army mannen hebben een M4 en richten op de groep van 4 special actors. Tot slot geven de 4 special actors zich over (handen omhoog). We zullen een sphere maken, waar de player in moetgaan staan voor de cutscene begint. Het zal raar zijn wanneer de player CJ kan bewegen tijdens de cutscene, daarom maken we het zo dat hij niet kan bewegen. Daarna zullen we alles laden wat in de cutscene gebruikt wordt. Ik denk niet dat ik dat nog eens uit moet leggen. //--------------------- //Start Cutscene //--------------------- :CUTSCENE 03BC: $begin = create_sphere_at 2489.0088 -1658.4554 13.3519 radius 1.0 repeat wait 0 until 00FE: actor $PLAYER_ACTOR sphere 0 in_sphere 2489.0088 -1658.4554 13.3519 radius 1.0 1.0 1.0 Player.CanMove($PLAYER_CHAR, false) //--------------------- //Load Models //--------------------- model.Load(#army) model.Load(#patriot) model.load(#m4) 023C: load_special_actor 'SWEET' as 1 // models 290-299 023C: load_special_actor 'KENDL' as 2 // models 290-299 023C: load_special_actor 'CESAR' as 3 // models 290-299 038B: load_requested_models :load_check wait 0 if and model.available(#army) model.available(#patriot) model.available(#m4) 023D: special_actor 1 loaded 023D: special_actor 2 loaded 023D: special_actor 3 loaded else_jump @load_check Fade en spawns Om te beginnen moet je wat "fade" gebruiken, omdat je anders alles zou zien spawnen en dat is niet mooi. Eerst je moet fade gebruiken en vervolgens moet je wachten tot het niet meer fade, dus het scherm zwart is. Anders is het scherm nog niet zwart en zie je alles alsnog spawnen. Na die loop moet je alles spawnen wat je op dat moment in je cutscene wil. //--------------------- //Spawn in fade //--------------------- fade 0 500 repeat wait 0 until 816B: not fading 02A3: enable_widescreen 1 03BD: destroy_sphere $begin Car.Create($car, #patriot, 2503.0217, -1672.2841, 13.3594) Car.Angle($car) = 82.3844 0129: 1@ = create_actor_pedtype 23 model #army in_car $car driverseat 01C8: 2@ = create_actor_pedtype 23 model #army in_car $car passenger_seat 0 01C8: 3@ = create_actor_pedtype 23 model #army in_car $car passenger_seat 1 01C8: 4@ = create_actor_pedtype 23 model #army in_car $car passenger_seat 2 01B2: give_actor 1@ weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor 2@ weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor 3@ weapon 31 ammo 60 // Load the weapon model before using this 01B2: give_actor 4@ weapon 31 ammo 60 // Load the weapon model before using this 009A: 5@ = create_actor_pedtype 4 model #SPECIAL01 at 2479.1279 -1680.2635 13.338 Actor.Angle(5@) = 359.6866 009A: 6@ = create_actor_pedtype 4 model #SPECIAL02 at 2477.7996 -1678.5049 13.3386 Actor.Angle(6@) = 266.6259 009A: 7@ = create_actor_pedtype 4 model #SPECIAL03 at 2479.3577 -1676.2166 13.337 Actor.Angle(7@) = 176.3852 00A1: put_actor $PLAYER_ACTOR at 2480.9185 -1678.2045 13.3404 Actor.Angle($PLAYER_ACTOR) = 98.7008 04ED: load_animation "GANGS" repeat wait 0 until 04EE: animation "GANGS" loaded 0605: actor 5@ perform_animation_sequence "PRTIAL_GNGTLKA" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -1 0605: actor 6@ perform_animation_sequence "PRTIAL_GNGTLKB" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -1 0605: actor 7@ perform_animation_sequence "PRTIAL_GNGTLKC" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -1 0605: actor $PLAYER_ACTOR perform_animation_sequence "PRTIAL_GNGTLKC" IFP_file "GANGS" 4.0 loop 1 0 0 0 time -1 Camera.SetPosition(2472.7151, -1681.5944, 16.9041, 0.0, 0.0, 0.0) Camera.PointAt(2494.2827, -1669.9541, 13.3359, 2) wait 2000 00A7: car $car drive_to 2487.1799 -1670.8324 13.3359 fade 1 500 repeat wait 0 until 816B: not fading We moeten ook de actors een animatie geven, omdat het eruit moet zien als een gesprek. Daarna misschien het moeilijkste deel van de ctuscenes: de camera. Er is geen makkelijke weg om de camera zo te krijgen zoals jij wilt. Ik gebruikte een jetpack en de coördinaten tool van Sanny Builder. Je zult veel moeten testen om te krijgen wat je wilt. Het is aan te raden om een langere "wait" in de fade te hebben, zodat je niet alsnog dingen na de fade ziet. Maar de "car drive to" moet na de wait, anders zal de auto op zijn bestemming zijn voordat de speler weer iets kan zien! Natuurlijk moeten we aan het einde de fade wegdoen. Gedrag na de fade //--------------------- //Behaviour after fade //--------------------- repeat wait 10 until 01AE: car $car sphere 0 near_point 2487.1799 -1670.8324 radius 3.0 3.0 stopped 0160: set_camera_point_at 2494.2827 -1669.9541 9.3359 mode 2 05CD: AS_actor 1@ exit_car $car 05CD: AS_actor 2@ exit_car $car 05CD: AS_actor 3@ exit_car $car 05CD: AS_actor 4@ exit_car $car 0635: AS_actor 1@ aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor 2@ aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor 3@ aim_at_actor $PLAYER_ACTOR -1 ms 0635: AS_actor 4@ aim_at_actor $PLAYER_ACTOR -1 ms 074D: AS_actor $PLAYER_ACTOR turns_to_and_look_at_actor 1@ timelimit -1 074D: AS_actor 5@ turns_to_and_look_at_actor 1@ timelimit -1 074D: AS_actor 6@ turns_to_and_look_at_actor 1@ timelimit -1 074D: AS_actor 7@ turns_to_and_look_at_actor 1@ timelimit -1 wait 2500 05C4: AS_actor $PLAYER_ACTOR hands_up -1 ms 05C4: AS_actor 5@ hands_up -1 ms 05C4: AS_actor 6@ hands_up -1 ms 05C4: AS_actor 7@ hands_up -1 ms wait 5000 Wat deze code simpelweg zegt is wat de actor moeten doen na de fade. Allereerst moeten we wachten tot de auto op zijn bestemming aankomt. Daarna willen we de camera veranderen, zodat het beter zicht geeft op wat gebeurt. We willen dat de army actors uit de auto komen en op de speler richten (of iemand anders van de 4 special actors). We willen dat de special actors naar de army actors kijken. Maar we moeten even wachten (de wait van 2500 ms), anders zullen de special actors hun handen omhoog doen voordat de army actors op hen richten. Dat ziet er natuurlijk een beetje vreemd uit. Dus na de 2500 ms, zullen ze hun handen omhoog doen en is de cutscene ten einde. Clean up Natuurlijk moeten we dingen opruimen na de cutscene. Om zeker te weten dat niemand dat ziet, moet je eerst weer een fade gebruiken. Dan moeten we de auto en de actors destroyen. De "clear task" opcode wordt gebruikt zodat de speler zijn handen niet meer omhoog heeft na de cutscene. De speler moet ook weer kunnen bewegen na de cutscene, dus we moeten die opcode terug op "true" zetten. De camera moet weer achter de speler en de widescreen moet weer weg. //--------------------- //Cleanup //--------------------- fade 0 500 repeat wait 0 until 816B: not fading 00A6: destroy_car $car 009B: destroy_actor 1@ 009B: destroy_actor 2@ 009B: destroy_actor 3@ 009B: destroy_actor 4@ 009B: destroy_actor 5@ 009B: destroy_actor 6@ 009B: destroy_actor 7@ 0687: clear_actor $PLAYER_ACTOR task Player.CanMove($PLAYER_CHAR, true) 0373: set_camera_directly_behind_player 02EB: restore_camera_with_jumpcut 02A3: enable_widescreen 0 wait 2000 fade 1 500 repeat wait 0 until 816B: not fading Complete code in a stripped main.scm Andere opcodes Er zijn veel meer dingen die je kunt regelen in een cutscene. Je kunt ook gewoon settings veranderen, zoals het weer: 01B6: set_weather 1 Of gewoon het Wanted Level (al raad ik dit niet aan omdat je cutscene dan erg onvoorspelbaar wordt, je weet niet of er politie in de buurt is): 010D: set_player $PLAYER_CHAR wanted_level_to 0 010E: set_player $PLAYER_CHAR minimum_wanted_level_to 2 01F0: set_max_wanted_level_to 6 Iets anders dat je kunt gebruiken in een cutscene, is de "skip cutscene" opcode. Wanneer je een missie maakt, en de player moet het nog een keer doen, dan wil die waarschijnlijk niet de cutscenes opnieuw doen. Er is een oplossing daarvoor. Een voorbeeld van de missie "General Dilemma" (gescript door PatrickW en mij): 0707: start_scene_skip_to @GENDIL_3502 :GENDIL_3502 0701: end_scene_skip if 08D0: cutscene_skipped jf @GENDIL_3523 fade 0 100 :GENDIL_3523 Dus, wanneer de player wil dat de cutscene niet opnieuw komt, gaat hij naar GENDIL_3502. Het zal waarschijnlijk zo zijn dat de "normale" code (dus de code mét de cutscene) er ook komt, daardoor kan je een check maken of de cutscene geskipped is. In dit geval, is er nog fade nodig. Als de cutscene niet geskipped was, dan had hij waarschijnlijk al fade gehad voordat hij bij dit aan komt. Je kunt ook objecten, andere animaties, pickups, teksten, etcetera gebruiken. Zo lang je maar in gedachte houdt dat je alles creeerd en verwijderd in de fades, kan je alles doen! Kijk vooral veel naar de AS opcodes, die erg handig zijn bij het maken van cutscenes. Bijvoorbeeld: 05CD: AS_actor -1 exit_car 22@ Deze opcodes zijn allemaal niet-bestuurbare opcodes, dus erg handig voor in cutscenes! Ik hoop dat je wat meer geleerd hebt over cutscenes. Wanneer je vragen of opmerkingen hebt over deze tutorial, of je hebt een request voor een andere tutorial, dan kan je altijd terecht in het reactietopic.
Dutchy3010 Geplaatst: 18 juli 2009 Auteur Rapport Geplaatst: 18 juli 2009 Menu's In deze tutorial zal ik een screen geven om te illustreren wat ik zeg met text. Dit is het "main panel" van een 0512: show_permanent_text_box 'CLOTHA' Dit is de tekst (textbox) die links boven komt. Het is rood gemarkeerd in de screen. 08D4: $MENU = create_panel_with_title 'DUMMY' position 29.0 145.0 width 220.0 columns 1 interactive 1 background 1 alignment 1 Met deze opcode creeer je een menu. Je moet de menu een naam (variabele/handle) geven, zodat je er later dingen mee kunt doen. Ook moet je een titel geven. DUMMY betekent dat je daar geen tekst wil hebben ingame. Wanneer je wilt dat het menu een titel heeft, dna moet je de tekst-id gebruiken in plaats van 'DUMMY'. Dat is het blauw gemarkeerde deel op de screen. 08DB: set_panel $MENU column 0 header 'DUMMY' data 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' Eerst moet je het een header geven, het geel gemarkeerde deel op de screen. Dan moet je dingen toevoegen die de player kan kiezen. Eén van die dingen is roze gemarkeerd op de screen. Er zijn twee manieren om van hieruit door te gaan. We zullen de makkelijkste manier gaan bekijken. Ik moet toegeven dat ikzelf ook altijd deze manier gebruik: het is makkelijker en overzichtelijk. repeat wait 0 ms if 00E1: player 0 pressed_key 15 then 08DA: remove_panel $MENU 03E6: remove text box jump @END end until 00E1: player 0 pressed_key 16 Dit is een repeat-wait-until structuur, dus de game herhaalt alles tussen repeat en until totdat een conditie waar is. In dit geval, de code zal zich herhalen tot de player een toets heeft gedrukt (16 = SPATIE). Wanneer de speler echter op 15 (ENTER/F) drukt voordat hij op SPATIE drukte, dan zal je het menu en de text box verwijderen. Daarna jump je naar het einde (of het begin, afhankelijk van wat je wilt). 08D7: $choice = panel $MENU active_row 08DA: remove_panel $MENU 03E6: remove text box Nadat de player op "SPATIE" heeft gedrukt, moeten de panel en de text box verwijderd worden. Daarnaast moet je kijken naar wat de player gekozen heeft. Je kunt dat doen met de 08D7 opcode, welke checked wat de laatste actieve lijn van het panel was. Tot slot moet je zeggen wat er gebeurd wanneer de player iets kiest. Let op, dit start met 0, niet met 1! if $choice == 0 then ... end if $choice == 1 then ... end Je moet deze if-then-end structuur even vaak doen als het aantal keuzes. Bijvoorbeeld, wanneer je 5 keuzes hebt, dan moet je deze code gebruiken van $choice == 0 tot en met $choice == 4. Totale code voor een menu 08D4: $MENU = create_panel_with_title 'DUMMY' position 29.0 145.0 width 220.0 columns 1 interactive 1 background 1 alignment 1 08DB: set_panel $MENU column 0 header 'DUMMY' data 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' 'DUMMY' repeat wait 0 ms if 00E1: player 0 pressed_key 15 then 08DA: remove_panel $MENU 03E6: remove text box jump @END end until 00E1: player 0 pressed_key 16 08D7: $choice = panel $MENU active_row 08DA: remove_panel $MENU 03E6: remove text box if $choice == 0 then ... end if $choice == 1 then ... end :END wait 1000 jump @END Hopelijk was dit duidelijk, anders kan je het natuurlijk altijd vragen in het reactietopic.
Dutchy3010 Geplaatst: 12 januari 2013 Auteur Rapport Geplaatst: 12 januari 2013 Door een paar forumupdates was een hoop uit deze tutorial weggevallen. Dit heb ik grotendeels opnieuw moeten schrijven, maar als het goed is staat alles nu correct. Veel succes ermee en vragen mogen in het reactietopic dan wel in een nieuw topic.
Recommended Posts