Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
die problematik ohne Prozent rechnung ein Schadenssystem aufzubauen resultiert dann wie in Gothic3 wo man am ende einfach alles one shotted deswegen wollte ich ein skalierungs system das "umso mehr umso weniger bekommst du" macht
hier ist dann mal die skalierung dargestellt wie ich es mir ungefähr vorgestellt habe
Grün = Blunt in der XML => es hilft nichts ob ich 150 oder 1000 rüstung habe, "Prügel schaden" wie zb Streitkolben sollte immer viel schaden machen
Schwarz = Pierce in der XML => wenn ich wenig rüstung habe dagegen bekomm ich viel schaden, bei viel rüstung weniger
Blau = Blade in der XML => der durchschnitt daraus
jede waffe und Rüstung sollte alle "stats" haben die möglich sind wie zb eine EisenRüstung hätte
Java:
Blunt=100
Pierce=100
Blade=100
damit hätte "nach der formel" die rüstung diese REduktions werte
eine auswirkung von
Blunt=60%
Pierce=60%
Blade=85%
wobei man dann wieder sagen könnte ich könnte den ganzen kram auch linear machen und einfach die werte der rüstung so setzen dass es passt...
Momentan knabbere ich immer noch an dem Diagramm "prozenturaler Schaden ist Funktion von Rüstung mit dem Parameter Stabilität"
Da es hier ja nicht um Rollenspiele geht, würde ich mal auf das Thema "Testen" zurückkommen,
Die Codeschnippel sind ungetestet und auch nicht syntaxfehlerfrei. Es geht mir nur mal um das Prinzip.
Im Prinzip würde ich den Ablauf so denken:
Java:
HEALTH=100;
STRENGHT=80;
ARMOR=50;
STABILITY=50;
h1= new Hero(HEALTH,STRENGTH,ARMOR,STABILITY);
EFFECT=50;
w1= new Weapon(EFFECT);
int power= 50;
damage=h1.attac(w1, power);
h1.wounded(damage);
Für alle Nichtrollenspieler: Hier wird ein Held h1 angelegt, der die Attribute Gesundheit, Stärke, Rüstung hat,. Zuätzlich gibt es noch eine Option Stabilität, die für die Stabilität der Rüstung steht. Dann wird ein Objekt w1 angelegt, dass für eine Waffe steht. Diese hat die Eigenschaft Effektivitivät. Ein Messer ist weniger effektiv als ein Schwert.
Die wichigste Methode ist die "attac"-Methode, wo der Held mit der Waffe attakiert wird, wobei die Waffe mit der Kraft "power" geführt wird. Ein kraftvoll geführter Stich mach mehr Schaden als ein Ritzen.
Java:
public class Held{
...
int attac(Weapon w, int power){
int damage;
// Code
return damage;
}
}
Das wäre in meinen Augen die zu testende Funktion.
Bis hierher würde ich übrigens tatsächlich nur die "äußere Hülle" der Klassen und Methoden schreiben, wenn ich mit TDD arbeiten würde.
Nun kann ich Tests schreiben, wo ich genau festlegen kann:
Wie stark wirkt die Rüstung? Wie stabil ist sie?
Wie groß ist der Schaden bei welcher Waffe, die mit welcher Intensität geführt wird?
Ein Test würde dann etwa so aussehen:
Code:
void damageTest(){
Hero h= new Hero(100,50,70,40)
Weapon messer= new Weapon(10)
assertEqual(h.damage(messer,100),20)
}
Und beim Test erhält man erst einen roten Balken. Und muss dann eben die Methode so umschreiben, dass man einen grünen Balken erhält.
Man kann dann auch die hier immer wieder auftauchende Formel einbinden.
Ich halte diesen Ablauf aber für die Arbeit für ziemlich sinnvoll. Weil ich denke, dass der Ablauf des Programmes für alle verständlicher wird.
Und man kann dann auch feststellen, wo Begrenzungen Sinn machen, und was sie eigentlich bedeuten.
gut nun habe ich nochmal hin und her geschaufelt vom aufbau her
ich habe jetzt ein Interface für die Rüstungs Konfiguration, damit sollte es egal werden woher man sie bekommt was bis jetzt noch nicht der Fall war
dann hab ich noch den Basis Resistenz wert eingefügt damit die Formeln mehr sinn ergeben
dann hab ich noch das mit "an xml gebunden" verworfen und durch das interface ersetzt
dann hab ich noch das sinnvoller aufbauen können dadurch dass es jetzt mehr an die Story gebunden ist, jetzt weis ich zumindest wo es damit hingehen soll
vllt tu ich die BaseResistance noch in das interface .. aber das ist ja nur ein Detail
C#:
using BfnDamage.Armory;
using Moq;
namespace BfnDamage;
public class ArmorEffectTests
{
[TestCase(0.8f, 50f, 100f, 0.6333f)]
[TestCase(-100900000f, 50f, 100f, 0.1f)]
[TestCase(-100000000f, -1000000000f, 100f, 0.1f)]
[TestCase(-100000000f, -1000000000f, 0f, 0.1f)]
[TestCase(100000000f, 0.8f, 40f, 0.9f)]
[TestCase(50f, 1000000f, 40f, 0.1f)]
[TestCase(100000000f, 1000000f, 40f, 0.9f)]
public void Calculate_ReturnsExpectedResult(float scalingFactor, float effectiveness, float armorValue, float expectedResult)
{
var mockArmorEffectMaterial = new Mock<IArmorMaterial>();
mockArmorEffectMaterial.SetupGet(a => a.Scaling).Returns(scalingFactor);
mockArmorEffectMaterial.SetupGet(a => a.Effectiveness).Returns(effectiveness);
var armor = new Armor(armorValue);
var result = armor.GetEffectivePercentage(mockArmorEffectMaterial.Object); ;
Assert.That(result, Is.EqualTo(expectedResult).Within(0.01f));
}
}
C#:
namespace BfnDamage.Armory;
public interface IArmorMaterial
{
/// <summary>
/// Name of the Armors Material
/// </summary>
public string Name { get; init; }
/// <summary>
/// Defines the maximum of an Armors Effectiveness in Relation to the Armor and <see cref="Effectiveness"/>
/// </summary>
public float Scaling { get; init; }
/// <summary>
/// Defines how Quick the Armor will reach its maximum Effectiveness
/// The lower the quicker it will reach the Maximum.
/// </summary>
public float Effectiveness { get; init; }
}
C#:
namespace BfnDamage.Armory;
/// <summary>
/// Calculates the Effectiveness of an Armor
/// </summary>
public class Armor {
public float LowestScalingFactor { get; init; } = 0f;
public float LowestEffectiveness { get; init; } = 10f;
public float BaseResistance { get; init; } = 0.1f;
public float HighestResistance { get; init; } = 0.9f;
private readonly float _armor;
public Armor(float armor)
{
_armor= armor;
}
/// <summary>
/// Transforms the Armor to the effective Reduction of damage.
/// This value is Clamped by <see cref="BindToResistanceBorders(float)"/>
/// </summary>
/// <param name="armor">The amount of Armor that needs to be transformed to a Percentage</param>
/// <returns>The Percentage of how much this Armor can reduce</returns>
public virtual float GetEffectivePercentage(IArmorMaterial material)
{
var clampedEffect = BindToLowest(material.Effectiveness, LowestEffectiveness);
var clampedFactor = BindToLowest(material.Scaling, LowestScalingFactor);
return BindToResistanceBorders((_armor / (_armor+ clampedEffect) * clampedFactor) + BaseResistance);
}
/// <summary>
/// clamps the value between <see cref="BaseResistance"/> and <see cref="HighestResistance"/> so it will always be an percentage between these two values.
/// </summary>
/// <param name="value"></param>
/// <returns>Clamped value between <see cref="BaseResistance"/> and <see cref="HighestResistance"/></returns>
private float BindToResistanceBorders(float value)
{
return Math.Clamp(value, BaseResistance, HighestResistance);
}
private float BindToLowest(float value, float lowestValue)
{
if (value < lowestValue)
return lowestValue;
return value;
}
}
ich hätte es nicht hingekriegt die grenzfälle zu betrachten, ich tu mich da eigentlich ziemlich schwer
bei einer Mathe formel wäre es da eigentlich das einfachste wenn man das jetzt mit deinen beispielen betrachtet.. und nicht mal da krieg ich es hin
wie denkt man dass man die grenzfälle raus bekommt? sollte ich mir den dämlichst möglichen fall überlegen?
Stichworte in die Richtung wären Äquivalenzklassen und Grenzwerte, zu beidem müsste man per Google auch was finden. Damit denkt man grad in solchen Fällen den Großteil der „kritischen“ Eingaben ab, vor allem aber auch die Invaliden Eingaben.
Was man in diesem Fall, wenn man das Innere der Methoden kennt, auch machen kann, ist sich Teil-Terme anzugucken. Man muss sich dann überlegen, welche Werte an den Stelle kritisch sein könnten, zB 0, 1, sehr hohe Werte, und dann ausgehend davon, welche Eingaben diese Werte provozieren. Damit fängt man dann in diesem Fall sowas wie Division durch 0 ab.
Als drittes kann man, wenn man die Funktion schon in geogebra oder so hat, sich einfach Beispielwerte als Tabelle geben lassen, und diese dann als Eingabe für die Tests zu nutzen. Dient dann gleichzeitig auch noch als schöne Doku.