======MAGx====== =====Infinite Runner Game===== An infinite runner involves a character moving along an infinitely long stage overcoming obstacles placed along the path. That's the foundation. Other additions can include an increasing speed, procedurally generated obstacles, etc. ====Parallax Scrolling Background==== A parallax background involves multiple layers scrolling along at different speeds to simulate depth. Layers farther back in the scene move slower than those closer to the camera. ===Data Needed for Parallax=== Each layer needs at least a X Position and Speed variables. On each frame, the X Position is subtracted by the Speed, so that the layer moves at a constant rate. Once the layer moves off-screen, increment its' X Position by the width of the layer asset so it's back on-screen and the scrolling effect doesn't have any cuts. (For simplicity, each layer asset is the width of the screen size.) ===Substituting Different Assets in a Layer=== Sometimes you want to include alternate variants of a layer asset for added visual flair. This'll require an array for however many slots you want within the layer (For this example, we'll go six with the last slot being the variant). We'll use a type variable to determine which asset variant to select (a boolean). When rendering the layer, it looks at the type to determine the texture variant to select. ====Player Physics and Animations==== ===Player Movement=== Since the parallax background already gives the impression of horizontal speed, the player does not actually need to move across the X-axis of the screen. This value can remain fixed throughout all gameplay scenarios. The player will be able to perform two actions while automatically running along: Sliding and Jumping with the A and B buttons respectively. These two actions are mutually exclusive. Sliding is simple. When the B button is held, the player will slide along the ground indefinitely. In this state, the player is half as tall and can duck under obstacles. Jumping is more complicated. ===Variable Jump Height=== When the Player jumps, they have some control over how high the jump is depending on how long the A button is held. To code such a feature, you'll need variables for the Player's position, speed, and acceleration. Each frame, the acceleration is added to the speed, and then the speed is added onto the position to create an arcing motion. The instant the button is pressed, the speed and acceleration of the player is set to be negative (negative is upwards). If the A button is released while the player is rising, the acceleration will decrease significantly (ex. from -1 to -3), which will allow the Player to go through the jump arc at a faster rate. As soon as the player starts falling back towards the ground, the acceleration is fixed no matter the button state so that the illusion of gravity remains consistent. ===Animation Control=== Since the player has three different states (running, jumping, and sliding), there will be 3 different animation states. While sliding, the player will be shown as sliding across the ground in a single pose. While jumping, the player will have two different visuals for jumping up and falling down. The asset that gets drawn will be dependent on the player's speed value. (If speed is negative, the player jump sprite is shown, if positive, the falling sprite). While running, the player will cycle between four different running sprites. A flag variable will be used to note which sprite should get displayed (0-3). Every 7 frames, the flag will get incremented and then modulated by 4. This can be achieved by using the FrameCounter that's built into Vircon32. The running animation is the default one that gets played, and will be overwritten when the player either jumps or slides. ===Obstacle Infrastructure and Generation=== Every good runner needs to have obstacles to avoid! For this runner, we'll have two building blocks: A block and a spike. Our obstacles will be controlled by an integer flag. A zero means no obstacle is spawned, and any number higher corresponds with an obstacle pattern. This flag can be triggered by the console clock, RNG, or whatever. When an obstacle is spawned (the flag is turned from 0 to a number), A variable we'll call "Obstacle X" is set to be a little over 640. The Obstacle X variable is a reference position in which each building block of the obstacle pattern will be positioned relative to. We only need to set the X as the Y will remain constant at ground level. Obstacle X will move left at the same rate as the background layer until it reaches at least -640. At this point, the Obstacle flag will be set to zero again, and a new pattern can be spawned. Each obstacle pattern will essentially be an array/list for each building element. Each element will have three variables: - Object type ( 0=Block, 1=Spike ) - Position X - Position Y Again, the Position data will be updated relative to the Obstacle X reference point. Additionally, a size variable will be kept in the stack so that we know how many elements reside within each obstacle pattern. ===Obstacle Collision and Rendering=== The processes for both collision checks and rendering are relatively the same. First, we check the Obstacle flag to see which pattern is currently spawned, and then grab the size variable associated with it. Secondly, we use that size variable to for-loop through each element in the obstacle to then either run collision checks on it, or render it. For Collision, we check if the element is either a Block or a Spike using the Object Type variable. If it's a block, we run checks to see if the Player is on top of it, so that the Player can run and jump along it, or if the Player is in it to trigger a game over. For Spikes, there are two boxes inside it that if the player enters also triggers a game over. For Rendering, the Object Type check is the same to select the right texture region, which gets printed at that position. Relatively simple.