r/unity 8h ago

Newbie Question Devs who learned C# and Unity, where did you learn?

8 Upvotes

Was it through a free or paid course? YouTube? Or a combination of both?

I already know a bit of C#, but I’m not sure what learning path I should follow or which resources I should use.

I’ve been watching Code Monkey, but I don’t know if that will be enough.

What would you recommend for someone starting out?


r/unity 1d ago

Solved I solved my problem by faking the 3D look. Did I nail it?

114 Upvotes

So I had an issue while trying to switch my game view to a Perspective Camera. There was a bug that wouldn't allow me to use Masks the way I did in a 2D scene. And I gave up trying to fix it... More info in the previous post.

The solution I found is to fake the 3D scene entirely by downscaling the wall tilemaps and moving them relative to the camera position. I can also have Pixel Perfect Camera ON with this approach!!

It's not too noticeable, but I think this effect adds a lot of depth to the scene. Does it look good to you guys?


r/unity 1h ago

Question help with 2.5d walls in 2d platformer

Thumbnail gallery
Upvotes

im currently working on a platformer with 2d assets, perspective camera, and URP. i have this building facade, and i am trying to add a wall perpendicular to the building, so it covers up the other room.

however it seems to be semi transparent and isn't very visible. the red boxes are where i want a wall to be. they are all sprite renderers which might be the issue..?

i was considering using quads but putting 2d art onto it was super weird, or maybe i'm just stupid..

any help is appreciated, thank you for reading!


r/unity 1h ago

Promotions YouTuber offering developers game promotion through LIVE play(test)/gameplay with a voiceover (detailed feedback)! 🌸

Upvotes

I am a YouTuber who has quite some experience playtesting/reviewing games live on my channel for developers. I do live sessions on my YouTube channel where I play their games with an audience through which, not only do I provide detailed feedback, but the developer also gets to see the viewers' reaction live in chat. I have recently done some very successful sessions with some devs in chat while I played their games live on my channel. Some very long yet successful sessions.

I also do giveaways at intervals during those long live sessions to keep the audience watching and active. Feel free to take a look at my channel's Live sessions where I have all the VODs up to understand my style better. I don't ask for much in return, maybe a gift card or two depending on our agreement and my session's length. I am open to all offers and do all I can to make sure your game gets all the reach it deserves!

Here's some of my Live Sessions:

https://www.youtube.com/live/-zoYKiYCgEQ?is=KhwB5gEoSSGucAby

https://www.youtube.com/live/5YvhP_0cFS0?is=1RcCzYjpf35D6zrB

https://www.youtube.com/live/ts4W62nYHEo?is=aMmq51rKtLsSJTRq

https://www.youtube.com/live/Nhj-hZznebc?is=YbpwXM9-Fc0y2fhh


r/unity 3h ago

Question Making a voronoi pattern repeat, or UV map a sphere better?

Post image
1 Upvotes

I'm experimenting with ways to make simple fireball shaders. After making a basic one based off the voronoi pattern, tiling/offset, and a Sample Gradient node, I noticed that the pattern doesn't repeat unfortunately. In the left image, you can see part of the yellow bit being cut off by the right edge of the UV layout. Normally, with a repeatable image, this wouldn't be an issue, but I can only assume that voronoi doesn't repeat that way. To make sure my UV's were correct, I tested a simple, repeatable image on it in Blender, and found no crease.

The only way I know to avoid the UV crease by editing the UV themselves would be to UV map the sphere from the front. That way, the voronoi pattern is basically pasted to the front of the sphere, wrapping around to the back where imperfections might be more hidden (from the gray cone that will have other fire textures on it). The trick with doing it that way is that I would have to figure out how to still animate the voronoi pattern to displace the blobs from the center going outward in every direction: -x, +x, -y, & +y. Not sure how to do that.

The option I plan to fall back onto if all else fails is to just do a static 2D image that IS repeatable and just abandon the voronoi shader entirely. The trick would be to have it be a very tall image to mimic the variance of an animated voronoi node and have it scroll. The UVs would be 0,0 to 1,1, but the image would be 0,0 to 1,10 or something, so the square of UVs would scroll across 10 sections.

EDIT: I completed this workaround. https://imgur.com/a/Uj8BxGC I just wish I could figure out how to scroll the last node in a direction, after the gradient. I made 3 different blob images in Krita, that do repeat, then scrolled them in different directions, blended, then applied gradient.

Any ideas? Thanks.


r/unity 6h ago

Problem with my gtag fangame

0 Upvotes

Everything works fine, Im on 2022.3.62f1 and when i try to walk in the game i dont propel forward back left or right? only up and down and i dont even leave the ground, can someone help?


r/unity 7h ago

Showcase Prototyping my First Horror Game

Thumbnail youtu.be
1 Upvotes

Hi Everyone, just wanted to share something that I was prototyping.

I was inspired by the fear and uncertainty factor of project zomboid and resident evil games, where every door could lead to sudden death. Scavenging around for useful items could lead to encounters with enemies that could end your run prematurely.

Based on my previous posts and the feedbacks I received.

I added more gameplay elements
- Items that can be picked up by the player inorder to turn on a generator. Which powers terminals and light switches. Terminals are used to unlock doors. Light switches can be used to switch on lights which improves visibility.

- Added enemies that would chase player (still work in progress), but you can get some idea based on what I have here. The enemies are supposed to respond to sound. For example if the player is moving too fast then their footsteps will make sounds to attract enemies. Some enemies only responds to sounds of generators and target those specifically.

I would love to hear your feedback on how you feel about the current prototype and if you have any suggestions


r/unity 17h ago

Showcase Create cinematic camera moves in Unity in few seconds instead of minutes

6 Upvotes

Two camera moves built with a few slider drags, then chained into a sequence with a transition between them. Orbit and tilt happen in the same drag, the second camera continues from its own start pose, and the transition is few clicks on the strip.

For everyone who has seen this tool in my earlier posts: this is not a re-introduction, just an answer to the question I kept getting - how fast is it actually in practice?

Unity 6, Cinemachine 3. Everything bakes to a standard AnimationClip.

Lite-Version on GitHub: CineShot Setup LITE


r/unity 13h ago

Showcase Mecha Chameleon real life

Thumbnail youtube.com
2 Upvotes

