Child calling a parent function that uses child's function in Unity - c#

I have a base class that has a function that does not know what one of the functions it calls will do. That behavior is defined in the child. The parents function is then called from the child. What is the correct syntax/method to make this work? Particularly what must I put instead of FunctionToBeDefinedLater Example follows:
public class ToolScript : MonoBehaviour {
public void isActive()
{
if (Input.GetKeyDown("space"))
{
Use();
}
}
FunctionToBeDefinedLater Use();
}
public class GunController : ToolScript
{
public void Use()
{
//Spawn bullet at this direction, this speed, give it spiral, tons of behavior etc. etc.
}
private void Update()
{
isActive();
}
}
public class FlamethrowerController : ToolScript
{
public void Use()
{
//Spawn fire at this direction, this speed, set tip of flamethrower to be red etc etc
}
private void Update()
{
isActive();
}
}
The Update function is from unity and is called every frame. Please let me know if I can clarify my question any further and I will do so as soon as possible. I do not know if this is referencing overriding, interfacing, or abstraction so I have tagged them all. I will fix this as soon as I know.

Based on what #Michael Curtiss directed me to I have updated my code to be:
public **abstract** class ToolScript : MonoBehaviour {
public void isActive()
{
if (Input.GetKeyDown("space"))
{
Use();
}
}
**public abstract void** Use();
}
public class GunController : ToolScript
{
public **override** void Use()
{
//Spawn bullet at this direction, this speed, give it spiral, tons of behavior etc. etc.
}
private void Update()
{
isActive();
}
}
public class FlamethrowerController : ToolScript
{
public **override** void Use()
{
//Spawn fire at this direction, this speed, set tip of flamethrower to be red etc etc
}
private void Update()
{
isActive();
}
}
Stars are not in code and are simply for emphasis. This code solved my problem.

Related

Unity overriding a virtual method and adding one statement to the if

I have a problem,
I have 3 classes, one is a base class from which two other inherit,
the base class has a method with a counter,
if the time runs out it should destroy gameObject,
but other classes should have this method but in this conditional statement you could was to add anything
I just want to add an extra command to if from another class.
If you don't understand, feel free to ask, because I'm not good at explaining.
public class A : MonoBehaviour
{
public virtual void DestroyByTime()
{
timeLeft -= Time.deltaTime;
if (timeLeft <= 0)
{
/*
This statement should only be added in class B
|
v
gameSession.GameOver();
*/
Destroy(gameObject);
}
}
private void Update()
{
DestroyByTime();
}
}
public class B : A
{
public override void DestroyByTime()
{
/*
I want the base class if to be saved, but in if statement time runs out you lose
(gameSession.GameOver())
*/
}
}
You can create an OnTimeOut method an override only in derived class:
public class A : MonoBehaviour
{
public virtual void DestroyByTime()
{
timeLeft -= Time.deltaTime;
if (timeLeft <= 0)
{
OnTimeOut();
Destroy(gameObject);
}
}
protected virtual void OnTimeOut()
{
// Do nothing here
}
private void Update()
{
DestroyByTime();
}
}
public class B : A
{
protected override void OnTimeOut()
{
gameSession.GameOver();
}
}

How to make Unity Tilemap.SetTile() to work in multiplayer?

I'm trying to make 2D-multiplayer game with randomly generated map.
Here's some simplified code what I have tried
public class Map : NetworkBehaviour
{
private TilePainter _tilePainter;
[Command]
public void CmdStartGenerating()
{
_tilePainter.PaintSection(section)//section is randomly generated map information
}
}
public class TilePainter : NetworkBehaviour
{
public Tile tile;
private Tilemap _tilemap;
public void PaintSection(Section section)
{
section.Foreach(x=>{
_tilemap.SetTile(x.Vector3(), tile);
})
}
}
Of course I made them have NetworkIdentity and CmdStartGenerating is called by button click.
The problem is that generated tilemap is visible only in host player.
The other client cannot see generated tile map.
In real code, TilePainter also instantiate some prefabs and they are visible to both player.
I have tried making them network spawnable prefabs but didn't work. (with same problem)
Is there any method like NetworkServer.Spawn for tilemap??
I'm new to Unity multiplayer feature so maybe I'm making some stupid mistake...
Thanks for reading my question!
####Edit
Uploading additional code I've tested in test scene.
public class NetTest : NetworkBehaviour
{
public TileRiverMap tileRiverMap;
private SectionGenerator _sectionGenerator =
new SectionGenerator(10, 20, 1f);
public void Test()
{
Debug.Log("hihi");
tileRiverMap.PaintSection(_sectionGenerator.GenerateSection((0, 0)), 5);
}
}
Class below is Player object
public class TestPlayer : NetworkBehaviour
{
private void FixedUpdate()
{
if (isLocalPlayer)
{
if (Input.GetButtonDown("Jump"))
{
CmdTest();
}
}
}
[Command]
private void CmdTest()
{
FindObjectOfType<NetTest>().Test();
}
}
public class TileRiverMap : NetworkBehaviour, IRiverMap
{
public Tile tile;
public GameObject stone;
private Tilemap _tilemap;
......
}
I don't think whole code of TileRiverMap is needed

