|
Post by Roger Cabo on Sept 4, 2023 17:03:39 GMT 1
Bonjour Roger, Il faut bien prendre en compte qu'il s'agit d'un algorithme de collision ligne/ligne et non ligne/polygone. Comme je l'ai dit plus haut il est nécessaire de checker la position du joueur AVANT de tester une collision. Si le joueur est trop près d'une ligne (à l'intérieur de la zone de collision) le test de collision est erroné. Dans un programme qui utilise ce genre d'algorithme (comme DOOM) la position du joueur doit être impérativement connue. Par exemple avec ton polygone à 8 coté, tu dois "savoir" si le joueur est dans ou en dehors du polygone, ceci est possible si tu définis préalablement le sens des lignes (cw,ccw). Si le joueur passe "à traver la ligne" si le point destination est à gauche ou droite de la ligne il est donc à l'intérieur ou à l'extérieur. Je n'ai pas le temps pour l'instant de te coder un example mais je vais revenir. Merci pour les commentaires.. Le programme est animé. Plus la taille du collisionneur est petite, moins les erreurs se produisent. J'ai aussi essayé de tester à l'intérieur et à l'extérieur. Mais il y a toujours d’autres lignes qui ne fonctionnent pas, selon la taille du collisionneur. Merci New collider Line 06.G32 (15.8 KB)
|
|
|
Post by scalion on Sept 8, 2023 12:44:05 GMT 1
Hi Roger. I took a little long but as a result I developed a 3D-Oriented MAP editor for the occasion (I might do a thread). So here's how a "Doom" style collision engine works: We have a set of lines which delimit sectors. Each line contains the index of the sector on its left and the one on the right, as well as its ability to be crossed or not. Each sector contains the list of lines which detour it as well as those of other sectors whose vertices are common. The position of the player MUST contain the index of the sector where he is. It is with this index that it will know with which lines it can collide and which ones it can cross. Each time the player crosses a line, the player's sector is affected by that line depending on whether he cross it from left to right or vice versa.
As a bonus I implemented an FPS timer to have the same rendering speed whatever the power of the PC.
If you have question, i'm here.
Have fun
|
|
|
Post by Roger Cabo on Sept 9, 2023 18:12:34 GMT 1
Hi Scalion, nice stuff .. but it's very difficultly to adapt this data structure and movement to the existing we started already. There are some issues in the code.. in the movement. A) If you change the direction, the player moves for a tiny moment into the old direction. If player_move_speed = 0 && (dir_old != dir_new) then you should reset the direction vectors to 0 as well? Or below speed X you should set the speed = 0 and the directions as well. I did not understand the code If I use gravitation in the Y+ direction its more like a bounce back physic. B) The play move is like on ice or like a ballon loose air in the vacuum of the universe or like the game Defender. C) The player rubbing against the wall.. The direction between the wall and the player movement. There is anything strange. D) The FPS on my system went from 100 down to FPS = 50 after some time.. Why ist not directly 50? F) Temporisation this affects the Frame rate massive! G) What? The game should always run at the predefined speed FPS? While Timer - FStart < Temporisation WendE) The pooling of the player actions should be outside of the draw loop urgently, perhaps in a timer with the 200FPS or HQTimer. And in this timer you use the time delta to calculate the next movement. If Btst(GetAsyncKeyState(VK_RIGHT), 15) = True Turn Player.Dx, Player.Dy, -0.05 EndIfAnyway it's nicely done, don't get me wrong!
__________________________________________
I'm sitting on a Mario game and done a complete collider and collision set only by lines. It's impossible to define sectors and complex structures with the Doom style map.. or? No way to fix the New collider Line 06.G32 ? Errors: If the player size is <= 1.0, then all works well at 99% Unfortunately I didn't understand what happen exactly in the line code calculates the edges. I think this happen to the code that tries to find the edges? What do you think? **************************************************************************************************************** Salut Scalion, Très bon boulot... mais il est très difficile d'adapter cette structure de données et ce mouvement à ce que nous avons déjà commencé. Il y a quelques problèmes dans le code... dans le mouvement. A) Si tu changes de direction, le joueur bouge pendant un bref instant dans l'ancienne direction. `If player_move_speed = 0 && (dir_old != dir_new)` Alors tu devrais également réinitialiser les vecteurs de direction à 0, non ? Ou en dessous d'une certaine vitesse X, tu devrais mettre la vitesse = 0 et les directions également. Je n'ai pas compris le code. Si j'utilise la gravité dans la direction Y+, c'est plus comme une physique de rebond. B) Le mouvement du joueur est comme sur la glace ou comme un ballon qui perd de l'air dans le vide de l'univers ou comme dans le jeu Defender. C) Le joueur frotte contre le mur... La direction entre le mur et le mouvement du joueur. Il y a quelque chose d'étrange. D) Les FPS sur mon système sont passés de 100 à 50 après un certain temps.. Pourquoi pas directement 50? F) Temporisation, cela affecte massivement le taux de trame ! G) Quoi ? Le jeu devrait toujours fonctionner à la vitesse FPS prédéfinie ? `While Timer - FStart < Temporisation` `Wend` E) Le pooling des actions du joueur devrait être en dehors de la boucle de dessin, peut-être dans un timer avec 200FPS ou HQTimer. Et dans ce timer, tu utilises le delta de temps pour calculer le prochain mouvement. `If Btst(GetAsyncKeyState(VK_RIGHT), 15) = True` `Turn Player.Dx, Player.Dy, -0.05` `EndIf` Je travaille sur un jeu Mario et j'ai réalisé un ensemble complet de collisionneurs et de collisions uniquement par des lignes. Est-ce impossible de définir des secteurs et des structures complexes avec la carte de style Doom... ou pas ? Pas moyen de corriger le nouveau collisionneur Line 06.G32 ? Erreurs : Si la taille du joueur est <= 1.0, alors tout fonctionne bien à 99%. Malheureusement, je n'ai pas compris ce qui se passe exactement dans le code de la ligne qui calcule les bords. Je pense que cela se produit dans le code qui essaie de trouver les bords ? Qu'en penses-tu ?
|
|
|
Post by scalion on Sept 9, 2023 20:19:09 GMT 1
Oui c'est ce que je voulais , c'est pour simuler une force d'inertie. A moins que ne parles de l'erreur de calcul dans la valeur speed (voi juste après) Non en fait il y a une valeur de déplacement (xShift,yShift), c'est elle qui doit être mise à zéro si on veut supprimer l'inertie. Par contre j'ai fait une bourde au niveau de la valeur speed (qui devrait être renommée DrivingForce ou quelque chose dans le genre). Cette valeur devrait effectivement remise à zéro et en tout cas remise dans le bon sens. avec un truc comme (pseudo-code) If VK_UP Player.Speed = Max(0, Player.Speed + 0.1) Player.xShift = 0 // à laplace de /= 1.05 Player.yShift = 0 // à laplace de /= 1.05 En bref mon système de déplacement à été créé à l'arrache juste pour la démo. C'est une idée à explorer. Je suis sûr que si. lol. Oui c'est encore voulu. J'adore l'image du ballon dans l'univers Oui, je n'ai pas implémenté le glissement. Ce n'est pas très compliqué à faire. Il s'agit d'un projection sur la ligne, un simple problème de trigonométrie (longueur restante à parcourir ^ 2 - hauteur ^ 2). Je vais le faire. Dans tous les cas cela dépend de ce qu'on a envie de représenter (un ballon ? un patineur saoul ? un troll ? un cornichon à roulettes ?) Parce-que le programme ne sait pas à l'avance le nombre de frames qu'il est en mesure d'afficher chaque seconde. Il mesure donc au fur et à mesure le nombre de FPS et ajuste progressivement le délai nécessaire. On ne peut pas faire de changements trop brusque car le nombre de FPS n'est pas constant. Si on le faisait le programme accélèrerait ou ralentirait de manière dramatique pour la jouabilité. Oui c'est le but, c'est une manière d'utiliser des valeurs de déplacements constantes en étant certain que le jeu fonctionne de la même manière quelque soit la configuration. Bah oui du coup. Oui tu as parfaitement raison, c'est l'autre manière de faire. Je ne l'ai pas implémenté ici. Il n'y a pas forcément besoin d'un OCX timer puisque le delta peut être calculé en fonction du FPS, mais pourquoi pas. Ce n'est pas un truc simple de créer une map avec des secteurs, c'est pour cela que je développe un éditeur de map sectorielle. Garde ton système, améliore le si besoin. Pour un jeu de plateau un système à secteurs ne me semble pas du tout approprié en fait. Le programme fonctionne comme j'avais prévu. Je ne vois pas de quoi tu parles (cela se produit), c'est quoi qui se produit ? Merci pour ton retour en tout cas.
|
|
|
Post by Roger Cabo on Sept 10, 2023 15:25:14 GMT 1
Je parle du code précédent que tu as ajouté... Intersection entre une ligne et un cercle. Il y a malheureusement des erreurs ici, et je pense que cela est dû à la requête aux bords qui n'est jamais résolue. Voici le lien vers le code gb32. gb32.proboards.com/attachment/download/1822Je vous remercie.
|
|
|
Post by scalion on Sept 10, 2023 18:59:31 GMT 1
Je parle du code précédent que tu as ajouté... Intersection entre une ligne et un cercle. Il y a malheureusement des erreurs ici, et je pense que cela est dû à la requête aux bords qui n'est jamais résolue. Voici le lien vers le code gb32. gb32.proboards.com/attachment/download/1822Je vous remercie. Désolé mais je n'imprime pas, tu dois avoir un besoin spécifique qui m'échappe.
Je continues sur ma lancée. J'ai modifié ma fonction collision en y incluant un calcul de glissement (sliding). J'utilise le cosinus de l'angle entre la surface (perpendiculaire à la normale d'où -normalx,normaly) et le vecteur de déplacement (xShift,yShift).
Afin de rendre le déplacement plus proche d'un humain en mouvement j'ai réparti le rebond incident et le glissement à 20% / 80%.
Le type Collision_Struct est donc enrichi de 2 nouvelles variables :
Type Collision_Struct - Double xClash, yClash - Double NormalX, NormalY - Double IncidentX, IncidentY - Double xSlide, ySlide // new variables for sliding - Double U EndType Voilà le programme modifié :
|
|
|
Post by Roger Cabo on Sept 11, 2023 15:23:03 GMT 1
Is it possible to use your new calculation for New collider Line 06.G32 or does it require any changes because of the sector calculation? New collider Line 06.G32 (15.86 KB) Can you pass your changes to the this gb32 code please? So everyone can use and I make an very easy demo in D2D. --------------
Est-il possible d'utiliser votre nouvelle calculatrice pour la nouvelle ligne de collision 06.G32, ou nécessite-t-elle des modifications en raison du calcul du secteur ? New collider Line 06.G32 (15.86 KB) Pouvez-vous transmettre vos modifications à ce code gb32, s'il vous plaît ? Ainsi, tout le monde peut les utiliser, et je réalise une démonstration très simple en D2D. Je pense que ce n'est plus un algorithme "swept"... Si le joueur se déplace trop rapidement, il dépasse les limites de l'espace et "s'échappe". Je ne suis pas sûr(e)...
Player.Speed = 300
Do Inc FSUM If FDS = FPS Ellapsed = Timer - SOFStart If Ellapsed > 1 'Temporisation = Max(0, Temporisation - StepTempo) Else 'Temporisation = Min(0.5, Temporisation + StepTempo) EndIf SOFStart = Timer FDS = 0 EndIf Inc FDS FStart = Timer DrawAll PeekEvent Pause 10 Loop Until Me Is Nothing
|
|
|
Post by Roger Cabo on Sept 12, 2023 21:08:16 GMT 1
Hi Scalion,
I started to build up from your code.. any tried to create a single function. No way.. I came up wit this.. but does not.. I hope you can have a look at anytime.
------------------------ Salut Scalion,
J'ai commencé à partir de votre code et j'ai essayé de créer une seule fonction. Pas moyen... J'en suis arrivé à ceci, mais ça ne fonctionne pas. J'espère que vous pourrez y jeter un coup d'œil à un moment donné.
J'ai maintenant essayé de résoudre le problème avec chatGPT 4.0 pendant 10 heures. Malheureusement, chatGPT n'a pas pu résoudre le problème non plus, car il oublie la nature du problème après un certain temps. Il dit ensuite : "Je suis désolé, j'ai oublié l'objectif de notre programmation, recommençons depuis le début." (Ouch!)
J'ai ensuite essayé de décomposer le mouvement du cercle dans l'espace 2D en différentes géométries, en une capsule, qui est composée de deux cercles et d'un rectangle tourné. Ce rectangle peut également être divisé en deux triangles. Mais ensuite, il devient compliqué de recalculer où le cercle a heurté et dans quelle direction le mouvement initial pointe. Je comprends les solutions géométriques, mais je ne peux pas les mettre en œuvre mathématiquement.
New collider Line 07_test.G32 (3.33 KB) $Library "gfawinx" $Library "UpdateRT" UpdateRuntime ' Patches GfaWin23.Ocx
$Library "Direct2D"
Type Player_Struct - Long Sector - Double x, y - Double Dx, Dy - Double Speed - Double xShift, yShift - Double Radius EndType
Global Player As Player_Struct
Type Collision_Struct - Double xClash, yClash, NormalX, NormalY, IncidentX, IncidentY, U - Double xSlide, ySlide EndType
Global Collision As Collision_Struct
Local CollisionCheck As Collision_Struct Local Collision As Collision_Struct
OpenW # 1, 0, 0, 1000, 500
Player.x = 100, Player.y = 50 Player.xShift = 400, Player.yShift = 350 Player.Radius = 20
Dim x1#, y1#, x2#, y2# x1 = 50, y1 = 300 x2 = 800, y2 = 300
Do Cls Color 0 Line x1, y2, x2, y2 Dim xNew# = Player.x + Player.xShift Dim yNew# = Player.y + Player.yShift Color RGB(255, 0, 0) Line Player.x, Player.y, xNew, yNew Circle Player.x, Player.y, Player.Radius Circle xNew, yNew, Player.Radius If CollisionFound(Player.x, Player.y, xNew, yNew, x1, y1, x2, y2, Player.Radius, CollisionCheck) Stop If CollisionCheck.U Stop EndIf EndIf Sleep (15) PeekEvent Loop Until Win_1 Is Nothing
Function CollisionFound(Shiftx1, Shifty1, Shiftx2, Shifty2, Wallx1, Wally1, Wallx2, Wally2, Radius, ByRef Collision As Collision_Struct) As Boolean // Calculate SidePoint to check which side the player is on Dim SP#, dx#, dy#, dx1#, dy1# dx = Wallx2 - Wallx1 dy = Wally2 - Wally1 dx1 = Shiftx1 - Wallx1 dy1 = Shifty1 - Wally1 SP = dx * dy1 - dy * dx1 // If player is on the wrong side, exit If SP < 0 Then Else Return False End If // Initialize local variables Dim lx#, ly#, ll#, uTest#, u#, dp#, cvv# Dim a#, a2#, b#, c#, v#, xx#, yy#, xs#, ys#, rr# lx = Wallx2 - Wallx1 ly = Wally2 - Wally1 ll = Sqr(lx * lx + ly * ly) xx = Shiftx1 * Shiftx1 yy = Shifty1 * Shifty1 xs = Shiftx2 - Shiftx1 ys = Shifty2 - Shifty1 rr = Radius * Radius a = xs * xs + ys * ys If a = 0 Then Return False EndIf a2 = a * 2 u = _maxDbl ' Test First circle b = 2 * ( xs * (Shiftx1 - Wallx1) + ys * (Shifty1 - Wally1) ) c = Wallx1 * Wallx1 + Wally1 * Wally1 + xx + yy - 2 * (Wallx1 * Shiftx1 + Wally1 * Shifty1 ) - rr v = b * b - 4 * a * c If v >= 0 Then v = Sqr(v) uTest = (-b - v) / a2 If uTest < 0 Or uTest > 1 Then uTest = (-b + v) / a2 If uTest >= 0 And uTest <= 1 Then Collision.xClash = Shiftx1 + uTest * xs Collision.yClash = Shifty1 + uTest * ys Collision.NormalX = (Collision.xClash - Wallx1) / Radius Collision.NormalY = (Collision.yClash - Wally1) / Radius u = uTest End If End If ' If Intersection found return true If u < _maxDbl Then a = Sqr(a) xs /= a ys /= a a = a * (1 - u) ' a becomes the rest cvv = (-Collision.NormalY * xs + Collision.NormalX * ys) Collision.xSlide = -Collision.NormalY * cvv * a Collision.ySlide = Collision.NormalX * cvv * a dp = 2 * (Collision.NormalX * xs + Collision.NormalY * ys) Collision.IncidentX = (xs - Collision.NormalX * dp) * a Collision.IncidentY = (ys - Collision.NormalY * dp) * a Collision.U = u Return True End If Return False End Function
|
|
|
Post by scalion on Sept 13, 2023 12:37:24 GMT 1
Hi Roger, sorry i dont have time for the moment. Si j'ai compris, tu veux utiliser cet algorithme de collision adapté à un jeu de plateau style Mario ? Si c'est bien le cas, le problème est que tu veux appliquer la fonction de collision telle qu'elle, hors elle doit être intégrée dans un algorithme global différent qui comprend le déplacement du joueur. Dans le cas d'un jeu style "Doom" cela nécessite un traitement par secteurs, ces secteurs ne sont pas à proprement parler en mémoire, c.a.d qu'en fait c'est en passant à travers certaines lignes traversables qu'on sait dans quel secteur on se trouve, voilà pourquoi il est absolument nécessaire de connaitre la position du joueur dès le départ en l'initialisant à la bonne valeur.
Pour un jeu de plateau il faut envisager les choses autrement. Cela dépend de la construction de ton jeu de plateau, est-ce que ce sont des "briques" agencées de manière statiques, ou des polygones, y-a-t'il des éléments mobiles, et les collisions concernent-elles uniquement le joueur et le décor, ou est-ce que d'autres éléments sont susceptibles d'entrer en collision comme des personnages ou autres ? Il existe d'autre algorithme de collision très efficaces comme celui du masque distances/normales mais qui n'est pas adapté à tout. Il faut d'abord répondre à ces questions avant d'adapter cette fonction. Si tu veux, tu peux m'envoyer un MP avec une source de ton jeu pour que je puisse jeter un oeil et comprendre de quoi il retourne.
US : If I understood, you want to use this collision algorithm adapted to a Mario-style board game? If this is indeed the case, the problem is that you want to apply the collision function as it is, except it must be integrated into a different global algorithm which includes the movement of the player. In the case of a "Doom" style game this requires processing by sectors, these sectors are not strictly speaking in memory, i.e. in fact it is by passing through certain traversable lines that we know in which sector we are in, this is why it is absolutely necessary to know the player's position from the start by initializing it to the correct value.
For a board game you have to look at things differently. It depends on the construction of your board game, are they statically arranged "bricks", or polygons, are there moving elements, and do collisions only concern the player and the setting, or are other elements likely to collide like characters or others? There are other very effective collision algorithms such as the distance/normal mask but which is not suitable for everything. These questions must first be answered before adapting this function. If you want, you can send me a PM with a source of your game so I can take a look and understand what it's all about.
|
|
|
Post by Roger Cabo on Sept 13, 2023 21:04:29 GMT 1
Salut Scalion, > If I understand correctly, you want to adapt this collision algorithm for use in a Mario-style board game?Yes, and more; it can also be applied to an isometric collision game, a Galaga-style game, billiards, pinball, and definitely a platformer. >> If this is indeed the case, the challenge lies in wanting to apply the collision function as is, but it needs to be integrated into a different global algorithm that encompasses player movement. In the case of a "Doom"-style game, this involves processing by sectors. These sectors are not strictly stored in memory; in fact, it's determined by passing through specific traversable lines that we identify which sector we're in. This is why knowing the player's position accurately from the outset, initialized to the correct value, is absolutely necessary.
a) I don't require sectoring for all the current projects I have in mind. I need a circle-line swept AB that works seamlessly, focusing on player-environment collisions. b) Sectoring must be handled by any code logic because, when you start building an environment and make complex changes, you wouldn't want to manually reconstruct points and lines for all sectors again. >>> For a board game, you need to approach things differently. It depends on the structure of your board game—whether it consists of statically arranged "bricks" or polygons, if there are moving elements, and whether collisions only involve the player and the environment or if other elements like characters or objects are likely to collide.
Yes, it involves player vs. static environment, dynamic objects, enemies, and static objects. The "mini-game engine" includes: 1) Game environment collisions that consist of colliders SWEPT AB: Lines, boxes, and circles only. + Lines are convex objects, like pyramids or anything non-rectangular in shape. + Boxes are aligned screen objects, similar to Minecraft boxes. + Circles represent projectiles or other round objects like fireballs, spheres, bubbles, etc. There are three SWEPT algorithms required: Circle vs. Line, Box vs. Box, and Circle vs. Circle. Box vs. Box and Circle vs. Circle are already implemented because they are straightforward. The Circle vs. Line SWEPT is the only one required. The Circle vs. Line should function like "Circle vs. convex Polygon" where all lines are tested against the Circle, which can also be an object rather than just the player. >>>> There are other highly effective collision algorithms, such as the distance/normal mask, but they may not be suitable for all situations. These questions need to be answered before adapting this function. If you'd like, you can send me a private message with the source of your game so I can take a look and better understand its specifics. Thank you very much! Ultimately, game creation must align with the available technical capabilities. Collision handling is of utmost importance. If these collision functions work flawlessly, then I can focus on developing a game around them. If you have a game idea, and after two years, you can't meet the technical requirements, it's game over. So in this case I would love to have all algorithms done, then this about what possible. ________________________________________________________________________________________________________________________________________ >Si je comprends bien, vous souhaitez adapter cet algorithme de collision pour l'utiliser dans un jeu de plateau de style Mario ?Oui, et plus encore ; il peut également être appliqué à un jeu de collision isométrique, un jeu de style Galaga, au billard, au flipper, et certainement à un jeu de plateforme. >> Si c'est effectivement le cas, le défi réside dans le fait que vous souhaitez utiliser la fonction de collision telle quelle, mais elle doit être intégrée à un algorithme global différent qui englobe le mouvement du joueur. Dans le cas d'un jeu de style "Doom", cela implique un traitement par secteurs. Ces secteurs ne sont pas strictement stockés en mémoire ; en réalité, ils sont déterminés en passant par des lignes traversables spécifiques qui nous permettent d'identifier dans quel secteur nous nous trouvons. C'est pourquoi il est absolument nécessaire de connaître la position du joueur avec précision dès le départ, initialisée à la valeur correcte.
a) Je n'ai pas besoin de secteurs pour tous les projets actuels que j'ai en tête. J'ai besoin d'un algorithme de collision cercle-ligne balayée AB qui fonctionne parfaitement, en mettant l'accent sur les collisions entre le joueur et l'environnement. b) La segmentation doit être gérée par une logique de code quelconque, car lorsque vous commencez à construire un environnement et à apporter des modifications complexes, vous ne voulez pas reconstruire manuellement tous les points et lignes pour tous les secteurs. >>> Pour un jeu de plateau, il faut aborder les choses différemment. Tout dépend de la structure de votre jeu de plateau, que ce soit des "briques" statiquement disposées ou des polygones, s'il y a des éléments en mouvement, et si les collisions ne concernent que le joueur et l'environnement, ou si d'autres éléments comme des personnages ou des objets risquent également de entrer en collision.
Oui, cela implique le joueur contre l'environnement statique, des objets dynamiques, des ennemis et des objets statiques. Le "mini-moteur de jeu" comprend : 1) Les collisions de l'environnement de jeu qui se composent de colliders SWEPT AB : des lignes, des boîtes et des cercles uniquement. + Les lignes sont des objets convexes, comme des pyramides ou tout ce qui n'est pas de forme rectangulaire. + Les boîtes sont des objets alignés à l'écran, similaires aux boîtes de Minecraft. + Les cercles représentent des projectiles ou d'autres objets de forme ronde, tels que des boules de feu, des sphères, des bulles, etc. Trois algorithmes SWEPT sont nécessaires : Cercle contre Ligne, Boîte contre Boîte, et Cercle contre Cercle. La Boîte contre Boîte et le Cercle contre Cercle sont déjà implémentés car ils sont simples. Le Cercle contre Ligne balayée est le seul requis. Le Cercle contre Ligne devrait fonctionner comme "Cercle contre Polygone convexe" où toutes les lignes sont testées contre le Cercle, qui peut également être un objet plutôt que simplement le joueur. >>>> Il existe d'autres algorithmes de collision très efficaces, tels que le masque de distance/normal, mais ils ne conviennent peut-être pas à toutes les situations. Ces questions doivent être résolues avant d'adapter cette fonction. Si vous le souhaitez, vous pouvez m'envoyer un message privé avec la source de votre jeu pour que je puisse y jeter un coup d'œil et mieux comprendre ses spécificités.
Merci beaucoup ! En fin de compte, la création de jeu doit s'aligner sur les capacités techniques disponibles. La gestion des collisions est d'une importance capitale. Si ces fonctions de collision fonctionnent parfaitement, je pourrai me concentrer sur le développement d'un jeu autour d'elles. Si vous avez une idée de jeu et que, deux ans plus tard, vous ne pouvez pas répondre aux exigences techniques, c'est game over. Dans ce cas, j'aimerais avoir tous les algorithmes terminés, puis réfléchir à ce qui est possible. --------------- 2 times I started with an idea, then I can't meet the technical requirements.. so I think the other way around has more success
|
|
|
Post by scalion on Sept 25, 2023 17:43:02 GMT 1
... Elaboration d'un nouveau système de collision circle / polygon... Bon, on est lundi. Voici l'approche que j'ai choisi de suivre, peut-être que je fait une erreur quelque part mais ca me semble pas mal pour l'instant. Considérons un polygone à N sommets, ce polygone ne sera valide pour le test de collision que si : - aucune ligne ne se croise. - il comprend au minimum 3 sommets (oui bon c'est sûr...) - il ne comporte pas un trou quelque part. Comme on veut savoir si la trajectoire d'un cercle entre en collision avec ce polygone on sait que la zone de collision correspond à la distance du centre du cercle au polygone. On doit aussi déterminer si le point de départ du cercle est à l'intérieur ou à l'extérieur du polygone. Ceci est facile à faire, il suffit de tirer une ligne horizontale depuis ce point et de compter les intersections avec le polygone. Si le résultat est pair le point est à l'extérieur, amusant.
Comme on peut le voir sur le schéma ci-dessus, on va devoir effectuer des intersections avec des lignes et des cercles.
Pour positionner les lignes extérieures qui représentent ici la zone de collision il faut faire en sorte que le polygone tourne toujours dans le même sens.
EDIT 26/09/2023, Youpi j'ai la matinée devant moi. Je continues.
Pour s'assurer qu'un polygone tourne dans le sens des aiguilles d'une montre (clockwise), on va prendre le sommet le plus à gauche et vérifier que le sommet suivant est bien à gauche du coté précédent. Si ce n'est pas le cas on inverse simplement l'ordre des sommets.
En ce qui concerne les cercle d'intersection, on commence par éliminer ceux qui se trouve dans un angle concave (voir schéma). L'intersection ne concernera que la partie du cercle en jaune (voir schéma), pour ce faire il faudra vérifier que le point d'intersection est à gauche ou à droite des perpendiculaires des cotés.
Les lignes de collision (en vert) devront être réduites dans les parties concaves par l'intersection.
Voilà pour la théorie.
-------------------
Et maintenant on code.
Pour la collision je garde mon UDT
Type Collision_Struct - Double xClash, yClash, NormalX, NormalY, IncidentX, IncidentY, U - Double xSlide, ySlide EndType
Pour le polygone, je vais essayer de faire au plus simple avec une adresse qui stocke une liste de sommets :
Type Polygon_Struct - Long Address - Long Vertices EndType
On pourrait compléter cet UDT et y ajouter le kit complet des intersections, et pour que ce soit le plus rapide possible on y stockerait les vecteurs qui permettent de calculer les intersections. :
Type Polygon_Struct - Long Address - Long Vertices - Long Circ_Address - Long Circ_Count - Long Line_Address - Long Line_Count EndType
Cependant cela imposerait que le cercle avec lequel on veut déterminer une collision soit toujours de même rayon, autrement il faudrait recalculer à chaque fois. Donc je vais garder le 1er UDT avec simplement Address et Vertices. Cependant je garde en mémoire cette possibilité.
Il ne reste plus qu'à utiliser tout ça avec des fonctions de construction et de manipulation de polygone et de collision, avec une petite démo à sa mémère.
A très bientôt.
...
To be continued...
|
|
|
Post by scalion on Sept 27, 2023 12:30:08 GMT 1
Après quelque essais, j'élimine le test préalable du point de départ du déplacement du cercle. En effet le calcul permettant de le déterminer revient à calculer la collision et est donc totalement inutile (et long). J'ai donc enrichi l'UDT Collision_Struct avec une variable Inside de type Byte. Si Collision.Inside > 0 alors le point est à l'intérieur, c'est beaucoup plus simple (il s'agit d'une mesure entre la normale et le déplacement). Voici donc un premier essai, merci pour ton retour Roger.
|
|
|
Post by (X) on Sept 27, 2023 12:38:25 GMT 1
Très joli!
|
|
|
Post by Roger Cabo on Sept 27, 2023 17:17:15 GMT 1
This is realty great! -------- Excusez-moi, j'ai été absent(e) pendant 2 jours.. car j'ai eu une opération dentaire.. Super !!! Ça a l'air bien ! J'aurai le temps de tester demain.. j'ai une question : a) Tu utilises *And* au lieu de l'opérateur binaire &&.. est-ce que c'est correct ? "If C_Concave And !IgnoreVector" je n'ai même pas vu de &&
|
|
|
Post by scalion on Sept 27, 2023 17:48:48 GMT 1
Si on a un polygone entièrement convexe (un octogone par exemple) tout va bien. Ce qui pose problème ce sont les parties concaves, je ne sais pas comment les gérer. Si bien qu'avec un radius trop grand les erreurs apparaissent, notamment sur la découpe des lignes de collision. De plus la fonction n'est pas conçue pour une collision depuis l'intérieur du polygone, cela reste à implémenter. Il faut que je revoie tout ça.
Et pour répondre à ta question, oui, AND est correct. Je sais qu'il y a une différence de fonctionnement avec && mais je ne m'y suis jamais vraiment intéressé. Je vais tester.
Wow la vache !!! && est 2x fois plus rapide !! tu le savais ? Moi je découvre !
Merci pour l'info !
|
|
|
Post by scalion on Sept 28, 2023 9:40:41 GMT 1
Ok, j'ai supprimé la réduction des lignes et en ce qui concerne une collision depuis l'extérieur du polygone ça à l'air de marcher parfaitement. Je n'ai toujours pas implémenté une collision depuis l'intérieur, mais je teste en premier si la position de départ est à l'intérieur du polygone. S'il est à l'intérieur alors la fonction renvoie False (pas de collision). Ca fonctionne très bien comme ça. Mais je vais réfléchir tout de même à la possibilité d'une collision depuis l'intérieur du polygone. Voici donc le 2ème essai : test collision circle polygon 2.G32 (17.26 KB)
|
|
|
Post by (X) on Sept 28, 2023 13:04:58 GMT 1
Encore... fabuleux! Ça serait impressionnant de voir ceci intégré avec les outils de base GFA. Ça me fais penser à pleins de possibilité utiles.
Again... fabulous! It would be impressive to see this integrated with the basic GFA tools. Makes me think of lots of useful possibilities.
Noch einmal ... fabelhaft! Es wäre beeindruckend, wenn dies in die grundlegenden GFA-Tools integriert werden könnte. Das lässt mich an viele nützliche Möglichkeiten denken.
Ancora una volta... favoloso! Sarebbe fantastico vederlo integrato con gli strumenti GFA di base. Mi fa pensare a molte possibilità utili.
De nuevo... ¡fabuloso! Sería genial ver esto integrado con las herramientas básicas de GFA. Me hace pensar en un montón de posibilidades útiles.
Και πάλι... υπέροχα! Θα ήταν φοβερό να ενσωματωθεί με τα βασικά εργαλεία GFA. Με κάνει να σκέφτομαι πολλές χρήσιμες δυνατότητες.
|
|
|
Post by Roger Cabo on Sept 28, 2023 16:38:12 GMT 1
Currently on my 2nd win10 machine the demo 1 and 2 crash completely.. for any reason.. I have no idea why this happen.. and always after about 200 until 250 frames. It crash directly when using the left mouse button to exchange the starting point.. I updated the GB32 to the latest version, and gpu Driver as well. Error persist. I think it has todo with D2D. When disabling D2D completely in gb32 it works!!!! Tonight I drive back to my home town and have a look on my main machine.
|
|
|
Post by scalion on Sept 28, 2023 16:43:37 GMT 1
Currently on my 2nd win10 machine the demo 1 and 2 crash completely.. for any reason.. I have no idea why this happen.. and always after about 200 until 250 frames. It crash directly when using the left mouse button to exchange the starting point.. I updated the GB32 to the latest version, and gpu Driver as well. Error persist. I think it has todo with D2D. View AttachmentWhen disabling D2D completely in gb32 it works!!!! Tonight I drive back to my home town and have a look on my main machine. I tried to crashing the programm, but inever reach the error ! I'm under win10.
Add this procedure : Proc WhereIsError If !IsNothing(Me) Me.Caption = TraceLnr & ": " & Trace$ EndIf EndProc Insert TRON WhereIsError somewhere arround Fullw #1 Run it ! Look the windows title when the programm crash and not respond and give me the line number. Dont use Debug windows because it's too long in this case.
|
|
|
Post by scalion on Sept 29, 2023 11:54:26 GMT 1
Je me rends compte qu'il y a encore des questions qui n'ont pas de réponses avec ce système de collision. Quelle position de collision doit-on renvoyer quand la position de départ du cercle est sur la ligne de collision où à l'intérieur ?
Je vais opter pour qu'une position de départ à l'intérieur du polygone ou trop proche de celui-ci, renvoie dans le sens inverse du déplacement sur la limite de collision,la longueur du vecteur incident étant alors égal à celle du déplacement.
Dans ces cas Collision.Inside = 1.
|
|
|
Post by Roger Cabo on Sept 29, 2023 18:07:21 GMT 1
Crash :Je n'ai aucun problème avec le code sur mon PC principal... Je n'ai aucune idée de la cause de l'erreur. L'ordinateur où l'erreur se produit est beaucoup plus lent, mais utilise aussi Win 10. Laissons tomber. Quand j'y retournerai, j'essaierai de résoudre le problème avec ta suggestion. Quand le problème survient, Gb32 s'arrête immédiatement.. Il n'y a plus aucune sortie de trace. J'ai essayé d'écrire dans un fichier avec Trace$, mais le fichier ne peut pas être fermé lorsque l'erreur survient et est bloqué sur le système. Réponses : Cercle sur la ligne de collision. Nous nous y dirigeons lentement en pensée. Un drapeau devrait être attribué à un polygone. Ce drapeau devrait être inclus dans la structure du polygone. Tu utilises Malloc pour créer une taille de polygone dynamique. Je comprends cela. En interne, je vais utiliser une structure de type qui peut accueillir un maximum de 32 points dans un objet. Cela a plusieurs avantages, le code reste clair et les adresses sont directement accessibles. Type Env_Object32 typ As Int // 1 = Joueur Cercle / 0 = objet de jeu / 2 = Position de départ du joueur radius As Double // Si joueur alors ici radius prop As Int '(0) = true // L'objet n'existe pas pour le gameplay. (sinon Porte, champ de force, Barricade) '(1) = true // Pas encore utilisé '(2) = true // Pas encore utilisé '(3) = true // Pas encore utilisé count As Int // Nombre de points utilisés dans un polygone. x(31) As Double y(31) As Double linePass(31) As Byte // voir plus tard lineBounce(31) As Double // voir plus tard chainSection As Int // ici se trouve l'indice du prochain Env_Object32 EndType
Considération : .linePass() Il ne peut pas y avoir de polygone où le joueur se trouve uniquement à l'intérieur. Ce serait alors tout son monde de jeu et un piège dont il ne pourrait pas s'échapper. (Je ne sais pas si c'est réalisable) Si un polygone est "accessible ou pénétrable", alors il doit aussi être possible d'en sortir. C'est là que .linePass entre en jeu. .linePass(0) = 0 // Propriété standard Le joueur collisionne de l'extérieur. Si le joueur est dans le polygone (à l'intérieur), il peut passer à travers cette ligne de l'intérieur vers l'extérieur. .linePass(0) = 1'1' définit la ligne de xy(0) à xy(1). Le joueur peut passer à travers la ligne de l'extérieur, et aussi revenir. Cela reste toujours "ouvert" et est toujours "franchissable". Il n'existe pas pour le joueur. .linePass(0) = 2Le joueur peut passer à travers la ligne de l'extérieur. Mais il ne peut pas passer à travers cette ligne de l'intérieur vers l'extérieur. Ce concept, (s'il est possible), offrirait de nombreuses possibilités pour les jeux. Modifier .LinePass(0) = 1 ou 2 pourrait symboliser un champ de force. Considération : .lineBounce() La collision du joueur sur cette ligne absorbe ou amplifie la collision. .lineBounce(n) *= 1 - n amplifie .lineBounce(n) *= 0.0 - 0.9999 réduit .lineBounce(n) *= 0.0 absorbe incident. Maintenant, cercle sur la ligne de collision :A) Alors il y a une erreur. Le joueur doit être sur la "position de départ" Env_Object32.typ = 2 B) Alors il y a une erreur. Le joueur doit être sur la "position de départ" Env_Object32.typ = 2 C) S'il est possible de déterminer que A ou B se produit, alors on pourrait aussi donner l'indication..
Msgbox "Erreur dans la construction de la carte et de l'objet xxx : Le joueur n'a pas d'espace pour bouger." Cela répond-il à ta question ? J'ai aussi une question :A) Les calculs d'un polygone convexe seraient-ils plus rapides ? B) Serait-il possible de développer en plus un code pour Circle vs Line à partir de cela ?
|
|
|
Post by Roger Cabo on Sept 29, 2023 18:51:19 GMT 1
Autres réflexions : Nous avons besoin d'environ 1 Mo pour 1000 objets avec cette structure (1K). Nous pouvons adresser un total de 285000 objets dans GB32, ce qui représente 285 MB.
Type Env_Object32 chainSection as Int
La Chain Section connecterait différents Env_Object32 comme dans votre projet précédent, les regrouperait et les entourerait d'une limite.
Quel serait l'intérêt d'une ChainSection ? Je ne suis pas sûr de la taille maximale qu'une image D2D peut atteindre. Je pense 16 bits avec 32535x32535 pixels comme dans Windows.. non ?
La question est, lorsque le joueur traverse une carte qui est plus grande que l'écran, que faisons-nous alors ? A) Déplaçons-nous tous les éléments x, y offset et dessinons-les à la position normale de l'écran ? (Défilement doux) Alors, devrions-nous déclarer un Dim ENV_OffsetX, Y, qui serait ajouté à toutes les coordonnées ENV_OffsetX, Y ? B) Ou y a-t-il une fonction de clip x, y, w, h dans D2D ? Nous devrions quand même réfléchir à la manière de grouper les objets par zones avec .ChainSection. Mais aurions-nous alors seulement une surface de monde de jeu de 32535x32535 pixels ?
Je viens de lire qu'il y a une matrice de décalage dans D2D.
Utilisation des matrices de transformation dans Direct2D : Création de la matrice : Vous pouvez créer une matrice de transformation qui représente un décalage (translation) le long des axes X et Y. Cette matrice agirait comme une "matrice de caméra".
D2D1::Matrix3x2F translation = D2D1::Matrix3x2F::Translation(global_X, global_Y);
Mais je n'ai absolument aucune idée si cela est adapté dans GB32 et comment l'appliquer.
J'ai aussi lu : En utilisant des matrices de transformation, vous pouvez éviter de devoir changer manuellement les coordonnées de chaque objet individuel lorsque le joueur se déplace dans le monde du jeu. Cela peut améliorer les performances et rendre le code plus clair.
|
|
|
Post by Roger Cabo on Oct 2, 2023 21:00:12 GMT 1
UPDATED: 03-10-2023
I overlooked in the hot calculation code:
// Function CollisionCirclePolygon() D2ForeColor = D2C_Gray D2Line BCx1, BCy1, BCx2, BCy2 D2Text ((BCx1 + BCx2) / 2, (BCy1 + BCy2) / 2, Trim(i))
That tame the performance completely. Without these lines, I got about 500 collisions per 1ms.
----------------
Today, I rebuilt the version with a structure for it. This now contains the polygon definitions x, y, and pCount. It wasn't easy at all .
Scalion, you really did an absolutely great job! Thanks! I manage to get around 10 collision queries per 1ms. If we want 60 FPS, that would mean we have 16ms per frame to process everything. Usually, one needs half of that time, so ~8ms for collisions, and the rest for rendering which is realistic. That would be ~4000 collisions that could occur in updating between 1 frame. That's a great amount!! What would be important are sectors that Scalion had already implemented. Objects are inserted into sectors, and when a sector is entered by the player, only collisions are tested there. Sectors should also be able to overlap. If a projectile or an object is thrown or fired by the player, or whatever, the player might already be in another sector, but the projectile in a previous one. Therefore, all dynamic objects with autonomy should be tested against all sectors. But we'll get to that later. -------------------
MIS À JOUR : 03-10-2023J'ai négligé dans le code de calcul chaud : // Function CollisionCirclePolygon(...) D2ForeColor = D2C_Gray D2Line BCx1, BCy1, BCx2, BCy2 D2Text ((BCx1 + BCx2) / 2, (BCy1 + BCy2) / 2, Trim(i)) Cela a complètement modéré la performance. Sans ces lignes, j'obtenais environ 500 collisions par 1ms. Aujourd'hui, j'ai reconstruit la version avec une structure pour cela. Elle contient désormais les définitions du polygone x, y et pCount. Ce n'était pas du tout facile . Scalion, tu as vraiment fait un travail absolument fantastique ! Merci !Je parviens à obtenir environ 10 requêtes de collision par 1ms. Si nous voulons 60 FPS, cela signifierait que nous avons 16ms par image pour tout traiter. Habituellement, on a besoin de la moitié de ce temps, soit environ 8ms pour les collisions, et le reste pour le rendu, ce qui est réaliste. Cela serait ~4000 collisions qui pourraient se produire en mettant à jour entre 1 image. C'est énorme ! Ce qui serait important, ce sont les secteurs que Scalion avait déjà mis en œuvre. Les objets sont insérés dans des secteurs, et lorsqu'un secteur est entré par le joueur, seules les collisions y sont testées. Les secteurs devraient également pouvoir se chevaucher. Si un projectile ou un objet est lancé ou tiré par le joueur, ou quoi que ce soit, le joueur pourrait déjà être dans un autre secteur, mais le projectile dans le précédent. Par conséquent, tous les objets dynamiques avec autonomie devraient être testés contre tous les secteurs. Mais nous y reviendrons plus tard. -------------------
|
|
|
Post by scalion on Oct 3, 2023 7:09:02 GMT 1
Hello Roger, J'ai bien lu tes remarques et idées. Je travaille là dessus. Pour ce qui est des matrices il faut utiliser D2TRANSFORM (voir l'aide).
Attention avec les secteurs qui se chevauchent, à mon humble avis tu ferais mieux de créer un 3ème secteur résultant de l'intersection des secteurs. Je suis en train d'améliorer le système. Je reviendrais bientôt pour plus de détails.
|
|
|
Post by Roger Cabo on Oct 3, 2023 19:12:17 GMT 1
UPDATED: 03-10-2023I overlooked in the hot calculation code: // Function CollisionCirclePolygon() D2ForeColor = D2C_Gray D2Line BCx1, BCy1, BCx2, BCy2 D2Text ((BCx1 + BCx2) / 2, (BCy1 + BCy2) / 2, Trim(i)) That tame the performance completely. Without these lines, I got about 500 collisions per 1ms. test collision circle polygon 4_struc.G32 (16.95 KB)
|
|
|
Post by Roger Cabo on Oct 8, 2023 22:22:14 GMT 1
|
|
|
Post by (X) on Oct 8, 2023 23:25:51 GMT 1
Sebatian is a star!
|
|
|
Post by Roger Cabo on Oct 9, 2023 10:30:24 GMT 1
Yes, he's has great math and trigonometry abilities / skills and he is able to find solutions.
|
|
|
Post by scalion on Oct 10, 2023 7:08:08 GMT 1
Yes it's truly astonishing ! And i love his cat !
Bon je n'ai pas tellement avancé sur la collision circle/polygon. J'essaie de définir de manière stricte la zone de collision afin de pouvoir effectuer une collision depuis l'intérieur.
Dans cette perspective j'ai codé une fonction qui m'a donné du fil à retordre pour connaitre la distance d'un cercle à un sommet dans un angle concave. Elle fonctionne à merveille mais cela ne résout pas tout.
La fonction :
Function CircleBissectorDistance(x1, y1, x2, y2, x3, y3, radius) As Double Local Double dx1, dy1, d1, dx2, dy2, d2 Local Double x, y, a, b, d, r dx1 = x1 - x2 dy1 = y1 - y2 d1 = dx1 * dx1 + dy1 * dy1 dx2 = x3 - x2 dy2 = y3 - y2 d2 = dx2 * dx2 + dy2 * dy2 If d1 > d2 d1 = Sqr(d2 / d1) x = dx1 * d1 - dx2 y = dy1 * d1 - dy2 d = d2 Else If d2 > d1 d2 = Sqr(d1 / d2) x = dx1 - dx2 * d2 y = dy1 - dy2 * d2 d = d1 Else x = dx1 - dx2 y = dy1 - dy2 d = d1 EndIf If d = 0 Return 0 a = x * x + y * y If a = 0 Return 0 b = a - 4 * d r = radius * radius Return (Sqr(r * a / d) + Sqr((r * b * b) / (d * a))) / 2 EndFunc
J'ai initialisé des données précalculées dans la structure même du polygone (bissecteurs, perpendiculaires, valeur max), ce qui fonctionne très bien aussi. Ainsi les segments de collision sont calculés rapidement lors du test.
Mais j'ai toujours un problème avec les parties concaves car les segments de collisions se recouvrent et donc on se retrouve à tester des intersections de segments ce qui alourdit terriblement les temps de calculs.
J'en viens donc à considérer qu'il faudrait que les polygones à collisionner soient toujours convexes, ce qui impliquerait qu'un polygone avec des parties concaves devrait être divisé en plusieurs polygones convexes. Je vois bien comment faire. Mais ce va me demander du temps.
Je vais poster mon fichier d'aide mis à jour avec quelques nouveautés.
|
|
|
Post by Roger Cabo on Oct 10, 2023 21:28:54 GMT 1
Hi Scalion,
Oui, on peut calculer la distance la plus courte entre un point et une ligne. Cette distance est la longueur de la perpendiculaire tracée du point à la ligne. Si le point se trouve à l'intérieur du segment de ligne, cette distance est correcte. Si le point se trouve en dehors du segment de ligne, la distance est celle du point le plus proche des extrémités du segment.
Pour savoir si le segment de polygone a été percuté de l'intérieur ou de l'extérieur, cela dépend de la direction du vecteur de mouvement par rapport à la normale de ce segment.
Convexe: Il est possible qu'un cercle ne puisse exister qu'à l'intérieur d'un polygone si ce polygone est convexe. Cela simplifie les choses. On pourrait aussi regrouper tous les points internes pour former un nouveau polygone, et je crois qu'il en résulterait un polygone convexe.
|
|