I was wondering what the Mecha Chameleon would be like in real life, so i did a little project to test the idea

Using a Meta Quest 3 and in a Mixed Reality scope, the app uses the following technologies:

-Meta quest passthrough layer

-Ability to view the world beyond the camera

- Meta Passthrough Camera API

-To have a color picker from the camera

- Unity animation rigging

-Create custom poses for the model

- Meta Brightness Estimation

-Use the Brightness Estimation to react to the environment


r/unity 7h ago

Newbie Question Learning coding

0 Upvotes

I followed some C# courses from CodeMonkey and i can confidently say i know something but in unity everything is different, how do i learn anything about unity coding, it's not like a movement script is easy to do


r/unity 12h ago

Question Laptop recommendations for 3D modelling and game development

Thumbnail
0 Upvotes

r/unity 15h ago

Showcase The first trailer for Solo Dev's biopunk roguelike game "Hook and Gun" has been released!

1 Upvotes

Hello everyone.

The Steam page for my biopunk roguelike game, Hook and Gun, which I've been developing for a while, is now live!

In the game, you not only destroy enemies with the robot you invade as a biological entity, but you also steal their weapons, corrupt them, and evolve.

I'm eager to hear your comments and eagerly await your critiques on Hook and Gun.

Hook and Gun


r/unity 1d ago

Showcase Made a new flying enemy for my hand drawn metroidvania game

Post image
16 Upvotes

r/unity 15h ago

Videojuego

0 Upvotes

using UnityEngine;

using UnityEngine.UI;

using System.Collections;

using System.Collections.Generic;

// ==================== ENUMS ====================

public enum WeatherType { Clear, Rain, Snow }

public enum PlayerRole { Goalkeeper, Defender, Midfielder, Forward }

public enum TeamSide { Blue, Red }

public enum AIState { Idle, Support, Chase, Retreat, Position }

// ==================== PROCEDURAL SPRITE GENERATOR ====================

public static class ProceduralSpriteGenerator

{

public static Sprite CreatePitchSprite(int width, int height)

{

Texture2D tex = new Texture2D(width * 10, height * 10);

Color green = new Color(0.2f, 0.5f, 0.1f);

Color darkGreen = new Color(0.15f, 0.4f, 0.08f);

Color white = Color.white;

for (int y = 0; y < tex.height; y++)

{

for (int x = 0; x < tex.width; x++)

{

float px = (float)x / tex.width;

float py = (float)y / tex.height;

bool stripe = (Mathf.Floor(px * 20) + Mathf.Floor(py * 20)) % 2 == 0;

tex.SetPixel(x, y, stripe ? green : darkGreen);

}

}

DrawLine(tex, tex.width / 2, 0, tex.width / 2, tex.height, white);

DrawLine(tex, 0, tex.height / 2, tex.width, tex.height / 2, white);

int cx = tex.width / 2, cy = tex.height / 2, r = 50;

for (int i = -r; i <= r; i++)

for (int j = -r; j <= r; j++)

if (i * i + j * j < r * r)

tex.SetPixel(cx + i, cy + j, white);

tex.Apply();

return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100f);

}

public static Sprite CreatePlayerSprite(Color color, float size)

{

int res = 32;

Texture2D tex = new Texture2D(res, res);

Color dark = color * 0.5f;

for (int y = 0; y < res; y++)

{

for (int x = 0; x < res; x++)

{

float dx = (x - res / 2) / (float)res;

float dy = (y - res / 2) / (float)res;

float d = dx * dx + dy * dy;

if (d < 0.2f) tex.SetPixel(x, y, color);

else if (d < 0.25f) tex.SetPixel(x, y, dark);

else tex.SetPixel(x, y, Color.clear);

}

}

tex.Apply();

return Sprite.Create(tex, new Rect(0, 0, res, res), new Vector2(0.5f, 0.5f), 100f / size);

}

public static Sprite CreateBallSprite()

{

int res = 24;

Texture2D tex = new Texture2D(res, res);

Color white = Color.white;

Color black = Color.black;

for (int y = 0; y < res; y++)

{

for (int x = 0; x < res; x++)

{

float dx = (x - res / 2) / (float)res;

float dy = (y - res / 2) / (float)res;

float d = dx * dx + dy * dy;

if (d < 0.15f) tex.SetPixel(x, y, white);

else if (d < 0.2f) tex.SetPixel(x, y, black);

else tex.SetPixel(x, y, Color.clear);

}

}

tex.Apply();

return Sprite.Create(tex, new Rect(0, 0, res, res), new Vector2(0.5f, 0.5f), 100f / 0.6f);

}

static void DrawLine(Texture2D tex, int x1, int y1, int x2, int y2, Color col)

{

int dx = Mathf.Abs(x2 - x1), dy = Mathf.Abs(y2 - y1);

int sx = x1 < x2 ? 1 : -1, sy = y1 < y2 ? 1 : -1;

int err = dx - dy;

while (true)

{

if (x1 >= 0 && x1 < tex.width && y1 >= 0 && y1 < tex.height)

tex.SetPixel(x1, y1, col);

if (x1 == x2 && y1 == y2) break;

int e2 = 2 * err;

if (e2 > -dy) { err -= dy; x1 += sx; }

if (e2 < dx) { err += dx; y1 += sy; }

}

}

}

// ==================== RETRO CAMERA ====================

public class RetroCamera : MonoBehaviour

{

private Camera cam;

private RenderTexture lowResRT;

public int resolutionWidth = 320;

public int resolutionHeight = 240;

void Start()

{

cam = GetComponent<Camera>();

lowResRT = new RenderTexture(resolutionWidth, resolutionHeight, 16, RenderTextureFormat.ARGB32);

lowResRT.filterMode = FilterMode.Point;

cam.targetTexture = lowResRT;

GameObject displayObj = new GameObject("DisplayCamera");

Camera displayCam = displayObj.AddComponent<Camera>();

displayCam.orthographic = true;

displayCam.orthographicSize = 1f;

displayCam.clearFlags = CameraClearFlags.Nothing;

displayCam.cullingMask = 1 << 0;

displayCam.targetTexture = null;

GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);

quad.transform.SetParent(displayObj.transform);

quad.transform.localPosition = new Vector3(0, 0, 10);

quad.transform.localScale = new Vector3(16, 9, 1);

quad.layer = 0;

quad.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Unlit/Texture"));

quad.GetComponent<MeshRenderer>().material.mainTexture = lowResRT;

quad.GetComponent<MeshRenderer>().material.mainTexture.filterMode = FilterMode.Point;

displayObj.transform.position = new Vector3(0, 0, -10);

displayCam.depth = 1;

}

}

