# Question
Title: Tile manipulation script doesn't work in build but works in editor
I have 100 cubes which makes a plane, and I have a script that moves those cubes in random patterns according to random chosen methods.

For example, in the method `LeftPartFalls`, only the cubes on the left part of the plane change materials, then fall down, then change materials again, then rise back up.

In the other methods I do the same actions but in the different patterns like:

* only the right part falls
* only the first, second, third, fourth and fifth lines fall

This all works fine when I test it in the Unity editor.

But when I build it for Android, it does the changing color and falling down things but not in the pattern that I wanted. Instead I get a kind of mosaic pattern, and I noticed it does that it does this in 2 random-looking mosaic patterns. For example, the first might look like this:

And after the cubes that are low in that screenshot rise back up, the pattern reverses, with the cubes that were high taking their turn to fall. And then the cycle repeats.

Why is this behaviour different on Android than in editor, and how can I fix it?

---

This is one of my methods to make a pattern of cubes change colour, fall, and rise:

```
void LeftPartFalls()
{
    if (LeftPartMat)
    {
        for (int i = 0; i < Mathf.Min(5, FirstLine.Length); i++)        // COLOR CHANGE
        {
            FirstLine[i].gameObject.GetComponent<MeshRenderer>().material = greyMAT;
            SecondLine[i].gameObject.GetComponent<MeshRenderer>().material = greyMAT;
            ThirdLine[i].gameObject.GetComponent<MeshRenderer>().material = greyMAT;
            FourthLine[i].gameObject.GetComponent<MeshRenderer>().material = greyMAT;
            FiftLine[i].gameObject.GetComponent<MeshRenderer>().material = greyMAT;
            SixthLine[i].gameObject.GetComponent<MeshRenderer>().material = greyMAT;
            SeventhLine[i].gameObject.GetComponent<MeshRenderer>().material = greyMAT;
            EighthLine[i].gameObject.GetComponent<MeshRenderer>().material = greyMAT;
            NinthLine[i].gameObject.GetComponent<MeshRenderer>().material = greyMAT;
            TenthLine[i].gameObject.GetComponent<MeshRenderer>().material = greyMAT;
        }
    }
    if (!LeftPartMat)
    {
        for (int i = 0; i < Mathf.Min(5, FirstLine.Length); i++)        // COLOR CHANGE 2
        {
            FirstLine[i].gameObject.GetComponent<MeshRenderer>().material = whiteMAT;
            SecondLine[i].gameObject.GetComponent<MeshRenderer>().material = whiteMAT;
            ThirdLine[i].gameObject.GetComponent<MeshRenderer>().material = whiteMAT;
            FourthLine[i].gameObject.GetComponent<MeshRenderer>().material = whiteMAT;
            FiftLine[i].gameObject.GetComponent<MeshRenderer>().material = whiteMAT;
            SixthLine[i].gameObject.GetComponent<MeshRenderer>().material = whiteMAT;
            SeventhLine[i].gameObject.GetComponent<MeshRenderer>().material = whiteMAT;
            EighthLine[i].gameObject.GetComponent<MeshRenderer>().material = whiteMAT;
            NinthLine[i].gameObject.GetComponent<MeshRenderer>().material = whiteMAT;
            TenthLine[i].gameObject.GetComponent<MeshRenderer>().material = whiteMAT;
        }
    }

    if (LeftPartFall)       // FALL DOWN
    {
        for (int i = 0; i < Mathf.Min(5, FirstLine.Length); i++)
        {
            FirstLine[i].gameObject.transform.position = Vector3.Lerp(FirstLine[i].transform.position, new Vector3(FirstLine[i].transform.position.x, -4f, FirstLine[i].transform.position.z), t);
            SecondLine[i].gameObject.transform.position = Vector3.Lerp(SecondLine[i].transform.position, new Vector3(SecondLine[i].transform.position.x, -4f, SecondLine[i].transform.position.z), t);
            ThirdLine[i].gameObject.transform.position = Vector3.Lerp(ThirdLine[i].transform.position, new Vector3(ThirdLine[i].transform.position.x, -4f, ThirdLine[i].transform.position.z), t);
            FourthLine[i].gameObject.transform.position = Vector3.Lerp(FourthLine[i].transform.position, new Vector3(FourthLine[i].transform.position.x, -4f, FourthLine[i].transform.position.z), t);
            FiftLine[i].gameObject.transform.position = Vector3.Lerp(FiftLine[i].transform.position, new Vector3(FiftLine[i].transform.position.x, -4f, FiftLine[i].transform.position.z), t);
            SixthLine[i].gameObject.transform.position = Vector3.Lerp(SixthLine[i].transform.position, new Vector3(SixthLine[i].transform.position.x, -4f, SixthLine[i].transform.position.z), t);
            SeventhLine[i].gameObject.transform.position = Vector3.Lerp(SeventhLine[i].transform.position, new Vector3(SeventhLine[i].transform.position.x, -4f, SeventhLine[i].transform.position.z), t);
            EighthLine[i].gameObject.transform.position = Vector3.Lerp(EighthLine[i].transform.position, new Vector3(EighthLine[i].transform.position.x, -4f, EighthLine[i].transform.position.z), t);
            NinthLine[i].gameObject.transform.position = Vector3.Lerp(NinthLine[i].transform.position, new Vector3(NinthLine[i].transform.position.x, -4f, NinthLine[i].transform.position.z), t);
            TenthLine[i].gameObject.transform.position = Vector3.Lerp(TenthLine[i].transform.position, new Vector3(TenthLine[i].transform.position.x, -4f, TenthLine[i].transform.position.z), t);
        }
    }
    if (!LeftPartFall)      // RISE UP
    {
        for (int i = 0; i < Mathf.Min(5, FirstLine.Length); i++)
        {
            FirstLine[i].gameObject.transform.position = Vector3.Lerp(FirstLine[i].transform.position, new Vector3(FirstLine[i].transform.position.x, 0f, FirstLine[i].transform.position.z), t);
            SecondLine[i].gameObject.transform.position = Vector3.Lerp(SecondLine[i].transform.position, new Vector3(SecondLine[i].transform.position.x, 0f, SecondLine[i].transform.position.z), t);
            ThirdLine[i].gameObject.transform.position = Vector3.Lerp(ThirdLine[i].transform.position, new Vector3(ThirdLine[i].transform.position.x, 0f, ThirdLine[i].transform.position.z), t);
            FourthLine[i].gameObject.transform.position = Vector3.Lerp(FourthLine[i].transform.position, new Vector3(FourthLine[i].transform.position.x, 0f, FourthLine[i].transform.position.z), t);
            FiftLine[i].gameObject.transform.position = Vector3.Lerp(FiftLine[i].transform.position, new Vector3(FiftLine[i].transform.position.x, 0f, FiftLine[i].transform.position.z), t);
            SixthLine[i].gameObject.transform.position = Vector3.Lerp(SixthLine[i].transform.position, new Vector3(SixthLine[i].transform.position.x, 0f, SixthLine[i].transform.position.z), t);
            SeventhLine[i].gameObject.transform.position = Vector3.Lerp(SeventhLine[i].transform.position, new Vector3(SeventhLine[i].transform.position.x, 0f, SeventhLine[i].transform.position.z), t);
            EighthLine[i].gameObject.transform.position = Vector3.Lerp(EighthLine[i].transform.position, new Vector3(EighthLine[i].transform.position.x, 0f, EighthLine[i].transform.position.z), t);
            NinthLine[i].gameObject.transform.position = Vector3.Lerp(NinthLine[i].transform.position, new Vector3(NinthLine[i].transform.position.x, 0f, NinthLine[i].transform.position.z), t);
            TenthLine[i].gameObject.transform.position = Vector3.Lerp(TenthLine[i].transform.position, new Vector3(TenthLine[i].transform.position.x, 0f, TenthLine[i].transform.position.z), t);
        }
    }
}

```

This is the enumerator part, that chooses the random method:

```
private IEnumerator enumerator(float waitTime)
{
    while (true)
    {
        RandomInt = Random.Range(1, 6);
        if (RandomInt == 1)
        {
            LeftPartCalls = true;
            LeftPartMat = true;
        }
        if (RandomInt == 2)
        {
            RightPartCalls = true;
            RightPartMat = true;
        }
        if (RandomInt == 3)
        {
            VerticalStripeCalls = true;
            VerticalStripeMat = true;
        }
        if (RandomInt == 4)
        {
            UpLeftDownRightCalls = true;
            UpLeftDownRightMat = true;
        }
        if (RandomInt == 5)
        {
            UpRightDownLeftCalls = true;
            UpRightDownLeftMat = true;
        }
        if (RandomInt == 6)
        {
            HorizontalStripeCalls = true;
            HorizontalStripeMat = true;
        }
        if (RandomInt == 7)
        {
            CenterCalls = true;
            CenterMat = true;
        }
        if (RandomInt == 8)
        {
            EdgeCalls = true;
            EdgeMat = true;
        }
        if (RandomInt == 9)
        {
            SkewCalls = true;
            SkewMat = true;
        }
        if (RandomInt == 10)
        {
            HorizontalWayCalls = true;
            HorizontalWayMat = true;
        }

        yield return new WaitForSeconds(MoveT);
        if (RandomInt == 1)
            LeftPartFall = true;
        if (RandomInt == 2)
            RightPartFall = true;
        if (RandomInt == 3)
            VerticalStripeFall = true;
        if (RandomInt == 4)
            UpLeftDownRightFall = true;
        if (RandomInt == 5)
            UpRightDownLeftFall = true;
        if (RandomInt == 6)
            HorizontalStripeFall = true;
        if (RandomInt == 7)
            CenterFall = true;
        if (RandomInt == 8)
            EdgeFall = true;
        if (RandomInt == 9)
            SkewFall = true;
        if (RandomInt == 10)
            HorizontalWayFall= true;

        t = 0f;
        t += Time.deltaTime / 0.7f;

        yield return new WaitForSeconds(3);
        LeftPartFall = false;
        LeftPartMat = false;
        RightPartMat = false;
        RightPartFall = false;
        VerticalStripeMat = false;
        VerticalStripeFall = false;
        UpLeftDownRightFall = false;
        UpLeftDownRightMat = false;
        UpRightDownLeftFall = false;
        UpRightDownLeftMat = false;
        HorizontalStripeFall = false;
        HorizontalStripeMat = false;
        CenterFall = false;
        CenterMat = false;
        EdgeFall = false;
        EdgeMat = false;
        SkewFall = false;
        SkewMat = false;
        HorizontalWayFall = false;
        HorizontalWayMat = false;
        yield return new WaitForSeconds(4);
        LeftPartCalls = false;
        RightPartCalls = false;
        VerticalStripeCalls = false;
        UpLeftDownRightCalls = false;
        UpRightDownLeftCalls = false;
        HorizontalStripeCalls = false;
        CenterCalls = false;
        EdgeCalls = false;
        SkewCalls = false;
        HorizontalWayCalls = false;

        if (MoveT >= 1.3f)
        {
            MoveT -= 0.7f;
        }
        if (MoveT <= 1.3f)
        {
            MoveT -= 0.6f;
        }
        if (MoveT <= 0.7f)
        {
            MoveT = 0.7f;
        }
        yield return new WaitForSeconds(MoveT);
    }
}

```

# Answer
> 0 votes
It still doesn't look like we have enough information here to identify why your game behaves differently on Android, but I'd like to recommend we start with a clean slate to hopefully make the code simpler to understand, more concise, with less room for bugs to creep in. I'll build this up in pieces so it's easier to follow:

First, let's generate your plane of cubes by script, and store it in a 2D array so we don't need to juggle ten different variables to store all the lines:

```
public class FallingFloor : MonoBehaviour {

    public Vector2Int size = new Vector2Int(10, 10);
    public float spacing = 1f;
    public MeshRenderer tilePrefab;
    MeshRenderer[,] tiles;

    void CreateFloor() {
        // Define our tiles array in the appropriate size.
        tiles = new MeshRenderer[size.x, size.y];

        // Spawn the floor centered around this object's position.
        Vector3 origin = transform.position + new Vector3(size.x, 0, size.y) * -0.5f * spacing;

        // For each row, and each column, instantiate a tile.
        for(int x = 0; x < size.x; x++) {
            for(int y = 0; y < size.y; y++) {
                tiles[x, y] = Instantiate<MeshRenderer>(
                                   tilePrefab,
                                   new Vector3(x, 0, y) * spacing + origin,
                                   Quaternion.identity
                              );
            }
        }
    }

// ...

```

With all the tiles in one variable, it's easy to define functions that select different patterns of tiles. Let's follow the convention that our tile selection functions will populate a list with the desired tiles:

```
void SelectLeftHalf(List<MeshRenderer> pattern) {
    pattern.Clear();
    for(int x = 0; x < size.x/2; x++) {
        for(int y = 0; y < size.y; y++) {
            pattern.Add(tiles[x, y]);
        }
    }
}

void SelectEverySecondRow(List<MeshRenderer> pattern) {
    pattern.Clear();
    for(int x = 0; x < size.x; x++) {
        for(int y = 0; y < size.y; y += 2) {
            pattern.Add(tiles[x, y]);
        }
    }
}

void SelectCross(List<MeshRenderer> pattern) {
    pattern.Clear();
    // Make sure we don't go out of bounds on non-square maps.
    int limit = Mathf.Min(size.x, size.y);
    for(int x = 0; x < limit; x++) {
        pattern.Add(tiles[x, x]);
        int y = size.y - 1 - x;
        // Don't double-add the middle tile in the case of odd sizes.
        if(x != y)
            pattern.Add(tiles[x, y]);
    }
}

// ...

```

Now we can simplify the falling and colour-changing animations to single functions each that act on a selected pattern of tiles:

```
void ChangeAllMaterials(List<MeshRenderer> pattern, Material material) {
    foreach(var renderer in pattern)
        renderer.sharedMaterial = material;
}

IEnumerator SlideAllBlocks(List<MeshRenderer> pattern, float startHeight, float endHeight, float duration) {
    float progress = 0f;
    while(progress < 1f) {
        progress = Mathf.Clamp01(progress + Time.deltaTime/duration);

        // Compute a height to move to, with an ease-out curve.
        float height = Mathf.Lerp(startHeight, endHeight, 1 - (1 - progress) * (1 - progress));

        // Set all blocks in the pattern to this height.
        foreach(var renderer in pattern) {
            var position = renderer.transform.position;
            position.y = height;
            renderer.transform.position = position;
        }

        // Wait one frame, then resume.
        yield return null;
    }
}

// ...

```

And our master loop can then just select a pattern, call these functions on it in our desired sequence, and repeat:

```
public Material fallingMaterial;
public Material risingMaterial;
public float fallSeconds = 3f;
public float fallHeight = -4f;
public float riseSeconds = 4f;

IEnumerator AnimationLoop(float moveSeconds) {
    // Prep our variable for tracking the pattern of tiles we're acting on.
    // Since this is a local variable, we can control exactly who gets to act on it,
    // so anything that changes the pattern should be easy to track down.
    var pattern = new List<MeshRenderer>();

    while(true) {
        // Each cycle, select a randomly-chosen pattern of blocks.
        int selection = Random.Range(1, 6);

        switch(selection) {
            case 1 : SelectLeftHalf(pattern); break;
            case 2 : SelectRightHalf(pattern); break;
            case 3 : SelectEverySecondRow(pattern); break;
            case 4 : SelectEverySecondColumn(pattern); break;
            case 5 : SelectCross(pattern); break;
        }

        // Change the material of all blocks in this pattern.
        ChangeAllMaterials(pattern, fallingMaterial);

        // Wait before we start to fall.
        yield return new WaitForSeconds(moveSeconds);

        // Chain control to our sliding method until the fall is complete.
        yield return SlideAllBlocks(pattern, 0, fallHeight, fallSeconds);

        // Done falling. Reset the materials and rise back up.
        ChangeAllMaterials(pattern, risingMaterial);

        // Chain control to our sliding method until the fall is complete.
        yield return SlideAllBlocks(pattern, fallHeight, 0f, riseSeconds);

        // Everything has risen and reset. Now adjust our moveSeconds for next cycle:
        if (moveSeconds >= 1.3f) {
            moveSeconds -= 0.7f;
        } else if (moveSeconds <= 1.3f) {
            moveSeconds = Mathf.Max(moveSeconds - 0.6f, 0.7f);
        }

        // Wait before starting the next cycle & choosing a new pattern.
        yield return new WaitForSeconds(moveSeconds);
     }
}

```

Now we don't need to rely on a small army of bool variables to coordinate all our actions. You should find an approach something like this makes your game behave more predictably, and makes it less laborious to add or change behaviour.

---
Tags: unity, c#, android
---


# Question
Title: Working hours and productivity expectations for game artists and programmers
I have a startup with a limited budget and have recently hired a programmer and an artist. Before they started the project, I set down a project roadmap with a lot of good documentation on what needs to be done and deadlines.

Both were asked to produce a timeline as to how these deadlines would be met. For the artist, I mentioned that if the workload was too much, it might be possible to hire an additional contractor for a month or two while they need help.

I have already started hearing things like, "well, I might need some extra help with this," and "I'm not exactly sure how long it will take me right now, so these timelines are just very rough estimates." And I get it, they're trying not to set themselves up for failure, but as a manager, I also need to know what the heck is going on.

So, there are two questions here:

* I frequently see both my hires using non-company Slack, answering phone messages, and doing life admin on my watch. They've turned up late more than once in the first week, when I have a company policy of being in at 9. Maybe this is unorthodox, but we're working on a big project, and the last thing I want is them turning around and accusing me of under-scoping the project. On the other hand, I realize that this might be the norm elsewhere, in larger companies. What can generally be expected from artists/programmers in terms of working style and productivity? What's the difference between flexibility and being lazy?
* My artist has already started to refuse other work (work for marketing assets, etc) on the basis that they have a lot of work on their plate already and need to manage expectations. I could deal with this if I didn't see them coming in late, answering messages on Slack, and generally doing things that don't relate to work. On the other hand, I don't know if this is normal/necessary for creatives. Is it?

---

If it can help:

* The studio is situated in Europe.
* I have no written policy, but working hours are contractual obligations.
* We're using agile project management.
* We are 3 people working on the project. Both are "leads" so they make decisions related to their own fields – art and code

# Answer
> 87 votes
**It's not unusual for workers to be less than 100% engaged in task work** for the entire duration of the work day. Humans have a hard time focusing on one task for longer than 20 minutes without some form of interruption.

Research suggests that, out of an 8-hour day, on average, workers are productive for *less than hal*f.

In fact, reducing the total hours worked in a week can *increase* productivity in some circumstances.

This isn't an argument for "anything goes" or making drastic changes to your office hours without further investigation. But, **a little variance in arrival times and some non-work activity occurring during work hours is not necessarily cause for alarm.**

Clamping down in a draconian way to try to eliminate non-work activity may well backfire, leading to unhappy and burnt-out workers who are less productive or outright quit.

Instead, **let your project milestones be your guide**. If your workers are meeting the schedule goals that were established early on, then you'd seem to be on track. Refusing work over and above the agreed-upon schedule is a reasonable thing for a worker to do, and not necessarily a sign of slacking. If you have more work than your scheduled bandwidth allows, try to incorporate this learning into planning for your next sprint/milestone/work unit, so you can prioritize the tasks or bring in additional helpers as needed.

If the project is falling behind schedule, that gives you a good, evidence-based way to raise the issue with your team, and **work with them to find solutions** to bring it back on track.

Studios I've worked at have for example instituted "focus afternoons" 2 days a week, in which we're requested to not schedule meetings, play videos in the background, or have conversations at desks where they might cause distractions, so everyone has a block of time they can count on to be uninterrupted.

Talk to your team about whether something like that might work for them, and **involve them in the decision-making**, so they feel like they're collaborators finding solutions together, not children being disciplined (nobody does their best work when they're feeling punished). Just knowing what's at stake and being empowered to help solve it may be enough to inspire your team to adjust their arrival times / focus to pick up the slack, if that's what's missing.

# Answer
> 21 votes
Good grief, reading this question stressed me out. You don't think your employees should be allowed to send personal messages and attend to their life during work hours? The top answer says it better than I will, but that's completely unrealistic. If you expect your employees to be focusing on their tasks 100% of the time, you're going to lose them.

Most businesses are open from 9 to 5, at least in America. It makes no sense, but it's the world we live in for some reason. That means that human beings who need to make appointments and deal with real life stuff are going to need to take care of it during work hours. If you offered flexible hours instead of insisting they come in at 9 (and presumably stay until all other businesses will be closed) then that would sort of be one thing (even then it's harsh), but demanding they stick to these rigid hours and then getting upset when they need to do people things is delusional.

Add on top of that that people have kids and family and situations at home, and you should be realizing that your expectations are insane. If you want to dedicate your entire life to work and sacrifice the meaningful portions such as relationships and health, that's your prerogative. But that's not a decision you should be making for your employees.

If you need to get more work done, you can hire more people. If that's not possible, you need to cut back on your expectations and goals for the project.

# Answer
> 18 votes
I think that strict working hours is generally not a good idea. For example I belong to these 20% of people who are much more productive at late hours. I worked in startups and big companies as well. I always had that talk with my managers about the late hours. After all I always told them, yes I can come to the office at 8am and be completely shut down until 2pm being almost useless... On the other hand, I always was completing my tasks on time and even before - I worked from 11am to 10pm because it was best for me - resulting in my own better productivity.

Also doing a little bit of own stuff (like answering couple of mails or even watching a YT video) is not a bad thing even contrary being a programmer, the job is intense and tedious. A human brain cant really work a full 9 hours straight; it needs little breaks - these breaks are actually much more productive than just sitting and staring at code - in these breaks I usually get the brightest ideas popping into my mind - that leads to good solutions for the problems. So I suppose everything is relative - of course it shouldn't be abused and the employees shouldn't watch YT all day long.

After all the best measurement of productivity is when you see if the employees are making their tasks in the given time (of course if the times are set correctly). I think the best way is to break the task into short time spans and check them once in a while - like once a week or once every 2 weeks or whatever makes more sense for you.

Taking all I said into consideration, if they are not meeting the deadlines consistently and not motivated enough to work on the project - then you have hired the wrong people and your best choice is to replace them with the people who will.

# Answer
> 16 votes
I think apart from the above mentioned views, I guess one has to take the region/country where the company is located. The culture has a major impact on these kind of stuffs too.

For example. I have worked in India, US and Currently in Germany. In India, People tend to come late everyday, I observed them to be less productive on first few hours after entering the office. They frequently use mobile phones and enjoy coffee breaks in Cafeteria. Having said that, they tend to form a strong bond among their colleagues.So, when it comes to work, They tend to finish it somehow to meet the deadlines.

Meanwhile in US, you can't restrict them or pressurize them to do a certain tasks. They feel responsible for the job no matter happens. In short, they don't like people bossing them around.

In Germany, things are completely different. They strictly follow "Work Hard and Party Hard" culture. Inside the office, they won't do anything related to their personal life. Even when having a chat with their colleagues, it will be about the work flow. They are extremely sincere. They care more about the quality than velocity. But I haven't seen them working after their required working hours in a week. No matter what happens they leave the office after the requested period.

Hope this point of view helps for you to analyse your Resources

# Answer
> 10 votes
# There are some red flags, but probably not the ones you expect

This

> I set down a project roadmap with a lot of good documentation on what needs to be done and deadlines.
>
> Both were asked to produce a timeline as to how these deadlines would be met. For the artist, I mentioned that if the workload was too much, it might be possible to hire an additional contractor for a month or two while they need help.
>
> I have already started hearing things like, "well, I might need some extra help with this," and "I'm not exactly sure how long it will take me right now, so these timelines are just very rough estimates." And I get it, they're trying not to set themselves up for failure, but as a manager, I also need to know what the heck is going on.

...sounds more like waterfall and less like Agile than you're probably aiming for. The point of Agile is to manage risk better by planning less up front, when you know far less about scope, schedule, and budget, and instead focus on continually adding value to the product and planning only as much as you need to at any given time. This lets you 1) always have a product that you can demo and maybe even sell; 2) always know the pace your team is working at; and 3) what you can reasonably accomplish in a given amount of time. As a result you can better respond to schedule hiccups and changing customer needs, both of which are important for a startup.

It sounds like your employees are doing Agile and you're unintentionally trying to force them back into waterfall. I'd recommend spending some more time learning about Agile, particularly with a focus on startups where I understand the risks are high and you want to avoid costly mistakes.

But if I were going to create a software startup I would 100% choose Agile over waterfall, because it would enable me to *be more agile* instead of blindly going over the waterfall because my employees didn't set expectations with me and instead kept taking on more work while promising to meet a deadline that had been set in stone months ago and that was not achievable. You don't want that.

**Bottom line: other than possibly the lateness issue, your employees are doing exactly what they should. You need to take a look at your management style; it seems to be the issue.**

# Answer
> 9 votes
Having managed several studios for a few of the large game companies, I could write you a large answer about productivity, etc but the problem is rarely there:

First, you can't expect people to sit 8 hours focused, it won't happen.

Flexibility is very important because if people can't deal with calling their bank, etc at the office, you will start to feel it very quickly. Unless there are some important deadlines, and the work is purely related to the time put in (as in no problem solving, no research, etc) you can't measure the work in hours and it's much better for employees to have flexible time, within reason.

In order to get people to be productive, forget time and focus on short measurable goals but also make sure they really understand, and share, the end goal. If they don't care about your project and are just contractors that want to collect their pay, your product will never be good.

People go into games because they're passionate about it, so you already don't have most of the problems you'd have with contractors in general. But you have to get them interested in your product and involved in building it, not treat them as extensions of your brain that will implement what you tell them. If there is no team feeling, productivity will be low, no matter the talent.

Another common thing in games is that your schedule is probably wrong; in almost 30 years in this field, only one team I was a part of (making the most popular soccer game) had a schedule that was realistic and made sense. It was an experienced team where people were used to work together. You have to constantly refine the direction with the team to see what can be done with the time / budget you have left, keeping in mind that there are always unknowns, etc popping up.

Almost all the time, productivity issues stem from management mistakes. Make sure the team likes the project, want to see it published, are contributing to it more than just coding and drawing, like it's theirs too, and that the goal makes sense at any moment.

# Answer
> 6 votes
A few things you need to know about creative types:

Programmers *love* being 100% engaged for hours at a time. This allows them to achieve deep flow. To gain the benefits of this, you need to provide a work environment absolutely free of distractions. Separate offices or remote is ideal. Cubicles are marginal. Open workspaces obliterate productivity. Something as simple as asking someone what time they're going to lunch can destroy half an hour of work.

Whether a developer is in deep flow or not, code quality drops off precipitously after about five hours of hard thinking. And sometimes that thinking may not look like work. I do some of my best programming with my eyes closed on the couch.

Read up on Scrum and other Agile methodologies. Set reasonable tasks and deadlines (which is a skill in itself that you'll need to hone as a team) and then let your developers decide how to meet those goals. Other than your daily standup, you don't need to synchronize your schedules at all. In fact, it's probably better if you don't.

# Answer
> 5 votes
Adding to other answers, it's worth noting that on top of the average office worker, most creative work like art and programming certainly does not benefit from monitoring over the shoulder and counting down the minutes.

However, this doesn't mean you cannot track or expect a deadline for goals.

**If your workers legitimately do not know when a task will be completed from your plan, their task is actually too big** \- or you've presented it as too big. Break the tasks down to things your workers can deliver frequently and effectively build up to your MVP. Think SMART goals and involve them in the process. Have a brief stand up meeting everyday to figure what's being tackled today, how work is going, or what's impeding their progress.

To say it again, do not set up overwatch on them with work hours. Gather with each team and discuss reasonable scope and deadlines. **Do not micromanage**, specially over creatives.

# Answer
> 2 votes
I think you were taking the problem on the reverse way (but hopefully the previous answers changed your mind).

Here is my way to lead creative people, and the way I like to be lead :

* I make sure they feel engaged toward the project. It must be their baby, not mine. I'm very strict with the briefing and then give full freedom within the defined frame. I feel very bad when I have to say someone "I know you don't want to do this that way but you have to" each time it happend and the job is done I consider I have a big debt regarding the worker. If there is a technical choice to make, the ones more impacted by it have to make it. Also split the tasks so they can aim at the end of it (agile methods).
* get focused very hard during small amount of time, then relax. Check pomodoro method, it force you to train to quit working even if you felt very productive at that time. Feel weird, but once you use it repeatedly you'll see it work. There are tons of similar methods. Make sure your employees experiment them, I'm so glad when I see my colleagues debating about these methods.
* Make sure they have top environment: descent computer, keyboard, mouse, monitor, desk, chairs, network, good water, even fruits... It cost nothing compare to salaries.
* Make sure they have a place to take a nap. Sometime after a bad night I could take a one hour nap, it saves me the rest of the day instead of fighting fatigue like a zombie in front of computer. Consider your developers are working while sleeping and exercising. They just come to work to type the code they though about while cooking the day before. If they sleep or have sport break during the day, you'll get two days of work for the price of one. The same apply at smaller scale with pomodoro methods. So make sure they have some quick stupid things to do. Ideally I would have a climbing wall in the office. So you can climb 5min get focused 25min... Also I would pay the one hour sport break.
* experiment things that seems to be a waste of time. Like peer programing for exemple, I can't remember how many keyboard shortcuts or software feature I learnt this way and how grateful I'm to the ones who taught me them. It also create bonds between people. Also at one company I was working with, employees made presentation to others once a week during lunch time. It was not mandatory for employees to do it but considered as a present to others. The company paid pizzas... Quite cheap for a one hour and half lesson to 20 persons.
* care for them, check the signs of fatigue, worries, bad health state. Talk with them, encourage exercising... It's like leading a sport team. Care for them, they'll care for you.
* Make sure there is no shame of not being working at a time, so they never fake it. They send messages on slack because it's a less obvious break than doing push-ups...

But how can you be sure they are working if it all look like an holiday place? You'll feel it. Make sure there's some pressure, some deadline and challenge and that they care. It's really easy to make happy people productive.

# Answer
> 2 votes
In addition to the existing answers that cover A. “employees are humans and need to be able to also live their lives” And B. “Setting up long term waterfall based work loads and deadlines, but meeting daily about them, doesn’t count as agile”

I’ll add some additional information I think will help you succeed. There is, sadly, just statistically, but also from my takeaway of your situation and view points, nearly a 100% chance you will never ship a game.

The setup you have going, plus how game development works, plus this being your first shot at running it all where you are the last line and the bottom line, means failure is imminent.

The only chance you have to ship a product, of any sort, is to constantly adapt. The grand vision of a game you have right now, whatever it is, will sink you. Plan on shipping a tenth of that vision at best. Hold on to one key feature or essence, and let everything else be flexible or “cut-able”.

If you were an artist or an engineer yourself, then you could drive slightly more of the vision home via your own sweat equity. As it is now, every sprint, look at what you have and then make a decision about where to try to take things in the next 2 weeks. Forget about the grand plan. Figure out what pieces there are for a minimal viable product and try to dedicate sprints to achieving a single piece.

Agile development is especially difficult to manage at the very beginning of a software project. Many producer/designers end up turning it into waterfall development without realizing it...but with a lot more meetings.

# Answer
> -1 votes
To me, it kinda sounds like you hired the wrong people. I only work with people who I know will be just as motivated as I am. Doing personal stuff in between is no biggie (as long as it's not too long of course!), but showing up late seems to me like a lack of discipline / they don't take their job too seriously.

Look, I don't know you, I don't know them, I don't know the company, but it feels like you should go over this with them. It doesn't need to be in a stern manner, but rather ask how they perceive such issues and help them get motivated for the end-goal, your release.

Oh, and as an artist I totally understand their "I don't wanna do marketing stuff" mindset, because it may not be what they learned to do in school. For tasks like those you may rather hire a specialist, especially since you're a starting studio. Without marketing you'll die a swift and unnoticed death.

Hope this helps, succes with figuring it out!

---
Tags: project-management
---


# Question
Title: How to rotate player to face mouse on canvas?
I'm building a basic game using plain javascript and I am trying to rotate my object to follow my mouse.

I've tried getting the client's mouse X and Y then subtracting the canvas width and height divided by two. Then taking those values and inputing it into `Math.atan2()`. However, I feel the issue may be in my transform and rotate. The code bellow is what I've tried.

```
WIDTH = c.height;
HEIGHT = c.width;
document.onmousemove = function(ve){
            let cX = -c.width / 2;
            let cY = -c.height / 2;
            let x = ve.offsetX;
            let y = ve.offsetY;
            var rX = cX + x - 8;
            var rY = cY + y - 8;
            player.angle = Math.atan2(rX, rY) / Math.PI * 180;
        }
function update(){
                        var now = Date.now();
                        dt = now - lastUpdate;
                        ctx.clearRect(0, 0, WIDTH, HEIGHT);
                        ctx.setTransform(1, 0, 0, 1, WIDTH / 2, HEIGHT / 2);
                        ctx.rotate(player.angle + 10);
                        drawCircle(player.x, player.y, 20, 0, 180, "red");
                        ctx.setTransform(1, 0, 0, 1, 0, 0);
}
setInterval(update, dt/10000);

```

The player spins around my mouse in wide circles with no apparent pattern. Here's a gif showing what's happening. https://gyazo.com/006c99879ecf219791d059de14d98b74

# Answer
You need to transform the `(0;0)` position of the canvas so that it lies on the center of the player, then after rotating it, draw the player at `(0; 0)`. This is required, because every rotation gets applied around the origin.
> 1 votes

---
Tags: javascript, html-canvas
---


title: A* GetNearest() implementation

text:
# Question
Title: A* GetNearest() implementation
I'm trying to implement pathfinding in my platformer and I'm having trouble coming up with a way to find the nearest node to a world point.

---

I tried this:

```
public Node GetNodeFromPoint(Vector2 point)
    {
        int xGridPoint = Mathf.RoundToInt(point.x / gridWorldSize.x);
        int yGridPoint = Mathf.RoundToInt(point.y / gridWorldSize.y);

        Debug.Log(xGridPoint + " " + yGridPoint);

        return grid[xGridPoint, yGridPoint];
    }

```

But it always gave me `[0,0]`.

This is my "NavGrid" class it creates the grid and is going to set up the links between nodes:

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

public class NavGrid : MonoBehaviour {

    public LayerMask unWalkableMask;
    public Vector2 gridWorldSize;
    public float nodeSize;

    public float maxFallLinkLimit = 100f;

    Node[,] grid;

    int gridSizeX;
    int gridSizeY;

    float nodeDiameter;

    // Use this for initialization
    void Start () {
        nodeDiameter = nodeSize * 2;
        gridSizeX = Mathf.RoundToInt(gridWorldSize.x / nodeDiameter);
        gridSizeY = Mathf.RoundToInt(gridWorldSize.y / nodeDiameter);
        CreateGrid();
        CreateFallLinks();
    }

    private void CreateGrid()
    {
        grid = new Node[gridSizeX, gridSizeY];
        Vector2 worldBottomLeft = transform.position - (Vector3)Vector2.left * gridWorldSize.x / 2 - (Vector3)Vector2.down * gridWorldSize.y / 2;

        for(int x = 0; x < gridSizeX; x++)
        {
            for(int y = 0; y < gridSizeY; y++)
            {
                Vector2 worldPoint = worldBottomLeft + Vector2.left * (x * nodeDiameter + nodeSize) + Vector2.down * (y * nodeDiameter + nodeSize);

                bool iswalkable = false;

                if (!Physics2D.CircleCast(worldPoint, nodeSize, Vector2.down, nodeSize/2, unWalkableMask))
                {
                    if (Physics2D.Raycast(new Vector2(worldPoint.x, worldPoint.y - nodeSize), Vector2.down, nodeDiameter, unWalkableMask))
                    {
                        iswalkable = true;
                    }
                }

                Node node = new Node(iswalkable, worldPoint);

                grid[x, y] = node;
            }
        }
    }

    private void CreateFallLinks()
    {
        for(int x = 0; x < gridSizeX; x++)
        {
            for(int y = 0; y < gridSizeY; y++)
            {
                Node node = grid[x, y];
                if (!node.isWalkable) continue;

                if(!grid[x+1,y].isWalkable && !grid[x+1,y-1].isWalkable)
                {
                    Vector2 fallPoint = grid[x + 1, y].worldPosition;

                    RaycastHit2D hit = Physics2D.Raycast(fallPoint, Vector2.down, maxFallLinkLimit, unWalkableMask);
                    if(hit.collider != null)
                    {
                        node.fallLink = GetNodeFromPoint(hit.point);
                        continue;
                    }
                }

                if (!grid[x - 1, y].isWalkable && !grid[x - 1, y - 1].isWalkable)
                {
                    Vector2 fallPoint = grid[x - 1, y].worldPosition;

                    RaycastHit2D hit = Physics2D.Raycast(fallPoint, Vector2.down, maxFallLinkLimit, unWalkableMask);
                    if (hit.collider != null)
                    {
                        node.fallLink = GetNodeFromPoint(hit.point);
                        continue;
                    }
                }
            }
        }
    }

    public Node GetNodeFromPoint(Vector2 point)
    {
        int xGridPoint = Mathf.RoundToInt(point.x / nodeSize);
        int yGridPoint = Mathf.RoundToInt(point.y / nodeSize);

        Debug.Log(xGridPoint + " " + yGridPoint);

        return grid[xGridPoint, yGridPoint];
    }

    public void OnDrawGizmos()
    {
        Gizmos.DrawWireCube(transform.position, new Vector3(gridWorldSize.x, gridWorldSize.y, 1));

        if (grid != null)
        {
            foreach (Node n in grid)
            {
                if (n.isWalkable)
                {
                    Gizmos.color = Color.red;
                    Gizmos.DrawRay(new Vector2(n.worldPosition.x, n.worldPosition.y - nodeSize), new Vector2(0, -nodeDiameter));
                    Gizmos.color = Color.cyan;
                    Gizmos.DrawCube(n.worldPosition, Vector3.one * (nodeDiameter * 0.9f));
                    Gizmos.color = Color.yellow;
                    Gizmos.DrawWireSphere(n.worldPosition, nodeSize / 2);
                }

                if(n.fallLink != null)
                {
                    Gizmos.color = Color.blue;
                    Gizmos.DrawLine(n.worldPosition, n.fallLink.worldPosition);
                }
            }
        }
    }
}

```

I tried coldSteel's answer but it gave me a array index out of range error because it world return a negative number.

This is the node class:

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

public class Node {

    public bool isWalkable = false;
    public Vector2 worldPosition;
    public Node fallLink = null;

    public Node(bool isWalkable, Vector2 worldPosition)
    {
        this.isWalkable = isWalkable;
        this.worldPosition = worldPosition;
    }
}

```

# Answer
In This tutorial there is a good way of doing it.

```
public Node NodeFromWorldPoint(Vector3 worldPosition) {
        float percentX = (worldPosition.x + gridWorldSize.x/2) / gridWorldSize.x;
        float percentY = (worldPosition.z + gridWorldSize.y/2) / gridWorldSize.y;
        percentX = Mathf.Clamp01(percentX);
        percentY = Mathf.Clamp01(percentY);

        int x = Mathf.RoundToInt((gridSizeX-1) * percentX);
        int y = Mathf.RoundToInt((gridSizeY-1) * percentY);
        return grid[x,y];
    }

```

It's explained here nicely.
> 0 votes

# Answer
You are dividing a point by a grid size - thus you get a 0,0 because I assume that grid size is much larger than a point.

What you want to do is: To take your point in World coordinates and divide it by a GridCellSize.

For example your CellSize is \[3,3\] And your point is \[6,0\]

XCoord = 6/3 = 2

YCoord = 0/3 = 0
> 1 votes

---
Tags: unity, mathematics, path-finding
---


# Question
Title: Trying to add my model's animation to the animator in Unity but it doesn't work?
I made an animation for a model in blender, then saved and imported it into Unity. In the preview, I can see the animation playing, but when I try to click on 'loop time' or to drag it over to the animator window, it doesn't work. In fact, I can't interact with it, other then drag the model into the scene. I'm not sure whether this is a bug, or if I've missed something with the settings. I am using 2.79

Does anyone know why this is, or has experienced anything similar? Also due to copyright reasons, I cannot upload any content from the game onto here.

# Answer
I forgot to drag and drop the animator controller onto the model -\_-;
> 0 votes

---
Tags: unity, animation, models, animator
---


# Question
Title: How can I build an array of coordinates of a truncated icosahedron's faces?
I can easily get a list of coordinates of all the vertices—the Wikipedia page has formulae and this page has a list of them, but that doesn't tell me which ones are part of which face.

What I'd like is to create an array of 32 faces, and for each one have:

* The 3-coordinate of the center of the face
* The rotation of the face about the center point
* Whether it's a pentagon or a hexagon

How can I generate that data?

# Answer
> 2 votes
I'd suggest you use Blender. It's easy to get the information you want for any geometric object you create, using python scripts. It's free, easy to use and you can get extensive support online.

1) download Blender here: https://www.blender.org/download/ (it's free)

2) Check this question, first answer, to create easily a truncated icosahedron https://blender.stackexchange.com/questions/31727/truncated-icosahedron

