This is a code for MonoGame 3.8.1 and .NET 6.
public interface IEntity
{
int Size { get; }
Vector2 Position { get; }
}
public class Player : IEntity
{
public int Size { get; } = 32;
public Vector2 Position { get; private set; }
public Player(Scene scene)
{
var spawnOffset = new Vector2(0, -3);
Position = new Vector2(
spawnOffset.X * scene.TileSize + scene.Room.Center.x - Size / 2,
spawnOffset.Y * scene.TileSize + scene.Room.Center.y - Size / 2);
}
}
public class Enemy : IEntity
{
public int Size { get; } = 32;
public Vector2 Position { get; private set; }
public Enemy(Scene scene)
{
var spawnOffset = new Vector2(0, 0);
Position = new Vector2(
spawnOffset.X * scene.TileSize + scene.Room.Center.x - Size / 2,
spawnOffset.Y * scene.TileSize + scene.Room.Center.y - Size / 2);
}
}
Without the use of inheritance, I want every class that implements IEntity to be able to reuse calculations for Position assignment. The only difference between both constructors is the spawnOffset values.
What's the most simple way to do this?
Normally - I would call the base class constructor, but here I'm trying to do this without a base class.
Looks like you follow "prefer composition over inheritance" - indeed that is a valid approach, just finish that by extracting "position" functionality into separate class:
class EntityPosition
{
public Vector2 Position { get; private set; }
public EntityPosition (Scene scene, Vector2 spawnOffset, int size)
{
Position = new Vector2(
spawnOffset.X * scene.TileSize + scene.Room.Center.x - size / 2,
spawnOffset.Y * scene.TileSize + scene.Room.Center.y - size / 2);
}
// add other shared methods for position updates here as necessary
}
public class Player : IEntity
{
EntityPosition position;
public int Size { get; } = 32;
public Vector2 Position => position.Position;
public Player(Scene scene)
{
var spawnOffset = new Vector2(0, -3);
position = EntityPosition(scene, spawnOffset, Size);
}
}
Related
I have a problem. I created a TriangleGrid using SkiaSharp. While I was drawing the grid I saved each triangle info in a Dictionary. The Dictionary looks like this:
public class TriangleRegistryObject
{
public float x1 { get; set; }
public float y1 { get; set; }
public float x2 { get; set; }
public float y2 { get; set; }
public float x3 { get; set; }
public float y3 { get; set; }
public bool Selected { get; set; }
public bool Visible { get; set; }
}
Now when I select a Triangle I set the boolean Selected to true. At the end I want to check if the Triangles I have selected are connected with eachother. I thought I could count the connected lines. Here is an example image:
Now I want to count the purple lines where Selected=true.
I have every coordinate (x1, y1) (x2, y2) and (x3, y3).
UPDATE:
Here is the code I use that return 0 for me!
public static bool ValidLayout()
{
bool IsValid;
int sharedEdges;
int SelectedTriangles = TriangleRegistry.Count(tr => tr.Value.Selected.Equals(true));
var triangles = new List<TriangleRegistryList>();
foreach (KeyValuePair<string, TriangleRegistryObject> row in TriangleRegistry.Where(n => n.Value.Selected == true).ToList())
{
triangles.Add(new TriangleRegistryList { x1 = row.Value.x1,
y1 = row.Value.y1,
x2 = row.Value.x2,
y2 = row.Value.y2,
x3 = row.Value.x3,
y3 = row.Value.y3
});
}
sharedEdges = triangles.GetKCombs(2).Where(t => t.First().IsAdjacentTo(t.Skip(1).Take(1).Single())).Count();
if (sharedEdges >= (SelectedTriangles - 1))
{
IsValid = true;
}
else
{
IsValid = false;
}
return IsValid;
}
But I have no idea how I can compare the coordinates with each other, to count the connected lines!
Can someone help me?
Here is a very simple solution. It definitely isn't the most efficient, but it gets the job done.
I've added a method to your triangle class that returns true if it shares at least 2 vertices with another triangle.
I've also used a method of finding the distinct permutations that is slightly modified from the one discussed here.
public class Program
{
public static void Main()
{
var triangles = new List<TriangleRegistryObject>{
new TriangleRegistryObject{x1=10,y1=10, x2=12,y2=10, x3=1,y3=11},
new TriangleRegistryObject{x1=9,y1=11, x2=11,y2=11, x3=10,y3=10},
new TriangleRegistryObject{x1=9,y1=11, x2=11,y2=11, x3=10,y3=12},
new TriangleRegistryObject{x1=34,y1=14, x2=15,y2=11, x3=10,y3=12},
};
var sharedEdges = triangles.GetPairs().Where(t => t.first.IsAdjacentTo(t.second)).Count();
Console.WriteLine($"Number shared edges: {sharedEdges}");
}
}
public class TriangleRegistryObject
{
public float x1 { get; set; }
public float y1 { get; set; }
public float x2 { get; set; }
public float y2 { get; set; }
public float x3 { get; set; }
public float y3 { get; set; }
public bool Selected { get; set; }
public bool Visible { get; set; }
public IEnumerable<(float x, float y)> GetPoints()
{
yield return (x1, y1);
yield return (x2, y2);
yield return (x3, y3);
}
public bool IsAdjacentTo(TriangleRegistryObject other)
{
return this.GetPoints().Intersect(other.GetPoints()).Count() >= 2;
}
}
public static class EnumerableExtensions
{
public static IEnumerable<(T first, T second)> GetPairs<T>(this IEnumerable<T> list)
{
return list.SelectMany((value, index) => list.Skip(index + 1),
(first, second) => (first, second));
}
}
I am making a food / water system, so when you are 0 on food or water you will loose some health, this shall go even faster when you are 0 on both. But i keep getting this Error "ERROR: The property or indexer "CharacterStats.currentHealth" cannot be used in this context because the set accessor is inaccessible." Here is my scripts can you guys help me, down below is my scripts.
public class PlayerStats : CharacterStats
{
public string ID{get;protected set;}
public Texture healthIcon;
public Texture waterIcon;
public Texture foodIcon;
public float water = 100;
public float food = 100;
// Use this for initialization
void Start()
{
EquipmentManager.instance.onEquipmentChanged += OnEquipmentChanged;
}
void OnEquipmentChanged(Equipment newItem, Equipment oldItem)
{
if (newItem != null)
{
armor.AddModifier(newItem.armorModifier);
damage.AddModifier(newItem.damageModifier);
}
if (oldItem != null)
{
armor.RemoveModifier(oldItem.armorModifier);
damage.RemoveModifier(oldItem.damageModifier);
}
}
public override void Die()
{
base.Die();
//Kill the player in some way
PlayerManager.instance.KillPlayer();
}
public void OnGUI()
{
//GUIStyle style = "box";
GUIStyle style = "box";
var healthstring = currentHealth.ToString("0");
var waterstring = water.ToString("0");
var foodstring = food.ToString("0");
//Health
GUI.Label(new Rect(10, 10, 100, 30), healthstring, style);
GUI.DrawTexture(new Rect(15, 12, 100 / 4, 25), healthIcon, ScaleMode.StretchToFill, true, 10f);
//Water
GUI.Label(new Rect(240, 10, 100, 30), waterstring, style);
GUI.DrawTexture(new Rect(245, 12, 100 / 4, 25), waterIcon, ScaleMode.StretchToFill, true, 10f);
//Food
GUI.Label(new Rect(355, 10, 100, 30), foodstring, style);
GUI.DrawTexture(new Rect(360, 12, 100 / 4, 25), foodIcon, ScaleMode.StretchToFill, true, 10f);
}
public void Update()
{
if(water <= 0)
{
Debug.Log("Losing food");
currentHealth = currentHealth - 1;
}
}
}
2nd-----------------------------------------------------------------------------
public class CharacterStats : MonoBehaviour {
public int maxHealth = 100;
public float currentHealth { get; private set; }
public Stat damage;
public Stat armor;
void Awake()
{
currentHealth = maxHealth;
}
public void TakeDamage(int damage)
{
damage -= armor.GetValue();
damage = Mathf.Clamp(damage, 0, int.MaxValue);
currentHealth -= damage;
Debug.Log(transform.name + " takes " + damage + " damage");
if(currentHealth <= 0)
{
Die();
}
}
public virtual void Die()
{
Debug.Log(transform.name + " died.");
}
}
The reason it doesn't work is because you have a private set. The problem with a private set is that the value can only be changed in the containing type CharacterStats and not derived types PlayerStats.
public class CharacterStats
{
public float Health {get; private set;}
public float HealthA2 {get; set;}
public CharacterStats()
{
Health = 100;//I can change the value in the constructor. Making this immutable
}
public void DoWork()
{
Health = 75;//I can again change the value after construction so immutable not so much after all
}
}
public class PlayerStats : CharacterStats
{
public void MoreWork()
{
HealthA2 = 50;//This works
//Health = 50;//ERROR: I cannot change a private set in the derived class. For that I need at least protected set;
}
}
See also Immutable. And accessibility levels.
I need to further my knowledge of IInterface classes used with abstract classes. Whether this stuff is ever used have work requirements to learn a little more about it.
What I think an interface is (this works and calculates area for 3 items, Rectangle, Triangle, Circle using values provided):
static void Main(string[] args)
{
Rectangle r = new Rectangle(4, 8, "Rectangle");
Triangle t = new Triangle(4, 4, "Triangle");
Circle c = new Circle(3, "Circle");
r.DisplayArea();
Console.WriteLine();
t.DisplayArea();
Console.WriteLine();
c.DisplayArea();
Console.ReadKey();
}
Here is my abstract class. It looks like it deals with the name of what is being measured:
namespace DrawShapes
{
abstract class Shape
{
public string name;
public abstract void DisplayArea();
public Shape(string name)
{
this.name = name;
}
}
I'm not positively sure but wouldn't these be in the IInterface class and get set or called somehow? Definitely not an expert at this object oriented stuff.
public int Radius { get; set; }
public int Height { get; set; }
public int Width { get; set; }
Instead, I am hardcoding the parameters into the "function call":
static void Main(string[] args)
{
Rectangle r = new Rectangle(4, 8, "Rectangle");
Triangle t = new Triangle(4, 4, "Triangle");
Circle c = new Circle(3, "Circle");
}
I personally can't think of why or how I would use IInterface.
Just to be complete and maybe help someone who is looking for stuff like this, here are my classes to calculate areas.There are other SO answers to calculate areas, this question is about IInterface and abstract classes:
namespace DrawShapes
{
class Rectangle : Shape
{
public int length;
public int width;
public Rectangle(int length, int width, string name) : base(name)
{
//this.angles = angles;
this.length = length;
this.width = width;
}
public override void DisplayArea()
{
Console.Write(name + "--");
Console.Write(length * width);
}
}
class Triangle : Shape
{
// public int angles;
public int width;
public int height;
public Triangle(int width, int height, string name) : base(name)
{
//this.angles = angles;
this.width = width;
this.height = height;
}
public override void DisplayArea()
{
Console.Write(name + "--");
Console.Write((width * height) / 2);
}
}
class Circle : Shape
{
public int radius;
public Circle(int radius, string name) : base(name)
{
this.radius = radius;
}
public override void DisplayArea()
{
Console.Write(name + "--");
Console.Write(3.22 * radius * radius);
}
}
}
So I'm quite new to programming in general. I'm currently working on a terrain generation program, everything is going great except for this:
public static class Desert
{
public const int iChance = 15;
public static int chance = iChance;
public static int chancepoint = 0;
public const int octaves = 4;
public const int lengthMin = 60;
public const int lengthMax = 90;
public const float scaleMin = 250;
public const float scaleMax = 350;
public const float persistenceMin = 0.5f;
public const float persistenceMax = 0.9f;
public const pType ptype = pType.Lowland;
public const bTag[] tags = { bTag.desert };
}
public static class Meadow
{
public const int iChance = 45;
public static int chance = iChance;
public static int chancepoint = 0;
public const int octaves = 4;
public const int lengthMin = 45;
public const int lengthMax = 70;
public const float scaleMin = 200;
public const float scaleMax = 470;
public const float persistenceMin = 0.35f;
public const float persistenceMax = 0.70f;
public const pType ptype = pType.noAbs;
public const bTag[] tags = { bTag.lush };
}
These are the properties for each different type of 'Biome'.
I currently have about 7 of these and they're all exactly the same except for the values of each field.
Is there a way that I can shorten the code? I looked into inheritance but I ended up with errors and I got a little confused. ><
It would be brilliant if all I had to write was:
public static class Desert
{
iChance = 15;
chance = iChance;
chancepoint = 0;
octaves = 4;
lengthMin = 60;
lengthMax = 90;
scaleMin = 250;
scaleMax = 350;
persistenceMin = 0.5f;
persistenceMax = 0.9f;
ptype = pType.Lowland;
strongTags = { bTag.desert };
}
Thanks in advance.
Oh, and sorry about the nubness of the question, you would probably scream at how terrible my code was if you saw the rest of the program. XD
EDIT: It's probably wise to tell you that I NEVER change the stuff within the class again with the exception of the value of 'chance'.
Instead of using a static class, you can use a non-static class.
public class Biome {
// Instance fields with default values
public int iChance = 15;
public int chance = iChance;
public int chancepoint = 0;
public int octaves = 4;
public int lengthMin = 60;
public int lengthMax = 90;
public float scaleMin = 250;
public float scaleMax = 350;
public float persistenceMin = 0.5f;
public float persistenceMax = 0.9f;
public pType ptype = pType.Lowland;
public bTag[] tags = { bTag.desert };
}
Here use the constructor for initializing:
public Biome(int iChance, int chance, int chancepoint, int octaves, public int lengthMin, int lengthMax, float scaleMin, float scaleMax, float persistenceMin, float persistenceMax,pType ptype, bTag[] tags) {
// init fields here
}
Then call the constructor:
Biome bimoe = new Biome(15, iChance, 0, 4, 60, 90, 250, 350, 0.5f, 0.9f, pType.Lowland, { bTag.desert });
With this it's difficult to see which parameter goes to which field, but it's much shorter.
If the fields must be read-only, you can make properties with only a public get and no set accessor. Example:
public Chance { get { return chance; } }
In this case make the fields private:
private int chance = iChance;
(Personally, for such a scenario, i would put all the data in a file)
The following would be shorter:
public const int iChance = 15, octaves = 4, lengthMin = 60, lengthMax = 90;
public const float scaleMin = 250, scaleMax = 350, persistenceMin = 0.5f,
persistenceMax = 0.9f;
public static int chance = iChance, chancepoint = 0;
However... these really don't look like things that should be static fields, or quite possibly not even const. They look like things that should be instance properties. Maybe something like:
public class Terrain {
public int Chance {get;private set;}
public int LengthMin {get;private set;}
// ...
private Terrain(int chance, int lengthMin, ...) {
Chance = chance;
LengthMin = lengthMin;
// ...
}
private static readonly Terrain
desert = new Terrain(45, 45, ...),
meadow = new Terrain(15, 60, ...),
...;
public static Terrain Desert { get { return desert;}}
public static Terrain Meadow { get { return meadow;}}
}
I don't know much about terrain generation programs, but you should store your data in a database.
Then create classes to map that data to your application.
I recommend you to lookup "Data structures" and see which one fits your application the best.
It's better to use only one class without inheritance, or even structure. Desert, Meadow and so on are not classes logically, it's have to be objects (maybe constants).
What you could do is use a single class called Terrain and Initialise this multiple times using a static constructor:
public class Terrain
{
public int IChance { get; private set; }
public int Chancepoint { get; private set; }
public int Octaves { get; private set; }
public int LengthMin { get; private set; }
public int LengthMax { get; private set; }
public float ScaleMin { get; private set; }
public float ScaleMax { get; private set; }
public float PersistenceMin { get; private set; }
public float PersistenceMax { get; private set; }
public pType Ptype { get; private set; }
public bTag[] Tags { get; private set; }
public static Terrain Desert()
{
return new Terrain
{
IChance = 15,
Chancepoint = 0,
Octaves = 4,
LengthMin = 60,
LengthMax = 90,
ScaleMin = 250,
ScaleMax = 350,
PersistenceMin = 0.5f,
PersistenceMax = 0.9f,
Ptype = pType.Lowland,
Tags = new bTag[] {bTag.Desert}
};
}
}
joe's answer is good, but the constructor call has far too many unnamed parameters - what does the 350 mean?
This is an ideal candidate for data driven design.
Rather than define all the Biome types in the code, put all the data for the Biome types into a file and read the file at run time. The C# language has a lot of stuff to help you do this, the key word to search for is Serialisation (and here's a link to MSDN about it).
The big advantage is that you can change the data values without needing to recompile the code.
The disadvantage is that is takes a lot more code to define the first instance, but after that, you can easily create as many instances as you want.
You could do something like declaring an abstract class like this and then inherting from it:
public abstract class Terrain
{
public int iChance;
public int chance;
public int chancepoint;
public int octaves;
public int lengthMin;
public int lengthMax;
public float scaleMin;
public float scaleMax;
public float persistenceMin;
public float persistenceMax;
public pType ptype;
public Tag[] strongTags;
}
public class Desert : Terrain
{
}
public enum pType
{
Desert = 1,
LowLand = 2
}
public enum Tag
{
desert = 1,
lush = 2
}
You can then instantiate desert like :
var desert = new Desert()
{
iChance = 15
,chance = 15
,chancepoint = 0
,octaves = 4
,lengthMin = 60
,lengthMax = 90
,scaleMin = 250
,scaleMax = 350
,persistenceMin = 0.5f
,persistenceMax = 0.9f
,ptype = pType.Desert
,strongTags = new Tag[]{Tag.desert}
};
Not sure what your exact requirements are but wouldn't this be a better approach:
public abstract class BiomeBase
{
public int Chance { get; set; }
public int Chancepoint { get; set; }
public int Octaves { get; set; }
// you get the idea ...
}
Then you have Desert and Meadow inheriting:
public class Desert : BiomeBase
{
// everything is inherited ...
// you can also add your own properties meant for Desert only (if needed)
}
public class Meadow : BiomeBase
{
// everything is inherited ...
}
Now Desert has everything Biome has and you can use it like this:
var desert = new Desert
{
Chance = 5,
Octaves = 1,
/// etc
};
Firstly you cant do inheritance on static classes. So you would have to start using instances.
Secondly you would use inheritance if you wanted to extend the object. So for instance if you wanted to add a new property "bool HasScorpions" onto Desert but not on Meadow.
Since your using the same properties but want to use different values I personally use an Interface. This way you can make the properties readonly ect while still easily setting the values.
public interface Terrain
{
int iChance = {get { return 15; private set; } ..and repeat.
int chance = iChance;
int chancepoint = 0;
int octaves = 4;
int lengthMin = 60;
int lengthMax = 90;
float scaleMin = 250;
float scaleMax = 350;
float persistenceMin = 0.5f;
float persistenceMax = 0.9f;
pType ptype = pType.Lowland;
bTag[] tags = { bTag.desert };
}
Im trying to create a seesaw with ball on its shape, that based on the shapes angle, the ball rolls.
Here is the screenshot of it.
So, the shape of the seesaw moves based on the angle generatated by a trackbar value.
Here are the variables declared:
private const float ONE_DEGREE = 0.0174532924f;
private ID3DMesh tab;
private ID3DMesh ball;
The 'tab' variable is the shape.
This method sets the angle of the shape:
public void setShapeAngle(float degree)
{
tabTargetAngle = Util.DegreeToRadian(degree);
}
And here is the method that updates it:
public void Update(int elapsedTime)
{
if (tab.Pitch != tabTargetAngle)
{
if (tabTargetAngle > tab.Pitch)
{
if (tab.Pitch >= (tabTargetAngle - ONE_DEGREE))
{
tab.Pitch = tabTargetAngle;
}
else
{
tab.Pitch += tabuaSpeed * elapsedTime;
}
}
else if (tabTargetAngle < tab.Pitch)
{
if (tab.Pitch <= (tabTargetAngle + ONE_DEGREE))
{
tab.Pitch = tabTargetAngle;
}
else
{
tab.Pitch -= tabuaSpeed * elapsedTime;
}
}
}
}
All of the objects, are ID3DMesh objects. Here is the code of the ID3DMesh class.
public interface ID3DMesh : IDisposable
{
Color Ambient { get; set; }
CollisionTestMethod CollisionDetectionMethod { get; set; }
Mesh D3DXMesh { get; }
Color Diffuse { get; set; }
Color Emissive { get; set; }
Material[] Materials { get; set; }
ID3DMesh Parent { get; set; }
float Pitch { get; set; }
Vector3 PivotOffset { get; set; }
float PivotOffsetX { get; set; }
float PivotOffsetY { get; set; }
float PivotOffsetZ { get; set; }
Vector3 Position { get; set; }
RenderOptions RenderSettings { get; set; }
float Roll { get; set; }
Vector3 Scale { get; set; }
float ScaleX { get; set; }
float ScaleY { get; set; }
float ScaleZ { get; set; }
Color Specular { get; set; }
float SpecularSharpness { get; set; }
Texture[] Textures { get; set; }
Color WireColor { get; set; }
float X { get; set; }
float Y { get; set; }
float Yaw { get; set; }
float Z { get; set; }
MeshBoundingBox GetBoundingBox();
MeshBoundingSphere GetBoundingSphere();
float GetDepth();
float GetHeight();
float GetWidth();
Matrix GetWorldMatrix();
bool Intersects(ID3DMesh mesh);
void Link(ID3DMesh parentMesh, Vector3 linkPosition);
void Move(float xAmount, float yAmount, float zAmount);
void Render();
void RenderPlanarShadow(Plane groundPlane, Light light, bool allowDoubleBlending);
void SetDepth(float depth);
void SetDepth(float depth, bool uniformScale);
void SetHeight(float height);
void SetHeight(float height, bool uniformScale);
void SetPlanarShadowOpacity(float shadowOpacity);
void SetScale(float amount);
void SetScale(float xAmount, float yAmount, float zAmount);
void SetSize(float width, float height, float depth);
void SetWidth(float width);
void SetWidth(float width, bool uniformScale);
}
I tried to use the Move(float, float, float) method. But it didnt moved as it should. If you could help me with that.
Thank you.
(Note: Below I'll be ignoring the third dimension, because the ball will always move along the same plane)
If we take the seesaw as a reference frame, I think the movement of the ball will be similar to that of an harmonic oscillator. That is to say, the position of the ball along the seesaw at a given instant of time, s(t), will be given by the following formula:
s(t) = L cos(2π t / T + ϕ)
where L is the length of the seesaw (the amplitude of the harmonic) and T is the time it takes the ball to move from one end of the seesaw to the other and back to the start (the period of the harmonic). ϕ, the initial phase of the harmonic, is there to adjust the formula so s(0) gives you the starting position. If you want it to start at the center, you need to make s(0) = 0, which means you need the cosine to be 0. So you have to make ϕ be π/2 (90 degrees), because cos(π/2) = 0.
With this you can put the ball in place by changing the world transform. If you rotate it to the current angle of the seesaw (let's call it θ(t)), you can just translate the ball by the value of s(t) along the xx axis.
This is equivalent to treating (s(t),θ(t)) as the position of the ball in polar coordinates. You can then get the cartesian coordinates at a given time (x(t),y(t)) with these formulae:
x(t) = s(t) cos(θ)
y(t) = s(t) sin(θ)
(Let's assume the up-vector is (0, 1, 0) and the tab is aligned with the X-axis)
You can imagine the ball would have to "roll" down the tab along the X-axis, and you would have to calculate the Y-position to let it stick to the tab.
You could use the Move() method for the X position, as the ball's speed has an impact on it's X-position in a relative way.
The Y-position though (as long as the ball remains on the tab) could more easily be calculated for each X-position, by setting the Y property.
If I were you I'd start by creating a method that calculates the Y position to make the ball "stick to the tab" for any X position.
If this doesn't point you in the right direction, please elaborate a bit more on "it didnt moved as it should".