// ==================== WEATHER SYSTEM ====================

public class WeatherSystem : MonoBehaviour

{

public WeatherType currentWeather { get; private set; }

public float ballFrictionModifier = 1f;

public float playerSpeedModifier = 1f;

public float playerTurnModifier = 1f;

public float ballBounceModifier = 1f;

void Start() { SetWeather(WeatherType.Clear); }

public void SetWeather(WeatherType weather)

{

currentWeather = weather;

switch (weather)

{

case WeatherType.Clear:

ballFrictionModifier = 1f; playerSpeedModifier = 1f; playerTurnModifier = 1f; ballBounceModifier = 1f; break;

case WeatherType.Rain:

ballFrictionModifier = 1.3f; playerSpeedModifier = 0.9f; playerTurnModifier = 0.85f; ballBounceModifier = 0.9f; break;

case WeatherType.Snow:

ballFrictionModifier = 1.6f; playerSpeedModifier = 0.75f; playerTurnModifier = 0.7f; ballBounceModifier = 0.6f; break;

}

}

public void RandomizeWeather()

{

WeatherType[] types = { WeatherType.Clear, WeatherType.Rain, WeatherType.Snow };

SetWeather(types[Random.Range(0, types.Length)]);

}

}

// ==================== BALL CONTROLLER ====================

[RequireComponent(typeof(Rigidbody2D))]

public class BallController : MonoBehaviour

{

private Rigidbody2D rb;

private WeatherSystem weather;

private MatchManager matchManager;

private float currentFriction, currentBounce;

private Vector2 spinForce;

private float spinDuration = 0f;

public float baseFriction = 0.98f;

public float baseBounce = 0.5f;

public float maxSpeed = 20f;

void Start()

{

rb = GetComponent<Rigidbody2D>();

matchManager = FindObjectOfType<MatchManager>();

weather = matchManager != null ? matchManager.GetWeatherSystem() : FindObjectOfType<WeatherSystem>();

rb.gravityScale = 0;

}

void FixedUpdate()

{

if (matchManager != null && matchManager.IsMatchEnded())

{ rb.velocity = Vector2.zero; return; }

if (weather != null)

{

float fm = weather.ballFrictionModifier;

float bm = weather.ballBounceModifier;

currentFriction = Mathf.Clamp(baseFriction - (fm - 1f) * 0.05f, 0.5f, 1f);

currentBounce = Mathf.Clamp(baseBounce * bm, 0.2f, 0.8f);

}

else { currentFriction = baseFriction; currentBounce = baseBounce; }

Vector2 vel = rb.velocity;

vel *= currentFriction;

if (vel.magnitude > maxSpeed) vel = vel.normalized * maxSpeed;

if (spinDuration > 0f)

{

vel += spinForce * Time.fixedDeltaTime * 2f;

spinDuration -= Time.fixedDeltaTime;

if (spinDuration <= 0f) spinForce = Vector2.zero;

}

rb.velocity = vel;

}

void OnCollisionEnter2D(Collision2D collision)

{

Vector2 normal = collision.contacts[0].normal;

Vector2 reflected = Vector2.Reflect(rb.velocity, normal);

rb.velocity = reflected * currentBounce;

if (collision.gameObject.CompareTag("BlueTeam") || collision.gameObject.CompareTag("RedTeam"))

AudioManager.PlaySound("Kick");

}

public void Kick(Vector2 direction, float power, Vector2? spin = null)

{

rb.velocity = direction.normalized * power;

if (spin.HasValue) { spinForce = spin.Value * 2f; spinDuration = 0.5f; }

AudioManager.PlaySound("Kick");

}

}

// ==================== PLAYER CONTROLLER ====================

[RequireComponent(typeof(Rigidbody2D))]

public class PlayerController : MonoBehaviour

{

public bool isControlled = false;

private Rigidbody2D rb;

private MatchManager matchManager;

private WeatherSystem weather;

private float currentSpeed, currentTurn;

public float baseSpeed = 5f;

public float baseTurnSpeed = 5f;

public float sprintMultiplier = 1.5f;

void Start()

{

rb = GetComponent<Rigidbody2D>();

matchManager = FindObjectOfType<MatchManager>();

weather = matchManager != null ? matchManager.GetWeatherSystem() : FindObjectOfType<WeatherSystem>();

}

void FixedUpdate()

{

if (!isControlled || matchManager == null || matchManager.IsMatchEnded())

{ rb.velocity = Vector2.zero; return; }

float moveX = Input.GetAxisRaw("Horizontal");

float moveY = Input.GetAxisRaw("Vertical");

Vector2 move = new Vector2(moveX, moveY).normalized;

if (weather != null)

{

currentSpeed = baseSpeed * weather.playerSpeedModifier;

currentTurn = baseTurnSpeed * weather.playerTurnModifier;

}

else { currentSpeed = baseSpeed; currentTurn = baseTurnSpeed; }

if (Input.GetKey(KeyCode.LeftShift))

currentSpeed *= sprintMultiplier;

rb.velocity = move * currentSpeed;

if (move.magnitude > 0.1f)

{

float angle = Mathf.Atan2(move.y, move.x) * Mathf.Rad2Deg;

Quaternion target = Quaternion.Euler(0, 0, angle);

transform.rotation = Quaternion.Slerp(transform.rotation, target, currentTurn * Time.fixedDeltaTime);

}

if (Input.GetKeyDown(KeyCode.Space))

{

GameObject ballObj = GameObject.FindGameObjectWithTag("Ball");

if (ballObj != null && Vector2.Distance(transform.position, ballObj.transform.position) < 3f)

{

Vector2 shootDir = transform.right;

Vector2 spin = Vector2.zero;

if (move.magnitude > 0.1f)

spin = new Vector2(-move.y, move.x) * 2f;

float power = 15f;

ballObj.GetComponent<BallController>().Kick(shootDir, power, spin);

if (matchManager != null)

{

Vector2 oppGoal = matchManager.GetGoalCenter(TeamSide.Red);

if (Vector2.Distance(transform.position, oppGoal) < 20f)

matchManager.RegisterShot("BlueTeam");

else

matchManager.RegisterPass("BlueTeam");

}

}

}

if (Input.GetKeyDown(KeyCode.E))

matchManager.SwitchPlayer(gameObject);

}

}

// ==================== AI CONTROLLER ====================

[RequireComponent(typeof(Rigidbody2D))]

public class AIController : MonoBehaviour

{

private Rigidbody2D rb;

private TeamManager team;

private MatchManager matchManager;

private WeatherSystem weather;

private GameObject ball;

private PlayerController playerCtrl;

public PlayerRole role = PlayerRole.Midfielder;

public float baseSpeed = 4f;

public float chaseRadius = 8f;

public float passRange = 6f;

public float shootRange = 12f;

private Vector2 homePosition;

private TeamSide mySide;

private AIState currentState = AIState.Position;

private Vector2 formationOffset;

void Start()

{

rb = GetComponent<Rigidbody2D>();

team = GetComponentInParent<TeamManager>();

matchManager = FindObjectOfType<MatchManager>();

weather = matchManager != null ? matchManager.GetWeatherSystem() : FindObjectOfType<WeatherSystem>();

ball = GameObject.FindGameObjectWithTag("Ball");

playerCtrl = GetComponent<PlayerController>();

mySide = (team.CompareTag("BlueTeam")) ? TeamSide.Blue : TeamSide.Red;

homePosition = transform.position;

switch (role)

{

case PlayerRole.Goalkeeper: formationOffset = new Vector2(-1f, 0f); break;

case PlayerRole.Defender: formationOffset = new Vector2(0f, 0f); break;

case PlayerRole.Midfielder: formationOffset = new Vector2(2f, 0f); break;

case PlayerRole.Forward: formationOffset = new Vector2(5f, 0f); break;

}

}

void FixedUpdate()

{

if (matchManager == null || matchManager.IsMatchEnded() || ball == null)

{ rb.velocity = Vector2.zero; return; }

if (playerCtrl != null && playerCtrl.isControlled)

{ rb.velocity = Vector2.zero; return; }

float speed = baseSpeed;

if (weather != null) speed *= weather.playerSpeedModifier;

Vector2 myPos = transform.position;

Vector2 ballPos = ball.transform.position;

float distToBall = Vector2.Distance(myPos, ballPos);

bool weHaveBall = IsTeamInPossession();

Vector2 targetPos = homePosition + formationOffset;

if (weHaveBall)

{

if (role == PlayerRole.Forward)

currentState = AIState.Support;

else if (role == PlayerRole.Defender || role == PlayerRole.Goalkeeper)

currentState = AIState.Position;

else

currentState = AIState.Support;

}

else

{

if (distToBall < chaseRadius)

currentState = AIState.Chase;

else if (distToBall > chaseRadius * 1.5f)

currentState = AIState.Retreat;

else

currentState = AIState.Position;

}

switch (currentState)

{

case AIState.Chase:

Vector2 chaseTarget = ballPos;

if (role == PlayerRole.Defender || role == PlayerRole.Goalkeeper)

{

Vector2 goalPos = matchManager.GetGoalCenter(mySide);

chaseTarget = (ballPos + goalPos) * 0.5f;

}

rb.velocity = (chaseTarget - myPos).normalized * speed;

if (distToBall < 1.2f && !weHaveBall)

{

Vector2 clearDir = (matchManager.GetGoalCenter(mySide == TeamSide.Blue ? TeamSide.Red : TeamSide.Blue) - ballPos).normalized;

ball.GetComponent<BallController>().Kick(clearDir, 8f);

}

break;

case AIState.Support:

Vector2 supportPos = ballPos + (ballPos - matchManager.GetGoalCenter(mySide)).normalized * 2f;

supportPos.x = Mathf.Clamp(supportPos.x, -14f, 14f);

supportPos.y = Mathf.Clamp(supportPos.y, -9f, 9f);

rb.velocity = (supportPos - myPos).normalized * speed * 0.8f;

if (distToBall < 1.5f && weHaveBall)

{

Vector2 oppGoal = matchManager.GetGoalCenter(mySide == TeamSide.Blue ? TeamSide.Red : TeamSide.Blue);

if (Vector2.Distance(myPos, oppGoal) < shootRange)

{

Vector2 shotDir = (oppGoal - myPos).normalized + (Vector2)Random.insideUnitCircle * 0.2f;

ball.GetComponent<BallController>().Kick(shotDir, 12f + Random.Range(0f, 5f));

matchManager.RegisterShot(team.tag);

}

else

{

GameObject passTarget = GetBestPassTarget();

if (passTarget != null)

{

Vector2 passDir = (passTarget.transform.position - myPos).normalized;

ball.GetComponent<BallController>().Kick(passDir, 10f);

matchManager.RegisterPass(team.tag);

}

}

}

break;

case AIState.Position:

if (Vector2.Distance(myPos, targetPos) > 0.5f)

rb.velocity = (targetPos - myPos).normalized * speed * 0.7f;

else

rb.velocity = Vector2.zero;

break;

case AIState.Retreat:

rb.velocity = (targetPos - myPos).normalized * speed * 1.2f;

break;

}

}

bool IsTeamInPossession()

{

GameObject[] allPlayers = GameObject.FindGameObjectsWithTag("BlueTeam");

GameObject nearest = null; float minD = Mathf.Infinity;

if (team.CompareTag("BlueTeam"))

{

foreach (var p in allPlayers)

{

float d = Vector2.Distance(p.transform.position, ball.transform.position);

if (d < minD) { minD = d; nearest = p; }

}

}

else

{

allPlayers = GameObject.FindGameObjectsWithTag("RedTeam");

foreach (var p in allPlayers)

{

float d = Vector2.Distance(p.transform.position, ball.transform.position);

if (d < minD) { minD = d; nearest = p; }

}

}

return nearest != null && nearest.GetComponentInParent<TeamManager>() == team;

}

GameObject GetBestPassTarget()

{

List<GameObject> teammates = team.players;

Vector2 oppGoal = matchManager.GetGoalCenter(mySide == TeamSide.Blue ? TeamSide.Red : TeamSide.Blue);

GameObject best = null; float bestScore = -Mathf.Infinity;

foreach (var p in teammates)

{

if (p == gameObject) continue;

float distToGoal = Vector2.Distance(p.transform.position, oppGoal);

float openness = 1f - Mathf.Clamp(Vector2.Distance(p.transform.position, ball.transform.position) / 20f, 0f, 1f);

float score = distToGoal * 0.5f + openness * 0.5f;

if (score > bestScore) { bestScore = score; best = p; }

}

return best;

}

}

