Newer
Older
Import / research / match3 / match3-test.cpp
//  Testbed for making a match3 board
//  Created: 28/10/2017 09:05:33
//  John Ryland (jryland@xiaofrog.com)
//  InvertedLogic, (C) Copyright 2017
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <pthread.h>
#include "board.h"
#include "windowing.h"
#include "game.h"
#include "common.h"

class MyWindow : public CanvasWindow
{
public:
  MyWindow()
  {
    createNewGame(game, 0, 0, 0);
    selectedSprite = -1;
    otherSprite = -1;

    // sprite sheet could come from DB
    loadSpriteSheet(spriteSheet, "data/sprites-32x32.txt");
  }
  ~MyWindow()
  {
    destroyGame(game);
  }
  void onDraw(int x1, int y1, int x2, int y2)
  {
    int finishedCount = 0;
    for (int i = 0; i < game.m_events.size(); i++)
    {
      BoardEvent& evt = game.m_events[i];
      if (!evt.userInit)
      {
        //printf("initing\n");
        evt.frame = 0;
        evt.frames = 40;
        evt.userInit = true;
        if (evt.type == BoardEvent::Added)
          canvasAddSprite(canvas, 32 + evt.x*40, 32 + evt.y*40, spriteSheet.sprites[evt.value]);
        if (evt.type == BoardEvent::NoMoreMoves) {
            evt.frames = 0;
            printf("no more moves\n");
        }
      }
      if (evt.frame == evt.frames)
      {
        //printf("finished\n");
        finishedCount++;
        evt.type = BoardEvent::None;
      }
      else
      {
        //printf("updating\n");
        switch (evt.type)
        {
          case BoardEvent::Swapped:
          {
            CanvasItem copy1 = canvas.sprites[evt.itemIndex];
            canvas.sprites[evt.itemIndex] = canvas.sprites[evt.newItemIndex];
            canvas.sprites[evt.newItemIndex] = copy1;
            evt.type = BoardEvent::None;
            break;
          }
          case BoardEvent::Added:
          {
            CanvasItem& item = canvas.sprites[evt.itemIndex];
            item.x = 32 + 40*evt.x;
            item.y = 32 + 40*evt.y - 40 + evt.frame;
            break;
          }
          case BoardEvent::Removed:
          {
            CanvasItem& item = canvas.sprites[evt.itemIndex];
            item.visible = false;
            break;
          }
          case BoardEvent::Moved:
          {
            CanvasItem& item = canvas.sprites[evt.itemIndex];
            item.y = 32 + 40*evt.newY - 40 + evt.frame;
            break;
          }
        }
        evt.frame++;
      }
    }
    if (finishedCount != 0 && finishedCount == game.m_events.size())
    {
      printf("anims finished\n");
      game.m_events.clear();

      // re-normalize the board<->sprites
      populateCanvasItems();
    }

    CanvasWindow::onDraw(x1, y1, x2, y2);
  }
  void populateCanvasItems()
  {
    updateTiles(game);
    canvas.sprites.clear();
    foreach (Tile& t, game.m_tiles) 
      canvasAddSprite(canvas, 32 + t.x*40, 32 + t.y*40, spriteSheet.sprites[t.tileTypeId]);
  }
  void onMouseEvent(int x, int y, int buttons)
  {
    //printf("mouse event: %i %i   %i\n", x, y, buttons);
    if (buttons) {
      if (selectedSprite != -1) {
        CanvasItem& item = canvas.sprites[selectedSprite];
        int dx = x - selx;
        int dy = y - sely;
        int boardX = selectedSprite % game.width();
        int boardY = selectedSprite / game.width();
        int curOtherSprite = -1;
        dx = std::min<int>(std::max<int>(dx, -40), 40);
        dy = std::min<int>(std::max<int>(dy, -40), 40);
        if (boardX == 0 && dx < 0) dx = 0;
        if (boardX == (game.width()-1) && dx > 0) dx = 0;
        if (boardY == 0 && dy < 0) dy = 0;
        if (boardY == (game.height()-1) && dy > 0) dy = 0;

        item.x = selitemx;
        item.y = selitemy;

        if (dx*dx > dy*dy) {
          item.x += dx;
          // find the item that will be swapped with this
          if (dx > 0)
            curOtherSprite = selectedSprite + 1;
          if (dx < 0)
            curOtherSprite = selectedSprite - 1;
        } else {
          item.y += dy;
          // find the item that will be swapped with this
          if (dy > 0)
            curOtherSprite = selectedSprite + game.width();
          if (dy < 0)
            curOtherSprite = selectedSprite - game.width();
        }

        if (otherSprite != -1 && curOtherSprite != otherSprite)
        {
          CanvasItem& other = canvas.sprites[otherSprite];
          other.x = otherX;
          other.y = otherY;
        }

        if (curOtherSprite != -1)
        {
          CanvasItem& other = canvas.sprites[curOtherSprite];
          if (curOtherSprite != otherSprite)
          {
            otherX = other.x;
            otherY = other.y;
            otherSprite = curOtherSprite;
          }
          other.x = otherX;
          other.y = otherY;
          if (dx*dx > dy*dy) {
            other.x -= dx;
          } else {
            other.y -= dy;
          }
        }
      } else {
        // HACK: offset -3,-3 to make it line up - perhaps there is a border between the view and the window
        selectedSprite = canvasHitTestWithAlpha(canvas, x-3, y-3);
        if (selectedSprite != -1) {
          size_t n = canvas.sprites.size() - 1;
          CanvasItem itemS = canvas.sprites[selectedSprite];
          /*
          // Reorder so the selected one will be rendered on top
          // if do this, the selected index is used to infer the position in the board, so will need a mapping of index to board position
          memmove(&canvas.sprites[selectedSprite], &canvas.sprites[selectedSprite+1], sizeof(CanvasItem)*(n-selectedSprite+1));
          canvas.sprites[n] = itemS;
          selectedSprite = n;
          */
          selx = x;
          sely = y;
          selitemx = itemS.x;
          selitemy = itemS.y;
        }
      }
    } else {
      bool canSwap = false;
      if (selectedSprite != -1 && otherSprite != -1) {
        int boardX1 = selectedSprite % game.width();
        int boardY1 = selectedSprite / game.width();
        int boardX2 = otherSprite % game.width();
        int boardY2 = otherSprite / game.width();
        canSwap = swapTiles(game, boardX1, boardY1, boardX2, boardY2);
        printf("can swap: %s\n", canSwap ? "true" : "false");
        if (canSwap)
        {
          int tmp = otherSprite;
          otherSprite = selectedSprite;
          selectedSprite = tmp;
        }
      }
      if (selectedSprite != -1) {
        CanvasItem& item = canvas.sprites[selectedSprite];
        item.x = selitemx;
        item.y = selitemy;
        // snaps back - but could then apply a swap if criteria is met
      }
      if (otherSprite != -1) {
        CanvasItem& item = canvas.sprites[otherSprite];
        item.x = otherX;
        item.y = otherY;
        // snaps back - but could then apply a swap if criteria is met
      }
      selectedSprite = -1;
      otherSprite = -1;
    }
  }
  void setBoardDimensions(int a_width, int a_height)
  {
    int sprites = spriteSheet.sprites.size();
    printf("New match3 board [%ix%i] %i\n", a_width, a_height, sprites);
    destroyGame(game);
    createNewGame(game, a_width, a_height, sprites);
    populateCanvasItems();
    //canvasAddSprite(canvas, x-32, y-32, spriteSheet.sprites[0]);
  }
private:
  Game game;
  SpriteSheet spriteSheet;
  int selectedSprite;
  int selx, sely, selitemx, selitemy;
  int otherSprite;
  int otherX, otherY;  
};

class MyApp : public Application
{
public:
  MyApp(int argc, char* argv[])
    : Application()
  {
    for (int i = 0; i < argc; i++)
      printf("argv[%i]: %s\n", i, argv[i]);
    int boardWidth = (argc > 1) ? atoi(argv[1]) : 4;
    int boardHeight = (argc > 2) ? atoi(argv[2]) : 4;
    window.setBoardDimensions(boardWidth, boardHeight);
  }
  void onStart()
  {
    window.create(480, 650);
  }
private:
  MyWindow window;
};

int main(int argc, char ** argv)
{
  MyApp app(argc, argv);
  return app.run();
}