Autor Tema: [MiniConcurso] Estilos de programación  (Leído 836 veces)

JaviCepa

  • Socio
  • Mega Jammer
  • ****
  • Mensajes: 433
  • Molas: 45
    • @JaviCepa
[MiniConcurso] Estilos de programación
« en: 31 de Agosto de 2015, 08:16:41 pm »
Estábamos hablando en este otro post sobre cuales eran las mejores prácticas a la hora de escribir código y se me ha ocurrido abrir este post para proponer un pequeño juego y entendernos mejor, a la vez que compartimos un poco de código :)

El juego consiste en lo siguiente:
  • Escribir un pequeño bloque de código que cumpla una serie de funcionalidades (ver más abajo) sin mirar el código de los demás tal cual lo harías normalmente, incluyendo comentarios, etc...
  • Insertarlo en un bloque code+spoiler para que no quede a la vista de los demás
  • Una vez publicado tu código en el hilo, invita a participar a alguien cuyo estilo de programación quieras conocer.

El código debe implementar la lógica de una torreta de juego tipo Tower Defense, incluyendo lo siguiente:
  • Un sistema de disparo automático cada X tiempo
  • Un sistema de upgrades
  • Un sistema de construcción / destrucción

Los comentarios sobre el código de los demás se deben hacer en el otro hilo para no entorpecer el juego.

Todos los posts que no contengan el código del "minijuego" serán borrados.

JaviCepa

  • Socio
  • Mega Jammer
  • ****
  • Mensajes: 433
  • Molas: 45
    • @JaviCepa
Re:[MiniConcurso] Estilos de programación
« Respuesta #1 en: 31 de Agosto de 2015, 08:53:55 pm »
Allá va mi código (lo he hecho en notepad, así que es probable que tenga errores, pero bueno, sirve para ver mi estilo).

Spoiler for Hiden:
Código: [Seleccionar]
public class TurretBehaviour : MonoBehaviour {

ShootSystem shootSystem;
UpgradeSystem upgradeSystem;

void Start() {
shootSystem=new ShootSystem(5);
upgradeSystem=new UpgradeSystem(10);
}

void Update() {
RunTurretIA();
CheckForInputs();
}

void RunTurretIA() {
shootSystem.TryToShoot();
}

void CheckForInputs() {
if (Input.GetKeyDown(KeyCode.Add)) {
upgradeSystem.TryToUpgrade();
}
}

public static Turret Build(Vector3 targetPosition) {
GameObject newTurretObject=new GameObject("Turret");
TurretBehaviour newTurret=newTurretObject.AddComponent<TurretBehaviour>();
newTurretObject.transform.position=targetPosition;
}

public void Demolish() {
Destroy(gameObject);
Debug.log("Kapow!");
}
}

public class UpgradeSystem {

public int currentLevel;
int upgradeCostPerLevel=10;

public UpgradeSystem(int upgradeCostPerLevel) {
this.upgradeCostPerLevel=upgradeCostPerLevel;
currentLevel=0;
}

public void TryToUpgrade() {
if (MeetsUpgradeRequirements()) {
Upgrade();
}
}

bool MeetsUpgradeRequirements() {
return Player.money>=CurrentLevelUpgradeCost();
}

int CurrentLevelUpgradeCost() {
return currentLevel*upgradeCostPerLevel;
}

void Upgrade() {
Player.money-=CurrentLevelUpgradeCost();
currentLevel++;
}

void Downgrade() {
if (currentLevel>0) {
currentLevel--;
} else {
Debug.log("Can't downgrade from level 0");
}
}

}

public class ShootSystem {

int ammo;
int maxAmmo;
float lastShootTime=0;
bool reloading=false;

public ShootSystem(int maxAmmo) {
this.maxAmmo=maxAmmo;
ammo=maxAmmo;
}

public void TryToShoot() {
if (IsReadyToShoot()) {
Shoot();
}
}

bool IsReadyToShoot() {
if (Time.time>lastShootTime+delayBetweenShots && ammo>0 && !reloading) {
return true;
} else {
return false;
}
}

void Shoot() {
SpendAmmo();
lastShootTime=Time.time;
Debug.Log("Panyum!");
}

void SpendAmmo() {
ammo--;
if (ammo==0) {
Reload();
}
}

void Reload() {
ammo=maxAmmo;
//TODO: Add reload time delay
}

}