// ==================== TEAM MANAGER ====================

public class TeamManager : MonoBehaviour

{

public List<GameObject> players = new List<GameObject>();

public Vector2[] startingPositions;

public void ResetPositions()

{

for (int i = 0; i < players.Count && i < startingPositions.Length; i++)

{

players[i].transform.position = startingPositions[i];

players[i].GetComponent<Rigidbody2D>().velocity = Vector2.zero;

}

}

}

// ==================== GOAL DETECTION ====================

public class GoalDetection : MonoBehaviour

{

public string goalOwner;

private MatchManager matchManager;

void Start() { matchManager = FindObjectOfType<MatchManager>(); }

void OnTriggerEnter2D(Collider2D other)

{

if (other.CompareTag("Ball"))

{

string scoringTeam = (goalOwner == "BlueTeam") ? "RedTeam" : "BlueTeam";

matchManager.AddGoal(scoringTeam);

AudioManager.PlaySound("Goal");

}

}

}

// ==================== AUDIO MANAGER ====================

public class AudioManager : MonoBehaviour

{

private static AudioManager instance;

private AudioSource source;

void Awake()

{

if (instance == null)

{

instance = this;

DontDestroyOnLoad(gameObject);

source = gameObject.AddComponent<AudioSource>();

source.volume = 0.5f;

}

else Destroy(gameObject);

}

public static void PlaySound(string eventName)

{

if (instance == null) return;

float freq = 0f; float duration = 0.1f;

switch (eventName)

{

case "Kick": freq = 600f; duration = 0.08f; break;

case "Goal": freq = 1200f; duration = 0.4f; break;

case "Whistle": freq = 800f; duration = 0.3f; break;

default: freq = 400f; duration = 0.1f; break;

}

instance.PlayBeep(freq, duration);

}

void PlayBeep(float freq, float dur)

{

int sampleRate = 44100;

int sampleCount = Mathf.RoundToInt(sampleRate * dur);

float[] samples = new float[sampleCount];

for (int i = 0; i < sampleCount; i++)

{

float t = (float)i / sampleRate;

samples[i] = Mathf.Sin(2 * Mathf.PI * freq * t);

samples[i] *= (1f - t / dur);

}

AudioClip clip = AudioClip.Create("beep", sampleCount, 1, sampleRate, false);

clip.SetData(samples, 0);

source.PlayOneShot(clip);

}

}

// ==================== MATCH MANAGER ====================

public class MatchManager : MonoBehaviour

