-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathChessGameScreen.h
430 lines (354 loc) · 14.2 KB
/
ChessGameScreen.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
#ifndef CHESSGAMESCREEN_H_INCLUDED
#define CHESSGAMESCREEN_H_INCLUDED
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <SFML/Audio/Music.hpp>
#include <SFML/Audio/Sound.hpp>
#include "Chess.h"
#include "ChessScreens.h"
#include "ChessMenuScreen.h"
#include "ChessExceptions.h"
#include "ChessTimer.h"
#include <thread>
using namespace std;
using namespace sf;
/// INICIALIZAR DATOS DEL HEADER "CHESS:H"
// Constante para la ubicación de la imagen del tablero
const string Chess::BOARD_SPRITESHEET_FILENAME="./assets/chess_board.png";
// Constante para la ubicación del spritesheet de piezas
const string Chess::PIECES_SPRITESHEET_FILENAME="./assets/pieces_spritesheet.png";
// Constante para los limites de la pantalla
const IntRect ChessBoard::LIMITS=IntRect(0, 0, ChessCoord::SIZE*8, ChessCoord::SIZE*8);
// Implementación de la constante estática de tamaño para la unidad de pixeles
const int ChessCoord::SIZE=100;
// Abrir el spritesheet de piezas
const Texture ChessPiece::spriteSheet=loadResource(Chess::PIECES_SPRITESHEET_FILENAME);
/**
Estructura del juego, maneja la seleccion de piezas y las mecanicas de seleccion
incluye el metodo de desplazamiento de pieza
*/
struct ChessGame{
static int status;
static ChessPiece* selectedPiece;
static ChessPiece stateSelectedPiece;
static list<ChessCoord> avaiableMovements;
static const int STATUS_IDLE=0; // Estado del juego sin actividad
static const int STATUS_SELECTED=1; // Estado del juego con selección de una pieza
static const int STATUS_RELEASED=2; // Estado del juego al terminar de mover una pieza
static const int STATUS_EATED=3; // Estado del juego al ser comida una pieza
static const int STATUS_PUT_BACK=4; // Estado del juego regresar una pieza a su lugar
// Detectar donde ocurrió el click y actuar según qué se clickeo
static int onClick(int x, int y){
/**
Evento de click sobre el tablero de juego
CODIGOS DE RETORNO:
STATUS_IDLE = 0 // Estado de inactividad
STATUS_SELECTED = 1 // Estado de seleccion de pieza
STATUS_RELEASED = 2 // Estado de colocar pieza
STATUS_EATED = 3 // Estado de comer pieza
*/
ChessPiece** playerPiecesInCoord =
ChessPlayer::getPiecesOfPlayerInTurnAtPosition(x,y);
ChessPiece** rivalPiecesInCoord =
ChessPlayer::getPiecesOfRivalInTurnAtPosition(x,y);
ChessPiece* newClickedPiece=NULL;
if(playerPiecesInCoord[1]!=NULL){
/** Tengo seleccionada una pieza y el click es
en una casilla con pieza propia
*/
cout<<"CLICK EN CASILLA PROPIA\n"; //DEV
if(playerPiecesInCoord[0] != selectedPiece){
newClickedPiece=playerPiecesInCoord[0];
}else{
newClickedPiece=playerPiecesInCoord[1];
}
/** Se resetea la pieza seleccionada anterior,
y se selecciona la nueva pieza clickeada
*/
if(selectedPiece != NULL){
restoreMovement();
selectedPiece=newClickedPiece;
stateSelectedPiece=*selectedPiece;
calculateAvaiableMovements(selectedPiece);
return STATUS_SELECTED;
}
}
else if(playerPiecesInCoord[0] != NULL && rivalPiecesInCoord[0] != NULL){
/** Click en una casilla con pieza rival */
/** Se come una pieza rival */
status = STATUS_EATED;
selectedPiece = NULL;
ChessPlayer::eatPieceRival(rivalPiecesInCoord[0]);
return STATUS_RELEASED;
}
else if(playerPiecesInCoord[0] != NULL){
/** Click en una casilla sin pieza rival */
newClickedPiece=playerPiecesInCoord[0];
if(selectedPiece != NULL){
if(*newClickedPiece==stateSelectedPiece){
/** La pieza seleccionada fue colocada en la misma
posición que estaba
*/
restoreMovement();
status = STATUS_IDLE;
return STATUS_PUT_BACK;
}
if(newClickedPiece != selectedPiece && selectedPiece != NULL){
/** Se resetea la pieza seleccionada anterior, y se
selecciona la nueva pieza clickeada
*/
restoreMovement();
selectedPiece=newClickedPiece;
stateSelectedPiece=*selectedPiece;
calculateAvaiableMovements(selectedPiece);
status = STATUS_SELECTED;
return STATUS_SELECTED;
}
/** Se coloca la pieza previamente seleccionada */
status = STATUS_IDLE;
selectedPiece = NULL;
return STATUS_RELEASED;
}
else{
/** Se selecciona la pieza clickeada */
selectedPiece=newClickedPiece;
stateSelectedPiece=*selectedPiece;
status = STATUS_SELECTED;
calculateAvaiableMovements(selectedPiece);
return STATUS_SELECTED;
}
}
status = STATUS_IDLE;
return STATUS_IDLE;
}
static void calculateAvaiableMovements(ChessPiece* selectedPiece){
ChessCoord aux;
avaiableMovements.clear();
avaiableMovements.push_back(selectedPiece->position);
if(ChessPlayer::playerInTurn==1&&selectedPiece->position.y>1){
aux=selectedPiece->position-ChessCoord(0,1);
if(ChessPlayer::getPiecesOfPlayerInTurnAtPosition(aux)[0] == NULL
&& ChessPlayer::getPiecesOfRivalInTurnAtPosition(aux)[0] == NULL){
avaiableMovements.push_back(aux);
}
if(selectedPiece->position.valueX>1){
aux=selectedPiece->position-ChessCoord(1,1);
if(ChessPlayer::getPiecesOfRivalInTurnAtPosition(aux)[0] != NULL){
avaiableMovements.push_back(aux);
}
}
if(selectedPiece->position.valueX<8){
aux=selectedPiece->position+ChessCoord(1,0)-ChessCoord(0,1);
if(ChessPlayer::getPiecesOfRivalInTurnAtPosition(aux)[0] != NULL){
avaiableMovements.push_back(aux);
}
}
}
else if(ChessPlayer::playerInTurn==0&&selectedPiece->position.y<8){
aux=selectedPiece->position+ChessCoord(0,1);
if(ChessPlayer::getPiecesOfPlayerInTurnAtPosition(aux)[0] == NULL
&& ChessPlayer::getPiecesOfRivalInTurnAtPosition(aux)[0] == NULL){
avaiableMovements.push_back(aux);
}
if(selectedPiece->position.valueX>1){
aux=selectedPiece->position-ChessCoord(1,0)+ChessCoord(0,1);
if(ChessPlayer::getPiecesOfRivalInTurnAtPosition(aux)[0] != NULL){
avaiableMovements.push_back(aux);
}
}
if(selectedPiece->position.valueX<8){
aux=selectedPiece->position+ChessCoord(1,1);
if(ChessPlayer::getPiecesOfRivalInTurnAtPosition(aux)[0] != NULL){
avaiableMovements.push_back(aux);
}
}
}
}
// Posiciona la pieza sobre la casilla de ajedrez en la que se encuentran los pixeles recibidos.
static void dragPiece(int pxX, int pxY){
if(selectedPiece == NULL )return;
ChessCoord coordToMove=ChessCoord::getChessPosition(pxX, pxY);
for(ChessCoord movement:avaiableMovements){
if(movement==coordToMove){
selectedPiece->setPosition(coordToMove);
return;
}
}
// cout<<"\n";
}
static void restoreMovement(){
if(selectedPiece == NULL)return;
avaiableMovements.clear();
*selectedPiece = stateSelectedPiece;
selectedPiece = NULL;
status = STATUS_IDLE;
}
};
// Estado inicial de el juego, nada está pasando así que es idle
int ChessGame::status=ChessGame::STATUS_IDLE;
// Inicializa en ChessGame la pieza selecionada como nula
ChessPiece* ChessGame::selectedPiece=NULL;
// Inicializa en ChessGame un estado por default
ChessPiece ChessGame::stateSelectedPiece;
// Inicializa en ChessGame una lista vacia de movimientos disponibles
list<ChessCoord> ChessGame::avaiableMovements;
struct ChessGameButtons{
RectangleShape pauseButton;
ChessGameButtons(){
pauseButton=RectangleShape({80,80});
pauseButton.setFillColor(Color::Transparent);
pauseButton.setPosition({949,682});
}
void renderButtons(RenderWindow &window){
window.draw(pauseButton);
}
};
struct ChessGameScreen : public ChessScreen{
Music music;
ChessBoard board;
Event event;
static int save_time;
static int current_time;
static Game_Timer *timer;
static Thread *timer_thread;
ChessGameButtons buttons;
ChessGameScreen(){
if (!music.openFromFile("./assets/sounds/BackgroundMusic.ogg")){
throw BackgroundMusicException();
}
}
// Declaracion de la funcion Run
virtual int Run(RenderWindow &window);
virtual void Pause(){
music.sf::SoundStream::pause();
ChessGame::restoreMovement();
save_time=current_time;
timer->stop();
}
static void onTimerEnds(){
ChessPlayer::updatePlayerInTurn();
//Inicializamos un contador
save_time=0;
timer->current_time=0;
timer_thread=new Thread(
ref( *timer )
);
timer_thread->launch();
}
static const int CLICK_ON_PAUSE=3;
static const int CLICK_ON_BOARD=2;
int onClick(Event::MouseButtonEvent mouseEvent){
/**
Funcion que busca la accion realizada al dar click en la pantalla de juego
Codigos de regreso:
CLICK_ON_BUTTONS = 2 // Usado cuando se da click a los botones de salir y de pausa
CLICK_ON_BOARD = 1 // Usado cuando el click es en el tablero de juego
CLICK_ON_NOTHING = 0 // Usado cuando no se clique� nada interactuable
*/
int operation=0;
if(ChessBoard::LIMITS.contains(mouseEvent.x, mouseEvent.y)){
operation=ChessGame::onClick(mouseEvent.x, mouseEvent.y);
if(operation==ChessGame::STATUS_IDLE){
return CLICK_ON_NOTHING;
}
else if(operation==ChessGame::STATUS_RELEASED||operation==ChessGame::STATUS_EATED){
ChessPlayer::updatePlayerInTurn();
}
return CLICK_ON_BOARD;
}else if(buttons.pauseButton.getGlobalBounds().contains(mouseEvent.x, mouseEvent.y)){
return CLICK_ON_PAUSE;
}else{
return CLICK_ON_NOTHING;
}
}
};
int ChessGameScreen::current_time=0;
int ChessGameScreen::save_time=0;
Game_Timer* ChessGameScreen::timer=NULL;
Thread* ChessGameScreen::timer_thread=NULL;
/* IMPLEMENTATIONS */
int ChessGameScreen::Run(RenderWindow &window){
if(!wasRun){
/**
Codigo a ejecutar solamente en la primer llamada al Run
El codigo aqui se usa en caso de requerir acciones que se ejecuten 1 sola ocasión en la primer llamada.
*/
wasRun=true;
music.setLoop(true);
// Reserva de espacio para los jugadores y sus piezas
ChessPlayer::players=new ChessPlayer[2];
if(MAIN_PLAYER_COLOR==ChessPiece::COLOR_WHITE){
ChessPlayer::players[0]=ChessPlayer::createPlayer(ChessPiece::COLOR_BLACK);
ChessPlayer::players[1]=ChessPlayer::createPlayer(ChessPiece::COLOR_WHITE);
}else{
ChessPlayer::players[0]=ChessPlayer::createPlayer(ChessPiece::COLOR_WHITE);
ChessPlayer::players[1]=ChessPlayer::createPlayer(ChessPiece::COLOR_BLACK);
}
//Inicializamos un contador
current_time=55;
timer=new Game_Timer(current_time, MinuteSecond(MINUTES_PER_TURN,0), onTimerEnds);
timer_thread=new Thread(
ref( *timer )
);
}else{
/**
Codigo a ejecutar siempre despues de la primera llamada a Run.
Aquí debe ir todo código que reanude las acciones que el metodo Pause haya detenido.
*/
current_time=save_time;
}
music.setVolume(10.f);
music.play();
timer_thread->launch();
bool running = true;
while (running)
{
/*
Bucle principal del juego
*/
while (window.pollEvent(event))
{
if (event.type == Event::Closed)
{
window.close();
// exit(1);
}
else if (event.type == Event::MouseButtonPressed)
{
if (event.mouseButton.button == Mouse::Left)
{
// El boton presionado es el click izquierdo
int operation=onClick(event.mouseButton);
if(operation == CLICK_ON_NOTHING){ // DEV
return CHESS_MENU_SCREEN_NUMBER;
}else if(operation==CLICK_ON_PAUSE){
return CHESS_PAUSE_SCREEN_NUMBER;
}
}
}
else if (event.type == Event::MouseMoved && ChessGame::status==ChessGame::STATUS_SELECTED)
{
ChessGame::dragPiece(event.mouseMove.x, event.mouseMove.y);
}
}
window.clear();
window.draw(board.sprite);
for(ChessPiece* piece:ChessPlayer::players[ChessPlayer::rivalInTurn].pieces){
window.draw(piece->sprite);
}
for(ChessPiece* piece:ChessPlayer::players[ChessPlayer::playerInTurn].pieces){
window.draw(piece->sprite);
}
buttons.renderButtons(window);
timer->clock_sprite.setPosition(sf::Vector2f(875,350));
window.draw(timer->clock_sprite);
timer->hand_timer_sprite.setPosition(sf::Vector2f(875+50,350+50));
window.draw(timer->hand_timer_sprite);
/*
Aqui se puede introducir cualquier cosa que se quiera dibujar
*/
window.display();
}
return -1;
}
#endif // CHESSGAMESCREEN_H_INCLUDED