2
\$\begingroup\$

I have built this code in the past and I am reviewing it once again. I have a feeling that I could make the code much faster. Could someone please look at the code.

What happens is that every time the player's animation changes, this code will be run and it will take a 2D image and make it look 3D. NO this cannot be a prefab, as the image itself in the future will be customization by the user. They can in the future upload their own characters and play them. I cannot make them 3D by hand since the characters are dynamic.

It draws the sides and right in front of the character, but not the back. Since no one will ever see the back.

The issue is, I can see this being an issue in the future for online multiplayer games.

Its all based off the clients perspective so I could be playing the game and seeing the front of the character, while you could be on the other side seeing a completely different mesh. Could I have someone review the concept and code and let me know if I am crazy :)

Here is the VisualRenderer. It decides based on the MotorHandler and the Camera, what sprite to use.

using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class VisualHandler: CharacterBase 
{
    public enum DirectionState { Down, Left, Right, Up }
    private DirectionState CurDirState = DirectionState.Down;

    public Texture2D defaultTexture;

    public Renderer myRenderer;
    public MeshFilter myMeshFilter;

    public bool IsAnimating;
    private bool m_ForceAnimate;

    private Vector3 m_PrevEular;
    private float m_PrevIndex;

    public Transform spriteTransform;

    public int m_UVTileX = 4;
    public int m_UVTileY = 4;
    public int m_FPS = 10;

    private Vector3 m_LeftEulerAngle =  new Vector3(0.0f, 90.0f, 0.0f);
    private Vector3 m_BackEulerAngle =  new Vector3(0.0f, 180.0f, 0.0f);
    private Vector3 m_RightEulerAngle = new Vector3(0.0f, 270.0f, 0.0f);
    private Vector3 m_FaceEulerAngle =  new Vector3(0.0f, 0.0f, 0.0f);

    private SpriteMesh sMesh;

    /// <summary>
    /// Start this instance.
    /// </summary>
    private void Start()
    {
        myRenderer.sharedMaterial.mainTexture=defaultTexture;

        if(sMesh==null)
            sMesh = new SpriteMesh(defaultTexture);

        ApplyImageRotationAndSpriteTexture ();
        UpdateIdolImage ();
    }

    /// <summary>
    /// Lates the update.
    /// </summary>
    private void LateUpdate () 
    {
        // Apply Handling the image rotation
        ApplyImageRotationAndSpriteTexture ();
        UpdateImage ();
    }

    private bool m_PrevAnimateWasTrue;
    /// <summary>
    /// Updates the image.
    /// </summary>
    public void UpdateImage()
    {
        if(sMesh.texture!=defaultTexture)
            sMesh.texture=defaultTexture;

        // Calculate index based on FPS and our timeScale
        int _index = (int)(Time.timeSinceLevelLoad * m_FPS) % (m_UVTileX * m_UVTileY);

        // split into horizontal and vertical index
        int uIndex = 0;

        //This will create an instant character image switch when the player rotates the player around the player.  
        // There used to be a noticable pause in changing the image
        if(m_ForceAnimate == false)
            if(m_PrevIndex == _index)   
                return;

        //Are we animating?  If so then update the uIndex
        if(IsAnimating == true) 
        {
            uIndex = _index % m_UVTileX;
            m_ForceAnimate = IsAnimating;
        }

        //If at anypoint our forceAnimate is false, do NOT update the mesh
        if(m_ForceAnimate == false)
            return;

        m_ForceAnimate = false;
        m_PrevIndex = _index;

        myRenderer.sharedMaterial.mainTexture=defaultTexture;

        myMeshFilter.mesh=null;
        myMeshFilter.mesh=sMesh.depthMesh(new Vector2((uIndex)*defaultTexture.width/4,(3-(int)CurDirState)*defaultTexture.height/4), new Vector2(defaultTexture.width/4,defaultTexture.height/4));  
    }

    public void UpdateIdolImage()
    {
        myRenderer.sharedMaterial.mainTexture=defaultTexture;

        myMeshFilter.mesh=null;
        myMeshFilter.mesh = sMesh.depthMesh(new Vector2((0)*defaultTexture.width/4,(3-(int)CurDirState)*defaultTexture.height/4), new Vector2(defaultTexture.width/4,defaultTexture.height/4)); 
    }

    /// <summary>
    /// Applies the image rotation depending on the rotation of the main Camera
    /// </summary>
    private void ApplyImageRotationAndSpriteTexture()
    {
        if(Camera.main == null)
            return;

        float _forwardPosition  =   Vector3.Distance(Camera.main.transform.position, transform.position + transform.forward);
        float _leftPosition     =   Vector3.Distance(Camera.main.transform.position, transform.position + -transform.right);
        float _rightPosition    =   Vector3.Distance(Camera.main.transform.position, transform.position + transform.right);
        float _backwardPosition =   Vector3.Distance(Camera.main.transform.position, transform.position + -transform.forward);

        var _result = Mathf.Min(Mathf.Min (_forwardPosition, _leftPosition), Mathf.Min(_rightPosition, _backwardPosition));

        if(_result == _leftPosition)
        {
            this.CurDirState = DirectionState.Left;
            if(m_PrevEular == m_LeftEulerAngle) return;

            m_PrevEular = spriteTransform.localEulerAngles = m_LeftEulerAngle;
            m_ForceAnimate = true;

            return;
        }
        else if(_result == _forwardPosition)
        {
            this.CurDirState = DirectionState.Down;
            if(m_PrevEular == m_BackEulerAngle) return;

            m_PrevEular = spriteTransform.localEulerAngles = m_BackEulerAngle;
            m_ForceAnimate = true;

            return;
        }
        else if(_result == _rightPosition)
        {

            this.CurDirState = DirectionState.Right;
            if(m_PrevEular == m_RightEulerAngle) return;

            m_PrevEular = spriteTransform.localEulerAngles = m_RightEulerAngle;
            m_ForceAnimate = true;

            return;
        }
        else if(_result == _backwardPosition)
        {

            this.CurDirState = DirectionState.Up;
            if(m_PrevEular == m_FaceEulerAngle) return;

            m_PrevEular = spriteTransform.localEulerAngles = m_FaceEulerAngle;
            m_ForceAnimate = true;

            return;
        }
    }
}

Here is the SpriteMesh Class, this class is what draws the 3d from looking at each pixel on the 2d image.

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

public class SpriteMesh 
{
    public List<Vector3> verts = new List<Vector3>();
    public List<int> tris = new List<int>();
    public List<Vector2> UV = new List<Vector2>();

    public Texture2D texture;
    int squareCount;

    public SpriteMesh() { }
    public SpriteMesh(Texture2D sprite) { texture=sprite; }

    Mesh tmp = new Mesh();

    public int downScale=2;
    public float depth=0.07f;

    public Mesh depthMesh(Vector2 pos, Vector2 size)
    {
        for(int x = 0; x < Mathf.RoundToInt(size.x/downScale); x ++)
        {
            for(int y = 0; y < Mathf.RoundToInt(size.y/downScale); y ++)
            {
                if(texture.GetPixel(Mathf.RoundToInt(pos.x)+(x*downScale),Mathf.RoundToInt(pos.y)+(y*downScale)).a!=0)
                {
                    CubeSouth(x-Mathf.RoundToInt(size.x/(downScale*2)),y-Mathf.RoundToInt(size.y/(downScale*2)),0,pos + new Vector2(x*downScale,y*downScale));
                    CubeNorth(x-Mathf.RoundToInt(size.x/(downScale*2)),y-Mathf.RoundToInt(size.y/(downScale*2)),0,pos + new Vector2(x*downScale,y*downScale));

                    if(Mathf.RoundToInt(pos.x)+((x+1)*downScale)>=texture.width)
                        CubeEast(x-Mathf.RoundToInt(size.x/(downScale*2)),y-Mathf.RoundToInt(size.y/(downScale*2)),0,pos + new Vector2(x*downScale,y*downScale));
                    if(Mathf.RoundToInt(pos.x)+((x-1)*downScale)<=0)
                        CubeWest(x-Mathf.RoundToInt(size.x/(downScale*2)),y-Mathf.RoundToInt(size.y/(downScale*2)),0,pos + new Vector2(x*downScale,y*downScale));
                    if(Mathf.RoundToInt(pos.y)+((y+1)*downScale)>=texture.height)
                        CubeTop(x-Mathf.RoundToInt(size.x/(downScale*2)),y-Mathf.RoundToInt(size.y/(downScale*2)),0,pos + new Vector2(x*downScale,y*downScale));
                    if(Mathf.RoundToInt(pos.y)+((y-1)*downScale)<=0)
                        CubeBot(x-Mathf.RoundToInt(size.x/(downScale*2)),y-Mathf.RoundToInt(size.y/(downScale*2)),0,pos + new Vector2(x*downScale,y*downScale));


                    if(texture.GetPixel(Mathf.RoundToInt(pos.x)+((x+1)*downScale),Mathf.RoundToInt(pos.y)+(y*downScale)).a==0)
                        CubeEast(x-Mathf.RoundToInt(size.x/(downScale*2)),y-Mathf.RoundToInt(size.y/(downScale*2)),0,pos + new Vector2(x*downScale,y*downScale));

                    if(texture.GetPixel(Mathf.RoundToInt(pos.x)+((x-1)*downScale),Mathf.RoundToInt(pos.y)+(y*downScale)).a==0)
                        CubeWest(x-Mathf.RoundToInt(size.x/(downScale*2)),y-Mathf.RoundToInt(size.y/(downScale*2)),0,pos + new Vector2(x*downScale,y*downScale));

                    if(texture.GetPixel(Mathf.RoundToInt(pos.x)+(x*downScale),Mathf.RoundToInt(pos.y)+((y+1)*downScale)).a==0)
                        CubeTop(x-Mathf.RoundToInt(size.x/(downScale*2)),y-Mathf.RoundToInt(size.y/(downScale*2)),0,pos + new Vector2(x*downScale,y*downScale));

                    if(texture.GetPixel(Mathf.RoundToInt(pos.x)+(x*downScale),Mathf.RoundToInt(pos.y)+((y-1)*downScale)).a==0)
                        CubeBot(x-Mathf.RoundToInt(size.x/(downScale*2)),y-Mathf.RoundToInt(size.y/(downScale*2)),0,pos + new Vector2(x*downScale,y*downScale));
                }               
            }
        }

        UpdateMesh (tmp);
        tmp.name="SpriteMesh";
        return tmp;
    }
    public Mesh mesh(Vector2 pos, Vector2 size)
    {       
        for(int x = 0; x < Mathf.RoundToInt(size.x/2); x ++)
        {
            for(int y = 0; y < Mathf.RoundToInt(size.y/2); y ++)
            {
                if(texture.GetPixel((int)pos.x+x,(int)pos.y+y).a!=0)
                    CubeSouth(x-Mathf.RoundToInt(size.x/2),y-Mathf.RoundToInt(size.y/2),0, pos + new Vector2(x,y));
            }
        }

        UpdateMesh (tmp);       
        tmp.name="SpriteMesh";
        return tmp;
    }

    public float scale=0.03f;
    public float pixelSizeX {
        get{
            return 1/(float)texture.width;
        }
    }
    public float pixelSizeY {
        get{
            return 1/(float)texture.height;
        }
    }

    void CubeSouth(int x, int y,float z, Vector2 text)
    {
        verts.Add(new Vector3 (x*scale, (y - 1)*scale, z));
        verts.Add(new Vector3 (x*scale, y*scale, z));
        verts.Add(new Vector3 ((x + 1)*scale, y*scale, z));
        verts.Add(new Vector3 ((x + 1)*scale, (y - 1)*scale, z));

        Cube (text);
    }
    void CubeNorth(int x, int y,float z, Vector2 text)
    {
        verts.Add(new Vector3 ((x + 1)*scale, (y - 1)*scale, z + depth));
        verts.Add(new Vector3 ((x + 1)*scale, y*scale, z + depth));
        verts.Add(new Vector3 (x*scale, y*scale, z + depth));
        verts.Add(new Vector3 (x*scale, (y - 1)*scale, z + depth));

        Cube (text);
    }
    void CubeBot(int x, int y,float z, Vector2 text)
    {
        verts.Add(new Vector3 (x*scale,  (y - 1)*scale,  z ));
        verts.Add(new Vector3 ((x + 1)*scale, (y - 1)*scale,  z ));
        verts.Add(new Vector3 ((x + 1)*scale, (y - 1)*scale,  z + depth));
        verts.Add(new Vector3 (x*scale, (y - 1)*scale,  z + depth));

        Cube (text);
    }
    void CubeTop(int x, int y,float z, Vector2 text)
    {
        verts.Add(new Vector3 (x*scale,  y*scale,  z + depth));
        verts.Add(new Vector3 ((x + 1)*scale, y*scale,  z + depth));
        verts.Add(new Vector3 ((x + 1)*scale, y*scale,  z ));
        verts.Add(new Vector3 (x*scale,  y*scale,  z ));

        Cube (text);
    }
    void CubeWest(int x, int y,float z, Vector2 text)
    {
        verts.Add(new Vector3 (x*scale, (y - 1)*scale, z + depth));
        verts.Add(new Vector3 (x*scale, y*scale, z + depth));
        verts.Add(new Vector3 (x*scale, y*scale, z));
        verts.Add(new Vector3 (x*scale, (y - 1)*scale, z));

        Cube (text);
    }
    void CubeEast(int x, int y,float z, Vector2 text)
    {
        verts.Add(new Vector3 ((x + 1)*scale, (y - 1)*scale, z));
        verts.Add(new Vector3 ((x + 1)*scale, y*scale, z));
        verts.Add(new Vector3 ((x + 1)*scale, y*scale, z + depth));
        verts.Add(new Vector3 ((x + 1)*scale, (y - 1)*scale, z + depth));

        Cube (text);
    }

