I have two classes in XNA.
maingame.cs
and
player.cs
In my maingame.cs I have a rectangle that is drawn wherever the mouse is, I use this for clicking.
My player.cs has a rectangle for the players sprite.
I Have No idea how to make these two classes 'talk' to eachother so that I can have something like
if (ButtonState.Pressed == mouseState.LeftButton && mouseRectangle.Intersects(playerRectangle))
{
//draw something
}
The problem is that playerRectangle is in the Player.CS and the mouseRectangle is in the maingame.CS
How do I get these two to talk to eachother? I've been Googling for hours now with no luck.
Player.CS looks like
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace PlanetDefence
{
class Battleship
{
//Textures
Texture2D playerBattleshipTexture;
//Rectangles
Rectangle playerBattleshipRectangle;
//Integers
public Battleship(Texture2D newPlayerBattleshipTexture, Rectangle newPlayerBattleshipRectangle)
{
playerBattleshipTexture = newPlayerBattleshipTexture;
playerBattleshipRectangle = newPlayerBattleshipRectangle;
newPlayerBattleshipRectangle = new Rectangle(100, 100, 100, 100);
}
public void Update()
{
}
public void Draw(SpriteBatch spriteBatch)
{
//Draw the player Battleship
spriteBatch.Draw(playerBattleshipTexture, playerBattleshipRectangle, Color.White);
}
}
}
I'm trying to make it so that my mouse rectangle in MainGame.CS is able to click it by doing
if (ButtonState.Pressed == mouseState.LeftButton && mouseRectangle.Intersects(playerBattleshipRectangle))
{
playerBattleship.Draw(spriteBatch);
}
I'm not sure if I'm stating the obvious here, but you need a public accessor for your Rectangle in your Battleship class. If you don't understand what that means then you need to do some reading on the basics of object-oriented programming. For now, though, if you modify the code of your Battleship class to say
public Rectangle playerBattleshipRectangle;
... you can then access it from your maingame.cs' reference to the player object using
player.playerBattleshipRectangle
(assuming your player is a Battleship class. If it's not then you need to be more clear in your question and post the class source code for whatever class your player is. You say "player.cs" but post the class Battleship-- which is it? If the filename is player.cs but the class name is actually battleship you should change one of them so that they are the same. Practice good, easy to understand class and variable names; be as descriptive as possible without being too wordy).
By default, if you include no scope modifier (public, private, protected, internal...) before your member fields in a class, then they are set to private and not accessible by other classes.
You can also use Properties to have more control over access to a class' member fields. For instance,
private int health;
public int Health
{
get { return health; }
set { health = MathHelper.Clamp(health, 0, 100); }
}
this code contains a private (only this class can access it) definition of the health of an object. It also provides a public way for other classes to 'see' the health of that object and change this health. As you can see in the 'set' section, when another class sets the health of this object it is automatically clamped between 0 and 100. You could also omit 'set' entirely and no other class could change the health, they could only see it.
This is all the basics of object-oriented programming in C#. I strongly encourage you to start from the basics if you don't know them. You cannot successfully create a game without understanding scope, properties, inheritance, object instances and references, just to name a few.
A quick summary of some relevant definitions from this post:
field - aka a variable; a basic trait stored in a class as a 'member'. i.e., 'health' or 'boundingBox'.
property - an accessor for a field which is useful for defining how outside classes can see and modify it.
instance - a 'real' object which is stored in memory. a class only defines the behavior of an object; it must be made into an instance for the object to actually exist. A class like Battleship can be used to make unlimited instances of battleships in memory. When you say Battleship player = new Battleship(), you are creating an instance of Battleship called 'player'.
private - placing 'private' before a field means only this class can see it.
public - placing 'public' before a field means all classes can see it.
protected - placing 'protected' before a field means only this class and any classes inherited off of this class can see it.
internal - placing 'internal' before a field means only classes in this class' namespace can see it.
I apologize if I underestimate your knowledge of the subject.
One of the classes needs to hold a reference to the other.
With such a reference, it can call methods on it, set properties etc.
You can do this by passing in an instance in the constructor or as a property.
public Maingame(Player player)
{
// use the Player instance
}
To access it outside of the constructor, you should use a field and assign it in the constructor (or property setter, whichever you decide to use):
Player myPlayer;
public Maingame(Player player)
{
myPlayer = player;
// use the myPlayer field in the class
}
To avoid tight coupling, you may want to investigate using events.
Related
I'm very new to coding, so apologies if any terminology is wrong. The code is trying to change a bool from false to true (it will do something more significant later, but I'm having issues doing this which is much simpler). I'm doing this in unity if that changes anything.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimalPositionalUpdates : MonoBehaviour
{
public PositionArrays ScripBeingAcessed;
// Use this for initialization
void Start()
{
//Find where the position is going to be input
int ArrayPosition = ScripBeingAcessed.FoodPosition.Length + 1;
PositionArrays.PositionBeingUpdated = transform.position;
}
// Update is called once per frame
void Update ()
{
}
}
Second Script (the one that I'm trying to influence)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PositionArrays : MonoBehaviour {
public bool PositionInProcess = false;
public Vector3 PositionBeingUpdated;
public Vector3[] FoodPosition = new Vector3[0];
// Use this for initialization
void Start () {
}
public void ArrayPosUpdate()
{
PositionInProcess = true;
}
// Update is called once per frame
void Update ()
{
}
}
Any help would be appreciated. As far as I know, there is some issue with me trying to use a static method like an instance??? Idk where it starts being static, and putting static in the method declaration for both only causes the same error to appear again referencing different components.
The error Is on line 16 of the first script.
Full error message
"CS0120 An object reference is required for the non-static field, method, or property 'PositionArrays.PositionBeingUpdated' 16 Active"
Obviously you are lacking fundamentals of OOP and delved into Unity development right away. You can do this, but I guess that programming in Unity will Taint your C# if you did not learn it properly. Having said that, you could certainly do it, but I'd suggest learning proper C# first and then use that sometimes uncommon Unity style.
There is some confusion around how the fields of your class are used, so let me explain: Usually, a class is a blueprint of sorts of which you can create instances. All of these instances adhere to that blueprint, which tells you exactly how you can use those instances (this is sometimes called implicit interface) and which data they contain (this is where Unity is somewhat sloppy). An instance bundles up the data with the methods you use to access and manipulate the data and you "always" need an instance to access these members, usually through a variable.
In your case, this variable is ScripBeingAcessed. This is the variable that holds your instance (at least if you did not forget to assign it) and therefor, you'd need the variable to access the field PositionBeingUpdated
void Start()
{
//Find where the position is going to be input
int ArrayPosition = ScripBeingAcessed.FoodPosition.Length + 1;
ScripBeingAcessed.PositionBeingUpdated = transform.position;
}
On static
Besides the members of a class that form the actual blueprint to create instances from, there are members that are accessed through the class itself. These are called static members. Anyway, since they are not bound to an instance, static members that contain any data will be the same regardless of where you access them from. This may be fine, if the static members are private (only instances of that class can access it) but I'd avoid it otherwise, since this creates a global state, which is not safe of being manipulated from other classes and can thus lead to hard to debug errors.
I am attempting to create a 2D game in Unity. Essentially, there are multiple types of 'agents': enemies and players. Programmatically, both classes 'enemy' and 'player' derive from the agent class. Then, there are different types of enemies (such as flying, ground enemies, etc).
My issue is that I need to call the Update function on all derivatives of an enemy. This is because there is code that needs to run for all enemies, and other code that should only run for some enemies - all enemies need to know where the player is, but only some enemies need to fly.
I read somewhere that you can use the new keyword, then call the base update function. However, with multiple levels of subclasses this seems inefficient and clunky as you have to state "new" for each new instance.
Is there any better way to call Update, Start and FixedUpdate (functions that are automatically called) than how I have implemented this below? Thanks in advance.
public abstract class Agent : MonoBehaviour
{
public void Start(){
// Run start code for all types of 'players', including AI
}
}
public class Enemy : Agent
{
public new void Start()
{
base.Start();
// Run start code specific to all enemies
}
}
public class WalkerEnemy : Enemy
{
public new void Start()
{
base.Start();
// Run start code specific to walking enemies ONLY
// Invoking Enemy.Start() will result in a call of Agent.Start() as well
}
}
Thank You for your help. Whilst I would call myself 'intermediate' in my programming skills, I doubt my object oriented knowledge is as fluent as it could be. So if there is some fundamental idea that I am missing, please let me know :)
First of all, when using inheritance structure, you usually want to avoid using the new keyword. Instead you mark the methods of the base class which you want to change for inheriting classes with the virtual keyword (or abstract if the baseclass does not contain code). That way you can re-use the code in the baseclass or even remove it all together.
An approach which may be even better in your case is to make an abstract method which you call in your baseclass start method. That way, inheriting classes MUST implement the method. This will be forced by the compiler.
Example:
public abstract class Agent : MonoBehaviour
{
private void Start(){
// Your code needed for all inheriting classes here.
// Call the abstract method which is defined on inheriting classes
OnStarting();
}
protected abstract void OnStarting();
}
public class Enemy : Agent
{
protected override OnStarting()
{
// Your enemy code here.
}
}
public class WalkerEnemy : Enemy
{
protected override OnStarting()
{
base.OnStarting(); // Call the code from the Enemy class
// Your walker enemy code here.
}
}
Also as you might see, I made your Start method private. Since Unity calls this by itself. You do not want to call this yourself from anywhere in your application. The OnStarting methods are marked as protected, because they should only exist/ be used in the scope of this inheritance tree.
Odd question here - I have a gameobject with a class object attached. I instantiate the gameobject, and assign the class object with data from an existing class.
I then instantiate a second gameobject with the exact same class object attached and assign it the same data as the first object. If I modify the class attached to the first gameobject, it is different to the class attached to the second object, even though they both reference (or should) reference the same original class.
Can anyone think why this would happen?
if you make the variables you want to persist in the class your adding static, it will use the same instance for both cases, modifying both when you mod one.
check out this enemy class from unity3d's own dev pages
https://unity3d.com/learn/tutorials/topics/scripting/statics
using UnityEngine;
using System.Collections;
public class Enemy
{
//Static variables are shared across all instances
//of a class.
public static int enemyCount = 0;
public Enemy()
{
//Increment the static variable to know how many
//objects of this class have been created.
enemyCount++;
}
}
They are different instances of the same class, they don't reference the same class.
You should write a duplicate method to duplicate the values
I navigated the site and found no topic that asked (or gave) specific examples of static's utility on C#. I am a beginner and wanted to find given cases in which the usefulness of statics are proved, in order to go further than the conceptual understanding of what a static class/method/etc is. I know only of one or two examples, such as being able to create a method that produces an object or a value when ran, but keep that one value "for ever", by the means of removing the new values created (when the script runs again) if a value has been created before. The code for that is this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MusicPlayerScript : MonoBehaviour {
static MusicPlayerScript instance = null;
// Use this for initialization
void Start () {
if (instance != null)
{
Destroy(gameObject);
print("Duplicate self-destructing");
} else
{
instance = this;
GameObject.DontDestroyOnLoad(gameObject);
}
}
// Update is called once per frame
void Update () {
}
}
What other examples could anybody give me? Thank you!
That's an easy one. If you have something to do that is not directly related to a specific object of the class you want to group it into, you define a static method. For example if you need a very specific helper function that acts on one of your properties but not on the whole object.
A static member variable allows you to define for example a singled-out object of your class. For example if your class is "Scene" and you want an all-encompassing Scene-object named World, you would define static Scene World.
In many ways statics can be considered what has been known as globals in older programming languages. What makes them less dangerous than globals is proper namespace resolution. You don't see them everywhere unless you know how to get to them, ie. on which namespace path.
Let me first try to explain what I'm trying to achieve.
I'm making a game where the player can pickup power-ups(which I called, for some reason, "Loot" in my game). So here's a really basic form of my Loot class:
public class Loot : Sprite
{
//Properties and fields...
public Loot(/*parameters...*/)
{
}
public virtual OnPickUp(Player player)
{
}
}
Player and Sprite are classes from me. Here's my problem: my sprite class holds a position(a Vector2, a struct from XNA representing a vector) and from my understanding of how C# works, copying two sprites will copy the reference of eachother, therefor, whenever I change one's position, it will change the other one's too.
Whenever a loot should spawn, I have a class holding the possible loots that can spawn which returns a random one and the loot is copied and shown to the screen, but as soon as I get more than one of the same type of loot, it messes up because of the reference copy problem (both will share the same position and only one will be visible).
So then I tried creating a new Loot object whenever I needed to spawn a new loot, so I had to provide a constructor with multiple parameters to easily copy a loot this way:
(Let's pretend toSpawn can be any type derived from the Loot class, like a HealthPack, or whatever)
Loot spawning = new Loot(toSpawn.Position, toSpawn.Color /*etc...*/);
It looked right until I decided to implement "OnPickUp". Since I create a new Loot object rather than the proper child class, the functionality of toSpawn's OnPickUp function would disappear and picking up a loot would end up doing nothing(it would only call the base class Loot's empty function).
Obviously, I am doing something wrong here. I don't have much programming experience, and even less with C#, so I really have no idea of how I can fix this. I tried using an Action< Player> object representing the OnPickUp functionality, it would work but still limit me quite a lot(since I have to pass a static function as an Action< Player>, therefor limiting me to use the information of the player parameter and preventing me from using the sub-class specific information).
So, finally, my question really is: What would be a better design to allow having sub-classes with overloaded functions, but still being able to clone the base class and its properties?
Thank you for your precious time.
If anything is not clear enough(and I know it's not), then just ask me in the comments and I'll try to describe my problem in more details.
have your Loot class implement ICloneable
public abstract class Loot : ICloneable
{
public virtual object Clone()
{
Type type = this.GetType();
Loot newLoot = (Loot) Activator.CreateInstance(type);
//do copying here
return newLoot;
}
}
I think I must be missing something with this question because Vector2 is a structure and not a class. Any direct assignment of one Vector2 to another automatically creates a copy.
var v2a = new Vector2(10.0f, 20.0f);
var v2b = v2a; //`v2b` is a new instance of `Vector2` distinct from `v2a`.
Your issue sounds like the PossibleLoots class isn't randomizing the position of each Loot instance created.
I assume your game logic says something like "each level there shall be a maximum of 10 loots spawned", so your PossibleLoots class creates all the possible Loot objects at start-up but doesn't display one unless it is asked to "spawn a loot".
So, if that's right, isn't this the kind of thing you need?
public class PossibleLoots
{
private IList<Loot> _loots = new List<Loot>();
public PossibleLoots(int maxLoots)
{
for (var i = 0; i < maxLoots; i++)
{
_loots.Add(new Loot(this.GetRandomPosition()));
}
}
private Vector2 GetRandomPosition()
{
// Your logic here to create suitable locations for loot to appear
}
// Rest of your `PossibleLoots` code
// to spawn each `Loot` and to deplete the `_loots`
// collection when the player picks up each `Loot`
}
Please let me know if I've missed the point of this question.
Vector2 is a struct not a class, so your original problem sounds like it is due to holding two references to the same Loot object, rather than having two different Loot objects with references to the same position.
The class responsible for creating Loot objects should be creating new instances of the relevant Loot subclass, rather than creating the base class. In your design, Loot should probably be an abstract class or even an interface, and you should use the abstract factory pattern to create the desired type of Loot object.
For example:
class LootFactory
{
const int numLootTypes = 3;
public Loot CreateLoot(Vector2 position)
{
Random rand = new Random();
int lootIndex = rand.Next(numLootTypes);
if (lootIndex == 0)
{
return new HealthPack(position);
}
if (lootIndex == 1)
{
...
}
...
}
}
To me it really sounds like you're still going about this the wrong way. While the answer given would work, it's not something you should have to do.
If you want to spawn a new loot and you want it to be a random of the possible types of loot, your constructor of the Loot class should do all that work. There shouldn't be any need for cloning or ICloneable.
When a new loot object is created, it should randomly become the type of loot it's going to be, no need to keep a list of all possible types somewhere and clone from them. The new loot object would then have it's own position and behaviors and work exactly like you're expecting it to.
Or am I just misunderstanding what you're trying to accomplish?