Skip to main content

尝试用pixi.js创建小游戏

在React里面使用pixi.js


写出下面的代码就可以创建出一个全屏的pixi.js画布

const PixiCanvas = () => {
const pixiContainerRef = useRef(null);

useEffect(() => {
const app = new PIXI.Application({resizeTo: window})

pixiContainerRef.current.appendChild(app.view);

return () => {
app.destroy(true);
}
}, []);

return <div ref={pixiContainerRef} />;
}


加入一个container, 将背景图片挂载到这个container上面,然后加到场景pixijs app里面

useEffect(() => {
const app = new PIXI.Application({ resizeTo: window });

const container = new PIXI.Container();

// background image
const backgroundTexture = PIXI.Texture.from(backgroundImage);
const backgroundSprite = new PIXI.Sprite(backgroundTexture);

const resizeBackground = () => {
backgroundSprite.width = window.innerWidth;
backgroundSprite.height = window.innerHeight;
};

// set position of the background picture
backgroundSprite.position.set(0, 0);
resizeBackground();

window.addEventListener('resize', resizeBackground);

container.addChild(backgroundSprite);
app.stage.addChild(container);

pixiContainerRef.current.appendChild(app.view);


loadAllImages(app);
return () => {
window.removeEventListener('resize', resizeBackground);
app.destroy(true);
}
}, []);


设置缩放大小

backgroundSprite.scale.set(2);


设置透明度

backgroundSprite.alpha = 0;

或者

backgroundSprite.visible = false;


滤镜

backgroundSprite.tint = 0xff0000;


居中

sprite.anchor.set(0.5);


为物体设置交互

sprite.interactive = true;
sprite.on("mousedown", onMouseDragStart, this)

然后在onMouseDragStart里面可以获取到e,即为event

我的游戏中,有背景的container,还有放拼图的container。因此,每次移动需要计算的offset为鼠标移动的距离加上原本的坐标。

所以在鼠标点下去的时候,可以使用以下的函数:

function onMouseDragStart(e) {
// 1. remember the position of the mouse cursor
this.touchPosition = {x: e.data.global.x, y: e.data.global.y}
// 2. set the dragging state for current sprite
this.dragging = true;
this.zIndex = 1;
}

记录下鼠标点下去的初始的点。

然后在移动的时候:

function onMouseMove(e) {
if (!this.dragging) {
return;
}
// console.log("this: ", this);
// 1. get the coordinate of the cursor
const currPosition = {x: e.data.global.x, y: e.data.global.y};

// 2. calculate offset
const offsetX = currPosition.x - this.touchPosition.x;
const offsetY = currPosition.y - this.touchPosition.y;

// 3. apply the result to this sprite
const {x, y} = this.field;
const newX = x + offsetX;
const newY = y + offsetY;
this.position.set(newX, newY);
}

计算并设置物体最终的位置。


然后在鼠标松开或者鼠标移开物体的时候,将dragging的state设置为false,并且复原位置:

function onMouseUp(e) {
this.dragging = false;
this.zIndex = 0;
this.position.set(this.field.x, this.field.y);
}

上面是整体思路,需要绑定许多事件:

sprite.on("mousedown", onMouseDragStart.bind(sprite));
sprite.on("touchstart", onMouseDragStart.bind(sprite));
sprite.on("mousemove", onMouseMove.bind(sprite));
sprite.on("touchmove", onMouseMove.bind(sprite));
sprite.on("mouseup", onMouseUp.bind(sprite));
sprite.on("mouseupoutside", onMouseUp.bind(sprite));
sprite.on("touchend", onMouseUp.bind(sprite));
sprite.on("touchendoutside", onMouseUp.bind(sprite));


在实现的过程中,我发现拖拽物体有时候拖拽无法穿过另外一个物体。然后发现穿不过去的物体,都是在我拖拽的物体的上方。说明z-index是大于我拖拽的物体的。

要实现成功拖拽,可以在拖拽开始的时候设置z-index为1,然后拖拽结束的时候重新设置为0。

并且需要在初始化拼图容器的时候,加上这个属性: 

puzzleContainer.sortableChildren = true

使其能够重新对index进行排序。


在pixi.js中,如果z-index一样,那么后生成的物体会在前面生成的物体之上。并且前生成的物体无法穿过后生成的物体。


相对位置

在我的拼图游戏中,背景的容器为一个容器,其中包含一个拼图的容器。而每次事件获取到的是global position,但是我的拼图用的都是相对于拼图容器的位置。

可以使用

const localPosition = globalPuzzleContainer.toLocal(new PIXI.Point(e.data.global.x, e.data.global.y));

来从global position获取到拼图容器中的位置


声音

要想在pixi.js中使用声音,可以使用pixi-sound

npm install pixi-sound

然后使用下面的语句来使用:

import sound from "pixi-sound";
import backgroundSound from "./sound/background-sound.mp3";
sound.add("backgroundSound", backgroundSound);
sound.play('backgroundSound');


动画

可以使用npm来安装

npm install @tweenjs/tween.js










Comments

Popular posts from this blog

Valgrind

  Using Valgrind to check memory How to use Valgrind -To valgrind the program, run the valgrind command and give it our program name as an argument. -For example, if we want to run ./myProgram hello 42, we can simply run Valgrind ./myProgram hello 42.  Uninitialized Values -When we run the program, we may use uninitialized values. It needs to be fixed. Valgrind can tell us about the use of uninitialized values. But it only tell when the control flow of the program depends on the unitialized value. For example, uninitialized value appears in the conditional expression of an if, or a loop, or in the switch statement. -If we want to know where the uninitialized value is from, we can use Valgrind    --track-origins=yes ./myProgram -Using -fsanitize=address can find a lot of problems that Memcheck cannot.  -We can use Valgrind with GDB to debug. We can run: --vgdb=full --vgdb-error=0., then Valgrind will stop on the first error that it encounters and give control to ...

Error Handling and Exceptions

  Error Handling and Exceptions - The worst possible way to deal with any problem is for the program to produce the wrong answer without informing the user - a silent failure.  - When the program deals with an error by aborting, it should do so with the explicit intention of the programmer. (i.e. the programmer should call assert or check a condition then call abort) And the program should give an error message to the user. Simply segmentation fault due to an invalid memory access is never appropriate. - Sometimes we would prefer to handle the error more gracefully. Graceful error handling requires making the user aware of the problem, as well as allowing the program to continue to function normally. - For example, we would present the user with some options to remedy the situation, like entering a different input, select a different file, retry a failed operation, etc.  - As our programming skills develop, we should get into the practice of writing bullet proof code - co...

ADTs

  ADTs 1. Queue -FIFO We can implement in this way:  template<typename T> class Queue { public:     void enqueue(const T & item);     T dequeue();     T & peek()     const T & peek() const;     int numbebrOfItem() const; }; - In the actual C++ STL library, it has the following functions: push() pop() peek() 2. Stack - LIFO We can implement in this way: template<typename T> class Stack { public:     void push(const T & item);     T pop();     T & peek();     const T & peek() const;     int numberOfItem() const; }; In the C++ STL library, it has similar functions as queue. 3. Sets - Add - Test if an item is in the set - Check if the set is empty - Take the union of two set - intersect two sets A variant of this ADT is a multiset. (Also called a bag) It allows the same element to appear multiple times, whereas a true set either has an object or n...