GFA
Vous souhaitez réagir à ce message ? Créez un compte en quelques clics ou connectez-vous pour continuer.
-40%
Le deal à ne pas rater :
Tefal Ingenio Emotion – Batterie de cuisine 10 pièces (induction, ...
59.99 € 99.99 €
Voir le deal

Champ d'étoiles vertical [FR] / [ENG]

4 participants

Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Champ d'étoiles vertical [FR] / [ENG]

Message par tomchi Mar 22 Sep - 14:11

Tuto : [Vous devez être inscrit et connecté pour voir ce lien] / [Vous devez être inscrit et connecté pour voir ce lien]



Hello, ya encore du monde ici ?
Pfiou, ça fait des années que je n'étais pas venu !
Bon, bref, sur le groupe Facebook de Lonny , un gars voulait faire un scrolling d'étoiles, j'ai fait un petit truc, du coup pourquoi ne pas le partager ici.... ( les comms sont en anglais, c'est plutôt facile mais bon, si ya des questions n'hésitez pas )
Code:

RESERVE 10000
'
@inits

REPEAT
  VSYNC
  CARD{&HFFFF8240}=0                           ! black backgroud
  ' clear oldstars
  starz.pointer&=0
  FOR i&=0 TO maxstar&-1
    xadr&=CARD{ADD(old.starz%,starz.pointer&)}
    yadr&=CARD{ADD(old.starz%,starz.pointer&+4)}
    adr&=ADD(xadr&,yadr&)
    CARD{ADD(log%,adr&)}=0                      ! clear previous starz
    ADD starz.pointer&,8
  NEXT i&
  '
  ' calc new coords and display star
  starz.pointer&=0
  FOR i&=0 TO maxstar&-1
    yadr&=CARD{ADD(mid.starz%,starz.pointer&+4)}
    yspeed&=CARD{ADD(mid.starz%,starz.pointer&+6)}
    newy%=ADD(yadr&,yspeed&)
    IF newy%>31999                              ! outside screen
      x&=RAND(319)                              ! new random star
      xadr&=SHL&(SHR&(x&,4),3)                  ! address
      xofst&=x& AND 15                          ! offset
      ADD xofst&,xofst&                         ! word
      CARD{starz%+starz.pointer&}=xadr&
      CARD{starz%+starz.pointer&+2}=xofst&
      CARD{starz%+starz.pointer&+4}=0                   ! new y adr=0
      CARD{starz%+starz.pointer&+6}=(RAND(8)+1)*160     ! new y speed
      '
      CARD{ADD(log%,xadr&)}=CARD{ADD(pxlz%,xofst&)} OR CARD{ADD(log%,xadr&)}      ! display new star
      ADD starz.pointer&,8
    ELSE
      xadr&=CARD{ADD(mid.starz%,starz.pointer&)}
      xofst&=CARD{ADD(mid.starz%,starz.pointer&+2)}
      '
      CARD{ADD(starz%,starz.pointer&)}=xadr&
      CARD{ADD(starz%,starz.pointer&+2)}=xofst&
      CARD{ADD(starz%,starz.pointer&+4)}=newy%
      CARD{ADD(starz%,starz.pointer&+6)}=yspeed&
      '
      adr&=ADD(xadr&,newy%)
      CARD{ADD(log%,adr&)}=CARD{ADD(pxlz%,xofst&)} OR CARD{ADD(log%,adr&)}  ! display new star
      ADD starz.pointer&,8
    ENDIF
  NEXT i&
  tuch&=BYTE{&HFFFFFC02}
  IF tuch&=&H38                                  ! Alt pressed
    CARD{&HFFFF8240}=&HF                         ! show CPU left
  ENDIF
  SWAP mid.starz%,old.starz%
  SWAP starz%,mid.starz%
  SWAP phy%,log%
  BYTE{&HFFFF8201}=SHR(phy%,16)
  BYTE{&HFFFF8203}=SHR(phy%,8)
  '
UNTIL tuch&=&H39                              ! Spacebar pressed
'
@fin
'
PROCEDURE inits
  super%=GEMDOS(32,L:0)                       ! supervisor mode
  '
  HIDEM
  OUT 4,8                                     ! no mouse
  rez|=XBIOS(4)
  xb2%=XBIOS(2)
  '
  scrbuf%=MALLOC(64000+256)
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)
  log%=ADD(phy%,32000)
  RC_COPY phy%,0,0,320,400 TO phy%,0,0,0       ! clears both phy% and log% buffers
  pxlz%=MALLOC(32+32)                          ! 16 words for pre decaled stars + 16 words palette
  palette%=pxlz%+32
  BMOVE &HFFFF8240,palette%,32                 ! saves oldpal
  BYTE{&HFFFF8260}=0                           ! low REZ
  ~XBIOS(5,L:log%,L:phy%,-1)                   ! set screens
  VSYNC
  SETCOLOR 1,&H777
  maxstar&=100
  starzbuf%=MALLOC(maxstar&*8*3)               ! (1 word X / 1 word offset / 1 word Y / 1 word speed)*3 buffers
  mid.pointer&=maxstar&*8
  old.pointer&=maxstar&*8*2
  FOR i|=0 TO maxstar&-1
    ' s&(i|,1)=RND(1)*319
    x&=RAND(319)
    xadr&=SHL&(SHR&(x&,4),3)                   ! address
    xofst&=x& AND 15                           ! offset
    ADD xofst&,xofst&                          ! word
    CARD{starzbuf%+mid.pointer&}=xadr&
    CARD{starzbuf%+mid.pointer&+2}=xofst&
    CARD{starzbuf%+mid.pointer&+4}=RAND(199)*160      ! y adr
    CARD{starzbuf%+mid.pointer&+6}=(RAND(8)+1)*160    ! y speed
    '
    CARD{starzbuf%+old.pointer&}=0
    CARD{starzbuf%+old.pointer&+2}=0
    CARD{starzbuf%+old.pointer&+4}=0
    CARD{starzbuf%+old.pointer&+6}=0
    ADD mid.pointer&,8
    ADD old.pointer&,8
  NEXT i|
  ' BMOVE ecran2%,bg%,32000
  starz%=starzbuf%
  mid.starz%=ADD(starzbuf%,maxstar&*8)
  old.starz%=ADD(starzbuf%,maxstar&*8*2)
  mystar%=&X1000000000000000
  CARD{pxlz%}=mystar%                           ! x=0
  FOR i&=2 TO 30 STEP 2
    mystar%=SHR(mystar%,1)                      ! 1 pixel shift to the right
    CARD{ADD(pxlz%,i&)}=mystar%
  NEXT i&
RETURN
'
PROCEDURE fin
  SHOWM
  OUT 4,12                                      ! mouse alive
  ~MFREE(scrbuf%)
  ~MFREE(starzbuf%)
  BMOVE palette%,&HFFFF8240,32                  ! restore old palette
  ~XBIOS(5,L:xb2%,L:xb2%,rez|)
  ~GEMDOS(32,L:super%)                          ! user mode
  EDIT
RETURN


Dernière édition par tomchi le Sam 21 Nov - 9:35, édité 1 fois
tomchi
tomchi

