基于Vue与Pixi.js的跑酷游戏开发实战
本文介绍如何利用Vue框架结合Pixi.js图形库开发一款简单的跑酷小游戏。内容涵盖项目初始化、依赖安装,以及核心逻辑模块的设计,包括场景滚动、障碍物生成与碰撞检测、玩家角色控制等功能的实现细节。
前言
本项目基于Vue框架与Pixi.js图形库构建,部分游戏素材来源于爱给网。该案例仅用于Pixi.js技术学习,若涉及侵权请联系删除。
项目地址
shellingfordly/pixi-games
演示地址
pixi-games

初始化项目
采用Vite工具进行项目初始化。
pnpm create vite my-vue-app安装pixi.js和pixi-tweener
Pixi-tweener是一个用于制作过渡动画的开源库。
pnpm i pixi.js pixi-tweener主要逻辑
useParkour
该函数负责创建Pixi应用实例,并将场景、障碍物及人物元素添加至应用中。
- containerRef:Canvas容器的引用
- gameStart:控制游戏启动
- start:表示游戏开始状态
- score:记录当前分数
- hp:表示玩家血量
export function useParkour() {
const containerRef = ref();
const app = new Application({
width: BODY_HEIGHT,
height: BODY_WIDTH,
backgroundColor: 0xffffff,
});
const start = ref(false);
Tweener.init(app.ticker);
const container = new Container();
app.stage.addChild(container);
const player = new Player();
const { scene, runScene, stopScene } = useScene();
const { trap, runHurdle, score, hp } = useHurdle();
container.addChild(player);
container.addChild(scene);
container.addChild(trap);
container.sortChildren();
runScene();
function gameStart() {
start.value = true;
player.play();
const timer = setTimeout(() => {
runHurdle(player);
clearTimeout(timer);
}, 1000);
}
watch(hp, (value) => {
if (value === 0) {
player.stop();
stopScene();
start.value = false;
}
});
onMounted(() => {
if (containerRef.value) containerRef.value.appendChild(app.view);
});
return { containerRef, app, score, hp, gameStart, start };
}useScene
该函数用于构建天空与地面的背景场景。
加载天空与地面的纹理数据,并创建平铺精灵(TilingSprite)。TilingSprite类在处理场景滚动效果时较为便捷。
通过创建Ticker实例,每帧递减精灵的x坐标,从而实现场景的移动效果。
export function useScene() {
const loader = new Loader();
const scene = new Container();
scene.height = 130;
scene.zIndex = 1;
const ticker = new Ticker();
loader
.add("footer", FooterImg)
.add("sky", SkyImg)
.load(() => {
const footer = new TilingSprite(
loader.resources.footer.texture as Texture,
BODY_HEIGHT,
130
);
footer.y = BODY_WIDTH - 130;
footer.zIndex = 2;
const sky = new TilingSprite(
loader.resources.sky.texture as Texture,
BODY_HEIGHT,
BODY_WIDTH - 80
);
sky.tileScale.y = 0.6;
sky.zIndex = 1;
sky.y = -30;
scene.addChild(footer);
scene.addChild(sky);
scene.sortChildren();
const sceneTicker = () => {
footer.tilePosition.x -= 3;
sky.tilePosition.x -= 3;
};
ticker.add(sceneTicker);
});
function runScene() {
ticker.start();
}
function stopScene() {
ticker.stop();
}
return { scene, runScene, stopScene };
}useHurdle
该函数负责生成游戏中的障碍物。
其创建方式与场景类似,但障碍物使用的是普通精灵类(Sprite)。通过Ticker更新其x坐标实现移动。
在障碍物移动过程中执行与玩家角色的碰撞检测:若发生碰撞则扣除生命值,若未碰撞则增加分数。
export function useHurdle() {
const loader = new Loader();
const trap = new Container();
const ticker = new Ticker();
const textures: Texture[] = [];
let player: Sprite | null = null;
const hp = ref(100);
const score = ref(0);
let timer: NodeJS.Timer;
trap.zIndex = 3;
loader.add("trap", TrapImg).load((_, resources) => {
TrapTexturePosition.forEach((position) => {
const t = new Texture(
resources.trap.texture as any,
new Rectangle(...position)
);
textures.push(t);
});
});
loader.load(() => {
timer = setInterval(() => {
const index = Math.floor(Math.random() * 2) + 1;
const item = new Sprite(textures[index]);
item.width = 80;
item.height = 40;
item.x = BODY_HEIGHT;
item.y = BODY_WIDTH - 120;
trap.addChild(item);
let scoreFlag = true;
let hpFlag = true;
let isHit = false;
function itemTicker() {
item.x -= 8;
if (player && !isHit) {
isHit = hitTestRectangle(player, item);
if (hpFlag && isHit) {
hp.value -= 10;
hpFlag = false;
if (hp.value === 0) stopGame();
} else if (scoreFlag && item.x < player.x) {
score.value++;
scoreFlag = false;
}
}
if (item.x < -item.width) {
ticker.remove(itemTicker);
trap.removeChild(item);
}
}
ticker.add(itemTicker);
}, 2000);
});
function runHurdle(target: Sprite) {
player = target;
ticker.start();
}
function stopGame() {
timer && clearInterval(timer);
ticker.stop();
}
return { trap, runHurdle, score, hp };
}Player
玩家类:实现了跑动、跳跃、滑铲以及入场动画等效果。
通过切换Sprite的纹理(texture)来实现跑动动画。同时监听键盘事件,按下上键时减小y坐标实现跳跃,按下下键时切换为滑铲纹理。
export class Player extends Sprite {
defaultY = BODY_WIDTH - 160;
textures: Texture[] = [];
status: "run" | "jump" | "slide" = "run";
ticker = new Ticker();
constructor() {
super();
this.width = 80;
this.height = 80;
this.x = -120;
this.y = this.defaultY;
this.zIndex = 10;
this.loader();
this.watchEvent();
}
private loader() {
const loader = new Loader();
loader.add("player", PlayerImg).load((_, resources) => {
PlayerTexturePosition.forEach((position, i) => {
const texture = new Texture(
resources.player.texture as any,
new Rectangle(...position)
);
this.textures.push(texture);
});
});
}
private watchEvent() {
document.addEventListener("keydown", this.keydown);
document.addEventListener("keyup", this.keyup);
}
private clearEvent() {
document.removeEventListener("keyup", this.keydown);
document.removeEventListener("keydown", this.keyup);
}
private keydown = (e: any) => {
if (e.code === "ArrowUp") {
this.status = "jump";
if (this.y === this.defaultY) {
Tweener.add(
{ target: this, duration: 0.3, ease: Easing.easeInOutQuint },
{ y: this.y - 120 }
);
}
} else if (e.code === "ArrowDown") {
this.status = "slide";
this.texture = this.textures[10];
}
};
private keyup = () => {
this.status = "run";
};
stop() {
this.ticker.stop();
this.clearEvent();
}
play() {
this.ticker.autoStart = true;
const runTicker = () => {
this.down();
this.entrance();
if (this.status === "run") this.run();
else if (this.status === "jump") this.jump();
};
this.ticker.add(runTicker);
}
// 跑
run() {
this.texture = this.textures[Math.floor(Date.now() / 100) % 8];
}
jump() {
this.texture = this.textures[(Math.floor(Date.now() / 100) % 5) + 11];
}
// 下落
down() {
if (this.y < this.defaultY) {
this.status = "jump";
this.y += 5;
} else {
if (this.status === "jump") {
this.status = "run";
}
}
}
// 入场
entrance() {
if (this.x < 120) this.x += 5;
}
}至此,关于利用Pixi.js制作简单跑酷小游戏的介绍已完成。如需了解更多Pixi.js跑酷游戏相关内容,请查阅本站过往文章或继续浏览后续内容。感谢大家的支持!
D3.js 比例尺与坐标轴的配置详解
2026-11-05 16:54:46
JavaScript怎么遍历对象的Symbol键和不可枚举属性
2026-11-05 13:13:39
封装一个健壮的JS字符串判空工具函数
2026-11-05 12:16:14
JavaScript合并数组的三种常用方法:concat、扩展运算符与push
2026-11-05 11:22:29
JavaScript立即执行函数(IIFE)是什么及基本语法
2026-11-05 10:51:19








