Add practice range: shooting, AK47, intro cinematic, dressed warehouse scene
- PortalTestDestination practice range: Valorant-style hitscan rifle (recoil, spray/bloom, reload, controller support), debug HUD, practice-dummy targets with head/body hitboxes, hit/death/respawn animations, procedural SFX/FX - AK47 model (Quaternius, CC0) held via Animator IK, with fire/reload/equip anims - Intro cinematic (camera shots, title card, target beam-in, GO hand-off) - Scene dressing editor pass: CC0 textures, props, warehouse roof, lighting and post-processing; custom stylized skybox shader - CharacterMovement: camera recoil, shoulder offset, cinematic control lock - Unity CLI pipeline package; plus in-progress chat/Rive/player changes Asset credits: Assets/Models/Props/PROPS_CREDITS.txt (3 CC-BY 3.0 props), Assets/Textures/Range/TEXTURES_LICENSE.txt, Assets/Resources/*/..._LICENSE.txt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c674d76549
commit
5fc9ebf1e6
@@ -0,0 +1,63 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
// Auto-installs the shooting prototype (targets + HitscanShooter) whenever the
|
||||
// PortalTestDestination scene loads, so no scene/prefab edits are needed. If a
|
||||
// ShootingRange is already placed in the scene by hand, the bootstrap does nothing.
|
||||
public class ShootingRange : MonoBehaviour
|
||||
{
|
||||
const string SceneName = "PortalTestDestination";
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
static void RegisterBootstrap()
|
||||
{
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
}
|
||||
|
||||
static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
{
|
||||
if (scene.name != SceneName) return;
|
||||
if (FindAnyObjectByType<ShootingRange>() != null) return;
|
||||
|
||||
var go = new GameObject("ShootingRange");
|
||||
SceneManager.MoveGameObjectToScene(go, scene);
|
||||
go.AddComponent<ShootingRange>();
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (GetComponent<HitscanShooter>() == null)
|
||||
gameObject.AddComponent<HitscanShooter>();
|
||||
|
||||
var targets = SpawnTargets();
|
||||
gameObject.AddComponent<RangeIntroCinematic>().Begin(targets);
|
||||
}
|
||||
|
||||
// Positions match the greybox map from SetupPortalTestDestinationScene: central street
|
||||
// along Z (spawns at z = ±14), buildings at x = ±13, crates at (-2,-4) and (2,4).
|
||||
List<ShootingTarget> SpawnTargets()
|
||||
{
|
||||
var root = new GameObject("Targets").transform;
|
||||
root.SetParent(transform, false);
|
||||
var list = new List<ShootingTarget>();
|
||||
|
||||
// Static bots along the street, visible from either spawn.
|
||||
list.Add(ShootingTarget.Create(root, "Target_Street_1", new Vector3(0f, 0f, 1.5f)));
|
||||
list.Add(ShootingTarget.Create(root, "Target_Street_2", new Vector3(0f, 0f, -1.5f)));
|
||||
list.Add(ShootingTarget.Create(root, "Target_Alley_L1", new Vector3(-6f, 0f, 8f)));
|
||||
list.Add(ShootingTarget.Create(root, "Target_Alley_R1", new Vector3(6f, 0f, 8f)));
|
||||
list.Add(ShootingTarget.Create(root, "Target_Alley_L2", new Vector3(-6f, 0f, -8f)));
|
||||
list.Add(ShootingTarget.Create(root, "Target_Alley_R2", new Vector3(6f, 0f, -8f)));
|
||||
|
||||
// Inside the middle buildings (visible through the street-facing doors).
|
||||
list.Add(ShootingTarget.Create(root, "Target_Building_L", new Vector3(-13f, 0f, 0f)));
|
||||
list.Add(ShootingTarget.Create(root, "Target_Building_R", new Vector3(13f, 0f, 0f)));
|
||||
|
||||
// Strafing bots for tracking practice.
|
||||
list.Add(ShootingTarget.Create(root, "Target_Strafe_N", new Vector3(0f, 0f, 7f), strafeDistance: 3f));
|
||||
list.Add(ShootingTarget.Create(root, "Target_Strafe_S", new Vector3(0f, 0f, -7f), strafeDistance: 3f));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user