Messages : 52
Date d'inscription : 15/09/2018
Age : 49

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par ManuM Ven 25 Sep - 1:14

Merci Tomchi Smile ,
Le forum a besoin de se réveiller, si tu as encore d'autres bouts de code n'hésites pas Smile

ManuM

Messages : 171
Date d'inscription : 01/01/2018
Localisation : Loir et Cher

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par Shaoth Lun 28 Sep - 19:52

Salut les gars !
C'est moi le gars sur le groupe Facebook de Lonny qui voulait mettre en place un scrolling d'étoiles.
Merci pour ta solution Tomchi, elle est élégante Wink
Shaoth
Shaoth

Messages : 64
Date d'inscription : 28/09/2020
Age : 54
Localisation : Courbevoie

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par tomchi Lun 28 Sep - 20:49

Cool !
On est en train de faire quelques tests avec Thomas (randomizer) et sur des bouts de code, finalement CARD n'est pas vriament ( du tout) plus rapide que d'utiliser un talbleau donc, même plus élégant le code pourrait afficher pas mal d'étoiles Smile
tomchi
tomchi

Messages : 52
Date d'inscription : 15/09/2018
Age : 49

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par Shaoth Lun 28 Sep - 21:44

Je suis très curieux de voir ça.
J'avais tenté d'utiliser un tableau pour stocker les coordonnées des étoiles mais ce n'était pas du tout convainquant...
Shaoth
Shaoth

Messages : 64
Date d'inscription : 28/09/2020
Age : 54
Localisation : Courbevoie

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par ManuM Lun 28 Sep - 23:00

Very Happy le forum est en vie ! merci pour ce starfield

ManuM

Messages : 171
Date d'inscription : 01/01/2018
Localisation : Loir et Cher

Jb aime ce message

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par Shaoth Mar 29 Sep - 8:01

un scrolling d'étoiles c'est basique...
je fais ça les doigts dans le nez dans n'importe quel langage moderne.
moderne au sens d'utiliser aujourd'hui pour les jeux.
Mais ramené 30 ans en arrière c'est moins simple.
il faut bien mieux connaitre la machine et ne plus compter sur la puissance brute des ordinateurs actuels, ce que j'ai encore trop tendance à faire, mais j'évolue ! (ou je régresse, ça dépend de comment on le prend Very Happy )
Shaoth
Shaoth

Messages : 64
Date d'inscription : 28/09/2020
Age : 54
Localisation : Courbevoie

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par tomchi Mar 29 Sep - 17:19

Jamais touché un "langage moderne" ici , du coup on doit être complémentaire, faudra m'aider Smile
Bon, ptit teaser juste pour moi : il manque vraiment pas grand chose pour arriver à 150 étoiles, aller aller aller !! Razz
tomchi
tomchi

Messages : 52
Date d'inscription : 15/09/2018
Age : 49

Jb aime ce message

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par Shadow272 Dim 4 Oct - 7:33

Merci Tomchi de prendre la relève.
Je suis un peu ko depuis un an du à de graves ennuis de santé, déjà 4 opérations et il y en a encore une prévue ce 8 octobre.
J'espère pouvoir m'y remettre plus sereinement après.
Shadow272
Shadow272
Admin

Messages : 328
Date d'inscription : 28/12/2017
Age : 65
Localisation : Hainaut Belgique

http://toutatari.blog4ever.xyz/

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par tomchi Dim 4 Oct - 21:37

Hello Georges !!
Ça fait plaisir de te lire, merci  Smile
Bon courage et prompt rétablissement !
( ton absence de post depuis pas mal de temps m'a inquiété quand je suis revenu faire un tour sur le forum, mais je n'ai pas osé demander de tes nouvelles, desolé Sad )
tomchi
tomchi

Messages : 52
Date d'inscription : 15/09/2018
Age : 49

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par tomchi Sam 21 Nov - 9:33

Le peu de connaissances que j'ai en programmation concerne le GFA Basic et vient de la

lecture des articles lus dans le magasine ST Mag. Ce qui suit est facile et basique, toute

contribution (utile) est la bienvenue.

Ok, c'est parti pour un petit Starfield !

Le but : Un programme facilement lisible et modifiable qui doit tourner à 50 fps compilé.
        Des étoiles en déplacement vertical ayant des vitesses différentes.
        Chaque étoile sortant de l'écran sera remplacée par une nouvelle générée

aléatoirement.

Le principe va être d'effacer les étoiles affichées précédemment puis de calculer leurs

nouvelles ordonnées en ajoutant la vitesse à y pour enfin les afficher.
En pseudo code ça donne:
Code:

REPEAT
  VSYNC                        ! rafraichissement ecran
  FOR star&=1 TO maxstar&
    erase(star&)               ! a coder
  NEXT star&
'
  FOR star&=1 TO maxstar&
    ADD y.star&,yspeed&        ! a
    display(star&)             ! coder
  NEXT star&
UNTIL space_pressed


On voit donc qu'il faut stocker les coordonnées de chaque étoile pour l'effacer à son  

ancienne position avant de l'afficher à la nouvelle position.
On se rend compte que du coup il faudra définir la position initiale de chaque étoile

avant que la boucle principale ne tourne.
La manière la plus évidente/simple en GFA de gérer ça sera d'utiliser un tableau : nous

definiront la constante maxstar& qui stockera le nombre d'étoiles que nous déplaceront.
D'après le pseudo code il nous faut un tableau à deux dimensions pour stocker les

coordonnées et la vitesse de chaque étoile.
Code:

maxstar&=50
DIM star&(maxstar&,2)
On stockera donc :
star&(blah&,0)=x&
star&(blah&,1)=y&
star&(blah&,2)=speed&
Où blah& est le numéro de l'étoile dont nous nous occupons.

Remarquez le "&" : il indique au GFA que nous voulons travailler avec des mots/word (-

32768;...;32767). Premièrement parce que nos valeurs (x& par exemple) pourront être plus

grandes que ce qu'un octet/byte ne peut contenir ("|"), deuxièmement parce que le ST

travaille plus vite ( à fortiori en GFA ) avec des mots qu'avec des longs mots ("%") ou

pire des nombres à virgule.

Nous y reviendront mais utiliser ce tableau à deux dimensions bien qu'étant suffisant pour

afficher quelques points, se révèle peu performant. ( En tout cas il y a une autre façon

facile de faire beaucoup plus efficace.)

Pour l'affichage / effaçage des points nous n'utiliserons *pas* PLOT, simplement parce que

nous voulons un résultat propre, rapide et fluide.

Il nous faut avoir au moins une idée rudimentaire de l'organisation des graphismes sur le

ST.
On va travailler en basse résolution cad 320*200 pixels avec 16 couleurs.
Les graphismes sont sockés par bloc de 16 pixels sur 8 octets : 320 pixels sont donc

stockés dans 160 octets , * 200 lignes = 32000 octets pour la taille d'un écran donc.
Pour obtenir les 16 couleurs, les pixels sont codés en 4 plans, on a donc chaque mot qui

stocke les 16 pixels pour chaque plan.
Code:

--------------------------------------------------------
!  n°     !   bin     ! plan 1 ! plan 2 ! plan 3 ! plan 4 !
!   00   !  0000   !  non   !  non   |  non   !  non   !
!   01   !  0001   !  oui   !  non   !  non   !  non   !
!   02   !  0010   !  non   !  oui   !  non   !  non   !
!   03   !  0011   !  oui   !  oui   !  non   !  non   !
!   04   !  0100   !  non   !  non   !  oui   !  non   !
!   05   !  0101   !  oui   !  non   !  oui   !  non   !
!   06   !  0110   !  non   !  oui   !  oui   !  non   !
!   07   !  0111   !  oui   !  oui   !  oui   !  non   !
!   08   !  1000   !  non   !  non   !  non   !  oui   !
!   09   !  1001   !  oui   !  non   !  non   !  oui   !
!   10   !  1010   !  non   !  oui   !  non   !  oui   !
!   11   !  1011   !  oui   !  oui   !  non   !  oui   !
!   12   !  1100   !  non   !  non   !  oui   !  oui   !
!   13   !  1101   !  oui   !  non   !  oui   !  oui   !
!   14   !  1110   !  non   !  oui   !  oui   !  oui   !
!   15   !  1111   !  oui   !  oui   !  oui   !  oui   !
--------------------------------------------------------


on comprend que la couleur 0 n'utilise aucun plan, la couleur 1 utilise le plan 1, la

couleur 2 le plan 2, la couleur 3 les plans 1 et 2, etc ...

Disons qu'on veut afficher le 3ème pixel en partant de la gauche avec la couleur 13 il

nous faudra écrire :
&X0010000000000000 à address%
&X0000000000000000 à address%+2 ( 2nd mot )
&X0010000000000000 à address%+4 ( 3ème mot )
&X0010000000000000 à address%+6 ( 4ème mot )

"&X" indique au GFA que nous lui fournissons des valeurs binaires, pour des valeurs

héxadécimales on indiquera "&H" )

Pour afficher les étoiles avec la couleur 1 nous n'aurons qu'à écrire un seul mot dans la

mémoire écran. Comme il est fort probable que plusieurs étoiles se trouvent sur le même

bloc de 16 pixels nous utiliseront l'opérande OR pour "plotter" chaque étoile afin de ne

pas en effacer une qu'on aurait déjà affichée sur le même mot.

Pour gagner du temps machine on va précalculer les 16 positions d'un pixel dans un autre

tableau.
Code:

  DIM pxlz&(15)
  pxlz&(0)=-32768                                 !&X1000000000000000=&H8000=-32768
  mystar&=&X0100000000000000
  pxlz&(1)=mystar&
  FOR i&=2 TO 15                                 !
    mystar&=SHR(mystar&,1)                       ! decalage d'un pixel sur la droite
    pxlz&(i&)=mystar&
  NEXT i&

Pour écrire ces mots à l'écran on utilisera la commande CARD:
Code:

CARD{screen_address%}=pxlz&(blah&) OR CARD{screen_address%}

Effacer sera encore plus simple, il suffira d'écrire 0 .

On gagnera du temps machine si au lieu de travailler avec des coordonnées on utilise

directement les adresses.
Convertir x en adresse : x.address&=SHL(SHR(x&,4),3)
=> Encore un tableau pour stocker ces adresses:

Code:

  DIM xadr.ar&(320)
  for i&=0 to 319
  xadr.ar&(i&)=SHL(SHR(i&,4),3)
  next i&
x offset                    : xofst&=x& AND 15
Convertir y en addresse     : y.address&=y&*160
Vitesse en addresse         : y.speed&=speed&*160

On aura donc:
Code:

CARD{screen_address%+x.address&+y.address&}=pxlz&(xofst&) OR CARD{screen_address%

+x.address&+y.address&}


Si on écrit à l'écran pendant que le ST rafraichit ce dernier on aura des bugs

d'affichage, pour eviter cela nous allons recourir à l'éternelle technique du double

buffer:
Pendant que le ST affiche l'écran (ecran physique), nous ecrirons dans un second buffer

identique en taille=32000 octets (écran logique), ensuite nouos mettrons à jour l'adresse

vidéo après avoir SWAPpé (=échangé) les adresses écran logique et physique et utiliserons

VSYNC pour attendre la fin du balayage et passage à la prochaine VBL.
Code:

  scrbuf%=MALLOC(64000+256)                   ! Alloue la memoire pour 2 ecrans
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)       ! adresse ecran physique
  log%=ADD(phy%,32000)                        ! adresse ecran logique


Sur STf l'adresse écran doit se situer sur une adresse multiple de 256 ce qui explique le

+256 sur la taille mémoire allouée et le fait que l'on mette l'octet de phy% à zéro (

AND&HFFFFFF00).

Notre routine, avant d'afficher les nouvelles étoiles doit les effacer, mais il faut

maintenant prendre en compte le double buffering .
En effet, il nous faudra connaitre la position de chaque étoile que nous voudrons effacer

non pas une mais deux VBL plus tôt :
1ère VBL: affiche buffer 1, on écrit dans le buffer 2 l'étoile est à y.
2ème VBL: affiche buffer 2, on écrit dans le buffer 1 l'étoile est à y+yspeed
3ème VBL: affiche buffer 1, on écrit dans le buffer 2, l'étoile est à y+yspeed+yspeed

Comme la routine peut avoir créé une nouvelle étoile dans le cas où la précédente serait

sortie de l'écran nous ne pouvons pas nous contenter de soustraire 2*yspeed, au lieu de

cela nous utiliserons (encore) 3 tableaux et utiliseront SWAP pour les intervertir, comme

pour les adresses écran.
Code:

DIM current.star&(maxstar&,3)
DIM middle.star&(maxstar&,3)
DIM old.star&(maxstar&,3)

Assez de blabla basico théorique, passons au code complet.
Quelques mots à propose de PROCEDURE inits:
Le programme avant de tourner vous demandera combien d'étoiles vous souhaitez qu'il

affiche, le maximum en 1 VBL (programme compilé) est d'environ 75.
On utilisera le mode superviseur afin d'écrire directement dans certains registres mémoire

du ST.
Le buffer alloué avec MALLOC sera effacé (rempli de 0), evitant que quelque donnée

résidant en mémoire ne se situe dans ledit bloc et vienne parasiter nos données.
Le pus facile/rapide en GFA est d'utiliser RC_COPY.

Certains pourront remarquer qu'il n'y a pas d'appel à la fonction XBIOS(5) (qui sert à

mettre en place les adresses écran logique et physique) dans la boucle principale mais

écriture dans les registres mémoire correspondants.
Il n'est pas du tout indispensable de procéder de cette façon mais comme mes programmes

sont principalement destinés au STE, j'ai pris l'habitude de coder de cette manière.

Appuyer sur Alternate pendant que le programme tourne changera la couleur de fond en bleu,

la partie de l'écran en bleu représentant le temps machine encore disponible avant la fin

de la VBL.
 
Code:

RESERVE 10000
'
@inits

