Skip to content

Instantly share code, notes, and snippets.

@hcosta
Last active November 18, 2021 18:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hcosta/4219c5f39ad2f2033599a563376147af to your computer and use it in GitHub Desktop.
Save hcosta/4219c5f39ad2f2033599a563376147af to your computer and use it in GitHub Desktop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AudioManager : MonoBehaviour
{
public static AudioManager Instance { get; private set; }
public AudioSource musicPlayer, soundPlayer;
public AudioClip[] availableSoundClips;
Dictionary<string, AudioClip> loadedAudioClips = new Dictionary<string, AudioClip>();
void Awake()
{
Instance = this;
}
void Start()
{
foreach (AudioClip audio in availableSoundClips)
{
loadedAudioClips.Add(audio.name, audio);
}
musicPlayer.Play();
}
public void PlaySound(string name)
{
soundPlayer.clip = loadedAudioClips[name];
soundPlayer.Play();
}
public void StopMusic()
{
musicPlayer.Stop();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyController : MonoBehaviour
{
public float speed = 2.5f;
void Update()
{
transform.Translate(Vector3.left * speed * Time.deltaTime);
if (transform.position.x < -10) Destroy(gameObject);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public enum GameState { Ready, Playing, Ended };
public class GameManager : MonoBehaviour
{
public GameState gameState = GameState.Ready;
public float paralaxSpeed = 0.02f;
public RawImage background, platform;
public GameObject uiReady, uiScore;
void Update()
{
bool userAction = Input.GetKeyDown("space") || Input.GetMouseButtonDown(0);
HandleExit();
HandleCollisions();
HandleJump(userAction);
UpdateParallax();
UpdateGameState(userAction);
}
void HandleJump(bool userAction)
{
if (gameState == GameState.Playing)
{
if (userAction && PlayerManager.Instance.grounded)
{
// Play audio preventing Prevent multiple jump sounds
AudioManager.Instance.PlaySound("Jump");
PlayerManager.Instance.SetAnimation("PlayerJump");
}
}
}
void HandleCollisions()
{
if (gameState == GameState.Playing)
{
if (PlayerManager.Instance.enemyCollision)
{
gameState = GameState.Ended;
PlayerManager.Instance.SetAnimation("PlayerDie");
AudioManager.Instance.PlaySound("Die");
AudioManager.Instance.StopMusic();
}
}
}
void UpdateGameState(bool userAction)
{
if (gameState == GameState.Ready && userAction)
{
gameState = GameState.Playing;
uiReady.SetActive(false);
uiScore.SetActive(true);
PlayerManager.Instance.SetAnimation("PlayerRun");
SpawnManager.Instance.StartSpawner();
SpeedManager.Instance.StartIncreasingSpeed();
}
else if (gameState == GameState.Ended)
{
if (userAction) SceneManager.LoadScene("Main");
SpawnManager.Instance.StopSpawner();
SpeedManager.Instance.ResetSpeed();
}
}
void UpdateParallax()
{
if (gameState == GameState.Playing)
{
float finalSpeed = paralaxSpeed * Time.deltaTime;
background.uvRect = new Rect(background.uvRect.x + finalSpeed, 0f, 1f, 1f);
platform.uvRect = new Rect(platform.uvRect.x + finalSpeed * 4, 0f, 1f, 1f);
}
}
void HandleExit()
{
if (Input.GetKey(KeyCode.Escape)) Application.Quit();
}
}
  • Introducción (hay que grabarla)

Hola a todos y bienvenidos a la unidad del curso donde vamos a desarrollar nuestro primer videojuego completo y multiplataforma en Unity: Jumping Guy.

Jumping Guy es un videojuego original de mi propia creación ideado para enseñar a los estudiantes de forma práctica los conceptos clave del desarrollo.

Lo más importante de este proyecto es que, más allá del propio videojuego, con él aprenderéis a diseñar conceptos responsivos compatibles en múltiples dispositivos y a organizar el código en sistemas extensibles y reutilizables para vuestros futuros videojuegos.

Espero que aprendáis mucho y si tenéis alguna duda reguntadme sin problema, estaré encantado de ayudaros.

  • Qué vas a aprender
  • Diseño responsivo (lo de multiplataforma no me gusta)
  • Creando la escena (recordar desactivar la compresión de los fondos)
  • Efecto parallax
  • Portada animada
  • Creación del jugador (recordar desactivar la compresión)
  • Animación de correr
  • Animación de saltar
  • Creación del enemigo (recordar desactivar la compresión)
  • Generador de enemigos
  • Autodestruir enemigos
  • Animación de muerte
  • Reinicio y cierre de juego
  • Dificultad progresiva
  • Marcador de puntos (recordar quitar el animador al clonar la UI)
  • Guardado del récord
  • Música y SFX (recordar que la posición Y del sprite idle y principio/final jump debe ser igual)
  • Distribución multiplataforma
    • En WebGL hacer build and run para probar en el servicio local
    • En Android instalar el módulo Android y OpenJDK, generar la apk en Debug (por defecto), utilizar el emulador BlueStacks para testear. Para poder ejecutar el juego en algunos emuladores desactivar de Projects Settings > Players > Resolution la opción Optimized Frame Pacing y generar el apk.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerManager : MonoBehaviour
{
public static PlayerManager Instance { get; private set; }
public bool enemyCollision, grounded;
public float startY;
void Awake()
{
Instance = this;
}
void Start()
{
startY = transform.position.y;
}
void Update()
{
grounded = transform.position.y == startY;
}
public void SetAnimation(string name)
{
GetComponent<Animator>().Play(name);
}
// Player => Kinematic RB2D ;; Enemy => Trigger
void OnTriggerEnter2D(Collider2D collision) {
if (collision.tag == "Enemy")
{
enemyCollision = true;
GetComponent<BoxCollider2D>().enabled = false; // disable to prevent extra points
}
else if (collision.tag == "Point")
{
ScoreManager.Instance.IncreasePoints();
AudioManager.Instance.PlaySound("Point");
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScoreManager : MonoBehaviour
{
public static ScoreManager Instance { get; private set; }
public Text currentPointsText, maxPointsText;
private int points;
void Awake()
{
Instance = this;
}
private void Start()
{
UpdateMaxScore();
}
public void IncreasePoints()
{
currentPointsText.text = (++points).ToString(); //points++;
UpdateMaxScore();
}
public void UpdateMaxScore()
{
int maxPoints = PlayerPrefs.GetInt("Max", 0);
if (points >= maxPoints)
{
maxPoints = points;
PlayerPrefs.SetInt("Max", maxPoints);
}
maxPointsText.text = "BEST: " + maxPoints.ToString();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnManager: MonoBehaviour
{
public static SpawnManager Instance { get; private set; }
public GameObject enemyPrefab;
public float spawnTimer = 2f;
void Awake()
{
Instance = this;
}
public void StartSpawner()
{
InvokeRepeating("SpawnEnemy", 0f, spawnTimer);
}
public void StopSpawner()
{
CancelInvoke("SpawnEnemy");
}
void SpawnEnemy()
{
Instantiate(enemyPrefab, transform.position, Quaternion.identity);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpeedManager : MonoBehaviour
{
public static SpeedManager Instance { get; private set; }
public float gameSpeedInc = 0.25f, gameSpeedTimer = 6f;
void Awake()
{
Instance = this;
}
public void StartIncreasingSpeed()
{
InvokeRepeating("IncreaseSpeed", gameSpeedTimer, gameSpeedTimer);
}
public void ResetSpeed()
{
Time.timeScale = 1f;
CancelInvoke("IncreaseSpeed");
}
void IncreaseSpeed()
{
Time.timeScale = Time.timeScale + gameSpeedInc;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment