Войти
BASIC[ProjectYaga]Форум

Реализация игры Match3

#0
(Правка: 13:08) 13:00, 11 янв. 2021
test game match3 | Реализация игры Match3
#include <SFML/Graphics.hpp>
'#include <SFML/Audio.hpp>


CONST GAMEWIDTH AS INTEGER = 640
CONST GAMEHEIGHT AS INTEGER = 480

CONST CENTERTILE AS INTEGER = 16
CONST SIZETILE AS INTEGER = 32
CONST FLIPSPEED AS INTEGER = 2'8
CONST MAPSIZEX AS INTEGER = 8
CONST MAPSIZEY AS INTEGER = 14
CONST MAPPOSITIONX AS INTEGER = 192
CONST MAPPOSITIONY AS INTEGER = 16

DIM map[MAPSIZEX][MAPSIZEY] AS INTEGER

DIM t1x AS INTEGER
DIM t1y AS INTEGER
DIM t2x AS INTEGER
DIM t2y AS INTEGER
DIM selection_done AS INTEGER = 0 
DIM mouse_left_state AS INTEGER
DIM mouse_position AS sf.Vector2i
DIM mx AS INTEGER 'For test
DIM my AS INTEGER 'For test
DIM helpx AS INTEGER = -1
DIM helpy AS INTEGER = -1

DIM SCORE AS LONG = 0
DIM LEVEL AS INTEGER = 7 'min = 7; max = 16
DIM GameOver AS BOOLEAN = FALSE

FUNCTION pred(BYVAL mapx AS INTEGER, BYVAL mapy AS INTEGER, BYVAL t AS INTEGER) AS BOOLEAN

  IF mapx >= 0 AND mapx <= MAPSIZEX - 1 THEN
    IF mapy >= 0 AND mapy <= MAPSIZEY - 1 THEN
      IF t = map[mapx][mapy] THEN
        RETURN TRUE
      END IF
    END IF
  END IF
  RETURN FALSE
  
END FUNCTION


FUNCTION EndGame() AS BOOLEAN

  DIM x AS INTEGER
  DIM y AS INTEGER
  DIM t AS INTEGER
  FOR y = 0 TO MAPSIZEY - 1
    FOR x = 0 TO MAPSIZEX - 1
      t = map[x][y]
      IF t = 0 THEN
        helpx = -1
        helpy = -1
        RETURN FALSE
      END IF
      IF pred(x, y + 1, t) = TRUE THEN
        IF pred(x, y + 3, t) = TRUE THEN
          helpx = x
          helpy = y + 3
          RETURN FALSE
        END IF
        IF pred(x - 1, y + 2, t) = TRUE THEN
          helpx = x - 1
          helpy = y + 2
          RETURN FALSE
        END IF
        IF pred(x + 1, y + 2, t) = TRUE THEN
          helpx = x + 1
          helpy = y + 2
          RETURN FALSE
        END IF
        IF pred(x, y - 2, t) = TRUE THEN
          helpx = x
          helpy = y - 2
          RETURN FALSE
        END IF
        IF pred(x - 1, y - 1, t) = TRUE THEN
          helpx = x - 1
          helpy = y - 1
          RETURN FALSE
        END IF
        IF pred(x + 1, y - 1, t) = TRUE THEN
          helpx = x + 1
          helpy = y - 1
          RETURN FALSE
        END IF
      END IF
      IF pred(x, y + 2, t) = TRUE THEN
        IF pred(x - 1, y + 1, t) = TRUE THEN
          helpx = x - 1
          helpy = y + 1
          RETURN FALSE
        END IF
        IF pred(x + 1, y + 1, t) = TRUE THEN
          helpx = x + 1
          helpy = y + 1
          RETURN FALSE
        END IF
      END IF
      IF pred(x + 1, y, t) = TRUE THEN
        IF pred(x + 3, y, t) = TRUE THEN
          helpx = x + 3
          helpy = y
          RETURN FALSE
        END IF
        IF pred(x + 2, y - 1, t) = TRUE THEN
          helpx = x + 2
          helpy = y - 1
          RETURN FALSE
        END IF
        IF pred(x + 2, y + 1, t) = TRUE THEN
          helpx = x + 2
          helpy = y + 1
          RETURN FALSE
        END IF
        IF pred(x - 2, y, t) = TRUE THEN
          helpx = x - 2
          helpy = y
          RETURN FALSE
        END IF
        IF pred(x - 1, y - 1, t) = TRUE THEN
          helpx = x - 1
          helpy = y - 1
          RETURN FALSE
        END IF
        IF pred(x - 1, y + 1, t) = TRUE THEN
          helpx = x - 1
          helpy = y + 1
          RETURN FALSE
        END IF
      END IF
      IF pred(x + 2, y, t) = TRUE THEN
        IF pred(x + 1, y - 1, t) = TRUE THEN
          helpx = x + 1
          helpy = y - 1
          RETURN FALSE
        END IF
        IF pred(x + 1, y + 1, t) = TRUE THEN
          helpx = x + 1
          helpy = y + 1
          RETURN FALSE
        END IF
      END IF
    NEXT x
  NEXT y
  helpx = -1
  helpy = -1
  RETURN TRUE
  
