|
|
|
|
12h Spielzeit \o/
Irgendeins von den Upgrades + Level 5 Shotgun ist komplett eskaliert, hab den in 20 Sekunden runtergeschossen gehabt. ![Breites Grinsen](img/smilies/biggrin.gif)
![](https://i.imgur.com/QoRvsV9.jpg)
|
|
|
|
|
|
|
Wow da war aber einer fleißig Also das mit dem händler/spawnen ist auf jeden fall ein bug da gucken wir mal. Die upgrade preise sind ein bischen... doof. Wissen wir kommt mit dem nächsten patch anders. Geld verliert man immer wenn man den aktuellen run verläßt, egal ob getorben oder zurück ins main menu. Das hilft im späteren spiel mit money keep das exploiten zu verhinden , am anfang ist es ok wenn wer drauf kommt . Was da beim boss passiert ist... Du hast auf jeden fall 4 mousteache extensions, die geben 120% attack speed wenn die proccen, scrap clover pin gibt 10% auf nen extra schuß, capitalist gun auch noch mal 10% attack speed und wieviele stacks das scavenger tool hat sieht man ja hier leider nicht. Da kann schon was zusammen kommen. Ist das dann nur beim boss passiert oder vorher auch? Und könntest du mal deine upgrades posten?
|
[Dieser Beitrag wurde 2 mal editiert; zum letzten Mal von FooFur am 03.04.2018 12:30]
|
|
|
|
|
|
Muss mal daheim schauen, aber fire speed hatte ich +2% / +3%, +dmg 2 vor dem 999 upgrade, also nichts unfassbar hohes.
Hatte auch schon davor eskaliert, praktisch immer wenn die geprocct haben.
Kam mir aber irgendwie so vor, dass sobald 1 procct, die Zeit verlängert wird und dabei den effekt stackt.
D.h. jedes mal wenn eins triggert, erhöht sich die Zeit wieder und irgendwann eskaliert der Effekt.
|
|
|
|
|
|
|
Bei 3:30 gehts los.
|
|
|
|
|
|
|
Mal ne kurze Frage, weil ich gerade drauf gestoßen bin. Kann man in C# irgendwie value-types per "ref" übergeben? Oder komm ich nur drumrum indem ich den value-type in ner reference-type class wrappe und mit der Klasse arbeite? Kommt mir etwas übertrieben, wenn auch logisch vor
|
|
|
|
|
|
|
|
|
|
|
Achso ja, hätte dazusagen sollen, dass es kein StandardType ist. Dachte das macht es kaputt, aber es war doch was anderes. Trotzdem danke für den RTFM Hinweis :P
e:
void Method1 (ref [object]) {} darf ich nicht mit Method1(ref [float]) aufrufen. Als value kriegt er die Konvertierung hin
|
[Dieser Beitrag wurde 1 mal editiert; zum letzten Mal von freakadelle am 14.04.2018 0:12]
|
|
|
|
|
|
![](https://i.imgur.com/1moFG63.jpg)
Endlich mal wieder etwas Fortschritt bei meinen character models. Werkstatt ist, wie man sieht, etwas provisorisch zum Scan-Studio hergerichtet worden.
Heute kam die Schaufensterpuppe, die noch zerteilt da rumliegt. Damit kann ich dann auch endlich mal langärmlige Oberteile scannen. Wenn man sich zeit nimmt dauert ein Durchgang schonmal 5-10 Minuten, weshalb mir ziemlich schnell die Versuchsopfer ausgegangen sind. Neben dem Stillhalten gabs dann noch zusätzlich das Problem, dass Hände und Kopf immer etwas im Weg sind. Die gelenkige Puppe kann ich an meine T-Pose in 3DsMax anpassen und mir Zeit beim scannen lassen.
Der Depth Sensor, den ich von MadMax geliehen habe, produziert dabei sowas hier:
![](https://i.imgur.com/4ZCN3wj.jpg) ![](https://i.imgur.com/Sbw2hMV.jpg)
Reicht für mein Projekt vollkommen und hat sogar den Vorteil, dass ich das mesh kaum cleanen muss. Einfach ne simple re-topo und baken. Hier und da während des Texturierens in Substance Painter ein paar Fehler fixen und das passt. Für FirstPerson etwas low, aber für eine Art top-down perspektive, bei der alle Details ab 5m eh flöten gehn passt das.
Mit der Pipeline verschwende ich im besten Fall nicht meine ganze Zeit damit ein paar wenige super high quality assets zu baun, sondern kann wesentlich mehr content raushaun.
|
[Dieser Beitrag wurde 3 mal editiert; zum letzten Mal von freakadelle am 17.04.2018 20:56]
|
|
|
|
|
|
Den ersten "Screenshot" gesehen ohne zu lesen "Hmm ist das Ingame oder gerendert.." .. text gelesen .. "oh.."
|
|
|
|
|
|
|
![](https://i.imgur.com/xBXGK4Y.png)
TBA? Hau mal raus :P
Germandevdays
|
|
|
|
|
|
|
Jo, hab Lust ein Tycoon Game zu bauen, mehr oder minder from scratch, hab auch schon ne grobe Ahnung wie die engine dahinter aussehen könnte.
Nichts desto trotz, hat jemand vielleicht interessante Artikel zu Tycoon/Simulation Game Entwicklung?
Fänds cool schonmal grob zu wissen in welche Fails ich laufen werde
|
|
|
|
|
|
|
Vertex Shader Animationen anstatt Skeletal Meshes (falls) nutzen.
|
|
|
|
|
|
|
Schwierig ohne weitere Informationen, aber Instancing ist mit Sicherheit generell ein gutes Stichwort
|
|
|
|
|
|
|
Eventuell über ECS (Entity Component System) und Pools informieren wenn du full retard gehen willst.
|
|
|
|
|
|
|
Ist das nicht ein unityspezifischer Term? Im grunde beschreibt das doch nur _einen_ data-oriented approach mit extrem optimiertem memory-layout.
e: Ok, mal auf Wikipedia geschaut. Jetzt frag ich mich noch mehr wieso die das feature in Unity so genannt haben, wenn es ein genereller Begriff ist ...
e2: Das Component System ist ja von Anfang an elementarer Bestandteil der engine, aber jetzt mit 2018 bringen sie das "Entity Component System" als neues features, was wie gesagt wie oben erwähnt einen data-oriented Ansatz mit reinbringt.
|
[Dieser Beitrag wurde 2 mal editiert; zum letzten Mal von freakadelle am 24.04.2018 19:15]
|
|
|
|
|
|
Component System != ECS.
Unreal hat auch ein Component System, ist allerdings von ECS meilenweit entfernt.
|
|
|
|
|
|
|
https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system
Das liest sich aber wie gesagt anders.
Der letzte Satz beschreibt ganz schon wieso ich das so verwirrend finde:
Common ECS approaches are highly compatible and often combined with data oriented design techniques.
Denn genau letzteres heisst in Unity plötzlich ECS, obwohl ein Component System wie im restlichen Absatz beschrieben schon immer in der engine existierte
e: Der Rest des Artikels unterscheidet dann zwar doch noch etwas genauer, ganz zufrieden bin ich alleridings nicht Vielleicht sollte ich das doch mal studieren.
Jedenfalls: Würde bei nem Tycoon game sicherlich helfen
|
[Dieser Beitrag wurde 1 mal editiert; zum letzten Mal von freakadelle am 24.04.2018 20:00]
|
|
|
|
|
|
Ah merci, ECS ist doch schonmal n cooles Keywort, wusste gar nicht dass es da ein pattern für gibt.
|
|
|
|
|
|
|
| Zitat von FreeHawk*
Jo, hab Lust ein Tycoon Game zu bauen, mehr oder minder from scratch, hab auch schon ne grobe Ahnung wie die engine dahinter aussehen könnte.
Nichts desto trotz, hat jemand vielleicht interessante Artikel zu Tycoon/Simulation Game Entwicklung?
Fänds cool schonmal grob zu wissen in welche Fails ich laufen werde
| |
Schon eine Vorstellung welche engine / Technologie?
|
[Dieser Beitrag wurde 1 mal editiert; zum letzten Mal von X-Tender am 27.04.2018 12:26]
|
|
|
|
|
|
halt die sim update Frequenz gering, die wird sehr wahrscheinlich die performance bremse werden.
renderer am besten, soweit wie möglich, von der sim entkoppeln.
die sim updates sollten zu exakten zeiten laufen, also keine grösseren spikes haben, da dort ansonsten lustige inkonsistenzen auftauchen können, bei denen du nicht weist, woher die kommen, weil alle deine "systeme" korrekt sind.
du kannst hier besser was für nen sim frame pausieren, als einfach immer alles zu simulieren.
LOD, LOD und LOD (render, sim, etc). nen sauber funktionierendes world management system, wenn es top-down sein sollte. das unterscheidet sich teil recht gut, von gewöhnlichen perspektivischen sachen (FPS, 3rd Person, etc).
vorsicht mit script sprachen, die laufen in aller regel alle single threaded und werden der limitierende faktor.
was du dir anschauen solltest sind job/task systeme, du spawnst n threads (je nach platform) und nagelst die an die cores / hw-threads. die ziehen sich ihre jobs aus ner globalen oder per-thread queue und arbeiten die ab. du solltest hier nach möglichkeit keine synchronisation zwischen den einzelnen threads / jobs haben. du kannst den state besser doppelt vorhalten, einmal für den aktuellen und einmal für den letzten "frame".
was potentiell für die sim interessant sein kann ist eine fibre implementation. das ist dann kooperatives multitasking, soll heissen du kannst methoden mitten drin unterbrechen (yield) und was anderes machen, dann später an genau der stelle weitermachen, wenn irgendeine abhängigkeit erfüllt ist.
was die ECS sachen angeht:
der grund, warum das in den letzten jahren beliebter wurde ist, weil die welten immer mehr sachen beinhalten, die flexibel sein müssen / sollen.
das alte system, den ganzen kram monolithisch zu machen ist in dem fall problematisch, weil du effektiv alles immer von vornherein festlegen musst und du das ganze z.b. nicht vernünftig über nen editor managen kannst.
zusätzlich kann man sich das inzwischen leisten, weil die CPUs einfach extrem viel schneller geworden sind, als zu dem zeitpunkt als die das erste mal aufkamen. ebenfalls bietet es sich dann daraus job graphen zu machen, damit die sachen schön parallel abgearbeitet werden können.
primär gehts dabei aber um die flexibilität und die managebarkeit, damit designer und co damit einfach arbeiten können und nicht immer nen programmierer anhauen müssen, damit irgendein entity was neues machen kann. mit dem system stellst du als programmierer einfach ein "paar" blöcke zur verfügung die du dann mehr oder weniger frei mit einander kombinieren kannst.
|
|
|
|
|
|
|
Naja ein richtiges ECS geht nicht nur darum einfach nur Componenten irgendwo ranzukoppeln.
Es geht darum von OOP wegzukommen und damit die Cache-Lines zu optimieren - was im Grunde bedeutet dass du von 1000-10000 entity handling auf 100.000 kommst. (geschätzt)
https://github.com/SergeyMakeev/ecs
|
[Dieser Beitrag wurde 2 mal editiert; zum letzten Mal von Murica am 28.04.2018 13:13]
|
|
|
|
|
|
![](https://i.imgur.com/IekrFgL.jpg)
Besser wirds mit der Technik nicht, aber ich bin zufrieden Für ein TopDown hätte ich auch nicht mehr details gesculpted, wenn ichs könnte
|
|
|
|
|
|
|
Euer secret project wird also ein Top Down Shooter. ( ͡° ͜ʖ ͡°)
|
|
|
|
|
|
|
Steht doch oben schon! Die Perspektive ist sone Art top down ja, aber man kann ein bisschen mehr machen als arcady wild in alle Richtungen zu schiessen. Komm halt mal vorbei, dann zeig ich dir das Projekt.
|
|
|
|
|
|
|
Was man noch so alles auf seiner Festplatte für Projekte findet ![Breites Grinsen](img/smilies/biggrin.gif)
![](https://i.imgur.com/gM2mAat.png)
![](https://i.imgur.com/emMIO4O.png)
![](https://i.imgur.com/W2KXOcv.png)
![](https://i.imgur.com/T17YnZX.png)
![](https://i.imgur.com/7oaBkBK.png)
![](https://i.imgur.com/ybDXoO2.png)
![](https://i.imgur.com/G8B5LaC.png)
![](https://i.imgur.com/EMbO5c5.png)
![](https://i.imgur.com/NVDIWpK.png)
![](https://i.imgur.com/kyRMMeU.png)
Morgen mal die anderen externen Platten durchschauen
|
|
|
|
|
|
|
Besteht hier Interesse an einem gut kommentierten A*-Algorithmus (zur Wegfindung in einem Grid oder Netzwerk) oder ist das zu billo? ![peinlich/erstaunt](img/smilies/icon16.gif)
Hat ein paar Tage gedauert, bis ich die Nuss geknackt hab und ich freue mich auch über Optimierungsvorschläge. ![Breites Grinsen](img/smilies/biggrin.gif)
|
Code: |
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FindPath : MonoBehaviour
{
public Grid grid; // this is the unity grid object. It is only used to translate grid coordinates to global coordinates or the other way round.
public NavGrid navGrid; // this is the actual grid used for navigation. It's based on the Unity grid, but any collection of nodes would do.
public Actor actor; // the actor used for pathing
public List<Vector3Int> totalPath; // the actual path
private string pathMessage; // just a string used for printing the path to the console
public void A_Star(Vector3Int start, Vector3Int goal)
{
/*
* What does "undiscovered" mean?
* An undiscovered node is not known to the algorithm yet. All nodes can be found in the navGrid.cells list. When a node was discovered (the goal node
* starts marked as discovered), the algorithm looks for neighboring nodes and if there are any that are marked as walkable, they are discovered.
*
* What does "discovered" mean?
* A discovered node means that we know the node's location and know it is walkable, but do not know the cost of of getting there from the goal node (gScore)
* or the cost of getting from goal to start by passing that node (fScore). A discovered node is part of openSet.
*
* What das "discovered and evaluated" mean?
* If a node was discovered and evaluated, we do now its location as well as its fScore and gScore. It is part of the closedSet now.
*
* How is the cost (fScore and gScore) calculated?
* The cost of travelling across a node is based on the most direct path ("beeline") from goal to the node (gScore) or
* from goal to the node + from the node to start (fScore). Visually speaking, the algorithm first tries to path directly towards the goal. When
* hitting an obstacle, it tries to go around by staying as close (again, based on direct path) to the goal as possible. If tiles are used that modify
* the walking speed of an actor, the algorithm is able to take that into calculation if that modifier is added to a node's gScore. In this example,
* I don't want actors to be that clever, but it's up to you.
*/
List<Vector3Int> closedSet = new List<Vector3Int>(); // set of nodes that have already been evaluated
List<Vector3Int> openSet = new List<Vector3Int>(); // set of nodes that have been discovered, but not yet evaluated
// In the beginning, only the goal node is known. A* returns the path beginning at the end, so the algorithm is started with goal instead of start.
// That way, the path does not need to be resorted in the end.
// gScore of a node describes the cost of getting from goal to the node. This is where the walkCost of a tile also needs to be anticipated.
// g(current) = distance between goal and current + walkCost(current)
// gScore[current] = Vector3.Distance(grid.GetCellCenterWorld(goal), grid.GetCellCenterWorld(current))
Dictionary<Vector3Int, float> gScore = new Dictionary<Vector3Int, float>();
// fScore of a node describes the cost of getting from goal to start by passing this node.
// f(current) = distance between start and current + g(current)
// fScore[current] = Vector3.Distance(grid.GetCellCenterWorld(start), grid.getCellCenterWorld(current)) + gScore[current]
Dictionary<Vector3Int, float> fScore = new Dictionary<Vector3Int, float>();
// the "cameFrom" node is the neighboring node through which a node can be reached from most efficiently. When the pathfinding is completed,
// this leaves the one path from goal to start that is the most efficient solution based on the nodes' fScores.
Dictionary<Vector3Int, Vector3Int> cameFrom = new Dictionary<Vector3Int, Vector3Int>();
// start with adding goal to openSet and setting gScore and fScore to 0 for goal (getting from goal to goal has no cost)
openSet.Add(goal); gScore[goal] = 0f; fScore[goal] = 0f;
// start the main loop. This loops as long as there are still nodes that have been discovered and not evaluated yet.
// In the beginning, it only contains the goal node. During the loop, the neighbors of each node in openSet are being looked at and added to the queue
// ("discovered"), if they have not yet been discovered (openSet) or evaluated (closedSet).
bool pathFound = new bool(); pathFound = false; // this is used for debugging (see below while loop)
while (openSet.Count > 0)
{
// which node has the lowest fScore in openSet?
float fScoreMin = new float();
Vector3Int nodeWithSmallestFScore = new Vector3Int();
foreach (Vector3Int node in openSet)
{
if (node == openSet[0]) // if first node in openSet
{
fScoreMin = fScore[node]; // set fScoreMin to this node's fScore and
nodeWithSmallestFScore = node; // remember this node, because it's the node with the smallest currently known fScore
}
else if ( node != openSet[0] && fScore[node] < fScoreMin) // if not the first node in openSet, but its fScore is smaller than fScoreMin
{
fScoreMin = fScore[node]; // set fScoreMin to this node's fScore and
nodeWithSmallestFScore = node; // remember this node, because it's the node with the smallest currently known fScore
}
}
// now we know the node with the smallest fScore in openSet
if (nodeWithSmallestFScore == start) // Is this node the start node?
{
Debug.Log("Actor " + actor.data.actorName + " has successfully pathed from cell " + start.x + ":" + start.y + " to cell " + goal.x + ":" + goal.y + " via:");
pathFound = true;
ReconstructPath(cameFrom, nodeWithSmallestFScore); // then we can start reconstructing the most efficient path
break; // and break the while loop
}
else // if not
{
// we move the node from openSet to closedSet (thus mark it as "discovered and evaluated"). This is important to prevent cycles.
openSet.Remove(nodeWithSmallestFScore);
closedSet.Add(nodeWithSmallestFScore);
// Now we look for neighboring nodes. In this example, actors can move vertically, horizontally and diagonally on the grid.
// This means that eachnode has a maximum of 8 possible neighbors.
for (int x = nodeWithSmallestFScore.x - 1; x <= nodeWithSmallestFScore.x + 1; x++)
{
for (int y = nodeWithSmallestFScore.y - 1; y <= nodeWithSmallestFScore.y + 1; y++)
{
// we have to look up the the cell x:y in the navGrid.cells list to check if it can act as a valid and walkable node.
foreach(CellData neighbor in navGrid.cells)
{
// if the cell exists in navGrid.cells, is marked as walkable AND has not been evaluated yet
if (neighbor.position == new Vector3Int(x,y,0) && neighbor.walkable == true && closedSet.Contains(neighbor.position) == false)
{
// we now calculate its tentative gScore
float tentative_gScore = new float();
tentative_gScore = CalculateGScore(gScore[nodeWithSmallestFScore], goal, neighbor.position);
// and check if that node has already been discovered
if (openSet.Contains(neighbor.position) == false)
{
// if not, we add it to openSet, set its gScore to tentative_gScore and calculate its fScore
// Note that dictionary.Add() throws an exception if it tries to add a duplicate key (which shouldn't happen)
openSet.Add(neighbor.position);
gScore.Add(neighbor.position, tentative_gScore);
fScore.Add(neighbor.position, CalculateFScore(start, neighbor.position, gScore[neighbor.position]));
// this is the best path yet. Remember it!
cameFrom.Add(neighbor.position, nodeWithSmallestFScore);
}
else
{
// if the node has already been discovered, we have to check if the tentative gScore is smaller than its current gScore
if (tentative_gScore < gScore[neighbor.position])
{
// and if it is, we have to reset its gScore, recalculate its fScore
gScore[neighbor.position] = tentative_gScore;
fScore[neighbor.position] = CalculateFScore(start, neighbor.position, gScore[neighbor.position]);
// this is the best path yet. Remember it!
cameFrom[neighbor.position] = nodeWithSmallestFScore;
}
}
}
}
}
}
// this is pretty much it. The while loop will continue to look for undiscovered neighbors of each node that was previously discovered. It
// will do so by prioritizing nodes with the minimal fScores. The loop will end if there are no undiscovered nodes left (every neighbor is
// already part of openSet or closedSet) or every discovered node has already been evaluated (openSet is empty), which means that there is no
// valid path from goal to start. It will break as soon as a path was found from goal to start.
if (pathFound == false) Debug.Log("Actor " + actor.data.actorName + " could not find a path from cell " + start.x + ":" + start.y + " to cell " + goal.x + ":" + goal.y + ".");
}
}
}
void ReconstructPath(Dictionary<Vector3Int, Vector3Int> cameFrom, Vector3Int current)
{
/*
* This function builds a complete path from the node-cameFrom-node-combinations that were previously constructed
* by the A_Star algorithm.
*/
pathMessage = "";
while (cameFrom.ContainsKey(current))
{
current = cameFrom[current]; // go to previous node and
totalPath.Add(current); // add it to final path
// build pathMessage
pathMessage = pathMessage + current.x + ":" + current.y;
if (cameFrom.Keys.Count > 1) pathMessage = pathMessage + ", ";
// show path by painting nodes in green color
foreach (CellData cell in navGrid.cells)
{
if (cell.position == current) cell.node.GetComponent<SpriteRenderer>().color = Color.green;
}
}
Debug.Log(pathMessage); // print path
}
float CalculateGScore(float gScoreOfPreviousNode, Vector3Int goal, Vector3Int current)
{
// This is where the gScore is calculated (see documentation). moveCosts of tiles (e.g. slowing effects by water tiles) go here if needed.
float ret = Vector3.Distance(grid.GetCellCenterWorld(goal), grid.GetCellCenterWorld(current)) + gScoreOfPreviousNode;
return (ret);
}
float CalculateFScore(Vector3Int start, Vector3Int current, float gScore_current)
{
// This is where the fScore is calculated (see documentation).
float ret = Vector3.Distance(grid.GetCellCenterWorld(start), grid.GetCellCenterWorld(current)) + gScore_current;
return (ret);
}
} |
|
/ Wieso nicht einfach direkt einbinden.
|
[Dieser Beitrag wurde 2 mal editiert; zum letzten Mal von Ameisenfutter am 03.07.2018 11:47]
|
|
|
|
|
|
A* ist viel unkomplizierter als man denken mag. Ich benutze den gleichen Algorithmus für mein AI Action Planning. Im grunde kannst du damit ja jede logische Verkettung von nodes aus einem cluster/grid ziehn.
Weil es mir gerade aufgefallen ist:
|
Code: |
ReconstructPath(cameFrom, nodeWithSmallestFScore); // then we can start reconstructing the most efficient path |
|
Das stimmt nicht ganz. Die Heuristik gibt dir nicht DEN kürzesten oder effizientesten Pfad, sondern den ERSTEN, der als gut genug betrachtet wird. Das ist unter Umständen ein riesen Performance-Unterschied.
Machst du daran noch weiter, oder war das nur eine Übung?
|
|
|
|
|
|
|
Optimierungsvorschlag:
.Add:
If Count is less than the capacity, this method approaches an O(1) operation. If the capacity must be increased to accommodate the new element, this method becomes an O(n) operation, where n is Count.
Unbedingt vorher Speicher reservieren, ansonsten kopiert er mit jedem .Add alles und sucht sich den passenden Speicher (+1) dazu raus.
-> http://cc.davelozinski.com/c-sharp/c-sharp-is-it-faster-to-preallocate-dictionary-sizes
|
|
|
|
|
|
|
| Zitat von freakadelle
A* ist viel unkomplizierter als man denken mag. Ich benutze den gleichen Algorithmus für mein AI Action Planning. Im grunde kannst du damit ja jede logische Verkettung von nodes aus einem cluster/grid ziehn.
Weil es mir gerade aufgefallen ist:
|
Code: |
ReconstructPath(cameFrom, nodeWithSmallestFScore); // then we can start reconstructing the most efficient path |
|
Das stimmt nicht ganz. Die Heuristik gibt dir nicht DEN kürzesten oder effizientesten Pfad, sondern den ERSTEN, der als gut genug betrachtet wird. Das ist unter Umständen ein riesen Performance-Unterschied.
Machst du daran noch weiter, oder war das nur eine Übung?
| |
Ne, ich bleib da noch ne Weile dran, gute Ablenkung zur Thesis. ![Breites Grinsen](img/smilies/biggrin.gif)
Statt ner Liste wäre ne Queue doch auch viel effizienter, oder? Die hab ich nur noch nicht ausgecheckt.
/ Ah, du bist bei den dictionaries. Das gucke ich mir mal an, danke!
// Mir ist aufgefallen, dass er manchmal nen kleinen, unnötigen Schlenker in Richtung des Ziels macht oder auf derselben Strecke in gegensätzlicher Richtung nicht denselben Weg nimmt, wenn grosse Hindernisse im Weg sind. Die Kosten werden ja ausschliesslich auf Basis der Luftlinie zum Ziel errechnet. Kann man da noch konkret was verbessern?
|
[Dieser Beitrag wurde 2 mal editiert; zum letzten Mal von Ameisenfutter am 03.07.2018 19:19]
|
|
|
|
|
|
Ich hab jetzt nicht nachgeschaut, aber ich denke eine Queue ist genauso dynamisch wie eine list. Der Vorteil von allem was fixed size ist, ist ja dass die elemente alle nebeneinander im mermory liegen. Die cache line die du bei nem access zurück bekommst beinhaltet im Falle deiner Liste wahrscheinlich ein element und sonst nur waste, weil die liste überall random memory allocated. Wenn deine elemente allerdings sortiert sind kannst du tendentiell mehrere davon in einer cache line ziehn, ohne waste.
Damit die daten allerdings so sortiert werden können musst du wissen wieviele du davon hast. Und das weiss eine list by default nicht. Denke bei ner Queue ist das intern genauso. Ein fixed size array muss wie der name schon sagt mit ner length initialisiert werden. Da hast du dann halt overhead sobald du das ding resized.
Meine Laienmeinung wäre: Macht bei 100 nodes nicht wirklich einen Unterschied Wenn dein pathfinder allerdings 10.000 nodes anschaut dann kann man was machen.
Wenn du aufgrund deines Anwednungsprofils ungefähr weisst wie lang ein Pfad normalerweise ist kannst du wie Murica sagte halt auch ungefähr entsprechend allocaten. Dann entsteht nur overhead bei ausreißern, die halt zufällig mal mehr nodes brauchen
|
[Dieser Beitrag wurde 1 mal editiert; zum letzten Mal von freakadelle am 03.07.2018 19:42]
|
|
|
|
|
Thema: Das pOT erstellt Spiele 4 ( code code durrrr ) |