<div dir="ltr">hello all, i am trying to design a classic role playing game dialog box that would animate the printing of text one character at a time. Little by little, I have been able to develop this working example, but it doesn't seem to work very well. I am sure part of the problem is that I am calculating local variables over and over again... but that is a symptom of a larger design problem. I have some experience with the HtDP design recipe which I am trying to use intelligently, but sometimes I overdo it and have unnecessary structs within structs, and other times I don't have enough. Some of the data I'm keeping in structs might be better off in a separate global variable. I don't really know the proper way to design something like this. Ideally, this code would end up being able to be used as a module so that one could could use the text-box code with their own dimensions, font, and background. It seems fairly simple, and the metaphor I was trying to use as a model was that of a printer with a print head that moves, and paper to print on. The basic function worked fine, but when trying to add in functionality to do word wrapping, things got a bit messy. I've rewritten a number of times, and was just hoping for some design advice before I start banging my head against the wall. Here's the code:<br>
<div><div><br>#lang racket<br>(require 2htdp/universe 2htdp/image)<br><br>;; current word is a list of chars, string-to-print is a list of strings<br>(struct buffer (current-word string-to-print))<br><br>;; defining a font structure, this is to use with the text/font function<br>
(struct font (size color face family style weight underline?))<br><br>(define terminus-16 (font 16 'white "Terminus" 'system 'normal 'bold #f))<br><br>;; input is a buffer, paper is an image, font is a font, cursor-x and -y are positive integers<br>
(struct text-box (input paper font cursor-x cursor-y))<br><br>(define my-text "Now THIS is the string I'd like to print! Oh my!, it appears to be working. However, there are some errors in my code (such as calling first on an empty list now and then) and it seems to slow down quite a bit.")<br>
<br>(define my-textbox (text-box (buffer empty (string-split my-text))<br> (rectangle 400 300 'solid 'blue)<br> terminus-16 <br> 10 10))<br><br>;; game-print: string font -> image<br>
;; draws string s with the font f<br>(define (game-print s f) <br> (text/font s (font-size f) (font-color f) (font-face f) (font-family f)<br> (font-style f) (font-weight f) (font-underline? f)))<br><br>(define (tick tb)<br>
(next-char tb))<br><br>;; updates the "paper" so that the next character is placed on it, and updates the current-word<br>(define (next-char tb)<br> (define s (buffer-string-to-print (text-box-input tb)))<br>
(define word (buffer-current-word (text-box-input tb)))<br> (define char-width (image-width (game-print " " (text-box-font tb))))<br> (if (empty? word) (next-char (next-word tb))<br> (text-box (buffer (rest word) s)<br>
(place-image (game-print (string (first word)) (text-box-font tb))<br> (text-box-cursor-x tb) (text-box-cursor-y tb)<br> (text-box-paper tb))<br> (text-box-font tb)<br> (+ char-width (text-box-cursor-x tb))<br>
(text-box-cursor-y tb))))<br><br>;; places the next word from the text-box-input's string-to-print into current-word<br>(define (next-word tb)<br> (define x (text-box-cursor-x tb))<br> (define y (text-box-cursor-y tb))<br>
(define s (buffer-string-to-print (text-box-input tb)))<br> (define word (first s))<br> (define word-width (image-width (game-print word (text-box-font tb))))<br> (define char-width (image-width (game-print " " (text-box-font tb))))<br>
(define line-height (+ 5 (image-height (game-print " " (text-box-font tb)))))<br> (define paper-width (image-width (text-box-paper tb)))<br> (cond [(empty? s) tb]<br> ;; this clause determines if we need to start a new line.<br>
[(> (+ x word-width) paper-width) (text-box (buffer (string->list word) (rest s))<br> (text-box-paper tb)<br> (text-box-font tb)<br> 10<br>
(+ line-height (text-box-cursor-y tb)))]<br> [else (text-box (buffer (string->list word) (rest s))<br> (text-box-paper tb)<br> (text-box-font tb)<br> (+ char-width (text-box-cursor-x tb))<br>
(text-box-cursor-y tb))]))<br><br>(define (render tb)<br> (overlay<br> (text-box-paper tb)<br> (empty-scene 500 450 'black))) <br><br>(define (start)<br> (big-bang my-textbox<br> (on-tick next-char)<br>
(to-draw render)))<br><br>(start)<br></div></div></div>