REPEAT
  VSYNC
  CARD{&HFFFF8240}=0                              ! fond noir
  ' clear oldstars
  FOR i&=0 TO maxstar&
    xadr&=old.star&(i&,0)
    yadr&=old.star&(i&,2)
    CARD{ADD(log%,ADD(xadr&,yadr&))}=0            ! efface les anciennes etoiles
  NEXT i&
  '
  ' calc new coords and display star
  FOR i&=0 TO maxstar&
    yadr&=middle.star&(i&,2)
    yspeed&=middle.star&(i&,3)
    newy%=ADD(yadr&,yspeed&)
    IF newy%>31999                                ! hors de l'ecran
      x&=RAND(319)                                ! nouvelle etoile randomisee
      xadr&=xadr.ar&(x&)
      xofst&=x& AND 15                            ! offset
      current.star&(i&,0)=xadr&
      current.star&(i&,1)=xofst&
      current.star&(i&,2)=0                       ! y nouvelle etoile = 0
      current.star&(i&,3)=(RAND(8)+1)*160         ! y speed
      '
      dest%=ADD(log%,xadr&)                       ! y=0 donc address=x address
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
    ELSE
      xadr&=middle.star&(i&,0)
      xofst&=middle.star&(i&,1)
      '
      current.star&(i&,0)=xadr&
      current.star&(i&,1)=xofst&
      current.star&(i&,2)=newy%
      current.star&(i&,3)=yspeed&
      '
      dest%=ADD(log%,ADD(xadr&,newy%))
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
    ENDIF
  NEXT i&
  tuch&=BYTE{&HFFFFFC02}
  IF tuch&=&H38                                   ! appui sur Alt
    CARD{&HFFFF8240}=&HF                          ! CPU restant
  ENDIF
  SWAP middle.star&(),old.star&()                 ! swap stars data arrays old=middle
  SWAP current.star&(),middle.star&()             !                        middle=current
  SWAP phy%,log%
  BYTE{&HFFFF8201}=SHR(phy%,16)
  BYTE{&HFFFF8203}=SHR(phy%,8)
  '
UNTIL tuch&=&H39                                  ! Spacebar pressed
'
@fin
'
PROCEDURE inits
  CLS
  INPUT "Max Stars",maxstar&                      ! combien d'etoiles ? screen
  DIM pxlz&(15)                                   ! tableau des 16 positions d'un pixel
  DIM xadr.ar&(320)                               ! tableau conversion X en adresse
  DIM current.star&(maxstar&,3)                   ! tableau stockant X adresse/ X ofset/ Y

adresse / Y speed pour chaque etoile
  DIM middle.star&(maxstar&,3)                    ! meme chose
  DIM old.star&(maxstar&,3)                       ! idem <= on swappera ces 3 tableaux

pour avoir les anciennes positions des etoiles
  scrbuf%=MALLOC(64000+256+32)                    ! 1 buffer pour les 2 ecrans +

sauvegarde de la palette
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)           ! phy% sur un octet nul
  log%=ADD(phy%,32000)                            ! log% 32000 octets plus loin
  palette%=ADD(starzbuf%,64000)                   ! palette% apres log%
  super%=GEMDOS(32,L:0)                           ! supervisor mode
  '
 HIDEM
  BYTE{&HFFFFFC02}=&H12                           ! no mouse
  rez|=XBIOS(4)                                   ! resolution sauvee
  xb2%=XBIOS(2)                                   ! adresse ecran sauvee
  '
  for i&=0 to 319
  xadr.ar&(i&)=SHL(SHR(i&,4),3)                   ! conversion X en adresse
  next i&
  BMOVE &HFFFF8240,palette%,32                    ! ancienne palette sauvee
  BYTE{&HFFFF8260}=0                              ! basse resolution
  VSYNC
  ~XBIOS(5,L:log%,L:phy%,-1)                      ! met en place les ecrans
  VSYNC
  RC_COPY phy%,0,0,320,400 TO phy%,0,0,0          ! effaceles buffers phy% et log%
  VSYNC
  SETCOLOR 1,&H777                                ! etoiles blanches, oh my god !
  FOR i&=0 TO maxstar&
    x&=RAND(319)
    xadr&=SHL(SHR(x&,4),3)                        ! adresse
    xofst&=x& AND 15                              ! offset
    middle.star&(i&,0)=xadr&
    middle.star&(i&,1)=xofst&
    middle.star&(i&,2)=RAND(199)*160              ! y adr
    middle.star&(i&,3)=(RAND(8)+1)*160            ! y speed
    '
    old.star&(i&,0)=0
    old.star&(i&,1)=0
    old.star&(i&,2)=0
    old.star&(i&,3)=0
  NEXT i&
  pxlz&(0)=-32768                                 ! -32768=&H8000=&X1000000000000000
  mystar&=&X0100000000000000
  pxlz&(1)=mystar&
  FOR i&=2 TO 15                              
    mystar&=SHR(mystar&,1)                        ! 1 pixel decale a droite
    pxlz&(i&)=mystar&
  NEXT i&
RETURN
'
PROCEDURE fin
  SHOWM
  BYTE{&HFFFFFC02}=&H8                            ! rend la souris ! mouse alive
  ~MFREE(scrbuf%)
  BMOVE palette%,&HFFFF8240,32                    ! remet ancienne palette
  ~XBIOS(5,L:xb2%,L:xb2%,rez|)
  ~GEMDOS(32,L:super%)                            ! user mode
  EDIT
RETURN

J'ai écrit cet article après des échanges constructifs avec Thomas, l'auteur de plusieurs

jeux en GFA (anarcho ride / frogs / randomazer ...).
Ma première routine utilisait CARD pour lire/écrire dans les buffers au lieu d'utiliser

les tableaux.
On a pas mal discuté sur la rapidité en temps machine de ces tableaux et Thomas a proposé

une routine plus rapide que celle que j'avais écrite en utilisant des tableaux à une

dimension. Après tests il s'avère que les tableaux à deux dimensions prenaient énormément

plus de temps que d'utiliser plusieurs tableaux simples. Bien que cela lui convienne

parfaitement, j'avaonçais que ça faisait trop de tableaux/variables à gérer pour moi. Il

faut un tableau pour x adr, x ofst, y, yspeed et tout cela multiplié par 3 (

current/mid/old).

L'intégriste du CARD que je suis se mit en tête d'optimiser la routine originale tirant

parti de chaque technique. Le code qui suit affichera 150 étoiles chaque VBL.
Le but étant d'éviter les calculs (additions) au maximum.

Au lieu d'utiliser plusieurs tableaux, les données seront stockées dans un unique buffer:
Code:

  INPUT "Max Stars",maxstar&
  DIM pxlz&(15)
  DIM xadr.ar&(320)
  scrbuf%=MALLOC(64000+256+maxstar&*8*3+32)
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)
  log%=ADD(phy%,32000)
  starzbuf%=ADD(log%,32000)             !MALLOC(maxstar&*8*3) (1 mot X / 1 mot offset / 1

mot Y / 1 mot speed)*3 buffers
  palette%=ADD(starzbuf%,maxstar&*8*3)  !MALLOC(32)

Un seul buffer donc, et des pointeurs pour chaque "buffer dans le buffer".
La quantité de mémoire nécessaire est alors maxstar&*8*3: on a besoin de stocker current /

mid / old positions des étoiles (=>*3) et un bloc de data pour une étoile fait 8 octets

