Files
sunny9898/task9/Final-w-bgm/Final.pde
louiscklaw 5637fbf94f update,
2025-02-01 02:07:58 +08:00

472 lines
17 KiB
Plaintext

import processing.sound.*;
SoundFile sample;
// 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
sample = new SoundFile(this, "./bg.mp3");
sample.play(1,1);
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
}