Moteur Raycasting
15 sujets de 1 à 15 (sur un total de 28)
- 1
- 2
-
Hello,
Plutôt que de passer mon temps a critiquer tous le monde et comme ma femme me laisse plus de temps à coder, j’ai revu mon moteur de raycasting créé avec Hollywood.
J’ai essayé de faire un code clair, facile à retranscrire sur d’autres langage de programmation tel que l’Amos (d’ailleurs, si quelqu’un pouvait s’y atteler, sa pourrait être marrant car je suis sûre que le rendu serait plus rapide sur un 1200 mais en 320×256)
Trêve de plaisanterie et laissons place au code :
<code>
; Moteur de Raycasting Simplifié
; Créer par Artblink en 2010, modifié en 2013
; Se moteur n’est pas optimisé mais simplifié pour la lecture
; Moteur à 90 FPS => peut être poussé à 200 FPS, mais difficilement lisible
; (testé Sur PC Quad Q9550 @ 2.83Ghz/4 Go/NVIDIA GeForce GTX 570 avec Hollywood 4.8)
; Il sert de tuto pour être adapté sur d’autres langage de programmation
; Normalement, il doit être très simple de l’adapter en Amos
;
@SCREEN {Mode = « ask », Width = 640, Height = 480}
; Définition de la taille de la carte, un tableau de 24 colonnes/24 lignes
NombreDeLigne=24
NombreDeColonne=24
; 0 rien, >0 un mur, le numéro étant la couleur de se mur
CarteDuJeux = {
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1},
{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1},
{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,2,2,0,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
}
; Position du départ dans le tableau
PositionEnXSurCarte = 22 ; Ligne N°21
PositionEnYSurCarte = 12 ; Colonne N°11
; Définition des variables Globales
DirectionEnX = 1
DirectionEnY = 0.1
planex = 0
planey = 0.66
VitesseDeDeplacement= 0.25
VitesseDeLaRotation = 0.05
TailleEcranEnX=639
TailleEcranEnY=479
; Fonction Principale
Function prg()
StartTimer(1) ; Départ du chronomètre pour calculer le nombre d’image par seconde
For Local CoordonnesEnX = 1 To TailleEcranEnX
; Variables Local pour gagner en rapidité
Local CameraEnX = 2*CoordonnesEnX/TailleEcranEnX-1
Local PositionEnXduLancerdeRayon = PositionEnXSurCarte
Local PositionEnYduLancerdeRayon = PositionEnYSurCarte
Local DirectionEnXduLancerDeRayon = DirectionEnX + planex*CameraEnX
Local DirectionEnYduLancerDeRayon = DirectionEnY + planey*CameraEnX
Local CarteEnX = Int(PositionEnXduLancerdeRayon)
Local CarteEnY = Int(PositionEnYduLancerdeRayon)
Local DistanceLateraleEnX = 0
Local DistanceLateraleEnY = 0
Local deltadistx = Sqrt(1+(DirectionEnYduLancerDeRayon*DirectionEnYduLancerDeRayon)/(DirectionEnXduLancerDeRayon*DirectionEnXduLancerDeRayon))
Local deltadisty = Sqrt(1+(DirectionEnXduLancerDeRayon*DirectionEnXduLancerDeRayon)/(DirectionEnYduLancerDeRayon*DirectionEnYduLancerDeRayon))
Local Perspective = 0
Local stepx = 0
Local stepy = 0
Local MurTouche = 0
Local CoteDuMur = 0
; Début des tests du raycasting (lancé de rayon)
If DirectionEnXduLancerDeRayon < 0
stepx = -1
DistanceLateraleEnX = (PositionEnXduLancerdeRayon – CarteEnX)*deltadistx
Else
stepx = 1
DistanceLateraleEnX = (CarteEnX + 1 – PositionEnXduLancerdeRayon)*deltadistx
EndIf
If DirectionEnYduLancerDeRayon < 0
stepy = -1
DistanceLateraleEnY = (PositionEnYduLancerdeRayon – CarteEnY)*deltadisty
Else
stepy = 1
DistanceLateraleEnY = (CarteEnY + 1 – PositionEnYduLancerdeRayon)*deltadisty
EndIf
; On test si lorsque l’on bouge, on touche un mur de la carte
While MurTouche = 0 ; Tant qu’il n’y a pas de mur
;
If DistanceLateraleEnX < DistanceLateraleEnY
DistanceLateraleEnX = DistanceLateraleEnX + deltadistx
CarteEnX = CarteEnX + stepx
CoteDuMur = 0
Else
DistanceLateraleEnY = DistanceLateraleEnY + deltadisty
CarteEnY = CarteEnY + stepy
CoteDuMur = 1
EndIf
;
If CarteDuJeux[CarteEnX][CarteEnY] > 0 Then MurTouche = 1
;
Wend ; fin du test de tant qu’il y a pas de mur
; Il est plus rapide de multiplier par 0.5 que de diviser par 2
If CoteDuMur = 0
Perspective = Abs((CarteEnX – PositionEnXduLancerdeRayon + (1-stepx)*0.5)/DirectionEnXduLancerDeRayon)
Else
Perspective = Abs((CarteEnY – PositionEnYduLancerdeRayon + (1-stepy)*0.5)/DirectionEnYduLancerDeRayon)
EndIf
;
If Perspective=0 Then Perspective=1
HauteurLigne = Int(TailleEcranEnY/Perspective)
DepartLigne = (-HauteurLigne*0.5 + TailleEcranEnY*0.5)
;
If DepartLigne <0 Then DepartLigne=0
;
FinLigne = (HauteurLigne*0.5 + TailleEcranEnY*0.5)
;
If FinLigne >= TailleEcranEnX Then FinLigne = TailleEcranEnX
; En fonction de la valeur du mur dans la carte, on change la couleur du mur
Switch(CarteDuJeux[CarteEnX][CarteEnY])
;
Case 1: Couleur = $AA2222 ; Rouge
Case 2: Couleur = $22AA22 ; Vert
Case 3: Couleur = $2222AA ; Bleu
Case 4: Couleur = $AAAAAA ; Blanc
Default: Couleur = $AAAA22 ; Jaune
;
EndSwitch
; Variable global pour les couleurs sauf celles des murs
Local CouleurSol = $444444
Local CouleurPlafond = $888888
Local CouleurBandes = $666666
;
If CoteDuMur = 1
Couleur=Couleur*0.5
CouleurBandes = CouleurBandes *0.5
EndIf
; Encore du local pour la rapiditée
Local BandeHaut = TailleEcranEnY/2+FinLigne
Local BandeBas = TailleEcranEnY/2+DepartLigne
; On trace les lignes pour créer la perspective
Line (CoordonnesEnX,DepartLigne,CoordonnesEnX,FinLigne,Couleur); Mur
Line (CoordonnesEnX,FinLigne,CoordonnesEnX,FinLigne+240,CouleurSol) ; Sol
Line (CoordonnesEnX,0,CoordonnesEnX,DepartLigne,CouleurPlafond) ; Plafond
Line (CoordonnesEnX,BandeHaut*0.5,CoordonnesEnX,BandeHaut*0.5,CouleurBandes) ; Trait haut des murs
Line (CoordonnesEnX,TailleEcranEnY*0.5,CoordonnesEnX,TailleEcranEnY*0.5,CouleurBandes); Trait du milieu des murs
Line (CoordonnesEnX,BandeBas*0.5,CoordonnesEnX,BandeBas*0.5,CouleurBandes) ; Trait bas des murs
; Fin de la boucles
Next
; Test si on appuie sur la touche flèche « Haut »
If IsKeyDown(« Up »)=True
;
If CarteDuJeux[Int(PositionEnXSurCarte + DirectionEnX * VitesseDeDeplacement)][Int(PositionEnYSurCarte)] = 0 Then PositionEnXSurCarte = PositionEnXSurCarte + DirectionEnX * VitesseDeDeplacement
If CarteDuJeux[Int(PositionEnXSurCarte)][Int(PositionEnYSurCarte + DirectionEnY * VitesseDeDeplacement)] = 0 Then PositionEnYSurCarte = PositionEnYSurCarte + DirectionEnY * VitesseDeDeplacement
;
EndIf
; Test si on appuie sur la touche flèche « Bas »
If IsKeyDown(« Down »)=True
If CarteDuJeux[Int(PositionEnXSurCarte + DirectionEnX * VitesseDeDeplacement)][Int(PositionEnYSurCarte)] = 0 Then PositionEnXSurCarte = PositionEnXSurCarte – DirectionEnX * VitesseDeDeplacement
If CarteDuJeux[Int(PositionEnXSurCarte)][Int(PositionEnYSurCarte + DirectionEnY * VitesseDeDeplacement)] = 0 Then PositionEnYSurCarte = PositionEnYSurCarte – DirectionEnY * VitesseDeDeplacement
EndIf
; Test si on appuie sur la touche flèche « Gauche »
If IsKeyDown(« Left »)=True
;
AncienneDirectionEnX=DirectionEnX
DirectionEnx = DirectionEnX * Cos(-VitesseDeLaRotation) – DirectionEnY * Sin(-VitesseDeLaRotation);
DirectionEnY = AncienneDirectionEnX * Sin(-VitesseDeLaRotation) + DirectionEnY * Cos(-VitesseDeLaRotation);
oldPlaneX = planex;
planex = planex * Cos(-VitesseDeLaRotation) – planey * Sin(-VitesseDeLaRotation);
planey = oldPlaneX * Sin(-VitesseDeLaRotation) + planey * Cos(-VitesseDeLaRotation);
EndIf
; Test si on appuie sur la touche flèche « Droite »
If IsKeyDown(« Right »)=True
;
AncienneDirectionEnX = DirectionEnX ;
DirectionEnx = DirectionEnX * Cos(VitesseDeLaRotation) – DirectionEnY * Sin(VitesseDeLaRotation);
DirectionEnY = AncienneDirectionEnX * Sin(VitesseDeLaRotation) + DirectionEnY * Cos(VitesseDeLaRotation);
oldPlaneX = planex;
planex = planex * Cos(VitesseDeLaRotation) – planey * Sin(VitesseDeLaRotation);
planey = oldPlaneX * Sin(VitesseDeLaRotation) + planey * Cos(VitesseDeLaRotation);
EndIf
; Calcule simple du FPS
Local Temps=GetTimer(1)
Local FPS=Int((1/Temps)*1000)
; Affichage du FPS
TextOut(0,0,FPS)
; Flip d’écran (technique du double buffer)
Flip
; Effacer l’écran est inutile, puisque l’on retrace par dessus l’ancienne image
; donc la commande Cls ne sert à rien, encore du temps de gagner
;
; Fin de la fonction principale
EndFunction
; Lancement du moteur Double Buffer, toujours en dehors de fonction
BeginDoubleBuffer
; Configuration de l’intervalle Maximale de temps entre l’affichage de chaque image, ici 50 FPS
SetInterval(1,PRG,20)
; Boucle infinie pour que le programme ne se termine jamais
Repeat
WaitEvent() ; Attendre une action, ici, se sera les touches fléchées du clavier
Forever
Amusez-vous bienLe moteur tourne à 80 FPS, mais avec un peux d’optimisation, il peut tourner à 200Fps…. sur ma config PC bien sûr
Edit : Si quelqu’un pouvais modifier les balises pour le départ du code car sa marche mais pas du tout se serait sympa… un codeur Hollywood reste un codeur de merde dixit bigard en manger un steack haché préparer sur une hacheuse piloter par AOS 4.x
Houuu, je sens que je vais regarder ce code de prêt pour voir à améliorer le miens qui me fait un bug d’eyefish très désagréable !
Abonnez-vous à ma nouvelle chronique "En Route vers le Futur" sur Youtube !
hum sur Amos…
hum….
je saurais pas faire…
L’effet eyefish, je l’ai eu, mais je sais plus comment j’ai fait pour l’enlever…. je crois si je m’en souvient que c’est du soit à la position de la caméra
Pour ne pas marcher en crabe, ne pas oublier le -1 sur la ligne
Local CameraEnX = 2*CoordonnesEnX/TailleEcranEnX-1
Pour la commance Switch, en fait on remplace chaque cas par un test
le bloc de cmd est le suivant
Switch(CarteDuJeux[CarteEnX][CarteEnY])
;
Case 1: Couleur = $AA2222 ; Rouge
Case 2: Couleur = $22AA22 ; Vert
Case 3: Couleur = $2222AA ; Bleu
Case 4: Couleur = $AAAAAA ; Blanc
Default: Couleur = $AAAA22 ; Jaune
;
EndSwitch
Ce code peut être remplacer par des conditions (est en plus c’est plus rapide) [corriger grâce à Tcheko]
ex
If CarteDuJeux[CarteEnX][CarteEnY]=1 then Couleur = $AA2222
Etc… pour chaque cas
@Hivernaal: Quasi aucune commande ne diffère de l’amos
@screen=openscreen
Pour les tables, utilise Dim
pour remplacer le tracage
Line (CoordonnesEnX,DepartLigne,CoordonnesEnX,FinLigne,Couleur); Mur
on fait (si je me souvient bien)
Pen 1,couleur
Line CoordonnesEnX,DepartLigne to CoordonnesEnX,FinLigne
Je crois que c’est pen, pas sur car je confond souvent l’Amos avec le basic loco
Pour accélérer le code, précalculer les sin/cos
ex :
DirectionEnx = DirectionEnX * Cos(-VitesseDeLaRotation) – DirectionEnY * Sin(-VitesseDeLaRotation);
La variable VitesseDeLaRotation est en fait une constante, donc on peux précalculer Cos(-VitesseDeLaRotation) et mettre la valeur dans une table, sa évite, lorsque l’on appuie sur la touche directionnel Gauche ou droite de refaire du sin cos
Ex: Avant la boucle Principale on fait
Dim Calcule[4]
Calcule[0]=Sin(VitesseDeLaRotation)
Calcule[1]=Cos(VitesseDeLaRotation)
Calcule[2]=Cos(-VitesseDeLaRotation)
Calcule[3]=Sin(-VitesseDeLaRotation)
et dans le test If IsKeyDown, on a
DirectionEnx = DirectionEnX * Cos(-VitesseDeLaRotation) – DirectionEnY * Sin(-VitesseDeLaRotation);
on remplace par :
DirectionEnx = DirectionEnX * Calcule[1] – DirectionEnY * Calcule[3]
Et voila, plus de calcul avec cos et on gagne beaucoup de temps… surtout pas de variable global, sinon encore plus simple…
On prend sa calculette et on remplace Calcule[1] par la vrai valeur puisque vitessedelarotation est tjrs la même 😉
Sur Amos, je crois que l’on ne différencie pas les variables locales (interne à une boucle) à une variable globale (interne au programme=plus lente), donc pas de déclaration local devant les variables
Petit truc aussi, c’est plus rapide avec hollywood de * par 0.5 que de diviser par 2
Dans le prg il y a des variables globales inutiles qui font ralentir le moteur comme les variables globale TailleEcranEnX=639
et TailleEcranEnY=479, il suffit de mettre la taille directement dans les formules (sauf si on vaut que sont prg puisse s’ouvrir sur n’importe quelle format d’écran bien sûr)
Et il y a encore bien d’autre chose 😉
Modhttp://w3.restena.lu/amifra/exos/orth/regsece.htm
Les se en ce et les ce en se me piquent les yeux.
Si vous voyez des fotes d’ortaugraffes ou de congeuguézon, ou autres, merci de le faire savoir, le code en fait… on s’en fou
😀
Si sa intéresse quelqu’un qui veux utiliser se code, enlever les 2 lignes
Line (CoordonnesEnX,FinLigne,CoordonnesEnX,FinLigne+240,CouleurSol) ; Sol
Line (CoordonnesEnX,0,CoordonnesEnX,DepartLigne,CouleurPlafond) ; Plafond
Pas besoin du sol et du plafond, par contre, dès le début de la boucle principale, mettre sa:
SetFillStyle(#FILLCOLOR)
Box(0, 0, TailleEcranEnX+ 1, ((TailleEcranEnY+ 1) >>1), $6666DD)
Box(0, #BOTTOM, TailleEcranEnX + 1, ((TailleEcranEnY+ 1) >>1), $999900)
Sa trace 2 rectangle qui se partage la moitié de l’écran donc tjrs out le Cls, et on peut choisir la couleur du plafond et du sol sans tracer 1 milliard de lignes supplémentaires
et hop, on passe de 80 à 120 FPS… Cooool
oui les fautes ça pique les yeux….
@Artblink,
Ah, je vois que tu t’y remets, c’est bien.
pas encore trouvé le temps de mon côté et c’est dommage car avec la tripoté de nouveautés sur Hollywood, il y a de quoi faire.
Tu peux me mettre ça dans notre Dropbox Hollywood pour que je jette un oeil?
Merci!Merci Steff
Pour expliquer comment fonctionne se moteur basé sur le même site que screetch à vu, sur 640 lignes (la taille en X de l’écran) on calcule la valeur du point le plus haut du mur en Y (la valeur de la variable DebutLigne) et la valeur du point le plus bas du mur en Y (la valeur de la variable FinLigne) et on trace un trait verticale de longueur FinLigne-DebutLigne qui commencera à la coordonnée Y=DebutLigne pour chaque coordonnée en X de l’écran soit 640 trait (une boucle for de 0 à 639)
Voilà
Mon code provient principalement d’un vieux article de 2 pages dans (Amiga) Dream qui donnait les bases théoriques d’un tel moteur.
Je mettrais bien ici mon code (SDL Basic) mais il est relativement long et il est codé salement à l’arrache ! Il mériterait d’être bien amélioré ^^.
Je vais essayer de le poster dans la journée.
Abonnez-vous à ma nouvelle chronique "En Route vers le Futur" sur Youtube !
Kikou Screetch,
T’as réussi à modifier ton prg? il fonctionne?
A+
15 sujets de 1 à 15 (sur un total de 28)
- 1
- 2
- Vous devez être connecté pour répondre à ce sujet.
› Forums › AmigaOS, MorphOS et AROS › Développement › Moteur Raycasting