//Esto es un singleton guarro, lo hago solamente para que tenga sentido lo de arriba. No hagáis esto en vuestras casas.
public static class Player {
public static int money=0;
}

EDIT: Por lo visto el spoiler y el code no se llevan bien... Es igual, publicadlos así y cuando ya esté maduro el hilo quitamos los spoilers.

EDIT2: Desafío a @JuDelCo !

santiandrade

  • Jammer
  • **
  • Mensajes: 89
  • Molas: 13
  • @SantiHisteria | histeriagamedev.com
    • Histeria Gamedev
Re:[MiniConcurso] Estilos de programación
« Respuesta #2 en: 01 de Septiembre de 2015, 12:09:42 pm »
Así es como yo lo haría, haciendo uso, como ya había comentado en el otro post, de algunos comentarios descriptivos. Sobre el refactoring, se podría mejorar seguro ;D Pero bueno para hacernos una idea de cómo codificamos cada uno...

Ahí va mi Tower Defense! Comentar que nunca he hecho uno y que el tema del "Upgrade" no sabía muy bien cómo abordarlo, así que he tirado a lo básico de subir nivel en fucnión de unos puntos obtenidos. A ver qué os parece :)

Spoiler for Hiden:
Código: [Seleccionar]
/// <summary>
/// "TowerDefense.cs" - Controla el comportamiento de una torre de defensa.
/// \author     Santi Andrade
/// \date       Creación: 01/09/2015
/// \date       Última modificación: 01/09/2015
/// \version    1.0.0
/// </summary>
public class TowerDefense : MonoBehaviour
{
    // ----------------
    // Public Variables
    // ----------------
   
    /// <summary>
    /// Es número máximo de disparos que tendrá la torre antes de volver a recargar.
    /// </summary>
    public int MaxNumberOfShots = 10;

    /// <summary>
    /// Es el tiempo (en segundos) que transcurrirá antes de cada disparo.
    /// </summary>
    public float TimeBeforeShot = 2;

    /// <summary>
    /// Es el tiempo que tardará en recargar después de agotar todos los disparos.
    /// </summary>
    public float ReloadingTime = 5;

    /// <summary>
    /// Es el prefab que usaremos como disparo. Para este ejemplo no me centraré en la implementación de este prefab.
    /// </summary>
    public GameObject ShotPrefab;

    /// <summary>
    /// Es el prefab de una de nuestras torres de defensa que usaremos para poder generarlas.
    /// </summary>
    public GameObject TowerPrefab;

    // -----------------
    // Private Variables
    // -----------------

    private float _lastShotTime;
    private int _currentShots;
    private bool _isReloading;

    // ------------
    // Unity Events
    // ------------

    void Start()
    {
        _lastShotTime = 0;
        _currentShots = 0;
        _isReloading = false;
    }

    void Update()
    {
        // Si en algún momento la torre agota todos sus disparos, recarga.
        if (_currentShots == MaxNumberOfShots)
        {
            Reload();
        }
    }

    void OnTriggerStay(Collider other)
    {
        // Si algún enemigo se encuentra en la zona de ataque de la torre, atacamos.
        if (other.Tag == "Enemy")
        {
            Fire();
        }
    }

    // --------------
    // Public Methods
    // --------------

    /// <summary>
    /// Construye una nueva torre en la posición indicada
    /// </summary>
    /// <param name="newTowerPosition"></param>
    public void GenerateTower(Vector3 newTowerPosition)
    {
        Instantiate(TowerPrefab, newTowerPosition, Quaternion.identity);
    }

    /// <summary>
    /// Destruye la torre
    /// </summary>
    public void DestroyTower()
    {
        Destroy(this.gameObject);
    }

    // ---------------
    // Private Methods
    // ---------------
   