(4*2).
Les pointeurs:
Code:

  starz%=starzbuf%
  mid.starz%=ADD(starzbuf%,maxstar&*8)
  old.starz%=ADD(starzbuf%,maxstar&*8*2)

dernier point, au lieu d'utiliser une boucle FOR/NEXT j'ai opté pour REPEAT/UNTIL,

définissant une variable qui pointe dans le buffer dans lequel je veux taper et lui

ajoutant 8 à chaque étoile jusqu'à ce qu'elle pointe à la fin du buffer.

Code:

RESERVE 10000
'
@inits

REPEAT
  VSYNC
  CARD{&HFFFF8240}=0                           ! black backgroud
  ' clear oldstars
  old.starz.pointer%=old.starz%
  old.starz.pointer.max%=ADD(old.starz%,maxstar.lg&)
  REPEAT
    xadr&=CARD{old.starz.pointer%}
    yadr&=CARD{ADD(old.starz.pointer%,4)}
    CARD{ADD(log%,ADD(xadr&,yadr&))}=0            ! clear previous starz
    ADD old.starz.pointer%,8
  UNTIL old.starz.pointer%=old.starz.pointer.max%
  '
  ' calc new coords and display star
  starz.pointer%=starz%
  starz.pointer.max%=ADD(starz%,maxstar.lg&)
  mid.starz.pointer%=mid.starz%
  REPEAT
    yadr&=CARD{ADD(mid.starz.pointer%,4)}
    yspeed&=CARD{ADD(mid.starz.pointer%,6)}
    newy%=ADD(yadr&,yspeed&)
    IF newy%>31999                              ! outside screen
      x&=RAND(319)                              ! new random star
      xadr&=xadr.ar&(x&)
      xofst&=x& AND 15                          ! offset
      CARD{starz.pointer%}=xadr&
      CARD{ADD(starz.pointer%,2)}=xofst&
      CARD{ADD(starz.pointer%,4)}=0
      CARD{ADD(starz.pointer%,6)}=MUL(ADD(RAND(8),1),160) !MUL(ADD(x& AND 7,1),160)  !

(RAND(8)+1)*160
      '
      dest%=ADD(log%,xadr&)
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
      ADD starz.pointer%,8
      ADD mid.starz.pointer%,8
    ELSE
      xadr&=CARD{mid.starz.pointer%}
      xofst&=CARD{ADD(mid.starz.pointer%,2)}
      '
      CARD{starz.pointer%}=xadr&
      CARD{ADD(starz.pointer%,2)}=xofst&
      CARD{ADD(starz.pointer%,4)}=newy%
      CARD{ADD(starz.pointer%,6)}=yspeed&
      '
      dest%=ADD(log%,ADD(xadr&,newy%))
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
      ADD starz.pointer%,8
      ADD mid.starz.pointer%,8
    ENDIF
  UNTIL starz.pointer%=starz.pointer.max%
  tuch&=BYTE{&HFFFFFC02}
  IF tuch&=&H38                                  ! Alt pressed
    CARD{&HFFFF8240}=&HF                         ! show CPU left
  ENDIF
  SWAP mid.starz%,old.starz%
  SWAP starz%,mid.starz%
  SWAP phy%,log%
  BYTE{&HFFFF8201}=SHR(phy%,16)
  BYTE{&HFFFF8203}=SHR(phy%,8)
  '
UNTIL tuch&=&H39                              ! Spacebar pressed
'
@fin
'
PROCEDURE inits
  CLS
  INPUT "Max Stars",maxstar&
  DIM pxlz&(15)
  DIM xadr.ar&(320)
  scrbuf%=MALLOC(64000+256+maxstar&*8*3+32)
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)
  log%=ADD(phy%,32000)
  starzbuf%=ADD(log%,32000)             !MALLOC(maxstar&*8*3)               ! (1 word X /

1 word offset / 1 word Y / 1 word speed)*3 buffers
  palette%=ADD(starzbuf%,maxstar&*8*3)       !MALLOC(32)
  super%=GEMDOS(32,L:0)                       ! supervisor mode
  '
 HIDEM
  BYTE{&HFFFFFC02}=&H12                        ! plus de souris ! no mouse
  rez|=XBIOS(4)
  xb2%=XBIOS(2)
  '
  for i&=0 to 319
  xadr.ar&(i&)=SHL(SHR(i&,4),3)
  next i&
  BMOVE &HFFFF8240,palette%,32                 ! saves oldpal
  BYTE{&HFFFF8260}=0                           ! low REZ
  VSYNC
  ~XBIOS(5,L:log%,L:phy%,-1)                   ! set screens
  VSYNC
  RC_COPY phy%,0,0,320,400 TO phy%,0,0,0       ! clears both phy% and log% buffers
  VSYNC
  SETCOLOR 1,&H777
  mid.pointer&=maxstar&*8
  old.pointer&=maxstar&*8*2
  FOR i|=0 TO maxstar&-1
    x&=RAND(319)
    xadr&=SHL(SHR(x&,4),3)                   ! address
    xofst&=x& AND 15                           ! offset
    CARD{starzbuf%+mid.pointer&}=xadr&
    CARD{starzbuf%+mid.pointer&+2}=xofst&
    CARD{starzbuf%+mid.pointer&+4}=RAND(199)*160      ! y adr
    CARD{starzbuf%+mid.pointer&+6}=(RAND(8)+1)*160    ! y speed
    '
    CARD{starzbuf%+old.pointer&}=0
    CARD{starzbuf%+old.pointer&+2}=0
    CARD{starzbuf%+old.pointer&+4}=0
    CARD{starzbuf%+old.pointer&+6}=0
    ADD mid.pointer&,8
    ADD old.pointer&,8
  NEXT i|
  maxstar.lg&=SHL(maxstar&-1,3)                  ! X8
  starz%=starzbuf%
  mid.starz%=ADD(starzbuf%,maxstar&*8)
  old.starz%=ADD(starzbuf%,maxstar&*8*2)
  pxlz&(0)=-32768                                 !&X1000000000000000
  mystar&=&X0100000000000000
  pxlz&(1)=mystar&
  FOR i&=2 TO 15                                !2 TO 30 STEP 2
    mystar&=SHR(mystar&,1)                      ! 1 pixel shift to the right
    pxlz&(i&)=mystar&
  NEXT i&
RETURN
'
PROCEDURE fin
  SHOWM
  BYTE{&HFFFFFC02}=&H8                         ! rend la souris ! mouse alive
  ~MFREE(scrbuf%)
  ~MFREE(starzbuf%)
  BMOVE palette%,&HFFFF8240,32                  ! restore old palette
  ~XBIOS(5,L:xb2%,L:xb2%,rez|)
  ~GEMDOS(32,L:super%)                          ! user mode
  EDIT
RETURN

tomchi
tomchi

Messages : 52
Date d'inscription : 15/09/2018
Age : 49

Shaoth aime ce message

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par tomchi Sam 21 Nov - 9:33

The very few programming I know is all about GFA Basic and comes from reading tutorials published in the french ST Mag magazine. Following is all easy and basic stuff, any contribution to improve this is welcome.

So, let's do some simple and easy vertical starfield then Smile .

