Vad spelet är
Urban Cleanup Crew är ett multiplayer-spel i Unity där flera spelare kan gå med i samma room, spawnas in i en bana, plocka upp verktyg, rengöra fläckar och hantera objekt tillsammans. Projektet kombinerar klassiska spelprogrammeringssystem med nätverk.
Spelare hostar eller joinar med party-kod.
Alla spelare hamnar i samma nätverksrum.
Photon skapar player-prefabs i scenen.
Spelare rör sig, plockar upp items och städar.
RPC, ownership och PhotonView håller klienter uppdaterade.
Det viktigaste för nya spelprogrammerare
Ett spelprojekt blir lätt svårt om man försöker förstå allt samtidigt. Tänk istället i system: input, movement, camera, UI, inventory, multiplayer, AI och game rules.
GameObject + Component
I Unity är nästan allt ett GameObject med komponenter. Ett script är en komponent som ger objektet beteende.
Update vs FixedUpdate
Update() passar input och kamera. FixedUpdate() passar physics och Rigidbody-rörelse.
Prefab
En prefab är en återanvändbar mall. Photon kan instansiera prefabs över nätverket.
Raycast
Raycast används för att se vad spelaren tittar på, till exempel dörrar, pickup-items och stains.
Layers och Tags
Layers hjälper raycasts och physics att filtrera objekt. Tags används för exempelvis Player.
State
Booleans som InventoryOpen och HandsAreBusy styr vad spelaren får göra just nu.
Vad Photon är och hur det fungerar
Photon är en multiplayer-tjänst för Unity. I det här projektet används Photon PUN. PUN gör att spelare kan ansluta till samma server, skapa rooms, skicka RPC-anrop, instansiera nätverksobjekt och synka viktiga data.
Master Server
Första steget är att koppla upp spelet mot Photon. När anslutningen är klar kan spelet gå vidare till lobby/room.
PhotonNetwork.ConnectUsingSettings();
Room
Ett room är matchen/lobbyn där spelarna möts. I projektet skapas privata rum med party-kod.
PhotonNetwork.CreateRoom(code, options);
PhotonNetwork.JoinRoom(code);
De viktigaste Photon-begreppen
photonView.IsMine.
Grundregel: låt varje spelare styra sin egen input lokalt, men använd Photon för att visa resultatet för andra spelare.
Därför ser man ofta if (!photonView.IsMine) return; i player-scripts.
Hur voice chat görs med Photon Voice
Photon Voice är ett tillägg till Photon som hanterar mikrofonljud mellan spelare.
I projektet används PhotonVoiceView tillsammans med ett eget script:
VoiceChatController.
På lokal spelare
Den lokala spelarens mikrofon får sända ljud. Voice detection kan aktiveras så att tystnad inte skickas.
voiceView.RecorderInUse.TransmitEnabled = true;
voiceView.RecorderInUse.VoiceDetection = true;
På remote players
Andra spelares objekt ska inte försöka sända från din mikrofon. Därför stängs transmit av på remote objects.
if (!photonView.IsMine)
voiceView.RecorderInUse.TransmitEnabled = false;
För att voice chat ska fungera behöver player-prefaben normalt ha Photon-komponenter, Photon Voice-komponenter och rätt koppling mellan Recorder/Speaker. Scriptet ser till att bara rätt spelare använder mikrofonen.
Player controller
Spelaren styrs av en Rigidbody FPS-controller. Det betyder att movement går genom Unitys physics-system,
medan kameran och input läses i vanliga Update().
Movement
RigidbodyFPSController hanterar walk, run, jump, acceleration, air control och landing dip.
Camera
Musen styr yaw på spelarens rotation och pitch på kameran. När inventory öppnas begränsas kameran.
if (!pv.IsMine) return;
moveInput = new Vector3(
Input.GetAxisRaw("Horizontal"),
0,
Input.GetAxisRaw("Vertical")
).normalized;
Det viktiga här är att remote players inte får läsa din input. De ska bara visas korrekt genom nätverkssync.
Inventory, suitcase och equipment
Spelet har två nivåer av föremålshantering: först läggs objekt i suitcase, sedan kan de flyttas till hotbar/equipment.
Spelaren tittar på ett föremål.
E lägger objektet i suitcase.
Objektet parentas till en ledig slot.
Objektet flyttas till hand slot.
Cleaning-systemet kollar om item är aktivt.
SuitcaseToggle
Öppnar/stänger suitcase med Tab och sätter globala state-flaggor som stoppar movement/interactions.
PlayerEquipmentManager
Hantera hotbar slots, UI-icons, aktiva items och animatorn HoldingItem.
Cleaning-systemet
Det mest tekniskt intressanta systemet är StainNetwork. Det rengör inte bara ett objekt direkt,
utan målar bort alpha från stain-texturen runtime. Det gör att fläcken faktiskt försvinner gradvis där spelaren rengör.
Hur en stain rengörs
- Spelaren håller musknappen.
- En raycast träffar stain.
- Scriptet kontrollerar att spelaren håller ett aktivt cleaning item.
- Brushen tar bort alpha från texturen.
- När tillräckligt mycket alpha är borta räknas stain som clean.
Varför det är bra att lära sig
Det visar hur gameplay kan byggas från flera små system: raycast, material, texture pixels, UI feedback, nätverk och object spawning.
float progress = 1f - (totalAlphaNow / (float)totalAlphaStart);
if (progress >= eraseFractionToClean && !isCleaned)
photonView.RPC(nameof(RPC_CleanStain), RpcTarget.AllBuffered, painterActorNr);
När stain blir clean spawnas en trash bag och stain tas bort. I multiplayer görs detta via Photon så alla spelare ser samma resultat.
Procedural level generation
SimpleLevelGenerator bygger en bana genom att koppla ihop prefabs via Doorway-punkter.
Det är ett tydligt exempel på procedural generation i mindre skala.
Doorways
Varje room/hallway har markers som visar var nya bitar kan kopplas på.
Prefab-val
Generatorn väljer rooms, hallways, unique rooms, elevator eller dead ends.
Overlap check
Physics overlap används för att undvika att nya rum placeras inuti gamla.
Detta är viktigt för elever eftersom det visar att banor inte alltid behöver byggas helt manuellt. Man kan skapa regler och låta koden bygga variation.
Monster och AI
Monster-systemet använder Unity NavMesh. MasterClient kör AI-logiken och skickar animation states till de andra klienterna.
Detection
Monstret hittar närmaste objekt med taggen Player och kontrollerar avståndet.
States
Om spelaren är nära går monstret mot spelaren. Om spelaren är väldigt nära spelas bite-animation.
if (!PhotonNetwork.IsMasterClient) return;
Transform targetPlayer = FindClosestPlayer();
agent.SetDestination(targetPlayer.position);
Det här är en bra multiplayer-princip: låt en auktoritativ klient bestämma AI, annars kan flera datorer ge olika beslut.
Viktigaste scriptsen
Tips till elever som ska börja med spelprogrammering
Börja singleplayer
Bygg movement, camera, pickup och UI lokalt först. Lägg på multiplayer när systemet fungerar.
Synka bara det viktiga
Skicka inte allt över nätverket. Synka position, ägare, animation states och viktiga events.
Använd tydliga prefabs
Player, stains, trash och monster bör vara prefabs med rätt komponenter från början.
Dokumentera states
Multiplayerbuggar blir mycket lättare att felsöka om man vet vem som äger objektet och vilket state det har.
Den viktigaste multiplayer-frågan är alltid: vem bestämmer? I det här projektet bestämmer lokal spelare över sin input, owner bestämmer över sina objekt, och MasterClient bestämmer över globala saker som monster och spawns.