Adding trick spawn and movement to Experiment scene
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
# GGJ2026 Agent Notes
|
||||
|
||||
These notes are for coding agents working in this repo. Keep them short, actionable, and up to date.
|
||||
|
||||
## Project Overview
|
||||
- Unity project (2D). Main code in `Assets/Scripts/`.
|
||||
- Input uses Unity Input System with `Assets/InputSystem_Actions.inputactions`.
|
||||
- Scene of interest: `Assets/Scenes/Level1.unity`.
|
||||
|
||||
## Input/Controllers
|
||||
- Player controllers are `PlayerPlatformerController` and `PlayerPickupController`.
|
||||
- Each controller instantiates its own `InputActionAsset` and can filter to a specific device.
|
||||
- Device filtering is based on:
|
||||
- `controlSchemeName == "Gamepad"` and/or
|
||||
- `gamepadIndex >= 0`.
|
||||
- When no matching gamepad is available, controllers ignore input until the device appears.
|
||||
- Gamepad index inference:
|
||||
- `actionMapName = Player` -> index 0
|
||||
- `actionMapName = Player2/Player3/...` -> index (N-1)
|
||||
- If you add/rename action maps, update inference or set `gamepadIndex` explicitly.
|
||||
|
||||
## Level1 Scene Notes
|
||||
- Player 2/3/4 are placed directly in the scene and set to Gamepad.
|
||||
- Current expected indices:
|
||||
- Player2 -> `gamepadIndex: 0`
|
||||
- Player3 -> `gamepadIndex: 1`
|
||||
- Player4 -> `gamepadIndex: 2`
|
||||
- If you want a 4th controller player, set `gamepadIndex: 3` and ensure `controlSchemeName: Gamepad`.
|
||||
|
||||
## Prefabs
|
||||
- `Assets/Prefabs/Player.prefab` defaults to `controlSchemeName: Keyboard&Mouse` and `gamepadIndex: -1`.
|
||||
- If you instantiate players at runtime, set `gamepadIndex` and `controlSchemeName` per player.
|
||||
|
||||
## Editing Tips
|
||||
- Use `rg` for searches (`rg -n "term" Assets`).
|
||||
- Prefer `apply_patch` for small edits.
|
||||
- Avoid touching `Library/`, `Temp/`, and `Logs/`.
|
||||
+58
-66
@@ -1,6 +1,6 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &4063493560390081740
|
||||
--- !u!1 &700000000
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
@@ -8,12 +8,11 @@ GameObject:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4813753125575581197}
|
||||
- component: {fileID: 417219162817149911}
|
||||
- component: {fileID: 3710467127740942334}
|
||||
- component: {fileID: 6722296303968501955}
|
||||
- component: {fileID: 493370774516464490}
|
||||
- component: {fileID: 8358140610337579774}
|
||||
- component: {fileID: 700000001}
|
||||
- component: {fileID: 700000002}
|
||||
- component: {fileID: 700000003}
|
||||
- component: {fileID: 700000004}
|
||||
- component: {fileID: 700000005}
|
||||
m_Layer: 0
|
||||
m_Name: Trick
|
||||
m_TagString: Untagged
|
||||
@@ -21,29 +20,29 @@ GameObject:
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4813753125575581197
|
||||
--- !u!4 &700000001
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4063493560390081740}
|
||||
m_GameObject: {fileID: 700000000}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -2.684, y: 1.03, z: 0}
|
||||
m_LocalScale: {x: 0.411, y: 0.4437, z: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!212 &417219162817149911
|
||||
--- !u!212 &700000002
|
||||
SpriteRenderer:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4063493560390081740}
|
||||
m_GameObject: {fileID: 700000000}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
@@ -83,49 +82,52 @@ SpriteRenderer:
|
||||
m_GlobalIlluminationMeshLod: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_SortingOrder: 2
|
||||
m_MaskInteraction: 0
|
||||
m_Sprite: {fileID: -9095717837082945937, guid: 207ee8102dd4143d288186ef0be518ee, type: 3}
|
||||
m_Color: {r: 0.735849, g: 0, b: 0, a: 1}
|
||||
m_Sprite: {fileID: 8755586062601758735, guid: 8530a46c93e30d54cb57c68ae0a1b06e, type: 3}
|
||||
m_Color: {r: 0.9, g: 0.35, b: 0.9, a: 1}
|
||||
m_FlipX: 0
|
||||
m_FlipY: 0
|
||||
m_DrawMode: 0
|
||||
m_Size: {x: 1, y: 2}
|
||||
m_Size: {x: 1, y: 1}
|
||||
m_AdaptiveModeThreshold: 0.5
|
||||
m_SpriteTileMode: 0
|
||||
m_WasSpriteAssigned: 1
|
||||
m_SpriteSortPoint: 0
|
||||
--- !u!114 &3710467127740942334
|
||||
MonoBehaviour:
|
||||
--- !u!50 &700000003
|
||||
Rigidbody2D:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4063493560390081740}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 246e7020310b45d4d92f3af76f126c12, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TrickController
|
||||
--- !u!114 &6722296303968501955
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4063493560390081740}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 246e7020310b45d4d92f3af76f126c12, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: '::'
|
||||
--- !u!61 &493370774516464490
|
||||
m_GameObject: {fileID: 700000000}
|
||||
m_BodyType: 0
|
||||
m_Simulated: 1
|
||||
m_UseFullKinematicContacts: 0
|
||||
m_UseAutoMass: 0
|
||||
m_Mass: 1
|
||||
m_LinearDamping: 0
|
||||
m_AngularDamping: 0.05
|
||||
m_GravityScale: 0
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_Interpolate: 0
|
||||
m_SleepingMode: 1
|
||||
m_CollisionDetection: 0
|
||||
m_Constraints: 4
|
||||
--- !u!61 &700000004
|
||||
BoxCollider2D:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4063493560390081740}
|
||||
m_GameObject: {fileID: 700000000}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Density: 1
|
||||
@@ -153,42 +155,32 @@ BoxCollider2D:
|
||||
m_UsedByEffector: 0
|
||||
m_CompositeOperation: 0
|
||||
m_CompositeOrder: 0
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Offset: {x: -0.0029773563, y: -0.000000029802322}
|
||||
m_SpriteTilingProperty:
|
||||
border: {x: 0, y: 0, z: 0, w: 0}
|
||||
pivot: {x: 0.5, y: 0.5}
|
||||
oldSize: {x: 1, y: 2}
|
||||
newSize: {x: 1, y: 2}
|
||||
oldSize: {x: 0.15, y: 0.31}
|
||||
newSize: {x: 1, y: 1}
|
||||
adaptiveTilingThreshold: 0.5
|
||||
drawMode: 0
|
||||
adaptiveTiling: 0
|
||||
m_AutoTiling: 0
|
||||
m_Size: {x: 1, y: 2}
|
||||
m_Size: {x: 0.16040364, y: 0.31522292}
|
||||
m_EdgeRadius: 0
|
||||
--- !u!50 &8358140610337579774
|
||||
Rigidbody2D:
|
||||
serializedVersion: 5
|
||||
--- !u!114 &700000005
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4063493560390081740}
|
||||
m_BodyType: 0
|
||||
m_Simulated: 1
|
||||
m_UseFullKinematicContacts: 0
|
||||
m_UseAutoMass: 0
|
||||
m_Mass: 1
|
||||
m_LinearDamping: 0
|
||||
m_AngularDamping: 0.05
|
||||
m_GravityScale: 1
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_Interpolate: 0
|
||||
m_SleepingMode: 1
|
||||
m_CollisionDetection: 0
|
||||
m_Constraints: 0
|
||||
m_GameObject: {fileID: 700000000}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a8cb5c6bd0dd4b8281aec250714b6fc1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
treatTag: Interactable
|
||||
moveSpeed: 3.5
|
||||
targetRefreshInterval: 0.4
|
||||
consumeDistance: 0.35
|
||||
wanderInterval: 1.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c0004e9e01ba3648b75049ead682f94
|
||||
guid: 8bf8957665594a718535d06aba0cdee7
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@@ -2576,6 +2576,53 @@ PrefabInstance:
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: 99cce68fc82caea44b5a140697be00a8, type: 3}
|
||||
--- !u!1 &2100000000
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2100000001}
|
||||
- component: {fileID: 2100000002}
|
||||
m_Layer: 0
|
||||
m_Name: NPC Spawner
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &2100000001
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2100000000}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &2100000002
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2100000000}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 14b0bf07aa1abc44a8ebd00cecacd6f4, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Spawner
|
||||
objectToSpawn: {fileID: 700000000, guid: 8bf8957665594a718535d06aba0cdee7, type: 3}
|
||||
spawnInterval: 6
|
||||
maxAlive: 1
|
||||
--- !u!1660057539 &9223372036854775807
|
||||
SceneRoots:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -2604,3 +2651,4 @@ SceneRoots:
|
||||
- {fileID: 792686806}
|
||||
- {fileID: 1685410085}
|
||||
- {fileID: 375061916}
|
||||
- {fileID: 2100000001}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class Spawner : MonoBehaviour
|
||||
@@ -7,6 +8,9 @@ public class Spawner : MonoBehaviour
|
||||
[SerializeField] private GameObject objectToSpawn;
|
||||
// Time interval between spawns
|
||||
public float spawnInterval = 1f;
|
||||
[SerializeField] private int maxAlive = 0;
|
||||
|
||||
private readonly List<GameObject> spawned = new List<GameObject>();
|
||||
|
||||
void Start()
|
||||
{
|
||||
@@ -21,8 +25,32 @@ public class Spawner : MonoBehaviour
|
||||
{
|
||||
// Wait for the specified interval
|
||||
yield return new WaitForSeconds(spawnInterval);
|
||||
if (objectToSpawn == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (maxAlive > 0 && CountAlive() >= maxAlive)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Spawn the object at the spawner's position and rotation
|
||||
Instantiate(objectToSpawn, transform.position, Quaternion.identity);
|
||||
var instance = Instantiate(objectToSpawn, transform.position, Quaternion.identity);
|
||||
spawned.Add(instance);
|
||||
}
|
||||
}
|
||||
|
||||
private int CountAlive()
|
||||
{
|
||||
for (var i = spawned.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (spawned[i] == null)
|
||||
{
|
||||
spawned.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return spawned.Count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,125 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(Rigidbody2D))]
|
||||
[RequireComponent(typeof(Collider2D))]
|
||||
public class TrickController : MonoBehaviour
|
||||
{
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
[SerializeField] private string treatTag = "Interactable";
|
||||
[SerializeField] private float moveSpeed = 3.5f;
|
||||
[SerializeField] private float targetRefreshInterval = 0.4f;
|
||||
[SerializeField] private float consumeDistance = 0.35f;
|
||||
[SerializeField] private float wanderInterval = 1.2f;
|
||||
|
||||
private Rigidbody2D body;
|
||||
private Transform target;
|
||||
private float nextTargetTime;
|
||||
private Vector2 wanderDirection;
|
||||
private float nextWanderTime;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
body = GetComponent<Rigidbody2D>();
|
||||
body.bodyType = RigidbodyType2D.Dynamic;
|
||||
body.gravityScale = 1f;
|
||||
body.freezeRotation = true;
|
||||
body.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
|
||||
body.interpolation = RigidbodyInterpolation2D.Interpolate;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
private void Update()
|
||||
{
|
||||
if (Time.time >= nextTargetTime)
|
||||
{
|
||||
target = FindNearestTreat();
|
||||
nextTargetTime = Time.time + targetRefreshInterval;
|
||||
}
|
||||
|
||||
if (target == null && Time.time >= nextWanderTime)
|
||||
{
|
||||
wanderDirection = Random.insideUnitCircle.normalized;
|
||||
if (wanderDirection.sqrMagnitude < 0.01f)
|
||||
{
|
||||
wanderDirection = Vector2.right;
|
||||
}
|
||||
nextWanderTime = Time.time + wanderInterval;
|
||||
}
|
||||
|
||||
TryConsumeTreat();
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
Vector2 desiredVelocity;
|
||||
var stopForTreat = false;
|
||||
if (target != null)
|
||||
{
|
||||
var direction = ((Vector2)target.position - (Vector2)transform.position).normalized;
|
||||
desiredVelocity = new Vector2(direction.x * moveSpeed, 0f);
|
||||
stopForTreat = Vector2.Distance(transform.position, target.position) <= consumeDistance;
|
||||
}
|
||||
else
|
||||
{
|
||||
desiredVelocity = new Vector2(wanderDirection.x * (moveSpeed * 0.6f), 0f);
|
||||
}
|
||||
|
||||
var velocity = body.linearVelocity;
|
||||
velocity.x = stopForTreat ? 0f : desiredVelocity.x;
|
||||
body.linearVelocity = velocity;
|
||||
}
|
||||
|
||||
private Transform FindNearestTreat()
|
||||
{
|
||||
var treats = GameObject.FindGameObjectsWithTag(treatTag);
|
||||
if (treats == null || treats.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Transform best = null;
|
||||
var bestDistance = float.MaxValue;
|
||||
var origin = transform.position;
|
||||
for (var i = 0; i < treats.Length; i++)
|
||||
{
|
||||
var candidate = treats[i];
|
||||
if (!candidate.activeInHierarchy)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!candidate.TryGetComponent<Collider2D>(out var collider) || !collider.enabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var distance = Vector2.Distance(origin, candidate.transform.position);
|
||||
if (distance < bestDistance)
|
||||
{
|
||||
bestDistance = distance;
|
||||
best = candidate.transform;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
private void TryConsumeTreat()
|
||||
{
|
||||
var hits = Physics2D.OverlapCircleAll(transform.position, consumeDistance);
|
||||
for (var i = 0; i < hits.Length; i++)
|
||||
{
|
||||
var hit = hits[i];
|
||||
if (hit == null || !hit.CompareTag(treatTag))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Destroy(hit.gameObject);
|
||||
if (target == hit.transform)
|
||||
{
|
||||
target = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 246e7020310b45d4d92f3af76f126c12
|
||||
guid: a8cb5c6bd0dd4b8281aec250714b6fc1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
Reference in New Issue
Block a user