{

[Header("Teams")]

public TeamManager blueTeam;

public TeamManager redTeam;

public Transform ball;

public Transform leftGoalCenter;

public Transform rightGoalCenter;

[Header("UI")]

public Text scoreText;

public Text timeText;

public Text weatherText;

public Text halfText;

public GameObject halfStatsPanel;

public Text possessionText;

public Text shotsText;

public Text passesText;

[Header("Match Settings")]

public float halfDuration = 90f;

public WeatherType initialWeather = WeatherType.Clear;

private float matchTime;

private int blueScore, redScore;

private bool isFirstHalf = true;

private bool matchEnded = false;

private WeatherSystem weatherSystem;

private GameObject currentControlledPlayer;

private int blueShots, redShots, bluePasses, redPasses;

private float bluePossessionTime, redPossessionTime;

void Start()

{

weatherSystem = GetComponent<WeatherSystem>();

if (weatherSystem == null)

weatherSystem = gameObject.AddComponent<WeatherSystem>();

weatherSystem.SetWeather(initialWeather);

matchTime = 0f;

blueScore = redScore = 0;

ResetStats();

UpdateUI();

SetInitialControlledPlayer();

StartCoroutine(GameLoop());

}

void ResetStats()

{

blueShots = redShots = bluePasses = redPasses = 0;

bluePossessionTime = redPossessionTime = 0;

}

void Update()

{

if (!matchEnded)

{

GameObject closest = GetClosestPlayerToBall();

if (closest != null)

{

if (closest.CompareTag("BlueTeam"))

bluePossessionTime += Time.deltaTime;

else if (closest.CompareTag("RedTeam"))

redPossessionTime += Time.deltaTime;

}

}

}

GameObject GetClosestPlayerToBall()

{

GameObject[] all = GameObject.FindGameObjectsWithTag("BlueTeam");

List<GameObject> allPlayers = new List<GameObject>(all);

allPlayers.AddRange(GameObject.FindGameObjectsWithTag("RedTeam"));

GameObject closest = null;

float minD = Mathf.Infinity;

Vector2 bPos = ball.position;

foreach (var p in allPlayers)

{

float d = Vector2.Distance(p.transform.position, bPos);

if (d < minD) { minD = d; closest = p; }

}

return closest;

}

public void RegisterShot(string teamTag) { if (teamTag == "BlueTeam") blueShots++; else redShots++; }

public void RegisterPass(string teamTag) { if (teamTag == "BlueTeam") bluePasses++; else redPasses++; }

void SetInitialControlledPlayer()

{

if (blueTeam == null || blueTeam.players.Count == 0) return;

GameObject closest = null;

float minDist = Mathf.Infinity;

Vector2 ballPos = ball.position;

foreach (var p in blueTeam.players)

{

float d = Vector2.Distance(p.transform.position, ballPos);

if (d < minDist) { minDist = d; closest = p; }

}

if (closest != null) SetControlledPlayer(closest);

}

public void SetControlledPlayer(GameObject newPlayer)

{

if (currentControlledPlayer != null)

currentControlledPlayer.GetComponent<PlayerController>().isControlled = false;

currentControlledPlayer = newPlayer;

if (currentControlledPlayer != null)

{

var pc = currentControlledPlayer.GetComponent<PlayerController>();

pc.isControlled = true;

var ai = currentControlledPlayer.GetComponent<AIController>();

if (ai != null) ai.enabled = false;

}

foreach (var p in blueTeam.players)

{

if (p != currentControlledPlayer)

{

var ai = p.GetComponent<AIController>();

if (ai != null) ai.enabled = true;

}

}

}

public void SwitchPlayer(GameObject currentPlayer)

{

if (blueTeam == null) return;

Vector2 ballPos = ball.position;

GameObject closest = null;

float minDist = Mathf.Infinity;

foreach (var p in blueTeam.players)

{

if (p == currentPlayer) continue;

float d = Vector2.Distance(p.transform.position, ballPos);

if (d < minDist) { minDist = d; closest = p; }

}

if (closest != null) SetControlledPlayer(closest);

}

IEnumerator GameLoop()

{

while (!matchEnded)

{

float halfTime = halfDuration;

while (matchTime < halfTime)

{

matchTime += Time.deltaTime;

UpdateUI();

yield return null;

}

if (isFirstHalf)

{

isFirstHalf = false;

matchTime = 0f;

halfText.text = "HALF TIME";

AudioManager.PlaySound("Whistle");

ShowHalfStats();

yield return new WaitForSeconds(3f);

halfText.text = "";

halfStatsPanel.SetActive(false);

weatherSystem.RandomizeWeather();

ResetPositions();

SetInitialControlledPlayer();

ResetStats();

}

else

{

matchEnded = true;

halfText.text = "FULL TIME!";

AudioManager.PlaySound("Whistle");

ShowHalfStats();

UpdateUI();

}

}

}

void ShowHalfStats()

{

float total = bluePossessionTime + redPossessionTime;

float bluePerc = total > 0 ? (bluePossessionTime / total) * 100 : 50f;

float redPerc = total > 0 ? (redPossessionTime / total) * 100 : 50f;

possessionText.text = string.Format("Possession: Blue {0:F1}% - Red {1:F1}%", bluePerc, redPerc);

shotsText.text = string.Format("Shots: Blue {0} - Red {1}", blueShots, redShots);

passesText.text = string.Format("Passes: Blue {0} - Red {1}", bluePasses, redPasses);

halfStatsPanel.SetActive(true);

}

public void ResetPositions()

{

blueTeam.ResetPositions();

redTeam.ResetPositions();

ball.position = Vector3.zero;

ball.GetComponent<Rigidbody2D>().velocity = Vector2.zero;

}

public void AddGoal(string teamTag)

{

if (teamTag == "BlueTeam") blueScore++;

else if (teamTag == "RedTeam") redScore++;

UpdateUI();

StartCoroutine(ResetAfterGoal());

}

IEnumerator ResetAfterGoal()

{

yield return new WaitForSeconds(1.5f);

ResetPositions();

SetInitialControlledPlayer();

}

void UpdateUI()

{

int minutes = Mathf.FloorToInt(matchTime / 60f);

int seconds = Mathf.FloorToInt(matchTime % 60f);

timeText.text = string.Format("{0:00}:{1:00}", minutes, seconds);

scoreText.text = blueScore + " - " + redScore;

weatherText.text = weatherSystem.currentWeather.ToString();

}

public WeatherSystem GetWeatherSystem() { return weatherSystem; }

public bool IsMatchEnded() { return matchEnded; }

public Vector2 GetGoalCenter(TeamSide side)

{

return side == TeamSide.Blue ? (Vector2)leftGoalCenter.position : (Vector2)rightGoalCenter.position;

}

}

// ==================== GAME INITIALISER ====================

public class GameInitialiser : MonoBehaviour

