-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgame.asm
1380 lines (1226 loc) · 37.7 KB
/
game.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#####################################################################
#
# CSCB58 Winter 2021 Assembly Final Project
# University of Toronto, Scarborough
#
# Student: Raymond Ma, 1006210048, maraymon
#
# Bitmap Display Configuration:
# - Unit width in pixels: 8 (update this as needed)
# - Unit height in pixels: 8 (update this as needed)
# - Display width in pixels: 256 (update this as needed)
# - Display height in pixels: 256 (update this as needed)
# - Base Address for Display: 0x10008000 ($gp)
#
# Which milestones have been reached in this submission?
# (See the assignment handout for descriptions of the milestones)
# - Milestones 1/2/3/4
#
# Which approved features have been implemented for milestone 4?
# (See the assignment handout for the list of additional features)
# 1. Scoring system (counts how many times you shoot an asteroid)
# 2. Shooting obstacles
# 3. Smooth graphics
#
# Link to video demonstration for final submission:
# - https://www.youtube.com/watch?v=TLwuP3Izxz4
#
# Are you OK with us sharing the video with people outside course staff?
# - yes, and please share this project github link as well!
# https://github.com/ma-ray/Going-To-MARS
#
# Any additional information that the TA needs to know:
# - When you are at the game over screen, you can press Q to end the program or P to restart
#
#####################################################################
.eqv BASE_ADDRESS 0x10008000 # address for framebuffer
## COLOURS for the ship and the obstacles
.eqv BLACK 0x000000
.eqv GREY 0x6f6f6f
.eqv LIGHT_GREY 0xa7a7a7
.eqv ORANGE 0xfd9825
.eqv BLUE 0x006dff
.eqv YELLOW 0xe3e70f
.eqv RED 0xff0000
.eqv WHITE 0xffffff
.eqv DARK_YELLOW 0x5a4d00
.eqv YELLOW2 0xffdc00
.eqv SMALL_OBS_SIZE 6 # size of the small_obs_list
.eqv SHOOTING_SPEED 2 # speed of the bullets
.data
SMALL_OBS_LIST: .word 30,14,-6,0,-7,0,-7,0,-7,0,-7,0 # array of (x,y), (x,y), (x,y)
SHIP_LOC: .word 4, 14 # an array that stores the ship's coordinates. SHIP_LOC[0] = x, SHIP_LOC[1] y
# Initially starts at (4,14)
SHIP_HEALTH: .word 12 # health of the ship. 12 hits then game_over
SHIP_HEALTH_STATUS: .word 3716, 3844, 3848, 3720, 3728, 3856, 3860, 3732, 3740, 3868, 3872, 3744
# array coordinates (in offset form) to pixels that represent the ship's health
SHOOTING_LIST: .word -1,10 # array of (x,y), (x,y), (x,y) coordinates of the bullets -1 indicates it has not spawned
SHOOTING_STATUS: .word 3808, 3816, 3824, 3832 # pixels to the shooting status
SHOOTING_AVAIL: .word 4
SHOOTING_TIMER: .word 0 # per second incremanet the shooting availabel
SCORE: .word 0 # keeps the score of the user
.text
.globl main
update_obs:
li $t1, 0 # $t1 = iterator = 0
update_obs_loop:
bge $t1, SMALL_OBS_SIZE, update_obs_end
la $t0, SMALL_OBS_LIST # load the address to obs_list
sll $t4, $t1, 3 # offset for ith element in array
add $t0, $t0, $t4 # $t0 = array[i]
lw $t2, 0($t0) # $t2 = current x
lw $t3, 4($t0) # $t3 = current y
## CALLING draw_obs(x,y,0)
# SAVING VARIABLES: $t0, $t1
addi $sp, $sp, -4 # save $t0 to the stack
sw $t0, 0($sp)
addi $sp, $sp, -4 # save $t1 to the stack
sw $t1, 0($sp)
addi $sp, $sp, -4 # save $ra on the stack
sw $ra, 0($sp)
# PUSH ARGUMENTS TO THE STACK
addi $sp, $sp, -4
sw $t2, 0($sp) # push the x to the stack
addi $sp, $sp, -4
sw $t3, 0($sp) # push y to the stack
addi $sp, $sp, -4
li $t7, 0 # set $t7 = 0 and then push to stack
sw $t7, 0($sp)
jal draw_obs # call draw_obs(x,y,0)
lw $ra, 0($sp) # restore $ra
addi $sp, $sp, 4
lw $t1, 0($sp) # restore $t1
addi $sp, $sp, 4
lw $t0, 0($sp) # restore $t0
addi $sp, $sp, 4
lw $t2, 0($t0) # restore $t2 = current x
lw $t3, 4($t0) # restore $t3 = current y
bgt $t2, -3, add_obs # if the obs is not off the screen skip generating new location
#### GENERATE NEW COORDINATES
## GENERATE NEW X BETWEEN 32 AND 48 INCLUSIVE (SHIFTED FOR SYSCALL 0 <= X < 17)
li $v0, 42
li $a0, 0
li $a1, 17
syscall
move $t2, $a0 # move random value to $t2
addi $t2, $t2, 32 # add 16 to it to acheive 32 AND 48 INCLUSIVE
sw $t2, 0($t0) # store in array
## GENERATE NEW Y BETWEEN 1 AND 24 INCLUSIVE
li $v0, 42
li $a0, 0
li $a1, 24
syscall
move $t3, $a0 # move random value to $t3
addi $t3,$t3, 1 # add 1 to it to achieve 1 AND 25 INCLUSIVE
sw $t3, 4($t0) # store in array
####
add_obs:
addi $t2, $t2, -1 # set current x = x - 1
sw $t2, 0($t0) # store in array[i]
# call draw_obs(x,y,s)
addi $sp, $sp, -4 # save $t1 to the stack
sw $t1, 0($sp)
addi $sp, $sp, -4 # save $ra on the stack
sw $ra, 0($sp)
# PUSH ARGUMENTS TO THE STACK
addi $sp, $sp, -4
sw $t2, 0($sp) # push x to the stack
addi $sp, $sp, -4
sw $t3, 0($sp) # push y to the stack
addi $sp, $sp, -4
li $t7, 1 # set $t7 = 1 and then push to stack
sw $t7, 0($sp)
jal draw_obs # call draw_obs(x,y,1)
lw $ra, 0($sp) # restore $ra
addi $sp, $sp, 4
lw $t1, 0($sp) # restore $t1
addi $sp, $sp, 4
addi $t1, $t1, 1 # update the iterator
j update_obs_loop # jump back to loop condition
update_obs_end:
jr $ra # return to caller
# Pass in x,y,s. if s is 1, draw the obstacle. Otherwise, clear the obstacle
# Uses stack calling convention
draw_obs:
lw $t0, 0($sp) # $t0, = s
addi $sp, $sp, 4
lw $t1, 0($sp) # $t1, = y
addi $sp, $sp, 4
lw $t2, 0($sp) # $t2, = x
addi $sp, $sp, 4
bgt $t2, 31, draw_obs_end # if x is not visible end function
la $t4, BASE_ADDRESS # $t4 = BASE_ADDRESS
# CALCULATE THE PIXEL LOCATION OF SHIP
sll $t5, $t2, 2 # $t5 = 4x
sll $t6, $t1, 7 # $t6 = 128y
add $t5, $t5, $t6 # $t5 = offset of frame buffer verison of location
add $t4, $t4, $t5 # $t4 = frame buffer verison of location
# LOAD COLOURS to draw obstalce color1: $t5, color2: $t6
beq $t0, 0, wipe_obs
li $t5, GREY
li $t6, LIGHT_GREY
j paint_obs
wipe_obs:
# LOAD black to clear the obstacle from the screen
li $t5, BLACK
li $t6, BLACK
# check the if the first pixel column of the obstacle is in bounds. Draw if it is.
paint_obs:
ble $t2, -1, paint_col_two # if the column is left of the screen (x < -1) move on to second column
bge $t2, 32, paint_col_two # if the column is right of the screen (x > 32) move on to second column
sw $t5, 0($t4) # draw the first column pixel
# check the if the second pixel column of the obstacle is in bounds. Draw if it is.
paint_col_two:
addi $t4, $t4, 4 # shift to next column
addi $t2, $t2, 1 # shift the x coordinate to the second column (x = x + 1)
ble $t2, -1, paint_col_three # if the column is left of the screen (x < -1) move on to third column
bge $t2, 32, paint_col_three # if the column is right of the screen (x > 32) move on to thrid column
sw $t5, -128($t4) # draw the pixels for the second column
sw $t6, 0($t4)
sw $t5, 128($t4)
# check the if the third pixel column of the obstacle is in bounds. Draw if it is.
paint_col_three:
addi $t4, $t4, 4 # shift to next column
addi $t2, $t2, 1 # shift the x coordinate to the second column (x = x + 1)
ble $t2, -1, draw_obs_end # if the column is left of the screen (x < -1) end the function
bge $t2, 32, draw_obs_end # if the column is right of the screen (x > 32) end the function
sw $t5, 0($t4) # draw the pixel for the third column
draw_obs_end:
jr $ra # return to caller
## Pass in a number (0,1,2) to $a0. if 1, draw the ship. Otherwise, clear the ship
## Use the register based calling convention
draw_ship:
la $t0, BASE_ADDRESS # $t0 = address of framebuffer
la $t1, SHIP_LOC # $t1 = address of the ship
lw $t2, 0($t1) # $t2 = x coord of ship
lw $t3, 4($t1) # $t3 = y coord of ship
# CALCULATE THE PIXEL LOCATION OF SHIP
sll $t2, $t2, 2 # $t2 = 4x
sll $t3, $t3, 7 # $t3 = 128y
add $t1, $t2, $t3 # $t1 = offset of frame buffer verison of location
add $t1, $t1, $t0 # $t1 = frame buffer verison of location
# LOAD COLOURS NEEDED FOR SHIP
beq $a0, 0, clear_ship # if value passed in is 0, clear the ship
beq $a0, 2, hit_ship # if value passed in is 2, render hit ship
# case where you need to render the ship
li $t4, YELLOW
li $t5, ORANGE
li $t6, BLUE
j render_ship
# make the ship red to indicate a hit
hit_ship:
li $t4, YELLOW
li $t5, ORANGE
li $t6, RED
j render_ship
# remove the ship off the screen by setting all colours to black
clear_ship:
li $t4, BLACK
li $t5, BLACK
li $t6, BLACK
render_ship:
# DRAWING THE SHIP
sw $t6, 0($t1) # draw main pixel to screen
sw $t4, -4($t1)
sw $t6, -8($t1)
sw $t6, -12($t1)
sw $t5, -16($t1)
sw $t6, -132($t1)
sw $t6, 124($t1)
sw $t6, -136($t1)
sw $t6, -140($t1)
sw $t5, -144($t1)
sw $t6, 120($t1)
sw $t6, 116($t1)
sw $t5, 112($t1)
sw $t6, -268($t1)
sw $t6, 244($t1)
jr $ra # return to the caller
update_ship:
# GET THE KEYBOARD INPUT
li $t3, 0xffff0000 # load addrress of keypress
lw $t4, ($t3) # load if key was pressed
bne $t4, 1, update_ship_end # if key not pressed jump to SLEEP
lw $t3, 4($t3) # otherwise load the button that was pressed
# LOAD SHIP COORDS
la $t0, SHIP_LOC # $t0 = address of ship
lw $t1, 0($t0) # $t1 = x coord of ship
lw $t2, 4($t0) # $t2 = y coord of ship
# DETERMINE WHICH DIRECTION IT IS GOING
beq $t3, 119, GO_UP # if W was pressed
beq $t3, 97, GO_LEFT # if A was pressed
beq $t3, 115, GO_DOWN # if D was pressed
beq $t3, 100, GO_RIGHT # if S was pressed
beq $t3, 32, SPAWN_BULLET # is SPACE was pressed
beq $t3, 112, RESTART # if P was pressed
jr $ra # otherwise return to caller
SPAWN_BULLET:
# load if we have enough bullets available
la $t7, SHOOTING_AVAIL # load how many bullets the player has
lw $t6, 0($t7)
blt $t6, 1, update_shooting_end # if bullets available is 0, do nothing
addi $t6, $t6, -1 # decrease the bullets available by 1
sw $t6, 0($t7) # store it back
# no need to update ship
la $t3, SHOOTING_LIST
# load the contents at index i
lw $t4, 0($t3) # $t4 = bulltet's x
lw $t6, 4($t3) # $t6 = bullet's y
bgt $t4, -1, update_shooting_end # if bullet active end
#addi $t1, $t1, SHOOTING_SPEED # x location of bullet
sw $t1, 0($t3) # store new location of bullet
sw $t2, 4($t3)
j update_shooting_end
# MOVE THE SHIP
GO_UP: addi $t2, $t2, -2 # y = y - 2
j update_ship_array
GO_LEFT:
addi $t1, $t1, -2 # x = x - 2
j update_ship_array
GO_DOWN:
addi $t2, $t2, 2 # y = y + 2
j update_ship_array
GO_RIGHT:
addi $t1, $t1, 2 # x = x + 2
update_ship_array:
# CHECK IF THE CHANGES ARE OUT OF BOUNDS
# if x < 4 or x > 31 return to caller
blt $t1, 4, update_ship_end
bgt $t1, 31, update_ship_end
# if y < 2 or y > 24 return to caller (white line boundary)
blt $t2, 2, update_ship_end
bgt $t2, 24, update_ship_end
# load coordinates back to array
sw $t1, 0($t0)
sw $t2, 4($t0)
update_ship_end:
jr $ra # return to caller
collision_check:
la $t2, SMALL_OBS_LIST # $t2 = address of obstacle list
li $t3, 0 # $t3 = iterator = 0
collision_check_loop:
bge $t3, SMALL_OBS_SIZE, collision_check_end # while i <= 3
sll $t4, $t3, 3 # the offset size
add $t7, $t4, $t2 # $t7 = address of obs_array[i]
lw $t5, 4($t7) # $t5 = obstacle's y coords
lw $t4, 0($t7) # $t4 = obstacles's x coords
# DO NOT CHECK IF OBSTACLES ARE ON THE EDGES
blt $t4, 1, collision_check_update # if obs x coords < 1, move on to next obstacle
bgt $t4, 30, collision_check_update # if obs x coords > 30, move on to next obstacle
## CHECK IF OBSTASCLE IS INBOUNDS OF SHIP
sll $t0, $t4, 2 # $t2 = 4x
sll $t1, $t5, 7 # $t3 = 128y
add $t0, $t0, $t1 # offset for pixel from frame buffer
la $t1, BASE_ADDRESS # $t1 = BASE_ADDRESS
add $t0, $t1, $t0 # address of the pixel
# Check the left of the obstacle
lw $t4, -4($t0) # load the colour of the adjacent pixel
addi $t5, $t0, -4 # pixel for bullet if we are going to erase
beq $t4, WHITE, collision_bullet # if adjacent pixel is white, the obstacle has hit a bullet
beq $t4, BLUE, collision_ship # if the adjacent if pixel is blue, thats means we hit a ship
# Check the top of the obstacle
lw $t4, -128($t0)
addi $t5, $t0, -128
beq $t4, WHITE, collision_bullet
# Check the bottom of the obstacle
lw $t4, 128($t0)
addi $t5, $t0, 128
beq $t4, WHITE, collision_bullet
### Check if the bullet was in proximity of the obstacle
lw $t4, -252($t0)
addi $t5, $t0, -252
beq $t4, WHITE, collision_bullet
lw $t4, 260($t0)
addi $t5, $t0, 260
beq $t4, WHITE, collision_bullet
lw $t4, -132($t0)
addi $t5, $t0, -132
beq $t4, WHITE, collision_bullet
lw $t4, 124($t0)
addi $t5, $t0, 124
beq $t4, WHITE, collision_bullet
### Check if the bullet has drawn over the obstacles
lw $t4, 0($t0)
addi $t5, $t0, 0
beq $t4, WHITE, collision_bullet
# Check the
lw $t4, 4($t0)
addi $t5, $t0, 4
beq $t4, WHITE, collision_bullet
lw $t4, 8($t0)
addi $t5, $t0, 8
beq $t4, WHITE, collision_bullet
lw $t4, -124($t0)
addi $t5, $t0, -124
beq $t4, WHITE, collision_bullet
lw $t4, 132($t0)
addi $t5, $t0, 132
beq $t4, WHITE, collision_bullet
######################################################
j collision_check_update
collision_ship:
# save $t0, $t1, $t2, $t3 to the stack
addi $sp, $sp, -4 # save $t0
sw $t0, 0($sp)
addi $sp, $sp, -4 # save $t1
sw $t1, 0($sp)
addi $sp, $sp, -4 # save $t2
sw $t2, 0($sp)
addi $sp, $sp, -4 # save $t3
sw $t3, 0($sp)
addi $sp, $sp, -4 # save $ra
sw $ra, 0($sp)
li $a0, 2 # call draw_ship(2)
jal draw_ship
jal update_health # call update_health to decrease health
lw $ra, 0($sp) # restore $ra
addi $sp, $sp, 4
lw $t3, 0($sp) # restore $t3
addi $sp, $sp, 4
lw $t2, 0($sp) # restore $t2
addi $sp, $sp, 4
lw $t1, 0($sp) # restore $t1
addi $sp, $sp, 4
lw $t0, 0($sp) # restore $t0
addi $sp, $sp, 4
# invoke sleep for 0.25 seconds
li $v0, 32
li $a0, 50
syscall
j collision_check_update
collision_bullet:
# Increment the score by 1
la $t4, SCORE # load the address of score
lw $t6, 0($t4)
addi $t6, $t6, 1 # add 1 to the score
sw $t6, 0($t4) # store it back into SCORE
# make the obstacle orange to indicate a hit
li $t6, ORANGE
sw $t6, 0($t0) # draw the first column pixel
sw $t6, 4($t0) # draw the pixels for the second column
sw $t6, 8($t0)
sw $t6, -124($t0)
sw $t6, 132($t0)
# invoke sleep for 0.25 seconds
li $v0, 32
li $a0, 25
syscall
# erase the obstacle and reset
sw $zero, 0($t0) # draw the first column pixel
sw $zero, 4($t0) # draw the pixels for the second column
sw $zero, 8($t0)
sw $zero, -124($t0)
sw $zero, 132($t0)
li $t6, -5 # load a value that is off the screen
sw $t6, 0($t7) # reset the obstacle
sw $zero, 4($t7)
# erase bullet and reset
sw $zero, 0($t5) # undraw the bullet
la $t7, SHOOTING_LIST # $t7 = address of shooting list
li $t6, -1 # load the inactive state
sw $t6, 0($t7) # store it in shooting list
collision_check_update:
addi $t3, $t3, 1 # i = i + 1
j collision_check_loop # jump back to while conditoin
collision_check_end:
addi $sp, $sp, -4 # save $ra
sw $ra, 0($sp)
# call draw_ship(1)
li $a0, 1 # call draw_ship(1)
jal draw_ship
lw $ra, 0($sp) # restore $ra
addi $sp, $sp, 4
jr $ra # return to caller
update_health:
############################
la $t0, SHIP_HEALTH # $t0 = address of ship health
lw $t1, 0($t0) # $t1 = ship health
addi $t1, $t1, -1 # decrease ship health
la $t2, SHIP_HEALTH_STATUS # $t2 = address of SHIP_HEALTH_STATUS
sll $t3, $t1, 2 # offset for accessing array[ship_health}
add $t2, $t2, $t3 # address for array[ship_health]
lw $t2, 0($t2) # $t2 = array[ship_heath]
la $t3, BASE_ADDRESS # $t3 = BASE_ADDRESS
add $t2, $t2, $t3 # address for the pixel to erase
li $t7, GREY # load the colour GREY
sw $t7, 0($t2) # paint the pixel GREY
sw $t1, 0($t0) # store the new ship health
jr $ra # return to caller
update_shooting:
la $t0, SHOOTING_LIST # $t0 = array of the coordinates of the bullet
li $t1, 0 # intialize iterator
# load the contents at index i
lw $t4, 0($t0) # $t4 = x
lw $t5, 4($t0) # $t4 = y
blt $t4, 0, update_shooting_end # if bullet is not active (not fired)
# CALCULATE THE PIXEL LOCATION OF BULLET
sll $t6, $t4, 2 # $t6 = 4x
sll $t7, $t5, 7 # $t7 = 128y
add $t6, $t7, $t6 # $t6 = offset of frame buffer verison of location
add $t6, $t6, $gp # $t6 = frame buffer verison of location
sw $zero, 0($t6) # undraw the pixel
addi $t4, $t4, SHOOTING_SPEED # x = x + 3
bgt $t4, 31, bullet_inactive # x is out of bounds make it inactive
li $t7, WHITE
li $t5, SHOOTING_SPEED
sll $t5, $t5, 2 # shooting speed * 4
add $t6, $t5, $t6 # update pixel address
sw $t7, 0($t6) # draw the new pixel 3 to the right from original location
sw $t4, 0($t0) # store new x in array
update_shooting_end:
jr $ra # return to caller
bullet_inactive:
li $t4, -1 # let x be -1 to indicate it is inactive
sw $t4, 0($t0) # store new x in array
j update_shooting_end
draw_gui:
# draw the white line at the bottom
li $t1, WHITE # $t1 = colour white
la $t0, BASE_ADDRESS # load the base address
li $t2, 3456 # $t2 = iterator
draw_gui_loop:
bgt $t2, 3580, setup_health # if pixel is greater tha 3580 exit loop
add $t7, $t0, $t2 # calculate address for pixel
sw $t1, 0($t7) # store white on that pixel
addi $t2, $t2, 4 # move to the right pixel
j draw_gui_loop # jump to loop condition
setup_health:
li $t3, RED
la $t4, BASE_ADDRESS # $t4 = BASE_ADDRESS
la $t0, SHIP_HEALTH_STATUS # $t0 = address of SHIP_HEALTH_STATUS
li $t1, 0 # $t1 = iterator = 0
setup_health_loop:
bge $t1, 12, draw_gui_end # i > 12
sll $t5, $t1, 2 # $t5 = offset for i
add $t5, $t5, $t0 # $t5 = address for array[i]
lw $t5, 0($t5) # $t5 = offset for pixel location
add $t5, $t5, $t4 # $t5 = pixel location
sw $t3, 0($t5) # draw the pixel red
addi $t1, $t1, 1 # update the iterator i = i + 1
j setup_health_loop
draw_gui_end:
jr $ra # return to caller
draw_shoot_status:
# check if enough time has passed to increment the bullets available
la $t0, SHOOTING_AVAIL
lw $t1, 0($t0) # load how many bullets the player can use
la $t2, SHOOTING_TIMER
lw $t3, 0($t2) # load the time so far
bge $t3, 2000, add_bullet # if it has been 2 seconds, increment availble bullets
j draw_bars # other wise draw the bullet status
add_bullet:
addi $t1, $t1, 1 # increment the bullet
sw $zero, 0($t2) # reset the timer
bgt $t1, 4, set_max_bullet # cap the available bullets to 4
j draw_bars
set_max_bullet:
li $t1, 4 # set the max bullets to 4
draw_bars:
sw $t1, 0($t0) # store the updated available bullets
la $t0, SHOOTING_STATUS # load address of SHOOTING_STATUS
li $t2, 0 # setup iterator
# set it all to dark yellow
inactive_shoot_loop:
bge $t2, 4, active_shoot
sll $t3, $t2, 2 # calculate offset for array
add $t4, $t3, $t0 # get address of SHOOT_STATUS[i]
lw $t5, 0($t4) # load SHOOT_STATUS[i]
la $t6, BASE_ADDRESS
add $t6, $t6, $t5 # calculate address to the pixel
li $t7, DARK_YELLOW # load the colour DARK_YELLOw
sw $t7, 0($t6) # draw the pixels
sw $t7, 128($t6)
addi $t2, $t2, 1 # update iterator
j inactive_shoot_loop # jump back to first loop
active_shoot:
li $t2, 0 # reset the iterator
active_shoot_loop:
bge $t2, $t1, draw_shoot_status_end
sll $t3, $t2, 2 # calculate offset for array
add $t4, $t3, $t0 # get address of SHOOT_STATUS[i]
lw $t5, 0($t4) # load SHOOT_STATUS[i]
la $t6, BASE_ADDRESS
add $t6, $t6, $t5 # calculate address to the pixel
li $t7, YELLOW2 # load the colour DARK_YELLOw
sw $t7, 0($t6) # draw the pixels
sw $t7, 128($t6)
addi $t2, $t2, 1 # update iterator
j active_shoot_loop # jump back to first loop
draw_shoot_status_end:
jr $ra # return to caller
# reset all values
RESTART:
## reset ship health
la $t0, SHIP_HEALTH # $t0 = health of the ship
li $t1, 12 # load intital health of the ship
sw $t1, 0($t0) # store to variable
## reset ship location
la $t0, SHIP_LOC # $t0, location of the ship_array
li $t1, 4 # ship's spawn point x = 4
li $t2, 14 # ship's spawn point y = 14
sw $t1, 0($t0) # store the ship's new location
sw $t2, 4($t0)
## reset bullet_location
la $t0, SHOOTING_LIST # $t0 = location of shooting list
li $t1, -1
sw $t1, 0($t0) # store -1 in list to show inactive state
# reset the shoot timer
la $t0, SHOOTING_TIMER
li $t1, 0
sw $t1, 0($t0) # reset the timer to 0
# reset the bullets available
la $t0, SHOOTING_AVAIL
li $t1, 4
sw $t1, 0($t0) # reset the bullets available to 4
# reset the score
la $t0, SCORE
li $t1, 0
sw $t1, 0($t0) # load 0 to SCORE
## reset obstacle location
la $t0, SMALL_OBS_LIST # $t0 = location of small obstacle array
li $t1, 0 # $t1 = iterator = 0
restart_obs_loop:
bge $t1, SMALL_OBS_SIZE, restart_end
sll $t2, $t1, 3 # $t2 = offset for the iterator
add $t3, $t2, $t0 # $t3 = address of small obs array[i]
li $t4, -5 # $t3 = location of new obstacle (off the screen)
sw $t4, 0($t3) # array[i] = -5
addi $t1, $t1, 1 # update the iterator i++
j restart_obs_loop # jump back to while condition
restart_end:
j begin # jump to the beginning of the main game loop
# clear the whole screen to black
clear_screen:
la $t0, BASE_ADDRESS
li $t1, BLACK
li $t2, 0 # the iterator
clear_screen_loop:
bge $t2, 1024, clear_screen_end
sw $t1, 0($t0) # set the pixel to black
addi $t0, $t0, 4 # update pixel location
addi $t2, $t2, 1 # update iterator: i = i + 1
j clear_screen_loop
clear_screen_end:
jr $ra # return to caller
main:
jal clear_screen
jal start_screen # draws the start screen
# sleep for 2 seconds the refresh rate
li $v0, 32
li $a0, 2000
syscall
begin: jal clear_screen # draw the screen
jal draw_gui # draw the gui
la $t0, SHIP_HEALTH # $t0 = address of SHIP_HEALTH
lw $t0, 0($t0) # $t1 = ship health
GAME_LOOP:
blt $t0, 1, game_over_state # if lives are 0 then jump to game_over_state
jal update_obs # update the location of obstacles
jal update_shooting # move the bullets and check for collisions
jal draw_shoot_status # update the status on how many bullets the player can shoot
jal collision_check # iterate thorugh each obstacle, and checks if it hits the ship
li $a0, 0 # call draw_ship(0)
jal draw_ship # clear the ship on the screen
jal update_ship # check user input and update location
li $a0, 1 # call draw_ship(1)
jal draw_ship # draw the ship on the screen
SLEEP: # sleep for 40ms for the refresh rate
li $v0, 32
li $a0, 40
syscall
la $t0, SHOOTING_TIMER # load address to the shooting timer
lw $t1, 0($t0) # load the contents
addi $t1, $t1, 40 # add 40 ms to the shooting timer
sw $t1, 0($t0) # store it back into .data
la $t0, SHIP_HEALTH # $t0 = address of SHIP_HEALTH
lw $t0, 0($t0) # $t1 = ship health
j GAME_LOOP # jump back to beginning of game loop
game_over_state:
jal clear_screen # clear the screen
jal game_over # draw the game over screen
jal print_score # print the scores to the screen
game_over_loop:
beq $t3, 113, END # if Q was pressed restart the game
# GET THE KEYBOARD INPUT (P to restart and Q to quit)
li $t3, 0xffff0000 # load address of keypress
lw $t4, ($t3) # load if key was pressed
bne $t4, 1, game_over_loop # if key not pressed jump to SLEEP
lw $t3, 4($t3) # otherwise load the button that was pressed
beq $t3, 112, RESTART # if P was pressed restart the game
j game_over_loop # check again for keyboard input
END:
li $v0, 10 # terminate the program gracfully
syscall
## IMAGE FUNCTIONS
# Will print the double digit score
print_score:
la $t0, SCORE # load address of SCORE
lw $t0, 0($t0) # $t0 = SCORE
li $t7, 10 # $t7 = 10 for division
div $t0, $t7 # SCORE / 10
# 10s digit
mflo $t6 # $t6 = SCORE // 10
# 1s digit
mfhi $t7 # $7 = SCORE % 10
addi $sp $sp, -4 # save $ra
sw $ra, 0($sp)
move $a0, $t7 # push parameters using register calling convention
li $a1, 2496
jal draw_digit # draw the 1s digit first
move $a0, $t6 # push parameters using register calling convention
li $a1, 2468
jal draw_digit # draw the 10s digit
lw $ra, 0($sp) # restore $ra
add $sp, $sp, 4
jr $ra
# passes in a digit and the addres on where to print $a0 = digit $a1 = pixel offset
draw_digit:
move $t0, $a0 # load the digit
move $t1, $a1 # load the offset
li $t2, WHITE # load the colour white
la $t3, BASE_ADDRESS
add $t1, $t3, $t1
beq $t0, 1, draw_one
beq $t0, 2, draw_two
beq $t0, 3, draw_three
beq $t0, 4, draw_four
beq $t0, 5, draw_five
beq $t0, 6, draw_six
beq $t0, 7, draw_seven
beq $t0, 8, draw_eight
beq $t0, 9, draw_nine
draw_zero: # Draws 0 on the screen
sw $t2, 136($t1)
sw $t2, 140($t1)
sw $t2, 260($t1)
sw $t2, 272($t1)
sw $t2, 388($t1)
sw $t2, 400($t1)
sw $t2, 516($t1)
sw $t2, 528($t1)
sw $t2, 644($t1)
sw $t2, 656($t1)
sw $t2, 776($t1)
sw $t2, 780($t1)
jr $ra
draw_one: # Draws 1 on the screen
sw $t2, 140($t1)
sw $t2, 264($t1)
sw $t2, 268($t1)
sw $t2, 396($t1)
sw $t2, 524($t1)
sw $t2, 652($t1)
sw $t2, 776($t1)
sw $t2, 780($t1)
sw $t2, 784($t1)
jr $ra
draw_two: # Draws 2 on the screen
sw $t2, 136($t1)
sw $t2, 140($t1)
sw $t2, 260($t1)
sw $t2, 272($t1)
sw $t2, 396($t1)
sw $t2, 520($t1)
sw $t2, 644($t1)
sw $t2, 772($t1)
sw $t2, 776($t1)
sw $t2, 780($t1)
sw $t2, 784($t1)
jr $ra
draw_three: # Draws 3 on the screen
sw $t2, 136($t1)
sw $t2, 140($t1)
sw $t2, 260($t1)
sw $t2, 272($t1)
sw $t2, 396($t1)
sw $t2, 528($t1)
sw $t2, 644($t1)
sw $t2, 656($t1)
sw $t2, 776($t1)
sw $t2, 780($t1)
jr $ra
draw_four: # Draws 4 on the screen
sw $t2, 140($t1)
sw $t2, 264($t1)
sw $t2, 268($t1)
sw $t2, 388($t1)
sw $t2, 396($t1)
sw $t2, 516($t1)
sw $t2, 520($t1)
sw $t2, 524($t1)
sw $t2, 528($t1)
sw $t2, 652($t1)
sw $t2, 780($t1)
jr $ra
draw_five: # Draws 5 on the screen
sw $t2, 132($t1)
sw $t2, 136($t1)
sw $t2, 140($t1)
sw $t2, 144($t1)
sw $t2, 260($t1)
sw $t2, 388($t1)
sw $t2, 392($t1)
sw $t2, 396($t1)
sw $t2, 528($t1)
sw $t2, 656($t1)
sw $t2, 772($t1)
sw $t2, 776($t1)
sw $t2, 780($t1)
jr $ra
draw_six: # Draws 6 on the screen
sw $t2, 136($t1)
sw $t2, 140($t1)
sw $t2, 144($t1)
sw $t2, 260($t1)
sw $t2, 388($t1)
sw $t2, 392($t1)
sw $t2, 396($t1)
sw $t2, 516($t1)
sw $t2, 528($t1)
sw $t2, 644($t1)
sw $t2, 656($t1)
sw $t2, 776($t1)
sw $t2, 780($t1)
jr $ra
draw_seven: # Draws 7 on the screen
sw $t2, 132($t1)
sw $t2, 136($t1)
sw $t2, 140($t1)
sw $t2, 144($t1)
sw $t2, 272($t1)
sw $t2, 396($t1)
sw $t2, 520($t1)
sw $t2, 648($t1)
sw $t2, 776($t1)
jr $ra
draw_eight: # Draws 8 on the screen
sw $t2, 136($t1)
sw $t2, 140($t1)
sw $t2, 260($t1)
sw $t2, 272($t1)
sw $t2, 392($t1)
sw $t2, 396($t1)
sw $t2, 516($t1)
sw $t2, 528($t1)
sw $t2, 644($t1)
sw $t2, 656($t1)
sw $t2, 776($t1)
sw $t2, 780($t1)
jr $ra
draw_nine: # Draws 9 on the screen
sw $t2, 136($t1)
sw $t2, 140($t1)
sw $t2, 260($t1)
sw $t2, 272($t1)
sw $t2, 388($t1)
sw $t2, 400($t1)
sw $t2, 520($t1)
sw $t2, 524($t1)
sw $t2, 528($t1)
sw $t2, 656($t1)
sw $t2, 776($t1)
sw $t2, 780($t1)
jr $ra
start_screen: # draws the start screen. Code generated by a Python script
la $t0, BASE_ADDRESS # $t0 is the base address
li $t1, 0xffdc00 # loads the colours required to draw the image
li $t2, 0xff0000
li $t3, 0xe26a03
sw $t1, 268($t0)
sw $t1, 272($t0)
sw $t1, 292($t0)
sw $t1, 296($t0)
sw $t1, 312($t0)
sw $t1, 316($t0)
sw $t1, 320($t0)
sw $t1, 332($t0)
sw $t1, 344($t0)
sw $t1, 360($t0)
sw $t1, 364($t0)
sw $t1, 392($t0)
sw $t1, 416($t0)
sw $t1, 428($t0)
sw $t1, 444($t0)
sw $t1, 460($t0)
sw $t1, 464($t0)
sw $t1, 472($t0)
sw $t1, 484($t0)