Cheese Trap

January 2019 - February 2019 | Jam Game


Project Information

  • Team Size: 7
  • Genre: 2D Party Game
  • Platform: Windows
  • Engine: Unity 5
  • Develop time: 1 week
  • itch.io: Download
  • Github: Source Code

About

Cheese trap is a local two-player game where you play as a mouse to compete each other. You are competing on an environment where you can eat foot to create holes, when your rival falls into the holes, you win.

When time is up, the player who consumes the most wins the game.


My contributions

  • Implemented majority of gameplay functions with another programmer
  • Developed the pipeline for creating map textures and hole textures
  • Implemented several shaders for creating the hole digging effect on the original map
  • Implemented several UI animations for the UI system

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

public class HoleManager : MonoBehaviour
{
    const int texWidth = 960;
    const int texHeight = 540;
    public List holes;
    public int[] areas;

    public GameObject holeColliderPrefab;
    // playerNum should be fetched from GameManager later
    private int playerNum = 2;
    // holeTexture has the size 960x540
    // holeTexture is used to calculate holes and masks
    private Texture2D holeTexture;
    private Texture2D terrainTexture;

    public int gameLevel;

    private int[,] caramelCoolDown = new int[960,540];
    private Texture2D originalHoleTexture;

    // only for debug
    // private GameObject testTextureDisplay;

    // SpriteRenderer sr;

    // Start is called before the first frame update
    public void InitializeLevel(int level)
    {
        holes = new List();
        caramelCoolDown = new int[960, 540];
        areas = new int[playerNum + 1];
        LoadLevelTerrainTexture(level);
        InitializeHoleTexture();
    }

    // Update is called once per frame
    void Update()
    {

    }

    // judge current status of the player on the terrain
    // -1 -> die
    // 0 -> normal
    // 1 -> ice / cream e.t.c
    public int getTerrainStatus(Vector2 position){
        position.x *= 50;
        position.y *= 50;
        if ((holeTexture.GetPixel((int)position.x, (int)position.y).r != 0 && holeTexture.GetPixel((int)position.x, (int)position.y).r != 1) ||
            holeTexture.GetPixel((int)position.x, (int)position.y).g == 1)
            return -1;
        return (int)Mathf.Round(holeTexture.GetPixel((int)position.x, (int)position.y).g * 255);
    }

    public Texture2D GetHoleTexture(){
        return holeTexture;
    }

    private void InitializeHoleTexture(){
        holeTexture = new Texture2D(texWidth, texHeight);
        Color[] colors = terrainTexture.GetPixels();
        // for (int i=0; i();
        // Sprite pic = Sprite.Create(holeTexture, new Rect(0, 0, texWidth, texHeight), new Vector2(0.5f,0.5f));
        // sr.sprite = pic;

    }

    void InitializeTerrainTexture(){
        terrainTexture= new Texture2D(texWidth, texHeight);
        Color[] colors = new Color[texWidth*texHeight];
        for (int i=0; i texWidth)
            Right = texWidth - 1;
        if (Bottom < 0)
            Bottom = 0;
        if (Top > texHeight)
            Top = texHeight - 1;

        int colorIndex = 0;
        for (int x = Left; x <= Right; x++){
            for (int y = Bottom; y <= Top; y++){
                if ((x - position.x)*(x - position.x) + (y - position.y)*(y - position.y) <= radius*radius && holeTexture.GetPixel(x, y).r == 0
                   && holeTexture.GetPixel(x, y).r != 1){
                    holeTexture.SetPixel(x, y, new Color32((byte)playerID, 0, 0, 255));
                    areas[playerID]++;
                }

                colorIndex++;
            }
        }
        holeTexture.Apply();
        DisplayHoleTexture();
    }

    public void GenerateCaramelAtPoint(Vector2 position, int radius){
        int cx = (int) position.x;
        int cy = (int) position.y;
        for (int x = cx - radius; x <= cx + radius; x++){
            for (int y = cy - radius; y <= cy + radius; y++){
                if (x >= 0 && x < texWidth && y >= 0 && y < texHeight && (x-cx)*(x-cx) + (y-cy)*(y-cy) <= radius * radius &&
                    holeTexture.GetPixel(x,y).r == 0 && holeTexture.GetPixel(x,y).g != 1){
                        StartCoroutine(SetCaramel(x, y));
                    }
            }
        }
        holeTexture.Apply();
    }

    IEnumerator SetCaramel(int x, int y){
        caramelCoolDown[x,y] += 1;
        Color c = holeTexture.GetPixel(x, y);
        Color originalColor = c;
        holeTexture.SetPixel(x, y, new Color(c.r, 3.0f/255, c.b, c.a));
        yield return new WaitForSeconds(1.5f);
        if (caramelCoolDown[x,y] == 1)
            holeTexture.SetPixel(x, y, originalHoleTexture.GetPixel(x, y));
        caramelCoolDown[x,y] -= 1;
        yield return null;
    }


    public void DisplayHoleTexture(){
        GameObject map = GameObject.Find("ForeGround");
        map.GetComponent().material.SetTexture("_Mask", holeTexture);
        GameObject shadow = GameObject.Find("HoleShadow");
        shadow.GetComponent().material.SetTexture("_Mask", holeTexture);
    }
}
            

HoleManager

The Hole Manager is used to create and update maps on the fly while players are digging holes which changes the map definition. The map size is 960x540 , and the script is capable of running at 60fps.


FlowAndSpinEffect

The Flow and Spin Effect is a UI Effect Shader used for tide flow effects on the UI Disc.

Shader "Custom/FlowAndSpinEffect"
{
    Properties
    {
        _MainTex ("Sprite Texture", 2D) = "white" {}
        _FlowTex ("Base (RGB)", 2D) = "white" {}
        _ScrollXSpeed("XSpeed", Range(-10, 10)) = -3
        _RotateSpeed("RotateSpeed", Range(-10, 10)) = 0.5
        _FadeAlpha("Alpha", Range(0, 1)) = 1
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        Blend SrcAlpha OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;
            sampler2D _FlowTex;
            fixed _ScrollXSpeed;
            fixed _RotateSpeed;
            fixed _FadeAlpha;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed xScrollValue = _ScrollXSpeed * _Time.y;
                fixed theta = _RotateSpeed * _Time.y;

                fixed2 pos = i.uv-fixed2(0.5, 0.5);
                fixed4 col = tex2D(_MainTex, fixed2(pos.x*cos(theta) - pos.y*sin(theta), pos.x*sin(theta) + pos.y*cos(theta)) + fixed2(0.5, 0.5));
                fixed4 flowcol = tex2D(_FlowTex, i.uv + fixed2(xScrollValue, 0));
                if ((i.uv.x-0.5) * (i.uv.x-0.5) + (i.uv.y-0.5) * (i.uv.y-0.5) > 0.25)
                    col.a = 0;
                if (col.r == 0 && col.g == 0 && col.b == 0)
                    col.a = 0;
                col.rgb = min(col.rgb + flowcol.rgb / 4, 1);
                if (col.a == 1)
                    col.a = _FadeAlpha;

                return col;
            }
            ENDCG
        }
    }
}
            

Data Oriented Maps

  • For displaying a map, we have 4 layers for making the level display working.
  • Background: Providing the static background information.
  • Foreground: Providing the original foreground information, also used as a base texture for hole shader.
  • Shadow Map: Providing information for creating the "dig shadow" feeling for the hole shader.
  • Terrain Map: Providing information for game manager to indicate "Where can player go" and "Where are the obstacles". It's also used in the Ice Map for making the ground feel slippery.

Post Moterm


What Went Well

  • Developed an awesome jam game with my good teammates in only one week
  • Learned how to create shaders
  • Implemented data oriented map structure

What Went Wrong

  • One programmer in our team has few experience and felt behind when we were developing at fast pace

What I learned

  • Developing with a team of strong developers is really fun
  • Learn to manage time properly, some days we stayed over night to make features working