1
0
forked from cgvr/DeltaVR

deltavr multiplayer 2.0

This commit is contained in:
Toomas Tamm
2023-05-08 15:56:10 +03:00
parent 978809a002
commit 07b9b9e2f4
10937 changed files with 2968397 additions and 1521012 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 63448578dbbb7944ba1a093819bf4d4c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Linq;
using _PROJECT.Scripts.Bow;
using FishNet.Object;
using FishNet.Object.Synchronizing;
using TMPro;
using UnityEngine;
using Random = UnityEngine.Random;
public class ArcheryRange : NetworkBehaviour
{
public TMP_Text highScoreText;
public TMP_Text timeLeftText;
public TMP_Text scoreText;
public Transform targetStartPosition;
public Transform targetEndPosition;
public GameObject targetPrefab;
public StartTarget startTarget;
public Vector3 minRandomOffset = new Vector3(0f, -2f, -5f);
public Vector3 maxRandomOffset = new Vector3(0f, 2f, 5f);
public float roundLength = 60f;
public float targetSpawnTime = 3f;
private List<ArcheryTarget> _targets;
[SyncVar]
private float _score;
private float _maxScore;
private float _roundEndTime;
private float _nextTargetTime;
private bool _roundActive;
public override void OnStartServer()
{
base.OnStartServer();
_roundActive = false;
_targets = new List<ArcheryTarget>();
_score = 0;
_maxScore = 0;
_roundEndTime = 0f;
SetHighScoreText("High Score: 0");
}
// Update is called once per frame
void Update()
{
if (!IsServer) return;
if (!_roundActive) return;
if (Time.time >= _roundEndTime)
{
ResetRange();
}
else
{
SetTimeLeftText($"Time Left: {Math.Ceiling((_roundEndTime - Time.time) % 60)}");
if (Time.time >= _nextTargetTime)
{
_nextTargetTime = Time.time + targetSpawnTime;
SpawnTarget();
}
}
}
private void SpawnTarget()
{
if (!IsServer) return;
var randomPos = targetStartPosition.position + new Vector3(
Random.Range(minRandomOffset.x, maxRandomOffset.x),
(float)Math.Round(Random.Range(minRandomOffset.y, maxRandomOffset.y)),
Random.Range(minRandomOffset.z, maxRandomOffset.z));
var target = SpawnTarget(randomPos);
_targets.Add(target);
}
private ArcheryTarget SpawnTarget(Vector3 randomPos)
{
var prefab = Instantiate(targetPrefab, randomPos, Quaternion.identity, null);
ArcheryTarget target = prefab.GetComponent<ArcheryTarget>();
target.endPosition = targetEndPosition.position;
target.addScore = AddScore;
Spawn(prefab);
return target;
}
public void ResetRange()
{
if (!IsServer) return;
foreach (var target in _targets.Where(target => target != null))
{
Despawn(target.gameObject, DespawnType.Pool);
}
_targets = new List<ArcheryTarget>();
if (_maxScore < _score) _maxScore = _score;
_score = 0;
SetHighScoreText($"High Score: {_maxScore}");
startTarget.ShowTarget();
_roundActive = false;
SetTimeLeftText("");
}
public void StartRound()
{
if (!IsServer) return;
_roundEndTime = Time.time + roundLength;
_nextTargetTime = Time.time;
_roundActive = true;
}
public void AddScore(float distance)
{
if (!IsServer) return;
_score += distance;
SetScoreText($"Score: {_score}");
}
[ObserversRpc]
public void SetHighScoreText(string text)
{
highScoreText.text = text;
}
[ObserversRpc]
public void SetScoreText(string text)
{
scoreText.text = text;
}
[ObserversRpc]
public void SetTimeLeftText(string text)
{
timeLeftText.text = text;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 592ba278f86ebec478622d8cf05c309d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
using System;
using _PROJECT.Scripts.Bow;
using _PROJECT.Scripts.Bow.Extra;
using FishNet.Object;
using FishNet.Object.Synchronizing;
using UnityEngine;
using Random = UnityEngine.Random;
public class ArcheryTarget : NetworkBehaviour, IArrowHittable
{
public GameObject pointsText;
[SyncVar]
public Vector3 endPosition;
public float forwardSpeed = 2f;
public Action<float> addScore;
private bool _flipDirection;
private void Awake()
{
_flipDirection = Random.value > 0.5f;
}
// Update is called once per frame
void Update()
{
if (!IsServer) return;
float step = forwardSpeed * Time.deltaTime;
var position = transform.position;
if (Math.Abs(position.x - endPosition.x) < 0.1) Destroy(gameObject);
transform.position = Vector3.MoveTowards(position,
new Vector3(endPosition.x, position.y, position.z), step);
}
public void Hit(Arrow arrow)
{
if (!IsServer) return;
if (arrow == null) return;
var position = transform.position;
float score = (float)Math.Round(Vector3.Distance(position, endPosition));
addScore(score);
GameObject prefab = Instantiate(pointsText, position, Quaternion.Euler(0, 90f, 0), null);
PointsText target = prefab.GetComponent<PointsText>();
target.SetPoints(score);
Spawn(prefab);
Despawn(arrow.gameObject, DespawnType.Pool);
Despawn(gameObject, DespawnType.Pool);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3b311379c72a5ae4b8936e3b7283dd7a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using System.Collections;
using _PROJECT.Multiplayer.NewBow;
using _PROJECT.Scripts.Bow;
using FishNet.Object;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
public class Arrow : XRGrabInteractable
{
private ArrowCaster _caster;
protected override void Awake()
{
base.Awake();
_caster = GetComponent<ArrowCaster>();
}
protected override void OnSelectExited(SelectExitEventArgs args)
{
base.OnSelectExited(args);
if (!_caster.IsServer) return;
Debug.Log("Arrow select exit by " + args.interactorObject);
if (args.interactorObject is not TwoHandedBowNotch notch)
{
Debug.Log("Arrow select exit not notch");
return;
}
Debug.Log("Arrow select exit can release");
_caster.LaunchArrow(notch);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4efde785f55475d4faf016df659306fa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,119 @@
using System.Collections;
using _PROJECT.Multiplayer.NewBow;
using _PROJECT.Scripts.Bow;
using FishNet.Object;
using UnityEngine;
public class ArrowCaster : NetworkBehaviour
{
[SerializeField] private Transform tip;
[SerializeField] private LayerMask layerMask = ~0;
[SerializeField] private float speed = 2000f;
private Vector3 lastPosition = Vector3.zero;
private readonly float _maxLifeTime = 30f;
private float _lifeTime;
private bool _launched;
private Rigidbody _rigidbody;
private Arrow _arrow;
private RaycastHit _hit;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
_arrow = GetComponent<Arrow>();
_launched = false;
}
private void Update()
{
if (!IsServer) return;
if (!_launched) return;
if (Time.time - _lifeTime > _maxLifeTime)
Despawn(DespawnType.Pool);
}
private bool CheckForCollision(out RaycastHit hit)
{
if (lastPosition == Vector3.zero)
lastPosition = tip.position;
bool collided = Physics.Linecast(lastPosition, tip.position, out hit, layerMask);
lastPosition = collided ? lastPosition : tip.position;
return collided;
}
public void LaunchArrow(TwoHandedBowNotch notch)
{
if (!IsServer) return;
Debug.Log("Launching arrow");
transform.rotation = Quaternion.LookRotation(notch.GetLaunchDirection());
Debug.Log("Launching arrow with direction " + notch.GetLaunchDirection());
Debug.Log("Launching arrow with pull amount " + notch.GetLastKnownPullAmount());
LaunchArrow(notch.GetLaunchDirection().normalized * (notch.GetLastKnownPullAmount() * speed));
}
private void LaunchArrow(Vector3 force)
{
_lifeTime = Time.time;
_launched = true;
RemoveOwnership();
transform.parent = null;
EnablePhysics();
ApplyForce(force);
StartCoroutine(LaunchRoutine());
}
private void ApplyForce(Vector3 force)
{
_rigidbody.AddForce(force);
}
private IEnumerator LaunchRoutine()
{
// Set direction while flying
while (!CheckForCollision(out _hit))
{
SetDirection();
yield return null;
}
Debug.Log(_hit.transform.name);
// Once the arrow has stopped flying
DisablePhysics();
CheckForHittable(_hit);
}
private void SetDirection()
{
if (_rigidbody.velocity.z > 0.5f)
transform.forward = _rigidbody.velocity;
}
private void DisablePhysics()
{
_rigidbody.isKinematic = true;
_rigidbody.useGravity = false;
}
private void EnablePhysics()
{
_rigidbody.isKinematic = false;
_rigidbody.useGravity = true;
}
private void CheckForHittable(RaycastHit hit)
{
if (hit.transform.TryGetComponent(out IArrowHittable hittable))
hittable.Hit(_arrow);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3186f8c7706ca9b4197d307b7d8bedc4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,85 @@
using System;
using _PROJECT.Multiplayer;
using FishNet.Connection;
using FishNet.Object;
using FishNet.Object.Synchronizing;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
namespace _PROJECT.Scripts.Bow
{
public class ArrowSpawner : NetworkBehaviour
{
[SerializeField] private GameObject arrowPrefab;
private XRMultiplayerInteractionManager _interactionManager;
private Notch _notch;
[SyncVar] private NetworkObject _arrowNetworkObject;
public override void OnStartServer()
{
base.OnStartServer();
_interactionManager = GameObject.Find("XR Interaction Manager").GetComponent<XRMultiplayerInteractionManager>();
_notch = GetComponent<Notch>();
CreateArrowServer();
}
public override void OnStartClient()
{
base.OnStartClient();
_interactionManager = GameObject.Find("XR Interaction Manager").GetComponent<XRMultiplayerInteractionManager>();
_notch = GetComponent<Notch>();
}
public void LaunchArrow()
{
Debug.Log("Sending arrow RPC at ");
LaunchArrowRPC();
}
[ServerRpc(RequireOwnership = false)]
private void LaunchArrowRPC()
{
if (!IsServer) return;
Debug.Log("Got launch arrow RPC");
if (_notch.hasSelection)
{
//OwnerDeselectRpc(Owner, _notch.firstInteractableSelected.transform.GetComponent<NetworkObject>());
_interactionManager.SelectExit(_notch, _notch.firstInteractableSelected);
}
_arrowNetworkObject = null;
Invoke(nameof(CreateArrowServer), _notch.recycleDelayTime + 0.1f);
}
private void CreateArrowServer()
{
if (!IsServer) return;
Debug.Log("Spawning arrow at " + transform.position);
GameObject arrowObject = Instantiate(arrowPrefab, transform.position, transform.rotation);
Spawn(arrowObject, Owner);
Arrow arrow = arrowObject.GetComponent<Arrow>();
_arrowNetworkObject = arrow.GetComponent<NetworkObject>();
_interactionManager.SelectEnter(_notch as IXRSelectInteractor, arrow);
//OwnerSelectRpc(Owner, arrowObject.GetComponent<NetworkObject>());
}
public override void OnOwnershipClient(NetworkConnection prevOwner)
{
base.OnOwnershipClient(prevOwner);
if (IsOwner && _arrowNetworkObject != null)
TakeArrowOwnershipRPC();
}
[ServerRpc(RequireOwnership = false)]
private void TakeArrowOwnershipRPC(NetworkConnection conn = null)
{
if (!IsServer) return;
if (_arrowNetworkObject == null) return;
_arrowNetworkObject.GiveOwnership(conn);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 29f557273d5348c2b3511dfc21f9a47c
timeCreated: 1678626807

View File

@@ -0,0 +1,6 @@
using _PROJECT.Scripts.Bow;
using UnityEngine.XR.Interaction.Toolkit;
public class Bow : XRGrabInteractable
{
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0d01ceece15e8724fab22ba74c52eba3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b91caed8300a5f547b05c97499015821
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
namespace _PROJECT.Scripts.Bow.Extra
{
public interface IArrowHittable
{
void Hit(Arrow arrow);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cfa6cad5516730442bdec89a52550144
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
using UnityEngine;
namespace _PROJECT.Scripts.Bow.Extra
{
public class Target : MonoBehaviour, IArrowHittable
{
public float forceAmount = 1.0f;
public Material otherMaterial;
public void Hit(Arrow arrow)
{
ApplyMaterial();
ApplyForce(arrow.transform.forward);
}
private void ApplyMaterial()
{
MeshRenderer meshRenderer = GetComponent<MeshRenderer>();
meshRenderer.material = otherMaterial;
}
private void ApplyForce(Vector3 direction)
{
Rigidbody rBody = GetComponent<Rigidbody>();
rBody.AddForce(direction * forceAmount);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 52e106f6721842f4fbabaeb95bc9c7c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,4 @@
public interface IArrowHittable
{
void Hit(Arrow arrow);
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 54d4d1ff1043a6442a1bbda903315edd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,69 @@
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
namespace _PROJECT.Scripts.Bow
{
[RequireComponent(typeof(ArrowSpawner))]
public class Notch : XRSocketInteractor
{
[SerializeField, Range(0, 1)] private float releaseThreshold = 0.25f;
public global::Bow Bow { get; private set; }
public PullMeasurer PullMeasurer { get; private set; }
private ArrowSpawner _arrowSpawner;
protected override void Awake()
{
base.Awake();
Bow = GetComponentInParent<global::Bow>();
_arrowSpawner = GetComponent<ArrowSpawner>();
PullMeasurer = GetComponentInChildren<PullMeasurer>();
}
protected override void OnEnable()
{
base.OnEnable();
PullMeasurer.selectExited.AddListener(ReleaseArrow);
}
protected override void OnDisable()
{
base.OnDisable();
PullMeasurer.selectExited.RemoveListener(ReleaseArrow);
}
public void ReleaseArrow(SelectExitEventArgs args)
{
Debug.Log("Requesting arrow launch...");
_arrowSpawner.LaunchArrow();
}
public override void ProcessInteractor(XRInteractionUpdateOrder.UpdatePhase updatePhase)
{
base.ProcessInteractor(updatePhase);
// Move attach when bow is pulled, this updates the renderer as well
attachTransform.position = PullMeasurer.PullPosition;
}
public override bool CanSelect(IXRSelectInteractable interactable)
{
return QuickSelect(interactable) && CanHover(interactable) && interactable is Arrow;
}
private bool QuickSelect(IXRSelectInteractable interactable)
{
// This lets the Notch automatically grab the arrow
return !hasSelection || IsSelecting(interactable);
}
private bool CanHover(IXRSelectInteractable interactable)
{
if (interactable is IXRHoverInteractable hoverInteractable)
return CanHover(hoverInteractable);
return false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 477605e3da91f604aaf76799722140f9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
using FishNet.Object;
using FishNet.Object.Synchronizing;
using TMPro;
using UnityEngine;
public class PointsText : NetworkBehaviour
{
public TMP_Text text;
[SyncVar]
public float destroyTime = 2f;
[SyncVar]
public float upSpeed = 2f;
[SyncVar]
private float _destroyOnTime;
private void Start()
{
if (!IsServer) return;
_destroyOnTime = Time.time + destroyTime;
}
public void Update()
{
if (!IsServer) return;
if (_destroyOnTime <= Time.time)
{
Despawn(gameObject, DespawnType.Pool);
}
float step = upSpeed * Time.deltaTime;
var position = transform.position;
transform.position = Vector3.MoveTowards(position,
new Vector3(position.x, position.y + 1f, position.z), step);
}
[ObserversRpc]
public void SetPoints(float points)
{
text.text = $"+{points}";
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f90b4cb440f999542a12d794b33ef22f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,61 @@
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
public class PullMeasurer : XRBaseInteractable
{
[SerializeField] private Transform start;
[SerializeField] private Transform end;
public float PullAmount { get; private set; } = 0.0f;
public Vector3 PullPosition => Vector3.Lerp(start.position, end.position, PullAmount);
protected override void OnSelectExited(SelectExitEventArgs args)
{
base.OnSelectExited(args);
PullAmount = 0;
}
public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase)
{
base.ProcessInteractable(updatePhase);
if (isSelected)
{
// Update pull values while the measurer is grabbed
if (updatePhase == XRInteractionUpdateOrder.UpdatePhase.Dynamic)
UpdatePull();
}
}
private void UpdatePull()
{
// Use the interactor's position to calculate amount
Vector3 interactorPosition = firstInteractorSelecting.transform.position;
// Figure out the new pull value, and it's position in space
PullAmount = CalculatePull(interactorPosition);
}
private float CalculatePull(Vector3 pullPosition)
{
// Direction, and length
Vector3 pullDirection = pullPosition - start.position;
Vector3 targetDirection = end.position - start.position;
// Figure out out the pull direction
float maxLength = targetDirection.magnitude;
targetDirection.Normalize();
// What's the actual distance?
float pullValue = Vector3.Dot(pullDirection, targetDirection) / maxLength;
return Mathf.Clamp(pullValue, 0.0f, 1.0f);
}
private void OnDrawGizmos()
{
// Draw line from start to end point
if (start && end)
Gizmos.DrawLine(start.position, end.position);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d5bad711d8ab0cb4db20eab960967d66
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
public class Quiver : XRBaseInteractable
{
[SerializeField] private GameObject arrowPrefab;
protected override void OnSelectEntered(SelectEnterEventArgs args)
{
base.OnSelectEntered(args);
CreateAndSelectArrow(args);
}
private void CreateAndSelectArrow(SelectEnterEventArgs args)
{
// Create arrow, force into interacting hand
Arrow arrow = CreateArrow(args.interactorObject.transform);
interactionManager.SelectEnter(args.interactorObject, arrow);
}
private Arrow CreateArrow(Transform orientation)
{
// Create arrow, and get arrow component
GameObject arrowObject = Instantiate(arrowPrefab, orientation.position, orientation.rotation);
return arrowObject.GetComponent<Arrow>();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8e5f8d9f9b7680c4ea92da637174b928
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,46 @@
using FishNet.Object;
using UnityEngine;
namespace _PROJECT.Scripts.Bow
{
public class StartTarget : NetworkBehaviour, IArrowHittable
{
public ArcheryRange archeryRange;
public Canvas textCanvas;
private MeshRenderer _meshRenderer;
private BoxCollider _boxCollider;
// Start is called before the first frame update
void Start()
{
_meshRenderer = GetComponent<MeshRenderer>();
_boxCollider = GetComponent<BoxCollider>();
}
[ObserversRpc]
private void HideTarget()
{
_meshRenderer.enabled = false;
_boxCollider.enabled = false;
textCanvas.enabled = false;
}
[ObserversRpc]
public void ShowTarget()
{
_meshRenderer.enabled = true;
_boxCollider.enabled = true;
textCanvas.enabled = true;
}
public void Hit(Arrow arrow)
{
if (!IsServer) return;
if (arrow == null) return;
Despawn(arrow.gameObject, DespawnType.Pool);
HideTarget();
archeryRange.StartRound();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c25614c8b9ec3ef40963a7887bf26792
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,47 @@
using UnityEngine;
[ExecuteInEditMode]
public class StringRenderer : MonoBehaviour
{
[Header("Render Positions")] [SerializeField]
private Transform start;
[SerializeField] private Transform middle;
[SerializeField] private Transform end;
private LineRenderer _lineRenderer;
private void Awake()
{
_lineRenderer = GetComponent<LineRenderer>();
}
private void Update()
{
// While in editor, make sure the line renderer follows bow
if (Application.isEditor && !Application.isPlaying)
UpdatePositions();
}
private void OnEnable()
{
Application.onBeforeRender += UpdatePositions;
}
private void OnDisable()
{
Application.onBeforeRender -= UpdatePositions;
}
private void UpdatePositions()
{
if (_lineRenderer == null) _lineRenderer = GetComponent<LineRenderer>();
// Set positions of line renderer, middle position is the notch attach transform
_lineRenderer.SetPositions(new Vector3[] { start.position, middle.position, end.position });
}
public void UpdateString(Vector3 pullPosition)
{
middle.position = pullPosition;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a7bf39fa7cd40e94b94b00dec7e5d4d3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
using UnityEngine;
public class Target : MonoBehaviour, IArrowHittable
{
public float forceAmount = 1.0f;
public Material otherMaterial = null;
public void Hit(Arrow arrow)
{
ApplyMaterial();
ApplyForce(arrow);
DisableCollider(arrow);
}
private void ApplyMaterial()
{
if (TryGetComponent(out MeshRenderer meshRenderer))
meshRenderer.material = otherMaterial;
}
private void ApplyForce(Arrow arrow)
{
if (TryGetComponent(out Rigidbody rigidbody))
rigidbody.AddForce(arrow.transform.forward * forceAmount);
}
private void DisableCollider(Arrow arrow)
{
if (arrow.TryGetComponent(out Collider collider))
collider.enabled = false;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9811e177caf046348abcb84042ed1ac1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: