Retro nostalgia

Discussions related to graphics (2D and 3D), animation and games programming
Ivan
Posts: 127
Joined: Tue 07 May 2019, 16:47

Retro nostalgia

Post by Ivan »

I am digging in some of my old programs from the eighties. In parallel with BBCBASIC I did a lot of UniComal programming. I did a Lander game and saw that UniComal had a procedures like:

loadscreen("picture.pic")
and of course a savescreen.

getshape(xmin, xmax, ymin, ymax, drawing$)

and

putshape(xmin, xmax, ymin, ymax, drawing$)

Do we have something like these procedures or similar in BBCBASIC?
You do not have the required permissions to view the files attached to this post.
Last edited by Ivan on Sat 06 Feb 2021, 13:41, edited 1 time in total.
BBC Model B - 1984-1989. 6502 assembler, Unicomal 1988-1994, Some C and C++, Pascal 1990-1994. Bought a copy of BBC-BASIC 2007, but started to program at a daily basis 2019. C++ in 2021.
DDRM

Re: Retro nostalgia

Post by DDRM »

Yes, indeed. Have a look *DISPLAY and *SCREENSAVE, for a start, which will load a picture from memory and display it, and save (a part of) the screen as a bitmap file. You can also use *LOAD to load a file into memory, and then *MDISPLAY to plot it, which might be better if you need a lot of speed, and/or to draw the same thing multiple times.

One nice thing you could also look at is using RECTANGLE TO and RECTANGLE FILL. If you make the graphics window bigger than the visible window you can draw things "offscreen", and copy them into view when you want them.

...but for simple things, it may be fine just to draw them on the fly - that's what I did when David Williams issued a challenge on a moonlander game (forgot the original name). I think David posted one too. I can't track it down, so I'll paste a copy here in case you are interested:

Code: Select all

      MODE 8
      xRes%=@vdu%!208 :REM Window width in pixels. There are 2 BB4W graphics units per pixel, so as a coordinate it represents the centre of the window
      yRes%=@vdu%!212
      numPoints%=3    :REM Number of points in the lander - could draw a fancier lander if you wanted to
      DIM sS(numPoints%-1,1)
      FOR x%=0 TO numPoints%-1
        READ sS(x%,0),sS(x%,1)
      NEXT x%
      DATA 10,0,0,30,-10,0   :REM Coordinates for the drawing of the lander
      g=9.8        :REM Acceleration due to gravity
      m=10000      :REM Mass of basic lander (fuel added to affect acceleration)
      Level%=1     :REM Starting level.If you are developing a new level, set this to your level number,to save having to fly through the earlier ones!
      maxLevel%=7
      Score%=0
      Lives%=3
      COLOUR 11    :REM Set text colour to yellow for showing score etc: Won't crash lander!
      REPEAT
        REM Choose and draw the level. Also sets initial position, velocity and fuel level, as well as landing pad size and position
        CASE Level% OF
          WHEN 1:PROCLevel1
          WHEN 2:PROCCrevasse
          WHEN 3:PROCLevel3
          WHEN 4:PROCRings
          WHEN 5:PROCTunnel1
          WHEN 6:PROCTunnel2
          WHEN 7:PROCMaze
        ENDCASE
        doneLevel%=FALSE
        *REFRESH OFF
        MOUSE OFF         :REM Hides mouse pointer, to make it less distracting - but risk you'll click outside the window, hide it, and crash!
        MOUSE TO xRes%,yRes%  :REM Centres the mouse on the window. Moving it left or right will tilt the lander
        Contact%=FALSE    :REM We haven't hit anything (yet)
        REPEAT
          MOUSE mx%,my%,mz%
          IF INKEY(-10) THEN t=5 ELSE t=0   :REM Thrust (engine on if left mouse button pressed)
          F-=t                              :REM Use up some fuel
          IF F<t THEN F=0:t=0               :REM If we've run out, we can't run the engine...
          IF t THEN SOUND &11,-15,32,1      :REM Make a sound to indicate that engine is on
          IF Contact% THEN PROCTest         :REM Check whether we had hit anything last time lander was drawn, and if so, what
          Angle=(xRes%-mx%)*PI/640              :REM Calculate angle of lander, depending on where the mouse is relative to the centre of the window
          vY+=t*COS(Angle)*100/(m+F)-g/1000     :REM Adjust vertical velocity according to gravity and thrust
          vX-=t*SIN(Angle)*100/(m+F)            :REM Adjust horizontal velocity according to thrust
          pX+=vX                            :REM Adjust coordinates of the lander according to velocity vectors
          pY+=vY
          IF pX<-10 THEN pX+=2*xRes%        :REM Wrap window - you can fly off the edge horizontally and appear on the other side!
          IF pX>2*xRes%+10 THEN pX-=2*xRes%
          PROCDrawSpaceship(pX,pY,Angle,t)      :REM Draw the lander in its (new) position
          PRINT TAB(65,0),"Score: "+STR$(Score%)
          PRINT TAB(65,1),"Lives: "+STR$(Lives%)
          PRINT TAB(65,2),"Level: "+STR$(Level%)
          PRINT TAB(65,3),"Fuel: "+STR$(F)+" "
          *REFRESH
          WAIT 2
          PROCDrawSpaceship(pX,pY,Angle,t)     :REM *UN*-draw the lander (by XOR plotting it over itself). Since REFRESH is off, we never see this,but it clears things before the new plot
        UNTIL doneLevel%                   :REM Landed or crashed!
      UNTIL Level%=maxLevel%+1 OR Lives%=0
      *REFRESH ON
      *MOUSE ON
      PROCMessage("Your final score was "+STR$(Score%),"Lander")
      REM SYS "MessageBox", @hwnd%, "Your final score was "+STR$(Score%), "Lander", 0
      QUIT
      :
      DEFPROCDrawSpaceship(px,py,a,t)
      LOCAL x%,tx%,ty%
      GCOL 3,15      :REM Note the use of XOR plotting mode (3) - if we redraw with the same parameters it rubs out the lander!
      MOVE px,py     :REM Move to defining point of the lander (centre bottom)
      FOR x%=0 TO numPoints%-1
        tx%=px+sS(x%,0)*COS(a)-sS(x%,1)*SIN(a)            :REM Calculate coordinates of each point, bearing in mind offset and angle
        ty%=py+sS(x%,0)*SIN(a)+sS(x%,1)*COS(a)
        IF POINT(tx%,ty%)<>0 THEN Contact%=POINT(tx%,ty%) :REM Test if any of the vertices coincide with the scenery.... at least, grey or green bits of it
        DRAW tx%,ty%
      NEXT x%
      DRAW px,py     :REM Close shape (could fill it, I guess, if you wanted to!)
      IF t THEN
        REM Engine is on: draw a red rocket flare!
        GCOL 3,1
        DRAW px+10*SIN(a),py-10*COS(a)
      ENDIF
      ENDPROC
      :
      DEFPROCTest
      LOCAL sc%
      REM Note that this only has an effect if the colour hit was 7 or 2 - so you could draw stars (or text) in other colours, and they wouldn't crash the lander
      CASE Contact% OF
        WHEN 7:
          REM Crash! We've hit the landscape
          PROCMessage("Oops! You crashed!","Lander (didn't)")
          REM SYS "MessageBox", @hwnd%, "Oops! You crashed!", "Lander (didn't)", 0
          Lives%-=1
          doneLevel%=TRUE
        WHEN 2:
          REM On landing pad!
          IF ABS(vX)<1 AND ABS(vY)<1 AND ABS(Angle)<0.5 THEN
            REM Not going too fast, or tipped over too much
            sc%=F+(TargetW%/2-ABS(pX-TargetX%))*100+(5000-3000*ABS(vY))+(5000-5000*ABS(Angle))
            PROCMessage("Congratulations! "+"You scored "+STR$(sc%),"Lander")
            REM SYS "MessageBox", @hwnd%, "Congratulations!"+CHR$(13)+CHR$(10)+"You scored "+STR$(sc%), "Lander", 0
            Score%+=sc%
            Level%+=1
            doneLevel%=TRUE
          ELSE
            REM We WERE going too fast, or tipped over too much
            PROCMessage("Oops! You crashed!","Lander (didn't)")
            REM SYS "MessageBox", @hwnd%, "Oops! You crashed!", "Lander (didn't)", 0
            Lives%-=1
            doneLevel%=TRUE
          ENDIF
      ENDCASE
      Contact%=FALSE
      ENDPROC
      :
      DEFPROCMessage(m$,h$)
      LOCAL x%,y%,z%,done%
      done%=FALSE
      GCOL 0,0
      RECTANGLE FILL xRes%/2,yRes%/2,xRes%,yRes%
      GCOL 0,15
      RECTANGLE  xRes%/2,yRes%/2,xRes%,yRes%
      VDU 5
      GCOL 0,3
      MOVE xRes%/2+5,yRes%*3/2-5
      PRINT h$
      MOVE xRes%-@vdu%!216*LEN(m$),yRes%+@vdu%!220
      PRINT m$
      MOVE xRes%-2*@vdu%!216,yRes%/2+2*@vdu%!220+25
      PRINT "OK"
      GCOL 0,15
      RECTANGLE xRes%-2*@vdu%!216-10,yRes%/2+20,4*(@vdu%!216)+20,2*@vdu%!220+30
      *REFRESH ON
      MOUSE ON
      REPEAT
        MOUSE x%,y%,z%
        WAIT 1
        IF z%>0 THEN IF x%>xRes%-2*@vdu%!216-10 AND x%<xRes%+2*@vdu%!216+10 AND y%>yRes%/2+20 AND y%<yRes%/2+2*@vdu%!220+50 THEN done%=TRUE
      UNTIL done%
      REPEAT MOUSE x%,y%,z% UNTIL z%=0
      VDU 4
      MOUSE OFF
      *REFRESH OFF
      ENDPROC
      :
      REM Here are the definitions for the different levels. Basically you need to define a landscape where Colour 7 defines things you can't hit
      REM and Colour 2 defines the landing area(s). I've assumed that open space is black, but it doesn't need to be
      REM - though you'll need to be careful with the flood fills if you draw in different colours!
      REM I've used some different approaches to drawing the landscape - see what you like.
      DEFPROCLevel1
      CLS
      GCOL 0,7           :REM Absolute colour plotted - use colour 7 (grey by default, but you could change that if you wanted a moon made of green cheese...)
      MOVE 0,20
      DRAW 300,50
      DRAW 400,100
      DRAW 600,40
      DRAW 800,40
      DRAW 900,100
      DRAW 1000,80
      DRAW 1050,120
      DRAW 1100,60
      DRAW 1280,80
      PLOT 141,10,10     :REM Flood fill
      GCOL 0,2           :REM Change to colour 2 to indicate landing pad - again you could reprogram colour 2 if you wanted to (for example, if you made colour 7 into green...)
      TargetX%=700       :REM Define target location and width - needed elsewhere to calculate score, which depends on how close you are to the centre
      TargetW%=160
      RECTANGLE FILL TargetX%-TargetW%/2,32,160,8
      pX=100             :REM Set initial coordinates of the lander, and its velocity vectors
      pY=2*yRes%-100
      vX=0
      vY=0
      F=5000             :REM Fuel load  -affects performance (heavy landers accelerate slower), or you could use it to make it more difficult!
      ENDPROC
      :
      DEFPROCCrevasse
      CLS
      GCOL 0,7
      MOVE 0,200
      DRAW 300,350
      DRAW 400,200
      DRAW 550,700
      DRAW 600,600
      DRAW 620,40
      DRAW 820,40
      DRAW 900,650
      DRAW 1000,400
      DRAW 1050,120
      DRAW 1100,260
      DRAW 1280,380
      PLOT 141,10,10
      GCOL 0,2
      TargetX%=700
      TargetW%=120
      RECTANGLE FILL TargetX%-TargetW%/2,32,160,8
      pX=100
      pY=2*yRes%-100
      vX=0
      vY=0
      F=5000
      ENDPROC
      :
      DEFPROCLevel3
      CLS
      GCOL 0,7
      MOVE 0,100
      DRAW 200,250
      DRAW 300,400
      DRAW 550,700
      DRAW 700,600
      DRAW 650,500
      DRAW 450,200
      DRAW 500,100
      DRAW 520,40
      DRAW 720,40
      DRAW 900,500
      DRAW 800,700
      DRAW 900,750
      DRAW 1050,520
      DRAW 1100,360
      DRAW 1280,380
      PLOT 141,10,10
      GCOL 0,2
      TargetX%=600
      TargetW%=120
      RECTANGLE FILL TargetX%-TargetW%/2,32,160,8
      pX=100
      pY=2*yRes%-100
      vX=0
      vY=0
      F=5000
      ENDPROC
      :
      DEFPROCRings
      CLS
      GCOL 0,7
      CIRCLE FILL 300,600,300
      CIRCLE FILL 900,400,300
      GCOL 0,0
      CIRCLE FILL 300,600,200
      CIRCLE FILL 900,400,200
      RECTANGLE FILL 400,650,250,100
      RECTANGLE FILL 800,550,100,300
      GCOL 0,2
      TargetX%=950
      TargetW%=160
      RECTANGLE FILL TargetX%-TargetW%/2,300,TargetW%,8
      pX=300
      pY=600
      vX=0
      vY=0
      F=5000
      ENDPROC
      :
      DEFPROCTunnel1
      LOCAL x%,y%,a%
      LOCAL DATA     :REM Store the existing data pointer, so we can move it here
      RESTORE +1     :REM Start reading data from the next line
      DATA 0,600,200,650,800,620,850,600,800,500,650,450,150,300,50,100,120,50,420,40,600,50
      DATA 900,40,1100,40,1150,80,1100,160,880,180,280,200,300,230,550,250,950,420,1280,920
      CLS
      GCOL 0,7
      READ x%,y%
      MOVE x%,y%
      REM Rather than a whole string of draw commands, read and plot them in a loop
      FOR a%=1 TO 20
        READ x%,y%
        DRAW x%,y%
      NEXT a%
      RESTORE DATA  :REM Put the old data pointer back in place
      PLOT 141,10,10
      GCOL 0,2
      TargetX%=1000
      TargetW%=120
      RECTANGLE FILL TargetX%-TargetW%/2,32,160,8
      pX=100
      pY=2*yRes%-100
      vX=0
      vY=0
      F=5000
      ENDPROC
      :
      DEFPROCTunnel2
      LOCAL x%,y%,a%
      LOCAL DATA     :REM Store the existing data pointer, so we can move it here
      RESTORE +1     :REM Start reading data from the next line
      DATA 0,200,100,50,200,20,450,70,800,100,1200,150,1250,400,1200,900,1100,950,650,700,350,500,700,450,950,450
      DATA 980,540,600,560,1000,740,1050,700,950,360,480,280,280,200,300,500,550,750,850,920,900,1024
      CLS
      GCOL 0,7
      READ x%,y%
      MOVE x%,y%
      REM Rather than a whole string of draw commands, read and plot them in a loop
      FOR a%=1 TO 23
        READ x%,y%
        DRAW x%,y%
      NEXT a%
      RESTORE DATA  :REM Put the old data pointer back in place
      PLOT 141,10,10
      GCOL 0,2
      TargetX%=840
      TargetW%=120
      RECTANGLE FILL TargetX%-TargetW%/2,450,TargetW%,8
      pX=100
      pY=2*yRes%-100
      vX=0
      vY=0
      F=5000
      ENDPROC
      :
      DEFPROCMaze
      LOCAL x%,y%,r%
      x%=500
      y%=500
      r%=500
      CLS
      GCOL 0,7
      CIRCLE FILL x%,y%,r%
      GCOL 0,0
      CIRCLE FILL x%,y%,r%-50
      GCOL 0,7
      CIRCLE FILL x%,y%,r%-150
      GCOL 0,0
      CIRCLE FILL x%,y%,r%-200
      GCOL 0,7
      CIRCLE FILL x%,y%,r%-300
      GCOL 0,0
      CIRCLE FILL x%,y%,r%-350
      RECTANGLE FILL x%+130,y%-50,80,50
      RECTANGLE FILL x%-295,y%,-60,50
      RECTANGLE FILL x%+430,y%+50,80,50
      TargetX%=1150
      TargetW%=120
      GCOL 0,2
      RECTANGLE FILL TargetX%-TargetW%/2,250,TargetW%,8
      pX=x%
      pY=y%
      vX=0
      vY=0
      F=5000
      ENDPROC
This version is mouse driven: move the mouse to rotate the spaceship, and press left button to fire the engine. Land on the green pad going slow enough...

Feel free to develop your own levels!
Ivan
Posts: 127
Joined: Tue 07 May 2019, 16:47

Re: Retro nostalgia

Post by Ivan »

Thanks.

I used a parable to simulate movements.
BBC Model B - 1984-1989. 6502 assembler, Unicomal 1988-1994, Some C and C++, Pascal 1990-1994. Bought a copy of BBC-BASIC 2007, but started to program at a daily basis 2019. C++ in 2021.