Apr 3, 2017

SMB3 Angry Sun Code Revisited



I just felt like revisiting my Angry Sun code from Super Mario Bros. 3, rewriting it for clarity since it was written during my Use-Alarms-For-Everything phase. I wanted to make it more accessible.




At a Glance

The Angry Sun in Super Mario Bros. 3 has often been programmed in Game Maker using a path, but this was not the proper way to code it, since it clearly did not fit into a path completely. For starters, the number of times the Sun would move around in a circle was random, which doesn't coincide with path use entirely. This wasn't a huge issue, since you could always stop the path early and then go to another path for the swooping attack.

However, the biggest weakness of the path method was in that attack itself: The attack itself was just a parabola, but the starting point was wherever the Sun starts its attack from, then stops when the sun reaches the "top" of the screen. The fact that the Sun moves with the view isn't a path concern since the path could be moved as well. The randomness of the parabola is significant enough, though.


Working With a View

There are two ways to tackle the view issue. You can calculate how much the view moves each step and move the Sun's position that much, or you can perform all movement calculations on an arbitrary pair of variables and then add those variables to the view's coordinates. The former is more work for the program to calculate and takes more events, but the latter restricts collision detection to strictly code rather than collision events. The code provided in this post is based on the former method, but can be adjusted for the latter method by simply replacing x and y with the arbitrary variables (such as xpos and ypos).


The Code

//This is a common useful feature in old console games. Here it just handles animation.
STEP_COUNT    =   STEP_COUNT + 1 & $FFFF;

//This code controls the Sun's image_index when angry.
image_index = !(STEP_COUNT& $C);

//If TIMER is ever set, decrease it.
if TIMER
    TIMER    -=  1;

//You don't need a timeline to make use of STATE. This code works the same way as a timeline, but better.
switch STATE
{
    case 0:
            image_index = 1;


            //This should be your conditional to make the Sun get angry.
            if STEP_COUNT == $2FF            

            {
                STATE       +=  1;
                hspd      =   0;
                vspd      =   -4;
 
              //This helps regulate the circular motion. 

               DIR         =   2;
               TIMER       =   choose(64,96,128,160);
            }
            break;
   
    case 1:

            //Call the script that handles the circular motion.            event_user(0);            

            if !TIMER
            {
                STATE       +=  1;
                hspd      =   0;
                vspd      =   0;
                TIMER       =   $10;
            }
            break;
           
    case 2:
            if !TIMER
            {
                STATE       +=  1;
                hspd      =   5/4;
                vspd      =   4;
            }
            break;
   
    case 3:
 

            //This gives the Sun a parabolic motion. 
            vspd  -=  1/16;
            //This value is due to a little quirk in the NES 
            if y < view_yview[0] + 33            
            {
                STATE       +=  1;
                y           =   view_yview[0] + 33;
                DIR         =   3;
                hspd      =   0;
                vspd      =   -4;
                TIMER       =   choose(64,96,128,160);;
            }
            break;
           
    case 4:
            event_user(0);
            if !TIMER
            {
                STATE       +=  1;
                hspd      =   0;
                vspd      =   0;
                TIMER       =   $10;
            }
            break;
           
    case 5:
            if !TIMER
            {
                STATE       +=  1;
                hspd      =   -5/4;
                vspd      =   4;
            }
            break;
           
    case 6:
            vspd      -=  1/16;
            if y < view_yview[0] + 33
            {

                //This is a complete cycle, so go back to position 1. 

                STATE       =   1;     
                y           =   view_yview[0] + 33;
                DIR         =   2;
                hspd      =   0;
                vspd      =   -4;
                TIMER    =   choose(64,96,128,160);;
            }
            break;
}

x += hspd;
y += vspd;




The code under event_user(0) as follows essentially defines the movement based on DIR:

if DIR & 1
{
            if hspd == -4
            {
                DIR     ^=  1;
                hspd  +=  1/2;
            }
            else
                hspd  -=  1/2;
}
else
{
            if hspd == 4
            {
                DIR     ^=  1;
                hspd  -=  1/2;
            }
            else
                hspd  +=  1/2;
}
if DIR & 2
{
            if vspd == -4
            {
                DIR     ^=  2;
                vspd  +=  1/2;
            }
            else
                vspd  -=  1/2;
}
else
{
            if vspd == 4
            {
                DIR     ^=  2;
                vspd  -=  1/2;
            }
            else
                vspd  +=  1/2;
}

No comments:

Post a Comment

©TheouAegis Productions™. Powered by Blogger.