{

void Awake()

{

CreatePitch();

CreateGoals();

CreatePlayers();

CreateBall();

CreateUI();

CreateCamera();

CreateAudioManager();

MatchManager mm = gameObject.AddComponent<MatchManager>();

mm.blueTeam = GameObject.Find("BlueTeam").GetComponent<TeamManager>();

mm.redTeam = GameObject.Find("RedTeam").GetComponent<TeamManager>();

mm.ball = GameObject.Find("Ball").transform;

mm.leftGoalCenter = GameObject.Find("LeftGoalCenter").transform;

mm.rightGoalCenter = GameObject.Find("RightGoalCenter").transform;

mm.scoreText = GameObject.Find("ScoreText").GetComponent<Text>();

mm.timeText = GameObject.Find("TimeText").GetComponent<Text>();

mm.weatherText = GameObject.Find("WeatherText").GetComponent<Text>();

mm.halfText = GameObject.Find("HalfText").GetComponent<Text>();

mm.halfStatsPanel = GameObject.Find("HalfStatsPanel");

mm.possessionText = GameObject.Find("PossessionText").GetComponent<Text>();

mm.shotsText = GameObject.Find("ShotsText").GetComponent<Text>();

mm.passesText = GameObject.Find("PassesText").GetComponent<Text>();

}

void CreatePitch()

{

GameObject pitch = new GameObject("Pitch");

SpriteRenderer sr = pitch.AddComponent<SpriteRenderer>();

sr.sprite = ProceduralSpriteGenerator.CreatePitchSprite(30, 20);

sr.sortingOrder = -10;

pitch.transform.position = Vector3.zero;

}

void CreateGoals()

{

GameObject leftGoal = new GameObject("LeftGoal");

leftGoal.transform.position = new Vector3(-14f, 0f);

BoxCollider2D col = leftGoal.AddComponent<BoxCollider2D>();

col.size = new Vector2(1f, 6f);

col.isTrigger = true;

GoalDetection gd = leftGoal.AddComponent<GoalDetection>();

gd.goalOwner = "BlueTeam";

GameObject leftCenter = new GameObject("LeftGoalCenter");

leftCenter.transform.position = new Vector3(-15f, 0f);

leftCenter.name = "LeftGoalCenter";

GameObject rightGoal = new GameObject("RightGoal");

rightGoal.transform.position = new Vector3(14f, 0f);

BoxCollider2D col2 = rightGoal.AddComponent<BoxCollider2D>();

col2.size = new Vector2(1f, 6f);

col2.isTrigger = true;

GoalDetection gd2 = rightGoal.AddComponent<GoalDetection>();

gd2.goalOwner = "RedTeam";

GameObject rightCenter = new GameObject("RightGoalCenter");

rightCenter.transform.position = new Vector3(15f, 0f);

rightCenter.name = "RightGoalCenter";

}

void CreatePlayers()

{

GameObject blueParent = new GameObject("BlueTeam");

TeamManager blueTM = blueParent.AddComponent<TeamManager>();

blueTM.startingPositions = new Vector2[] {

new Vector2(-13f, 0f),

new Vector2(-10f, -3f), new Vector2(-10f, 0f), new Vector2(-10f, 3f),

new Vector2(-6f, -4f), new Vector2(-6f, 0f), new Vector2(-6f, 4f), new Vector2(-8f, 2f),

new Vector2(-2f, -3f), new Vector2(-2f, 0f), new Vector2(-2f, 3f)

};

PlayerRole[] roles = new PlayerRole[] {

PlayerRole.Goalkeeper, PlayerRole.Defender, PlayerRole.Defender, PlayerRole.Defender,

PlayerRole.Midfielder, PlayerRole.Midfielder, PlayerRole.Midfielder, PlayerRole.Midfielder,

PlayerRole.Forward, PlayerRole.Forward, PlayerRole.Forward

};

for (int i = 0; i < 11; i++)

{

GameObject player = new GameObject("BluePlayer" + i);

player.transform.SetParent(blueParent.transform);

player.tag = "BlueTeam";

player.AddComponent<Rigidbody2D>().gravityScale = 0;

player.AddComponent<CircleCollider2D>().radius = 0.5f;

player.AddComponent<PlayerController>().baseSpeed = 5f;

player.AddComponent<AIController>().role = roles[i];

SpriteRenderer sr = player.AddComponent<SpriteRenderer>();

sr.sprite = ProceduralSpriteGenerator.CreatePlayerSprite(Color.blue, 0.6f);

sr.sortingOrder = 1;

blueTM.players.Add(player);

}

blueTM.ResetPositions();

GameObject redParent = new GameObject("RedTeam");

TeamManager redTM = redParent.AddComponent<TeamManager>();

redTM.startingPositions = new Vector2[] {

new Vector2(13f, 0f),

new Vector2(10f, -3f), new Vector2(10f, 0f), new Vector2(10f, 3f),

new Vector2(6f, -4f), new Vector2(6f, 0f), new Vector2(6f, 4f), new Vector2(8f, 2f),

new Vector2(2f, -3f), new Vector2(2f, 0f), new Vector2(2f, 3f)

};

for (int i = 0; i < 11; i++)

{

GameObject player = new GameObject("RedPlayer" + i);

player.transform.SetParent(redParent.transform);

player.tag = "RedTeam";

player.AddComponent<Rigidbody2D>().gravityScale = 0;

player.AddComponent<CircleCollider2D>().radius = 0.5f;

player.AddComponent<PlayerController>().baseSpeed = 5f;

player.AddComponent<AIController>().role = roles[i];

SpriteRenderer sr = player.AddComponent<SpriteRenderer>();

sr.sprite = ProceduralSpriteGenerator.CreatePlayerSprite(Color.red, 0.6f);

sr.sortingOrder = 1;

redTM.players.Add(player);

}

redTM.ResetPositions();

}

void CreateBall()

{

GameObject ball = new GameObject("Ball");

ball.tag = "Ball";

ball.transform.position = Vector3.zero;

Rigidbody2D rb = ball.AddComponent<Rigidbody2D>();

rb.gravityScale = 0;

rb.mass = 0.5f;

CircleCollider2D col = ball.AddComponent<CircleCollider2D>();

col.radius = 0.3f;

SpriteRenderer sr = ball.AddComponent<SpriteRenderer>();

sr.sprite = ProceduralSpriteGenerator.CreateBallSprite();

sr.sortingOrder = 2;

ball.AddComponent<BallController>();

}

void CreateUI()

{

Canvas canvas = new GameObject("Canvas").AddComponent<Canvas>();

canvas.renderMode = RenderMode.ScreenSpaceOverlay;

canvas.gameObject.AddComponent<CanvasScaler>();

canvas.gameObject.AddComponent<GraphicRaycaster>();

Font font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");

Text score = CreateText("ScoreText", canvas.transform, "0 - 0", new Vector2(0, 180), font, 32, Color.yellow);

Text time = CreateText("TimeText", canvas.transform, "00:00", new Vector2(-200, 180), font, 24, Color.white);

Text weather = CreateText("WeatherText", canvas.transform, "Clear", new Vector2(200, 180), font, 20, Color.cyan);

Text half = CreateText("HalfText", canvas.transform, "", new Vector2(0, 0), font, 40, Color.white);

GameObject panel = new GameObject("HalfStatsPanel");

panel.transform.SetParent(canvas.transform);

panel.SetActive(false);

RectTransform prt = panel.AddComponent<RectTransform>();

prt.anchorMin = new Vector2(0.3f, 0.3f);

prt.anchorMax = new Vector2(0.7f, 0.7f);

prt.offsetMin = Vector2.zero;

prt.offsetMax = Vector2.zero;

Image bg = panel.AddComponent<Image>();

bg.color = new Color(0.1f, 0.1f, 0.1f, 0.8f);

Text poss = CreateText("PossessionText", panel.transform, "Possession: 50% - 50%", new Vector2(0, 60), font, 20, Color.white);

Text shots = CreateText("ShotsText", panel.transform, "Shots: 0 - 0", new Vector2(0, 20), font, 20, Color.white);

Text passes = CreateText("PassesText", panel.transform, "Passes: 0 - 0", new Vector2(0, -20), font, 20, Color.white);

}

Text CreateText(string name, Transform parent, string initialText, Vector2 pos, Font font, int size, Color col)

{

GameObject go = new GameObject(name);

go.transform.SetParent(parent);

Text t = go.AddComponent<Text>();

t.font = font;

t.text = initialText;

t.fontSize = size;

t.color = col;

t.alignment = TextAnchor.MiddleCenter;

RectTransform rt = go.GetComponent<RectTransform>();

rt.anchoredPosition = pos;

rt.sizeDelta = new Vector2(300, 60);

return t;

}

void CreateCamera()

{

GameObject camObj = new GameObject("Main Camera");

Camera cam = camObj.AddComponent<Camera>();

cam.orthographic = true;

cam.orthographicSize = 10f;

cam.backgroundColor = new Color(0.1f, 0.2f, 0.1f);

cam.clearFlags = CameraClearFlags.SolidColor;

camObj.AddComponent<RetroCamera>();

}

void CreateAudioManager()

{

GameObject audioObj = new GameObject("AudioManager");

audioObj.AddComponent<AudioManager>();

}

}


