Auteur: felix.huiskamp

  • Game Jam – Young and Old

    Game Jam – Young and Old

    Schooljaar 3 periode 1 

    In periode 1 van schooljaar 2025 – 2026 hadden we een game jam voor 1 week. De project was een Game gemaakt met Unity C#. Ik had toen besloten om de UI te gaan programmeren. Ik had dus toen de Main Menu, Settings en Win screen gemaakt. 

    Main Menu

    Pause Menu

    
    public class MainMenu : MonoBehaviour
    {
        [Header("Panels")]
        public GameObject mainMenuPanel;    
        public GameObject settingsPanel;
    
        [Header("Settings Controls")] 
        public Slider volumeSlider;
        public Toggle fullscreenToggle;
        
    
        private void Start()
        {
            mainMenuPanel.SetActive(true);
            settingsPanel.SetActive(false);
    
            // Initialize settings from PlayerPrefs
            volumeSlider.value = PlayerPrefs.GetFloat("Volume");
            fullscreenToggle.isOn = PlayerPrefs.GetInt("Fullscreen") == 1;
        }
    
        public void PlayGame()
        {
            // Load the main game scene
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
        }
    
        public void QuitGame()
        {
            // Quit the application
            Debug.Log("Quit Game!");
            Application.Quit();
        }
    
        public void OpenSettings()
        {
            mainMenuPanel.SetActive(false);
            settingsPanel.SetActive(true);
        }
    
        public void BackToMenu()
        {
            mainMenuPanel.SetActive(true);
            settingsPanel.SetActive(false);
        }
    
        public void SetVolume(float value)
        {
            AudioListener.volume = value;
            PlayerPrefs.SetFloat("Volume", value);
        }
    
        public void SetFullscreen(bool isFullscreen)
        {
            Screen.fullScreen = isFullscreen;
            PlayerPrefs.SetInt("Fullscreen", isFullscreen ? 1 : 0);
        }
    }

    Main Menu Script

  • Ultrakill-Slideshow

    Ultrakill-Slideshow

    In periode 2 van schooljaar 2024 – 2025 kregen we een slideshow en kon je kiezen welke game je moest namaken. Ik had toen Ultrakill gekozen en gingen we samenwerken met Game-Artists. Het groepje bestond uit 3 Game-Developers en 3 Game-Artists. We  deden er ongeveer 10 weken over om het spel na te maken.

    Health en stamina systeem

    public class PlayerHealth : MonoBehaviour
    {
    
        [Header("Health Settings")]
        [SerializeField] private float maxHealth = 100f;
        private float currentHealth;
    
        [Header("UI")]
        public Slider healthBar;
        public GameObject deathScreen; 
        void Start()
        {
            //Geeft de speler max health als je begint met het spel.
    
            currentHealth = maxHealth;
    
            if (healthBar != null)
            {     
                healthBar.maxValue = maxHealth;
                healthBar.value = currentHealth;
            }
    
            if (deathScreen != null) 
            { 
                deathScreen.SetActive(false);
            }
        }
    
        void Update()
        {
            //Geeft 10 damage als je op Q drukt.
    
            if (Input.GetKeyDown(KeyCode.Q))
            {
                TakeDamage(10f);
            }
    
            //Geeft de speler 10 health terug als je op E drukt.
    
            if (Input.GetKeyDown(KeyCode.E))
            {
                Heal(10f);
            }
    
            //Restart de game als je dood gaat en een death screen krijgt.
    
            if (deathScreen.activeSelf && Input.GetKeyDown(KeyCode.R))
            {
                RestartGame();
            }
        }
    
        public void TakeDamage(float damage) 
        { 
            //Zorgt ervoor dat als je damage krijgt dat het van de healthbar af gaat.
            currentHealth -= damage;
            currentHealth = Mathf.Clamp(currentHealth, 0, maxHealth);
    
            if (healthBar != null) 
            {
                healthBar.value = currentHealth;
            }
            //Als de speler minder dan 0 health heeft gaat de speler dood.
            if (currentHealth <= 0)
            {
                Die();
            }
        }
    
        public void Heal(float amount) 
        { 
            //Zorgt ervoor dat als je healed dat je health bij je healthbar krijgt.
            currentHealth += amount;
            currentHealth = Mathf.Clamp(currentHealth, 0, maxHealth);
    
            if (healthBar != null)
            {
                healthBar.value = currentHealth;
            }
        }
    
        private void Die() 
        {
            //Zorgt ervoor dat als je dood bent dat het de deathScreen activeert en de tijd van de spel op stop zet.
            Debug.Log("Player is dead!");
            if (deathScreen != null) 
            {
                deathScreen.SetActive(true);
            }
            Time.timeScale = 0f;
        }
    
        public void RestartGame()
        {
            //Zorgt ervoor dat als je de spel restart dat de tijd weer doorgaat en dat de scene wordt terug geladen.
            Time.timeScale = 1f;
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }

    Health script

    public class PlayerDash : MonoBehaviour
    {
        [Header("Movement Settings")]
        public float moveSpeed = 5f; 
        public float dashSpeed = 20f;
        public float dashDuration = 0.2f;
        public float dashCooldown = 1f; 
    
        private CharacterController controller;
        private Vector3 moveDirection;
        private bool isDashing = false;
        private float dashTime;
        private float lastDashTime;
    
        [Header("Camera Settings")]
        public Transform cameraTransform;
        public float dashShakeIntensity = 0.1f;
    
        [Header("Stamina Settings")]
        public int maxDashes = 3;
        private int currentDashes;
        public float staminaRechargeTime = 3f;
        private float staminaRechargeTimer;
    
        [Header("UI")]
        public Slider staminaBar; 
        void Start()
        {
            //De speler begint met max 3 dashes als je de game opstart
            controller = GetComponent<CharacterController>();
            currentDashes = maxDashes;
    
            if(staminaBar != null)
            {
                staminaBar.maxValue = maxDashes;
                staminaBar.value = currentDashes;
            }
        }
    
        
        void Update()
        {
            if (!isDashing)
            {
                HandleMovement();
                HandleDashInput(); 
            }
            else 
            {
                DashMove(); 
            }
            RechargeStamina();
        }
    
        //Zorgt ervoor dat de player kan bewegen in de goeie directie. 
    
        void HandleMovement()
        {
            float moveX = Input.GetAxis("Horizontal");
            float moveZ = Input.GetAxis("Vertical");
    
            moveDirection = (cameraTransform.forward * moveZ + cameraTransform.right  * moveX).normalized;
            controller.Move(moveDirection * moveSpeed * Time.deltaTime);
        }
    
        //Zorgt ervoor dat de player max 3 keer kan dashen met Left shift.
    
        void HandleDashInput()
        {
            if (Input.GetKeyDown(KeyCode.LeftShift) && currentDashes > 0)
            {
                StartDash(); 
            }
        }
    
    
        //Zorgt ervoor dat de dash begint en neemt ook stamina af als je dashed.
        void StartDash()
        {
            isDashing = true; 
            dashTime = Time.time + dashDuration;
            lastDashTime = Time.time;
    
            currentDashes--; 
    
            if (staminaBar != null)
            {
                staminaBar.value = currentDashes;
            }
        }
    
        //Zorgt ervoor dat de player dashed in de goeie richting met de juiste velocity.
    
        void DashMove()
        {
            Vector3 dashVelocity = moveDirection * dashSpeed; 
            controller.Move(dashVelocity * Time.deltaTime);
    
            cameraTransform.localPosition += Random.insideUnitSphere * dashShakeIntensity; 
    
            if (Time.time >= dashTime)
            {
                isDashing = false; 
                cameraTransform.localPosition = new Vector3(0, 1.8f, 0);
            }
        }
    
        //Laat de player stamina rechargen na een paar secondes.
    
        void RechargeStamina()
        {
            if (currentDashes < maxDashes)
            {
                staminaRechargeTimer += Time.deltaTime; 
    
                if(staminaRechargeTimer >= staminaRechargeTime)
                {
                    currentDashes++;
                    staminaRechargeTimer = 0;
    
                    if(staminaBar != null)
                    {
                        staminaBar.value = currentDashes;
                    }
                }
            }
        }
    }
    

    Dash script

  • Game Jam

    Game Jam

    Game Jam van periode 1 Jaar 3

    In periode 1 van schooljaar 2025 – 2026 hadden we in het eerste week voor drie dagen een game jam. Je moest dan iets creatiefs bedenken en ik had dus toen gekozen om een Commands systeem te gaan maken. 

    AI W.I.P.

    public class CommandExecutor : MonoBehaviour
    {
        /// <summary>
        /// Voert een command uit in de vorm van "ObjectName MethodName [param1] [param2] ..."
        /// </summary>
        public void ExecuteCommand(string command)
        {
            if (string.IsNullOrWhiteSpace(command))
            {
                Debug.LogWarning("[CommandExecutor] Leeg commando ontvangen.");
                return;
            }
    
            // Split command op spaties
            string[] parts = command.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
    
            if (parts.Length < 2)
            {
                Debug.LogError("[CommandExecutor] Ongeldig commando formaat. Gebruik: ObjectName MethodName [params]");
                return;
            }
    
            string objectName = parts[0];
            string methodName = parts[1];
            string[] parameters = parts.Skip(2).ToArray();
    
            Debug.Log($"[CommandExecutor] Uitvoeren: {objectName}.{methodName}({string.Join(", ", parameters)})");
    
            // Zoek het MonoBehaviour object in de scène
            MonoBehaviour targetObject = FindObjectByName(objectName);
    
            if (targetObject == null)
            {
                Debug.LogError($"[CommandExecutor] Object '{objectName}' niet gevonden in de scène.");
                return;
            }
    
            // Zoek de methode via reflectie
            Type objectType = targetObject.GetType();
            MethodInfo method = FindMethod(objectType, methodName, parameters.Length);
    
            if (method == null)
            {
                Debug.LogError($"[CommandExecutor] Methode '{methodName}' niet gevonden op '{objectName}' met {parameters.Length} parameter(s).");
                return;
            }
    
            // Converteer parameters naar de juiste types
            ParameterInfo[] methodParams = method.GetParameters();
            object[] convertedParams = new object[methodParams.Length];
    
            try
            {
                for (int i = 0; i < methodParams.Length; i++)
                {
                    convertedParams[i] = ConvertParameter(parameters[i], methodParams[i].ParameterType);
                }
            }
            catch (Exception ex)
            {
                Debug.LogError($"[CommandExecutor] Fout bij converteren van parameters: {ex.Message}");
                return;
            }
    
            // Roep de methode aan
            try
            {
                method.Invoke(targetObject, convertedParams);
                Debug.Log($"[CommandExecutor] Commando succesvol uitgevoerd: {objectName}.{methodName}");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[CommandExecutor] Fout bij uitvoeren van methode: {ex.InnerException?.Message ?? ex.Message}");
            }
        }
    
        /// <summary>
        /// Zoekt een MonoBehaviour in de scène op basis van class naam
        /// </summary>
        private MonoBehaviour FindObjectByName(string objectName)
        {
            // Zoek alle MonoBehaviours in de scène
            MonoBehaviour[] allObjects = FindObjectsOfType<MonoBehaviour>();
    
            foreach (MonoBehaviour obj in allObjects)
            {
                // Vergelijk class naam (case insensitive)
                if (obj.GetType().Name.Equals(objectName, StringComparison.OrdinalIgnoreCase))
                {
                    return obj;
                }
            }
    
            return null;
        }
    
        /// <summary>
        /// Zoekt een methode met de juiste naam en aantal parameters
        /// </summary>
        private MethodInfo FindMethod(Type type, string methodName, int paramCount)
        {
            // Zoek alle publieke methods
            MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
    
            foreach (MethodInfo method in methods)
            {
                if (method.Name.Equals(methodName, StringComparison.OrdinalIgnoreCase) &&
                    method.GetParameters().Length == paramCount)
                {
                    return method;
                }
            }
    
            return null;
        }
    
        /// <summary>
        /// Converteert een string parameter naar het gewenste type
        /// </summary>
        private object ConvertParameter(string value, Type targetType)
        {
            try
            {
                // Bool conversie
                if (targetType == typeof(bool))
                {
                    if (value.Equals("true", StringComparison.OrdinalIgnoreCase) || value == "1")
                        return true;
                    if (value.Equals("false", StringComparison.OrdinalIgnoreCase) || value == "0")
                        return false;
                    throw new FormatException($"Kan '{value}' niet converteren naar bool");
                }
    
                // Int conversie
                if (targetType == typeof(int))
                {
                    return int.Parse(value);
                }
    
                // Float conversie
                if (targetType == typeof(float))
                {
                    return float.Parse(value);
                }
    
                // Double conversie
                if (targetType == typeof(double))
                {
                    return double.Parse(value);
                }
    
                // String conversie
                if (targetType == typeof(string))
                {
                    return value;
                }
    
                // Fallback: gebruik Convert.ChangeType
                return Convert.ChangeType(value, targetType);
            }
            catch (Exception ex)
            {
                throw new FormatException($"Kan '{value}' niet converteren naar type {targetType.Name}: {ex.Message}");
            }
        }
    
        /// <summary>
        /// Test methode om de executor te testen vanuit de Unity Inspector
        /// </summary>
        [ContextMenu("Test Command: Cheats NoClip")]
        public void TestCheatNoClip()
        {
            ExecuteCommand("Cheats NoClip");
        }
    
        [ContextMenu("Test Command: Player Heal 50")]
        public void TestPlayerHeal()
        {
            ExecuteCommand("Player Heal 50");
        }
    
        [ContextMenu("Test Command: PlayerJump Jump")]
        public void TestPlayerJump()
        {
            ExecuteCommand("PlayerJump Jump");
        }
    
    }

    Commands Script

    public class EnemyPatrol : MonoBehaviour
    {
        public Transform[] waypoints;
        public float waitTime = 2f;
    
        private int currentWaypointIndex = 0;
        private NavMeshAgent agent;
        private float waitTimer;
        void Start()
        {
            agent = GetComponent<NavMeshAgent>();
    
            if (waypoints.Length > 0)
            {
                agent.SetDestination(waypoints[currentWaypointIndex].position);
            }
        }
    
        
        void Update()
        {
            if (waypoints.Length == 0) return;
    
            if (!agent.pathPending && agent.remainingDistance < 0.5f) 
            {
                waitTimer += Time.deltaTime;
    
                if (waitTimer >= waitTime) 
                {
                    GoToNextWaypoint();
                    waitTimer = 0f;
                }
            }
        }
    
        void GoToNextWaypoint()
        {
            currentWaypointIndex = (currentWaypointIndex  + 1) % waypoints.Length;
            agent.SetDestination(waypoints[currentWaypointIndex].position);
        }
    }

    Enemy AI Script

  • Tower – Defense

    Tower – Defense

    Project van periode 1 schooljaar 2

    In periode 1 van schooljaar 2024 – 2025 kregen we een Tower defense project en kon je kiezen welke thema je de game mee ging maken. Ik had toen Sci-fi gekozen en ging ik in mijn eentje aan het werk. Ik deed er ongeveer 10 weken over om het spel te maken.

    public class AutoTurret : MonoBehaviour
    {
        [SerializeField] private GameObject proctilePrefab;
        [SerializeField] private Transform firePoint; 
        [SerializeField] private float fireRate = 1f;
        [SerializeField] private float range = 5f;
        [SerializeField] private LayerMask alienLayer;
    
        private float fireCountdown = 0f;
    
        void Update()
        {
            Collider2D[] targetsInRange = Physics2D.OverlapCircleAll(transform.position, range, alienLayer);
    
            foreach (Collider2D target in targetsInRange)
            {
                
                if (target.CompareTag("Alien"))
                {
                    AimAtTarget(target.transform);
    
                    if (fireCountdown <= 0f)
                    {
                        Shoot();
                        fireCountdown = 1f / fireRate; 
                    }
    
                    fireCountdown -= Time.deltaTime;
                    break; 
                }
    
            }
    
            if (targetsInRange.Length > 0)
            {
                Transform target = targetsInRange[0].transform;
                AimAtTarget(target);
            }
        }
    
        void AimAtTarget(Transform target)
        {
            Vector2 direction = (target.position - transform.position).normalized;
            float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
    
            transform.rotation = Quaternion.Euler(0, 0, angle);
        }
    
        void Shoot()
        {
            Instantiate(proctilePrefab, firePoint.position, firePoint.rotation);
        }
    
        void OnDrawGizmosSelected()
        {
            Gizmos.color = Color.red; 
            Gizmos.DrawWireSphere(transform.position, range);
        }
    }