Jump to content

[SA|SCM] Mission Coding for Dummies!


Recommended Posts

Geplaatst:

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. :)

Geplaatst:

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

post-33831-1247910184_thumb.jpg

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. :)

  • 3 years later...
Geplaatst:

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. :)

Gast
Dit onderwerp is gesloten.
  • Recent actief   0 leden

    • Er zijn hier geen geregistreerde gebruikers aanwezig.
×
×
  • Create New...