So implementieren Sie weiche Randbereiche mit Partikeln

13

Mein Spiel wurde mit Phaser erstellt, aber die Frage selbst ist motorunabhängig.

In meinem Spiel gibt es mehrere Umgebungen, im Wesentlichen polygonale Bereiche, in die sich Spielercharaktere bewegen und von denen sie betroffen sind. Zum Beispiel Eis, Feuer, Gift usw. 'Das grafische Element dieser Bereiche ist der mit Farbe gefüllte Polygonbereich selbst und Partikel des geeigneten Typs (in diesem Beispiel Eisscherben). So setze ich das gerade um - mit einer Polygonmaske, die einen Kacheldrucker mit dem Partikelmuster bedeckt:

Bildbeschreibung hier eingeben

Die harte Kante sieht schlecht aus. Ich möchte mich verbessern, indem ich zwei Dinge tue: 1. Den Polygonfüllbereich so gestalten, dass er eine weiche Kante hat und in den Hintergrund übergeht. 2. Lassen Sie einige Scherben aus dem Polygonbereich herausgehen, damit sie nicht in der Mitte geschnitten werden und der Bereich keine gerade Linie aufweist

Zum Beispiel (Modell):

Bildbeschreibung hier eingeben

Ich denke, 1 kann durch Verwischen des Polygons erreicht werden, aber ich bin nicht sicher, wie ich mit 2 vorgehen soll.

Wie würden Sie dies umsetzen?

OpherV
quelle
2
Das sieht super aus. Kann ich bitte einen Link zu deinem Spiel haben ? :)
ashes999
@ GameAlchemist Hier ist das Kachelbild i.imgur.com/y54CeQ9.png
OpherV
@ ashes999 Es ist noch in Arbeit. Ich werde auf jeden Fall einen Link hier posten, sobald ich ihn habe :)
OpherV
Beachten Sie, dass es sich um ein transparentes PNG mit weißen Objekten handelt. Wenn Sie es auf einem weißen Hintergrund anzeigen (wie es beim Öffnen eines Bildes in einem Browser häufig der Fall ist), sehen Sie nichts
OpherV
@OpherV das wäre toll. Bitte bearbeite einfach deine Frage und poste einen Link - das ist wahrscheinlich die
aktuellste

Antworten:

2

1.Wenn Sie etwas wünschen, das Ihrem Modell nahe kommt, würde ich Partikel verwenden (es muss kein vollständig ausgeblasenes Partikelsystem sein).

