29.08.2013 Views

Grafik i Racket

Grafik i Racket

Grafik i Racket

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Grafik</strong><br />

med <strong>Racket</strong><br />

TDDC74 Mikael Silvén 2013


Dagens föreläsning<br />

Förkunskaper<br />

2D <strong>Grafik</strong><br />

- Grunderna<br />

- Målare och målarduk<br />

- <strong>Grafik</strong> i <strong>Racket</strong><br />

- Två typer av renderingssystem<br />

- Världens enklaste spelmotor<br />

Kort om numerisk integration<br />

Exempelprogram


Förkunskaper<br />

OOP<br />

- <strong>Grafik</strong>biblioteken är objektorienterade<br />

- ((sak 'msg) x), (ask sak 'msg x),<br />

(send sak msg x)<br />

- Arv används för att komma åt input (se pdf)<br />

Samplingsteori<br />

- Vi måste sampla tillräkligt snabbt för att<br />

kunna återskapa animationer.


2D-<strong>Grafik</strong><br />

Pixel<br />

- Picture Element<br />

- Minsta beståndsdelen av en skärm<br />

- Beskrivs med 3 värden, R G B mellan 0-255<br />

Bild<br />

- En mängd pixlar, en bredd, en höjd<br />

- R G B, Kanske A, för alpha/genomskinlighet<br />

2D-<strong>Grafik</strong> är konsten att bygga intressanta<br />

bilder genom att manipulera dess pixlar


2D-<strong>Grafik</strong> II<br />

Super Mario Bros 3 av Nintendo


2D-<strong>Grafik</strong> III


2D-<strong>Grafik</strong> IV


2D-<strong>Grafik</strong> V


2D-<strong>Grafik</strong> VI<br />

Kortfattat<br />

- Målarduken målas på<br />

- Målaren förändrar målarduken<br />

Men kod då?<br />

Instans av canvas% behöver en paint-callback<br />

som får canvas samt drawing-contex som<br />

argument: (define (draw-stuff canvas dc) ...)


Minimalt Exempel<br />

(define *my-window* (new frame%<br />

[width 300] [height 200] [label "En ram"]))<br />

(define (render-fn canvas dc)<br />

(let-values ([(w h) (send canvas get-virtual-size)])<br />

(send dc draw-rectangle 4 4 (- w 8) (- h 8))))<br />

(define *my-canvas* (new canvas%<br />

[parent *my-window*]<br />

[paint-callback render-fn]))<br />

(send *my-window* show #t)


Mer man kan göra?<br />

(send dc draw-rectangle x y width height)<br />

(send dc draw-rounded-rectangle x y width height radius)<br />

(send dc draw-arc x y width height start end)<br />

(send dc draw-ellipse x y width height)<br />

(send dc draw-line x1 y1 x2 y2)<br />

(send dc draw-text text x y)<br />

(send dc set-alpha opacity)<br />

(send dc set-background color)<br />

...<br />

;; Kanske mest intressant<br />

(send dc translate dx dy)<br />

(send dc rotate angle)<br />

(send dc scale x-scale y-scale)<br />

(send dc draw-bitmap source x y)


Måla bilder<br />

(send dc translate x y)<br />

(send dc rotate angle)<br />

(send dc draw-bitmap image<br />

(/ (- (send image get-width)) 2)<br />

(/ (- (send image get-height)) 2))<br />

(send dc rotate (- angle))<br />

(send dc translate (- x) (- y))<br />

// Javakod nedan, visst är det likt?<br />

g.translate(x, y);<br />

g.rotate(angle);<br />

g.drawImage(image, -image.getWidth(null) /2,<br />

-image.getHeight(null)/2, null);<br />

g.rotate(-angle);<br />

g.translate(-x, -y);<br />

// g är ett graphics-objekt, motsvarar dc


<strong>Grafik</strong>motorer<br />

Kod som målar ut saker på skärmen.<br />

För enklare projekt finns det två kategorier:<br />

- Tillståndsmaskiner, måla varje gång du<br />

byter tillstånd. T.ex. efter giltigt drag som svar<br />

på musklick i Schack eller varje gång en figur<br />

förflyttas i Tetris.<br />

- Simuleringar, updatera och måla så ofta<br />

som möjligt. T.ex: När en fågel flyger i Angry<br />

Birds eller en match i FIFA.


<strong>Grafik</strong>motorer II<br />

Kommer inte föreläsa om finita<br />

tillståndsmaskiner<br />

Absoluta majoriteten av spel är av den senare<br />

kategorin<br />

Enklare att implementera animationer<br />

Tekniken är densamma: (send *my-canvas* refresh)


<strong>Grafik</strong>motorer III<br />

Låt oss anta koden från tidigare slide:<br />

(define *my-window* ...)<br />

(define (render-fn ...)<br />

(define *my-canvas* ...)<br />

(send *my-window* show #t)<br />

Lägg nu till:<br />

(define (tick!)<br />

(send *my-canvas* refresh))<br />

(define *my-timer* (new timer% [notify-callback tick!]))<br />

(send *my-timer* start 16) ;; 16 ms intervall ger ~60 FPS


<strong>Grafik</strong>motorer IV<br />

Det händer inte så mycket... Vi provar en<br />

intressantare renderingsfunktion:<br />

(define *angle* 0.0)<br />

(define (render-fn canvas dc)<br />

(send dc translate 50 50)<br />

(send dc rotate *angle*)<br />

(send dc draw-rectangle -25 -25 50 50)<br />

(send dc rotate (- *angle*))<br />

(send dc translate (- 50) (- 50)))<br />

(tick!) blir nu:<br />

(define (tick!)<br />

(set! *angle* (+ *angle* (/ 1 6.28))))<br />

(send *my-canvas* refresh))


<strong>Grafik</strong>motorer V<br />

Resultatet blir en roterande ruta:<br />

Men det är jobbigt ha lägga<br />

till en massa saker såhär...<br />

Tänk istället om vi kapslade<br />

in beteendet för utmålning<br />

Om varje sak kunde uppdatera och måla sig<br />

själv behöver vi bara ha en lista med saker


<strong>Grafik</strong>motorer VI<br />

(define *all-things* '())<br />

(define (make-thing ...)<br />

(define (update) ...)<br />

(define (render canvas dc) ...)<br />

(lambda (cmd)<br />

(cond ((eq? cmd 'update) update)<br />

((eq? cmd 'render) render))))<br />

(define (render-fn canvas dc)<br />

(define (render-one thing)<br />

((thing 'render) canvas dc))<br />

(for-each render-one *all-things*))<br />

(define (tick!)<br />

(define (update-one! thing)<br />

((thing 'update))) ;;Kanske vill skicka med saker här<br />

(for-each update-one! *all-things*)<br />

(send *my-canvas* refresh))


<strong>Grafik</strong>motorer VII<br />

(define (rotating-square x y)<br />

(let ((angle 0))<br />

(define (update)<br />

(set! angle (+ angle (/ 1 6.28))))<br />

(define (render canvas dc)<br />

(send dc translate x y)<br />

(send dc rotate angle)<br />

(send dc draw-rectangle -25 -25 50 50)<br />

(send dc rotate (- angle))<br />

(send dc translate (- x) (- y)))<br />

(define (dispatch cmd)<br />

(cond<br />

((eq? cmd 'update) update)<br />

((eq? cmd 'render) render)))<br />

dispatch))<br />

(set! *all-things* (cons (rotating-square 50 50)<br />

*all-things*))


<strong>Grafik</strong>motorer VIII<br />

Vi har nu grunden till världens enklaste<br />

spelmotor<br />

Koden lite huller om buller, bättre ordning i<br />

fristående pdf<br />

Att lägga till lager och olika skärmar lämnas<br />

som övning<br />

http://commons.wikimedia.org/wiki/File:Parallax-scroll-example-2.png


Simuleringar<br />

De flesta spel är<br />

simuleringar. Saker<br />

händer hela tiden<br />

och objekt måste<br />

uppdateras<br />

P = P + v * dt<br />

v = v + a * dt<br />

a = a + F / m<br />

http://en.wikipedia.org/wiki/Euler_method


Tack för er tid<br />

Frågor?

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!