I'm a student programmer and we are learning to use unity. I have this problem in C#. So I have a weapon class and a chil named gun. On weapon :
public override void PrimaryInteraction() {
if (transform.parent == null || transform.parent.name != "Hand")
{
Debug.LogWarning("Weapon is not being held by a player!");
return;
}
}
On gun :
public override void PrimaryInteraction()
{
base.PrimaryInteraction();
if (!_gunModel.Automatic && Time.time >= _nextTimeToFire) {
_nextTimeToFire = Time.time + 1f / _gunModel.FireRate;
Shoot();
return;
}
_isShooting=true;
}
PrimaryInteraction is called on a different file who handles player Input using polymorphism.
public void HandlePrimaryAction()
{
GameObject objectInHand = _handController.GetObjectInHand();
if (HandleObjectInHand(objectInHand)) return;
if (Physics.Raycast(_playerCamera.transform.position, _playerCamera.transform.forward, out RaycastHit hit, 5f, _interactableLayer))
{
HandleRaycastHit(hit);
}
}
private bool HandleObjectInHand(GameObject obj)
{
if (obj == null) return false;
if (obj.TryGetComponent(out IConsumableObject consumable))
{
_inventoryManager.ConsumeCurrentItem();
return true;
}
if (obj.TryGetComponent(out Weapon weapon))
{
weapon.PrimaryInteraction();
return true;
}
return false;
}
private void HandleRaycastHit(RaycastHit hit)
{
GameObject objectInHand = _handController.GetObjectInHand();
if (hit.collider.TryGetComponent(out IRequiredObjectInteraction requiredInteraction) && objectInHand != null)
{
requiredInteraction.RequiredObjectInteraction(objectInHand);
}
if (hit.collider.TryGetComponent(out IInteractableObject interactable))
{
interactable.PrimaryInteraction();
_currentInteractableObject = interactable;
}
if (hit.collider.TryGetComponent(out DraggableObject draggable) && !objectInHand)
{
DragObject(draggable);
}
}
My problem is that even if I return on Weapon, the function still be executed on Gun, because the return is only for the base.PrimaryInteraction call and not for the rest of the function. I cannot change the type of PrimaryInteraction in order to catch a true or false because a lot of other classes Inherits from an Interface.
Thanks for your help!
I don't know what solution I can use. I have think about cathing exceptions but if it's possible I want a more elegant solution unless it's a good pratice.
I'm a student programmer and we are learning to use unity. I have this problem in C#. So I have a weapon class and a chil named gun. On weapon :
public override void PrimaryInteraction() {
if (transform.parent == null || transform.parent.name != "Hand")
{
Debug.LogWarning("Weapon is not being held by a player!");
return;
}
}
On gun :
public override void PrimaryInteraction()
{
base.PrimaryInteraction();
if (!_gunModel.Automatic && Time.time >= _nextTimeToFire) {
_nextTimeToFire = Time.time + 1f / _gunModel.FireRate;
Shoot();
return;
}
_isShooting=true;
}
PrimaryInteraction is called on a different file who handles player Input using polymorphism.
public void HandlePrimaryAction()
{
GameObject objectInHand = _handController.GetObjectInHand();
if (HandleObjectInHand(objectInHand)) return;
if (Physics.Raycast(_playerCamera.transform.position, _playerCamera.transform.forward, out RaycastHit hit, 5f, _interactableLayer))
{
HandleRaycastHit(hit);
}
}
private bool HandleObjectInHand(GameObject obj)
{
if (obj == null) return false;
if (obj.TryGetComponent(out IConsumableObject consumable))
{
_inventoryManager.ConsumeCurrentItem();
return true;
}
if (obj.TryGetComponent(out Weapon weapon))
{
weapon.PrimaryInteraction();
return true;
}
return false;
}
private void HandleRaycastHit(RaycastHit hit)
{
GameObject objectInHand = _handController.GetObjectInHand();
if (hit.collider.TryGetComponent(out IRequiredObjectInteraction requiredInteraction) && objectInHand != null)
{
requiredInteraction.RequiredObjectInteraction(objectInHand);
}
if (hit.collider.TryGetComponent(out IInteractableObject interactable))
{
interactable.PrimaryInteraction();
_currentInteractableObject = interactable;
}
if (hit.collider.TryGetComponent(out DraggableObject draggable) && !objectInHand)
{
DragObject(draggable);
}
}
My problem is that even if I return on Weapon, the function still be executed on Gun, because the return is only for the base.PrimaryInteraction call and not for the rest of the function. I cannot change the type of PrimaryInteraction in order to catch a true or false because a lot of other classes Inherits from an Interface.
Thanks for your help!
I don't know what solution I can use. I have think about cathing exceptions but if it's possible I want a more elegant solution unless it's a good pratice.
Share Improve this question edited Mar 11 at 14:49 Oroitz Lago Ramos asked Mar 11 at 14:04 Oroitz Lago RamosOroitz Lago Ramos 114 bronze badges 2- Can we see your file where these functions are being called? – Mark Hollis Commented Mar 11 at 14:35
- Done, thank you – Oroitz Lago Ramos Commented Mar 11 at 14:50
2 Answers
Reset to default 0You cannot know where your function returned from as long as it's a void. The whole reason for a void is that either it succeeds or throws in which case your program should not continue down the current path.
Secondly, base
is not polymorphic. In my opinion it tightly couples your two classes and can defeat the whole purpose of polymorphism, for instance if you later override the PrimaryInteraction()
in a sub class of Gun, it will no longer run the code specified in PrimaryInteraction()
of class Weapon.
One scalable way to structure your requirement is to write a function specifically to meant to be overridden by abstracting all common code in base classes, so as to not deal with it in sub classes, which is the crux of OOP design in general.
For your case you could introduce RunPrimaryInteraction() in your Weapon class:
class Weapon {
public override void PrimaryInteraction() {
if (transform.parent == null || transform.parent.name != "Hand")
{
Debug.LogWarning("Weapon is not being held by a player!");
return;
}
// Will run when conditions are correct
RunPrimaryInteraction()
}
protected virtual void RunPrimaryInteraction() {
// to be overridden in sub class
}
}
class Gun : Weapon {
protected override void RunPrimaryInteraction() {
// no need to deal with base class methods
if (!_gunModel.Automatic && Time.time >= _nextTimeToFire) {
_nextTimeToFire = Time.time + 1f / _gunModel.FireRate;
Shoot();
return;
}
_isShooting=true;
}
}
This pattern can be scaled without breaking polymorphism and you can still call PrimaryInteraction()
as before with no need to refactor code.
You should only need to override RunPrimaryInteraction() when something specific to the subclass needs to happen.
You should first consider if interacting with a non held object is an programming error. If that is the case, as it looks in your example, you should probably throw an exception so you get alerted to the problem and can fix it. Just returning without doing anything can "hide" errors, and make them less obvious and increase the risk that you find them long after they where created, when they are much more difficult to find and fix.
You might also consider creating a method like bool CanUsePrimaryInteraction()
to let the caller check if the action is available, and allow it to react accordingly. Or maybe a method like bool TryUsePrimaryInteraction()
that does the action if it is valid, and returns success/fail. In the later case you probably still want a protected CanUse*
-method if you are using polymorphism, so you are sure that all checks are run before the object is actually modified.
I would also recommend being somewhat careful not to overuse OOP. See Composition over Inheritance for a general summary. Eric Lipperts articles on Wizards and warriors might also be useful if you want to learn more about OOP.