
The objective of this fun project was to program an endless side-scrolling game with a fast-paced runner style of gameplay. While completing this prototype, I learned how to completely transform the experience of my projects using sound effects and music. I also learned how to create dynamic endless repeating backgrounds that are critical for a side-scrolling gameplay experience. The final piece of work was learning how to use particle effects such as splatters and explosions. They seem to make the game so much more satisfying to play!
Project Outcomes:
The character, background, and obstacle of your choice will be set up. The player will be able to press spacebar and make the character jump, as obstacles spawn at the edge of the screen and block the player’s path.
The background moves flawlessly at the same time as the obstacles, and the obstacles will despawn when they exit game boundaries. With the power of script communication, the background and spawn manager will halt when the player collides with an obstacle. Colliding with an obstacle will also trigger a game over message in the console log, halting the background and the spawn manager.
With the animations from the animator controller, the character will have 3 new animations that occur in 3 different game states. These states include running, jumping, and death, all of which transition smoothly and are timed to suit the game.
Music will play as the player runs through the scene, kicking up dirt particles in a spray behind their feet. A springy sound will play as they jump and a boom will play as they crash, bursting in a cloud of smoke particles as they fall over.

My instructor gave me a good grade and said that “overall I made an incredibly polished game.” He said that there was “super cool sound and particle effects and upbeat background music.” He said it was clear that I had learned how to utilize animations for the characters and that I “programmed perfectly the scrolling endless background.”
Feel free to check it out at the link below:
https://meta.dwdenney.com/unit3/
C# Code Samples
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RepeatBackground : MonoBehaviour
{
private Vector3 startPos;
private float repeatWidth;
// Start is called before the first frame update
void Start()
{
startPos = transform.position;
repeatWidth = GetComponent<BoxCollider>().size.x / 2;
}
// Update is called once per frame
void Update()
{
if(transform.position.x < startPos.x - repeatWidth)
{
transform.position = startPos;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
//declare variable to hold the players rigidbody component for use in physics scripting
private Rigidbody playerRb;
public float jumpForce;
public float gravityModifier;
public bool isOnGround = true;
public bool gameOver = false;
private Animator playerAnim;
public ParticleSystem explosionParticle;
public ParticleSystem dirtParticle;
public AudioClip jumpSound;
public AudioClip crashSound;
private AudioSource playerAudio;
// Start is called before the first frame update
void Start()
{
//initialize the rigidbody player variable
playerRb = GetComponent<Rigidbody>();
//initialize the animator variable
playerAnim = GetComponent<Animator>();
// initialize the audio variable
playerAudio = GetComponent<AudioSource>();
//adjust the gravity
Physics.gravity *= gravityModifier;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && isOnGround && !gameOver)
{
playerRb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
isOnGround = false;
playerAnim.SetTrigger("Jump_trig");
dirtParticle.Stop();
playerAudio.PlayOneShot(jumpSound, 1.0f);
}
}
private void OnCollisionEnter(Collision collision)
{
Debug.Log("I collided with " + collision.gameObject.name);
if (collision.gameObject.CompareTag("Ground"))
{
isOnGround = true;
dirtParticle.Play();
} else if (collision.gameObject.CompareTag("Obstacle"))
{
gameOver = true;
Debug.Log("Game Over!");
playerAnim.SetBool("Death_b", true);
playerAnim.SetInteger("DeathType_int", 1);
explosionParticle.Play();
dirtParticle.Stop();
playerAudio.PlayOneShot(crashSound, 1.0f);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveLeft : MonoBehaviour
{
private float speed = 30;
private PlayerController playerControllerScript;
private float leftBound = -15;
// Actions to be run before the first frame update
void Start()
{
playerControllerScript = GameObject.Find("Player").GetComponent<PlayerController>();
}
// Actions to be run once per frame
void Update()
{
if(playerControllerScript.gameOver == false)
{
transform.Translate(Vector3.left * Time.deltaTime * speed);
}
if(transform.position.x < leftBound && gameObject.CompareTag("Obstacle"))
{
Destroy(gameObject);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnManager : MonoBehaviour
{
// spawning a log obstacle set in the ui as obstaclePrefab
public GameObject obstaclePrefab;
private Vector3 spawnPosition = new Vector3(25, 0, 0);
private float startDelay = 2;
private float repeatRate = 2;
private PlayerController playerControllerScript;
// Actions to be called before the first frame update
void Start()
{
InvokeRepeating("SpawnObstacle", startDelay, repeatRate);
playerControllerScript = GameObject.Find("Player").GetComponent<PlayerController>();
}
void SpawnObstacle()
{
if (playerControllerScript.gameOver == false)
{
GameObject theObstacle = (GameObject)Instantiate(obstaclePrefab, spawnPosition, obstaclePrefab.transform.rotation);
theObstacle.name = "The Log"; // spawing a log obstacle set in the ui
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotator : MonoBehaviour
{
//Actions to be run once per frame
void Update()
{
// Rotate the game object that this script is attached to by 15 in the X axis,
// 30 in the Y axis and 45 in the Z axis, multiplied by deltaTime in order to make it per second
// rather than per frame.
transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);
}
}