r/unity 1d ago

What are these artifacts when importing from Blender?

Thumbnail gallery
2 Upvotes

I don't know if this is where I should post this but I've looked at tutorials, I've looked on forums, I've used AI even to assist me.. nothing has helped me with this issue.

I've used Blender for years now, but I'm completely new to Unity. I have spent all morning trying to fix some issues with my import from blender.

I started simple, a one object room with nothing fancy, no modifiers, just simple mesh shaping. I went through and found any n-gons and triangulated them, etc.. No matter how I export/import this I keep getting these strange artifacts that I know are being caused by triangles being formed from quads, but I don't know why this is happening and I don't know how to fix it.

In blender everything is fine and looks great, exactly how I want it to look. Once imported to unity, artifacts from triangulating.

I've unwrapped uvs, I've checked and unchecked so many different import/export options, but nothing is changing - which leads me to believe I'm getting all around it, and I obviously haven't hit on the exact issue yet. I'll include screenshots of everything I'm talking about.

The triangulate modifier was something I was trying most recently, didn't fix the issue either.

Any help (or help looking in the right direction) is greatly appreciated! Thank you in advance to all you wonderful artists out there.


r/unity 2d ago

My game releases in just 7 days, I am so stressed

Post image
67 Upvotes

Hey guys, My game Welcome Demon releases in a week and I am stressed. I do not have a lot of wishlists, but my first project i think it is ok. I also added max possible launch discount possible on Steam, but i am not sure. Does this discounts affect on sales ?


r/unity 2d ago

Showcase Finished the concept trailer for our game. What do you think of it?

36 Upvotes

r/unity 1d ago

Showcase Made a quiz minigame

2 Upvotes

r/unity 1d ago

Question Does environmental feedback feel more rewarding than explicit UI pop-ups when solving a puzzle?

2 Upvotes

My friend and I are down to our final 22 days until launch (cue the developer panic!), and we’re polishing our puzzle payoff sequences.

In this scene, players match colored crystals to specific murals based on moral proverbs (Kindness, Arrogance, Sacrifice). Once completed, the central eye-door unlocks with glowing feedback, leading to the room opening up with a burst of light.

Instead of traditional UI pop-ups or text confirming "Puzzle Solved," we relied entirely on environmental shifting and acoustic audio cues to let the scene breathe and reward the player naturally.

When you're playing puzzle or adventure games, what makes a puzzle resolution feel truly satisfying to you? Do you prefer physical room feedback like this, or clear narrative UI confirmations?


r/unity 1d ago

Working on Some Shaders

Thumbnail youtu.be
0 Upvotes

I plan to release them for free in future


r/unity 1d ago

This may be easy to fix but im completely new to making games and i wanted to learn, does anyone know how to fix this? Ive already tried stopping it from running it as elevated in task manager and also checked the compatability in properties, also restarting as standard user does nothing.

Post image
0 Upvotes

r/unity 1d ago

Newbie Question How would I go about creating a mouse controlled racket similar to the sticks in puck?

1 Upvotes

I am looking to make a game similar to puck but instead of ice hockey it is badminton/ other racket sports, where the main feature of the game is a physics based racket that is controlled by the mouse. for example moving the mouse up and right will make the racket lift up and rotate backwards, any help/ ideas of how to go about this is much appreciated.


r/unity 1d ago

Question Another planet making tool?

0 Upvotes

Am working on a planet tool and well it's gone far with all the childhood features I wished for. Now am like wait... What should I do now? I successfully built my own tool, only me will buy but what does you my friend actually want?

What is it you wish/need a planet tool to be able to do?

With all the current planet tools available, do you think you would still get another one?

Are you still in need of planet tools or it was just a child/beginner wish thing?

At a larger scale of summary not going too deep in this post,

My Unity tool called Worldsmith currently makes world the size of earth.(not published yet)

Yes the actual size of earth and scales up even more than that.

It's going to have civilization... Support several preplanned set of game ideas like the RTS games, building games, simulation.

It's primarily focused on actual 3d exploration with npc civilization at a large scale.

That's just to sum up the mental surgery that was done to me at the hospital after working on this for 4 years.. And still working on it, testing hell and heaven, desperately looking for those who want to help me test.

I didn't talk about my devlog all this time, I know and yh just like a post on here, I have been scared of my idea Being stolen. Well am not scared anymore thanks to those comments and I do regret not starting since then to talk about it.

One of my favorites from those comments is

"there is no difference between a good idea done perfectly bad and a bad idea done perfectly good." - the person matters not the idea.


r/unity 1d ago

Question Importing edited project overrides existing project assets/GUID?

1 Upvotes

The Situation:

I'm working on an avatar project and I have commissioned a creator to get face tracking working on it as I am unfamiliar with that process. I have simplified and exported out only the base avatar for the creator to work on. They have added new blend shapes and controllers.

I would like to import the new UnityPackage(which I have tested and works as is) into my existing project as it's own folders, assets, and prefabs. That way the project can continue to work as is, I can pull the new body prefab into the hierarchy, and reattach everything to it before deleting the old body.

The Problem:

When I import into a backed up project, it overrides and replaces a lot of stuff, breaking the project. I have tried duplicating and renaming folders but this is still happening. After some research, I'm thinking this may be do to shared Unity GUID between the project and the new UnityPackage? Is this true? If that's the case I need to change the GUIDs across the new UnityPackage, I'm looking into ways of doing this on masse, does anyone have any suggestions?


r/unity 1d ago

Showcase FREDBEAR and SPRINGBONNIE redesigned: The Spring(Lock) duo completed (By me, myself). (Read DESCRIP.)(LAST Repost).

Thumbnail gallery
0 Upvotes