END FUNCTION


FUNCTION CountTile(BYVAL x AS INTEGER, BYVAL y AS INTEGER, BYVAL ty AS INTEGER, BYVAL dir AS INTEGER, BYREF cn AS INTEGER) AS BOOLEAN

  cn = 0
  SELECT CASE dir
    CASE 0 'Up
      DO WHILE (y > 0)
        IF map[x][y] = ty THEN
          cn = cn + 1
        ELSE
          RETURN (cn > 2)
        END IF
        y = y - 1
      LOOP
      RETURN (cn > 2)
    CASE 1 'Right
      DO WHILE (x < MAPSIZEX)
        IF map[x][y] = ty THEN
          cn = cn + 1
        ELSE
          RETURN (cn > 2)
        END IF
        x = x + 1
      LOOP
      RETURN (cn > 2)
    CASE 2 'Down
      DO WHILE (y < MAPSIZEY)
        IF map[x][y] = ty THEN
          cn = cn + 1
        ELSE
          RETURN (cn > 2)
        END IF
        y = y + 1
      LOOP
      RETURN (cn > 2)
    CASE 3 'Left
      DO WHILE (x > 0)
        IF map[x][y] = ty THEN
          cn = cn + 1
        ELSE
          RETURN (cn > 2)
        END IF
        x = x - 1
      LOOP
      RETURN (cn > 2)
  END SELECT
  cn = 0
  RETURN FALSE

END FUNCTION


FUNCTION CausesPop() AS BOOLEAN

  DIM x AS INTEGER
  DIM y AS INTEGER
  DIM tl AS INTEGER
  DIM tlc AS INTEGEr 

  FOR y = 0 TO MAPSIZEY - 1
    FOR x = 0 TO MAPSIZEX - 1
      tl = map[x][y]
      IF tl > 0 THEN
        IF CountTile(x, y, tl, 0, tlc) THEN
          RETURN TRUE
        ELSE
          IF CountTile(x, y, tl, 1, tlc) THEN
            RETURN TRUE
          ELSE
            IF CountTile(x, y, tl, 2, tlc) THEN
              RETURN TRUE
            ELSE
              IF CountTile(x, y, tl, 3, tlc) THEN
                RETURN TRUE
              END IF
            END IF
          END IF
        END IF
      END IF
    NEXT x
  NEXT y
  RETURN FALSE
  
END FUNCTION


FUNCTION Switch(BYVAL x0 AS INTEGER, BYVAL y0 AS INTEGER, BYVAL x1 AS INTEGER, BYVAL y1 AS INTEGER) AS BOOLEAN

  DIM a AS INTEGER
  a = map[x0][y0]
  map[x0][y0] = map[x1][y1]
  map[x1][y1] = a
  IF CausesPop() = TRUE THEN 
    RETURN TRUE
  END IF
  a = map[x0][y0]
  map[x0][y0] = map[x1][y1]
  map[x1][y1] = a
  RETURN FALSE
  
END FUNCTION


SUB UpdateSelection(BYVAL mpx AS INTEGER, BYVAL mpy AS INTEGER, BYVAL isButtonPressed AS BOOLEAN)

  IF mpx >= MAPPOSITIONX AND mpx <= MAPPOSITIONX + (SIZETILE * MAPSIZEX) THEN
    IF mpy >= MAPPOSITIONY AND mpy <= MAPPOSITIONY + (SIZETILE * MAPSIZEY) THEN
      DIM dx AS INTEGER
      DIM dy AS INTEGER
      IF (isButtonPressed = TRUE) THEN
        mx = INT((mpx - MAPPOSITIONX) / SIZETILE)
        my = INT((mpy - MAPPOSITIONY) / SIZETILE)
        SELECT CASE mouse_left_state
          CASE 0
            t1x = mx
            t1y = my
            mouse_left_state = 1
          CASE 2
            t2x = mx
            t2y = my
            mouse_left_state = 3
        END SELECT
      ELSE
        SELECT CASE mouse_left_state
          CASE 1
            mouse_left_state = 2
          CASE 3
            dx = MATH.ABS(t2x - t1x)
            dy = MATH.ABS(t2y - t1y)
            IF dx = 1 AND dy = 0 THEN
              selection_done = 1
            ELSE
              IF dx = 0 AND dy = 1 THEN
                selection_done = 1
              END IF
            END IF
            mouse_left_state = 0
            IF (dx > 1 OR dy > 1) OR (dx = 0 AND dy = 0) OR (dx = 1 AND dy = 1) THEN
              mouse_left_state = 1
              t1x = t2x
              t1y = t2y
            END IF
        END SELECT
      END IF
    END IF
  END IF

END SUB


SUB KillTiles(BYVAL x AS INTEGER, BYVAL y AS INTEGER, BYVAL c AS INTEGER, BYVAL dir AS INTEGER)

  SELECT CASE c
    CASE 3
      SCORE = SCORE + 3
    CASE 4
      SCORE = SCORE + 10
    CASE IS > 4
      SCORE = SCORE + 50
  END SELECT
    
  DIM d AS INTEGER
  FOR d = 0 TO c - 1
    SELECT CASE dir
      CASE 0
        map[x][y] = 0
        y = y - 1
      CASE 1
        map[x][y] = 0
        x = x + 1
      CASE 2
        map[x][y] = 0
        y = y + 1
      CASE 3
        map[x][y] = 0
        x = x - 1
    END SELECT
  NEXT d

END SUB


SUB FillGrid()

  DIM x AS INTEGER
  DIM y AS INTEGER
  DIM tl AS INTEGER
  DIM tlc AS INTEGER
  FOR x = 0 TO MAPSIZEX - 1
    IF map[x][0] = 0 THEN
      map[x][0] = ((MATH.RAND() % LEVEL) + 1)
    END IF
  NEXT x
  FOR y = MAPSIZEY - 2 TO 0 STEP -1
    FOR x = 0 TO MAPSIZEX - 1
      IF map[x][y] > 0 THEN
        IF map[x][y + 1] = 0 THEN
          map[x][y + 1] = map[x][y]
          map[x][y] = 0
        END IF
      END IF
    NEXT x
  NEXT y
  FOR y = 0 TO MAPSIZEY - 1
    FOR x = 0 TO MAPSIZEX - 1
      tl = map[x][y]
      IF tl > 0 THEN
        IF CountTile(x, y, tl, 0, tlc) = TRUE THEN
          KillTiles (x, y, tlc, 0)
        ELSE
          IF CountTile(x, y, tl, 1, tlc) = TRUE THEN
            KillTiles (x, y, tlc, 1)
          ELSE
            IF CountTile(x, y, tl, 2, tlc) = TRUE THEN
              KillTiles (x, y, tlc, 2)
            ELSE
              IF CountTile(x, y, tl, 3, tlc) = TRUE THEN
                KillTiles (x, y, tlc, 3)
              END IF
            END IF
          END IF
        END IF
      END IF
    NEXT x
  NEXT y

END SUB


