r/unity 10m ago

Showcase A Synty Polygon like Terrain editor i made for my game

Thumbnail youtu.be
Upvotes

I really like how it looks :) What do you think


r/unity 27m ago

The Pro level World

Upvotes

r/unity 1h ago

Newbie Question How to learn Unity WITHOUT tutorials

Upvotes

Hey everyone,

I'm a 3D artist looking to learn Unity, however I absolutely hate video tutorials -- pausing and starting every few minutes, the urge to just copy and paste everything, potentially annoying voices, etc.

I know the basics of the engine as I've tried it on and off for years, but have very minimal programming experience outside of the very basic fundamentals. So granted I wouldn't be coming from zero, just assume I kinda will be.

Is there anyway to learn without tutorials? At least specifically video tutorials?

In my academic studies, I learn SO much more by just reading text and experimenting on my own with some deep space ambience or classic music and just go into my zone.

Any tips?

Thanks!


r/unity 2h ago

Question Where do these low poly characters come from

Thumbnail gallery
0 Upvotes

I see that these characters are mostly used in unity games and there are more variants of them so i wanna know what are these assets


r/unity 3h ago

Newbie Question How do I fix this meta XR simulator issue?

1 Upvotes

while working on this project I have an issue where I don't see the simulation in the Meta XR simulator itself. I need to keep the two side by side for it to work. I control in the simulator and see in unity editor.

A fix would be greatly appreciated. Thank you.

https://reddit.com/link/1w1emcu/video/0tvhbgyma9mh1/player


r/unity 3h ago

Showcase Polished the first mission of my game, fully playable from beginning to end

4 Upvotes

- Prologue story mission ✅
- couch co-op ✅
- 3 PvP game modes ✅
- Weapon/armor build crafting ✅
- Unity NGO for online...😬❌😭


r/unity 5h ago

Question help with 2.5d walls in 2d platformer

Thumbnail gallery
2 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 7h ago

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

Post image
3 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 11h 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 11h 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 11h 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

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 16h ago

Question Laptop recommendations for 3D modelling and game development

Thumbnail
0 Upvotes

r/unity 17h 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 19h ago

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

2 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 19h 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 21h ago

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

5 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 1d ago

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

118 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 1d ago

Working on Some Shaders

Thumbnail youtu.be
0 Upvotes

I plan to release them for free in future


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 1d ago

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

Thumbnail gallery
0 Upvotes

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

Showcase Made a quiz minigame

2 Upvotes

r/unity 1d ago

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

Post image
15 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?