From 8aaed3e201be59dfb5bd48f24e3386e9a4a7dcba Mon Sep 17 00:00:00 2001 From: Metehan Gezer Date: Tue, 10 Oct 2023 08:13:37 +0300 Subject: [PATCH] promote and improvements --- CMakeLists.txt | 9 +- assets/images/button.png | Bin 106 -> 1795 bytes assets/images/panel.png | Bin 0 -> 1795 bytes assets/images/pieces/MaskPieces-Sheet.png | Bin 0 -> 1580 bytes src/app/app.cpp | 6 +- src/{ => canvas}/game_canvas.cpp | 174 +++++++++++++++++----- src/{ => canvas}/game_canvas.h | 20 ++- src/{ => canvas}/loading_canvas.cpp | 14 +- src/{ => canvas}/loading_canvas.h | 0 src/{ => canvas}/menu_canvas.cpp | 2 +- src/{ => canvas}/menu_canvas.h | 0 src/{ => canvas}/message_canvas.cpp | 4 + src/{ => canvas}/message_canvas.h | 0 src/canvas/promote_screen.cpp | 118 +++++++++++++++ src/canvas/promote_screen.h | 51 +++++++ src/chess/chess_board.cpp | 4 + src/chess/chess_board.h | 1 + src/net/chess_connection.cpp | 51 ++++++- src/net/chess_connection.h | 16 +- src/net/packets.h | 32 ++++ src/util.cpp | 49 ++++++ src/util.h | 4 +- 22 files changed, 486 insertions(+), 69 deletions(-) create mode 100644 assets/images/panel.png create mode 100644 assets/images/pieces/MaskPieces-Sheet.png rename src/{ => canvas}/game_canvas.cpp (69%) rename src/{ => canvas}/game_canvas.h (71%) rename src/{ => canvas}/loading_canvas.cpp (91%) rename src/{ => canvas}/loading_canvas.h (100%) rename src/{ => canvas}/menu_canvas.cpp (99%) rename src/{ => canvas}/menu_canvas.h (100%) rename src/{ => canvas}/message_canvas.cpp (93%) rename src/{ => canvas}/message_canvas.h (100%) create mode 100644 src/canvas/promote_screen.cpp create mode 100644 src/canvas/promote_screen.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cd7f1c..6594fcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,10 +86,11 @@ set(GlistApp_SOURCES ${APP_DIR}/src/color.cpp ${APP_DIR}/src/app/main.cpp ${APP_DIR}/src/app/app.cpp - ${APP_DIR}/src/loading_canvas.cpp - ${APP_DIR}/src/menu_canvas.cpp - ${APP_DIR}/src/message_canvas.cpp - ${APP_DIR}/src/game_canvas.cpp + ${APP_DIR}/src/canvas/promote_screen.cpp + ${APP_DIR}/src/canvas/loading_canvas.cpp + ${APP_DIR}/src/canvas/menu_canvas.cpp + ${APP_DIR}/src/canvas/message_canvas.cpp + ${APP_DIR}/src/canvas/game_canvas.cpp ${APP_DIR}/src/chess/chess_board.cpp ${APP_DIR}/src/chess/piece.cpp ${APP_DIR}/src/net/packets.cpp diff --git a/assets/images/button.png b/assets/images/button.png index 9a181f0da4531136be7913b597cca05fe0a0823e..bd4bbb6e6b59a4c60ce5422662cd9d8c9ff973e5 100644 GIT binary patch literal 1795 zcmb_dO>f*p7&aW*w4zsvkdQ35NUe(P@!0FNM>SQN4P*sQqjV+0rRsQQylZ9cG4>?8 z$+5SJ8$YB+E*#(oAj%KuAK(NxuDr7!RvXe1MOd;u9zXBL^StlOJm1^>^2YU#uN#JO zW4JTehxdlQH{OTmSLNMT@VZv-eA^nvho9>Ez2W}tzYOEb55?#}9i(3qCQFBMnF(iJ z)_^vQ`w!+dWrsqUnHU#UV*UBk&z4#6#QLU}qO{%;lVazz5sy!IN9^>F#oT)Exp{w1 zz(FY#HRt8DYRNpY7Jdng^|Wi53y3;QtW6!zJV^JwrW>OfoATU)~@Fu&1wPUti#nu z&2$l*GgnMSDJsKzuyP|>ZWNIoRM5MB?ZbwNyoyitFdKv zLXs^xl??=j?EFO*X-bAwt7yfw zQ;?mag>s#&*2H7+-D)%~%tap%%5;Ax7Sn|l+*(Z+=O}P721~cIi2$eXDEAW9%3RH8 zBR0pN)&&~MeOvl1J$`rcSx!OWoZ5L5P>|oFb`;RVlJj&tJcHr zn1GM&pb-@))xa_G>mR@W2uIM(;b3#L@d^9j(Vgsf*p7&aVAQc;e8IJqvBT2Xt(WAEA?)l?xH$cj3R(v=9ej%UWZR@NS4JK0T+ z+_?7CUjaXW1N@1q7tWR70zaYe?1$Bcv_uh>Y>&s!`|&*QJ2OA+?|pOQ`e)Y-!?-cr z9UQ=WL*EarkUEi!sA_<9u%zG7?AwiQKaHk&y!&r$Ulxlt4$OtcR`*v)C# zvbkM0x7Hp8vf*`JwYe%y?UAMGxQ#7HcFCfsI=5xBQVKLfb5OS7ryb}d<}>XA~@b*=W-DVxN1T=P!CcwTA}cV9D+1J=seg1ULOi*4+U zuuCza#Qg$$6yqf{Q6kSy&q1S+>rz5!?@cK5jbJVNPq5%LQ+2_Ba$c~pL{&Mq%uYzU zt){Amz>uA{$RbJTuxwgZaycBt7O-~mT+l2OGR;`u=EUW;pAl|HJP7STxS0rKN<)NjE1=vTT&u|d>b}CqC`@-wlVc#b<@xq7%DGo%`U)w*bb68$%dSyR)(dnk3 zyLkiUI$f=a$MT2OXquagKA?>2{*EoK3oC`Sn$9m!;BpL>Zf6q-PTx`PC9F|dJ7cxn z8iQJwXejiy^c!~a?&P6#pm4_QEc6-3?=m|Kd)V%$Uf&ZU4SmmFlRuX{G$5vapOR?Z zt5-{YB`u$@ax7ubMAp^mT&^20ti`|A)Bi~a>78=fXXtzjF8;l?t3ojsQ?OO*VRuZx zM|aT35|pap7xqDFgrj literal 0 HcmV?d00001 diff --git a/assets/images/pieces/MaskPieces-Sheet.png b/assets/images/pieces/MaskPieces-Sheet.png new file mode 100644 index 0000000000000000000000000000000000000000..c6e5503d527b0584b504555ff254fdd06e6c9c82 GIT binary patch literal 1580 zcmbVMTWB0r7(QFmi%A=bg&@VtaVo@8XXlpf?woW@<8InraN?3IHAa-2ojJQZW@pYg zGs#{+8)N!VeGwHAEi^(f)rul&trVMxilQ(2AoM{>`c{IaDn(j_>Y2S!L%nrjcFxRv z|M&mje>=~#ySf3<5%#ng=$GMBAmN;k{aqgjrCTdQC6wOr4 zC8M?BtX`YcRf8M25ALZTMqm*i!-`e1JyeNvbza2I!E1qob%;M1=LQ3Za7@d<1a%2i z!y>PXq6njE*uZ@_N+KkGFO)@D79>fKWnNNHL_}f~Hh&y*=o)!6lHAvH$DZO`(f1uB z2<37)Tvo!=EeMjTs)8s791OvGRollE-u8C17?Q-(UDNSRYQumL=jfCl=UA`}6_(Sc zwY_GhSk8nBb_6Lb2CC{nLvQ1pDYsO2Zs-Cj5sTQq$FNcx>lCR^y(0Y^>h|ZqIAGb; zw6>4y#$s7*7oI;f&15taa$U5StvW;)As(G_buu)~!rT$4aZth~*r#rm(o(BdnO4Y9 z?h8xs9u4cJ9f;U@jR{F&pTs#whV$}dl9jR_9`Pb+g~nQROinuuw@9& zrjvu&;@JzYoVw*RxVhuXA4gw4{?dtO9$S2#>^sy|T{&>uJjp-z?Rt)3I{?@VR=&Et z8EpFE;M`2+)6NYuCuiTAzvJil)-$2*bEj`N!Q$`5#X~=KUpzP-s`Os{)mq>4LTIA@ zqi_0^-lOABuU^^p`O+hE3+uLp-ni-552t(Ar9Pa0{I?fF$#-8rmpD1q)qQ;B?egC9 z+s8kiSxtQK=<=JO2Y{d62XEEx+F!ez1>bK}d+tUv{nMGrr%r&?19OMF;H9mj0}EH> qJ3}D=sPN_NC-9e$xDoVlUoU~>*YJ1G=H~{2eV!f~PQG*h#O$B4=>h=& literal 0 HcmV?d00001 diff --git a/src/app/app.cpp b/src/app/app.cpp index 0ac3753..9260d6d 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -6,9 +6,8 @@ */ #include "app.h" -#include -#include "game_canvas.h" -#include "menu_canvas.h" +#include "canvas/loading_canvas.h" +#include "canvas/game_canvas.h" gApp::gApp() { } @@ -26,6 +25,7 @@ void gApp::setup() { cursor_->setFiltering(2, 2); cursor_height_ = cursor_->getHeight(); cursor_width_ = 16; + //auto* cnv = new GameCanvas(this, CreateRef(), nullptr); auto* cnv = new LoadingCanvas(this); appmanager->setCurrentCanvas(cnv); appmanager->getWindow()->setCursorMode(0x00034002); // GLFW_CURSOR_HIDDEN diff --git a/src/game_canvas.cpp b/src/canvas/game_canvas.cpp similarity index 69% rename from src/game_canvas.cpp rename to src/canvas/game_canvas.cpp index 78162eb..6df7c0c 100644 --- a/src/game_canvas.cpp +++ b/src/canvas/game_canvas.cpp @@ -13,6 +13,7 @@ GameCanvas::~GameCanvas() { } void GameCanvas::setup() { + enableAlphaBlending(); if (!connection_->IsHost()) { player_color_ = kPieceColorBlack; flip_board_ = true; @@ -33,6 +34,8 @@ void GameCanvas::setup() { white_pieces_.setFiltering(2, 2); black_pieces_.loadImage("pieces/BlackPieces-Sheet.png"); black_pieces_.setFiltering(2, 2); + mask_pieces_.loadImage("pieces/MaskPieces-Sheet.png"); + mask_pieces_.setFiltering(2, 2); outliner_.loadImage("outliner.png"); outliner_.setFiltering(2, 2); ResetSelection(); @@ -41,6 +44,12 @@ void GameCanvas::setup() { input_lock_ = true; game_started_ = false; ended_ = false; + promote_screen_ = new PromoteScreen(root_, this, player_color_); + promote_screen_->Setup(); + promote_screen_->SetSelectCallback([this](PieceType type) { + promoting_ = false; + connection_->Promote(promote_piece_x_, promote_piece_y_, type, player_color_); + }); // todo move chess board spaghetti stuff to connection and handle everything there chess_board_ = CreateRef(*connection_->GetBoardData()); connection_->SetOnMove([this](int x, int y, int to_x, int to_y) { @@ -66,6 +75,7 @@ void GameCanvas::setup() { }); connection_->SetOnStartGame([this]() { game_started_ = true; + input_lock_ = false; }); connection_->SetOnEndGame([this](PieceColor color) { input_lock_ = true; @@ -79,20 +89,23 @@ void GameCanvas::setup() { SetInfoText("You lost!"); } }); + connection_->SetOnPieceChance([this](int x, int y, PieceType type, PieceColor color) { + chess_board_->SetPiece(x, y, type, color); + }); connection_->Ready(); } void GameCanvas::update() { game_time_ += appmanager->getElapsedTime(); + if (promoting_) { + promote_screen_->Update(); + } UpdateInfoText(); if (ended_) { dance_anim_time_ += appmanager->getElapsedTime(); return; } - if (game_started_) { - UpdateFallAnimation(); - } } void GameCanvas::UpdateInfoText() { @@ -104,16 +117,6 @@ void GameCanvas::UpdateInfoText() { } } -void GameCanvas::UpdateFallAnimation() { - if (fall_anim_dist_ > 0.0f) { - fall_anim_dist_ = Lerp(fall_anim_dist_, 0.0f, 0.01f + (game_time_ / 20.0f)); - if (fall_anim_dist_ < 0.001f) { - fall_anim_dist_ = 0.0f; - input_lock_ = false; - } - } -} - void GameCanvas::draw() { clearColor(0x6f, 0x75, 0x83); if (!game_started_) { @@ -121,15 +124,8 @@ void GameCanvas::draw() { } DrawBoard(); DrawInfoText(); - // pos * 2 -> pos * 4 / 2 -> pos * pixelScale / 2 + DrawPromote(); root_->DrawCursor(); - /*for (int x = 0; x < 8; ++x) { - for (int y = 0; y < 8; ++y) { - RenderUtil::DrawFont(gToStr(x) + " " + gToStr(y), - board_pos_x + (7 + x * 16) * RenderUtil::kPixelScale, - board_pos_y + (10 + y * 12) * RenderUtil::kPixelScale, {1.0f, 0, 0}); - } - }*/ } void GameCanvas::HighlightPosition(int board_x, int board_y, const gColor& color) { @@ -142,6 +138,8 @@ void GameCanvas::HighlightPosition(int board_x, int board_y, const gColor& color } bool GameCanvas::Move(int x, int y, int to_x, int to_y) { + animate_start_ = game_time_; + animate_duration_ = 0.18f; animate_move_piece_x_ = to_x; animate_move_piece_y_ = to_y; animate_from_pos_x_ = (7 + x * 16) * RenderUtil::kPixelScale; @@ -162,8 +160,10 @@ bool GameCanvas::Move(int x, int y, int to_x, int to_y) { SetInfoText("Promote your pawn!"); promoting_ = true; show_moves_ = false; - hover_piece_x_ = to_x; - hover_piece_y_ = to_y; + promote_piece_x_ = to_x; + promote_piece_y_ = to_y; + promote_screen_->Reset(); + promote_screen_->SetPromotePosition(to_x, to_y); return false; } else { SetInfoText("Your opponent is promoting its pawn!"); @@ -176,8 +176,10 @@ bool GameCanvas::Move(int x, int y, int to_x, int to_y) { SetInfoText("Promote your pawn!"); promoting_ = true; show_moves_ = false; - hover_piece_x_ = to_x; - hover_piece_y_ = to_y; + promote_piece_x_ = to_x; + promote_piece_y_ = to_y; + promote_screen_->Reset(); + promote_screen_->SetPromotePosition(to_x, to_y); return false; } else { SetInfoText("Your opponent is promoting its pawn!"); @@ -224,16 +226,40 @@ void GameCanvas::DrawInfoText() { } } +void GameCanvas::DrawPromote() { + if (!promoting_) { + return; + } + promote_screen_->Draw(); +} + void GameCanvas::DrawPiece(int x, int y) { + int render_offset_x = (7 + x * 16) * RenderUtil::kPixelScale; + int render_offset_y = (6 + ConvertY(y) * 12 - piece_offset_) * RenderUtil::kPixelScale; + Ref piece = chess_board_->GetPiece(x, y); if (hover_piece_x_ == x && hover_piece_y_ == y) { if (!show_moves_) { - HighlightPosition(x, y, {0.0f, 139 / 255.0f, 203 / 255.0f}); + if (piece && (!animate_ || (animate_move_piece_x_ != x && animate_move_piece_y_ != y))) { + const gColor& og_color = renderer->getColor(); + renderer->setColor(0.0f, 0.545f, 0.796f); + DrawOutline(piece->GetType(), board_pos_x + render_offset_x, board_pos_y + render_offset_y, RenderUtil::kPixelScale); + renderer->setColor(og_color); + } else { + HighlightPosition(x, y, {0.0f, 0.545f, 0.796f}); + } } } if (show_moves_) { if (move_piece_x_ == x && move_piece_y_ == y) { - HighlightPosition(x, y, {250 / 255.0f, 100 / 255.0f, 20 / 255.0f}); + if (piece && (!animate_ || (animate_move_piece_x_ != x && animate_move_piece_y_ != y))) { + const gColor& og_color = renderer->getColor(); + renderer->setColor(0.98f, 0.394f, 0.078f); + DrawOutline(piece->GetType(), board_pos_x + render_offset_x, board_pos_y + render_offset_y, RenderUtil::kPixelScale); + renderer->setColor(og_color); + } else { + HighlightPosition(x, y, {0.98f, 0.394f, 0.078f}); + } } Ref hover_piece = chess_board_->GetPiece(move_piece_x_, move_piece_y_); @@ -256,17 +282,16 @@ void GameCanvas::DrawPiece(int x, int y) { if (index < 0) { return; } - int render_offset_x = (7 + x * 16) * RenderUtil::kPixelScale; - int render_offset_y = (6 + ConvertY(y) * 12 - piece_offset_) * RenderUtil::kPixelScale; if (animate_ && animate_move_piece_x_ == x && animate_move_piece_y_ == y) { - image.drawSub(board_pos_x + animate_from_pos_x_, board_pos_y + animate_from_pos_y_, // render pos + float t = std::min((game_time_ - animate_start_) / animate_duration_, 1.0); + animate_current_pos_x_ = Lerp(animate_from_pos_x_, animate_to_pos_x_, t); + animate_current_pos_y_ = Lerp(animate_from_pos_y_, animate_to_pos_y_, t); + image.drawSub(board_pos_x + animate_current_pos_x_, board_pos_y + animate_current_pos_y_, // render pos 16 * RenderUtil::kPixelScale, 32 * RenderUtil::kPixelScale, // render size index * 16, index * 32, // image pos 16, 32 // image size ); - animate_from_pos_x_ = Lerp(animate_from_pos_x_, animate_to_pos_x_, 0.15f); - animate_from_pos_y_ = Lerp(animate_from_pos_y_, animate_to_pos_y_, 0.15f); - if (std::abs(animate_to_pos_x_ - animate_from_pos_x_) < 0.02f && std::abs(animate_to_pos_y_ - animate_from_pos_y_) < 0.02f) { + if (t >= 1.0f) { animate_ = false; } } else if (ended_ && (piece->GetColor() == winner_color_ || winner_color_ == kPieceColorNone)) { @@ -280,8 +305,7 @@ void GameCanvas::DrawPiece(int x, int y) { (int) gRadToDeg(std::cos(dance_anim_time_ * 3) * 0.25f) // rotation ); } else { - int start_offset = -fall_anim_dist_ * 800 * (x + 1); - image.drawSub(board_pos_x + render_offset_x, board_pos_y + render_offset_y + start_offset, // render pos + image.drawSub(board_pos_x + render_offset_x, board_pos_y + render_offset_y, // render pos 16 * RenderUtil::kPixelScale, 32 * RenderUtil::kPixelScale, // render size index * 16, index * 32, // image pos 16, 32 // image size @@ -289,6 +313,67 @@ void GameCanvas::DrawPiece(int x, int y) { } } +void GameCanvas::DrawPieceAnimating(PieceType type, PieceColor color, int board_x, int board_y, int to_board_x, int to_board_y, float progress) { + float from_pos_x = (7 + board_x * 16) * RenderUtil::kPixelScale; + float from_pos_y = (6 + ConvertY(board_y) * 12 - piece_offset_) * RenderUtil::kPixelScale; + float to_pos_x = (7 + to_board_x * 16) * RenderUtil::kPixelScale; + float to_pos_y = (6 + ConvertY(to_board_y) * 12 - piece_offset_) * RenderUtil::kPixelScale; + float current_pos_x = Lerp(from_pos_x, to_pos_x, progress); + float current_pos_y = Lerp(from_pos_y, to_pos_y, progress); + auto& pieces = color == kPieceColorWhite ? white_pieces_ : black_pieces_; + int index = type - 1; + pieces.drawSub(board_pos_x + current_pos_x, board_pos_y + current_pos_y, // render pos + 16 * RenderUtil::kPixelScale, 32 * RenderUtil::kPixelScale, // render size + index * 16, index * 32, // image pos + 16, 32 // image size + ); +} + +void GameCanvas::DrawPieceAnimatingUnbound(PieceType type, PieceColor color, int x, int y, int to_board_x, int to_board_y, float progress) { + float to_pos_x = (7 + to_board_x * 16) * RenderUtil::kPixelScale; + float to_pos_y = (6 + ConvertY(to_board_y) * 12 - piece_offset_) * RenderUtil::kPixelScale; + float current_pos_x = Lerp(x, board_pos_x + to_pos_x, progress); + float current_pos_y = Lerp(y, board_pos_y + to_pos_y, progress); + auto& pieces = color == kPieceColorWhite ? white_pieces_ : black_pieces_; + int index = type - 1; + pieces.drawSub(current_pos_x, current_pos_y, // render pos + 16 * RenderUtil::kPixelScale, 32 * RenderUtil::kPixelScale, // render size + index * 16, index * 32, // image pos + 16, 32 // image size + ); +} + +void GameCanvas::DrawPiece(PieceType type, PieceColor color, int x, int y, float scale) { + auto& pieces = color == kPieceColorWhite ? white_pieces_ : black_pieces_; + int index = type - 1; + pieces.drawSub(x, y, // render pos + 16 * scale, 32 * scale, // render size + index * 16, index * 32, // image pos + 16, 32 // image size + ); +} + +void GameCanvas::DrawOutline(PieceType type, int x, int y, float scale) { + int index = type - 1; + int offsets[16]{ + -1,0, + 0,-1, + 1,0, + 0,1, + 0,-1, + -1,0, + 0,1, + 1,0 + }; + for (int i = 0; i < 16; i += 2) { + mask_pieces_.drawSub(x + (scale * offsets[i]), y + (scale * offsets[i + 1]), // render pos + 16 * scale, 32 * scale, // render size + index * 16, index * 32, // image pos + 16, 32 // image size + ); + } +} + int GameCanvas::ConvertY(int y) { return flip_board_ ? y : 7 - y; } @@ -313,7 +398,11 @@ void GameCanvas::charPressed(unsigned int codepoint) { void GameCanvas::mouseMoved(int x, int y) { root_->SetCursorPos(x, y); - if (input_lock_ || promoting_ || connection_->GetCurrentTurn() != player_color_) { + if (promoting_) { + promote_screen_->OnMouseMoved(x, y); + return; + } + if (input_lock_ || connection_->GetCurrentTurn() != player_color_) { return; } // gLogi("GameCanvas") << "mouseMoved" << ", x:" << x << ", y:" << y; @@ -337,19 +426,27 @@ void GameCanvas::mouseDragged(int x, int y, int button) { // gLogi("GameCanvas") << "mouseDragged" << ", x:" << x << ", y:" << y << ", b:" << button; root_->SetCursorPos(x, y); root_->SetCursorType(CursorType::kHandClosed); + if (promoting_) { + promote_screen_->OnMouseMoved(x, y); + return; + } } void GameCanvas::mousePressed(int x, int y, int button) { // gLogi("GameCanvas") << "mousePressed" << ", x:" << x << ", y:" << y << ", b:" << button; root_->SetCursorType(CursorType::kHandClosed); + if (promoting_) { + promote_screen_->OnMousePressed(x, y); + } } void GameCanvas::mouseReleased(int x, int y, int button) { root_->SetCursorType(CursorType::kArrow); - if (animate_ || input_lock_ || connection_->GetCurrentTurn() != player_color_) { + if (promoting_) { + promote_screen_->OnMouseReleased(x, y); return; } - if (promoting_) { + if (animate_ || input_lock_ || connection_->GetCurrentTurn() != player_color_) { return; } @@ -380,7 +477,6 @@ void GameCanvas::mouseReleased(int x, int y, int button) { bool switch_turn = Move(move_piece_x_, move_piece_y_, hover_piece_x_, hover_piece_y_); connection_->Move(move_piece_x_, move_piece_y_, hover_piece_x_, hover_piece_y_, switch_turn); - ResetSelection(); } } diff --git a/src/game_canvas.h b/src/canvas/game_canvas.h similarity index 71% rename from src/game_canvas.h rename to src/canvas/game_canvas.h index fde2f66..6200362 100644 --- a/src/game_canvas.h +++ b/src/canvas/game_canvas.h @@ -7,7 +7,7 @@ #include "gBaseCanvas.h" #include "gImage.h" #include "net/packets.h" - +#include "promote_screen.h" class GameCanvas : public gBaseCanvas { public: @@ -21,7 +21,7 @@ class GameCanvas : public gBaseCanvas { void keyPressed(int key); void keyReleased(int key); void charPressed(unsigned int codepoint); - void mouseMoved(int x, int y ); + void mouseMoved(int x, int y); void mouseDragged(int x, int y, int button); void mousePressed(int x, int y, int button); void mouseReleased(int x, int y, int button); @@ -37,12 +37,16 @@ class GameCanvas : public gBaseCanvas { bool Move(int x, int y, int to_x, int to_y); void DrawBoard(); void DrawInfoText(); + void DrawPromote(); void DrawPiece(int x, int y); + void DrawPieceAnimating(PieceType type, PieceColor color, int board_x, int board_y, int to_board_x, int to_board_y, float progress); + void DrawPieceAnimatingUnbound(PieceType type, PieceColor color, int x, int y, int to_board_x, int to_board_y, float progress); + void DrawPiece(PieceType type, PieceColor color, int x, int y, float scale); + void DrawOutline(PieceType type, int x, int y, float scale); int ConvertY(int y); void ResetSelection(); void UpdateInfoText(); - void UpdateFallAnimation(); private: gApp* root_; gImage board_textures_[2]; @@ -51,20 +55,23 @@ class GameCanvas : public gBaseCanvas { int board_width_, board_height_; gImage white_pieces_; gImage black_pieces_; + gImage mask_pieces_; Ref chess_board_; - int hover_piece_x_, hover_piece_y_; - int move_piece_x_, move_piece_y_; + int hover_piece_x_ = -1, hover_piece_y_ = -1; + int move_piece_x_ = -1, move_piece_y_ = -1; + int promote_piece_x_ = -1, promote_piece_y_ = -1; bool show_moves_; PieceColor player_color_; gFont font_; bool animate_ = false; int animate_move_piece_x_, animate_move_piece_y_; float animate_from_pos_x_, animate_from_pos_y_; + float animate_current_pos_x_, animate_current_pos_y_; float animate_to_pos_x_, animate_to_pos_y_; + double animate_start_, animate_duration_; int piece_offset_; bool input_lock_; double game_time_ = 0.0f; - double fall_anim_dist_ = 1.0f; std::string info_text_; int info_pos_x_, info_pos_y_; Ref connection_; @@ -77,6 +84,7 @@ class GameCanvas : public gBaseCanvas { bool ended_ = false; PieceColor winner_color_; double dance_anim_time_ = 0.0f; + PromoteScreen* promote_screen_; private: void SetInfoText(const std::string& text); }; diff --git a/src/loading_canvas.cpp b/src/canvas/loading_canvas.cpp similarity index 91% rename from src/loading_canvas.cpp rename to src/canvas/loading_canvas.cpp index 5ccba5e..0185a26 100644 --- a/src/loading_canvas.cpp +++ b/src/canvas/loading_canvas.cpp @@ -29,18 +29,18 @@ void LoadingCanvas::update() { void LoadingCanvas::draw() { clearColor(0x1c, 0x1e, 0x25); const gColor& old_color = renderer->getColor(); - if (delta_ < 4) { + if (delta_ < 3) { int opacity = delta_ * delta_ * 255; - if (delta_ > 3) { - opacity = 255 - (delta_ - 3) * (delta_ - 3) * 255; + if (delta_ > 2) { + opacity = 255 - (delta_ - 2) * (delta_ - 2) * 255; } renderer->setColor(255, 255, 255, std::min(opacity, 255)); brand_logo_.draw(brand_x_, brand_y_, brand_width_, brand_height_); - } else if (delta_ < 8) { - double delta = this->delta_ - 4; + } else if (delta_ < 6) { + double delta = this->delta_ - 3; int opacity = delta * delta * 255; - if (delta > 3) { - opacity = 255 - (delta - 3) * (delta - 3) * 255; + if (delta > 2) { + opacity = 255 - (delta - 2) * (delta - 2) * 255; } renderer->setColor(255, 255, 255, std::min(opacity, 255)); glist_logo_.draw(glist_x_, glist_y_, glist_width_, glist_height_); diff --git a/src/loading_canvas.h b/src/canvas/loading_canvas.h similarity index 100% rename from src/loading_canvas.h rename to src/canvas/loading_canvas.h diff --git a/src/menu_canvas.cpp b/src/canvas/menu_canvas.cpp similarity index 99% rename from src/menu_canvas.cpp rename to src/canvas/menu_canvas.cpp index 555505c..8a5e84c 100644 --- a/src/menu_canvas.cpp +++ b/src/canvas/menu_canvas.cpp @@ -16,7 +16,7 @@ HostTask::HostTask(gApp* root) : root(root) { server = CreateRef(config); completed = false; wait = false; - thread = CreateRef([&]() { + thread = CreateRef([&, root]() { znet::Result result; title = "Binding server..."; if ((result = server->Bind()) != znet::Result::Success) { diff --git a/src/menu_canvas.h b/src/canvas/menu_canvas.h similarity index 100% rename from src/menu_canvas.h rename to src/canvas/menu_canvas.h diff --git a/src/message_canvas.cpp b/src/canvas/message_canvas.cpp similarity index 93% rename from src/message_canvas.cpp rename to src/canvas/message_canvas.cpp index 8b2a3f0..1957388 100644 --- a/src/message_canvas.cpp +++ b/src/canvas/message_canvas.cpp @@ -46,20 +46,24 @@ void MessageCanvas::charPressed(unsigned int codepoint) { void MessageCanvas::mouseMoved(int x, int y) { // gLogi("gCanvas") << "mouseMoved" << ", x:" << x << ", y:" << y; + root->SetCursorPos(x, y); back_button->OnMouseMoved(x, y); } void MessageCanvas::mouseDragged(int x, int y, int button) { // gLogi("gCanvas") << "mouseDragged" << ", x:" << x << ", y:" << y << ", b:" << button; + root->SetCursorPos(x, y); } void MessageCanvas::mousePressed(int x, int y, int button) { // gLogi("gCanvas") << "mousePressed" << ", x:" << x << ", y:" << y << ", b:" << button; + root->SetCursorType(CursorType::kHandClosed); back_button->OnMousePressed(x, y); } void MessageCanvas::mouseReleased(int x, int y, int button) { // gLogi("gCanvas") << "mouseReleased" << ", button:" << button; + root->SetCursorType(CursorType::kArrow); back_button->OnMouseReleased(x, y); } diff --git a/src/message_canvas.h b/src/canvas/message_canvas.h similarity index 100% rename from src/message_canvas.h rename to src/canvas/message_canvas.h diff --git a/src/canvas/promote_screen.cpp b/src/canvas/promote_screen.cpp new file mode 100644 index 0000000..a9937a3 --- /dev/null +++ b/src/canvas/promote_screen.cpp @@ -0,0 +1,118 @@ + +#include "promote_screen.h" +#include "game_canvas.h" + +PromoteScreen::PromoteScreen(gApp* root, GameCanvas* canvas, PieceColor player_color) : root_(root), canvas_(canvas), player_color_(player_color) { + renderer_ = canvas_->getRenderer(); +} + +void PromoteScreen::Setup() { + x_ = (renderer_->getWidth() - width_) / 2; + y_ = (renderer_->getHeight() - height_) / 2; + mouse_x_ = 0; + mouse_y_ = 0; + anim_time_ = 0.0f; +} + +void PromoteScreen::Draw() { + const gColor& og_color = renderer_->getColor(); + double alpha_anim = std::min(popup_time_ * 4.0f, 1.0); + float t = anim_time_ * 4.0f; + if (t > 0) { + alpha_anim = 1.0f - t; + } + renderer_->setColor(0, 0, 0, (int) (alpha_anim * 100)); + gDrawRectangle(0, 0, renderer_->getWidth(), renderer_->getHeight(), true); + renderer_->setColor(255, 255, 255, (int) (alpha_anim * 255)); + RenderUtil::DrawRect(x_, y_, + width_, + height_); + for (int i = 0; i < 4; i++) { + PieceType type = (PieceType) (kPieceTypeKnight + i); + int scale = RenderUtil::kPixelScale; + int dx = (padding_ * scale) + (space_ * i * scale) + (piece_width_ * i * scale); + int dy = 4 * scale; + int x = x_ + dx; + int y = y_ - dy; + if (type == selected_type_) { + continue; + } + bool hover = mouse_x_ >= x && mouse_x_ <= x + piece_width_ * scale && + mouse_y_ >= y && mouse_y_ <= y + piece_height_ * scale; + if (selected_type_ == kPieceTypeNone && hover) { + const gColor& og_color = renderer_->getColor(); + renderer_->setColor(0.0f, 0.545f, 0.796f); + canvas_->DrawOutline(type, x, y, scale); + renderer_->setColor(og_color); + } + canvas_->DrawPiece(type, player_color_, x, y, scale); + } + renderer_->setColor(og_color); + if (selected_type_ != kPieceTypeNone) { + int i = selected_type_ - kPieceTypeKnight; + int scale = RenderUtil::kPixelScale; + int dx = (padding_ * scale) + (space_ * i * scale) + (piece_width_ * i * scale); + int dy = 4 * scale; + int x = x_ + dx; + int y = y_ - dy; + canvas_->DrawPieceAnimatingUnbound(selected_type_, player_color_, x, y, promote_x_, promote_y_, t); + if (t >= 1.0f) { + callback_fn_(selected_type_); + selected_type_ = kPieceTypeNone; + } + } +} + +void PromoteScreen::Update() { + if (selected_type_ != kPieceTypeNone) { + anim_time_ += appmanager->getElapsedTime(); + } + popup_time_ += appmanager->getElapsedTime(); +} + +void PromoteScreen::OnMouseMoved(int mouse_x, int mouse_y) { + mouse_x_ = mouse_x; + mouse_y_ = mouse_y; +} + +void PromoteScreen::OnMousePressed(int mouse_x, int mouse_y) { + mouse_x_ = mouse_x; + mouse_y_ = mouse_y; +} + +void PromoteScreen::OnMouseReleased(int mouse_x, int mouse_y) { + mouse_x_ = mouse_x; + mouse_y_ = mouse_y; + if (selected_type_ != kPieceTypeNone) { + return; + } + for (int i = 0; i < 4; i++) { + PieceType type = (PieceType) (kPieceTypeKnight + i); + int scale = RenderUtil::kPixelScale; + int dx = (padding_ * scale) + (space_ * i * scale) + (piece_width_ * i * scale); + int dy = 4 * scale; + int x = x_ + dx; + int y = y_ - dy; + bool hover = mouse_x_ >= x && mouse_x_ <= x + piece_width_ * scale && + mouse_y_ >= y && mouse_y_ <= y + piece_height_ * scale; + if (hover) { + selected_type_ = type; + break; + } + } +} + +void PromoteScreen::SetSelectCallback(SelectCallback callback_fn) { + callback_fn_ = std::move(callback_fn); +} + +void PromoteScreen::SetPromotePosition(int x, int y) { + promote_x_ = x; + promote_y_ = y; +} + +void PromoteScreen::Reset() { + selected_type_ = kPieceTypeNone; + anim_time_ = 0.0f; + popup_time_ = 0.0f; +} \ No newline at end of file diff --git a/src/canvas/promote_screen.h b/src/canvas/promote_screen.h new file mode 100644 index 0000000..0b2b063 --- /dev/null +++ b/src/canvas/promote_screen.h @@ -0,0 +1,51 @@ + +#pragma once + +#include "util.h" +#include "app/app.h" +#include "chess/piece.h" + +class GameCanvas; + +class PromoteScreen { + public: + using SelectCallback = std::function; + + PromoteScreen(gApp* root, GameCanvas* canvas, PieceColor player_color); + + void Setup(); + void Draw(); + void Update(); + void OnMouseMoved(int x, int y); + void OnMousePressed(int x, int y); + void OnMouseReleased(int x, int y); + + void SetPromotePosition(int x, int y); + + void SetSelectCallback(SelectCallback callback_fn); + + void Reset(); + private: + gApp* root_; + GameCanvas* canvas_; + gRenderer* renderer_; + PieceColor player_color_; + int space_ = 3; + int padding_ = 6; + int piece_width_ = 16; + int piece_height_ = 32; + int piece_num_ = 4; + int width_ = (piece_width_ * piece_num_ + + space_ * (piece_num_ - 1) + padding_ * 2) * RenderUtil::kPixelScale; + int height_ = 35 * RenderUtil::kPixelScale; + int x_; + int y_; + int mouse_x_; + int mouse_y_; + SelectCallback callback_fn_; + int promote_x_; + int promote_y_; + PieceType selected_type_ = PieceType::kPieceTypeNone; + double anim_time_ = 0.0f; + double popup_time_ = 0.0f; +}; \ No newline at end of file diff --git a/src/chess/chess_board.cpp b/src/chess/chess_board.cpp index e9a50ba..eed11e7 100644 --- a/src/chess/chess_board.cpp +++ b/src/chess/chess_board.cpp @@ -43,6 +43,10 @@ void ChessBoard::SetPiece(int x, int y, Ref piece) { board_[PosToIndex(x, y)] = std::move(piece); } +void ChessBoard::SetPiece(int x, int y, PieceType type, PieceColor color) { + SetPiece(x, y, pieces_[type]->CopyTeam(color)); +} + bool ChessBoard::IsValidMove(int x, int y, int to_x, int to_y) { if (x < 0 || x > 8 || y < 0 || y > 8 || (x == to_x && y == to_y)) { return false; diff --git a/src/chess/chess_board.h b/src/chess/chess_board.h index dceab48..38eefc4 100644 --- a/src/chess/chess_board.h +++ b/src/chess/chess_board.h @@ -19,6 +19,7 @@ class ChessBoard { Ref GetPiece(int x, int y); void SetPiece(int x, int y, Ref piece); + void SetPiece(int x, int y, PieceType type, PieceColor color); bool IsValidMove(int x, int y, int to_x, int to_y); diff --git a/src/net/chess_connection.cpp b/src/net/chess_connection.cpp index 1cd1bbc..984a693 100644 --- a/src/net/chess_connection.cpp +++ b/src/net/chess_connection.cpp @@ -43,6 +43,11 @@ ChessConnectionLocal::~ChessConnectionLocal() { } void ChessConnectionLocal::Move(int x, int y, int to_x, int to_y, bool switch_turn) { +#ifdef DEBUG + if (x < 0 || x > 7 || y < 0 || y > 7 || to_x < 0 || to_x > 7 || to_y < 0 || to_y > 7) { + throw std::runtime_error("Invalid move"); + } +#endif auto pk = CreateRef(); pk->x_ = x; pk->y_ = y; @@ -54,8 +59,15 @@ void ChessConnectionLocal::Move(int x, int y, int to_x, int to_y, bool switch_tu } } -void ChessConnectionLocal::Promote(int x, int y, PieceType piece_type) { - // todo +void ChessConnectionLocal::Promote(int x, int y, PieceType piece_type, PieceColor piece_color) { + auto pk = CreateRef(); + pk->x_ = x; + pk->y_ = y; + pk->type_ = piece_type; + pk->color_ = piece_color; + opponent_session_->SendPacket(pk); + on_piece_change_(x, y, piece_type, piece_color); + SwitchTurn(); } bool ChessConnectionLocal::IsOpen() { @@ -129,6 +141,9 @@ bool ChessConnectionLocal::OnClientConnect(znet::ServerClientConnectedEvent& eve auto end_game_handler = CreateRef>(); end_game_handler->AddReceiveCallback(ZNET_BIND_FN(OnEndGamePacket)); layer.AddPacketHandler(end_game_handler); + auto set_piece_handler = CreateRef>(); + set_piece_handler->AddReceiveCallback(ZNET_BIND_FN(OnSetPiecePacket)); + layer.AddPacketHandler(set_piece_handler); on_connect_(); return false; } @@ -164,6 +179,11 @@ bool ChessConnectionLocal::OnMovePacket(znet::ConnectionSession&, Ref packet) { + on_piece_change_(packet->x_, packet->y_, packet->type_, packet->color_); + return true; +} + ChessConnectionNetwork::ChessConnectionNetwork(Ref client) : client_(client) { board_data_ = nullptr; client->SetEventCallback(ZNET_BIND_FN(OnEvent)); @@ -174,6 +194,11 @@ ChessConnectionNetwork::~ChessConnectionNetwork() { } void ChessConnectionNetwork::Move(int x, int y, int to_x, int to_y, bool switch_turn) { +#ifdef DEBUG + if (x < 0 || x > 7 || y < 0 || y > 7 || to_x < 0 || to_x > 7 || to_y < 0 || to_y > 7) { + throw std::runtime_error("Invalid move"); + } +#endif auto pk = CreateRef(); pk->x_ = x; pk->y_ = y; @@ -185,8 +210,14 @@ void ChessConnectionNetwork::Move(int x, int y, int to_x, int to_y, bool switch_ } } -void ChessConnectionNetwork::Promote(int x, int y, PieceType piece_type) { - +void ChessConnectionNetwork::Promote(int x, int y, PieceType piece_type, PieceColor piece_color) { + auto pk = CreateRef(); + pk->x_ = x; + pk->y_ = y; + pk->type_ = piece_type; + pk->color_ = piece_color; + client_->client_session()->SendPacket(pk); + on_piece_change_(x, y, piece_type, piece_color); } bool ChessConnectionNetwork::IsOpen() { @@ -235,6 +266,9 @@ bool ChessConnectionNetwork::OnClientConnectedToServerEvent(znet::ClientConnecte auto end_game_handler = CreateRef>(); end_game_handler->AddReceiveCallback(ZNET_BIND_FN(OnEndGamePacket)); layer.AddPacketHandler(end_game_handler); + auto set_piece_handler = CreateRef>(); + set_piece_handler->AddReceiveCallback(ZNET_BIND_FN(OnSetPiecePacket)); + layer.AddPacketHandler(set_piece_handler); auto pk = CreateRef(); session->SendPacket(pk); @@ -269,6 +303,11 @@ bool ChessConnectionNetwork::OnEndGamePacket(znet::ConnectionSession&, Ref packet) { + on_piece_change_(packet->x_, packet->y_, packet->type_, packet->color_); + return true; +} + ChessConnectionDummy::ChessConnectionDummy() { board_data_ = CreateRef>(); std::array& board_data = *board_data_.get(); @@ -296,4 +335,8 @@ ChessConnectionDummy::ChessConnectionDummy() { board_data[ChessBoard::PosToIndex(4, 7)] = {true, kPieceTypeKing, kPieceColorBlack}; board_data[ChessBoard::PosToIndex(3, 7)] = {true, kPieceTypeQueen, kPieceColorBlack}; +} + +void ChessConnectionDummy::Promote(int x, int y, PieceType piece_type, PieceColor piece_color) { + on_piece_change_(x, y, piece_type, piece_color); } \ No newline at end of file diff --git a/src/net/chess_connection.h b/src/net/chess_connection.h index 2f013e5..501e72d 100644 --- a/src/net/chess_connection.h +++ b/src/net/chess_connection.h @@ -13,12 +13,13 @@ class ChessConnection { using OnConnectFunction = std::function; using StartGameFunction = std::function; using EndGameFunction = std::function; + using PieceChangeFunction = std::function; ChessConnection(); virtual ~ChessConnection(); virtual void Move(int x, int y, int to_x, int to_y, bool switch_turn) = 0; - virtual void Promote(int x, int y, PieceType piece_type) = 0; + virtual void Promote(int x, int y, PieceType piece_type, PieceColor piece_color) = 0; virtual bool IsOpen() = 0; @@ -53,12 +54,17 @@ class ChessConnection { void SetOnEndGame(EndGameFunction on_end_game) { on_end_game_ = std::move(on_end_game); } + + void SetOnPieceChance(PieceChangeFunction on_piece_change) { + on_piece_change_ = std::move(on_piece_change); + } protected: TurnChangeFunction on_turn_change_; MoveFunction on_move_; OnConnectFunction on_connect_; StartGameFunction on_start_game_; EndGameFunction on_end_game_; + PieceChangeFunction on_piece_change_; }; class ChessConnectionLocal : public ChessConnection { @@ -69,7 +75,7 @@ class ChessConnectionLocal : public ChessConnection { ~ChessConnectionLocal() override; void Move(int x, int y, int to_x, int to_y, bool switch_turn) override; - void Promote(int x, int y, PieceType piece_type) override; + void Promote(int x, int y, PieceType piece_type, PieceColor piece_color) override; bool IsOpen() override; bool IsHost() override { return true; } @@ -107,6 +113,7 @@ class ChessConnectionLocal : public ChessConnection { bool OnBoardRequestPacket(znet::ConnectionSession&, Ref packet); bool OnClientReadyPacket(znet::ConnectionSession&, Ref packet); bool OnEndGamePacket(znet::ConnectionSession&, Ref packet); + bool OnSetPiecePacket(znet::ConnectionSession&, Ref packet); void StartGame(); }; @@ -116,7 +123,7 @@ class ChessConnectionNetwork : public ChessConnection { ~ChessConnectionNetwork() override; void Move(int x, int y, int to_x, int to_y, bool switch_turn) override; - void Promote(int x, int y, PieceType piece_type) override; + void Promote(int x, int y, PieceType piece_type, PieceColor piece_color) override; bool IsOpen() override; bool IsHost() override { return false; } @@ -145,6 +152,7 @@ class ChessConnectionNetwork : public ChessConnection { bool OnSetTurnPacket(znet::ConnectionSession&, Ref packet); bool OnStartGamePacket(znet::ConnectionSession&, Ref packet); bool OnEndGamePacket(znet::ConnectionSession&, Ref packet); + bool OnSetPiecePacket(znet::ConnectionSession&, Ref packet); }; class ChessConnectionDummy : public ChessConnection { @@ -153,7 +161,7 @@ class ChessConnectionDummy : public ChessConnection { ~ChessConnectionDummy() override = default; void Move(int x, int y, int to_x, int to_y, bool switch_turn) override {} - void Promote(int x, int y, PieceType piece_type) override {} + void Promote(int x, int y, PieceType piece_type, PieceColor piece_color) override; bool IsOpen() override { return false; } Ref> GetBoardData() override { return board_data_; } diff --git a/src/net/packets.h b/src/net/packets.h index 0f7a545..0977f76 100644 --- a/src/net/packets.h +++ b/src/net/packets.h @@ -56,6 +56,16 @@ class EndGamePacket : public znet::Packet { PieceColor winner_; }; +class SetPiecePacket : public znet::Packet { + public: + SetPiecePacket() : znet::Packet(8) { } + + int x_; + int y_; + PieceType type_; + PieceColor color_; +}; + class UpdateBoardPacketSerializerV1 : public znet::PacketSerializer { public: UpdateBoardPacketSerializerV1() : PacketSerializer(1) {} @@ -179,4 +189,26 @@ class EndGamePacketSerializerV1 : public znet::PacketSerializer { packet->winner_ = (PieceColor) buffer->ReadInt(); return packet; } +}; + +class SetPiecePacketSerializerV1 : public znet::PacketSerializer { + public: + SetPiecePacketSerializerV1() : PacketSerializer(8) {} + + Ref Serialize(Ref packet, Ref buffer) override { + buffer->WriteInt(packet->x_); + buffer->WriteInt(packet->y_); + buffer->WriteInt((uint8_t) packet->type_); + buffer->WriteInt((uint8_t) packet->color_); + return buffer; + } + + Ref Deserialize(Ref buffer) override { + auto packet = CreateRef(); + packet->x_ = buffer->ReadInt(); + packet->y_ = buffer->ReadInt(); + packet->type_ = (PieceType) buffer->ReadInt(); + packet->color_ = (PieceColor) buffer->ReadInt(); + return packet; + } }; \ No newline at end of file diff --git a/src/util.cpp b/src/util.cpp index 52e56af..178d311 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -7,6 +7,7 @@ gImage* RenderUtil::button_; gImage* RenderUtil::button_pressed_; gImage* RenderUtil::button_hover_; gImage* RenderUtil::progress_bar_; +gImage* RenderUtil::panel_; void RenderUtil::Setup() { font_ = new gFont(); @@ -25,6 +26,9 @@ void RenderUtil::Setup() { progress_bar_ = new gImage(); progress_bar_->loadImage("progress_bar.png"); progress_bar_->setFiltering(2, 2); + panel_ = new gImage(); + panel_->loadImage("panel.png"); + panel_->setFiltering(2, 2); } void RenderUtil::DrawFont(const std::string& text, int x, int y, const gColor& color, bool bold) { @@ -73,4 +77,49 @@ void RenderUtil::DrawProgress(int x, int y, int percentage, int width) { 4, 0, 4, 4); } +} + +void RenderUtil::DrawRect(int x, int y, int width, int height) { + if (width % 4 != 0) { + width += 4 - width % 4; + } + if (height % 4 != 0) { + height += 4 - height % 4; + } + int scaled_width = width; + int scaled_height = height; + int dx = x; + int dy = y; + int size = kPixelScale * 4; + int woffset = scaled_width - size; + int hoffset = scaled_height - size; + + // fill + int fill_width = woffset / 2; + int fill_height = hoffset / 2 + size; + // top left + panel_->drawSub(dx + size, dy + size, fill_width, fill_height - size, 3, 3, 1, 1); + panel_->drawSub(dx, dy + size, size, fill_height - size, 0, 3, 4, 1); + panel_->drawSub(dx + size, dy, fill_width, size, 3, 0, 1, 4); + + // top right + panel_->drawSub(dx + size + fill_width, dy + size, fill_width, fill_height - size, 4, 3, 1, 1); + panel_->drawSub(dx + fill_width * 2, dy + size, size, fill_height - size, 4, 3, 4, 1); + panel_->drawSub(dx + size + fill_width, dy, fill_width, size, 4, 0, 1, 4); + + // bottom left + panel_->drawSub(dx + size, dy + fill_height, fill_width, fill_height - size * 2, 3, 4, 1, 1); + panel_->drawSub(dx, dy + fill_height, size, fill_height - size * 2, 0, 4, 4, 1); + panel_->drawSub(dx + size, dy + fill_height * 2 - size * 2, fill_width, size, 3, 4, 1, 4); + + // bottom right + panel_->drawSub(dx + size + fill_width, dy + fill_height, fill_width, fill_height - size * 2, 4, 4, 1, 1); + panel_->drawSub(dx + fill_width * 2, dy + fill_height, size, fill_height - size * 2, 4, 4, 4, 1); + panel_->drawSub(dx + size + fill_width, dy + fill_height * 2 - size * 2, fill_width, size, 4, 4, 1, 4); + + // corners + panel_->drawSub(dx, dy, size, size, 0, 0, 4, 4); + panel_->drawSub(dx + woffset, dy, size, size, 4, 0, 4, 4); + panel_->drawSub(dx, dy + hoffset, size, size, 0, 4, 4, 4); + panel_->drawSub(dx + woffset, dy + hoffset, size, size, 4, 4, 4, 4); } \ No newline at end of file diff --git a/src/util.h b/src/util.h index 0e66d52..e95418a 100644 --- a/src/util.h +++ b/src/util.h @@ -10,7 +10,7 @@ using znet::Ref; using znet::CreateRef; inline float Lerp(float a, float b, float t) { - return a + (b - a) * t; + return a + (b - a) * std::min(std::max(std::abs(t), 0.0f), 1.0f); } enum class ButtonState { @@ -30,6 +30,7 @@ class RenderUtil { static void DrawButton(const std::string& text, int x, int y, int width, int height, ButtonState state = ButtonState::None); static void DrawProgress(int x, int y, int percentage, int width); + static void DrawRect(int x, int y, int width, int height); static int GetStringWidth(const std::string& text, bool bold = false) { return bold ? font_bold_->getStringWidth(text) : font_->getStringWidth(text); @@ -46,4 +47,5 @@ class RenderUtil { static gImage* button_hover_; static gImage* button_pressed_; static gImage* progress_bar_; + static gImage* panel_; }; \ No newline at end of file