77# Space/Up/W : jump (only while standing on a platform)
88# Escape : quit
99#
10- # Goal: climb the platforms and touch the gold flag at the top.
10+ # Goal: climb the platforms and reach the door at the top.
1111#
1212# Physics is done in 1 / 256 - pixel fixed point so th at gravity and
1313# velocities have sub - pixel precision. Pixel coordinates are obtained
@@ -30,7 +30,7 @@ WINDOW_TITLE:
3030.stringz "UVM Platformer" ;
3131
3232WIN_STR:
33- .stringz "You reached the goal !\n" ;
33+ .stringz "You win !\n" ;
3434
3535# Platform table: 5 platforms , each is { x , y , w , h } in pixels (i32).
3636. align 4 ;
@@ -59,7 +59,7 @@ PLATFORMS:
5959# L6 key_right 1 if right is held (integer flag)
6060# L7 running 1 while the game loop runs (integer flag)
6161# L8 i platform loop index (integer)
62- # L9 won 1 while overlapping the goal (integer flag)
62+ # L9 won 0 = playing , > 0 = win - animation frame counter
6363# L10 gx scratch: platform x / base address
6464# L11 gy scratch: platform y
6565# L12 gw scratch: platform w
@@ -177,6 +177,9 @@ POLL_DONE:
177177# Quit if requested
178178get_local 7 ; jz EXIT;
179179
180+ # If the win animation is playing , freeze input/physics and skip ahead
181+ get_local 9 ; jnz WIN_UPDATE;
182+
180183# =====================================================================
181184# Compute horizontal velocity from held keys
182185# =====================================================================
@@ -287,28 +290,38 @@ get_local 1; push 8; rshift_i64; push 500; gt_i64; jz NO_RESPAWN;
287290NO_RESPAWN:
288291
289292# =====================================================================
290- # Goal check
293+ # Goal check: reaching the door (pixels 400 , 136 , 24 , 40 - > * 256 )
291294# =====================================================================
292- # Goal flag rectangle in pixels: x= 405 , y= 144 , w= 16 , h= 32 - > * 256
293295get_local 0 ; get_local 1; push 6144; push 8192;
294- push 103680 ; push 36864 ; push 4096 ; push 8192 ;
296+ push 102400 ; push 34816 ; push 6144 ; push 10240 ;
295297call AABB_OVERLAP , 8 ;
296- jz GOAL_OUT ;
297- get_local 9 ; jnz GOAL_DONE ; # already announced this touch
298- push 1 ; set_local 9;
298+ jz RENDER ;
299+ get_local 9 ; jnz RENDER ; # win animation already started
300+ push 1 ; set_local 9; # start it (frame counter = 1)
299301 push WIN_STR ; syscall print_str;
300- jmp GOAL_DONE ;
301- GOAL_OUT:
302+ jmp RENDER ;
303+
304+ # =====================================================================
305+ # Win animation update: physics is frozen , just advance the timer.
306+ # When the animation ends , respawn the player for another go.
307+ # =====================================================================
308+ WIN_UPDATE:
309+ get_local 9 ; push 1; add_u64; set_local 9;
310+ get_local 9 ; push 180; lt_i64; jnz RENDER;
311+ push 10240 ; set_local 0;
312+ push 89600 ; set_local 1;
313+ push 0 ; set_local 2;
314+ push 0 ; set_local 3;
302315 push 0 ; set_local 9;
303- GOAL_DONE:
304316
305317# =====================================================================
306318# Render
307319# =====================================================================
320+ RENDER:
308321# Clear to sky blue ( 0xFF87CEEB in BGRA - as - u32)
309322push PIXEL_BUFFER ; push_u32 0xFF87CEEB; push 307200; syscall memset32;
310323
311- # Draw platforms (green )
324+ # Draw platforms (with bevel shading for depth )
312325push 0 ; set_local 8;
313326RLOOP:
314327get_local 8 ; push 5; ge_i64; jnz RLOOP_END;
@@ -317,21 +330,32 @@ get_local 10; load_u32; # x
317330get_local 10 ; push 4; add_u64; load_u32; # y
318331get_local 10 ; push 8; add_u64; load_u32; # w
319332get_local 10 ; push 12; add_u64; load_u32; # h
320- push_u32 0xFF3CB44B ; # green
321- call FILL_RECT , 5 ; pop;
333+ call DRAW_PLATFORM , 4 ; pop;
322334get_local 8 ; push 1; add_u64; set_local 8;
323335jmp RLOOP ;
324336RLOOP_END:
325337
326- # Draw the goal as a little door
327- push 405 ; push 144;
328- call DRAW_DOOR , 2 ; pop;
338+ # When winning , draw the celebration instead of the normal door/guy
339+ get_local 9 ; jnz RENDER_WIN;
329340
330- # Draw the player as a little guy. Convert fixed point - > pixels.
341+ # Door ground shadow , then the door
342+ push 404 ; push 176; push 24; push 4; push_u32 0xFF2A7A34; call FILL_RECT, 5; pop;
343+ push 400 ; push 136; call DRAW_DOOR, 2; pop;
344+
345+ # Player cast shadow , then the little guy
346+ get_local 0 ; push 8; rshift_i64;
347+ get_local 1 ; push 8; rshift_i64;
348+ call DRAW_SHADOW , 2 ; pop;
331349get_local 0 ; push 8; rshift_i64;
332350get_local 1 ; push 8; rshift_i64;
333351call DRAW_GUY , 2 ; pop;
352+ jmp RENDER_PRESENT ;
334353
354+ RENDER_WIN:
355+ get_local 9 ;
356+ call DRAW_WIN , 1 ; pop;
357+
358+ RENDER_PRESENT:
335359# Present the frame
336360push 0 ; push PIXEL_BUFFER; syscall window_draw_frame;
337361
@@ -443,16 +467,25 @@ ret;
443467# hair , head , eyes , shirt , arms , legs and shoes. Returns 0 .
444468#
445469DRAW_GUY:
446- # hair
447- get_arg 0 ; push 6; add_u64; get_arg 1; push 0; add_u64; push 12; push 3; push_u32 0xFF5A3A1A; call FILL_RECT, 5; pop;
448- # head
449- get_arg 0 ; push 6; add_u64; get_arg 1; push 3; add_u64; push 12; push 8; push_u32 0xFFF0C8A0; call FILL_RECT, 5; pop;
470+ # head (skin)
471+ get_arg 0 ; push 6; add_u64; get_arg 1; push 2; add_u64; push 12; push 9; push_u32 0xFFF0C8A0; call FILL_RECT, 5; pop;
472+ # hair crown (slightly wider than the head , drawn over its top)
473+ get_arg 0 ; push 5; add_u64; get_arg 1; push 0; add_u64; push 14; push 5; push_u32 0xFF5A3A1A; call FILL_RECT, 5; pop;
474+ # left sideburn
475+ get_arg 0 ; push 5; add_u64; get_arg 1; push 5; add_u64; push 2; push 3; push_u32 0xFF5A3A1A; call FILL_RECT, 5; pop;
476+ # right sideburn
477+ get_arg 0 ; push 17; add_u64; get_arg 1; push 5; add_u64; push 2; push 3; push_u32 0xFF5A3A1A; call FILL_RECT, 5; pop;
478+ # swept fringe (longer on the left , short flick on the right)
479+ get_arg 0 ; push 6; add_u64; get_arg 1; push 5; add_u64; push 7; push 2; push_u32 0xFF5A3A1A; call FILL_RECT, 5; pop;
480+ get_arg 0 ; push 13; add_u64; get_arg 1; push 5; add_u64; push 5; push 1; push_u32 0xFF5A3A1A; call FILL_RECT, 5; pop;
450481# left eye
451- get_arg 0 ; push 9 ; add_u64; get_arg 1; push 6 ; add_u64; push 2; push 2; push_u32 0xFF202020; call FILL_RECT, 5; pop;
482+ get_arg 0 ; push 8 ; add_u64; get_arg 1; push 7 ; add_u64; push 2; push 2; push_u32 0xFF202020; call FILL_RECT, 5; pop;
452483# right eye
453- get_arg 0 ; push 13; add_u64; get_arg 1; push 6 ; add_u64; push 2; push 2; push_u32 0xFF202020; call FILL_RECT, 5; pop;
484+ get_arg 0 ; push 13; add_u64; get_arg 1; push 7 ; add_u64; push 2; push 2; push_u32 0xFF202020; call FILL_RECT, 5; pop;
454485# shirt / torso
455486get_arg 0 ; push 4; add_u64; get_arg 1; push 11; add_u64; push 16; push 10; push_u32 0xFFE63C3C; call FILL_RECT, 5; pop;
487+ # shirt shading (darker lower edge)
488+ get_arg 0 ; push 4; add_u64; get_arg 1; push 18; add_u64; push 16; push 3; push_u32 0xFFB02C2C; call FILL_RECT, 5; pop;
456489# left arm
457490get_arg 0 ; push 1; add_u64; get_arg 1; push 11; add_u64; push 3; push 9; push_u32 0xFFF0C8A0; call FILL_RECT, 5; pop;
458491# right arm
@@ -471,20 +504,169 @@ ret;
471504#
472505# DRAW_DOOR(i64 x , i64 y)
473506#
474- # Draw a little wooden door inside the 16 x 32 goal box whose top - left
507+ # Draw a little wooden door inside the 24 x 40 goal box whose top - left
475508# corner is at the given pixel coordinates: outer frame , recessed inner
476509# panel , two sub - panels and a gold knob. Returns 0 .
477510#
478511DRAW_DOOR:
479512# frame
480- get_arg 0 ; push 0; add_u64; get_arg 1; push 0; add_u64; push 16 ; push 32 ; push_u32 0xFF8B5A2B; call FILL_RECT, 5; pop;
513+ get_arg 0 ; push 0; add_u64; get_arg 1; push 0; add_u64; push 24 ; push 40 ; push_u32 0xFF8B5A2B; call FILL_RECT, 5; pop;
481514# recessed inner panel
482- get_arg 0 ; push 2 ; add_u64; get_arg 1; push 2 ; add_u64; push 12 ; push 28 ; push_u32 0xFF6B3F1A; call FILL_RECT, 5; pop;
515+ get_arg 0 ; push 3 ; add_u64; get_arg 1; push 3 ; add_u64; push 18 ; push 34 ; push_u32 0xFF6B3F1A; call FILL_RECT, 5; pop;
483516# upper sub - panel
484- get_arg 0 ; push 4 ; add_u64; get_arg 1; push 4 ; add_u64; push 8; push 10 ; push_u32 0xFF8B5A2B; call FILL_RECT, 5; pop;
517+ get_arg 0 ; push 6 ; add_u64; get_arg 1; push 6 ; add_u64; push 12; push 12 ; push_u32 0xFF8B5A2B; call FILL_RECT, 5; pop;
485518# lower sub - panel
486- get_arg 0 ; push 4 ; add_u64; get_arg 1; push 16 ; add_u64; push 8; push 12 ; push_u32 0xFF8B5A2B; call FILL_RECT, 5; pop;
519+ get_arg 0 ; push 6 ; add_u64; get_arg 1; push 22 ; add_u64; push 12; push 13 ; push_u32 0xFF8B5A2B; call FILL_RECT, 5; pop;
487520# door knob
488- get_arg 0 ; push 11; add_u64; get_arg 1; push 18; add_u64; push 2; push 3; push_u32 0xFFFFD700; call FILL_RECT, 5; pop;
521+ get_arg 0 ; push 18; add_u64; get_arg 1; push 20; add_u64; push 3; push 4; push_u32 0xFFFFD700; call FILL_RECT, 5; pop;
522+ push 0 ;
523+ ret ;
524+
525+ #
526+ # DRAW_PLATFORM(i64 x , i64 y , i64 w , i64 h)
527+ #
528+ # Draw a platform with a lighter top highlight and a darker bottom edge so
529+ # it reads as a solid 3D block rather than a fl at rectangle. Returns 0 .
530+ #
531+ DRAW_PLATFORM:
532+ # body
533+ get_arg 0 ; get_arg 1; get_arg 2; get_arg 3; push_u32 0xFF3CB44B; call FILL_RECT, 5; pop;
534+ # top highlight (3px)
535+ get_arg 0 ; get_arg 1; get_arg 2; push 3; push_u32 0xFF5AD06A; call FILL_RECT, 5; pop;
536+ # bottom shadow (4px)
537+ get_arg 0 ; get_arg 1; get_arg 3; add_u64; push 4; sub_u64; get_arg 2; push 4; push_u32 0xFF2A8038; call FILL_RECT, 5; pop;
538+ push 0 ;
539+ ret ;
540+
541+ #
542+ # DRAW_SHADOW(i64 x , i64 y)
543+ #
544+ # Draw a soft contact shadow for the player on the nearest platform below
545+ # its feet. The shadow shrinks as the player rises , giving a sense of
546+ # height while jumping. x , y are the player's pixel top - left. Returns 0 .
547+ #
548+ # Locals:
549+ # L0 i platform index
550+ # L1 best y of the closest platform top at or below the feet
551+ # L2 feet y + 32
552+ # L3 cx x + 12 (horizontal centre)
553+ # L4 gx scratch: platform x
554+ # L5 gy scratch: platform y
555+ # L6 gw scratch: platform w
556+ # L7 sw shadow width
557+ # L8 dist feet - to - platform distance
558+ # L9 sx shadow left edge
559+ #
560+ DRAW_SHADOW:
561+ push 0 ; push 0; push 0; push 0; push 0; push 0; push 0; push 0; push 0; push 0;
562+ push 0 ; set_local 0;
563+ push 100000 ; set_local 1;
564+ get_arg 1 ; push 32; add_u64; set_local 2; # feet
565+ get_arg 0 ; push 12; add_u64; set_local 3; # cx
566+ DS_LOOP:
567+ get_local 0 ; push 5; ge_i64; jnz DS_DONE;
568+ get_local 0 ; push 16; mul_u64; push PLATFORMS; add_u64; # base
569+ dup ; load_u32; set_local 4; # gx
570+ dup ; push 4; add_u64; load_u32; set_local 5; # gy
571+ push 8 ; add_u64; load_u32; set_local 6; # gw
572+ # horizontal overlap: x < gx + gw && x + 24 > gx
573+ get_arg 0 ; get_local 4; get_local 6; add_u64; lt_i64;
574+ get_arg 0 ; push 24; add_u64; get_local 4; gt_i64;
575+ and_u64 ;
576+ jz DS_NEXT ;
577+ # platform top at or below the feet?
578+ get_local 5 ; get_local 2; push 2; sub_u64; ge_i64; jz DS_NEXT;
579+ # nearest one so far?
580+ get_local 5 ; get_local 1; lt_i64; jz DS_NEXT;
581+ get_local 5 ; set_local 1;
582+ DS_NEXT:
583+ get_local 0 ; push 1; add_u64; set_local 0;
584+ jmp DS_LOOP ;
585+ DS_DONE:
586+ # no platform below - > nothing to draw
587+ get_local 1 ; push 100000; ge_i64; jnz DS_RET;
588+ # dist = max( 0 , best - feet)
589+ get_local 1 ; get_local 2; sub_u64; set_local 8;
590+ get_local 8 ; push 0; lt_i64; jz DS_DIST_OK;
591+ push 0 ; set_local 8;
592+ DS_DIST_OK:
593+ # sw = max( 6 , 24 - dist/ 5 )
594+ get_local 8 ; push 5; div_i64; push 24; swap; sub_u64; set_local 7;
595+ get_local 7 ; push 6; lt_i64; jz DS_SW_OK;
596+ push 6 ; set_local 7;
597+ DS_SW_OK:
598+ # sx = cx - sw/ 2
599+ get_local 3 ; get_local 7; push 2; div_i64; sub_u64; set_local 9;
600+ get_local 9 ; get_local 1; get_local 7; push 3; push_u32 0xFF2A7A34;
601+ call FILL_RECT , 5 ; pop;
602+ DS_RET:
603+ push 0 ;
604+ ret ;
605+
606+ #
607+ # DRAW_WIN(i64 t)
608+ #
609+ # Draw the victory celebration for animation frame t: the door swings open
610+ # to reveal warm light , the little guy steps inside , and confetti rains
611+ # down over the whole scene. Returns 0 .
612+ #
613+ # Locals:
614+ # L0 ow width of the door opening
615+ # L1 gx walking guy's x
616+ # L2 i confetti index
617+ # L3 - unused scratch
618+ #
619+ DRAW_WIN:
620+ push 0 ; push 0; push 0; push 0;
621+
622+ # the door itself (closed frame as a backdrop)
623+ push 400 ; push 136; call DRAW_DOOR, 2; pop;
624+
625+ # opening width ow = min( 20 , t/ 2 )
626+ get_arg 0 ; push 2; div_i64;
627+ dup ; push 20; gt_i64; jz DW_OW;
628+ pop ; push 20;
629+ DW_OW:
630+ set_local 0 ;
631+
632+ # warm light spilling out of the growing opening
633+ push 400 ; push 24; get_local 0; sub_u64; push 2; div_i64; add_u64; # lx = 400 + (24-ow)/2
634+ push 140 ;
635+ get_local 0 ;
636+ push 32 ;
637+ push_u32 0xFFFFE9A0 ;
638+ call FILL_RECT , 5 ; pop;
639+
640+ # the little guy steps into the doorway during the first ~ 48 frames
641+ get_arg 0 ; push 48; lt_i64; jz DW_NOGUY;
642+ push 372 ; get_arg 0; push 2; mul_u64; push 3; div_i64; add_u64; set_local 1; # gx = 372 + t*2/3
643+ get_local 1 ; push 144; call DRAW_GUY, 2; pop;
644+ DW_NOGUY:
645+
646+ # confetti: 16 falling squares whose colour cycles
647+ push 0 ; set_local 2;
648+ DW_CONF:
649+ get_local 2 ; push 16; ge_i64; jnz DW_CONF_END;
650+ # x = (i * 53 + 40 ) mod 600
651+ get_local 2 ; push 53; mul_u64; push 40; add_u64; push 600; mod_u64;
652+ # y = (t * 4 + i * 37 ) mod 460
653+ get_arg 0 ; push 4; mul_u64; get_local 2; push 37; mul_u64; add_u64; push 460; mod_u64;
654+ # size
655+ push 5 ; push 5;
656+ # colour by i mod 3
657+ get_local 2 ; push 3; mod_u64;
658+ dup ; push 0; eq_u64; jnz DW_C0;
659+ dup ; push 1; eq_u64; jnz DW_C1;
660+ pop ; push_u32 0xFF4CC3FF; jmp DW_CDRAW;
661+ DW_C0:
662+ pop ; push_u32 0xFFE63C3C; jmp DW_CDRAW;
663+ DW_C1:
664+ pop ; push_u32 0xFFFFD700;
665+ DW_CDRAW:
666+ call FILL_RECT , 5 ; pop;
667+ get_local 2 ; push 1; add_u64; set_local 2;
668+ jmp DW_CONF ;
669+ DW_CONF_END:
670+
489671push 0 ;
490672ret ;
0 commit comments