How to script a repeating environment texture

Hey Guys,

I’m working on a top-down 2.5D space combat game that has the player ship in the center of the screen, and the camera follows it as it moves around through the bigger environment.

It’s a big enough environment that having a massive quad with an even more massive texture is not even close to being an option.

What I’m trying to do is to have the background texture (a grid, to track movement) that repeats. But instead of having this texture repeating across the entire environment at the same time, I want to have a 3x3 set of texture squares, with the player ship in the center. As the player ship moves from one square to another, squares are destroyed and spawned as needed to keep the player ship occupying the center square, providing the illusion of a continuous grid.

I’ve been wracking my brain trying to figure out how to write a C# script that would do this, but cannot figure it out.

There is a Youtube 1 in which the person does something similar with terrain squares, but he only provides the script with no explanation on how it works and no comment lines in the code. I’ve been trying to figure out how it works, but with very little knowledge of C#, I’ve not yet had any success in doing so.

If anyone is familiar with this type of technique and can help me to understand it, or at least point me to a tutorial (which I can not find), I would really appreciate it.

Thanks in advance.

Why not just use a quad and scroll the UVs ?

UVs are clamped between a value of 0 and 1, but you can still set a UV value to a higher value and it will wrap around the Texture to the other side. So you might be able to get away with generating your 3x3 square by increasing the UV values dynamically. You wouldn’t even need to create and destroy your quads. You could probably even do it in the shader if you were savvy enough. Just normalize your movement vector into the applicable UV translation and add it to the x and y coords in the shader program. (Maybe, that last bit is speculation. I’ve never done this fyi)

Does it need to work in any direction or just forward and backward?

So as far as dynamically updating the UVs goes, this works fairly well:

1)Create an empty GameObject and add this script to it.
using UnityEngine;
using System.Collections;

public class ShipMovement : MonoBehaviour {

    public float movementSpeed = 1f;
	
	void FixedUpdate () {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        MovementManagement(h, v);
	}

    void MovementManagement(float h, float v)
    {
        Vector3 targetDirection = new Vector3(h, 0, v);
        targetDirection.Normalize();
        Move(targetDirection);
    }

    void Move(Vector3 targetDirection)
    {
        transform.position += targetDirection * movementSpeed * Time.deltaTime;
    }
}
  1. Add your ship and your scene camera to that empty as children.

  2. Create another empty, add a MeshFilter and a Mesh Renderer to it, then attach this script - (I adapted an answer from another of my posts)

    using UnityEngine;

    [RequireComponent(typeof(MeshFilter))]
    [RequireComponent(typeof(MeshRenderer))]

    public class DynamicSquare : MonoBehaviour
    {

     private Vector3[] vertices;
     private int[] triangles;
     private Vector2[] uv; // if you want to add uv coordinates
     private Vector3[] normals;
     void Awake()
     {
    
         /* The vertex indicies look like this, with these triangles
          *         3 ------ 0
          *           |   /|
          *           |  / |
          *           | /  |
          *           |/   |
          *         2 ------ 1
          */
    
         // the 4 vertices making up our square counterclock-wise from top right
         vertices = new Vector3[4];
         vertices[0] = new Vector3(1, 1, 0);
         vertices[1] = new Vector3(1, 0, 0);
         vertices[2] = new Vector3(0, 0, 0);
         vertices[3] = new Vector3(0, 1, 0);
    
         // list of index locations for the vertices making up each triangle
         triangles = new int[6];
    
         triangles[0] = 0;
         triangles[1] = 1;
         triangles[2] = 2;
    
         triangles[3] = 0;
         triangles[4] = 2;
         triangles[5] = 3;
    
         // list of UV coordinates for the corners, again counter clockwise from the top right
         uv = new Vector2[4];
         uv[0] = new Vector2(1, 1);
         uv[1] = new Vector2(1, 0);
         uv[2] = new Vector2(0, 0);
         uv[3] = new Vector2(0, 1);
    
         // list of normals for the verts
         normals = new Vector3[4];
         for(int i = 0; i < normals.Length; i++)
         {
             normals *= Vector3.back;*
    

}

Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.uv = uv; //<-- If you want to create uvs to map to a texture
mesh.normals = normals;
mesh.name = “DynamicSquareMesh”;

GetComponent().mesh = mesh;
}
}
4) scale the first empty to about .1 .1 .1, and adjust the rotations on the second empty according to the image.
![alt text][1]
[1]: /storage/temp/38880-uvscrolltest.png
5) Create a simple Material and put your texture on it. Add the material to the second empty.
6) Also add this script to the second empty (all the magic happens here. You’ll need to drop the first empty into the public ‘ship’ variable once this script is in place)-
using UnityEngine;
using System.Collections;

public class MoveAndUpdateUVs : MonoBehaviour {

public Transform ship;
private Vector3 lastShipPos;
private Mesh mesh;

void Start()
{
lastShipPos = ship.position;
mesh = GetComponent().mesh;
}
void Update()
{
Vector3 pos = ship.position;
Vector2 shift = new Vector2(pos.x - lastShipPos.x, pos.z - lastShipPos.z);
lastShipPos = pos;

Vector2[] newUVs = mesh.uv;
for(int i = 0; i < newUVs.Length; i++)
{
newUVs += shift;
}

mesh.uv = newUVs;
}
}

optional) I added a point light to the bow of my primitive ship. If you use unlit materials you won’t need to obviously.