    void Cube (Vector2 text) 
    {       
        tris.Add(squareCount*4);
        tris.Add((squareCount*4)+1);
        tris.Add((squareCount*4)+3);
        tris.Add((squareCount*4)+1);
        tris.Add((squareCount*4)+2);
        tris.Add((squareCount*4)+3);

        UV.Add( new Vector2(text.x*pixelSizeX,text.y*pixelSizeY) +new Vector2(pixelSizeX/2,pixelSizeY/2 ));
        UV.Add( new Vector2(text.x*pixelSizeX,text.y*pixelSizeY) +new Vector2(pixelSizeX/2,pixelSizeY/2 ));
        UV.Add( new Vector2(text.x*pixelSizeX,text.y*pixelSizeY) +new Vector2(pixelSizeX/2,pixelSizeY/2 ));
        UV.Add( new Vector2(text.x*pixelSizeX,text.y*pixelSizeY) +new Vector2(pixelSizeX/2,pixelSizeY/2 ));

        squareCount++; // Add this line
    }

    void UpdateMesh (Mesh m) 
    {
        m.Clear ();
        m.vertices = verts.ToArray();
        m.triangles = tris.ToArray();
        m.uv = UV.ToArray();
        ;
        m.RecalculateNormals ();

        squareCount=0;
        verts.Clear();
        tris.Clear();
        UV.Clear(); }

}

And then finally here is the renderer class

using UnityEngine;
using System.Collections;

public class SpriteMeshRenderer : MonoBehaviour
{
    SpriteMesh spr;
    public Texture2D texture;

    public float scale;

    // Use this for initialization
    void Start () 
    {
        spr = new SpriteMesh(texture);
        GenerateSpriteMesh();
    }

    void GenerateSpriteMesh()
    {
        spr.scale=scale/10;
        spr.depth=0.04f;
        GetComponent<MeshFilter>().mesh=spr.depthMesh(new Vector2(0,0), new Vector2(texture.width,texture.height));
        GetComponent<MeshRenderer>().material.mainTexture=texture;
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.