FUNCTION main(BYVAL COMMANDCOUNT AS INTEGER, BYPTR COMMAND[] AS CHAR) AS INTEGER

  setlocale(LC_ALL, "RUS")
  
  RANDOMIZE

  DIM Clock AS sf.Clock 
  DIM x1 AS INTEGER
  DIM x2 AS INTEGER
  DIM y1 AS INTEGER
  DIM y2 AS INTEGER
  DIM Center_X AS INTEGER
  DIM Center_Y AS INTEGER
  DIM size1 AS FLOAT
  DIM size2 AS FLOAT
  DIM mt1 AS INTEGER
  DIM mt2 AS INTEGER
  DIM Do_Swap_Tiles AS BOOLEAN = FALSE
  DIM move_blocks AS INTEGER
  DIM move_axis AS INTEGER

  SET window(sf.VideoMode(GAMEWIDTH, GAMEHEIGHT, 32), "Match-three", sf.Style.Titlebar | sf.Style.Close) AS sf.RenderWindow
  window.setVerticalSyncEnabled(true)

  DIM font AS sf.Font
    IF NOT(font.loadFromFile("sansation.ttf")) THEN
        RETURN EXIT_FAILURE
  END IF
  DIM debugMessage AS sf.Text
    debugMessage.setFont(font)
    debugMessage.setCharacterSize(14)
    debugMessage.setPosition(5.f, 355.f)
    debugMessage.setFillColor(sf.Color.White)
  DIM scoreMessage AS sf.Text
    scoreMessage.setFont(font)
    scoreMessage.setCharacterSize(14)
    scoreMessage.setPosition(5.f, 2.f)
  scoreMessage.setStyle(sf.Text.Bold);
    scoreMessage.setFillColor(sf.Color.White)
  DIM GameOverMessage AS sf.Text
    GameOverMessage.setFont(font)
    GameOverMessage.setCharacterSize(70)
    GameOverMessage.setPosition(115.f, 195.f)
  GameOverMessage.setStyle(sf.Text.Bold);
    GameOverMessage.setFillColor(sf.Color.White)
  GameOverMessage.setString("GAME OVER")

  DIM tileSet AS sf.Texture
  tileSet.loadFromFile("blocks2.png")
  DIM tile(tileSet) AS sf.Sprite
  
  DIM textureback AS sf.Texture
  textureback.loadFromFile("back.png")
  DIM spback(textureback) AS sf.Sprite
  
  DIM textureselect AS sf.Texture
  textureselect.loadFromFile("select.png")
  DIM spselect(textureselect) AS sf.Sprite
  
  DIM texturehelp AS sf.Texture
  texturehelp.loadFromFile("help.png")
  DIM sphelp(texturehelp) AS sf.Sprite
  
  DO WHILE (window.isOpen())
    DIM event AS sf.Event
        DO WHILE (window.pollEvent(event))
            IF ((event.type = sf.Event.Closed) OR ((event.type = sf.Event.KeyPressed) AND (event.key.code = sf.Keyboard.Escape))) THEN
                window.close()
        EXIT DO
            END IF
        LOOP

    IF selection_done = 0 THEN
      FillGrid()
    END IF

        window.clear(sf.Color(0, 0, 0))
    window.draw(spback)

    'DrawGrid
    DIM x AS INTEGER
    DIM y AS INTEGER
    FOR y = 0 TO MAPSIZEY - 1
      FOR x = 0 TO MAPSIZEX - 1
        IF selection_done <> 0 THEN
          IF map[x][y] > 0 THEN
            IF (x = t1x AND y = t1y) OR (x = t2x AND y = t2y) THEN
            ELSE
              tile.setTextureRect(sf.IntRect(((map[x][y]) - 1) * SIZETILE, 0, SIZETILE, SIZETILE))
              tile.setPosition(MAPPOSITIONX + x * SIZETILE, MAPPOSITIONY + y * SIZETILE)
              window.draw(tile)
            END IF
          END IF
        ELSE
          IF map[x][y] > 0 THEN
            tile.setTextureRect(sf.IntRect(((map[x][y]) - 1) * SIZETILE, 0, SIZETILE, SIZETILE))
            tile.setPosition(MAPPOSITIONX + x * SIZETILE, MAPPOSITIONY + y * SIZETILE)
            window.draw(tile)
          END IF
        END IF
      NEXT x
    NEXT y

    IF selection_done <> 0 THEN
      'Do_Swap_Tiles
      'SELECT CASE selection_done
      Do_Swap_Tiles = FALSE
      'CASE 1
      IF selection_done = 1 THEN
        move_blocks = SIZETILE
        selection_done = 2
        x1 = MAPPOSITIONX + t1x * SIZETILE
        x2 = MAPPOSITIONX + t2x * SIZETILE
        y1 = MAPPOSITIONY + t1y * SIZETILE
        y2 = MAPPOSITIONY + t2y * SIZETILE
        Center_X = ((x2 - x1) / 2) + x1
        Center_Y = ((y2 - y1) / 2) + y1
        IF t1y = t2y THEN
          IF t1x > t2x THEN
            mt1 = map[t2x][t2y]
            mt2 = map[t1x][t1y]
          ELSE
            mt1 = map[t1x][t1y]
            mt2 = map[t2x][t2y]
          END IF
        ELSE
          IF t1y > t2y THEN
            mt1 = map[t2x][t2y]
            mt2 = map[t1x][t1y]
          ELSE
            mt1 = map[t1x][t1y]
            mt2 = map[t2x][t2y]
          END IF
        END IF
        move_axis = 1
        IF t1y = t2y THEN move_axis = 0
      END IF
      'CASE 2
      IF selection_done = 2 THEN
        IF move_blocks < 0 THEN
          IF Switch(t1x, t1y, t2x, t2y) = TRUE THEN
            selection_done = 0
            'mouse_left_state = 1
            mouse_left_state = 0
            t1x = t2x
            t1y = t2y
          ELSE
            selection_done = 3
            SCORE = SCORE - 5
          END IF
        ELSE
          Do_Swap_Tiles = TRUE
          move_blocks = move_blocks - FLIPSPEED
        END IF
      END IF
      'CASE 3
      IF selection_done = 3 THEN
        IF move_blocks >= SIZETILE THEN
          selection_done = 0
          Do_Swap_Tiles = TRUE
        ELSE
          move_blocks = move_blocks + FLIPSPEED
          Do_Swap_Tiles = TRUE
        END IF
        'mouse_left_state = 1
        mouse_left_state = 0
      END IF
    'END SELECT
    ELSE
      'UpdateSelection
      'IF GameOver = FALSE THEN
        mouse_position = sf.Mouse.getPosition(window)
        UpdateSelection(mouse_position.x, mouse_position.y, sf.Mouse.isButtonPressed(sf.Mouse.Left))
      'END IF
    END IF

    IF Do_Swap_Tiles = TRUE THEN
      SELECT CASE move_axis
      CASE 0 'x
        tile.setTextureRect(sf.IntRect((mt1 - 1) * SIZETILE, 0, SIZETILE, SIZETILE))
        tile.setPosition(Center_X + CENTERTILE - move_blocks, Center_Y) 
        window.draw(tile)
        tile.setTextureRect(sf.IntRect((mt2 - 1) * SIZETILE, 0, SIZETILE, SIZETILE))
        tile.setPosition(Center_X - CENTERTILE + move_blocks, Center_Y) 
        window.draw(tile)
      CASE 1 'y
        tile.setTextureRect(sf.IntRect((mt1 - 1) * SIZETILE, 0, SIZETILE, SIZETILE))
        tile.setPosition(Center_X, Center_Y + CENTERTILE - move_blocks) 
        window.draw(tile)
        tile.setTextureRect(sf.IntRect((mt2 - 1) * SIZETILE, 0, SIZETILE, SIZETILE))
        tile.setPosition(Center_X, Center_Y - CENTERTILE + move_blocks) 
        window.draw(tile)
      END SELECT
    END IF

    IF selection_done = 0 THEN
      IF mouse_left_state <> 0 then
        spselect.setPosition(MAPPOSITIONX + t1x * SIZETILE, MAPPOSITIONY + t1y * SIZETILE) 
        window.draw(spselect)
      END IF
      IF EndGame() = TRUE THEN GameOver = TRUE
      IF helpx <> -1 AND helpy <> -1 THEN
        sphelp.setPosition(MAPPOSITIONX + helpx * SIZETILE, MAPPOSITIONY + helpy * SIZETILE) 
        window.draw(sphelp)
      ELSE
        'IF EndGame() = TRUE THEN GameOver = TRUE
      END IF
    END IF

    'FPS
    DIM Framerate AS sf.Time = Clock.getElapsedTime()
    Clock.restart()
    
    'info for test
    debugMessage.setString("FPS " + TO_STRING(1.f / Framerate.asSeconds()) + "\n" _
      + "selection_done = " + TO_STRING(selection_done) + "\n" _
      + "x = " + TO_STRING(mouse_position.x) + " y = " + TO_STRING(mouse_position.y) + "\n" _
      + "mx = " + TO_STRING(INT((mouse_position.x - MAPPOSITIONX) / SIZETILE)) + "   my = " + TO_STRING(INT((mouse_position.y - MAPPOSITIONY) / SIZETILE)) + "\n" _
      + "mouse_left_state = " + TO_STRING(mouse_left_state) + "\n" _
      + "map[mx][my] = " + TO_STRING(map[mx][my]) + "\n" _
      + "t1x = " + TO_STRING(t1x) + "   t1y = " + TO_STRING(t1y) + "\n" _
      + "t2x = " + TO_STRING(t2x) + "   t2y = " + TO_STRING(t2y) + "\n" _
      )
    
    IF SCORE > 100 THEN LEVEL = 8
    IF SCORE > 200 THEN LEVEL = 9
    IF SCORE > 300 THEN LEVEL = 10
    IF SCORE > 500 THEN LEVEL = 11
    IF SCORE > 600 THEN LEVEL = 12
    IF SCORE > 700 THEN LEVEL = 13
    IF SCORE > 800 THEN LEVEL = 14
    IF SCORE > 900 THEN LEVEL = 15
    IF SCORE > 1000 THEN LEVEL = 16
    scoreMessage.setString("LEVEL  " + TO_STRING(LEVEL - 6) + "\n" + "SCORE  " + TO_STRING(SCORE) + "\n")
  
    window.draw(debugMessage)
    window.draw(scoreMessage)
    
    IF GameOver = TRUE THEN
      window.draw(GameOverMessage)
    END IF
    
        window.display()

    LOOP
    RETURN 0

END FUNCTION

BASIC[ProjectYaga]Форум