3) Go to "Objects mode" and select your geometry (right mouse button).

4) Open the python console by pressing `Shift-F4`. Copy and paste this script:

```
import bpy, bmesh
obj = bpy.context.active_object
verts = [vert.co.to_tuple() for vert in obj.data.vertices]
faces = [ [ vertex for vertex in face.vertices ] for face in obj.data.polygons]

```

Now `verts` is a list of the coordinates of all the vertices, and `faces` is a list of all the faces. Each face is a list of indices referencing to the `verts` list. You can inspect them using `print verts` and `print faces`. I would suggest you save them to a file, using numpy for example.

---
Tags: geometry, coordinates
---


title: How to make UI text longer?

text:
# Question
Title: How to make UI text longer?
I'm working on a menu that needs a wordy description, but I've noticed that it only shows 4 letters, then cuts off and this doesn't seem right.

I right click, select UI \> text and again, it only displays 4 words, even though I can write a lot more there. Am I doing something wrong here?

I'm not sure how to get past this and I want to ask if anyone knows how to get past this? It seems like such a strange limit to put on the UI canvas.

# Answer
> 1 votes
Okay, the fix to this is very simple and you can easily miss it. On the text options, you want to scroll down to Vertical Overflow and change that from 'Truncate' to 'Overflow' this will no longer limit the amount of words you can display. You can do the same with Horizontal Overflow as well.

I hope this helps somebody :)

---
Tags: unity, gui, text
---


title: Phaser Editor / Phaser 2 Resize State

text:
# Question
Title: Phaser Editor / Phaser 2 Resize State
I’m working with Phaser Editor, and I was wondering if it was possible to resize the scene with the editor or just plain Phaser 2. I want to resize the world, by which I mean to make a camera follow the player past the screen, but I can’t figure out how in the docs for phaser 2 or phaser editor. Can someone help?

# Answer
I haven't tested Phaser Editor to see if it's possible to resize a game but if you want to resize your game in Phaser 2 (CE) with some code it's easy, in fact you have diffrent ways of doing that in the `init()` method using :

```
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;

```

You can replace `SHOW_ALL` and play with this command by

* EXACT\_FIT
* RESIZE
* SHOW\_ALL

Plus other options for the command that I don't add to this list because those are the most important and you can find in the documentation

In my opinion the best one and the most used is to scale it like the code below by using `Phaser.ScaleManager.SHOW_ALL`

```
var game = new Phaser.Game({
  state: {

    init: function() {
      game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
      game.scale.pageAlignHorizontally = true;
      game.scale.pageAlignVertically = true;
    },

    preload: function() {
      // This is equivalent to <https://examples.phaser.io/assets/>.
      this.load.baseURL = 'https://raw.githubusercontent.com/photonstorm/phaser-examples/master/examples/assets/';
      this.load.crossOrigin = 'anonymous';
      this.load.image('einstein', 'pics/ra_einstein.png');
    },

    create: function() {
      this.add.image(0, 0, 'einstein');
    },

    update: function() {

    }

  }
});
```

```
html, body {
  padding: 0;
  margin: 0;
}
```

```
<script src="https://cdn.jsdelivr.net/npm/phaser-ce@2.13.1/build/phaser.js"></script>
```
> 1 votes

# Answer
I guess you are using Phaser Editor 1.5.3. You look inside the examples provided by the editor: Friend of Cuco or Sunny Land Forest. In both examples, the world is bigger than the screen and the camera follows the player. You should do that in code, using the Phaser 2 API.
> 0 votes

---
Tags: phaser
---


title: Javascript Jumping Physics

text:
# Question
Title: Javascript Jumping Physics
I have asked questions for this project before, but the jumping physics are a bit messed up. I cannot jump unless I hold down the W key, and then it just teleports me upwards. Does anybody know how to fix this glitch? Here's the code:

```
var canvas = document.getElementById("canvas")
            var ctx = canvas.getContext("2d")
            var x = 1
            var y = 0
            var xPos = 0
            var yPos = 0

            function updateVariables() {
            x = x * 0.9
            y = y * -0.9
            y = y + 0.5
            xPos += x
            yPos += y
            }

            function clear() {
            ctx.clearRect(0,0,600,600)
            }

            function Draw() {
            collisionCheck();
            clear();
            ctx.fillRect(xPos,yPos,10,10)
            ctx.fillRect(0,canvas.offsetHeight * 0.7,600,200)
            window.requestAnimationFrame(Draw)
            }

            function collisionCheck() {
            if (yPos > canvas.offsetHeight * 0.7 - 10) {
                yPos = canvas.offsetHeight * 0.7 - 10
            }
            }

            function right() {
                x = 2
            }

            function left() {
                x = -2
            }

            function jump() {
                y =+ 20
            }

            function detectKeys() {
                document.onkeypress = function (e) {
                    e = e || window.event;
                    console.log(e.key)
                    if (e.key == "d") {
                        right()
                    }
                    if (e.key == "a") {
                        left()
                    }
                    if (e.key == "w") {
                        jump()
                    }
                }
            }

            window.requestAnimationFrame(Draw)
            setInterval(updateVariables, 1)
            setInterval(detectKeys, 1)
```

```
<canvas id="canvas" width="500" height="140"></canvas>
```

# Answer
A glaring math problem pointed out by DMGregory is that you're multiplying your `y` position by `-0.9`, meaning it's oscillating between positive and negative. That's probably a good brunt of why jumping doesn't work, even ignoring the other problems below.

A few other problems, most JavaScript/Web specific:

First, your `detectKeys` doesn't at all do what you think it's doing. It's just registering a callback on `onkeypress`. It won't actually read any keys at that time. The event handler will get triggered when a key is pressed. And since you're re-registering this over and over again via `setInterval`, you're registered multiple handlers, which will all get called whenever a key is pressed. You just want to register the handlers once at the beginning of the game and never again; the callbacks will be invoked when a key is pressed so there's no need to keep polling. The callback will be called only when the key state is triggered (I'll address that below).

Second, `document.onkeypress` isn't what you want anyway. It is triggered when you first press the key and is automatically repeated based on the browser's/OS's key repeat rate. You want to use `onkeydown` instead.

Third, and going back to how you're using the callbacks, you're only applying movement when the key is triggered (first pressed, or on the key repeated rate because you're using `onkeypress`). You want to store the input state (e.g. whether the player is trying to move left/right or is trying to jump) and apply that state, rather than directly responding to keyboard events. This means using `onkeydown`/`onkeyup` to update some state variables and then reading those state variables in your game loop.

Fourth, you have a typo in `jump`. You wrote `y=+20` instead of `y+=20`. What you wrote is equivalent to saying `y=(+20)` or just `y=20`.

Finally (from what I see in a quick perusal), the way you're trying to do the game loop is wrong. You have `draw` correctly keyed to `requestAnimationFrame`, but your `updateVariables` should be as well. `setInterval` is not a good function to use in general for this kind of stuff, because the interval is non-reliable (it might be more or less frequent than requested or be skipped periodically, etc.). Make just a single `update` function that is scheduled via `requestAnimationFrame`, and then have this `update` function call your `updateVariables` function and then the `draw` function. You'd also insert a new function here that reads those keyboard state variables and applies the requested movement. I'd further add that you want to use a time delta (because you can't predict the framerate that `requestAnimationFrame` will run at) when applying your physics/movement code so that you get smooth and predictable movement; you can calculate a time delta via the `performance.now` call.

I'd highly recommend that you read over some tutorials like https://codeincomplete.com/posts/javascript-game-foundations-the-game-loop/ and https://codeincomplete.com/posts/javascript-game-foundations-player-input/ (perhaps that whole series) which will cover all these topics with code samples.
> 2 votes

# Answer
For just fixing the jumping you only need to change a few things. I put a comment in the code wherever I changed something. There are other things that could be nice to change, but you only asked to fix the jumping so here it is. Good luck with your project!

```
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
var x = 1
var y = 0
var xPos = 0
var yPos = 0
var onGround = false; // keep track if you're on the ground, so you cant jump mid-air
function updateVariables() {
    x = x * 0.9
    // y = y * -0.9  // removed line because it did many weird things with the y velocity
    y = y + 0.05 // changed from 0.5 to 0.05 otherwise it went back down way too fast
    xPos += x
    yPos += y
}

function clear() {
    ctx.clearRect(0, 0, 600, 600)
}

function Draw() {
    collisionCheck();
    clear();
    ctx.fillRect(xPos, yPos, 10, 10)
    ctx.fillRect(0, canvas.offsetHeight * 0.7, 600, 200)
    window.requestAnimationFrame(Draw)
}

function collisionCheck() {
    if (yPos > canvas.offsetHeight * 0.7 - 10) {
        yPos = canvas.offsetHeight * 0.7 - 10
        onGround = true; // new line
        y = 0; // set y speed to 0 when you hit the ground
    }
}

function right() {
    x = 2
}

function left() {
    x = -2
}

function jump() {
    if (onGround) { // check if you're on the ground before jumping
        // y =+ 20 // old code removed because y is negative in the up direction
        y = -2; // set y velocity to a negative number to jump up.
        onGround = false; // make so you cant jump again mid-air
    }

}

function detectKeys() {
    document.onkeypress = function (e) {
        e = e || window.event;
        console.log(e.key)
        if (e.key == "d") {
            right()
        }
        if (e.key == "a") {
            left()
        }
        if (e.key == "w") {
            jump()
        }
    }
}

window.requestAnimationFrame(Draw)
setInterval(updateVariables, 1)
setInterval(detectKeys, 1)

```
> 0 votes

---
Tags: physics, javascript
---


title: NavMesh - LoS and "Containing"

text:
# Question
Title: NavMesh - LoS and "Containing"
For a gameserver/backend, I have a navmesh for "walkable" areas in form of points/triangles.

Now I want to check every gametick if the client is still in a legit place and if he shots/casts a spell, if his target is in line of sight.

I found several possibilities, but I am not sure what is performance-wise ideal.

To check if the player is still in the allowed area (and not wallhacking) I would check if his position is in one of the triangles with a algorithm using barycentric coordinates like this: https://github.com/SebLague/Gamedev-Maths/blob/master/PointInTriangle.cs But this would mean that every gametick I have to check soooo much triangles.

To check if its LoS I could either check if the line from the player to its target crosses one of the "border" lines of the mesh (which have no other triangle next to it). Those border lines could be computed at bake time and are just a static list for each level. But still it would be a lot lines per check. Second option I found would be to start a Simple Stupid Funnel Algorithm (http://digestingduck.blogspot.com/2010/03/simple-stupid-funnel-algorithm.html) until LoS is broken.

The questions now are: How does a good gameserver handle this/can it be optimised? What way to check is the best/fastest? Is it common to only check if the position is legit every now and then or every gametick?

The Levels are fairly simple (~300 mesh-triangles, ~200 border lines, 10 players, 10 npcs maybe)

# Answer
Firstly, ~300 triangles or ~200 border lines is peanuts to a modern computer. You're unlikely to see problematic inefficiencies with such a tiny amount of data to process each tick.

> To check if the player is still in the allowed area (and not wallhacking) I would check if his position is in one of the triangles with a algorithm using barycentric coordinates like this: https://github.com/SebLague/Gamedev-Maths/blob/master/PointInTriangle.cs But this would mean that every gametick I have to check soooo much triangles.

Would you really? If the player is running with speed `s`, then you only need to check the triangles within `s * dt` of the last player position you validated, not every triangle in the map. In fact, much of the time, the player will still be in the same triangle as they were in the previous tick, so your very first check will succeed and you're done without looking at even a second triangle.

As is usually the case with spatial checks, a spatial partition helps here. If you break your map into cells in a way that lets you quickly determine which cell your player is in (eg. if you use a regular grid of bins, you can just divide and round their position), then you can limit your triangle checks to only the triangles that overlap that cell. The rest couldn't possibly contain this point so we don't even need to check them.

You can store your navmesh itself in a spatial partition data structure so the set of triangles touching a cell is available on demand without searching. In some implementations (eg. BSP trees), your navmesh and the partition could even be the same structure, where each cell/leaf node corresponds to one navmesh or obstacle polygon.

> But still it would be a lot lines per check.

Again, you don't need to check every line, just the ones that could potentially be in the line of sight. We can use a spatial partition to narrow the list.

You start with the set of lines touching the same cell as the player position. If none of those block the line of sight, you march your los ray into the next cell of the spatial partition along its path, and check the lines touching that cell, repeating until you reach the cell containing the target. Now you've checked only the obstacles that come close to the line of sight, rather than every obstacle in the map.
> 1 votes

---
Tags: networking, path-finding, navmesh, line-of-sight
---


# Question
Title: Sampled texture from bitmap font produces blue glow
I'm creating a texture is DirectX 11 from bitmap fonts. I realize that I can use DXTK, but this is an exercise for me, not in learning another library. My sample code looks like this.

```
// Object Declarations
Texture2D g_MeshTexture;            // Color texture for mesh

SamplerState MeshTextureSampler
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

float4 PS(VS_OUTPUT input) : SV_TARGET
{
    return g_MeshTexture.Sample(MeshTextureSampler, input.uv);
}

```

The texture of the rendered font produces strange blue artifacts where the text should have alpha values but instead appear as blue.

I did try gamma color correction with the code

```
float4 PS(VS_OUTPUT input) : SV_TARGET
{
    float4 sRGBA = g_MeshTexture.Sample(MeshTextureSampler, input.uv);
    float3 sRGB = float3(sRGBA.x, sRGBA.y, sRGBA.z);
    float3 gRGB = pow(sRGB, 1/2.2);

    return float4(gRGB.x, gRGB.y, gRGB.z, sRGBA.w);
}

```

However this did not provide results any different from what the image showed above. I sample the text from the bitmap data and store it in a vector when then is used to create the texture with CreateTexture2D.

```
for (long y = 0; y < m_texture_height; y++)
{
    for (long x = 0; x < m_texture_width; x++)
    {
        BYTE alpha = (bitmap_bits[m_texture_width * y + x] & 0xff);

        if (alpha > 0)
            pixel_data.push_back(0xFFFFFF00 + alpha);
        else
            pixel_data.push_back(0);
    }
}

```

My back buffer uses DXGI\_FORMAT\_R32G32B32A32\_FLOAT, however I have tried DXGI\_FORMAT\_R8G8B8A8\_UNORM and experienced no change. If there's any other information I should provide please let me know.

# Answer
> 2 votes
So in true programmer fashion, I solved the issue after being frustrated with it forever. BITMAPINFO stores in ARGB format, not RGBA like I was expected. The solution is just changing the alpha reading to this.

```
for (long y = 0; y < m_texture_height; y++)
{
    for (long x = 0; x < m_texture_width; x++)
    {
        BYTE alpha = (bitmap_bits[m_texture_width * y + x] & 0xff);

        if (alpha > 0)
            pixel_data.push_back((alpha << 24) | 0x00FFFFFF);
        else
            pixel_data.push_back(0);
    }
}

```

---
Tags: directx11, hlsl, fonts
---


# Question
Title: Should the lobby and game room be database tables or arrays?
I'm designing a lobby which holds all game rooms

* If a room is empty, it gets deleted by the lobby
* If a room is full, a new room is created
* For now the lobby is an array of objects on a websockets server which holds the room.
* The rooms are are arrays of objects which hold the players.

The players data are stored on firebase, I don't care about the room data, they're just spawned and deleted, therefore they're not stored anywhere now. The problem I'm facing is the following:

* If I leave it like that, I'm going to face problems when scaling on multiple servers, plus it I don't think I can get away with an array holding 50k arrays which holds players data.
* I don't want to install redis, every time I have to use that I have stringify and serialize.
* Using a database like MongoDb, means installing a database, doing read and write, perhaps managing clusters, all that for data I don't care about.
* Using firebase, means doing too many unnecessary requests

---

My architecture is simple

* The client is the mobile app
* The game logic is done on the server using nodejs
* Data storage and authentication is done on firebase, using nodejs, from the server side
* The websockets server is uwebsockets.js

I have to solve the last part which is the rooms and lobby, If I manage to do it without installing a database it would be great, because as of now, I managed to do everything without needing a database on the server, which means easier to scale and all the server has to do is run some nodejs code.

# Answer
Generally speaking, data at rest belongs into the databases and data in use belongs into the RAM of the application server. Which database technology you use doesn't change this basic principle much.

That means that if you have any data about offline players, that data should be in the database until that player decides to log in again. But any data of players which are online right now should be in the RAM of the server for faster access.

So your lobby server doesn't need to hold the data of all players. It only needs to hold the data of those players who are currently in the lobby. And it likely doesn't even need *all* the data about the players. It only needs the data which is relevant for matchmaking.

If you really need multiple lobby servers, you should synchronize their data via your own network protocol. But I really doubt that this will be necessary. I mean, what does a lobby server do? Keep a list of ongoing matches and online players, send these lists when a client connects and propagate updates to the connected clients when these lists change. These change events happen every few seconds tops and none of these events are latency-critical. Unless you expect to get as big as Fortnite or Counter Strike, one global lobby server should be able to handle it.

The actual load of the game (the "rooms") is handled by the gameservers. Investing into a scalable design from the get go is definitely a good approach here. If your matches are small, then it's a good approach to start a game thread for every ongoing game and terminate the thread when the game is over. When the lobby server tells the players the IP and port of their gameserver, you basically already have an architecture which supports scaling to multiple physical servers. (Scalable architectures for open world MMOs are a far more complicated topic, but this is out of scope for this question).

The gameservers should use the database as little as possible and keep data in memory. Communicating with a database usually takes far too long for real-time gameplay, even when the database server is in the same server rack. So the gameserver should request all the data about a player when that player joins its game, write that data back to the DB when the player leaves and *maybe* write data back at periodic intervals of several minutes to avoid data loss in case of a server crash (but the necessity of that is debatable depending on how much persistence you have in your gameplay and how stable your gameserver runs). But the actual gameplay loop should operate only on data in the RAM of the gameserver.

I am looking forward to playing your game.
> 2 votes

---
Tags: architecture
---


title: How can I change position of camera?

text:
# Question
Title: How can I change position of camera?
I'm working on 3D game, where the player needs to complete 4 play fields called "homes" in level 1, then progress to level 2 which has 4 homes of its own.

In level 1, when the player completes the first home, how can I move the camera to the second home?

**Referance**:

Gameover script on camera:

```
void fixedupdate()
{
 gameover();
}
void gameover()
{
     //some code here
    //camera position change but not move when my game over
    Vector3 positions = cams.transform.position + new Vector3(-12, 0, 0);
}

```

# Answer
> 1 votes
```
void gameover()
{
    Vector3 positions = cams.transform.position + new Vector3(-12, 0, 0);
}

```

This code creates a temporary variable called `positions` and assigns it a value 12 units to the left of the camera's position. It then does *nothing whatsoever* with that variable, and exits.

If you want to move the camera, then you can assign your new shifted position value to the camera's `transform.position` property:

```
void gameover()
{
    // Compute the new desired position for the camera in a temporary variable.
    Vector3 newPosition = cams.transform.position + new Vector3(-12, 0, 0);
    // Assign that position to the camera's transform to actually move it.
    cams.transform.position = newPosition;
}

```

---
Tags: unity, c#, 3d, camera
---


# Question
Title: Textures in build duplicated, despite they're packed into atlases
I have a simple `SpriteAtlas`: "UIAtlas" which is located in the `Resources` folder. It points to a folder "UIAtlas" which contains my menu textures.

All of my batching is working perfectly, everything is being batched, because of the atlas.

When I build an iOS version, in the `Editor.log` I can see this:

> Build Report
>
> Uncompressed usage by category:
>
> **Textures 299.5 mb (30%)**
>
> Meshes 0.0kb (0%)
>
> ...
>
> Used Assets and files from the Resources folder, sorted by uncompressed size:
>
> **16.0 mb 1.6% Built-in Texture2D: sactx-2048x2048-Uncompressed-UIAtlas-312aba98**
>
> ...
>
> **345.3 kb 0.1% Assets/Resources/UIAtlas/medal.png**
>
> ... more entries like this ...

Please notice that this texture (medal.png), along with the other textures belongs to this atlas, which is already included in the build-executable.

I feel this is wrong. If I pack things, they should be packed into that texture and only that 2048x2048 texture should be in the build, right?

What's wrong here?

# Answer
> 2 votes
Here's an official answer.

> Any assets inside the Resources folder (including Sprites and Atlases regardless of being packed) will always be exported. This is by design.

So when we make a `SpriteAtlas` with some textures, and put in it the `Resources` folder, it's a total mess. I did it initially cause I wanted to unload assets and load them dynamically.

---
Tags: unity, android, ios, texture-atlas, build-process
---


# Question
Title: Set UI text using value from separate script
I've been working on the TANKS! tutorial from unity, attempting to add a U.I overlay that displays the scores of each player.

I cannot seem to get it working with the current setup the game has:

* Each instance of the tanks being spawned in will have the same elements that can be changed in the inspector

+ Color
    + spawn
    + and what I am trying to add: Score display)
