Get the full commented source code of

HTML5 Suika Watermelon Game

Talking about Circular endless runner game, C#, Game development and Unity3D.

Here we go with another step of Circular Endless Runner creation, this time using Unity and C#.

In previous step we built the prototype of the circular endless runner featuring double jump without using any physics engine, just good old trogonometry.

This time I am pushing things a little further, adding moving spikes and a basic collision detection.

The collision detection forgives a lot but that’s what today players want: say “heeew it almost got me”.

Have a look at the prototype:

Click to jump or double jump. If you hit a spike, the game restarts.

Actually collision detection does not check for circle/triangle collision, it only checks for the distance between the very top pixel of the spike and the ball.

But it works anyway, the game is fun and you can easily port it in any other language since it does not rely on any specific Unity physics engine.

The code is quite a mess but I am going to improve it next time, and will add comments too.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class mainScript : MonoBehaviour {

	public GameObject player;
	public GameObject spikeObject;
	public float bigCircleRadius;
	public float smallCircleRadius;
	public float revolutionSpeed;
	public float currentAngle;
	private float revolutions;
	public float gravity;
	public float[] jumpForce;
	private float jumpOffset = 0;
	private int jumps = 0;
	private float currentJumpForce = 0;
	private float spikeHeight;

	void Start () {
		revolutions = bigCircleRadius / smallCircleRadius + 1;
		spikeHeight = spikeObject.GetComponent<Renderer> ().bounds.size.x;
		for (int i = 0; i < 6; i++) {
			GameObject spike = Instantiate (spikeObject);
			placeSpike (spike, Mathf.FloorToInt(i / 2) + 1);
		}
	}

	void Update () {
		handleJumps ();
		handleRevolution (Time.deltaTime);
		handleSpikes ();
	}
		
	void placeSpike(GameObject spike, int quadrant){
		float totalRadius = bigCircleRadius + spikeHeight / 2 - 0.01f;
		int randomAngle = Random.Range (quadrant * 90, (quadrant + 1) * 90);
		spike.transform.eulerAngles = new Vector3(0, 0, randomAngle);
		float radians = randomAngle * Mathf.Deg2Rad;
		spike.transform.position = new Vector2 (totalRadius * Mathf.Cos (radians), totalRadius * Mathf.Sin (radians));
		spike.GetComponent<spikeScript>().isApproaching = false;
		spike.GetComponent<spikeScript>().quadrant = quadrant;
	}

	void handleJumps(){
		if (Input.GetButtonDown ("Fire1")) {
			if (jumps < 2) {
				jumps++;
				currentJumpForce = jumpForce [jumps - 1];
			}	
		}
		if (jumps > 0) {
			jumpOffset += currentJumpForce;
			currentJumpForce -= gravity;
			if (jumpOffset < 0) {
				jumpOffset = 0;
				jumps = 0;
				currentJumpForce = 0;
			}
		}
	}

	void handleRevolution(float elapsedTime){
		currentAngle += 360f * elapsedTime / revolutionSpeed;
		currentAngle = (currentAngle + 360) % 360;
		Vector2 newPosition = player.transform.position;
		float radians = currentAngle * Mathf.Deg2Rad;
		float totalRadius = bigCircleRadius + smallCircleRadius + jumpOffset;
		newPosition.x = totalRadius * Mathf.Cos (radians);
		newPosition.y = totalRadius * Mathf.Sin (radians);
		player.transform.position = newPosition;
		player.transform.Rotate (0, 0, 360f * revolutions * elapsedTime / revolutionSpeed);
	}

	void handleSpikes(){
		GameObject[] spikes = GameObject.FindGameObjectsWithTag ("Spike");
		foreach (GameObject spike in spikes) {
			float spikeAngle = spike.transform.localRotation.eulerAngles.z;
			float angleDifference = Mathf.Abs(Mathf.DeltaAngle (spikeAngle, currentAngle));
			if (angleDifference < 10 && !spike.GetComponent<spikeScript> ().isApproaching) {
				spike.GetComponent<spikeScript> ().isApproaching = true;
			}
			if (angleDifference > 20 && spike.GetComponent<spikeScript> ().isApproaching) {
				placeSpike (spike, (spike.GetComponent<spikeScript> ().quadrant - 3) % 4);
			}
			if (spike.GetComponent<spikeScript> ().isApproaching) {
				checkSpikeCollision (spikeAngle);
			}
		}
	}

	void checkSpikeCollision(float spikeAngle){
		float totalSpikeHeight = bigCircleRadius + spikeHeight / 2;
		float radians = spikeAngle * Mathf.Deg2Rad;
		Vector2 spikeTop = new Vector2 (totalSpikeHeight * Mathf.Cos (radians), totalSpikeHeight * Mathf.Sin (radians));
		float minimumDistance = smallCircleRadius;
		float distance = Vector2.Distance (spikeTop, player.transform.position);
		if (distance < minimumDistance) {
			SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
		}
	}
}

Next time I’ll add some collectibe item, meanwhile download the complete project.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.