Rendern Sie Ihre Partikel in Form eines Polygons auf einer RenderTexture. Achten Sie darauf, die Partikel mit Additiven zu mischen. Die Partikel innerhalb des Polygons fügen sich nahtlos ineinander, während die Partikel auf der Außenseite die gewünschte weiche Kante ergeben. (Ein Beispiel für den Effekt finden Sie in diesem Youtube-Video: Additive Partikel-Video Rendern Sie jetzt die RenderTexture auf Ihrem Hauptbildschirm, und Sie sind fertig. Die RenderTexture ist erforderlich, damit die Partikel nicht mit Ihrem Hintergrund verschmelzen.

Sie können versuchen, die Dreiecke direkt auf die Partikeltextur zu setzen und zu sehen, wie dies funktioniert. Andernfalls rendern Sie sie als separate Ebene auf Ihre Partikelsuppe.

Erstellt ein schnelles Modell in einem aktualisierten Jsfiddle, das so aussieht. Demo Die aktualisierte Demo finden Sie hier

2. Jedes Teilchen hat eine Geschwindigkeit und einen Ursprung. Wenn Ihr Spieler das Polygon berührt, ändern Sie die Geschwindigkeit der einzelnen Partikel proportional zur Geschwindigkeit des Spielers. Je weiter ein Partikel von Ihrem Spieler entfernt ist, desto weniger wird es von der Geschwindigkeit des Spielers beeinflusst.

Die Formel zur Berechnung der Geschwindigkeit eines Partikels würde etwa so lauten:

//player.velocity and particle.velocity are vectors 
//k is a factor to enhance or weaken the influence of players velocity
var distanceToPlayer = (player.position - particle.position).length();
particle.velocity = particle.velocity + ((k * player.velocity) + particle.velocity) * (1/distanceToPlayer);

Um die Position des Partikels zu berechnen, geben Sie dies in Ihre Aktualisierungsmethode ein:

var speedY = -(springConstant * (particle.position.y - particle.origin.y)) - (dampingFactor * particle.velocity.y);
var speedX = -(springConstant * (particle.position.x - particle.origin.x)) - (dampingFactor * particle.velocity.x);

particle.position.y = particle.position.y + speedY;
particle.position.x = particle.position.x + speedX;

particle.velocity.x = particle.velocity.x + speedX;
particle.velocity.y = particle.velocity.y + speedY;

Dies sollte Ihnen eine "Flüssigkeit" geben, in der jedes Partikel um seinen Ursprung schwingt, wenn der Spieler die Flüssigkeit rührt. Die springConstant ändert, wie weit ein Partikel von seinem Ursprung wegschwingt, und den dampingFactor, wie schnell das Partikel zur Ruhe kommt. Möglicherweise müssen Sie den Code anpassen, da er die modifizierte Version einer 1d-Simulation ist, die ich in meinem Spiel verwende.

Jetzt mit einer Demo: Demo Passen Sie einfach die drei Konstanten oben an, bis sich die Flüssigkeit so verhält, wie Sie es möchten.

Zilluss
quelle
Das ist eine wirklich interessante Idee, um # 1 zu lösen! Ich mag das. Wie würden Sie vorschlagen, die Dreiecksbewegung \ Abstand zu implementieren?
OpherV
1
Ich habe den ursprünglichen Beitrag bearbeitet, um Frage 2 zu beantworten.
Zilluss
fügte eine kleine Demo des Partikeleffekts hinzu. Ich denke, Sie könnten Ihren gewünschten Effekt mit einem kleinen Tweaking erzielen.
Zilluss
Am Ende habe ich Ihre Lösung verwendet. Sie kommt dem Effekt, den ich erreichen wollte, am nächsten. Vielen Dank! Eine Frage jedoch: Wie würde ich die Federung in Ihren Beispielen einschränken, damit wirklich leichte Bewegungen nicht dazu führen, dass die Partikel über so große Entfernungen springen?
OpherV
Sie können mit dem Dämpfungsfaktor und der Federkonstante herumspielen. Eine hohe Dämpfung bringt die Partikel schneller zur Ruhe. Eine niedrigere Federkonstante senkt die Geschwindigkeit der Partikel. Leider lassen beide Werte die Partikelsuppe viskoser wirken. Wenn Ihr Player also das Partikel berührt, können Sie die maximale Geschwindigkeit, die der Player dem Partikel hinzufügt, wie folgt klemmen: particle.velocity.x = clamp (maxVelocity, -maxVelocity, particle.velocity.x + ((playerInfluenceFactor * deltaVelocityX ) + Partikelgeschwindigkeit.x) * (1 / distanceToPlayer)); Informationen
zilluss
4

Meine Gedanken zu diesen beiden Punkten:

  1. Sie könnten Shader Blur verwenden, aber das wird sehr teuer. Stattdessen würde ich einen zusätzlichen Rand aus Dreiecken zeichnen, der in der Mitte durchscheinend und an den Rändern transparent wird, um die "Unschärfe" zu simulieren. Ich habe das in einem meiner Spiele gemacht und es funktioniert ziemlich gut. Hier sind zwei Screenshots eines Regenbogen-Boosters in meinem Spiel.

    Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben

    Der äußere Rand hat eine Steigung. In meiner Situation beginnt der Rand nicht mit der gleichen Deckkraft wie der innere Teil, aber wenn Sie diese Deckkraft gleich setzen, erhalten Sie eine schöne Überblendung.

  2. Ich würde ein Partikelsystem programmieren und die Partikel dem Polygon folgen lassen. Auf diese Weise müssen Sie sich keine Gedanken darüber machen, was an den Rändern passieren wird. Die Dynamik Ihres Partikelsystems stellt sicher, dass sich die Partikel innerhalb des Polygons befinden und gleichmäßig verteilt sind. Sie könnten versuchen, die engsten Teilchen voneinander wegzudrücken, aber machen Sie es mit viel "Masse", so dass Sie Trägheit haben und es glatt aussieht. Um dies zu beschleunigen, gibt es einige Möglichkeiten, aber das große Problem wird die zeitliche Komplexität des gegenseitigen Druckmechanismus sein. Wenn Sie jedes Partikel dazu bringen, jedes andere Partikel zu pushen, haben Sie O (n ^ 2), was nicht gut ist, wenn Sie zum Beispiel 100 Partikel in Ihrem System haben. Eine gute Lektüre darüber, wie Sie dies optimieren können, ist die folgende Präsentation von PixelJunk:http://fumufumu.q-games.com/gdc2010/shooterGDC.pdf

    Ein einfacherer Ansatz wäre, jedes Partikel beim Aufbau des Partikelsystems mit drei oder vier anderen Partikeln zu verbinden. Jetzt muss jedes Partikel nur noch die vier anderen Partikel drücken, mit denen es verbunden ist. Dieser Ansatz macht jedoch Turbulenzen in Ihrem Partikelsystem unmöglich. Dies scheint jedoch kein Problem zu sein, da Ihre aktuelle Situation eine statische Textur verwendet. Dieser Ansatz wird O (n) sein, was großartig ist.

Martijn Courteaux
quelle
Vielen Dank! 1. Es fällt mir schwer, mir das vorzustellen. Kannst du bitte ein Modell veröffentlichen, wie es in deinem Spiel aussieht \ funktioniert? 2. Interessant! werde das nachlesen
OpherV
Danke für die Bilder. Ich kann sehen, wie das in einer rohr- oder linienbasierten Form funktionieren würde, aber wie funktioniert das mit einem Polygon? Passen die Steigungen der von jeder Seite projizierten Dreiecke nicht gut zusammen ...?
OpherV
Passen Sie sie gut an. Das ist die Idee. Dazu gehören einige mathematische Berechnungen und Schnittpunkte usw. Sie können den Rand auch unterteilen und ihn glätten. Jede Menge Möglichkeiten.
Martijn Courteaux
3

Die Idee, die ich beim Lesen Ihres Beitrags hatte, war folgende:
• Bauen Sie eine Reihe von Kacheln, die Sie für Ihre Gebiete verwenden werden.
• Rendern Sie das Flächenpolygon auf einer kleinen temporären Leinwand mit der Kachelauflösung (Beispiel: Wenn die Kacheln 16X16 groß sind, rendern Sie mit einer (16X, 16X) geringeren Auflösung).
• Verwenden Sie diese temporäre Leinwand, um zu entscheiden, ob Kacheln auf der Hauptleinwand gerendert werden sollen oder nicht:
Wenn ein Punkt auf der Leinwand mit niedriger Auflösung festgelegt ist, zeichnen Sie eine zufällige Kachel auf der Hauptleinwand. Wenn ein Punkt nur ein Nachbar eines Sollwerts ist, zeichnen Sie eine zufällige Kachel mit einer geringeren Deckkraft (um einen Übergang zu erzielen) auf der Hauptleinwand.

Ich befürchtete, dass eine niedrigere Auflösung einen Blockeffekt erzeugen würde, aber selbst bei 20x20-Kacheln sieht es ganz gut aus:

Bildbeschreibung hier eingeben

Schritte dafür sind: nimm dein Polygon:
Bildbeschreibung hier eingeben

Zeichnen Sie das Polygon mit Ihrer Kachelauflösung: Bildbeschreibung hier eingeben(!! Ja, es ist das rote Einkaufszentrum).

Verwenden Sie dann die imageData der Leinwand mit niedriger Auflösung, um zu entscheiden, ob Sie eine Kachel oder eine Notiz zeichnen möchten.
Wenn ein Pixel auf der Leinwand mit niedriger Auflösung festgelegt ist, bedeutet dies, dass wir die Kachel zeichnen sollten: Wählen Sie einen zufälligen Kachelindex aus, um die zu zeichnende Kachel auszuwählen. Dieser Zufallsindex sollte für einen bestimmten Bereich / eine bestimmte Kachel immer gleich sein.
Wenn ein Punkt leer ist, aber neben einem gefüllten Punkt liegt, zeichnen Sie auch eine Kachel mit halber Deckkraft.

Bildbeschreibung hier eingeben

Also lasst uns die Kacheln zeichnen:

Bildbeschreibung hier eingeben

Für das Polygon zeichne ich einfach ein Vielfaches des Polygons, verkleinere es und erhöhe die Deckkraft bei jedem Zeichnen (man könnte auch das 'Feuerzeug' von globalCompositeOperation verwenden).

Bildbeschreibung hier eingeben

Wenn Sie alles addieren, erhalten Sie:

Bildbeschreibung hier eingeben

Geige ist hier:

http://jsfiddle.net/gamealchemist/T7b4Y/

Lassen Sie mich wissen, ob das hilft.

GameAlchemist
quelle
Vielen Dank, dass Sie Ihre Lösung ausgearbeitet und den Code bereitgestellt haben! Was meinen Sie mit "Dann verwenden Sie die Bilddaten der niedrig aufgelösten Leinwand, um zu entscheiden, ob Sie eine Kachel oder eine Notiz zeichnen möchten"? Wie verwenden Sie die kleinen Bilddaten, um zu entscheiden, wo auf dem großen Bild gezeichnet werden soll? Und wie kann ich mit dieser Methode die Überlappung der Dreiecke vermeiden, um einen ähnlichen Abstand wie bei meinem Modell zu erzielen?
OpherV
Ich meine, es ist ein vollständiger Boolescher Test: Muss ich diese Kachel füllen? , true oder false, ergibt sich aus dem Test der niedrigauflösenden Prüfung auf imageData [(x + y * width) * 4]! = 0, dh == 'habe ich etwas auf die niedrigauflösende Leinwand bei gezeichnet dieser Kachelplatz? '. Wenn ja, verwende ich eine ausgearbeitete mit Primzahlen gefüllte Formel (getRandomNumber), um von (x, y) zu einem 'zufälligen' Kachelindex zu gelangen, der für einen bestimmten Bereich immer die gleiche Zahl + (x, y) liefert. Ich sehe nicht, wie sich die Dinge überschneiden könnten, wenn Sie Ihr Polygon richtig definieren, sodass ich Ihre zweite Frage nicht bekomme.
GameAlchemist
1

Nur eine Idee:

In Ihrer Kachel sind die "Teile" höchstens etwa 80px breit. Ich würde vorschlagen, 2 Bereiche zu machen. Sie zeichnen Ihr ursprüngliches Polygon und erstellen ein Modell davon, das ungefähr 80 Pixel von jeder Kante entfernt ist. Anschließend zeichnen Sie Ihre Kacheln in das größere Polygon.

Dann können Sie alle "Teile", die ein Pixel außerhalb des inneren Polygons und keinen Schnittpunkt mit dem inneren Polygon haben, mit Transparenz füllen.

Das ist ein sehr hohes Niveau, aber ich dachte, ich würde es mit Ihnen teilen. Es gibt hier eine Menge Details zu bestimmen.

Ein grobes Bild, um zu demonstrieren:

Bildbeschreibung hier eingeben

Wenn das innere schwarze Polygon das Original wäre, würden Sie alle Polygone mit einem roten Punkt löschen.

user46560
quelle
Wie würden Sie die Schnittmenge der im Kachelbild eingebetteten Teile mit dem inneren Polygon überprüfen?
OpherV
@OpherV Uhmm, Sie können bestimmen, ob Punkt X in einem Polygon ist, oder? Sie können alle Pixel im äußeren Polygon durchlaufen und für jedes weiße Pixel alle Pixel überfluten und prüfen, ob die inneren / äußeren Pixel vorhanden sind. Das klingt zwar nicht besonders effizient, aber wenn Sie etwas haben, können Sie Möglichkeiten zur Optimierung finden?
user46560
Die Nachbearbeitung erfolgt auf der CPU. An sich kaum optimierbar. Ihre Idee könnte gut funktionieren, wenn das innere Polygon und das äußere durch einen Dreiecksstreifen verbunden werden. Das OP könnte Scheitelpunktattributinformationen hinzufügen und jeden Scheitelpunkt als innen oder außen kennzeichnen. Dann kann im Vertex-Shader die Opazität / Alpha linear von einem weniger transparenten Wert zu einem vollständig opaken Wert interpoliert werden.
Teodron
@teodron Dies ist der Punkt, den ich in der Antwort ansprechen wollte. Es ist eine hochkarätige Idee und ich bin nicht wirklich ein Spieleentwickler. Ich hatte gerade eine Idee.
user46560
@ user46560 ja, aber auf diese Weise müssen Sie nicht berechnen, welche Pixel sich in diesem Inter-Polygon-Band befinden. Weder auf der GPU noch auf der CPU. Da Sie nicht an die Art und Weise der Spieleentwicklung gewöhnt sind, verdienen Sie +1 für Ihre Idee :).
Teodron