Hello I keep getting the error "return type must be 'void' to match overridden member" and I can't seem to fix it

Here is my code. I keep getting the same error and I can't seem to resolve it.
using System.Collections;
using UnityEngine;
namespace CreatingCharacters.Abilities
{
[RequireComponent(typeof(PlayerMovementController))]
public class genjidash : Ability
{
[SerializeField] private float dashForce;
[SerializeField] private float dashDuration;
private PlayerMovementController playerMovementController;
private void Awake()
{
playerMovementController = GetComponent<PlayerMovementController>();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
StartCoroutine(Cast());
}
}
public override IEnumerator Cast()
{
playerMovementController.AddForce(Camera.main.transform.forward, dashForce);
yield return new WaitForSeconds(dashDuration);
playerMovementController.ResetImpact()
}
}
}
Here is the code that it is parented to:
using UnityEngine;
namespace CreatingCharacters.Abilities
{
public abstract class Ability : MonoBehaviour
{
public abstract void Cast();
}
}
Any advise would be great and thank you in advance.
class genjidash is derived from Ability, the return of Cast() in Ability is void, but in genjidash it's IEnumerator, so maybe you should change your base Cast() to
public abstract class Ability : MonoBehaviour
{
public abstract IEnumerator Cast();
}
If you can't change Ability's Cast(), you need
private void Update()
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
StartCoroutine(CastAndReset());
}
}
private IEnumrator CastAndReset()
{
Cast();
yield return new WaitForSeconds(dashDuration);
playerMovementController.ResetImpact()
}
public override void Cast()
{
playerMovementController.AddForce(Camera.main.transform.forward, dashForce);
}

OnMouseDown() null reference exception

public class TowerNode : MonoBehaviour {
public bool IsShopOpen=false;
//Z position
public Vector3 positionOffSet;
//colors
public Color hoverColor;
private Color startColor;
//GameObjects
public GameObject turret;
//shop
public Shop shop;
//Build Manager
BuildManager buildManager;
void Start()
{
rend=GetComponent<Renderer>();
startColor = rend.material.color;
buildManager = BuildManager.instance;
shop = GetComponent<Shop>();
}
//When mouse is on the turret node
public void OnMouseDown()
{
Debug.Log("Mouse is Down");
bool IsShopOpen = true;
if (IsShopOpen == true)
{
Debug.Log("shop is open");
shop.onEnable();
}
if (EventSystem.current.IsPointerOverGameObject())
{
return;
}
if (!buildManager.CanBuild)
{
return;
}
if (turret != null)
{
Debug.Log("Cant Build Here!!!");
return;
}
buildManager.BuildTurretOn(this);
}
the other script of the shop is this:
public class Shop : MonoBehaviour
{
public TurretBlueprint Archery;
public TurretBlueprint Treb;
public TurretBlueprint Workamp;
public TurretBlueprint Barracks;
public Button Archeryy;
public Button Trebb;
public Button WorkCampp;
public Button Barrackss;
BuildManager buildManager;
void Start()
{
buildManager = BuildManager.instance;
disableAllButtons();
//OnEnable();
}
public void SelectArchery()
{
buildManager.SelectTurretToBuild(Archery);
Debug.Log("archery!!!!");
}
public void SelectTreb()
{
buildManager.SelectTurretToBuild(Treb);
Debug.Log("Treb!!!!");
}
public void SelectWorkamp()
{
buildManager.SelectTurretToBuild(Workamp);
Debug.Log("Work Camp!!!!");
}
public void SelectBarracks()
{
buildManager.SelectTurretToBuild(Barracks);
Debug.Log("Barracks!!!!");
}
public void onEnable()
{
Archeryy.gameObject.SetActive(true);
Trebb.gameObject.SetActive(true);
WorkCampp.gameObject.SetActive(true);
Barrackss.gameObject.SetActive(true);
}
public void disableAllButtons()
{
Archeryy.gameObject.SetActive(false);
Trebb.gameObject.SetActive(false);
WorkCampp.gameObject.SetActive(false);
Barrackss.gameObject.SetActive(false);
}
}
I need when i click on the game object that the shop will open the sop got few buttons under it, but it gives me:
"NullReferenceException: Object reference not set to an instance of an object
TowerNode.OnMouseDown () (at Assets/Scripts/TowerNode.cs:51)
UnityEngine.SendMouseEvents:DoSendMouseEvents(Int32)"
and I don't understand why.
The error you are getting implies that an object in the OnMouseDown function is null when executed:
NullReferenceException: Object reference not set to an instance of an object TowerNode.OnMouseDown () (at Assets/Scripts/TowerNode.cs:51)
You should look at ine 51 of TowerNode.cs and ascertain what can be null on that line. Could shop or buildManager be null? Perhaps this event is firing before you have initialised your TowerNode object.
It seems you are trying to access a component (Shop) from a completely unrelated GameObject. If you want all of your TowerNode objects to reference the Shop then you could use GameObject.Find. This isn't really recommended though; it seems like there is a better way to link these two objects but I am unsure of your use case.

Are command patterns efficient enough, and what's the concrete benefit of it?

So today I am learning and implementing Command Patterns for handling input and movement for objects.
So my question is:
Am I getting the implementation of Command Patterns right or do I need to modify it? If so, can somebody give me a little example on to improve it.
I know that it improves code reusability. But what difference does it make when I just use a simple MovementScript.cs to my game object component? Wouldn't it just be the same and take less time to write rather than making a whole Command Pattern?
The one I attached to the gameobject is only the InputHandler. Here's my code which involves moving an object:
This is my Input Handler or as far as I know as The Client
public class InputHandler : MonoBehaviour
{
GameObject theObject;
public Command buttonA, buttonD;
public float acceleration, maxSpeed;
Movement moves;
void Awake()
{
theObject = gameObject;
moves = new Movement(theObject, acceleration, maxSpeed);
}
void Start()
{
buttonA = new MoveLeft(moves);
buttonD = new MoveRight(moves);
}
void Update()
{
HandleInput();
}
public void HandleInput()
{
if (Input.GetKey(KeyCode.A))
{
buttonA.Execute();
}
else if (Input.GetKey(KeyCode.D))
{
buttonD.Execute();
}
}
}
The Command abstract class
public abstract class Command
{
//The Receiver of the command..
protected IReceiver receiver = null;
public Command(IReceiver receiver)
{
this.receiver = receiver;
}
public abstract void Execute();
}
The Receiver class (where I implemented the logic, which is the movement)
public class Movement : IReceiver
{
public ACTION_LIST currentMoves;
private GameObject theObject;
private float acceleration;
private float maxspeed;
public Movement(GameObject theObject, float acceleration, float maxspeed)
{
this.theObject = theObject;
this.acceleration = acceleration;
this.maxspeed = maxspeed;
}
public void Action(ACTION_LIST moves)
{
if (moves == ACTION_LIST.MOVERIGHT)
MoveRight(theObject);
else if (moves == ACTION_LIST.MOVELEFT)
MoveLeft(theObject);
}
public void MoveRight(GameObject obj)
{
obj.GetComponent<Rigidbody2D>().AddForce(new Vector2(acceleration, obj.GetComponent<Rigidbody2D>().velocity.y));
}
public void MoveLeft(GameObject obj)
{
obj.GetComponent<Rigidbody2D>().AddForce(new Vector2(-acceleration, obj.GetComponent<Rigidbody2D>().velocity.y));
}
}
Interface of receiver, to make things easier..
public enum ACTION_LIST
{
MOVERIGHT,
MOVELEFT
}
public interface IReceiver
{
void Action(ACTION_LIST moves);
}
The concrete command. I only posted 1 of the movements..
public class MoveRight : Command
{
public MoveRight(IReceiver receiver):base(receiver)
{
}
public override void Execute()
{
receiver.Action(ACTION_LIST.MOVERIGHT);
}
}
I disagree with Joe Blow and others saying that Unity is a bunch of scripts and not OOP. I use main script with single entry point and create all objects and components dynamically. I even use interfaces, mock and unit tests.
So, using Command pattern is ok. But I don't see a reason to use it in your case. Command pattern could be very handy in case when you need a stack of commands to be able Do() and Undo() your commands (Editor, Strategy game). Please read more here: http://gameprogrammingpatterns.com/command.html

Categories