Welcome, Guest |
You have to register before you can post on our site.
|
Forum Statistics |
» Members: 490
» Latest member: Dr.Creek
» Forum threads: 2,823
» Forum posts: 26,475
Full Statistics
|
|
|
Correcting the code |
Posted by: Chris - 10-27-2023, 07:19 PM - Forum: Programs
- Replies (15)
|
|
The code is intended to work as follows: when only the Enter key is pressed, the variable (H#) cannot be set to zero. However, when the zero (0) key is pressed, the variable (H#) is supposed to have a zero value. But if the entered number is 1,2,3,4,5,6 digits, it is to be confirmed with the Enter key. However, the 7-digit number is to be approved automatically.
To sum up, the entered numbers may have the following values: 0, 11, 232, 1254, 36547, 325478, 3254657.
H$ = "": B$ = ""
WHILE LEN(H$) < 7 AND B$ <> CHR$(13)
B$ = ""
WHILE B$ = "": B$ = INKEY$: _LIMIT 30: WEND
IF B$ = CHR$(27) THEN 4200
IF B$ = CHR$(32) THEN 8425
IF B$ = CHR$(45) THEN 6171
IF B$ = CHR$(43) THEN 6172
IF B$ = CHR$(81) OR B$ = CHR$(113) THEN 6304
IF B$ = CHR$(65) OR B$ = CHR$(97) THEN 6305
IF B$ = CHR$(87) OR B$ = CHR$(119) THEN 6306
IF B$ = CHR$(83) OR B$ = CHR$(115) THEN 6307
IF B$ = CHR$(69) OR B$ = CHR$(101) THEN 6308
IF B$ = CHR$(68) OR B$ = CHR$(100) THEN 6309
IF B$ = CHR$(82) OR B$ = CHR$(114) THEN 6310
IF B$ = CHR$(70) OR B$ = CHR$(102) THEN 6311
IF B$ <> CHR$(13) THEN H$ = H$ + B$
WEND
H# = VAL(H$): PRINT H#
Thank you for your help - regards
|
|
|
Little ASCII Race Car Game |
Posted by: TerryRitchie - 10-27-2023, 06:21 PM - Forum: Programs
- No Replies
|
|
I'm working on some very simple games for users of the tutorial to tear apart and learn from.
The very first computer game I ever played was a text race car game on the TRS-80 Model I in 1980.
I've recreated it here for your ASCII enjoyment.
Code: (Select All) '* Race Day!
'* Inspired by the first computer game I ever played on a TRS-80 Model I in 1980
'* Terry Ritchie
'* for the QB64 tutorial ( www.qb64tutorial.com )
'*
'* RIGHT/LEFT arrow keys to steer car, ESC to exit.
'*
DIM RoadWidth AS INTEGER ' width of roadway
DIM RoadX AS INTEGER ' left location of roadway
DIM Road AS STRING ' one segment of roadway
DIM CarX AS INTEGER ' car location on roadway
DIM CarY AS INTEGER
DIM Travel AS INTEGER ' distance traveled counter
DIM Speed AS SINGLE ' current speed of car
DIM Direction AS INTEGER ' next turn direction on roadway
DIM Turn AS INTEGER ' distance to turn in direction
DIM Marker AS STRING * 2 ' road side markers
DIM Crash AS INTEGER ' crash indicator
DIM Score AS INTEGER ' player's score
RANDOMIZE TIMER ' seed the random number generator
RoadWidth = 44 ' initial width of roadway
RoadX = 18 ' initial left side of roadway
CarX = 40 ' intitial car location
CarY = 1
Speed = .2 ' initial speed
Turn = 25 ' turn counter
Marker = "||" ' initial road markers
DO ' BEGIN MAIN PROGRAM LOOP
Travel = Travel + 1 ' increment travel counter
IF Travel = 25 THEN ' 25 frames gone by?
Travel = 0 ' reset travel counter
IF Speed > .07 THEN Speed = Speed - .02 ' increase speed
IF RoadWidth > 7 THEN ' road width at least 8?
RoadWidth = RoadWidth - 2 ' yes, decrease width of roadway
RoadX = RoadX + 1 ' move roadway to right one position
END IF
IF CarY < 14 THEN CarY = CarY + 1 ' increase car position on roadway
END IF
Turn = Turn - 1 ' decrement turn counter
IF Turn = 1 THEN Marker = "||" ' make a smooth transition between curves
IF Turn = 0 THEN ' has this turn ended?
Direction = INT(RND * 3) - 1 ' which new direction? (-1, 0, or 1)
Turn = INT(RND * 7) + 2 ' how long should turn last?
IF Direction = -1 THEN Marker = "//" ' create appropriate turn road markers
IF Direction = 0 THEN Marker = "||"
IF Direction = 1 THEN Marker = "\\"
END IF
RoadX = RoadX + Direction ' move road in direction
IF RoadX < 1 THEN ' too far left?
RoadX = 1 ' yes, keep here
Marker = "||" ' straighten the road out
ELSEIF RoadX > 80 - LEN(Road) THEN ' too far right?
RoadX = 80 - LEN(Road) ' yes, keep here
Marker = "||" ' straighten the road out
END IF
IF _KEYDOWN(19200) THEN CarX = CarX - 1 ' move car left when left arrow pressed
IF _KEYDOWN(19712) THEN CarX = CarX + 1 ' move car right when right arrow pressed
Road = Marker + SPACE$(RoadWidth) + Marker ' create road segment
LOCATE 24, RoadX ' position cursor for road segment
PRINT Road ' print road segment
IF SCREEN(CarY, CarX, 0) = 32 THEN ' is the road clear?
LOCATE CarY, CarX ' yes, position cursor for car
PRINT "V" ' print the car
LOCATE 1, 1 ' position cursor at top left corner
Score = Score + 1 ' increment score
PRINT "Score:"; Score; ' print player's score
_DELAY Speed ' pause at current speed
ELSE
Crash = -1 ' no, kaboom
END IF
LOOP UNTIL _KEYDOWN(27) OR Crash ' leave when player crashes or presses ESC
IF Crash THEN ' did player crash?
LOCATE CarY, CarX ' yes, position cursor at car
PRINT "*" ' print wrecked car
LOCATE 1, 1 ' position cursor at top left
PRINT "---------------------" ' print player's final score
PRINT "------ !CRASH! ------"
PRINT "---------------------"
PRINT " Final Score:"; Score
PRINT "---------------------"
PRINT "- Press ESC to exit -"
PRINT "---------------------"
DO ' begin exit loop
_LIMIT 10 ' don't hog cpu
LOOP UNTIL _KEYDOWN(27) ' leave when player presses ESC
END IF
SYSTEM ' return to operating system
|
|
|
SaveScreen and RestoreScreen |
Posted by: SMcNeill - 10-24-2023, 08:33 AM - Forum: SMcNeill
- Replies (8)
|
|
Two of the simplest little routines in the world, though I think they'll both end up becoming something I rely on more often in the future:
Code: (Select All)
Sub SaveScreen (Image As Long, SaveTo As _MEM)
Dim m As _MEM
m = _MemImage(Image)
SaveTo = _MemNew(m.SIZE)
_MemCopy m, m.OFFSET, m.SIZE To SaveTo, SaveTo.OFFSET
_MemFree m
End Sub
Sub RestoreScreen (FromWhich As _MEM, Image As Long)
Dim m As _MEM
m = _MemImage(Image)
_MemCopy FromWhich, FromWhich.OFFSET, FromWhich.SIZE To m, m.OFFSET
_MemFree m
End Sub
So what's these brilliant little pieces of code do for us? The just let us save a screen and then restore that screen.
That's it. Nothing special. No great bells or whistles here, to see folks!
There's already about 9000 different ways to do this, so why do we need THIS particular way, you ask??
Let's take a moment and look at this scenario:
Code: (Select All) SUB foo
PCOPY 0, 1
.... do stuff
PCOPY 1, 0
END SUB
Now the above is a simple enough way to grab a copy of the screen, do stuff (like place a pop up box on it), and then restore it and get rid of whatever temporary changes we made to it (such as when we close that pop up box).
But here's a question for you: What happens if your main program already had a PCOPY 0, 1 to save a screen?? Didn't you just overwrite that page with the new PCOPY 0, 1 that your SUB did? How's that gonna screw up stuff when the main routine now does a call back to the old PCOPY 1, 0 when it needs it?
So PCOPY isn't particularly a great command to make use of for SUBs or Library code...
But then there's always the old _COPYIMAGE trick!
Code: (Select All) SUB foo
tempImage = _COPYIMAGE(0)
... do stuff
_PUTIMAGE ,tempImage
_FREEIMAGE tempImage
Which works all fine and dandy.... BUT.... What if the _DISPLAY is a SCREEN 0 text screen? Can't _PUTIMAGE that image back then, now can you?
So we try and get tricky:
Code: (Select All) SUB foo
tempImage = _COPYIMAGE(0)
...do stuff
D = _DISPLAY
SCREEN tempImage
_FREEIMAGE D
Which works all fine and dandy.... BUT.... What if someone writes their code in the following manner:
Code: (Select All) WorkScreen = _NEWIMAGE(1280, 720, 32)
When you did the tempImage, QB64 had to create a new image handle for that screen... Since the main routine already had a reserved handle for the screen -- that you just freed with the _FREEIMAGE D -- none of the routines in the main program are going to work anymore as the handles don't match.
One glitch after another after another!!
Which is why I give you the two little routines above:
SaveScreen (Image As Long, SaveTo As _MEM) <-- This takes any image handle (even _DISPLAY) and saves it to a designated memblock.
RestoreScreen (FromWhich As _MEM, Image As Long) <-- And this does the reverse, taking a memblock and using it to restore the desired image.
Should work on ALL screen modes -- text, legacy graphics, 256 color screens, and 32-bit color screens. Shouldn't have any problems with using _DISPLAY or 0 as imagehandles. They're quick. They're simple. And they solve a lot of the issues which all the other various methods of saving and restoring a screen can have.
A simple working example is below, which shows that it works in both text screens and graphic screen modes.
Code: (Select All)
Screen _NewImage(640, 480, 32)
$Color:32
Cls , Pink
Print "An original Pink screen"
Sleep
GreenFoo
Sleep
Screen 0
Cls , 4 'redscreen
Print "A Red TEXT Screen 0"
Sleep
WhiteFoo
Sub GreenFoo
Dim Saver As _MEM
SaveScreen _Display, Saver
Cls , Green
Print "A happy Green screen"
Sleep
RestoreScreen Saver, _Display
_MemFree Saver
End Sub
Sub WhiteFoo
Dim Saver As _MEM
SaveScreen _Display, Saver
Cls , 15
Print "Replaced with white"
Sleep
RestoreScreen Saver, _Display
_MemFree Saver
End Sub
Sub SaveScreen (Image As Long, SaveTo As _MEM)
Dim m As _MEM
m = _MemImage(Image)
SaveTo = _MemNew(m.SIZE)
_MemCopy m, m.OFFSET, m.SIZE To SaveTo, SaveTo.OFFSET
_MemFree m
End Sub
Sub RestoreScreen (FromWhich As _MEM, Image As Long)
Dim m As _MEM
m = _MemImage(Image)
_MemCopy FromWhich, FromWhich.OFFSET, FromWhich.SIZE To m, m.OFFSET
_MemFree m
End Sub
|
|
|
ASCII-mation Game |
Posted by: SpriggsySpriggs - 10-23-2023, 12:45 PM - Forum: Works in Progress
- Replies (8)
|
|
I am no good at graphics. It is not my forte. However, I am somewhat decent at filming and photography. So, my idea is to use my new system for converting images into ASCII text files and making a game using real actors for the main characters, some sort of pixel art characters for the enemies, and AI art for the bosses. All will be converted into ASCII text files that will contain all animation data for their movesets. Basically the entire screen will be created using PRINTSTRING and other PRINT commands. Collision will be fairly easy, as I will have tags on the boundary of each character that will not be printed but will be checked for proximity to another character's tag. If the tags are touching, there is collision. I'm even considering going as far as having cutscenes in the game, with varying degrees of detail provided by the ASCII conversion, so as to have cinematic qualities. Note, this will be my first game EVER, so expect development to be long and arduous, with me asking many of our resident game programmers for assistance. I don't know when I will start this project, but I also don't want people hounding me about it as I'm very bad about getting sidetracked and starting multiple projects at the same time and never finishing them. For the game, I'm thinking typical sidescroller with basic combat. Melee, ranged, etc. I am on call this week for work so I probably won't do much this week but Monday & Tuesday of next week will be a good time for me to start. I want to at least get a first character put on the screen with basic animations for idling, walking, running, and jumping. The hopes for this game will be that it will be compatible with not only QB64 (on all platforms) but that it will also run on QBJS. Shouldn't be too difficult to make that happen. The game probably won't be open source at first, but snippets might be shared for helping with debugging and whatnot.
|
|
|
Speed comparison of MID$ vs ASC |
Posted by: SMcNeill - 10-22-2023, 03:19 AM - Forum: Learning Resources and Archives
- Replies (10)
|
|
As it seems everyone is always trying to make their stuff run as fast as possible, I want to take a moment to once again point out the difference in speed between using STRING manipulation (such as MID$) verses the equivalent numeric manipulation (such as with ASC).
Take a brief moment to look at the following code, and compare the run times of these two simple routines:
Code: (Select All)
DEFLNG A-Z
CONST Limit = 100000000 '100 million
DIM s AS STRING
s = STRING$(Limit, "A") 'a string Limit characters long of all "A".
t# = TIMER
FOR i = 1 TO Limit
IF MID$(s, i, 1) = "A" THEN MID$(s, i, 1) = "B"
NEXT
t1# = TIMER
FOR i = 1 TO Limit
IF ASC(s, i) = 66 THEN ASC(s, i) = 67 'replace "B" with "C"
NEXT
t2# = TIMER
PRINT USING "###.### seconds to replace with MID$."; t1# - t#
PRINT USING "###.### seconds to replace with ASC."; t2# - t1#
PRINT LEFT$(s, 10) 'just to show we're all "C" now, so we know both replacements worked.
Replacing 100 million characters inside a string with another character, so give this a wee bit to run. (Particularly if you're on an older, slower PC.) On my machine, this takes about 8 seconds from start to finish, so you can use that as some sort of general starting benchmark of what to expect with a higher-end PC. (If your machine is 10 years old, or a bargain basement model, give it 30+ seconds to run. If you're on something older than that, go grab yourself a cup of coffee and kindly report the results when your antique finishes two hours from now -- I'd love to see the comparison values on some older hardware!)
Most folks seem to forget that in QB64PE, you can add a second exponent to the ASC command to get the particular character you want. Even more folks seem to have absolutely no knowledge in the fact that ASC is also a SUB and not just a FUNCTION, and that the SUB version can be used to assign values to your string!
If you guys are ever the type to be concerned about the speed and performance of your programs, **REMEMBER** these two commands and the features they possess. They're quite a bit faster than MID$, and can improve program performance considerably!
|
|
|
Performance improvement splitting huge file |
Posted by: mdijkens - 10-21-2023, 01:36 PM - Forum: Help Me!
- Replies (11)
|
|
This is a simplified part of a more complex process to split 1 huge inFile into multiple smaller outFile() ones:
Code: (Select All) Dim As _Unsigned _Byte inPos, splitFiles, splitFile
Dim As _Unsigned _Integer64 inSize, splitPos, splitSize
Dim As _Unsigned _Byte inFile(1 To inSize), char
Get #1, 1, inFile()
Dim As String outFile(splitFiles)
For splitFile = 1 To splitFiles
outFile(splitFile) = String$(splitSize, 0)
Next splitFile
For splitPos = 1 To splitSize
For splitFile = 1 To splitFiles
inPos = inPos + 1
If inPos <= inSize Then
char = inFile(inPos)
Mid$(outFile(splitFile), splitPos, 1) = Chr$(char)
End If
Next splitFile
Next splitPos
For splitFile = 1 To splitFiles
Put #splitFile%, , outFile(splitFile)
Next splitFile
inFile is the byte-array of the inputfile
inSize is the size in bytes of the inFile
inPos is the current characterposition of the inFile
outFile() are the strings build for the split-files
splitFiles is the number of files to split into
splitSize is the size in bytes of each outFile (e.g. roundup(inSize/splitFiles))
splitFile is current splitFile
splitPos is the current characterposition of the outFile
Above works, but variable length strings and the Mid$() command are very time-expensive (2GB inFile takes ~3 minutes)
I've tried 2-dimensional byte-arrays for the out-files like outFile(files, length) , but QB64 does not support Put with one dimension like Put #x, , outFile(x)
I've also tried mapping this 2-dimensional array with _MEM but did not succeed so far.
Does anyone have a clever trick to speed this up?
|
|
|
ASCII Animations |
Posted by: SpriggsySpriggs - 10-21-2023, 07:15 AM - Forum: Programs
- Replies (6)
|
|
Inspired by the thread started by mnrvovrfc (https://qb64phoenix.com/forum/showthread.php?tid=2112), I converted the whole Rick Astley - Never Gonna Give You Up music video to an ASCII animation.
And the code:
Code: (Select All)
Option Explicit
$NoPrefix
Screen NewImage(80, 25)
'You know the rules and so do I
Sleep
Open "B", 1, "rickroll.txt"
Dim As Long x
Dim As String pic, buf
Dim As Long s: s = SndOpen("02 - Rick Astley - Never Gonna Give You Up.flac", "STREAM")
If s Then SndPlay (s)
While Not EOF(1)
For x = 0 To 24
If EOF(1) = 0 Then
Line Input #1, buf
pic = pic + buf
End If
Next
Cls
Print Mid$(pic, 2)
Limit 60
pic = ""
If EOF(1) Then Exit While
Wend
Close
Converted the video like this:
1) Download a GIF or video with plain background, preferably white. In my case, I had to get the green screen version of the music video and then use Kdenlive to make it white.
2) Use ffmpeg to convert the video/GIF into a JPEG image sequence
Code: (Select All) ffmpeg -i rickroll.mkv -vsync 0 rickroll/rickroll_%d.jpg
3) Use a Python script
img2ascii.txt (Size: 3.15 KB / Downloads: 49)
(save as img2ascii.py) in a bash loop to iterate over each frame and convert them into ASCII text files
Code: (Select All) #!/bin/bash
for filename in rickroll/*.jpg; do
sem -j+0 python img2ascii.py --file "$filename" --out rickroll/$(basename "$filename".txt)
done
#you might have to kill this sem call to proceed
sem --wait
cat $(find rickroll/ -name "rickroll_*.jpg.txt" | sort -V) >> rickroll.txt
rm rickroll/rickroll_*.jpg.txt
echo "DONE"
4) Monitor the output of the script. It will tell you how many columns and rows the images are. Set your QB64 up for that many columns and rows for a perfect output!
5) ???
6) Profit
If you don't want to go through all that and just want to run it:
Linux -
rickroll_lnx.zip (Size: 30.2 MB / Downloads: 77)
Windows -
rickroll_win.zip (Size: 30.51 MB / Downloads: 81)
|
|
|
|