0
\$\begingroup\$

I'm a web developer with over 12 years of experience and I'm moving my first steps in game development in the latest days. Specifically I'm playing with Unity and trying to understand how it works and how can I realize a 2d platform game. Currently I created a character that can be controlled with the keyboard (it moves to right, left and can jump), so far it seems more easy than I was expecting and despite I never used C# before I'm already quite comfortable. My first big concerning is about sprites and how can I create combined sprites or use an image as a repeated background. For example, let's imagine that I have a png of a brick and that I want to use it to create a wall, that can be of a variable width and height. How can I achieve that? With html/css I would simply create a class like this:

.wall {
    background: url(brick.png);
}

and by applying that class to any html element it will render a repeated background by adapting it to its container no matter how large or tall is it. In unity/C# what should I do?

So far I tried to create a new material and applied it to a cube object but the result is that the image gets stretched and sucks. I saw some example that creates N sprites programmatically by adding them one after another, but I wonder about the performance implications of this technique... for example if I have to repeat the brick 100 times I have to create 100 objects, it seems unfeasible to me! What I want to achieve is the most flexible, simple and performant way to create "shapes" with repeated background.

\$\endgroup\$
1
\$\begingroup\$

So, I've recently done something along these lines and I'll put this here for future use.

This is the object I use for this effect:

enter image description here

Here's the script that modifies the object:

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

public class SlidingSpriteBackground : MonoBehaviour
{
    public Sprite[] backgrounds;
    public RawImage backgroundRenderer;
    public float repeat = 3;
    public float slidingSpeedX = .2f, slidingSpeedY = -.2f;
    float moveByX, moveByY;
    Resolution res;
    Sprite useThis;
    float horizontalTiles, verticalTiles;
    int vTiles, hTiles;
    // Use this for initialization
    void Start()
    {
        res = Screen.currentResolution;
//this script uses a random background, you can set any kind of texture here
        System.Random rnd = new System.Random(System.DateTime.Now.Minute);
        useThis = backgrounds[rnd.Next(0, backgrounds.Length)]; 
//this part calculates the screen's size vs texture's size, 
//so that you don't have to think about it
        horizontalTiles = (float)Screen.width / (float)(useThis.texture.width); 
        verticalTiles = (float)Screen.height / (float)(useThis.texture.height);
//adds in the repeat amount you want in there
        verticalTiles = verticalTiles * repeat; 
        horizontalTiles = horizontalTiles * repeat;
        backgroundRenderer.texture = useThis.texture;
        Rect uvRect = new Rect(0, 0, horizontalTiles, verticalTiles);
        backgroundRenderer.uvRect = uvRect;

    }

    // Update is called once per frame
    void Update()
    {
//moves the sprite over time. if you want this to move with the player,
//you'll need to get the player location and move it according to that.
//(it should be relatively easy, but it'll take time to implement).
            moveByX = moveByX + slidingSpeedX * Time.unscaledDeltaTime; 
            moveByY = moveByY + slidingSpeedY * Time.unscaledDeltaTime;
            backgroundRenderer.uvRect = new Rect(moveByX, moveByY, horizontalTiles, verticalTiles);
//check if the screen size changed and recalculate
            if (res.height != Screen.currentResolution.height 
            || res.width != Screen.currentResolution.width)
            {
                horizontalTiles = (float)Screen.width / (float)(useThis.texture.width);
                verticalTiles = (float)Screen.height / (float)(useThis.texture.height);
                verticalTiles = verticalTiles * repeat;
                backgroundRenderer.texture = useThis.texture;
                horizontalTiles = horizontalTiles * repeat;
            }
    }
}

And here's what it looks like in effect (unfortunately I can't upload anything bigger because it goes over the 2MB limit):

enter image description here

\$\endgroup\$
-2
\$\begingroup\$

As far as I understand your problem, you can try the following.

  1. Firstly, depending on the screen resolution, you have to scale the background object so that it occupies the entire space. This can be done using the something like the following code.

    newWidth = Screen.width / textureSize; newHeight = Screen.height / textureSize; transform.localScale = new Vector3(newWidth * textureSize, newHeight * textureSize, 1);

The variable textureSize is the size of your sprite.

  1. Secondly, while applying the texture to the background object, you can add the tiling values so that the sprite is repeated instead of being stretched. This can be done using something like this.

    GetComponent().material.mainTextureScale = new Vector3(newWidth, newHeight, 1);

I hope this helps you.

\$\endgroup\$
  • \$\begingroup\$ mmm I think you get it wrong, I don't want a background for my scene, but instead I want to be able to create elements (like platforms you can jump on) with a repeated background... forgive me if I've been not clear, perhaps I'm using terms improperly since game development is not my field :P \$\endgroup\$ – daveoncode Jun 8 '16 at 9:30
  • \$\begingroup\$ I am guessing that you don't have any problem with the creation of the new objects. Its just the repeated sprite part that is an issue. Right? In that case you can try the same approach as I mentioned in my answer to apply the sprite but instead of using the variables Screen. width and Screen.height, you can use the dimensions of your objects to find the tiling values newWidth, newHeight. \$\endgroup\$ – greenPadawan Jun 9 '16 at 7:16
  • \$\begingroup\$ Yep, it's right \$\endgroup\$ – daveoncode Jun 9 '16 at 7:18
  • \$\begingroup\$ Please have a look at the updated comment. \$\endgroup\$ – greenPadawan Jun 9 '16 at 11:08
  • 1
    \$\begingroup\$ There are a couple of problems with this answer: 1. Unity doesn't support arbitrary texture scale & offset parameters on SpriteRenderers (it doesn't play nicely with the texture atlasing it's doing under the hood to save batches), but you can switch to quads with MeshRenderers to fix this. 2. Setting renderer.material will copy the material, so you'll end up creating unique materials for every object with this script, making them difficult to batch together and possibly leaking materials when these objects are destroyed (Unity doesn't clean up unused materials as readily as other garbage) \$\endgroup\$ – DMGregory Aug 12 '16 at 11:38

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.