* I have U.I text elements in the Scene that are being plugged in, but I just can't seem to get the code working

The problem is in the `Scorekeeper` method of `GameManager`, where the compiler doesn't recognize the `Text` property of `m_PlayerScore`.

Game Manager

```
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

namespace Complete
{
    public class GameManager : MonoBehaviour
    {
        public int m_NumRoundsToWin = 5;            // The number of rounds a single player has to win to win the game.
        public float m_StartDelay = 3f;             // The delay between the start of RoundStarting and RoundPlaying phases.
        public float m_EndDelay = 3f;               // The delay between the end of RoundPlaying and RoundEnding phases.
        public CameraControl m_CameraControl;       // Reference to the CameraControl script for control during different phases.
        public Text m_MessageText;                  // Reference to the overlay Text to display winning text, etc.
        public GameObject m_TankPrefab;             // Reference to the prefab the players will control.
        public TankManager[] m_Tanks;               // A collection of managers for enabling and disabling different aspects of the tanks.
        public TankManager m_PlayerScore;

        public Text Player1Score;                   // Score for player 1 shown on the scorekeeper
        public Text Player2Score;                   // Score for player 2 shown on the scorekeeper

        public int m_RoundNumber;                  // Which round the game is currently on.
        public WaitForSeconds m_StartWait;         // Used to have a delay whilst the round starts.
        public WaitForSeconds m_EndWait;           // Used to have a delay whilst the round or game ends.
        public TankManager m_RoundWinner;          // Reference to the winner of the current round.  Used to make an announcement of who won.
        public TankManager m_GameWinner;           // Reference to the winner of the game.  Used to make an announcement of who won.
        public int LevelLoaded;

        private GameObject LightingObject;

        private void Start()
        {
            // Create the delays so they only have to be made once.
            m_StartWait = new WaitForSeconds(m_StartDelay);
            m_EndWait = new WaitForSeconds(m_EndDelay);

            SpawnAllTanks();
            SetCameraTargets();
            Scorekeeper();
            //Scorekeeper1();
            //Scorekeeper2();

            // Once the tanks have been created and the camera is using them as targets, start the game.
            StartCoroutine(GameLoop());
        }

        private void SpawnAllTanks()
        {

            for (int i = 0; i < m_Tanks.Length; i++)
            {
                // ... create them, set their player number and references needed for control.
                m_Tanks[i].m_Instance =
                    Instantiate(m_TankPrefab, m_Tanks[i].m_SpawnPoint.position, m_Tanks[i].m_SpawnPoint.rotation) as GameObject;
                m_Tanks[i].m_PlayerNumber = i + 1;
                m_Tanks[i].Setup();
            }
        }

        private void SetCameraTargets()
        {
            // Create a collection of transforms the same size as the number of tanks.
            Transform[] targets = new Transform[m_Tanks.Length];

            // For each of these transforms...
            for (int i = 0; i < targets.Length; i++)
            {
                // ... set it to the appropriate tank transform.
                targets[i] = m_Tanks[i].m_Instance.transform;
            }

            // These are the targets the camera should follow.
            m_CameraControl.m_Targets = targets;
        }

        // This is called from start and will run each phase of the game one after another.
        private IEnumerator GameLoop ()
        {
            // Start off by running the 'RoundStarting' coroutine but don't return until it's finished.
            yield return StartCoroutine (RoundStarting ());

            // Once the 'RoundStarting' coroutine is finished, run the 'RoundPlaying' coroutine but don't return until it's finished.
            yield return StartCoroutine (RoundPlaying());

            // Once execution has returned here, run the 'RoundEnding' coroutine, again don't return until it's finished.
            yield return StartCoroutine (RoundEnding());

            // This code is not run until 'RoundEnding' has finished.  At which point, check if a game winner has been found.
            if (m_GameWinner != null)
            {
                // If there is a game winner, restart the level.
                SceneManager.LoadScene (0);
            }
            else
            {
                // If there isn't a winner yet, restart this coroutine so the loop continues.
                // Note that this coroutine doesn't yield.  This means that the current version of the GameLoop will end.
                StartCoroutine (GameLoop ());
            }
        }

        private IEnumerator RoundStarting ()
        {
            //Calling method meant to load in additive levels. Seems to work...
            LoadMapForRound();
            // As soon as the round starts reset the tanks and make sure they can't move.
            ResetAllTanks ();
            DisableTankControl ();

            // Snap the camera's zoom and position to something appropriate for the reset tanks.
            m_CameraControl.SetStartPositionAndSize ();

            // Increment the round number and display text showing the players what round it is.
            m_RoundNumber++;
            m_MessageText.text = "ROUND " + m_RoundNumber;

            // Wait for the specified length of time until yielding control back to the game loop.
            yield return m_StartWait;
        }

        //Method meant to load in additive levels.
        private void LoadMapForRound()
        {
            int mapChosen = Random.Range(2, 6);
            LevelLoaded = mapChosen;
            SceneManager.LoadScene(LevelLoaded, LoadSceneMode.Additive);
            SceneManager.LoadScene(1, LoadSceneMode.Additive);
            //Debug.Log("SceneLoaded");
        }
        //Method meant to unload levels

        private IEnumerator RoundPlaying ()
        {
            // As soon as the round begins playing let the players control the tanks.
            EnableTankControl ();

            // Clear the text from the screen.
            m_MessageText.text = string.Empty;

            // While there is not one tank left...
            while (!OneTankLeft())
            {
                // ... return on the next frame.
                yield return null;
            }
        }

        private void DestroyRoundMap()
        {
            SceneManager.UnloadSceneAsync(LevelLoaded);
            SceneManager.UnloadSceneAsync(1);
        }

        private IEnumerator RoundEnding ()
        {
            // Stop tanks from moving.
            DisableTankControl();

            // Clear the winner from the previous round.
            m_RoundWinner = null;

            // See if there is a winner now the round is over.
            m_RoundWinner = GetRoundWinner();

            // If there is a winner, increment their score.
            if (m_RoundWinner != null)
                m_RoundWinner.m_Wins++;
                m_RoundWinner.m_PlayerScore.text = string.Format("{0}: {1}",
                                          m_RoundWinner.m_ColoredPlayerText,
                                          m_RoundWinner.m_Wins
                                    );

            // Now the winner's score has been incremented, see if someone has one the game.
            m_GameWinner = GetGameWinner();

            // Get a message based on the scores and whether or not there is a game winner and display it.
            string message = EndMessage();
            m_MessageText.text = message;

            // Wait for the specified length of time until yielding control back to the game loop.
            yield return m_EndWait;

            //Unload Maps
            DestroyRoundMap();

        }

        // This is used to check if there is one or fewer tanks remaining and thus the round should end.
        public bool OneTankLeft()
        {
            // Start the count of tanks left at zero.
            int numTanksLeft = 0;

            // Go through all the tanks...
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                // ... and if they are active, increment the counter.
                if (m_Tanks[i].m_Instance.activeSelf)
                    numTanksLeft++;
            }

            // If there are one or fewer tanks remaining return true, otherwise return false.
            return numTanksLeft <= 1;
        }

        // This function is to find out if there is a winner of the round.
        // This function is called with the assumption that 1 or fewer tanks are currently active.
        public TankManager GetRoundWinner()
        {
            // Go through all the tanks...
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                // ... and if one of them is active, it is the winner so return it.
                if (m_Tanks[i].m_Instance.activeSelf)
                    return m_Tanks[i];
            }

            // If none of the tanks are active it is a draw so return null.
            return null;
        }

        // This function is to find out if there is a winner of the game.
        public TankManager GetGameWinner()
        {
            // Go through all the tanks...
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                // ... and if one of them has enough rounds to win the game, return it.
                if (m_Tanks[i].m_Wins == m_NumRoundsToWin)
                    return m_Tanks[i];
            }

            // If no tanks have enough rounds to win, return null.
            return null;
        }

        // Returns a string message to display at the end of each round.
        private string EndMessage()
        {
            // By default when a round ends there are no winners so the default end message is a draw.
            string message = "DRAW!";

            // If there is a winner then change the message to reflect that.
            if (m_RoundWinner != null)
                message = m_RoundWinner.m_ColoredPlayerText + " WINS THE ROUND!";

            // Add some line breaks after the initial message.
            message += "\n\n\n\n";

            // Go through all the tanks and add each of their scores to the message.
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                message += m_Tanks[i].m_ColoredPlayerText + ": " + m_Tanks[i].m_Wins + " WINS\n";
            }

            // If there is a game winner, change the entire message to reflect that.
            if (m_GameWinner != null)
                message = m_GameWinner.m_ColoredPlayerText + " WINS THE GAME!";

            return message;

        }
        private void Scorekeeper()

        {
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                m_PlayerScore.Text = m_Tanks[i].m_ColoredPlayerText + ": " + m_Tanks[i].m_Wins;
            }
        }

        /*
            // This function is used to constantly show the score between both tanks.
            private void Scorekeeper1()

            {
                for (int i = 0; i < m_Tanks.Length; i++)
                {
                    Player1Score.text = m_Tanks[0].m_ColoredPlayerText + ": " + m_Tanks[0].m_Wins;
                }
            }

            private void Scorekeeper2()

            {
                for (int i = 0; i < m_Tanks.Length; i++)
                {
                    Player2Score.text = m_Tanks[1].m_ColoredPlayerText + ": " + m_Tanks[1].m_Wins;
                }
            }
          */
        // This function is used to turn all the tanks back on and reset their positions and properties.
        private void ResetAllTanks()
        {
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                m_Tanks[i].Reset();
            }
        }

        private void EnableTankControl()
        {
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                m_Tanks[i].EnableControl();
            }
        }

        private void DisableTankControl()
        {
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                m_Tanks[i].DisableControl();
            }

        }
        private void Update()
        {
            Scorekeeper();
            //Scorekeeper2();
        }
    }
}

```

Tank Manager

```
    using System;
    using UnityEngine;
    using UnityEngine.UI;

    namespace Complete
    {
        [Serializable]
        public class TankManager
        {
            // This class is to manage various settings on a tank.
            // It works with the GameManager class to control how the tanks behave
            // and whether or not players have control of their tank in the
            // different phases of the game.

            public Color m_PlayerColor;                             // This is the color this tank will be tinted.
            public Transform m_SpawnPoint;                          // The position and direction the tank will have when it spawns.
            public Text m_PlayerScore;
            [HideInInspector] public int m_PlayerNumber;            // This specifies which player this the manager for.
            [HideInInspector] public string m_ColoredPlayerText;    // A string that represents the player with their number colored to match their tank.
            [HideInInspector] public GameObject m_Instance;         // A reference to the instance of the tank when it is created.
            [HideInInspector] public int m_Wins;                    // The number of wins this player has so far.

            private TankMovement m_Movement;                        // Reference to tank's movement script, used to disable and enable control.
            private TankShooting m_Shooting;                        // Reference to tank's shooting script, used to disable and enable control.
            private GameObject m_CanvasGameObject;                  // Used to disable the world space UI during the Starting and Ending phases of each round.

            public string Text { get; internal set; }

            public void Setup ()
            {
                // Get references to the components.
                m_PlayerScore = m_Instance.GetComponent<Text>();
                m_Movement = m_Instance.GetComponent<TankMovement> ();
                m_Shooting = m_Instance.GetComponent<TankShooting> ();
                m_CanvasGameObject = m_Instance.GetComponentInChildren<Canvas> ().gameObject;

                // Set the player numbers to be consistent across the scripts.
                m_Movement.m_PlayerNumber = m_PlayerNumber;
                m_Shooting.m_PlayerNumber = m_PlayerNumber;

                // Create a string using the correct color that says 'PLAYER 1' etc based on the tank's color and the player's number.
                m_ColoredPlayerText = "<color=#" + ColorUtility.ToHtmlStringRGB(m_PlayerColor) + ">PLAYER " + m_PlayerNumber + "</color>";

                // Get all of the renderers of the tank.
                MeshRenderer[] renderers = m_Instance.GetComponentsInChildren<MeshRenderer> ();

                // Go through all the renderers...
                for (int i = 0; i < renderers.Length; i++)
                {
                    // ... set their material color to the color specific to this tank.
                    renderers[i].material.color = m_PlayerColor;
                }
            }

            // Used during the phases of the game where the player shouldn't be able to control their tank.
            public void DisableControl ()
            {
                m_Movement.enabled = false;
                m_Shooting.enabled = false;

                m_CanvasGameObject.SetActive (false);
            }

            // Used during the phases of the game where the player should be able to control their tank.
            public void EnableControl ()
            {
                m_Movement.enabled = true;
                m_Shooting.enabled = true;

                m_CanvasGameObject.SetActive (true);
            }

            // Used at the start of each round to put the tank into it's default state.
            public void Reset ()
            {
                m_Instance.transform.position = m_SpawnPoint.position;
                m_Instance.transform.rotation = m_SpawnPoint.rotation;

                m_Instance.SetActive (false);
                m_Instance.SetActive (true);
            }
        }
    }

```

# Answer
I can't see anywhere you actually use the value that's been assigned to `TankManager`'s `string Text` property.

Moreover, assigning to the same variable repeatedly in a loop like this would result in each iteration's value getting stomped by the next one, so that only the final iteration's value remains at the end of the method. Probably not what you want?

```
private void Scorekeeper()
{
    for (int i = 0; i < m_Tanks.Length; i++)
    {
        m_PlayerScore.Text = m_Tanks[i].m_ColoredPlayerText + ": " + m_Tanks[i].m_Wins;
    }
}

```

Rather, it looks like you want to assign this text to *each player's own text object*:

```
private void Scorekeeper()
{
    for (int i = 0; i < m_Tanks.Length; i++)
    {
        m_Tanks[i].m_PlayerScore.text = m_Tanks[i].m_ColoredPlayerText + ": " + m_Tanks[i].m_Wins;
    }
}

```

Moreover, you probably want to assign this text *only when someone's win number changes*, otherwise you're constructing new strings every frame, creating a lot of garbage that will eventually trigger the garbage collector to put your game on pause and sweep it all up.

```
// If there is a winner, increment their score.
if (m_RoundWinner != null) {
    m_RoundWinner.m_Wins++;
    m_RoundWinner.m_PlayerScore.text = string.Format("{0}: {1}",
                                              m_RoundWinner.m_ColoredPlayerText,
                                              m_RoundWinner.m_Wins
                                        );
}

```

Or this could be placed entirely inside a `Win()` method inside `TankManager` for better encapsulation. So `GameManager` only needs to know someone won, and `TankManager` can manipulate its own internal state to reflect that.
> 1 votes

---
Tags: unity, c#, gui
---


# Question
Title: Does CharacterController benefit from adding lerp?
Does CharacterController benefit from adding lerp?

as in this script.

```
mouse = Input.GetAxis("Mouse X");
current = Mathf.Lerp(current, mouse, Time.deltaTime * 10);
transform.Rotate(0, current * 600 * Time.deltaTime, 0);

```

I was using,

```
transform.Rotate(0, mouse * 18, 0);

```

But read into the idea of lerp and wrote that.

# Answer
As a general practice, find a problem before you try to solve it.

There are lots of solutions in game development, and many of those solutions are for problems that you do not have.

Reaching for a solution before you know if there's a problem or what it is can lead to:

* **wasted work** (you didn't have a problem at all, now you've spent time for no benefit)
* **sub-optimal solutions** (you missed an opportunity for a better solution for your specific case)
* **creating new problems** (this solution is so ill-fit for the current situation that it actually makes it *worse*)

The specific example you have here looks like one of the "creating new problems" variety.

Here you're taking the player's mouse input, and instead of using it to immediately turn their camera in exact proportion to their movement to make their control tight & responsive, you are adding a layer of indirection.

The variable `current` will seek toward `mouse` (at an inconsistent rate when running at different frame rates, since you used Time.deltaTime incorrectly in your third Lerp argument), but always lag behind it:

* if I move sharply to the right, `current` will increase by only a fraction of my movement: I have to make an exaggeratedly large movement to get the response I intended.
* if I keep moving to the right at a constant speed, `current` will gradually increase closer and closer to my actual input value, by smaller and smaller intervals each time. So to turn at a constant rate, I actually have to start moving fast then slow down my arm to avoid over-accelerating.
* if I stop moving, *`current` will continue to have a positive value* and the camera will keep spinning for several frames. So I have to stop early and hope the camera will come to rest somewhere near where I want it.

This will tend to make your controls feel spongy, laggy, and non-responsive, or even outright sloshy and motion sickness inducing.

So no: don't do this.

`Lerp` isn't your "make stuff smoother" sauce. It's a math function that blends two values. First, understand what values you're working with and whether it's appropriate to blend them, before reaching to `Lerp` or another method.
> 0 votes

---
Tags: unity, rotation, lerp
---


# Question
Title: I have an editable SWF with Refferal protection, how would I remove that
Im using JPEXS to edit an SWF I obtained of MutilateADoll2 that is Site locked (referrer) to the kongregate website, is it possible to.... per say... Remove that referral lock and gain access to use the swf offline (via embed)

# Answer
> 2 votes
As described in the comments above, even given that your intentions are perfectly noble, this is a publicly visible site. If we told you how to defeat a game developer's protections on their game here, any bad actor could come along and use that information to rip off our fellow developers' hard work.

So, I hope you'll understand that many users of this site would find it unethical to post an answer about how to defeat this type of protection.

So, instead of "how can *I remove* this protection", I'd recommend we approach this question from the direction of **"how can *I obtain* a version of this game that works offline?"**

Here, the best approach we can offer you is to contact the game's original developer, eg. via their Twitter account, and ask if they would be willing to share a non-protected version with you / grant you a licence to use their work in the way that you describe.

---
Tags: flash, swf
---


title: Optimizing Hitboxes

text:
# Question
Title: Optimizing Hitboxes
Way over 90% of the performance cost seems to be coming from colliders parented to animated bones. If I disable Motion & Animation I can spawn 20 soldiers with around 1ms cost on my mid-low end system. Unfortunately even when the soldiers are "not moving" the idle animation requires the colliders to move with the bones. With motion enabled the performance of 20 soldiers is roughly 15ms. I managed to improve performance by creating a simple hitbox (see left photo), the performance of 20 such soldiers is 10ms. Removing all colliders from the Soldier again lowered performance cost down to 1ms.

The hitbox colliders have been disabled for all collisions in the Physics Manager. Obviously they are not set as static. They are for raycast detection ONLY.

I have developed a 6th sense for when I'm "doing something wrong". Are moving colliders really that expensive?

Inspector Settings:

Physics:

Script attached to Collider:

# Answer
> 1 votes
According to Unity any Collider that will be moved should have a Rigidbody attached to it with isKinematic checked. That solved my problem.

---
Tags: unity, animation, movement, collider
---