- Home /
How to make 2d sprite tiled?
I have a grass sprite, I want to scale gameobject using this sprite and tile the texture. What is the right way to do this? There're texture offset and scale in material properties for the common renderer, but I can't find any similar for 2d.2d,
In texture properties, do you have the wrap mode set to 'repeat'?
@kihu, presumably $$anonymous$$astobaev is using a Texture Type of Sprite and thus there is no "Wrap $$anonymous$$ode". I am stuck with the same question. The Unity 2D Toolkit (3rd party package) supports this right out of the box, allowing you to scale a sprite and have it tile automatically.
Think you will need to use a quad for that. Create Gameobject -> Quad
Answer by Ash-Blue · Jul 23, 2014 at 04:24 PM
To create a 2D repeating sprite, you just need to take a stretched SpriteRenderer and tile it at the unstretched size as a child. No need to create a bunch of messy textures and additional elements beyond a SpriteRenderer and some scripting magic.
EDIT: I've written a Unity parallaxing library that takes care of this and supports the x and/or y axis for repeated elements. Library can be found here on GitHub https://github.com/ashblue/unity-2d-parallax/tree/develop
using UnityEngine;
using System.Collections;
// @NOTE the attached sprite's position should be "top left" or the children will not align properly
// Strech out the image as you need in the sprite render, the following script will auto-correct it when rendered in the game
[RequireComponent (typeof (SpriteRenderer))]
// Generates a nice set of repeated sprites inside a streched sprite renderer
// @NOTE Vertical only, you can easily expand this to horizontal with a little tweaking
public class RepeatSpriteBoundary : MonoBehaviour {
SpriteRenderer sprite;
void Awake () {
// Get the current sprite with an unscaled size
sprite = GetComponent<SpriteRenderer>();
Vector2 spriteSize = new Vector2(sprite.bounds.size.x / transform.localScale.x, sprite.bounds.size.y / transform.localScale.y);
// Generate a child prefab of the sprite renderer
GameObject childPrefab = new GameObject();
SpriteRenderer childSprite = childPrefab.AddComponent<SpriteRenderer>();
childPrefab.transform.position = transform.position;
childSprite.sprite = sprite.sprite;
// Loop through and spit out repeated tiles
GameObject child;
for (int i = 1, l = (int)Mathf.Round(sprite.bounds.size.y); i < l; i++) {
child = Instantiate(childPrefab) as GameObject;
child.transform.position = transform.position - (new Vector3(0, spriteSize.y, 0) * i);
child.transform.parent = transform;
}
// Set the parent last on the prefab to prevent transform displacement
childPrefab.transform.parent = transform;
// Disable the currently existing sprite component since its now a repeated image
sprite.enabled = false;
}
}
I tried your script and works, repeated sprite, but how can I do to do move offset from material ?
I'm trying add material in sprite repeat, but doesn't works.
To move offset I did this.
public class $$anonymous$$oveBackground : $$anonymous$$onoBehaviour {
private $$anonymous$$aterial current$$anonymous$$aterial;
public float speed;
private float offset;
// Use this for initialization
void Start()
{
current$$anonymous$$aterial = renderer.material;
}
// Update is called once per frame
void Update()
{
offset += 0.001f;
current$$anonymous$$aterial.SetTextureOffset("_$$anonymous$$ainTex", new Vector2(this.offset * this.speed, 0));
}
}
@ferpa Well this is meant for a SpriteRenderer, not too sure on how to get this working with a texture sadly :(
Answer by Linus · Feb 21, 2014 at 05:40 AM
As mentioned in my comment, I think best solution for now is to use a Quad.
See this other question for details: http://answers.unity3d.com/questions/587007/im-trying-to-create-a-tiled-sprite-what-am-i-doing.html
Another thing you could do is a tile map out of many sprites. This script is for a tile of 32px
#pragma strict
import System.Collections.Generic;
var mapSizeX : int;
var mapSizeY : int;
var tilePrefab : GameObject;
var tiles : List.<Transform> = new List.<Transform>();
function Start () {
var i : int = 0;
var xIndex : int = 0;
var yIndex : int = 0;
while(yIndex < mapSizeY){
xIndex = 0;
while(xIndex < mapSizeX){
var newTile : GameObject = Instantiate (tilePrefab, Vector3(xIndex*0.32, yIndex*0.32, 0), Quaternion.identity);
tiles.Add(newTile.transform);
newTile.transform.parent = transform;
newTile.transform.name = "tile_"+i;
i++;
xIndex++;
}
yIndex++;
}
}
Answer by XOR-Gaming · Feb 04, 2015 at 04:40 PM
Adapted from abeldantas This exposes public variables that allow you to specify how many tiles you want on a grid, instead of having to modify the original source sprite/texture.
using UnityEngine;
using System.Collections;
// @NOTE the attached sprite's position should be "Top Right" or the children will not align properly
// Strech out the image as you need in the sprite render, the following script will auto-correct it when rendered in the game
[RequireComponent (typeof (SpriteRenderer))]
// Generates a nice set of repeated sprites inside a streched sprite renderer
// @NOTE Vertical only, you can easily expand this to horizontal with a little tweaking
public class RepeatSpriteBoundary : MonoBehaviour {
public float gridX = 0.0f;
public float gridY = 0.0f;
SpriteRenderer sprite;
void Awake () {
sprite = GetComponent<SpriteRenderer>();
if(!GetSpriteAlignment(gameObject).Equals(SpriteAlignment.TopRight)){
Debug.LogError("You forgot change the sprite pivot to Top Right.");
}
Vector2 spriteSize_wu = new Vector2(sprite.bounds.size.x / transform.localScale.x, sprite.bounds.size.y / transform.localScale.y);
Vector3 scale = new Vector3(1.0f, 1.0f, 1.0f);
if (0.0f != gridX) {
float width_wu = sprite.bounds.size.x / gridX;
scale.x = width_wu / spriteSize_wu.x;
spriteSize_wu.x = width_wu;
}
if (0.0f != gridY) {
float height_wu = sprite.bounds.size.y / gridY;
scale.y = height_wu / spriteSize_wu.y;
spriteSize_wu.y = height_wu;
}
GameObject childPrefab = new GameObject();
SpriteRenderer childSprite = childPrefab.AddComponent<SpriteRenderer>();
childPrefab.transform.position = transform.position;
childSprite.sprite = sprite.sprite;
GameObject child;
for (int i = 0, h = (int)Mathf.Round(sprite.bounds.size.y); i*spriteSize_wu.y < h; i++) {
for (int j = 0, w = (int)Mathf.Round(sprite.bounds.size.x); j*spriteSize_wu.x < w; j++) {
child = Instantiate(childPrefab) as GameObject;
child.transform.position = transform.position - (new Vector3(spriteSize_wu.x*j, spriteSize_wu.y*i, 0));
child.transform.localScale = scale;
child.transform.parent = transform;
}
}
Destroy(childPrefab);
sprite.enabled = false; // Disable this SpriteRenderer and let the prefab children render themselves
}
}
Answer by abeldantas · Dec 02, 2014 at 05:04 AM
Adapted from Ash Blue
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (SpriteRenderer))]
public class RepeatSpriteBoundary : MonoBehaviour {
SpriteRenderer sprite;
void Awake () {
sprite = GetComponent<SpriteRenderer>();
if(!SpritePivotAlignment.GetSpriteAlignment(gameObject).Equals(SpriteAlignment.TopRight)){
Debug.LogError("You forgot change the sprite pivot to Top Right.");
}
Vector2 spriteSize = new Vector2(sprite.bounds.size.x / transform.localScale.x, sprite.bounds.size.y / transform.localScale.y);
GameObject childPrefab = new GameObject();
SpriteRenderer childSprite = childPrefab.AddComponent<SpriteRenderer>();
childPrefab.transform.position = transform.position;
childSprite.sprite = sprite.sprite;
GameObject child;
for (int i = 0, h = (int)Mathf.Round(sprite.bounds.size.y); i*spriteSize.y < h; i++) {
for (int j = 0, w = (int)Mathf.Round(sprite.bounds.size.x); j*spriteSize.x < w; j++) {
child = Instantiate(childPrefab) as GameObject;
child.transform.position = transform.position - (new Vector3(spriteSize.x*j, spriteSize.y*i, 0));
child.transform.parent = transform;
}
}
Destroy(childPrefab);
sprite.enabled = false;
}
}
I use this for determining the pivot of the sprite
using UnityEngine;
using System.Collections;
public static class SpritePivotAlignment {
public static SpriteAlignment GetSpriteAlignment(GameObject SpriteObject){
BoxCollider2D MyBoxCollider= SpriteObject.AddComponent<BoxCollider2D> ();
float colX = MyBoxCollider.center.x;
float colY = MyBoxCollider.center.y;
if (colX > 0f && colY < 0f)
return (SpriteAlignment.TopLeft);
else if (colX < 0 && colY < 0)
return (SpriteAlignment.TopRight);
else if (colX == 0 && colY < 0)
return (SpriteAlignment.TopCenter);
else if (colX > 0 && colY == 0)
return (SpriteAlignment.LeftCenter);
else if (colX < 0 && colY == 0)
return (SpriteAlignment.RightCenter);
else if (colX > 0 && colY > 0)
return (SpriteAlignment.BottomLeft);
else if (colX < 0 && colY > 0)
return (SpriteAlignment.BottomRight);
else if (colX == 0 && colY > 0)
return (SpriteAlignment.BottomCenter);
else if (colX == 0 && colY == 0)
return (SpriteAlignment.Center);
else
return (SpriteAlignment.Custom);
}
}
Add this after line 19 to pull across the correct sorting:
childSprite.sortingLayerID = sprite.sortingLayerID;
childSprite.sortingOrder = sprite.sortingOrder;
Answer by peterjp80 · Nov 17, 2016 at 07:19 AM
You can use a quad combined with a script, so that multiple quads using the same material can repeat the sprite differently.
On your sprite, set Texture Type to "Texture" and Wrap Mode to "Repeat"
Create a new material and set the Shader to "Particles / Alpha Blended"
Select your sprite as the Texture
Create a Quad and size as needed
Assign the new material you created to the Quad
Create a new C# Script named SetTiles then assign the new script to the Quad
using UnityEngine;
[RequireComponent(typeof(MeshRenderer))] public class SetTiles : MonoBehaviour { public Vector2 tiling;
void Start () { GetComponent<MeshRenderer>().material.mainTextureScale = tiling; } }