mirror of
https://github.com/tiennm99/nntv.git
synced 2026-10-16 06:14:38 +00:00
fix: bug when get into level
This commit is contained in:
1 parent
93f59a65ab
commit
5b75abdd88
4 files changed
+147
-89
No files matched your search
@@ -150,9 +150,8 @@ export const LEVELS = [
|
||||
type: "static",
|
||||
position: { row: 1, col: 6 },
|
||||
litCells: [
|
||||
// Removed ALL lit cells to make level 5 completable
|
||||
// { row: 1, col: 5 },
|
||||
// { row: 1, col: 7 }
|
||||
// Adding back one lit cell with a path still possible
|
||||
{ row: 1, col: 7 }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -230,9 +229,8 @@ export const LEVELS = [
|
||||
type: "static",
|
||||
position: { row: 1, col: 5 },
|
||||
litCells: [
|
||||
// Removed ALL lit cells to make level 7 completable
|
||||
// { row: 1, col: 4 },
|
||||
// { row: 1, col: 6 }
|
||||
// Adding back one lit cell with a path still possible
|
||||
{ row: 1, col: 6 }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -244,9 +242,8 @@ export const LEVELS = [
|
||||
type: "static",
|
||||
position: { row: 5, col: 2 },
|
||||
litCells: [
|
||||
// Removed ALL lit cells to make level 7 completable
|
||||
// { row: 5, col: 1 },
|
||||
// { row: 5, col: 3 }
|
||||
// Adding back one lit cell with a path still possible
|
||||
{ row: 5, col: 1 }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -4,8 +4,10 @@ export class LightingSystem {
|
||||
constructor(scene, grid) {
|
||||
this.scene = scene;
|
||||
this.grid = grid;
|
||||
// Create graphics object for rendering light effects
|
||||
this.graphics = this.scene.add.graphics();
|
||||
}
|
||||
|
||||
|
||||
// Xóa tất cả ánh sáng trên lưới
|
||||
clearAllLight() {
|
||||
for (let row = 0; row < this.grid.rows; row++) {
|
||||
@@ -14,11 +16,11 @@ export class LightingSystem {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Cập nhật ánh sáng từ tất cả các trạm gác
|
||||
updateLightFromGuards(guards) {
|
||||
this.clearAllLight();
|
||||
|
||||
|
||||
if (guards && Array.isArray(guards)) {
|
||||
guards.forEach(guard => {
|
||||
guard.updateLight();
|
||||
|
||||
+11
-11
@@ -13,12 +13,12 @@ export class Player {
|
||||
createSprite() {
|
||||
// Lấy vị trí pixel từ tọa độ lưới
|
||||
const { x, y } = this.scene.gridToScreen(this.row, this.col);
|
||||
|
||||
|
||||
// Tạo sprite người chơi (hình tròn đen)
|
||||
this.sprite = this.scene.add.circle(
|
||||
x,
|
||||
y,
|
||||
this.grid.cellSize / 3,
|
||||
x,
|
||||
y,
|
||||
this.grid.cellSize / 3,
|
||||
0x000000
|
||||
);
|
||||
}
|
||||
@@ -31,10 +31,10 @@ export class Player {
|
||||
|
||||
this.row = row;
|
||||
this.col = col;
|
||||
|
||||
|
||||
// Lấy vị trí pixel mới
|
||||
const { x, y } = this.scene.gridToScreen(this.row, this.col);
|
||||
|
||||
|
||||
// Tạo hiệu ứng di chuyển
|
||||
this.scene.tweens.add({
|
||||
targets: this.sprite,
|
||||
@@ -43,7 +43,7 @@ export class Player {
|
||||
duration: 100,
|
||||
ease: 'Linear'
|
||||
});
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ export class Player {
|
||||
move(direction) {
|
||||
let newRow = this.row;
|
||||
let newCol = this.col;
|
||||
|
||||
|
||||
switch (direction) {
|
||||
case 'up':
|
||||
newRow--;
|
||||
@@ -66,18 +66,18 @@ export class Player {
|
||||
newCol++;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return this.moveTo(newRow, newCol);
|
||||
}
|
||||
|
||||
// Kiểm tra xem người chơi có đang ở ô sáng không
|
||||
isInLitCell() {
|
||||
return this.grid.getCell(this.row, this.col).isLit;
|
||||
return this.grid.isLight(this.row, this.col);
|
||||
}
|
||||
|
||||
// Kiểm tra xem người chơi có đến đích không
|
||||
isAtGoal() {
|
||||
return this.grid.getCell(this.row, this.col).isGoal;
|
||||
return this.grid.isGoal(this.row, this.col);
|
||||
}
|
||||
|
||||
// Cập nhật vị trí sprite
|
||||
|
||||
+125
-66
@@ -37,40 +37,40 @@ export class Game extends Phaser.Scene {
|
||||
// Calculate grid position to center it
|
||||
const width = this.cameras.main.width;
|
||||
const height = this.cameras.main.height;
|
||||
|
||||
|
||||
this.gridOffsetX = (width - (this.gridSize * this.cellSize)) / 2;
|
||||
this.gridOffsetY = (height - (this.gridSize * this.cellSize)) / 2;
|
||||
|
||||
|
||||
// Create grid system
|
||||
this.createGridSystem();
|
||||
|
||||
|
||||
// Create lighting system
|
||||
this.lightSystem = new LightingSystem(this, this.grid);
|
||||
|
||||
|
||||
// Make guard classes available to LevelManager
|
||||
this.StaticGuard = StaticGuard;
|
||||
this.RotatingGuard = RotatingGuard;
|
||||
this.BlinkingGuard = BlinkingGuard;
|
||||
this.PatrollingGuard = PatrollingGuard;
|
||||
|
||||
|
||||
// Create level manager
|
||||
this.levelManager = new LevelManager(this);
|
||||
|
||||
|
||||
// Create turn manager
|
||||
this.turnManager = new TurnManager(this);
|
||||
|
||||
|
||||
// Create player
|
||||
this.createPlayer(0, 0); // Default position, will be updated by level data
|
||||
|
||||
|
||||
// Setup input
|
||||
this.setupInput();
|
||||
|
||||
|
||||
// Create UI
|
||||
this.createUI();
|
||||
|
||||
|
||||
// Create mobile controls if needed
|
||||
this.createMobileControls();
|
||||
|
||||
|
||||
// Load level
|
||||
this.levelManager.loadLevel(this.currentLevel);
|
||||
}
|
||||
@@ -80,16 +80,21 @@ export class Game extends Phaser.Scene {
|
||||
if (!this.isPaused) {
|
||||
// Check for keyboard input
|
||||
this.handleKeyboardInput();
|
||||
|
||||
// Check for final level special condition
|
||||
if (this.isFinalLevel) {
|
||||
this.checkFinalLevelCondition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createGridSystem() {
|
||||
this.grid = new GridSystem(this, this.gridSize, this.gridSize, this.cellSize);
|
||||
|
||||
|
||||
// Position the grid in the center of the screen
|
||||
this.grid.graphics.x = this.gridOffsetX;
|
||||
this.grid.graphics.y = this.gridOffsetY;
|
||||
|
||||
|
||||
// Render the grid
|
||||
this.grid.render();
|
||||
}
|
||||
@@ -101,7 +106,7 @@ export class Game extends Phaser.Scene {
|
||||
setupInput() {
|
||||
// Setup keyboard input
|
||||
this.cursors = this.input.keyboard.createCursorKeys();
|
||||
|
||||
|
||||
// WASD keys
|
||||
this.wasd = {
|
||||
up: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W),
|
||||
@@ -109,18 +114,18 @@ export class Game extends Phaser.Scene {
|
||||
down: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S),
|
||||
right: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D)
|
||||
};
|
||||
|
||||
|
||||
// Add click/tap input for grid cells
|
||||
this.input.on('pointerdown', (pointer) => {
|
||||
if (this.isPaused || !this.inputEnabled || !this.turnManager.isPlayerTurn) return;
|
||||
|
||||
|
||||
// Convert screen coordinates to grid coordinates
|
||||
const gridPos = this.screenToGrid(pointer.x, pointer.y);
|
||||
|
||||
|
||||
// Check if the clicked position is adjacent to the player
|
||||
const rowDiff = Math.abs(gridPos.row - this.player.row);
|
||||
const colDiff = Math.abs(gridPos.col - this.player.col);
|
||||
|
||||
|
||||
// Only allow moving to adjacent cells (not diagonally)
|
||||
if ((rowDiff === 1 && colDiff === 0) || (rowDiff === 0 && colDiff === 1)) {
|
||||
if (this.player.moveTo(gridPos.row, gridPos.col)) {
|
||||
@@ -133,15 +138,15 @@ export class Game extends Phaser.Scene {
|
||||
handleKeyboardInput() {
|
||||
// Only process input during player's turn and when input is enabled
|
||||
if (!this.inputEnabled || !this.turnManager.isPlayerTurn) return;
|
||||
|
||||
|
||||
// Use a cooldown to prevent multiple inputs in a single frame
|
||||
if (this.inputCooldown > 0) {
|
||||
this.inputCooldown--;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
let direction = null;
|
||||
|
||||
|
||||
// Check arrow keys
|
||||
if (this.cursors.up.isDown || this.wasd.up.isDown) {
|
||||
direction = 'up';
|
||||
@@ -152,7 +157,7 @@ export class Game extends Phaser.Scene {
|
||||
} else if (this.cursors.right.isDown || this.wasd.right.isDown) {
|
||||
direction = 'right';
|
||||
}
|
||||
|
||||
|
||||
if (direction) {
|
||||
if (this.player.move(direction)) {
|
||||
this.turnManager.nextTurn();
|
||||
@@ -164,56 +169,56 @@ export class Game extends Phaser.Scene {
|
||||
createUI() {
|
||||
// Create UI elements
|
||||
const width = this.cameras.main.width;
|
||||
|
||||
|
||||
// Lives display
|
||||
this.livesText = this.add.text(20, 20, `Lives: ${this.livesRemaining}`, {
|
||||
font: '18px Arial',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
|
||||
|
||||
// Level display
|
||||
this.levelText = this.add.text(width - 20, 20, `Level: ${this.currentLevel}`, {
|
||||
font: '18px Arial',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
this.levelText.setOrigin(1, 0);
|
||||
|
||||
|
||||
// Pause button
|
||||
this.pauseButton = this.add.rectangle(width - 20, 60, 100, 30, 0x444444);
|
||||
this.pauseButton.setOrigin(1, 0);
|
||||
|
||||
|
||||
this.pauseText = this.add.text(width - 70, 75, 'PAUSE', {
|
||||
font: '16px Arial',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
this.pauseText.setOrigin(0.5, 0.5);
|
||||
|
||||
|
||||
this.pauseButton.setInteractive({ useHandCursor: true })
|
||||
.on('pointerdown', () => {
|
||||
this.togglePause();
|
||||
});
|
||||
|
||||
|
||||
// Create pause menu (initially hidden)
|
||||
this.createPauseMenu();
|
||||
}
|
||||
|
||||
|
||||
createPauseMenu() {
|
||||
const width = this.cameras.main.width;
|
||||
const height = this.cameras.main.height;
|
||||
|
||||
|
||||
// Create container for pause menu
|
||||
this.pauseMenu = this.add.container(width / 2, height / 2);
|
||||
|
||||
|
||||
// Background
|
||||
const bg = this.add.rectangle(0, 0, 300, 250, 0x000000, 0.8);
|
||||
|
||||
|
||||
// Title
|
||||
const title = this.add.text(0, -100, 'PAUSED', {
|
||||
font: 'bold 32px Arial',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
title.setOrigin(0.5, 0.5);
|
||||
|
||||
|
||||
// Resume button
|
||||
const resumeButton = this.add.rectangle(0, -40, 200, 40, 0x444444);
|
||||
const resumeText = this.add.text(0, -40, 'RESUME', {
|
||||
@@ -221,7 +226,7 @@ export class Game extends Phaser.Scene {
|
||||
fill: '#ffffff'
|
||||
});
|
||||
resumeText.setOrigin(0.5, 0.5);
|
||||
|
||||
|
||||
// Restart button
|
||||
const restartButton = this.add.rectangle(0, 20, 200, 40, 0x444444);
|
||||
const restartText = this.add.text(0, 20, 'RESTART LEVEL', {
|
||||
@@ -229,7 +234,7 @@ export class Game extends Phaser.Scene {
|
||||
fill: '#ffffff'
|
||||
});
|
||||
restartText.setOrigin(0.5, 0.5);
|
||||
|
||||
|
||||
// Main menu button
|
||||
const menuButton = this.add.rectangle(0, 80, 200, 40, 0x444444);
|
||||
const menuText = this.add.text(0, 80, 'MAIN MENU', {
|
||||
@@ -237,10 +242,10 @@ export class Game extends Phaser.Scene {
|
||||
fill: '#ffffff'
|
||||
});
|
||||
menuText.setOrigin(0.5, 0.5);
|
||||
|
||||
|
||||
// Add all elements to container
|
||||
this.pauseMenu.add([bg, title, resumeButton, resumeText, restartButton, restartText, menuButton, menuText]);
|
||||
|
||||
|
||||
// Make buttons interactive
|
||||
resumeButton.setInteractive({ useHandCursor: true })
|
||||
.on('pointerover', () => resumeButton.fillColor = 0x666666)
|
||||
@@ -248,7 +253,7 @@ export class Game extends Phaser.Scene {
|
||||
.on('pointerdown', () => {
|
||||
this.togglePause();
|
||||
});
|
||||
|
||||
|
||||
restartButton.setInteractive({ useHandCursor: true })
|
||||
.on('pointerover', () => restartButton.fillColor = 0x666666)
|
||||
.on('pointerout', () => restartButton.fillColor = 0x444444)
|
||||
@@ -256,59 +261,59 @@ export class Game extends Phaser.Scene {
|
||||
this.togglePause();
|
||||
this.levelManager.loadLevel(this.currentLevel);
|
||||
});
|
||||
|
||||
|
||||
menuButton.setInteractive({ useHandCursor: true })
|
||||
.on('pointerover', () => menuButton.fillColor = 0x666666)
|
||||
.on('pointerout', () => menuButton.fillColor = 0x444444)
|
||||
.on('pointerdown', () => {
|
||||
this.scene.start('MainMenu');
|
||||
});
|
||||
|
||||
|
||||
// Hide pause menu initially
|
||||
this.pauseMenu.setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
togglePause() {
|
||||
this.isPaused = !this.isPaused;
|
||||
this.pauseMenu.setVisible(this.isPaused);
|
||||
this.inputEnabled = !this.isPaused;
|
||||
}
|
||||
|
||||
|
||||
createMobileControls() {
|
||||
// Create mobile control buttons
|
||||
const width = this.cameras.main.width;
|
||||
const height = this.cameras.main.height;
|
||||
|
||||
|
||||
// Container for mobile controls
|
||||
this.mobileControls = this.add.container(width / 2, height - 100);
|
||||
|
||||
|
||||
// Create directional buttons
|
||||
const buttonSize = 60;
|
||||
const buttonSpacing = 70;
|
||||
|
||||
|
||||
// Up button
|
||||
const upButton = this.add.circle(0, -buttonSpacing, buttonSize / 2, 0x444444);
|
||||
const upText = this.add.text(0, -buttonSpacing, '↑', { font: '32px Arial', fill: '#ffffff' });
|
||||
upText.setOrigin(0.5, 0.5);
|
||||
|
||||
|
||||
// Left button
|
||||
const leftButton = this.add.circle(-buttonSpacing, 0, buttonSize / 2, 0x444444);
|
||||
const leftText = this.add.text(-buttonSpacing, 0, '←', { font: '32px Arial', fill: '#ffffff' });
|
||||
leftText.setOrigin(0.5, 0.5);
|
||||
|
||||
|
||||
// Right button
|
||||
const rightButton = this.add.circle(buttonSpacing, 0, buttonSize / 2, 0x444444);
|
||||
const rightText = this.add.text(buttonSpacing, 0, '→', { font: '32px Arial', fill: '#ffffff' });
|
||||
rightText.setOrigin(0.5, 0.5);
|
||||
|
||||
|
||||
// Down button
|
||||
const downButton = this.add.circle(0, buttonSpacing, buttonSize / 2, 0x444444);
|
||||
const downText = this.add.text(0, buttonSpacing, '↓', { font: '32px Arial', fill: '#ffffff' });
|
||||
downText.setOrigin(0.5, 0.5);
|
||||
|
||||
|
||||
// Add buttons to container
|
||||
this.mobileControls.add([upButton, upText, leftButton, leftText, rightButton, rightText, downButton, downText]);
|
||||
|
||||
|
||||
// Make buttons interactive
|
||||
upButton.setInteractive({ useHandCursor: true })
|
||||
.on('pointerdown', () => {
|
||||
@@ -318,7 +323,7 @@ export class Game extends Phaser.Scene {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
leftButton.setInteractive({ useHandCursor: true })
|
||||
.on('pointerdown', () => {
|
||||
if (!this.isPaused && this.inputEnabled && this.turnManager.isPlayerTurn) {
|
||||
@@ -327,7 +332,7 @@ export class Game extends Phaser.Scene {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
rightButton.setInteractive({ useHandCursor: true })
|
||||
.on('pointerdown', () => {
|
||||
if (!this.isPaused && this.inputEnabled && this.turnManager.isPlayerTurn) {
|
||||
@@ -336,7 +341,7 @@ export class Game extends Phaser.Scene {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
downButton.setInteractive({ useHandCursor: true })
|
||||
.on('pointerdown', () => {
|
||||
if (!this.isPaused && this.inputEnabled && this.turnManager.isPlayerTurn) {
|
||||
@@ -345,16 +350,16 @@ export class Game extends Phaser.Scene {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Only show mobile controls on touch devices
|
||||
this.mobileControls.setVisible(false);
|
||||
|
||||
|
||||
// Check if device has touch capability
|
||||
if (this.sys.game.device.input.touch) {
|
||||
this.mobileControls.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Helper method to convert grid coordinates to screen coordinates
|
||||
gridToScreen(row, col) {
|
||||
const gridPos = this.grid.gridToPixel(row, col);
|
||||
@@ -363,24 +368,24 @@ export class Game extends Phaser.Scene {
|
||||
y: gridPos.y + this.gridOffsetY
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Helper method to convert screen coordinates to grid coordinates
|
||||
screenToGrid(x, y) {
|
||||
return this.grid.pixelToGrid(x - this.gridOffsetX, y - this.gridOffsetY);
|
||||
}
|
||||
|
||||
|
||||
// Xử lý khi người chơi bị bắt
|
||||
handlePlayerCaught() {
|
||||
this.livesRemaining--;
|
||||
|
||||
|
||||
// Cập nhật hiển thị số mạng
|
||||
if (this.livesText) {
|
||||
this.livesText.setText(`Lives: ${this.livesRemaining}`);
|
||||
}
|
||||
|
||||
|
||||
if (this.livesRemaining <= 0) {
|
||||
// Hết mạng, game over
|
||||
this.scene.start('GameOver', {
|
||||
this.scene.start('GameOver', {
|
||||
level: this.currentLevel,
|
||||
isLastLevel: false
|
||||
});
|
||||
@@ -389,30 +394,84 @@ export class Game extends Phaser.Scene {
|
||||
this.levelManager.loadLevel(this.currentLevel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Xử lý khi người chơi hoàn thành màn chơi
|
||||
handleLevelComplete() {
|
||||
const nextLevel = this.currentLevel + 1;
|
||||
|
||||
|
||||
// Kiểm tra xem có phải màn cuối không
|
||||
if (this.isFinalLevel) {
|
||||
// Đây là màn cuối với cái kết đặc biệt
|
||||
this.scene.start('GameOver', {
|
||||
this.scene.start('GameOver', {
|
||||
level: this.currentLevel,
|
||||
isLastLevel: true
|
||||
});
|
||||
} else if (nextLevel > this.levelManager.getTotalLevels()) {
|
||||
// Đã hoàn thành tất cả các màn
|
||||
this.scene.start('GameOver', {
|
||||
this.scene.start('GameOver', {
|
||||
level: this.currentLevel,
|
||||
isLastLevel: false
|
||||
});
|
||||
} else {
|
||||
// Chuyển đến màn tiếp theo
|
||||
this.scene.start('Game', {
|
||||
this.scene.start('Game', {
|
||||
level: nextLevel,
|
||||
lives: this.livesRemaining
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Kiểm tra điều kiện đặc biệt cho màn cuối
|
||||
checkFinalLevelCondition() {
|
||||
if (!this.isFinalLevel) return false;
|
||||
|
||||
// Kiểm tra xem người chơi có đang ở gần công chúa không
|
||||
const playerRow = this.player.row;
|
||||
const playerCol = this.player.col;
|
||||
const goalRow = 9; // Vị trí công chúa ở màn cuối (row 9, col 9)
|
||||
const goalCol = 9;
|
||||
|
||||
// Tính khoảng cách Manhattan từ người chơi đến công chúa
|
||||
const distance = Math.abs(playerRow - goalRow) + Math.abs(playerCol - goalCol);
|
||||
|
||||
// Nếu người chơi đến gần công chúa (khoảng cách <= 2), kích hoạt cơ chế đặc biệt
|
||||
if (distance <= 2) {
|
||||
// Bật sáng toàn bộ bản đồ
|
||||
this.lightUpEntireMap();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bật sáng toàn bộ bản đồ cho màn cuối
|
||||
lightUpEntireMap() {
|
||||
// Hiển thị thông báo
|
||||
const width = this.cameras.main.width;
|
||||
const height = this.cameras.main.height;
|
||||
|
||||
if (!this.finalLevelMessage) {
|
||||
this.finalLevelMessage = this.add.text(width / 2, height / 4,
|
||||
'Công chúa phát hiện ra ninja! Toàn bộ cung điện sáng đèn!', {
|
||||
font: 'bold 20px Arial',
|
||||
fill: '#FF0000',
|
||||
backgroundColor: '#000000',
|
||||
padding: { x: 10, y: 5 }
|
||||
});
|
||||
this.finalLevelMessage.setOrigin(0.5, 0.5);
|
||||
this.finalLevelMessage.setDepth(100);
|
||||
}
|
||||
|
||||
// Bật sáng toàn bộ các ô
|
||||
for (let row = 0; row < this.grid.rows; row++) {
|
||||
for (let col = 0; col < this.grid.cols; col++) {
|
||||
if (!this.grid.isWall(row, col)) {
|
||||
this.grid.setLight(row, col, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vẽ lại lưới
|
||||
this.grid.render();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user