모바일 오유 바로가기
http://m.todayhumor.co.kr
분류 게시판
베스트
  • 베스트오브베스트
  • 베스트
  • 오늘의베스트
  • 유머
  • 유머자료
  • 유머글
  • 이야기
  • 자유
  • 고민
  • 연애
  • 결혼생활
  • 좋은글
  • 자랑
  • 공포
  • 멘붕
  • 사이다
  • 군대
  • 밀리터리
  • 미스터리
  • 술한잔
  • 오늘있잖아요
  • 투표인증
  • 새해
  • 이슈
  • 시사
  • 시사아카이브
  • 사회면
  • 사건사고
  • 생활
  • 패션
  • 패션착샷
  • 아동패션착샷
  • 뷰티
  • 인테리어
  • DIY
  • 요리
  • 커피&차
  • 육아
  • 법률
  • 동물
  • 지식
  • 취업정보
  • 식물
  • 다이어트
  • 의료
  • 영어
  • 맛집
  • 추천사이트
  • 해외직구
  • 취미
  • 사진
  • 사진강좌
  • 카메라
  • 만화
  • 애니메이션
  • 포니
  • 자전거
  • 자동차
  • 여행
  • 바이크
  • 민물낚시
  • 바다낚시
  • 장난감
  • 그림판
  • 학술
  • 경제
  • 역사
  • 예술
  • 과학
  • 철학
  • 심리학
  • 방송연예
  • 연예
  • 음악
  • 음악찾기
  • 악기
  • 음향기기
  • 영화
  • 다큐멘터리
  • 국내드라마
  • 해외드라마
  • 예능
  • 팟케스트
  • 방송프로그램
  • 무한도전
  • 더지니어스
  • 개그콘서트
  • 런닝맨
  • 나가수
  • 디지털
  • 컴퓨터
  • 프로그래머
  • IT
  • 안티바이러스
  • 애플
  • 안드로이드
  • 스마트폰
  • 윈도우폰
  • 심비안
  • 스포츠
  • 스포츠
  • 축구
  • 야구
  • 농구
  • 바둑
  • 야구팀
  • 삼성
  • 두산
  • NC
  • 넥센
  • 한화
  • SK
  • 기아
  • 롯데
  • LG
  • KT
  • 메이저리그
  • 일본프로야구리그
  • 게임1
  • 플래시게임
  • 게임토론방
  • 엑스박스
  • 플레이스테이션
  • 닌텐도
  • 모바일게임
  • 게임2
  • 던전앤파이터
  • 마비노기
  • 마비노기영웅전
  • 하스스톤
  • 히어로즈오브더스톰
  • gta5
  • 디아블로
  • 디아블로2
  • 피파온라인2
  • 피파온라인3
  • 워크래프트
  • 월드오브워크래프트
  • 밀리언아서
  • 월드오브탱크
  • 블레이드앤소울
  • 검은사막
  • 스타크래프트
  • 스타크래프트2
  • 베틀필드3
  • 마인크래프트
  • 데이즈
  • 문명
  • 서든어택
  • 테라
  • 아이온
  • 심시티5
  • 프리스타일풋볼
  • 스페셜포스
  • 사이퍼즈
  • 도타2
  • 메이플스토리1
  • 메이플스토리2
  • 오버워치
  • 오버워치그룹모집
  • 포켓몬고
  • 파이널판타지14
  • 배틀그라운드
  • 기타
  • 종교
  • 단어장
  • 자료창고
  • 운영
  • 공지사항
  • 오유운영
  • 게시판신청
  • 보류
  • 임시게시판
  • 메르스
  • 세월호
  • 원전사고
  • 2016리오올림픽
  • 2018평창올림픽
  • 코로나19
  • 2020도쿄올림픽
  • 게시판찾기
  • 게시물ID : programmer_16964
    작성자 : 중용자
    추천 : 1
    조회수 : 1154
    IP : 182.228.***.202
    댓글 : 4개
    등록시간 : 2016/04/27 20:30:07
    http://todayhumor.com/?programmer_16964 모바일
    FastASM으로 제작한 테트리스 전체 소스코드
    FastASM에 대한 얘기를 간간이 해왔는데 실제 소스코드는 공개한적이 없어서 FastASM으로 제작한 Tetris의 전체 코드를 올립니다.
    첫버전이 Class를 지원하지 않은 상태에서 만들어진 이후에 Class와 문법변경에 맞춰 테스트 용도로 계속 변경이 되었기에 그다지 좋다고 보기는 힘들지만 제가 만들어온 FastASM이 어떤 것인지 정도는 파악할 수 있지 않을까 합니다.

    아래의 소스에 아이콘등이 포함된 리소스 파일을 합쳐서 컴파일 하면 오유에 예전에 올렸던 테트리스인 10KB 정도의 실행파일이 만들어집니다.
    어셈블러, 컴파일러 개발에 관심이 있거나 기술적으로 궁금한 점 있으면 짧게라도 설명드릴테니 편하게 답글 남기기 바랍니다.


    FastASMTetris.asm
    Compile옵션 및 FastASM의 라이브러리와 전체 코드를 불러오는 일종의 make 역할을 하는 파일입니다.


    include "%FastASM%\Init.inc"
    !_
      Purpose:  FastASM Tetris
    _!

    Option WindowsForms
    Option Resource On
    Option Buffer Memory
    ;Option Debug On
    ;Option Error On
    ;Option DebugProcedure On

    !_
      Purpose:  Header
    _!
    include "%FastASM%\FastASM.inc"
    include "frmMain.inc"

    !_
      Purpose:  Code
    _!
    include "%FastASM%\FastASM.asm"
    include "frmMain.asm"

    Run frmMain

    ; Buffer Type   File size
    ;------------------------
    ; NoBuffer      0000264D
    ; MemoryBuffer  00002F35
    ; BitmapBuffer  0000279C

    ; Compile optimization time
    ; 1, 0.8 0.7 0.6

    frmMain.inc
    클래스와 변수들을 정의한 해더파일입니다.
    변수들이 전역과 Class가 섞여 있는데 초칭기 FastASM은 클래스를 지원하지 않았었기에 전부 전역으로 변수를 정의했었고 Class 지원을 하면서 Class 테스트를 위한 코드 수정을 하다보니 이런 모양이 됐습니다.

    !_
      Purpose:  frmMain
    _!

    TIMER_ID        = 1     ; 타이머 ID
    PADDING_ALL     = 50    ; 상하좌우 여백
    BLOCK_SHADOW    = 3     ; 테트리스 블록 테두리 두께

    Enum eDoBlock, \    ; 블록 출력 , 이동, 저장 구분 열거자
        Paint, Move, Save, Next
    Enum eMove, \       ; 블록 이동 구분 열거자
        Rotate, Left, Right, Down

    MATRIX_SPACE    = 7     ; 테트리스 배열 공백
    MATRIX_GHOST    = 8     ; 테트리스 배열 고스트
    MATRIX_ROWS     = 20    ; 테트리스 배열 높이
    MATRIX_COLS     = 10    ; 테트리스 배열 넓이
    MATRIX_BLOCK    = 30    ; 테트리스 블록 크기

    ; 테트리스 배열 좌표
    MATRIX_LEFT     = PADDING_ALL
    MATRIX_TOP      = PADDING_ALL
    MATRIX_RIGHT    = MATRIX_LEFT + MATRIX_COLS * MATRIX_BLOCK
    MATRIX_BOTTOM   = MATRIX_TOP + MATRIX_ROWS * MATRIX_BLOCK

    BORDER_WIDTH    = 8         ; 테트리스 배열 테두리 두께
    COLOR_BORDER    = $667799   ; 테트리스 배열 테두리 

    Dim BrushBorder As Long := COLOR_BORDER  ; 테트리스 배열 테두리 브러시

    ; 테트리스 배열  테두리 좌표
    Dim RectMatrix  As RECT :=  MATRIX_LEFT, MATRIX_TOP, MATRIX_RIGHT, MATRIX_BOTTOM
    Dim RectBorder  As RECT :=  MATRIX_LEFT - BORDER_WIDTH,     MATRIX_TOP - BORDER_WIDTH, \
                                MATRIX_RIGHT + BORDER_WIDTH,    MATRIX_BOTTOM + BORDER_WIDTH

    TETRIS_FONT_SIZE= 30 ; 출력 폰트 크기
    SCORE_UNIT      = 10 ; 점수 단위
    GOAL_LINE       = 5  ; 레벨당 클리어 라인 시작 개수

    ; 게임 정보 좌표
    INFO_RIGHT      = MATRIX_RIGHT + MATRIX_BLOCK * 5
    Dim RectInfo    As RECT := MATRIX_RIGHT + MATRIX_BLOCK, MATRIX_TOP, INFO_RIGHT, MATRIX_BOTTOM

    ; 0.8초를 시작으로  레벨 12%  속도가 빨라진다. 타이머에서 사용시 4  곱해서 사용한다 .
    Dim abLevelSpeed(20) As Byte := 200,176,155,136,120,106,93,82,72,63,56,49,43,38,33,29,26,23,20,18

    ; 윈도우 클라이언트 크기
    CLIENT_WIDTH    = INFO_RIGHT + PADDING_ALL
    CLIENT_HEIGHT   = MATRIX_BOTTOM + PADDING_ALL

    INIT_BLOCK = 20 ; 초기화면 블록 크기
    ; 초기화면, TETRIS 글자하나의 크기는 3 * 5
    Dim abGameInit(21)(5) As Byte := \
        0,0,0,7,1,1,1,7,0,0,0,7,2,2,7,7,3,7,7,5,5,\
        7,0,7,7,1,7,7,7,7,0,7,7,2,7,2,7,3,7,5,7,7,\
        7,0,7,7,1,1,1,7,7,0,7,7,2,2,7,7,3,7,7,5,7,\
        7,0,7,7,1,7,7,7,7,0,7,7,2,7,2,7,3,7,7,7,5,\
        7,0,7,7,1,1,1,7,7,0,7,7,2,7,2,7,3,7,5,5,7

    ; 초기화면 그래픽 TETRIS 출력용 좌표
    INIT_LEFT   = (CLIENT_WIDTH - (INIT_BLOCK * abGameInit.Cols)) / 2
    INIT_TOP    = CLIENT_HEIGHT / 2 - (INIT_BLOCK * abGameInit.Rows)

    ; 초기화면의 문자열 출력용 좌표
    Dim RectInit    As RECT := 0, INIT_TOP-TETRIS_FONT_SIZE*2, CLIENT_WIDTH,INIT_TOP+TETRIS_FONT_SIZE*12

    ; 블록 종류별 brush, pen        
    Dim aBrushBlock(7)  As Long := $EAEA00,$02FBFF,$00CC30,$FF3101,$FF9933,$3366FF,$CC33CC
    Dim aBrushBorder(7) As Long := $FDB100,$00B9CE,$239841,$B41F00,$D26900,$0026B4,$8A208A

    ; 블록 종류별 모양 데이터
    Dim awBlock(4)(aBrushBlock.Cols) As Short := \
        0000011001100000b,0000011001100000b,0000011001100000b,0000011001100000b,\   ; O
        0000111100000000b,0010001000100010b,0000111100000000b,0010001000100010b,\   ; I
        0000001101100000b,0010001100010000b,0000001101100000b,0010001100010000b,\   ; S
        0000011000110000b,0001001100100000b,0000011000110000b,0001001100100000b,\   ; Z
        0000011101000000b,0010001000110000b,0001011100000000b,0110001000100000b,\   ; L
        0000011100010000b,0011001000100000b,0100011100000000b,0010001001100000b,\   ; J
        0000011100100000b,0010001100100000b,0010011100000000b,0010011000100000b     ; T


    ; 파일 크기를 줄이기 위해 문자열을 1바이트 문자열로 정의한다.
    Dim sGameOver   As StringA :=   "GAME OVER"
    Dim sGamePause  As StringA :=   "PAUSE"
    Dim sGameInfo   As StringA :=   "NEXT",13,13,13,13,13,\
                                    "LEVEL",13,"%d" ,13,13,\
                                    "SCORE",13,"%d" ,13,13,\
                                    "GOAL",13,"%d" ,13,13,\
                                    "HELP",13,"<F1>"
    Dim sGameInit   As StringA :=   "FastASM",13,13,13,13,13,13,13,13,13,13,\
                                    "Press enter key to start"
    Dim sGameHelpTitle As StringA:= "About"
    Dim sGameHelp   As StringA :=   "ENTER",Keys.Tab, "Start",13,\
                                    "ESC",Keys.Tab,"Stop" ,13,\
                                    "PAUSE",Keys.Tab,"Pause" ,13,\
                                    "G",Keys.Tab,"Ghost" ,13,13,\
                                    "UP",Keys.Tab,"Rotate" ,13,\
                                    "LEFT",Keys.Tab,"Move Left" ,13,\
                                    "RIGHT",Keys.Tab,"Move Right" ,13,\
                                    "DOWN",Keys.Tab,"Soft Drop" ,13,\
                                    "SPACE",Keys.Tab,"Hard Drop" ,13,13,\
                                    "http://blog.naver.com/asmpro "

    ; 블록 드랍 소리
    _BLOCK_DROP_INST    = 118
    _BLOCK_DROP_NOTE    = 20
    _BLOCK_DROP_TIME    = 30

    ; 레벨업 소리
    _BLOCK_LEVEL_INST   = 55
    _BLOCK_LEVEL_NOTE   = 50
    _BLOCK_LEVEL_TIME   = 1000

    ;  클리어 소리
    _BLOCK_CLEAR_INST   = 127
    _BLOCK_CLEAR_NOTE   = 10
    _BLOCK_CLEAR_TIME   = 200

    ; 블록 정보
    Class clsBlock
        Dim Type        As Long ; 블록 종류
        Dim NextType    As Long ; 다음 블록 종류
        Dim Rotate      As Long ; 블록 회전 순서
        Dim X           As Long ; 블록 X좌표
        Dim Y           As Long ; 블록 Y좌표
    End Class

    ; 게임 정보
    Enum eGame, \
        Init, Run, Pause, Over
    Class clsGame
        Dim Level       As Long
        Dim Score       As Long
        Dim GoalLine    As Long
        Dim bStatus     As Byte
    End Class

    Class frmMain Form
        Dim Block       As clsBlock
        Dim Game        As clsGame
        Dim bGhost      As Byte
        Dim abMatrix(MATRIX_COLS)(MATRIX_ROWS) As Byte  ; 테트리스 배열
       
        Static FontName As String := "Fixedsys"
        Static Name     As String := "FastASMTetris"
        Static Text     As String := "FastASM Tetris"
    End Class

    frmMain.asm
    클래스 함수를 정의한 코드 파일입니다.
    초창기 클래스는 함수 상속을 지원하지 않았으나 비용없이 상속이 가능하게 구현한 후 상속받은 함수를 사용하기도 합니다.
    코드 부분 또한 클래스를 지원하지 않을 때 제작된 걸 클래스에 맞춰 테스트 용도로 수정한 코드라 객체지향을 제대로 보여주는데는 많이 부족합니다.

    !_
      Purpose:  frmMain
    _!

    Class frmMain
        Sub WindowProc
        Begin
            BEGIN_MSG_MAP
                ON_PAINT
                ON_KEYDOWN
                ON_TIMER
                ON_CREATE
                ON_DESTROY
            END_MSG_MAP
        End Sub

        !_
          Purpose:  생성자
        _!
        Sub Tiny New
        Begin
            Let rMe:WndProc(0)   := frmMain.WindowProc
            Let rMe:psName(0)    := frmMain.Name
            Let rMe:psText(0)    := frmMain.Text

            Let rMe:Style(0)     :=   WS_VISIBLE or \
                                    WS_CAPTION or \
                                    WS_THICKFRAME or \
                                    WS_SYSMENU or \
                                    WS_MAXIMIZEBOX or \
                                    WS_MINIMIZEBOX or \
                                    WS_CLIPCHILDREN or \
                                    WS_CLIPSIBLINGS
            Let rMe:BackColor(0)     := Color.Black
            Let rMe:Cursor(0)        := Cursors.Default
            Let rMe:Icon(0)          := IDI_FASTASMTETRIS

            Let  rMe:BitmapFont(0)    := Font.Bitmap.Default
            Let  rMe:BitmapFontSize(0):= 2
            ;Let rMe:psFontName(0)    := frmMain.FontName
            ;Let rMe:FontSize(0)      := TETRIS_FONT_SIZE
            Let rMe:ForeColor(0)     := Color.White
           
            Let rTemp := CW_USEDEFAULT
            Let rMe:Left(0)          := rTemp
            Let rMe:Top(0)           := rTemp

            Let rMe:iClientWidth(0)  := CLIENT_WIDTH
            Let rMe:iClientHeight(0) := CLIENT_HEIGHT

            Let rMe:bBufferMode(0)   := eBufferMode.Fit
            Let rMe:BufferWidth(0)   := CLIENT_WIDTH
            Let rMe:BufferHeight(0)  := CLIENT_HEIGHT
           
            ; Class
            Let rMe:bGhost(0)    := True
        End Sub

        !_
          Purpose:  사용할 자원을 생성한다.
        _!
        Sub frmMain_CREATE
            Dim .rLoop  As Long rbx
        Begin
            ; 미디출력을 준비한다 .
            Midi.Out.Open

    if Project.Buffer <> eDoubleBuffer.Memory
            ; brush pen  생성한다 .
            Get BrushBorder(0) := Brush.Solid BrushBorder(0)
            For Each .rLoop In aBrushBlock
                Get aBrushBorder(.rLoop):= Brush.Solid aBrushBorder(.rLoop)
                Get aBrushBlock(.rLoop) := Brush.Solid aBrushBlock(.rLoop)
            Next
    end if
        End Sub

        !_
          Purpose:  사용한 자원을 반환하고 종료한다.
        _!
        Sub frmMain_DESTROY
            Dim .rLoop  As Long rbx
        Begin
            ; 미디출력을 종료한다 .
            Midi.Out.Close

    if Project.Buffer <> eDoubleBuffer.Memory
            ; 사용한 brush  pen 해제한다.
            Brush.Dispose BrushBorder(0)
            For Each .rLoop In aBrushBlock
                Brush.Dispose   aBrushBorder(.rLoop)
                Brush.Dispose   aBrushBlock(.rLoop)
            Next
    end if
            Application.Exit
        End Sub

        !_
          Purpose:  키입력을 처리한다 .
        _!
        Sub frmMain_KEYDOWN, .Key, .KeyData
            Dim .rbKey  As Byte rParam1L
        Begin
            Select .rbKey
                Case Keys.F1        ; 도움말
                    MessageBoxA.Show sGameHelp, sGameHelpTitle
                Case Keys.Escape    ; 게임 종료
                    If rMe:Game.bStatus(0) = eGame.Init
                        Me OnClose
                        Return
                    Else If rMe:Game.bStatus(0) = eGame.Run
                        Timer.Stop TIMER_ID
                    End If
                    Let rMe:Game.bStatus(0) := eGame.Init
                    Me Refresh
                Case Keys.Enter     ; 게임 시작
                    Me StartGame
                Case Keys.Pause     ; 게임 정지
                    If rMe:Game.bStatus(0) = eGame.Run
                        Let rMe:Game.bStatus(0) := eGame.Pause
                        Timer.Stop TIMER_ID
                    Else If rMe:Game.bStatus(0) = eGame.Pause
                        Let rMe:Game.bStatus(0) := eGame.Run
                        Me StartTimer
                    End If
                    Me Refresh
                Case "G"
                    Let rMe:bGhost(0) ^= 1
                    Me Refresh
                Case Keys.Up        ; 블록 회전
                    Me MoveBlock, eMove.Rotate
                Case Keys.Down      ; 블록 아래
                    Me MoveBlock, eMove.Down
                Case Keys.Left      ; 블록 왼쪽
                    Me MoveBlock, eMove.Left
                Case Keys.Right     ; 블록 오른쪽
                    Me MoveBlock, eMove.Right
                Case Keys.Space     ; 블록 바닥
                    If rMe:Game.bStatus(0) = eGame.Run
                        Me DropBlock
                        If rRetL = False Return
                        Me SaveBlock
                    End If
            End Select
        End Sub

        !_
          Purpose:  WM_TIMER, 오직 블록을 아래로 내릴 때만 이벤트가 발생한다.
        _!
        Sub frmMain_TIMER, .TimerID
        Begin
            Me MoveBlock, eMove.Down
        End Sub

        !_
          Purpose:  타이머를 실행한다 . 블록이 떨어지는 속도는 레벨당 1 바이트로 저장하기 위해
                    밀리세컨드 / 4 단위로 저장되어 있다 . 읽은  4 곱해서 타이머를 실행한다 .
        _!
        Sub StartTimer
        Begin
            Le3 rTemp   := rMe:Game.Level(0) --1; 레벨은 1부터 , 레벨속도 데이터는 0부터 시작하기 때문에
                                                ; 레벨에서 1  뺀후 데이터를 읽는다.
            Let rTemp   <= abLevelSpeed(rTemp)
            Let rTemp   <<= 2
            Timer.Start TIMER_ID, rTemp
        End Sub

        !_
          Purpose:  게임화면을 출력한다.
        _!
        Sub frmMain_PAINT, .e As rbx
        Begin
            ; 배경을 지운다.
            Graphics.Clear .e

            ; 시작화면 또는 실행화면을 출력한다.
            If rMe:Game.bStatus(0) = eGame.Init
                Me PaintMatrix, .e, abGameInit, abGameInit.Cols - 1, abGameInit.Rows - 1, \
                    INIT_LEFT, INIT_TOP, INIT_BLOCK
                Graphics.DrawStringA .e, sGameInit, sGameInit.Length, RectInit, DT_CENTER
            Else
                Me PaintGame, .e
            End If
           
            Let rRet := 0
        End Sub

        !_
          Purpose:  실행화면을 출력한다.   
        _!
        Sub PaintGame, .e As rbx
            Dim .rGhost As Long r12
            Dim .sBuffer(sGameInfo.Length + 30) As Char
        Begin
            ; 테트리스 배열 테두리를 그린다.
            Graphics.FillRectangle .e, BrushBorder(0), RectBorder
            Graphics.FillRectangle .e, rMe:hBackColor(0), RectMatrix
           
            ; 테트리스 배열을 그린다 .
            Me PaintMatrix, .e, ByRef rMe:abMatrix(0),frmMain.abMatrix.Cols-1,frmMain.abMatrix.Rows-1,\
                MATRIX_LEFT, MATRIX_TOP, MATRIX_BLOCK

            ; 고스트를 출력한다.
            If rMe:bGhost(0) <> False And rMe:Game.bStatus(0) = eGame.Run
                Let .rGhost := rMe:Block.Y(0)
                Me DropBlock
                Me DoBlock, .e, eDoBlock.Paint, True
                Let rMe:Block.Y(0) := .rGhost
            End If

            Me DoBlock, .e, eDoBlock.Next, False   ; 다음 블록을 출력한다 .
            Me DoBlock, .e, eDoBlock.Paint, False  ; 블록을 출력한다.

            ; 정지 또는 게임오버시 문자열을 출력한다.
            Let rParam2 := 0
            If rMe:Game.bStatus(0) = eGame.Over
                Let rParam2 := sGameOver
                Let rParam3 := sGameOver.Length
            Else If rMe:Game.bStatus(0) = eGame.Pause
                Let rParam2 := sGamePause
                Let rParam3 := sGamePause.Length
            End If
            If rParam2 <> 0
                Graphics.DrawStringA .e, rParam2, rParam3, RectBorder, \
                    DT_CENTER or DT_VCENTER or DT_SINGLELINE
            End If

            ; 게임 진행상황을 출력한다.
            String.FormatA ByRef .sBuffer(0), sGameInfo, rMe:Game.Level(0), rMe:Game.Score(0), \
                rMe:Game.GoalLine(0)
            Graphics.DrawStringA .e, ByRef .sBuffer(0), rRet, RectInfo, DT_CENTER
        End Sub

        !_
          Purpose:  게임을 시작한다 .
        _!
        Sub StartGame
        Begin
            If rMe:Game.bStatus(0) <> eGame.Run
                ; 데이터를 초기화한다 .
                Array.Clear rMe:abMatrix, 0, 0, MATRIX_SPACE

                Let rTemp := 0
                Let rMe:Game.Level(0)    := 1
                Let rMe:Game.GoalLine(0) := GOAL_LINE
                Let rMe:Game.Score(0)    := rTemp
                Let rMe:Block.NextType(0):= rTemp
                Let rMe:Game.bStatus(0)   := eGame.Run

                ; 타이머를 실행한다.
                Me StartTimer

                ; 블록을 생성한다.
                Get rMe:Block.NextType(0) := Me CreateBlockType
                Me CreateBlock
            End If
        End Sub

        !_
          Purpose:  배열을 출력한다 .
        _!
        Sub PaintMatrix, .e As r14, .pbMatrix, .Cols, .Rows, .Left, .Top, .Size
            Dim .rIndex As Long rbx
            Dim .rCols  As Long rdi
            Dim .rRows  As Long r13
            Dim .rX     As Long rsi
            Dim .rY     As Long r12
        Begin
            Let .rIndex := .pbMatrix
            Let .rCols  := .Cols
            Let .rRows  := .Rows
            For .rY = 0 To .rRows
                For .rX = 0 To .rCols
                    Let rTemp <= byte [.rIndex]
                    If rTempL <> MATRIX_SPACE
                        Me PaintSquare, .e, rTemp, .rX, .rY, .Left(0), .Top(0), .Size(0), False
                    End If
                    Let .rIndex++
                Next
            Next
        End Sub
       
        !_
          Purpose:  블록의 사각형 하나를 출력한다.
        _!
        Sub PaintSquare, .e As r12, .Color, .X, .Y, .Left, .Top, .Size, .IsGhost
            Dim .rLeft  As Long rdi
            Dim .rTop   As Long rsi
            Dim .rColor As Long r13
            Dim .rSize  As Long rbx
        Begin
            If .X >= 0 And .Y >=0
                Let .rColor := .Color
                Let .rSize  := .Size(0)

                Le3 .rLeft  := .X ** .rSize
                Let .rLeft  += .Left(0)
                Le3 .rTop   := .Y ** .rSize
                Let .rTop   += .Top(0)

                Graphics.DrawRectangle .e, aBrushBorder(.rColor), .rLeft, .rTop, \
                    ByRef [.rLeft + .rSize], ByRef [.rTop + .rSize]
                Let rTemp := rMe:hBackColor(0)
                If .IsGhost(0) = False Then rTemp := aBrushBlock(.rColor)
                Graphics.DrawRectangle .e, rTemp, ByRef [.rLeft+BLOCK_SHADOW], ByRef [.rTop+BLOCK_SHADOW],\
                    ByRef [.rLeft + .rSize - BLOCK_SHADOW], ByRef [.rTop + .rSize - BLOCK_SHADOW]
            End If
        End Sub
       
        !_
          Purpose:  블록 타입을 랜덤하게 생성한다.
        _!
        Sub Tiny CreateBlockType
            Dim .riBlockTypeCount   As Long ecx
            Dim .riBlockType        As Long edx
        Begin
            Random.Int
            Let .riBlockTypeCount   := awBlock.Rows
            div .riBlockTypeCount
            Let rRet    := 0
            Let rRetE   := .riBlockType
        End Sub

        !_
          Purpose:  블록을 생성한다 .
        _!
        Sub CreateBlock
            Dim .rBlockType As Long rcx
        Begin
            ; 같은 블록이 3 연속해서 나오지 않도록 한다.
            Do
                Me CreateBlockType
            Loop Until rRet <> rMe:Block.NextType(0) Or rRet <> rMe:Block.Type(0)
            Let .rBlockType          := rRet
            Let rMe:Block.Type(0)    := rMe:Block.NextType(0)
            Let rMe:Block.NextType(0):= .rBlockType
            Let rMe:Block.Rotate(0)  := 0
            Let rMe:Block.Y(0)       := -1
            Let rMe:Block.X(0)       := (frmMain.abMatrix.Cols - 4) / 2
           
            ; 블록을 생성할 자리가 없으면 게임을 종료한다 .
            Me DoBlock, 0, eDoBlock.Move, False

            If rRetL = False
                Let rMe:Game.bStatus(0) := eGame.Over
                Timer.Stop TIMER_ID
            End If
            Me Refresh
        End Sub
       
        !_
          Purpose:  블록을 출력하거나 이동 가능을 검토하거나 테트리스 배열에 저장한다 .
          Returns:  True- 이동가능, False- 이동불가
        _!
        Sub DoBlock, .e As r13, .Mod, .IsGhost As r15
            Dim .rX             As Long rsi   ; 블록 사각형 X좌표
            Dim .rY             As Long rdi   ; 블록 사각형 Y좌표
            Dim .rBlockType     As Long rcx   ; 블록 타입
            Dim .rBlockTypeL    As Byte cl    ; 블록 타입 ( 테트리스 배열 저장용 1 바이트 변수)
            Dim .rBlockRotate   As Long rdx   ; 블록 회전
            Dim .rwBlock        As Short r14w ; 블록 데이터
            Dim .rBlockCol      As Long r12   ; 블록 모양을 읽어오기 위한 루프
            Dim .rbBlockRow     As Byte bh
            Dim .rbMode         As Byte bl
        Begin       
            Let .rbMode     := CByte .Mod

            If .rbMode = eDoBlock.Next
                Let .rY             := 0
                Let .rBlockType     := rMe:Block.NextType(0)
                Let .rBlockRotate   := 0
            Else
                Let .rY             := rMe:Block.Y(0)
                Let .rBlockType     := rMe:Block.Type(0)
                Let .rBlockRotate   := rMe:Block.Rotate(0)
            End If
            Let .rwBlock := awBlock(.rBlockRotate)(.rBlockType)
           
            For .rbBlockRow = 0 To 3
                Let .rX := rMe:Block.X(0)
                For .rBlockCol = 0 To 3
                    Let .rwBlock <<= 1
                    If CARRY?
                        Select .rbMode
                            Case eDoBlock.Paint  ; 블록을 출력한다.
                                Me PaintSquare, .e, rMe:Block.Type(0), .rX, .rY, \
                                    MATRIX_LEFT, MATRIX_TOP, MATRIX_BLOCK, .IsGhost

                            Case eDoBlock.Next   ; 다음 블록을 출력한다 .
                                ; TODO: 테트리스 타입에 따라 출력하는 위치를 하드코딩으로 조정했다 .
                                ;       블록 모양이 변경되면 수정해야 한다.
                                Let rTemp   := 0
                                Let rTempE  := RectInfo.left(0)
                                If rMe:Block.NextType(0) > 1
                                    Let rTempE -= MATRIX_BLOCK / 2
                                End If
                                Me PaintSquare, .e, rMe:Block.NextType(0), .rBlockCol, .rY, \
                                    rTemp, MATRIX_TOP + TETRIS_FONT_SIZE, MATRIX_BLOCK, False
                               
                            Case eDoBlock.Move   ; 블록을 이동할  있는지 검토한다.
                                If .rY >= 0
                                    If .rX>=frmMain.abMatrix.Cols Or .rX<0 Or .rY>=frmMain.abMatrix.Rows
                                        GoTo .CantMove
                                    End If
                                    If rMe:abMatrix(.rX)(.rY) <> MATRIX_SPACE GoTo .CantMove
                                End If
                               
                            Case eDoBlock.Save   ; 블록을 테트리스 배열에 저장한다.
                                Let rMe:abMatrix(.rX)(.rY) := .rBlockTypeL
                        End Select 
                    End If
                    Let .rX++
                Next
                Let .rY++
            Next

            Let rRetL := True
            Return

        .CantMove:
            Let rRetL := False
        End Sub
       
        !_
          Purpose:  블록을 이동시킨다 .
        _!
        Sub MoveBlock, .Direction
            Dim .rbDirection    As Byte bl
            Dim .rBlockX        As Long rdi
            Dim .rBlockY        As Long rsi
            Dim .rBlockRotate   As Long r12
        Begin
            If rMe:Game.bStatus(0) <> eGame.Run Return

            Let .rbDirection    := CByte .Direction
            Let .rBlockX        := rMe:Block.X(0)
            Let .rBlockY        := rMe:Block.Y(0)     
            Let .rBlockRotate   := rMe:Block.Rotate(0)

            Select .rbDirection
                Case eMove.Rotate
                    Let rMe:Block.Rotate(0)++
                    Let rMe:Block.Rotate(0) %= awBlock.Cols
                Case eMove.Left
                    Let rMe:Block.X(0)--
                Case eMove.Right
                    Let rMe:Block.X(0)++
                Case eMove.Down
                    Let rMe:Block.Y(0)++
            End Select

            Me DoBlock, 0, eDoBlock.Move, False

            If rRetL = False
                Let rMe:Block.X(0)      := .rBlockX
                Let rMe:Block.Y(0)      := .rBlockY
                Let rMe:Block.Rotate(0) := .rBlockRotate

                If .rbDirection = eMove.Down
                    Me SaveBlock
                End If
            Else
                Me Refresh
            End If
        End Sub

        !_
          Purpose:  블록을 떨어뜨린다 .
        _!
        Sub DropBlock
        Begin
            ; 블록을 떨어뜨린다 .
            For rMe:Block.Y(0) To frmMain.abMatrix.Rows - 1
                Me DoBlock, 0, eDoBlock.Move, False
                If rRetL = False Exit For
            Next
            Let rMe:Block.Y(0)--

            ; 시작위치부터 블록을 내릴수 없으면 게임을 종료한다.
            Let rRetL := True
            If rMe:Block.Y(0) < 0
                Let rMe:Game.bStatus(0) := eGame.Over
                Timer.Stop TIMER_ID
                Let rRetL := False
            End If
        End Sub
       
        !_
          Purpose:  블록을 저장하고 클리어한다.
        _!
        Sub SaveBlock
            Dim .rIndex     As Long r12
            Dim .rX         As Long rdi
            Dim .rSource    As Long rsi
            Dim .rDest      As Long rdi
            Dim .rScore     As Long rbx
        Begin
            ; 블록을 저장한다.
            Me DoBlock, 0, eDoBlock.Save, False

            ; 완성된 줄을 지운다 .
            ; 블록의 크기는 4칸이므로 블록이 저장된 위치부터 아래로 4 칸까지 검토하고 지운다 .
            Let .rScore := SCORE_UNIT

            Le3 .rIndex := rMe:Block.Y(0) ** frmMain.abMatrix.Cols
            For rMe:Block.Y(0) To frmMain.abMatrix.Rows - 1
                Let rTemp := 0
                For .rX = 0 To frmMain.abMatrix.Cols-1
                    If rMe:abMatrix(.rIndex) < MATRIX_SPACE
                        Let rTemp++
                    End If
                    Let .rIndex++
                Next

                If rTemp = frmMain.abMatrix.Cols
                    ; 완성된 줄을 지운다 .
                    Let rDest   := ByRef rMe:abMatrix(.rIndex - 1)
                    Le3 rSource := rDest -- frmMain.abMatrix.Cols
                    Le3 rCount  := rMe:Block.Y(0) ** frmMain.abMatrix.Cols
                    std
                    rep movsb
                    cld

                    ;  윗줄을 지운다 .
                    Array.Clear rMe:abMatrix, 0, frmMain.abMatrix.Cols, MATRIX_SPACE

                    ; ; 점수를 증가시킨다 . 점수 획득은 2 배수로 증가한다.
                    Let rMe:Game.Score(0) += .rScore
                    Let .rScore *= 2

                    ; 레벨마다 할당된 줄을 클리어하면 레벨을 높인다.
                    Let rMe:Game.GoalLine(0)--
                    If rMe:Game.GoalLine(0) = 0
                        Le3 rMe:Game.GoalLine(0) := rMe:Game.Level(0) ++ GOAL_LINE
                        If rMe:Game.Level(0) < abLevelSpeed.Length
                            Let rMe:Game.Level(0)++
                            Timer.Stop TIMER_ID
                            Me StartTimer
                            Midi.Out.Play _BLOCK_LEVEL_INST, _BLOCK_LEVEL_NOTE, _BLOCK_LEVEL_TIME
                        End If
                    End If
                End If
            Next

            If .rScore = SCORE_UNIT
                Midi.Out.Play _BLOCK_DROP_INST, _BLOCK_DROP_NOTE, _BLOCK_DROP_TIME
            Else
                Midi.Out.Play _BLOCK_CLEAR_INST, _BLOCK_CLEAR_NOTE, _BLOCK_CLEAR_TIME
            End If

            ;  블록을 생성한다 .
            Me CreateBlock
        End Sub
    End Class

    이 게시물을 추천한 분들의 목록입니다.
    [1] 2016/04/29 08:10:35  121.139.***.69  흠ㅁ  273530
    푸르딩딩:추천수 3이상 댓글은 배경색이 바뀝니다.
    (단,비공감수가 추천수의 1/3 초과시 해당없음)

    죄송합니다. 댓글 작성은 회원만 가능합니다.

    번호 제 목 이름 날짜 조회 추천
    23458
    [KOCCA] 2024 게임콘텐츠 제작지원 이용자평가 체험단모집 장파랑 24/11/26 16:56 179 0
    23457
    [한국콘텐츠진흥원] 2024 게임콘텐츠 제작지원 이용자평가 이용자 모집 장파랑 24/11/18 14:02 301 0
    23456
    [한국콘텐츠진흥원] 2024 게임콘텐츠 제작지원 이용자평가 이용자 모집 장파랑 24/10/28 18:24 742 0
    23455
    논문 읽는 사람들을 위한 문서 번역 서비스 rWhale 24/10/10 13:06 1057 2
    23453
    로또번호 [2] 까망사투리 24/09/19 11:10 1501 2
    23452
    AI와 함께가는 코딩 업계 [1] 펌글 우가가 24/09/02 22:19 1903 9
    23451
    Switch문 도배된 2100줄 짜리 함수 [3] 펌글 우가가 24/08/26 22:37 1803 4
    23450
    개인정보 수집 없는 이미지 리사이즈 사라밍 24/08/23 20:31 1312 0
    23449
    디자인 패턴의 템플릿 메소드 패턴 실무 적용 사례 써니썬 24/08/23 16:47 1322 1
    23448
    TMDB API Key 얻을 때 동의하게 되는 면책 및 포기 조항 우가가 24/08/18 16:07 1334 1
    23447
    펌) 아무튼 개쩌는 번역기를 국내기술로 개발완료 했다는 소식 [1] 펌글 우가가 24/08/15 17:30 1593 2
    23446
    쿠팡 가격 변동 추적 알림 서비스 피드백 요청 (제발) 창작글펌글 애오옹 24/08/10 14:30 1496 0
    23445
    넥사크로 17.1 관련 [2] 본인삭제금지 나르하나 24/08/01 12:30 1536 0
    23444
    개밯자 의자에 머리받침 없어 [1] 까망사투리 24/07/25 13:32 1856 1
    23443
    안드로이드 EditText 리스너 연동 문의드립니다. - 해결됨 [1] 창작글 상사꽃 24/07/01 17:47 1797 2
    23442
    펌) 파이어폭스 엔진이 신인 이유 [1] 펌글 우가가 24/06/30 23:25 2376 2
    23441
    예전에는 함수 하나에 대한 기능에 고민을 많이 했는데.. ssonacy 24/05/21 09:45 2173 0
    23440
    c++ 에서 DB 쿼리문처럼 사용할 방법이 있을까요? [8] 상사꽃 24/05/19 11:10 2322 0
    23439
    쉬운 배터리 알림 창작글 언젠가아자 24/05/14 10:47 2467 0
    23438
    아후 서터레스 [1] NeoGenius 24/04/02 17:52 2157 1
    23436
    로또 [3] 까망사투리 24/03/11 15:53 2792 4
    23434
    copilot 기업유료버전 intelliJ에 붙여서 쓰고있는데 지리네요 안녕월드 24/02/22 00:15 2829 0
    23433
    코딩마을 대나무숲 [6] cocoa 24/02/20 14:50 2996 5
    23432
    (질문) 프로그래머분들은 싱글PC게임 레벨제한 풀수 있죠?? [23] 본인삭제금지 할배궁디Lv2 24/02/13 13:36 2996 1
    23431
    Freemium NeoGenius 24/02/13 13:23 2456 0
    23429
    부산에서 프로그래머 구인하는데 연봉 6천에서 8천 작은건가 [3] 폴팡 24/02/04 20:50 3314 1
    23427
    chatgpt? bard? [4] 별빛러브 24/01/25 06:24 2597 0
    23426
    Next.js로 만들어봤어요~ [2] 창작글 sonnim 24/01/24 12:52 2811 3
    23425
    Spring Boot 공부하기 - 한국투자증권 오픈API 호출 옐로우황 24/01/21 17:51 2833 1
    23424
    파이썬 코딩 관련해서 질문드립니다. [5] 투투나 24/01/08 09:49 2917 0
    [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [다음10개▶]
    단축키 운영진에게 바란다(삭제요청/제안) 운영게 게시판신청 자료창고 보류 개인정보취급방침 청소년보호정책 모바일홈