466 lines
17 KiB
Plaintext
466 lines
17 KiB
Plaintext
// Declare a global variable to track key presses
|
|
int key_pressed = 0;
|
|
|
|
// Global variables for canvas dimensions
|
|
int canvas_width;
|
|
int canvas_height;
|
|
|
|
// Constants representing game states
|
|
int GAME_START = 0;
|
|
int GAME_ENDED = 1;
|
|
int GAME_SHOW_RESULT = 2;
|
|
|
|
// Constants representing puzzle states
|
|
int PUZZLE_READY = 0;
|
|
int PUZZLE_FALLING = 1;
|
|
int PUZZLE_LANDED = 2;
|
|
int PUZZLE_IGNORE = 3;
|
|
|
|
// Constants for showing or hiding puzzle
|
|
int SHOW_PUZZLE = 0;
|
|
int HIDE_PUZZLE = 1;
|
|
|
|
// Constant for falling speed of puzzles
|
|
int FALLING_SPEED = 2;
|
|
|
|
// Path to the full image
|
|
String FULL_IMAGE = "./test_400_600.jpg";
|
|
|
|
// Global GameState object
|
|
GameState gs;
|
|
|
|
// Setup function runs once at the beginning
|
|
void setup() {
|
|
size(800, 900); // Set canvas size
|
|
canvas_width = 800; // Initialize canvas width
|
|
canvas_height = 900; // Initialize canvas height
|
|
|
|
frameRate(30); // Set frame rate
|
|
|
|
gs = new GameState(GAME_ENDED); // Initialize game state
|
|
}
|
|
|
|
// Draw function runs repeatedly in a loop
|
|
void draw() {
|
|
background(204); // Clear the background
|
|
gs.redraw(); // Call the redraw function in GameState
|
|
}
|
|
|
|
// Function to draw marks on the canvas
|
|
void DrawMarks(float marks) {
|
|
// Convert marks to a string
|
|
String str_marks = str(marks);
|
|
textSize(64); // Set text size
|
|
|
|
// Display marks text on the canvas
|
|
text("marks:", 450, 400);
|
|
fill(0, 0, 0); // Set text color
|
|
text(str_marks, 450, 460); // Display marks value
|
|
fill(0, 0, 0); // Reset text color
|
|
}
|
|
|
|
// Function to draw "Press to Start" message
|
|
void DrawPressToStart() {
|
|
textSize(32); // Set text size
|
|
|
|
// Display instructions for controls
|
|
text("press \"s\" to start", 450, 480);
|
|
text("\"j\" = left", 450, 540);
|
|
text("\"k\" = right", 450, 600);
|
|
text("\"m\" = down", 450, 660);
|
|
fill(0, 0, 0); // Set text color
|
|
}
|
|
|
|
// Function to draw "Game Ended" message
|
|
void DrawGameEnded() {
|
|
textSize(32); // Set text size
|
|
|
|
// Display "Game Ended" message and restart instructions
|
|
text("Game ended", 450, 600);
|
|
text("press \"s\" to restart", 450, 640);
|
|
fill(0, 0, 0); // Set text color
|
|
}
|
|
|
|
// Class representing the game state
|
|
class GameState {
|
|
Puzzles puzzles; // Puzzles object in the game
|
|
int state; // Current state of the game
|
|
float final_marks; // Final marks earned in the game
|
|
float each_correct_earn = 100.0 / 16; // Marks earned for each correct puzzle placement
|
|
|
|
// Constructor to initialize game state
|
|
GameState(int init_state) {
|
|
state = init_state; // Set initial game state
|
|
}
|
|
|
|
// Getter method for game state
|
|
int getState() {
|
|
return state;
|
|
}
|
|
|
|
// Method to start the game
|
|
void start_game() {
|
|
this.puzzles = new Puzzles(this, FULL_IMAGE); // Create new Puzzles object
|
|
this.state = GAME_START; // Update game state to start
|
|
this.puzzles.fall_init_puzzle(); // Initialize the falling puzzle
|
|
this.final_marks = 0.0; // Reset final marks
|
|
println("reset marks"); // Print reset marks message
|
|
}
|
|
|
|
// Method to reset the game
|
|
void reset_game() {
|
|
this.state = GAME_ENDED; // Update game state to ended
|
|
}
|
|
|
|
// Method to end the game
|
|
void end_game() {
|
|
this.state = GAME_ENDED; // Update game state to ended
|
|
println("game ended"); // Print game ended message
|
|
}
|
|
|
|
// Method to show game result
|
|
void show_result() {
|
|
this.state = GAME_SHOW_RESULT; // Update game state to show result
|
|
print("game show result"); // Print game show result message
|
|
int correct_placed = 0; // Initialize count for correctly placed puzzles
|
|
|
|
// Iterate through puzzles to check correct placements
|
|
for (int i = 0; i < 16; i++) {
|
|
println("--- ---");
|
|
println(this.puzzles.puzzle_array[i].puzzle_correct_place);
|
|
println(this.puzzles.puzzle_array[i].puzzle_user_placed);
|
|
|
|
// Check if puzzle is correctly placed
|
|
if (this.puzzles.puzzle_array[i].puzzle_correct_place == this.puzzles.puzzle_array[i].puzzle_user_placed) {
|
|
correct_placed = correct_placed + 1; // Increment correct count
|
|
}
|
|
println("--- ---");
|
|
}
|
|
println("correct ?");
|
|
println(correct_placed); // Print number of correctly placed puzzles
|
|
this.final_marks = correct_placed * this.each_correct_earn; // Calculate final marks
|
|
}
|
|
|
|
// Method to redraw the game
|
|
void redraw() {
|
|
if (this.state == GAME_START || this.state == GAME_SHOW_RESULT) {
|
|
this.puzzles.redraw(); // Redraw puzzles
|
|
} else if (this.state == GAME_ENDED) {
|
|
DrawPressToStart(); // Draw "Press to Start" message
|
|
}
|
|
|
|
if (this.state == GAME_SHOW_RESULT) {
|
|
DrawGameEnded(); // Draw "Game Ended" message
|
|
println("draw marks"); // Print draw marks message
|
|
println(this.final_marks); // Print final marks
|
|
DrawMarks(this.final_marks); // Draw final marks on the canvas
|
|
}
|
|
}
|
|
}
|
|
|
|
// Function to convert bottom zero coordinate to canvas y coordinate
|
|
int convert_to_canvas_y(int bottom_zero_coord) {
|
|
int temp;
|
|
temp = canvas_height - bottom_zero_coord; // Calculate canvas y coordinate
|
|
return temp;
|
|
}
|
|
|
|
// Class representing a puzzle
|
|
class Puzzle {
|
|
PImage p_img; // Image for the puzzle
|
|
int current_x; // Current x coordinate
|
|
int current_y; // Current y coordinate
|
|
int current_lane; // Current lane of the puzzle
|
|
int pos_y; // Y position of the puzzle
|
|
int lane_puzzle_count; // Count of puzzles in the lane
|
|
int state; // State of the puzzle
|
|
int show; // Flag to show or hide the puzzle
|
|
Puzzles parent_puzzles; // Parent Puzzles object
|
|
int puzzle_correct_place; // Correct position of the puzzle
|
|
int puzzle_user_placed; // User placed position of the puzzle
|
|
|
|
// Constructor to initialize puzzle
|
|
Puzzle(Puzzles puzzles, PImage puzzle_img, int init_pos_x, int init_pos_y, int correct_place) {
|
|
this.current_x = 99;
|
|
this.current_y = 99;
|
|
this.p_img = puzzle_img; // Set puzzle image
|
|
this.current_lane = 1; // Initialize lane
|
|
this.state = PUZZLE_READY; // Set initial puzzle state
|
|
this.pos_y = 0; // Initialize y position
|
|
this.lane_puzzle_count = 0; // Initialize lane puzzle count
|
|
this.parent_puzzles = puzzles; // Set parent Puzzles object
|
|
this.show = HIDE_PUZZLE; // Set initial show flag
|
|
this.puzzle_correct_place = correct_place; // Set correct place for the puzzle
|
|
}
|
|
|
|
// Method to get puzzle lane bottom
|
|
int get_puzzle_lane_bottom(int lane_puzzle_count) {
|
|
return canvas_height - (150 * (lane_puzzle_count + 1)); // Calculate puzzle lane bottom
|
|
}
|
|
|
|
// Method to update lane puzzle count
|
|
void update_lane_puzzle_count(int lane_puzzle_count) {
|
|
this.lane_puzzle_count = lane_puzzle_count; // Update lane puzzle count
|
|
}
|
|
|
|
// Method to make puzzle fall to the bottom
|
|
void fall_to_bottom() {
|
|
this.pos_y = get_puzzle_lane_bottom(this.parent_puzzles.lane_puzzle_count[this.current_lane]) - 10; // Calculate y position for falling
|
|
}
|
|
|
|
// Method to redraw the puzzle
|
|
void redraw() {
|
|
if (this.state == PUZZLE_FALLING) {
|
|
this.show = SHOW_PUZZLE; // Set show flag to display puzzle
|
|
|
|
// Check if puzzle is still falling
|
|
if (this.pos_y < (get_puzzle_lane_bottom(this.parent_puzzles.lane_puzzle_count[this.current_lane]))) {
|
|
this.pos_y = this.pos_y + FALLING_SPEED; // Move puzzle down
|
|
} else {
|
|
this.state = PUZZLE_LANDED; // Change puzzle state to landed
|
|
}
|
|
} else if (this.state == PUZZLE_LANDED) {
|
|
this.parent_puzzles.puzzle_landed(this.current_lane); // Inform parent puzzles about landed puzzle
|
|
this.state = PUZZLE_IGNORE; // Change puzzle state to ignore
|
|
this.puzzle_user_placed = lookup_user_puzzle_position(this.current_lane, this.pos_y); // Calculate user placed puzzle
|
|
}
|
|
|
|
if (this.show == SHOW_PUZZLE) {
|
|
image(this.p_img, 100 * this.current_lane, this.pos_y); // Draw puzzle on the canvas
|
|
}
|
|
}
|
|
}
|
|
|
|
// Class representing a set of puzzles
|
|
class Puzzles {
|
|
PImage img; // Full image for puzzles
|
|
PImage[] sliced_img = new PImage[16]; // Array to store sliced puzzle images
|
|
Puzzle[] puzzle_array = new Puzzle[16]; // Array to store puzzle objects
|
|
int[] puzzle_order = new int[]{12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3}; // Order of puzzles
|
|
IntList temp_to_shuffle = new IntList(); // Temporary list for shuffling
|
|
int[] shuffled_puzzle_order = new int[16]; // Shuffled order of puzzles
|
|
int[] puzzle_state = new int[16]; // State of each puzzle
|
|
int[][] puzzle_pos_x_y = new int[16][2]; // Positions of puzzles
|
|
int puzzle_idx = 0; // Index of puzzle
|
|
int x_div = 400 / 4; // X division for slicing puzzles
|
|
int y_div = 600 / 4; // Y division for slicing puzzles
|
|
int lane_puzzle_count[] = new int[]{0, 0, 0, 0}; // Count of puzzles in each lane
|
|
int current_puzzle = 0; // Index of current falling puzzle
|
|
int landed_puzzle = 0; // Index of landed puzzle
|
|
int fallen_puzzle = 0; // Count of fallen puzzles
|
|
int test_puzzle_idx = 0; // Index of test puzzle
|
|
GameState parent_gs; // Parent game state object
|
|
IntList fallen_puzzles; // List of fallen puzzles
|
|
|
|
// Method to load the full image and slice it
|
|
void load_image(String jpg_file_path) {
|
|
this.img = loadImage(jpg_file_path); // Load full image
|
|
this.slice(); // Slice the image
|
|
}
|
|
|
|
// Method to slice the image into puzzles
|
|
void slice() {
|
|
// Initialize puzzle index and i
|
|
puzzle_idx = 0;
|
|
int i = 0;
|
|
|
|
// Define x and y rulers for slicing
|
|
int x_ruler[] = new int[]{0, x_div, 2 * x_div, 3 * x_div};
|
|
int y_ruler[] = new int[]{0, y_div, 2 * y_div, 3 * y_div};
|
|
|
|
// Iterate through rows and columns for slicing
|
|
for (int y = 0; y < 4; y++) {
|
|
for (int x = 0; x < 4; x++) {
|
|
puzzle_idx = puzzle_order[i]; // Get puzzle index from order
|
|
this.sliced_img[puzzle_idx] = this.img.get(x_ruler[x], y_ruler[y], x_div, y_div); // Slice the image
|
|
i = i + 1; // Increment i
|
|
}
|
|
}
|
|
}
|
|
|
|
// Constructor to initialize puzzles
|
|
Puzzles(GameState parent_gs, String jpg_file_path) {
|
|
this.test_puzzle_idx = 0; // Initialize test puzzle index
|
|
this.parent_gs = parent_gs; // Set parent game state object
|
|
|
|
this.load_image(jpg_file_path); // Load and slice the image
|
|
for (int i = 0; i < 16; i++) {
|
|
// Create puzzle objects with sliced images and correct positions
|
|
this.puzzle_array[i] = new Puzzle(this, sliced_img[i], 1, 1, i);
|
|
}
|
|
|
|
// Shuffle puzzle order for initial display
|
|
for (int i = 0; i < 16; i = i + 4) {
|
|
temp_to_shuffle = new IntList();
|
|
temp_to_shuffle.append(i + 0);
|
|
temp_to_shuffle.append(i + 1);
|
|
temp_to_shuffle.append(i + 2);
|
|
temp_to_shuffle.append(i + 3);
|
|
|
|
// Shuffle the temporary list
|
|
temp_to_shuffle.shuffle();
|
|
|
|
// Update shuffled puzzle order
|
|
this.shuffled_puzzle_order[i + 0] = temp_to_shuffle.get(0);
|
|
this.shuffled_puzzle_order[i + 1] = temp_to_shuffle.get(1);
|
|
this.shuffled_puzzle_order[i + 2] = temp_to_shuffle.get(2);
|
|
this.shuffled_puzzle_order[i + 3] = temp_to_shuffle.get(3);
|
|
}
|
|
|
|
// Initialize fallen puzzles list and other variables
|
|
this.fallen_puzzles = new IntList();
|
|
this.current_puzzle = 0;
|
|
this.fallen_puzzle = 0;
|
|
this.landed_puzzle = 0;
|
|
}
|
|
|
|
// Method to move the active puzzle left
|
|
void move_left() {
|
|
if (this.get_active_puzzle().state == PUZZLE_FALLING) {
|
|
if (this.get_active_puzzle().current_lane > 0) {
|
|
this.get_active_puzzle().current_lane = this.get_active_puzzle().current_lane - 1;
|
|
this.get_active_puzzle().update_lane_puzzle_count(1);
|
|
}
|
|
} else {
|
|
println("move ignored");
|
|
}
|
|
}
|
|
|
|
// Method to move the active puzzle right
|
|
void move_right() {
|
|
if (this.get_active_puzzle().state == PUZZLE_FALLING) {
|
|
if (this.get_active_puzzle().current_lane < 3) {
|
|
this.get_active_puzzle().current_lane = this.get_active_puzzle().current_lane + 1;
|
|
this.get_active_puzzle().update_lane_puzzle_count(1);
|
|
}
|
|
} else {
|
|
println("move ignored");
|
|
}
|
|
}
|
|
|
|
// Method to move the active puzzle down
|
|
void move_down() {
|
|
this.get_active_puzzle().fall_to_bottom();
|
|
}
|
|
|
|
// Method to initialize the falling puzzle
|
|
void fall_init_puzzle() {
|
|
this.set_active_puzzle(this.shuffled_puzzle_order[this.test_puzzle_idx]);
|
|
this.get_active_puzzle().state = PUZZLE_FALLING;
|
|
}
|
|
|
|
// Method to move to the next falling puzzle
|
|
void fall_next_puzzle() {
|
|
if (this.fallen_puzzle < (puzzle_array.length - 1)) {
|
|
this.fallen_puzzle = this.fallen_puzzle + 1;
|
|
this.test_puzzle_idx = this.test_puzzle_idx + 1;
|
|
this.set_active_puzzle(this.shuffled_puzzle_order[this.test_puzzle_idx]);
|
|
gs.puzzles.get_active_puzzle().state = PUZZLE_FALLING;
|
|
} else {
|
|
println("all puzzle fallen");
|
|
}
|
|
}
|
|
|
|
// Method to increment lane puzzle count
|
|
void inc_lane_puzzle_count(int lane) {
|
|
this.lane_puzzle_count[lane] = this.lane_puzzle_count[lane] + 1;
|
|
}
|
|
|
|
// Method to handle a landed puzzle
|
|
void puzzle_landed(int lane) {
|
|
this.inc_lane_puzzle_count(lane); // Increment lane puzzle count
|
|
this.fallen_puzzles.append(this.current_puzzle); // Add puzzle to fallen puzzles list
|
|
|
|
// Check if all puzzles have fallen
|
|
if (this.fallen_puzzles.size() < 16) {
|
|
gs.puzzles.fall_next_puzzle(); // Move to next falling puzzle
|
|
} else {
|
|
println("all puzzle falled");
|
|
this.parent_gs.show_result(); // Show game result
|
|
}
|
|
}
|
|
|
|
// Method to set the active puzzle
|
|
void set_active_puzzle(int active_puzzle) {
|
|
this.current_puzzle = active_puzzle; // Set active puzzle index
|
|
}
|
|
|
|
// Method to get the active puzzle
|
|
Puzzle get_active_puzzle() {
|
|
return this.puzzle_array[this.current_puzzle]; // Return active puzzle object
|
|
}
|
|
|
|
// Method to redraw the puzzles
|
|
void redraw() {
|
|
for (int i = 0; i < this.fallen_puzzles.size(); i++) {
|
|
this.puzzle_array[this.fallen_puzzles.get(i)].redraw(); // Redraw fallen puzzles
|
|
}
|
|
this.get_active_puzzle().redraw(); // Redraw active puzzle
|
|
}
|
|
}
|
|
|
|
// Function to lookup user puzzle position based on lane and y position
|
|
int lookup_user_puzzle_position(int lane, int pos_y) {
|
|
int[] tmp_list = new int[]{0, 0, 0, 0}; // Initialize temporary list
|
|
|
|
switch (pos_y) {
|
|
case 750:
|
|
tmp_list = new int[]{0, 1, 2, 3}; // Update list for y position 750
|
|
return tmp_list[lane]; // Return user placed puzzle position
|
|
case 600:
|
|
tmp_list = new int[]{4, 5, 6, 7}; // Update list for y position 600
|
|
return tmp_list[lane]; // Return user placed puzzle position
|
|
case 450:
|
|
tmp_list = new int[]{8, 9, 10, 11}; // Update list for y position 450
|
|
return tmp_list[lane]; // Return user placed puzzle position
|
|
case 300:
|
|
tmp_list = new int[]{12, 13, 14, 15}; // Update list for y position 300
|
|
return tmp_list[lane]; // Return user placed puzzle position
|
|
default:
|
|
tmp_list = new int[]{-1, -1, -1, -1}; // Default list for other positions
|
|
return tmp_list[lane]; // Return user placed puzzle position
|
|
}
|
|
}
|
|
|
|
// Function to handle key press events
|
|
void keyPressed() {
|
|
if (key_pressed == 0) {
|
|
// Check key pressed and perform corresponding action
|
|
if (key == 'j') {
|
|
gs.puzzles.move_left(); // Move puzzle left
|
|
}
|
|
|
|
if (key == 'k') {
|
|
gs.puzzles.move_right(); // Move puzzle right
|
|
}
|
|
|
|
if (key == 'm') {
|
|
println("down pressed");
|
|
gs.puzzles.move_down(); // Move puzzle down
|
|
}
|
|
|
|
if (key == 'd') {
|
|
// Handle other key events
|
|
}
|
|
|
|
if (key == 's') {
|
|
gs.start_game(); // Start the game
|
|
}
|
|
|
|
if (key == 'r') {
|
|
println("press r to restart");
|
|
gs.reset_game(); // Reset the game
|
|
}
|
|
|
|
if (key == 'n') {
|
|
// Handle other key events
|
|
}
|
|
key_pressed = 1; // Set key pressed flag
|
|
}
|
|
}
|
|
|
|
// Function to handle key release events
|
|
void keyReleased() {
|
|
key_pressed = 0; // Reset key pressed flag
|
|
}
|