What we want : Easily readable, modifiable code, also it *has* to run nicely at 50 fps (once compiled).
Multiple speed stars moving verticaly.
Each star getting outside screen will be replaced with a randomly plotted new one.

Basically, what we'll do is erase previous star then increase star y with its speed and PLOT it.
Pseudo code would look like :
Code:

REPEAT
  VSYNC                        ! Screen refresh
  FOR star&=1 TO maxstar&
    erase(star&)              ! to be coded
  NEXT star&
'
  FOR star&=1 TO maxstar&
    ADD y.star&,yspeed&        ! to be
    display(star&)            ! coded
  NEXT star&
UNTIL space_pressed

Now that means that we have to store coordinates of each star to erase where they were, then add speed and then plot them.
Also that shows us that we have to set them once before we start the main loop.
Most obvious way to handle them is to use an array : say we define maxstar& as a constant to set the numbers of stars we want to move.
Then we set a 2 dimensions array to store coords + speed of each star:
Code:

maxstar&=50
DIM star&(maxstar&,2)
That way we could store everything :
star&(blah&,0)=x&
star&(blah&,1)=y&
star&(blah&,2)=speed&
Where blah& is the current star we're computing.

Notice the "&" : this tells GFA Basic we want to deal with words (-32768;..;32767). Why ? First because our values will be higher than what a byte ("|") can carry, and also because the ST will work faster with words than with longwords ("%") or floats.

We'll come on that later but this 2 dimensions array will prove to be far from being fast ( at least there's some other easy stuff being way faster ) tho enough for a few stars.

Now how will we erase/display them ? We're *not* going to use PLOT, because we want the starfield to be fast and fluid.

One has to know ( at least a bit ) how graphics are stored in memory in a ST.
We'll work in ST Low resolution, that means 320*200 pixels / 16 colors.
Graphics are stored 16 pixels at a time into 8 bytes : 320 pixels are then stored in 160 bytes * 200 lines = 32000 bytes (size of screen).
Also, to use the 16 colors, pixels are coded into 4 bitplanes, that way each word in memory stores the pixels for each plane.

--------------------------------------------------------
! numb ! bin ! plane1 ! plane2 ! plane3 ! plane4 !
! 00 ! 0000 ! no ! no | no ! no !
! 01 ! 0001 ! yes ! no ! no ! no !
! 02 ! 0010 ! no ! yes ! no ! no !
! 03 ! 0011 ! yes ! yes ! no ! no !
! 04 ! 0100 ! no ! no ! yes ! no !
! 05 ! 0101 ! yes ! no ! yes ! no !
! 06 ! 0110 ! no ! yes ! yes ! no !
! 07 ! 0111 ! yes ! yes ! yes ! no !
! 08 ! 1000 ! no ! no ! no ! yes !
! 09 ! 1001 ! yes ! no ! no ! yes !
! 10 ! 1010 ! no ! yes ! no ! yes !
! 11 ! 1011 ! yes ! yes ! no ! yes !
! 12 ! 1100 ! no ! no ! yes ! yes !
! 13 ! 1101 ! yes ! no ! yes ! yes !
! 14 ! 1110 ! no ! yes ! yes ! yes !
! 15 ! 1111 ! yes ! yes ! yes ! yes !
--------------------------------------------------------
Now you see color 0 uses no plane, color 1 uses plane 1, color 2 uses plane 2, color 3 uses plane 1 and plane 2 , etc .

So if you want to put third pixel from the left with color 13 you have to write :
&X0010000000000000 into address%
&X0000000000000000 into address%+2 ( second word )
&X0010000000000000 into address%+4 ( third word )
&X0010000000000000 into address%+6 ( fourth word )

( "&X" tells GFA you're setting binary values, for hexadecimal values use "&H" )

If we want to use color 1 to plot the stars, we'll only write a single word to screen memory. As it may happen that many stars have to be plotted within the same 16 pixels bloc, we'll be ORing our pixel with the word we want to write on screen so that we don't erase previously plotted star,

The 16 positions of a pixel within a word will be stored into another array.
Code:

  DIM pxlz&(15)
  pxlz&(0)=-32768                                !&X1000000000000000=&H8000=-32768
  mystar&=&X0100000000000000
  pxlz&(1)=mystar&
  FOR i&=2 TO 15                                !
    mystar&=SHR(mystar&,1)                      ! 1 pixel shift to the right
    pxlz&(i&)=mystar&
  NEXT i&
we'll use the CARD command to write our word on screen.
Code:

CARD{screen_address%}=pxlz&(blah&) OR CARD{screen_address%}

Erasing the star will be easy too, just write 0 for each previous star position.

To avoid having to convert x and y for each star each VBL, we won't just store coordinates in the array, instead we'll work with addresses.
Convert x to an address : x.address&=SHL(SHR(x&,4),3) that will put it on an 8 bytes boundary (=16 pixels boundary)
=> Let's use another array to store these addresses:
Code:

  DIM xadr.ar&(320)
  for i&=0 to 319
  xadr.ar&(i&)=SHL(SHR(i&,4),3)
  next i&
Get x offset : xofst&=x& AND 15
Convert y to an address : y.address&=y&*160
Set speed as a line address : y.speed&=speed&*160

That way we get to:
Code:

CARD{screen_address%+x.address&+y.address&}=pxlz&(xofst&) OR CARD{screen_address%+x.address&+y.address&}




Plotting stars to screen memory will result into flickering as the ST will refresh screen as we write to it, to avoid that we'll use double buffering:
While ST is displaying screen (physical screen), we'll write to another buffer that has the same size=32000 bytes (logical screen) , then we'll set video base address after SWAPping physical and logical screen address, then VSYNC will wait till the whole screen display is done.
Code:

  scrbuf%=MALLOC(64000+256)                  ! Allocate memory for 2 screens
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)      ! Sets physical screen address
  log%=ADD(phy%,32000)                        ! sets logical screen address


On ST screen address has to be on a 256 bytes boundary hence the +256 memory allocation and phy% having low byte zeroed (AND &HFFFFFF00).

Remember that our routine has to erase previous stars before plotting new ones, with double screen buffer that brings us to another simple trick to do.
Indeed, this means we have to know where the star we want to erase was, not one but two VBLs before.
Because getting back to the same buffer will take 2 VBLs.
1st VBL: display buffer 1, write to buffer 2 star is at y
2nd VBL: display buffer 2, write to buffer 1 star is at y+yspeed
3rd VBL: display buffer 1, write to buffer 2 star is at y+yspeed+yspeed

Of course, we could have set a new star in case it got out of screen, so we can't just SUB 2*yspeed, instead we'll use 3 arrays and SWAP them as we SWAP screen buffers.
Code:

DIM current.star&(maxstar&,3)
DIM middle.star&(maxstar&,3)
DIM old.star&(maxstar&,3)

Right, we now have enough theory to start coding the routine.
A few words about PROCEDURE inits
You'll be asked how many stars you want to display, max in 1 VBL is approx 75.
We'll get into supervisor mode to write to some memory registers, saving resolution / screens addresses / palette etc to restore them once the user quits the prg.
The buffer MALLOCed for screens is cleared (filled with zeros ), you never know if some data was already in this location before your prg is launched.
Easiest way is to use RC_COPY.

Also, one will notice there's no call to XBIOS(5) (which sets the screen addresses) in the main loop, instead it also writes to memory registers, not that this has to be done that way, ususally using STE features , I just got used to code like that.

Pressing Alternate while running will change background color to blue, blue part of screen being CPU time left before end of VBL.



Code:

RESERVE 10000
'
@inits

REPEAT
  VSYNC
  CARD{&HFFFF8240}=0                              ! black backgroud
  ' clear oldstars
  FOR i&=0 TO maxstar&
    xadr&=old.star&(i&,0)
    yadr&=old.star&(i&,2)
    CARD{ADD(log%,ADD(xadr&,yadr&))}=0            ! clear previous starz
  NEXT i&
  '
  ' calc new coords and display star
  FOR i&=0 TO maxstar&
    yadr&=middle.star&(i&,2)
    yspeed&=middle.star&(i&,3)
    newy%=ADD(yadr&,yspeed&)
    IF newy%>31999                                ! outside screen
      x&=RAND(319)                                ! new random star
      xadr&=xadr.ar&(x&)
      xofst&=x& AND 15                            ! offset
      current.star&(i&,0)=xadr&
      current.star&(i&,1)=xofst&
      current.star&(i&,2)=0                      ! y new star = 0
      current.star&(i&,3)=(RAND(8)+1)*160        ! y speed
      '
      dest%=ADD(log%,xadr&)                      ! y=0 so address=x address
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
    ELSE
      xadr&=middle.star&(i&,0)
      xofst&=middle.star&(i&,1)
      '
      current.star&(i&,0)=xadr&
      current.star&(i&,1)=xofst&
      current.star&(i&,2)=newy%
      current.star&(i&,3)=yspeed&
      '
      dest%=ADD(log%,ADD(xadr&,newy%))
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
    ENDIF
  NEXT i&
  tuch&=BYTE{&HFFFFFC02}
  IF tuch&=&H38                                  ! Alt pressed
    CARD{&HFFFF8240}=&HF                          ! show CPU left
  ENDIF
  SWAP middle.star&(),old.star&()                ! swap stars data arrays old=middle
  SWAP current.star&(),middle.star&()            !                        middle=current
  SWAP phy%,log%
  BYTE{&HFFFF8201}=SHR(phy%,16)
  BYTE{&HFFFF8203}=SHR(phy%,8)
  '
UNTIL tuch&=&H39                                  ! Spacebar pressed
'
@fin
'
PROCEDURE inits
  CLS
  INPUT "Max Stars",maxstar&                      ! asks for how many stars you want on screen
  DIM pxlz&(15)                                  ! array storing 16 shifted pixels
  DIM xadr.ar&(320)                              ! array storing X addresses
  DIM current.star&(maxstar&,3)                  ! array storing X address / X ofset / Y address / Y speed for each star
  DIM middle.star&(maxstar&,3)                    ! same as above
  DIM old.star&(maxstar&,3)                      ! idem <= we'll swap these 3 to get stars old address

  scrbuf%=MALLOC(64000+256+32)                    ! 1 buffer for both 2 screens + palette save
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)          ! phy% on a byte boundary
  log%=ADD(phy%,32000)                            ! log% 32000 bytes further
  palette%=ADD(starzbuf%,64000)                  ! palette% after log%
  super%=GEMDOS(32,L:0)                          ! supervisor mode
  '
 HIDEM
  BYTE{&HFFFFFC02}=&H12                          ! no mouse
  rez|=XBIOS(4)                                  ! saves resolution
  xb2%=XBIOS(2)                                  ! saves screen address
  '
  for i&=0 to 319
  xadr.ar&(i&)=SHL(SHR(i&,4),3)                  ! X coordinate to address
  next i&
  BMOVE &HFFFF8240,palette%,32                    ! saves oldpal
  BYTE{&HFFFF8260}=0                              ! low REZ
  VSYNC
  ~XBIOS(5,L:log%,L:phy%,-1)                      ! set screens
  VSYNC
  RC_COPY phy%,0,0,320,400 TO phy%,0,0,0          ! clears both phy% and log% buffers
  VSYNC
  SETCOLOR 1,&H777                                ! stars are white, oh my god !
  FOR i&=0 TO maxstar&
    x&=RAND(319)
    xadr&=SHL(SHR(x&,4),3)                        ! address
    xofst&=x& AND 15                              ! offset
    middle.star&(i&,0)=xadr&
    middle.star&(i&,1)=xofst&
    middle.star&(i&,2)=RAND(199)*160              ! y adr
    middle.star&(i&,3)=(RAND(8)+1)*160            ! y speed
    '
    old.star&(i&,0)=0
    old.star&(i&,1)=0
    old.star&(i&,2)=0
    old.star&(i&,3)=0
  NEXT i&
  pxlz&(0)=-32768                                ! -32768=&H8000=&X1000000000000000
  mystar&=&X0100000000000000
  pxlz&(1)=mystar&
  FOR i&=2 TO 15                             
    mystar&=SHR(mystar&,1)                        ! 1 pixel shift to the right
    pxlz&(i&)=mystar&
  NEXT i&
RETURN
'
PROCEDURE fin
  SHOWM
  BYTE{&HFFFFFC02}=&H8                            ! rend la souris ! mouse alive
  ~MFREE(scrbuf%)
  BMOVE palette%,&HFFFF8240,32                    ! restore old palette
  ~XBIOS(5,L:xb2%,L:xb2%,rez|)
  ~GEMDOS(32,L:super%)                            ! user mode
  EDIT
RETURN

I decided to write this article after interesting chats with Thomas, author of great GFA games (anarcho ride / frogs / randomizer ... ).
My first attempt for this starfield didn't use array, it CARDed values to/from a buffer. We talked about arrays and speed, and Thomas came to some fastest code than mine using one dimensional arrays. Tests did prove that two dimensions arrays as showed in the code above were chewing much more CPU time than using multiple one dimension arrays, while he felt comfortable with that point, I argued that was too many arrays for me. One has to have an array for x adr, xofst, y, yspeed three times (current / mid / old ).

Being a CARD "integrist", I challenged myself to optimize the old routine, following code will display 150 stars each VBL and uses both CARD and arrays.
Goal was to avoid computations as much as possible.

Instead of using many arrays, stars data will be stored in a buffer :
Code:

  INPUT "Max Stars",maxstar&
  DIM pxlz&(15)
  DIM xadr.ar&(320)
  scrbuf%=MALLOC(64000+256+maxstar&*8*3+32)
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)
  log%=ADD(phy%,32000)
  starzbuf%=ADD(log%,32000)            !MALLOC(maxstar&*8*3) (1 word X / 1 word offset / 1 word Y / 1 word speed)*3 buffers
  palette%=ADD(starzbuf%,maxstar&*8*3)  !MALLOC(32)

Only one big buffer is MALLOCed, then we set pointers to tell where each buffer starts.
Memory needed for the stars data is maxstar&*8*3 : we still need to store current / mid / old positions (=>*3) and one set of data is 8 bytes (4*2).
Let's set pointers for current / mid / old stars data:
Code:

  starz%=starzbuf%
  mid.starz%=ADD(starzbuf%,maxstar&*8)
  old.starz%=ADD(starzbuf%,maxstar&*8*2)

Last thing, instead of using FOR/NEXT I went for REPEAT/UNTIL, set a variable that points to the buffer I wanna poke to and add 8 to it each loop until it points to the end of the buffer.

Code:

RESERVE 10000
'
@inits

REPEAT
  VSYNC
  CARD{&HFFFF8240}=0                          ! black backgroud
  ' clear oldstars
  old.starz.pointer%=old.starz%
  old.starz.pointer.max%=ADD(old.starz%,maxstar.lg&)
  REPEAT
    xadr&=CARD{old.starz.pointer%}
    yadr&=CARD{ADD(old.starz.pointer%,4)}
    CARD{ADD(log%,ADD(xadr&,yadr&))}=0            ! clear previous starz
    ADD old.starz.pointer%,8
  UNTIL old.starz.pointer%=old.starz.pointer.max%
  '
  ' calc new coords and display star
  starz.pointer%=starz%
  starz.pointer.max%=ADD(starz%,maxstar.lg&)
  mid.starz.pointer%=mid.starz%
  REPEAT
    yadr&=CARD{ADD(mid.starz.pointer%,4)}
    yspeed&=CARD{ADD(mid.starz.pointer%,6)}
    newy%=ADD(yadr&,yspeed&)
    IF newy%>31999                              ! outside screen
      x&=RAND(319)                              ! new random star
      xadr&=xadr.ar&(x&)
      xofst&=x& AND 15                          ! offset
      CARD{starz.pointer%}=xadr&
      CARD{ADD(starz.pointer%,2)}=xofst&
      CARD{ADD(starz.pointer%,4)}=0
      CARD{ADD(starz.pointer%,6)}=MUL(ADD(RAND(8),1),160) !MUL(ADD(x& AND 7,1),160)  !(RAND(8)+1)*160
      '
      dest%=ADD(log%,xadr&)
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
      ADD starz.pointer%,8
      ADD mid.starz.pointer%,8
    ELSE
      xadr&=CARD{mid.starz.pointer%}
      xofst&=CARD{ADD(mid.starz.pointer%,2)}
      '
      CARD{starz.pointer%}=xadr&
      CARD{ADD(starz.pointer%,2)}=xofst&
      CARD{ADD(starz.pointer%,4)}=newy%
      CARD{ADD(starz.pointer%,6)}=yspeed&
      '
      dest%=ADD(log%,ADD(xadr&,newy%))
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
      ADD starz.pointer%,8
      ADD mid.starz.pointer%,8
    ENDIF
  UNTIL starz.pointer%=starz.pointer.max%
  tuch&=BYTE{&HFFFFFC02}
  IF tuch&=&H38                                  ! Alt pressed
    CARD{&HFFFF8240}=&HF                        ! show CPU left
  ENDIF
  SWAP mid.starz%,old.starz%
  SWAP starz%,mid.starz%
  SWAP phy%,log%
  BYTE{&HFFFF8201}=SHR(phy%,16)
  BYTE{&HFFFF8203}=SHR(phy%,8)
  '
UNTIL tuch&=&H39                              ! Spacebar pressed
'
@fin
'
PROCEDURE inits
  CLS
  INPUT "Max Stars",maxstar&
  DIM pxlz&(15)
  DIM xadr.ar&(320)
  scrbuf%=MALLOC(64000+256+maxstar&*8*3+32)
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)
  log%=ADD(phy%,32000)
  starzbuf%=ADD(log%,32000)            !MALLOC(maxstar&*8*3)              ! (1 word X / 1 word offset / 1 word Y / 1 word speed)*3 buffers
  palette%=ADD(starzbuf%,maxstar&*8*3)      !MALLOC(32)
  super%=GEMDOS(32,L:0)                      ! supervisor mode
  '
 HIDEM
  BYTE{&HFFFFFC02}=&H12                        ! plus de souris ! no mouse
  rez|=XBIOS(4)
  xb2%=XBIOS(2)
  '
  for i&=0 to 319
  xadr.ar&(i&)=SHL(SHR(i&,4),3)
  next i&
  BMOVE &HFFFF8240,palette%,32                ! saves oldpal
  BYTE{&HFFFF8260}=0                          ! low REZ
  VSYNC
  ~XBIOS(5,L:log%,L:phy%,-1)                  ! set screens
  VSYNC
  RC_COPY phy%,0,0,320,400 TO phy%,0,0,0      ! clears both phy% and log% buffers
  VSYNC
  SETCOLOR 1,&H777
  mid.pointer&=maxstar&*8
  old.pointer&=maxstar&*8*2
  FOR i|=0 TO maxstar&-1
    x&=RAND(319)
    xadr&=SHL(SHR(x&,4),3)                  ! address
    xofst&=x& AND 15                          ! offset
    CARD{starzbuf%+mid.pointer&}=xadr&
    CARD{starzbuf%+mid.pointer&+2}=xofst&
    CARD{starzbuf%+mid.pointer&+4}=RAND(199)*160      ! y adr
    CARD{starzbuf%+mid.pointer&+6}=(RAND(8)+1)*160    ! y speed
    '
    CARD{starzbuf%+old.pointer&}=0
    CARD{starzbuf%+old.pointer&+2}=0
    CARD{starzbuf%+old.pointer&+4}=0
    CARD{starzbuf%+old.pointer&+6}=0
    ADD mid.pointer&,8
    ADD old.pointer&,8
  NEXT i|
  maxstar.lg&=SHL(maxstar&-1,3)                  ! X8
  starz%=starzbuf%
  mid.starz%=ADD(starzbuf%,maxstar&*8)
  old.starz%=ADD(starzbuf%,maxstar&*8*2)
  pxlz&(0)=-32768                                !&X1000000000000000
  mystar&=&X0100000000000000
  pxlz&(1)=mystar&
  FOR i&=2 TO 15                                !2 TO 30 STEP 2
    mystar&=SHR(mystar&,1)                      ! 1 pixel shift to the right
    pxlz&(i&)=mystar&
  NEXT i&
RETURN
'
PROCEDURE fin
  SHOWM
  BYTE{&HFFFFFC02}=&H8                        ! rend la souris ! mouse alive
  ~MFREE(scrbuf%)
  ~MFREE(starzbuf%)
  BMOVE palette%,&HFFFF8240,32                  ! restore old palette
  ~XBIOS(5,L:xb2%,L:xb2%,rez|)
  ~GEMDOS(32,L:super%)                          ! user mode
  EDIT
RETURN



















tomchi
tomchi

Messages : 52
Date d'inscription : 15/09/2018
Age : 49

Shadow272 aime ce message

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par Shaoth Sam 21 Nov - 10:56

Cette explication de fou !!
Merci @tomchi
Je vais lire ça avec intérêt !
Shaoth
Shaoth

Messages : 64
Date d'inscription : 28/09/2020
Age : 54
Localisation : Courbevoie

Revenir en haut Aller en bas

Champ d'étoiles vertical [FR] / [ENG] Empty Re: Champ d'étoiles vertical [FR] / [ENG]

Message par Contenu sponsorisé


Contenu sponsorisé


Revenir en haut Aller en bas

Revenir en haut


 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum