<?php
require dirname(__DIR__) . "/vendor/autoload.php";
use Kingbes\Raylib\Core;
use Kingbes\Raylib\Shapes;
use Kingbes\Raylib\Text;
use Kingbes\Raylib\Utils;
const SCREEN_WIDTH = 800;
const SCREEN_HEIGHT = 600;
const GRID_SIZE = 20;
const GRID_WIDTH = SCREEN_WIDTH / GRID_SIZE;
const GRID_HEIGHT = SCREEN_HEIGHT / GRID_SIZE;
const UP = 0;
const RIGHT = 1;
const DOWN = 2;
const LEFT = 3;
Core::initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "贪吃蛇 - php-raylib");
Core::setTargetFPS(10);
$black = Utils::color(0, 0, 0, 255);
$white = Utils::color(255, 255, 255, 255);
$red = Utils::color(255, 0, 0, 255);
$green = Utils::color(0, 255, 0, 255);
$blue = Utils::color(0, 0, 255, 255);
$snake = [];
$food = [];
$direction = RIGHT;
$nextDirection = RIGHT;
$score = 0;
$gameOver = false;
function initGame(&$snake, &$food, &$direction, &$nextDirection, &$score) {
$snake = [
['x' => GRID_WIDTH / 2, 'y' => GRID_HEIGHT / 2],
['x' => GRID_WIDTH / 2 - 1, 'y' => GRID_HEIGHT / 2],
['x' => GRID_WIDTH / 2 - 2, 'y' => GRID_HEIGHT / 2]
];
generateFood($snake, $food);
$direction = RIGHT;
$nextDirection = RIGHT;
$score = 0;
}
function generateFood($snake, &$food) {
do {
$food['x'] = rand(0, GRID_WIDTH - 1);
$food['y'] = rand(0, GRID_HEIGHT - 1);
$onSnake = false;
foreach ($snake as $segment) {
if ($segment['x'] == $food['x'] && $segment['y'] == $food['y']) {
$onSnake = true;
break;
}
}
} while ($onSnake);
}
function checkCollision($snake) {
$head = $snake[0];
if ($head['x'] < 0 || $head['x'] >= GRID_WIDTH ||
$head['y'] < 0 || $head['y'] >= GRID_HEIGHT) {
return true;
}
for ($i = 1; $i < count($snake); $i++) {
if ($head['x'] == $snake[$i]['x'] && $head['y'] == $snake[$i]['y']) {
return true;
}
}
return false;
}
initGame($snake, $food, $direction, $nextDirection, $score);
while (!Core::windowShouldClose()) {
if (Core::isKeyPressed(265) && $direction != DOWN) {
$nextDirection = UP;
}
if (Core::isKeyPressed(262) && $direction != LEFT) {
$nextDirection = RIGHT;
}
if (Core::isKeyPressed(264) && $direction != UP) {
$nextDirection = DOWN;
}
if (Core::isKeyPressed(263) && $direction != RIGHT) {
$nextDirection = LEFT;
}
if (Core::isKeyPressed(32) && $gameOver) {
$gameOver = false;
initGame($snake, $food, $direction, $nextDirection, $score);
}
if (!$gameOver) {
$direction = $nextDirection;
$head = $snake[0];
$newHead = ['x' => $head['x'], 'y' => $head['y']];
switch ($direction) {
case UP:
$newHead['y']--;
break;
case RIGHT:
$newHead['x']++;
break;
case DOWN:
$newHead['y']++;
break;
case LEFT:
$newHead['x']--;
break;
}
array_unshift($snake, $newHead);
if ($newHead['x'] == $food['x'] && $newHead['y'] == $food['y']) {
$score += 10;
generateFood($snake, $food);
$newSpeed = min(20, 10 + (int)($score / 100) * 2);
Core::setTargetFPS($newSpeed);
} else {
array_pop($snake);
}
if (checkCollision($snake)) {
$gameOver = true;
}
}
Core::beginDrawing();
Core::clearBackground($black);
foreach ($snake as $index => $segment) {
$color = ($index == 0) ? $blue : $green;
Shapes::drawRectangle(
$segment['x'] * GRID_SIZE,
$segment['y'] * GRID_SIZE,
GRID_SIZE - 1, // 减1是为了显示网格线
GRID_SIZE - 1,
$color
);
}
Shapes::drawRectangle(
$food['x'] * GRID_SIZE,
$food['y'] * GRID_SIZE,
GRID_SIZE - 1,
GRID_SIZE - 1,
$red
);
Text::drawText("Score: " . $score, 10, 10, 20, $white);
if ($gameOver) {
Shapes::drawRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, Utils::color(0, 0, 0, 150));
Text::drawText("Game Over!", SCREEN_WIDTH / 2 - 100, SCREEN_HEIGHT / 2 - 30, 30, $red);
Text::drawText("Score: " . $score, SCREEN_WIDTH / 2 - 100, SCREEN_HEIGHT / 2 + 10, 20, $white);
Text::drawText("Press Space to Restart", SCREEN_WIDTH / 2 - 150, SCREEN_HEIGHT / 2 + 40, 20, $white);
}
Core::endDrawing();
}
Core::closeWindow();