    private void Fire()
    {
        if (ShotPrefab != null &&
            _currentShots < MaxNumberOfShots &&
            (_lastShotTime + TimeBeforeShot) < Time.time &&
            !_isReloading)
        {
            // En lugar de usar el método Instantiate(), haremos uso de object pooling.
            // El método de extensión Spawn() pertenece a una clase "ObjectPool" que implementa el sistema de reciclaje.
            // No me centraré en la implementación de dicho sistema de pooling.
            ShotPrefab.Spawn(transform.parent.position, Quaternion.identity);

            _currentShots++;
            _lastShotTime = Time.time;
        }
    }

    private void Reload()
    {
        _currentShots = 0;

        // Realizamos un delay mientras nuestra torre recarga.
        StartCoroutine(WaitForReload());
    }

    IEnumerator WaitForReload()
    {
        _isReloading = true;
        yield return new WaitForSeconds(ReloadingTime);
        _isReloading = false;
    }
}

/// <summary>
/// "UpgradeSystem.cs" - Controla la actualización de niveles de nuestro juego.
/// \author     Santi Andrade
/// \date       Creación: 01/09/2015
/// \date       Última modificación: 01/09/2015
/// \version    1.0.0
/// </summary>
public class UpgradeSystem : MonoBehaviour
{
    // ----------------
    // Public Variables
    // ----------------
   
    /// <summary>
    /// Indica el nivel actual del juego.
    /// </summary>
    public int CurrentLevel;

    /// <summary>
    /// Indica el número de puntos necesarios para subir de nivel.
    /// </summary>
    public int PointsToLevelUp;


    // ------------
    // Unity Events
    // ------------

    void Update()
    {
        // Comprobamos si podemos subir de nivel.
        if (GameGeneralVariables.TotalPoints > PointsToLevelUp * CurrentLevel)
        {
            CurrentLevel++;
        }
    }
}

/// <summary>
/// "GameGeneralVariables.cs" - Almacena las variables generales de nuestro juego.
/// \author     Santi Andrade
/// \date       Creación: 01/09/2015
/// \date       Última modificación: 01/09/2015
/// \version    1.0.0
/// </summary>
public static class GameGeneralVariables
{
    // Esto es una variable estática que usaremos para ir almacenando la puntuación del jugador.
    // No me centraré en la implementación del sistema de puntuación.
    public static int TotalPoints;
}

JuDelCo

  • En evolución
  • Socio
  • Super Jammer
  • ***
  • Mensajes: 240
  • Molas: 35
  • The Game
    • Twitter
Re:[MiniConcurso] Estilos de programación
« Respuesta #3 en: 02 de Septiembre de 2015, 07:39:34 pm »
A ver, lo he escrito rápido y sin IDE ni nada, pero así más o menos quedaría la base del código programado con Entitas que es el framework que he utilizado para mi último juego.

No está todo definido y faltan cosas, pero con esto se coge la idea principal de como se usa el framework. No trabajo con comentarios así que no los tiene. Es normal que no se entienda el código ya que primero hay que entender como funciona el framework, pero bueno, como la implementación del concurso era libre es lo que ha tocado  ;D

Spoiler for Hiden:
Código: [Seleccionar]
public class TurretComponent : IComponent
{
public float enemyRange;
}

public class LevelUpgradeComponent : IComponent
{
public int multiplier;
}

public class ShooterComponent : IComponent
{
public float nextShoot;
public float delay;
}

public static Entity CreateTurret(this Pool pool, Vector3 position, float shootDelay)
{
    return pool.CreateEntity()
        .AddTurret(50.0f)
        .AddPosition(position)
        .AddHealth(100.0f)
        .AddShooter(0, shootDelay)
        .AddLevelUpgrade(1);
}

--------------------------------

public class TurretSystem : IExecuteSystem, ISetPool
{
Pool _pool;
Group _turrets;

public void SetPool(Pool pool)
{
_pool = pool;
_turrets = pool.GetGroup(Matcher.AllOf(Matcher.Turret, Matcher.Shooter, Matcher.Position, Matcher.LevelUpgrade));
}

public void Execute()
{
foreach (var e in _turrets.GetEntities())
{
if(e.shooter.nextShoot <= Time.time)
{
e.replaceShooter(Time.time + e.shooter.delay, e.shooter.delay);

_pool.CreateBullet(
e.position.value,
_pool.FindClosestEnemy(e.position.value, e.turret.enemyRange),
e.levelUpgrade.multiplier
);
}
}
}
}