TypePHP 编译器 https://swoole.com/aot/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

299 lines
8.6 KiB

#include <phpx.h>
#include <SDL2/SDL.h>
#include <map>
#include <cstdlib>
using namespace php;
// Game constants
#define BLOCK_SIZE 30
#define BOARD_WIDTH 10
#define BOARD_HEIGHT 20
// Global window map to store SDL_Window* and SDL_Renderer* by handle
static std::map<Int, std::pair<SDL_Window*, SDL_Renderer*>> g_windows;
static Int g_nextHandle = 1;
// Simple test function to verify SDL is working
void php_test_sdl_loop() {
printf("[C++] Starting test_sdl_loop...\n");
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("[C++] SDL Init Error: %s\n", SDL_GetError());
return;
}
SDL_Window* window = SDL_CreateWindow("Test Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
if (!window) {
printf("[C++] Test Window Error: %s\n", SDL_GetError());
return;
}
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer) {
printf("[C++] Test Renderer Error: %s\n", SDL_GetError());
SDL_DestroyWindow(window);
return;
}
bool running = true;
SDL_Event event;
int frame = 0;
while (running) {
// Set color to Green
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = false;
}
}
frame++;
if (frame % 60 == 0) {
printf("[C++] Test loop running... frame %d\n", frame);
}
SDL_Delay(16);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
printf("[C++] Test loop exited.\n");
}
// Colors for each piece type (SDL RGBA)
static const SDL_Color COLORS[7] = {
{0, 255, 255, 255}, // I - Cyan
{255, 255, 0, 255}, // O - Yellow
{128, 0, 128, 255}, // T - Purple
{0, 255, 0, 255}, // S - Green
{255, 0, 0, 255}, // Z - Red
{0, 0, 255, 255}, // J - Blue
{255, 165, 0, 255} // L - Orange
};
// Simple game state - stores board data from PHP
class TetrisBox : public Box {
public:
int board[BOARD_HEIGHT][BOARD_WIDTH];
int score;
bool gameOver;
SDL_Window* window;
SDL_Renderer* renderer;
TetrisBox() : score(0), gameOver(false), window(nullptr), renderer(nullptr) {
memset(board, 0, sizeof(board));
printf("[C++] TetrisBox constructor called\n");
}
~TetrisBox() {
printf("[C++] TetrisBox destructor called\n");
if (renderer) {
SDL_DestroyRenderer(renderer);
}
if (window) {
SDL_DestroyWindow(window);
}
SDL_Quit();
}
};
// Create new game instance
var php_tetris_new() {
printf("[C++] php_tetris_new called\n");
auto box = new TetrisBox();
// Initialize SDL and create window
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("[C++] SDL Init Error: %s\n", SDL_GetError());
} else {
box->window = SDL_CreateWindow(
"俄罗斯方块 - PHP版",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
BLOCK_SIZE * BOARD_WIDTH + 200,
BLOCK_SIZE * BOARD_HEIGHT + 40,
SDL_WINDOW_SHOWN
);
if (box->window) {
box->renderer = SDL_CreateRenderer(box->window, -1, SDL_RENDERER_ACCELERATED);
printf("[C++] Window and renderer created\n");
}
}
return {box};
}
// Reset game
void php_tetris_reset(var box) {
auto tetris = box.toBox<TetrisBox>();
tetris->score = 0;
tetris->gameOver = false;
memset(tetris->board, 0, sizeof(tetris->board));
}
// Get score
Int php_tetris_get_score(var box) {
auto tetris = box.toBox<TetrisBox>();
return tetris->score;
}
// Check if game over
Bool php_tetris_is_game_over(var box) {
auto tetris = box.toBox<TetrisBox>();
return tetris->gameOver;
}
// Stub functions - logic is in PHP
Bool php_tetris_move_down(var box) { return true; }
Bool php_tetris_move_left(var box) { return true; }
Bool php_tetris_move_right(var box) { return true; }
void php_tetris_rotate(var box) {}
void php_tetris_hard_drop(var box) {}
// Process SDL events - returns array [type, sym, scancode] or empty array if no event
Array php_tetris_poll_event(var box) {
SDL_Event event;
Array result;
if (SDL_PollEvent(&event)) {
// Convert SDL_Event to PHP array
result.append((Int)event.type);
if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) {
result.append((Int)event.key.keysym.sym);
result.append((Int)event.key.keysym.scancode);
}
}
return result;
}
// Get SDL ticks (milliseconds since SDL init)
Int php_sdl_getticks() {
return (Int)SDL_GetTicks();
}
// Set board state from PHP
void php_tetris_set_board(var box, Array board) {
auto tetris = box.toBox<TetrisBox>();
// Copy board data from PHP array to C++ array
for (size_t i = 0; i < BOARD_HEIGHT && i < board.count(); i++) {
auto row = board[i].toArray();
for (size_t j = 0; j < BOARD_WIDTH && j < row.count(); j++) {
tetris->board[i][j] = row[j].toInt();
}
}
}
// Render game - Draw board from PHP
void php_tetris_render(var box, Int hWnd) {
auto tetris = box.toBox<TetrisBox>();
if (!tetris->renderer) {
return;
}
SDL_Renderer* renderer = tetris->renderer;
// Clear background (Black)
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
// Draw board from PHP
for (int i = 0; i < BOARD_HEIGHT; i++) {
for (int j = 0; j < BOARD_WIDTH; j++) {
if (tetris->board[i][j]) {
int colorIndex = tetris->board[i][j] - 1;
if (colorIndex >= 0 && colorIndex < 7) {
SDL_SetRenderDrawColor(renderer, COLORS[colorIndex].r, COLORS[colorIndex].g, COLORS[colorIndex].b, COLORS[colorIndex].a);
}
SDL_Rect blockRect;
blockRect.x = j * BLOCK_SIZE;
blockRect.y = i * BLOCK_SIZE;
blockRect.w = BLOCK_SIZE;
blockRect.h = BLOCK_SIZE;
SDL_RenderFillRect(renderer, &blockRect);
}
}
}
// Draw score panel on the right
int panelX = BOARD_WIDTH * BLOCK_SIZE + 20;
int panelY = 20;
// Draw background for score panel
SDL_SetRenderDrawColor(renderer, 40, 40, 40, 255);
SDL_Rect panelRect;
panelRect.x = panelX;
panelRect.y = panelY;
panelRect.w = 180;
panelRect.h = 200;
SDL_RenderFillRect(renderer, &panelRect);
// Draw "SCORE" label using simple rectangles
SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255);
for (int i = 0; i < 5; i++) {
SDL_Rect bar;
bar.x = panelX + 10;
bar.y = panelY + 10 + i * 3;
bar.w = 60;
bar.h = 2;
SDL_RenderFillRect(renderer, &bar);
}
// Display score value as simple horizontal bars
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
int score = tetris->score;
// Draw score digits as bars
char scoreStr[16];
snprintf(scoreStr, sizeof(scoreStr), "%d", score);
int yPos = panelY + 40;
for (int i = 0; scoreStr[i] != '\0' && i < 6; i++) {
int digit = scoreStr[i] - '0';
// Each digit represented by vertical bar height
int barHeight = digit * 15 + 5;
SDL_Rect digitBar;
digitBar.x = panelX + 20 + i * 25;
digitBar.y = yPos + (150 - barHeight);
digitBar.w = 15;
digitBar.h = barHeight;
SDL_RenderFillRect(renderer, &digitBar);
}
// Update the screen
SDL_RenderPresent(renderer);
}
// Handle keyboard input
void php_tetris_handle_key(var box, Int keyCode) {
auto tetris = box.toBox<TetrisBox>();
// Simplified: just increase score for testing
tetris->score += 1;
}
// Post quit message
void php_tetris_post_quit(Int exitCode) {
SDL_Quit();
}
// Show message box with UTF-8 support
Int php_tetris_messagebox(Int hWnd, String text, String caption, Int uType) {
// Use SDL's built-in message box function
SDL_MessageBoxFlags flags = SDL_MESSAGEBOX_INFORMATION;
if (uType & 0x00000010) { // MB_ICONERROR
flags = SDL_MESSAGEBOX_ERROR;
} else if (uType & 0x00000030) { // MB_ICONWARNING
flags = SDL_MESSAGEBOX_WARNING;
}
int result = SDL_ShowSimpleMessageBox(flags, caption.data(), text.data(), nullptr);
// Return appropriate value based on button pressed
// For OK button, return 1
return result == 0 ? 1 : 0;
}