
рыцари и сок добрый
Страница: 1
Сообщений 1 страница 14 из 14
Поделиться102026-05-16 13:09:58
аххаах
Поделиться142026-05-23 01:32:32
Код:
//=============================================================================
// PK_Platformer.js
//=============================================================================
/*:
* @plugindesc Полноценная платформерная физика и плавная камера поверх RPG Maker MZ
* @author YourName
*
* @help
* 1. Поставь на события-платформы тег в Note: <platform:X>
* Где X - ширина платформы в тайлах (1 тайл = 48px). Высота всегда 24px.
* Пример: <platform:3> создаст платформу 144x24 пикселей.
* 2. Управление: Стрелки / A,D - бег. Пробел / Enter / Z - прыжок.
*/
(() => {
// --- НАСТРОЙКИ ФИЗИКИ ---
const TILE_SIZE = 48;
// Изменено: Увеличена гравитация для ощущения веса
const GRAVITY = 1.1; // Было 0.6
const MAX_FALL_SPEED = 18; // Было 12 (падаем быстрее)
const MOVE_ACCEL = 1.0; // Было 0.8 (чуть быстрее разгоняется)
const FRICTION = 0.85;
const MAX_SPEED = 6;
// Изменено: Снижена сила прыжка
const JUMP_FORCE = -12; // Было -11 (прыгаем ниже)
const JUMP_MOMENTUM_BONUS = 0.1; // Было 0.15
const JUMP_CUT_MULTIPLIER = 0.4;
const LOW_GRAVITY_MULTIPLIER = 0.55; // Было 0.5 (чуть быстрее отпускаем вершину прыжка)
// --- Наш кастомный игрок ---
const player = {
x: 0, y: 0,
width: 30, height: 30,
vx: 0, vy: 0,
isGrounded: false,
isJumping: false
};
// --- Массивы ---
let platforms = [];
let platformSprites = [];
let playerSprite = null;
// ==========================================
// 1. ИНИЦИАЛИЗАЦИЯ КАРТЫ
// ==========================================
const _Game_Map_setup = Game_Map.prototype.setup;
Game_Map.prototype.setup = function(mapId) {
_Game_Map_setup.call(this, mapId);
cachePlatforms();
player.x = $gamePlayer.x * TILE_SIZE;
player.y = $gamePlayer.y * TILE_SIZE;
player.vx = 0;
player.vy = 0;
playerSprite = null;
platformSprites = [];
};
function cachePlatforms() {
platforms = [];
$gameMap.events().forEach(event => {
const platformWidthStr = event.event().meta.platform;
if (platformWidthStr) {
const widthInTiles = Number(platformWidthStr);
platforms.push({
x: event.x * TILE_SIZE,
y: event.y * TILE_SIZE,
width: widthInTiles * TILE_SIZE,
height: TILE_SIZE / 2
});
}
});
}
// ==========================================
// 2. СКРЫВАЕМ СТАНДАРТНОГО ГЕРОЯ
// ==========================================
const _Spriteset_Map_createCharacters = Spriteset_Map.prototype.createCharacters;
Spriteset_Map.prototype.createCharacters = function() {
_Spriteset_Map_createCharacters.call(this);
this._characterSprites.forEach(sprite => {
if (sprite._character === $gamePlayer) {
sprite.opacity = 0;
}
});
};
// ==========================================
// 3. СОЗДАНИЕ СПРАЙТОВ
// ==========================================
const _Spriteset_Map_createLowerLayer = Spriteset_Map.prototype.createLowerLayer;
Spriteset_Map.prototype.createLowerLayer = function() {
_Spriteset_Map_createLowerLayer.call(this);
if (platformSprites.length === 0 && platforms.length > 0) {
platforms.forEach(p => {
let spr = new Sprite();
spr.bitmap = new Bitmap(p.width, p.height);
spr.bitmap.fillRect(0, 0, p.width, p.height, '#444444');
spr.bitmap.fillRect(0, 0, p.width, 3, '#666666');
this.addChild(spr);
platformSprites.push({ sprite: spr, x: p.x, y: p.y });
});
}
if (!playerSprite) {
playerSprite = new Sprite();
playerSprite.bitmap = new Bitmap(player.width, player.height);
this.addChild(playerSprite);
}
};
// ==========================================
// 4. ОБНОВЛЕНИЕ ПОЗИЦИЙ СПРАЙТОВ
// ==========================================
const _Spriteset_Map_update = Spriteset_Map.prototype.update;
Spriteset_Map.prototype.update = function() {
_Spriteset_Map_update.call(this);
if (!$gameMap) return;
const camX = $gameMap.displayX() * TILE_SIZE;
const camY = $gameMap.displayY() * TILE_SIZE;
platformSprites.forEach(ps => {
ps.sprite.x = ps.x - camX;
ps.sprite.y = ps.y - camY;
});
if (playerSprite) {
playerSprite.x = player.x - camX;
playerSprite.y = player.y - camY;
playerSprite.bitmap.clear();
if (!player.isGrounded) {
playerSprite.bitmap.fillRect(0, 0, player.width, player.height, '#ff5555');
} else if (Math.abs(player.vx) > 0.5) {
playerSprite.bitmap.fillRect(0, 0, player.width, player.height, '#55ff55');
} else {
playerSprite.bitmap.fillRect(0, 0, player.width, player.height, '#ffffff');
}
}
};
// ==========================================
// 5. ПЛАВНАЯ КАМЕРА
// ==========================================
Game_Player.prototype.updateScroll = function() {};
function updateCamera() {
const targetX = (player.x + player.width / 2) - Graphics.width / 2;
const targetY = (player.y + player.height / 2) - Graphics.height / 2;
const lerpSpeed = 0.1;
$gameMap._displayX += ((targetX / TILE_SIZE) - $gameMap._displayX) * lerpSpeed;
$gameMap._displayY += ((targetY / TILE_SIZE) - $gameMap._displayY) * lerpSpeed;
const maxX = Math.max(0, $gameMap.width() - Graphics.width / TILE_SIZE);
const maxY = Math.max(0, $gameMap.height() - Graphics.height / TILE_SIZE);
$gameMap._displayX = Math.max(0, Math.min(maxX, $gameMap._displayX));
$gameMap._displayY = Math.max(0, Math.min(maxY, $gameMap._displayY));
}
// ==========================================
// 6. ИГРОВОЙ ЦИКЛ И ФИЗИКА
// ==========================================
const _Scene_Map_update = Scene_Map.prototype.update;
Scene_Map.prototype.update = function() {
_Scene_Map_update.call(this);
if (!$gameMessage.isBusy()) {
updatePhysics();
updateCamera();
}
};
function updatePhysics() {
const left = Input.isPressed('left');
const right = Input.isPressed('right');
const ok = Input.isPressed('ok');
const okTriggered = Input.isTriggered('ok');
if (left) player.vx -= MOVE_ACCEL;
if (right) player.vx += MOVE_ACCEL;
if (!left && !right) {
player.vx *= FRICTION;
if (Math.abs(player.vx) < 0.1) player.vx = 0;
}
player.vx = Math.max(-MAX_SPEED, Math.min(MAX_SPEED, player.vx));
if (okTriggered && player.isGrounded) {
let currentJumpForce = JUMP_FORCE - (Math.abs(player.vx) * JUMP_MOMENTUM_BONUS);
player.vy = currentJumpForce;
player.isGrounded = false;
player.isJumping = true;
}
if (!ok && player.isJumping && player.vy < 0) {
player.vy *= JUMP_CUT_MULTIPLIER;
player.isJumping = false;
}
if (ok && player.vy < 0) {
player.vy += GRAVITY * LOW_GRAVITY_MULTIPLIER;
} else {
player.vy += GRAVITY;
}
if (player.vy > MAX_FALL_SPEED) player.vy = MAX_FALL_SPEED;
player.x += player.vx;
player.y += player.vy;
player.isGrounded = false;
// ИЗМЕНЕНО: Логика One-Way платформ (проходимые снизу)
for (let p of platforms) {
// Проверка пересечения
if (player.x < p.x + p.width &&
player.x + player.width > p.x &&
player.y < p.y + p.height &&
player.y + player.height > p.y) {
// Мы приземляемся ТОЛЬКО если падаем вниз (vy > 0)
// И в предыдущем кадре мы были ВЫШЕ платформы
if (player.vy > 0 && (player.y + player.height) - player.vy <= p.y) {
player.y = p.y - player.height;
player.vy = 0;
player.isGrounded = true;
player.isJumping = false;
}
// Убрана проверка на удар головой (else if).
// Теперь, если vy <= 0, мы просто пролетаем сквозь платформу!
}
}
const mapWidth = $gameMap.width() * TILE_SIZE;
if (player.x < 0) { player.x = 0; player.vx = 0; }
if (player.x + player.width > mapWidth) { player.x = mapWidth - player.width; player.vx = 0; }
if (player.y > $gameMap.height() * TILE_SIZE) {
player.x = $gamePlayer.x * TILE_SIZE;
player.y = $gamePlayer.y * TILE_SIZE;
player.vx = 0;
player.vy = 0;
}
$gamePlayer._x = Math.floor((player.x + player.width/2) / TILE_SIZE);
$gamePlayer._y = Math.floor((player.y + player.height/2) / TILE_SIZE);
$gamePlayer._realX = $gamePlayer._x;
$gamePlayer._realY = $gamePlayer._y;
$gamePlayer._through = true;
}
})();Страница: 1














