热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Egret引擎学习笔记之一:实现简易贪吃蛇

Egret引擎学习笔记之一:实现简易贪吃蛇初识egret,十分简约的一款H5游戏引擎,话不多说,开始制作我们的简易版彩虹贪吃蛇。大体上是一个忽略的自生碰撞自身可以以一种离奇方式扭曲的彩

Egret引擎学习笔记之一:实现简易贪吃蛇

初识egret,十分简约的一款H5游戏引擎,话不多说,开始制作我们的简易版彩虹贪吃蛇。

大体上是一个忽略的自生碰撞的的奇怪的彩虹蛇,我们姑且把他认为是五维生物

大体上是一个忽略的自生碰撞自身可以以一种离奇方式扭曲的彩虹蛇,我们姑且把他认为是五维生物。


一、食物类

首先在这条贪吃的彩虹蛇还未出现之前,神奇的宇宙便突然出现了美味的彩虹糖,它的颜色都是随机生成生成的,当然或许是上帝偏爱七色彩虹,所以你也可以指定这些颜色,只需把下面代码中注释的地方去掉,并且注释下一行代码即可,例如:

/**
* 食物颜色
*/

private static colorList: number[] =
[0x70f3ff, 0xff461f, 0x00bc12, 0x21a675, 0x4c221b, 0xbf242a, 0x161823, 0xffa400,];
/**
* 获取随机的颜色
*/

private randomColor(): number {
// return Food.colorList[Math.round(Math.random() * Food.colorList.length)];
return parseInt("0x" + ("000000" + ((Math.random() * 16777215 + 0.5) >> 0).toString(16)).slice(-6));
}

随机颜色的获取其实就是获取六位随机十六进制数字然后在前加上“0x”标志。

为了确定食物所在的具体位置和大小,我们还需要传入二维坐标和食物的半径

private food: egret.Shape;
public color: number;
/**
* 初始化
*
* 1.绘制果实
*/

private init(x: number, y: number, r: number): void {

//获取随机颜色
this.color = this.randomColor();

this.food = new egret.Shape();
this.food.graphics.beginFill(this.color);
this.food.graphics.drawCircle(0, 0, r);
this.food.graphics.endFill();

this.food.x = r;
this.food.y = r;

//位置
this.x = x;
this.y = y;

this.addChild(this.food);
}

我们可以看到,食物的形状是作为一个Shape存在的,这是egret内置的一个对象类,可以使用画笔进行绘图,先获取事物对象的graphics画笔,由于粒子间的相互作用,食物被力制约成圆形,所以我们使用drawCircle( )函数进行绘制,绘制完成后设置食物的位置

我们可以看到上块代码中有
this.food.x = r;
this.food.y = r;
//位置
this.x = x;
this.y = y;
以上两种位置设置,首先需要说明的是typescript就像所有面向对象语言一样,在在类中this就代表了当前实例对象。那么第一个是设置该图像(即圆形)出现在食物中的位置,我们设定为处于中间位置即可,第二个是设置食物在空间中的位置,我们将传进来的位置写入即可。

最后作为食物就要有被吃掉的觉悟,我们将食物这个物体在父节点——也就是舞台中去除就好了。

/**
* 被吃的
*/

public onEat() {
this.parent.removeChild(this);
}

当然我们仍然不能忘记食物作为一个自定义类就必须拥有我们的构造函数。它需要传入的横纵坐标来确定位置,还需要半径来确定大小,之后我们调用前面的init方法初始化食物的样式和位置即可。

/**
* @param x 横坐标
* @param y 纵坐标
* @param r 半径
*/

public constructor(x: number, y: number, r: number) {
super();
this.init(x, y, r);
}

食物作为一个会在屏幕上反复出现的元素,我们将其称为精灵
在egret中使用Sprite来定义,所以我们的食物类便需要继承自它

当然,我们完全可以将食物看做在游戏中一次只会出现一个的“固定”的对象,每次更改食物都是单纯的更改它的属性;但为了日后可以制作多人网络对战的版本,我们选用目前的精灵版。

最后我们彩虹糖食物的代码看起来就像这样

class Food extends egret.Sprite {

/**
* 食物颜色
*/

private static colorList: number[] =
[0x70f3ff, 0xff461f, 0x00bc12, 0x21a675, 0x4c221b, 0xbf242a, 0x161823, 0xffa400,];

/**
* @param x 横坐标
* @param y 纵坐标
* @param r 半径
*/

public constructor(x: number, y: number, r: number) {
super();
this.init(x, y, r);
}

private food: egret.Shape;
public color: number;

/**
* 初始化
*
* 1.绘制果实
*/

private init(x: number, y: number, r: number): void {

//获取随机颜色
this.color = this.randomColor();

this.food = new egret.Shape();
this.food.graphics.beginFill(this.color);
this.food.graphics.drawCircle(0, 0, r);
this.food.graphics.endFill();

this.food.x = r;
this.food.y = r;

//位置
this.x = x;
this.y = y;

this.addChild(this.food);
}

/**
* 获取随机的颜色
*/

private randomColor(): number {
// return Food.colorList[Math.round(Math.random() * Food.colorList.length)];
return parseInt("0x" + ("000000" + ((Math.random() * 16777215 + 0.5) >> 0).toString(16)).slice(-6));
}

/**
* 被吃
*/

public onEat() {
this.parent.removeChild(this);
}
}

二、彩虹蛇类

即使作为一只四维生物,彩虹蛇仍然改变不了贪吃的本质,所以我们要先给它一颗张着嘴巴的脑袋:

    //蛇头
private head: egret.Shape;
//蛇身的半径
private radius;
//蛇身的全部节点list(保存蛇每个节点的信息和蛇本身做区别)
private bodyList: egret.Shape[] = [];
/**
* 根据横纵坐标,半径和颜色来初始化蛇头
* @param x 横坐标
* @param y 纵坐标
* @param r 半径
* @param color 颜色
*/

private init(x: number, y: number, r: number, color: number) {
//绘制蛇头,同样是一个实心圆
this.head = new egret.Shape();
this.head.graphics.lineStyle(10, 0xff4777);
this.head.graphics.beginFill(color);
this.head.graphics.drawCircle(r, r, r);
this.head.graphics.endFill();

//设置蛇头在蛇身的位置
this.head.x = 0;
this.head.y = 0;
this.radius = r;

//设置蛇身的位置
this.x = x;
this.y = y;
//将蛇头添加入蛇身的list
this.bodyList.push(this.head);
//将蛇头加入到蛇身中并指定显示索引为最大,以保证蛇头永远在蛇身其他节点的上方。
this.addChild(this.bodyList[this.bodyList.length - 1]);
this.setChildIndex(this.bodyList[this.bodyList.length - 1], -999);
}

同样地添加蛇的构造函数,此时蛇的颜色不是随机的,由我们在以后来指定。

public constructor(x: number, y: number, r: number, color: number) {
super();
this.init(x, y, r, color);
}

当我们的彩虹蛇吃到食物时,就会引发身体变长的事件,也就是蛇身新增一个节点,我们将食物自身的颜色作为新增节点的颜色,同时绘制一个实心圆添加到蛇身上即可。

/***
* 吃食物后增加节点
* @param color 食物的颜色
*/

public afterEat(color: number) {
//新增的节点(蛇身)
var node: egret.Shape = new egret.Shape();
node.graphics.beginFill(color);
node.graphics.drawCircle(this.radius, this.radius, this.radius);
node.graphics.endFill();

//指定新增节点的位置在蛇身节点list的最后一个节点,也就是蛇尾的一个坐标偏移(这里可以随便指定合理的位置即可)
node.x = this.bodyList[this.bodyList.length - 1].x + this.radius * 0.6;
node.y = this.bodyList[this.bodyList.length - 1].y + this.radius * 0.6;

//将新增节点添加入蛇身和蛇身节点list
this.bodyList.push(node);
this.addChild(this.bodyList[this.bodyList.length - 1]);
//不要忘了指定新增节点的显示索引,我们将它放在所有节点的最下面。
this.setChildIndex(this.bodyList[this.bodyList.length - 1], 0);
}

我们的彩虹蛇现在万事俱备,只需要扭动着它肥胖的身体,受着贪婪欲望的指使便可以来一场饕鬄盛宴了,我们为它加上移动的逻辑:
首先考虑到游戏玩法是用鼠标或者手指在屏幕上点击,以获得一个位置坐标,然后我们将这个坐标视为彩虹蛇移动的目的地,将它移动过去即可;
为了获取方向,我们必须先得到目标点坐标和蛇头坐标:

    //我们可以利用用户的点击事件 e:egret.TouchEvent来方便的获取到点击坐标
var mx = e.stageX;
var my = e.stageY;

为了获取蛇头的坐标,我们必须先理解一个概念:用户点击的点存在于Stage舞台上;而彩虹蛇本身作为一个Spite出现在Stage上,蛇头和蛇身都是彩虹蛇内部的一个Shape,为了使蛇移动,那么我们需要获取到蛇头在Stage上的位置,使用它和目标点进行运算才可以确定蛇移动下一步的位置。

    //我们前面知道蛇身节点list的首个节点其实就是蛇头
//让它在蛇中的偏移坐标加上蛇在舞台中的坐标,便可以得到全局坐标
var hx = this.x + this.bodyList[0].x;
var hy = this.y + this.bodyList[0].y;

好了,反过头来看蛇身节点,我们知道彩虹蛇总是位于后边的节点会走到它前边的节点的位置上,所以我们遍历所有节点,让它新的位置改为它的上一个节点的位置即可:

var tween: egret.Tween;
for (var i = this.bodyList.length - 1; i >= 1; i--) {
tween = egret.Tween.get(this.bodyList[i]);
tween.to({ x: this.bodyList[i - 1].x, y: this.bodyList[i - 1].y }, during);
}

egret的缓动动画由Tween定义,使用tween.to()函数进行对某些数值的变化,在上面代码中,我们将该节点当前位置的坐标改为上一个节点的坐标,持续时间是during所定义好的数值,会有一个平滑的数值改变,增强用户体验。

需要看到的是,我们使用了反向遍历节点集合,这样做的目的很好理解,因为我们需要位于索引前的节点的坐标值。

最后我们的首节点,也就是蛇头需要一个明确的位置去移动。
所以根据所学的平面几何可以很方便的计算两点的连线:

    //斜率
var mk = (my - hy) / (mx - hx);
//角度
var mangle = Math.atan(mk);

之后便可以按照预设好的移动距离,将蛇头的坐标更改上去即可

 //
//修改横纵坐标
tmpx = this.bodyList[0].x - this.speed * Math.cos(mangle);
tmpy = this.bodyList[0].y - this.speed * Math.sin(mangle);
//别忘了缓动动画
tween.to({ x: tmpx, y: tmpy }, during);

当然我们还应该考虑多种情况:

  1. 点击的位置和蛇头相同
  2. x轴上垂直
  3. 方向

所以最后看起了像这样

    tween = egret.Tween.get(this.bodyList[0]);
var tmpx, tmpy;
if (hx == mx && hy == my) {
//位置相同
return;
}
if (hx != mx) {
//非垂直

//斜率
var mk = (my - hy) / (mx - hx);
//角度
var mangle = Math.atan(mk);
if (mx //左边
tmpx = this.bodyList[0].x - this.speed * Math.cos(mangle);
tmpy = this.bodyList[0].y - this.speed * Math.sin(mangle);
tween.to({ x: tmpx, y: tmpy }, during);
} else {
//右边
tmpx = this.bodyList[0].x + this.speed * Math.cos(mangle);
tmpy = this.bodyList[0].y + this.speed * Math.sin(mangle);
tween.to({ x: tmpx, y: tmpy }, during);
}
} else {
//垂直
if (mx //水平向左
tmpx = this.bodyList[0].x - this.speed;
tween.to({ x: tmpx, y: tmpy }, during);
} else {
//水平向右
tmpx = this.bodyList[0].x + this.speed;
tween.to({ x: tmpx, y: tmpy }, during);
}
}

好了,最后我们的彩虹蛇也制作完成了,Snake.ts的完整代码如下:

class Snake extends egret.Sprite {
public constructor(x: number, y: number, r: number, color: number) {
super();
this.init(x, y, r, color);
}

//蛇头
private head: egret.Shape;
//蛇身的半径
private radius;
//蛇身的全部节点list(保存蛇每个节点的信息和蛇本身做区别)
private bodyList: egret.Shape[] = [];
/**
* 根据横纵坐标,半径和颜色来初始化蛇头
* @param x 横坐标
* @param y 纵坐标
* @param r 半径
* @param color 颜色
*/

private init(x: number, y: number, r: number, color: number) {
//绘制蛇头,同样是一个实心圆
this.head = new egret.Shape();
this.head.graphics.lineStyle(10, 0xff4777);
this.head.graphics.beginFill(color);
this.head.graphics.drawCircle(r, r, r);
this.head.graphics.endFill();

//设置蛇头在蛇身的位置
this.head.x = 0;
this.head.y = 0;
this.radius = r;

//设置蛇身的位置
this.x = x;
this.y = y;
//将蛇头添加入蛇身的list
this.bodyList.push(this.head);
//将蛇头加入到蛇身中并指定显示索引为最大,以保证蛇头永远在蛇身其他节点的上方。
this.addChild(this.bodyList[this.bodyList.length - 1]);
this.setChildIndex(this.bodyList[this.bodyList.length - 1], -999);
}
/***
* 吃食物后增加节点
* @param color 食物的颜色
*/

public afterEat(color: number) {
//新增的节点(蛇身)
var node: egret.Shape = new egret.Shape();
node.graphics.beginFill(color);
node.graphics.drawCircle(this.radius, this.radius, this.radius);
node.graphics.endFill();

//指定新增节点的位置在蛇身节点list的最后一个节点,也就是蛇尾的一个坐标偏移(这里可以随便指定合理的位置即可)
node.x = this.bodyList[this.bodyList.length - 1].x + this.radius * 0.6;
node.y = this.bodyList[this.bodyList.length - 1].y + this.radius * 0.6;

//将新增节点添加入蛇身和蛇身节点list
this.bodyList.push(node);
this.addChild(this.bodyList[this.bodyList.length - 1]);
//不要忘了指定新增节点的显示索引,我们将它放在所有节点的最下面。
this.setChildIndex(this.bodyList[this.bodyList.length - 1], 0);
}

public speed = 20;
public move(e: egret.TouchEvent, during: number) {
//我们可以利用用户的点击事件 e:egret.TouchEvent来方便的获取到点击坐标
var mx = e.stageX;
var my = e.stageY;

var tween: egret.Tween;
for (var i = this.bodyList.length - 1; i >= 1; i--) {
tween = egret.Tween.get(this.bodyList[i]);
tween.to({ x: this.bodyList[i - 1].x, y: this.bodyList[i - 1].y }, during);
}

//我们前面知道蛇身节点list的首个节点其实就是蛇头
//让它在蛇中的偏移坐标加上蛇在舞台中的坐标,便可以得到全局坐标
var hx = this.x + this.bodyList[0].x;
var hy = this.y + this.bodyList[0].y;

//设置当前缓动对象为蛇头
tween = egret.Tween.get(this.bodyList[0]);
var tmpx, tmpy;
if (hx == mx && hy == my) {
//位置相同
return;
}
if (hx != mx) {
//非垂直

//斜率
var mk = (my - hy) / (mx - hx);
//角度
var mangle = Math.atan(mk);
if (mx //左边
tmpx = this.bodyList[0].x - this.speed * Math.cos(mangle);
tmpy = this.bodyList[0].y - this.speed * Math.sin(mangle);
tween.to({ x: tmpx, y: tmpy }, during);
} else {
//右边
tmpx = this.bodyList[0].x + this.speed * Math.cos(mangle);
tmpy = this.bodyList[0].y + this.speed * Math.sin(mangle);
tween.to({ x: tmpx, y: tmpy }, during);
}
} else {
//垂直
if (mx //水平向左
tmpx = this.bodyList[0].x - this.speed;
tween.to({ x: tmpx, y: tmpy }, during);
} else {
//水平向右
tmpx = this.bodyList[0].x + this.speed;
tween.to({ x: tmpx, y: tmpy }, during);
}
}
}

public getHead() {
return this.bodyList[0];
}
}

三、Main类

作为游戏的控制类,egret以它作为游戏创建的响应事件:

 this.addEventListener(egret.Event.ADDED_TO_STAGE, this.createGameScene, this);

新建一个项目的时候egret在Main.ts中自带了一大串加载图片资源的代码,我们可以把它删除,或者完全不用理会,直接考虑游戏的主题逻辑:

    private food: Food;
private snake: Snake;
private stageW: number;
private stageH: number;
private radius = 30;
/**
* 创建游戏场景
* Create a game scene
*/

private createGameScene(): void {
//获取舞台宽和高,在Main.ts中,this代表了整个游戏
this.stageW = this.stage.stageWidth;
this.stageH = this.stage.stageHeight;

//白色背景填满整个屏幕
var bg = new egret.Shape();
bg.graphics.beginFill(0xffffff);
bg.graphics.drawRect(0, 0, this.stageW, this.stageH);
bg.graphics.endFill();
this.addChild(bg);

//调用方法生产随机食物
this.randomFood();

//生成彩虹蛇
this.snake = new Snake(this.stageW * 0.5, this.stageH * 0.5, this.radius, 0x000000);
this.addChild(this.snake);

//开启舞台的点击,并注册指定的点击(触摸)事件
this.touchEnabled = true;
this.addEventListener(egret.TouchEvent.TOUCH_TAP, this.move, this);
this.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.onMove, this);
this.addEventListener(egret.TouchEvent.TOUCH_END, this.moveEnd, this);
}

食物需要随机生成,并显示在舞台上:

 private randomFood() {
//随机坐标
var tmpx = Math.random() * (this.stageW - this.radius * 2);
var tmpy = Math.random() * (this.stageH - this.radius * 2);
//新建食物对象
this.food = new Food(tmpx, tmpy, this.radius);
//显示
this.addChild(this.food);
}

当食物被吃时的事件:

private onEat() {
//在舞台上移除食物
this.removeChild(this.food);
//调用彩虹蛇吃食物的事件
this.snake.afterEat(this.food.color);
//随机产生食物
this.randomFood();
}

最后就是用户的点击事件了:我们需要理解这个过程:

  1. egret.TouchEvent.TOUCH_TAP(点击开始)
  2. egret.TouchEvent.TOUCH_MOVE(点击拖动)
  3. egret.TouchEvent.TOUCH_END(点击结束)

这三个事件是按照顺序一步步进行的

   //定时器
private timer: egret.Timer;
private during: number = 40;
private moveEvent: egret.TouchEvent;
private head: egret.Shape;

//根据点击事件调用彩虹蛇的移动方法
private move(e: egret.TouchEvent) {
this.snake.move(e, this.during);
}

//当点击拖动时
private onMove(e: egret.TouchEvent) {
//保存event
this.moveEvent = e;
//开启一个计时器
if (this.timer == null) {
this.timer = new egret.Timer(this.during);
this.timer.addEventListener(egret.TimerEvent.TIMER, this.onTimer, this);
this.timer.start();
}
}
//点击结束
private moveEnd(e: egret.TouchEvent) {
//关闭计时器
if (this.timer != null) {
this.timer.stop();
this.timer = null;
}
}
//计时器逻辑
private onTimer(e: egret.TimerEvent) {
//获取蛇头
this.head = this.snake.getHead();
//调用方法,检测蛇头和事物是否发生碰撞
if (this.hit(this.head, this.food))
//发生碰撞,则调用食物被吃事件
this.onEat();
//彩虹蛇继续移动
this.snake.move(this.moveEvent, this.during);
}

//使用包装盒检测碰撞
private hit(a, b) {
return (new egret.Rectangle(a.x + this.snake.x, a.y + this.snake.y, a.width, a.height))
.intersects(new egret.Rectangle(b.x, b.y, b.width, b.height));
}

好了,大功告成,Main.ts的完整代码如下:

class Main extends egret.DisplayObjectContainer {

/**
* 加载进度界面
* Process interface loading
*/

private loadingView: LoadingUI;

public constructor() {
super();
this.addEventListener(egret.Event.ADDED_TO_STAGE, this.createGameScene, this);
}

private food: Food;
private snake: Snake;
private stageW: number;
private stageH: number;
private radius = 30;

/**
* 创建游戏场景
* Create a game scene
*/

private createGameScene(): void {

this.stageW = this.stage.stageWidth;
this.stageH = this.stage.stageHeight;

//白色背景
var bg = new egret.Shape();
bg.graphics.beginFill(0xffffff);
bg.graphics.drawRect(0, 0, this.stageW, this.stageH);
bg.graphics.endFill();
this.addChild(bg);

this.randomFood();

this.snake = new Snake(this.stageW * 0.5, this.stageH * 0.5, this.radius, 0x000000);
this.addChild(this.snake);

this.touchEnabled = true;
this.addEventListener(egret.TouchEvent.TOUCH_TAP, this.move, this);
this.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.onMove, this);
this.addEventListener(egret.TouchEvent.TOUCH_END, this.moveEnd, this);
}
private color = 0x4c8dae;

private onEat() {
this.removeChild(this.food);
this.snake.afterEat(this.food.color);
this.randomFood();
}

private randomFood() {
//显示果实
var tmpx = Math.random() * (this.stageW - this.radius * 2);
var tmpy = Math.random() * (this.stageH - this.radius * 2);
this.food = new Food(tmpx, tmpy, this.radius);
this.addChild(this.food);
//模拟被吃
// this.food.touchEnabled = true;
// this.food.addEventListener(egret.TouchEvent.TOUCH_TAP, this.onEat, this);
}


private timer: egret.Timer;
private during: number = 40;
private moveEvent: egret.TouchEvent;
private head: egret.Shape;
private move(e: egret.TouchEvent) {
this.snake.move(e, this.during);
}
private onMove(e: egret.TouchEvent) {
this.moveEvent = e;
if (this.timer == null) {
this.timer = new egret.Timer(this.during);
this.timer.addEventListener(egret.TimerEvent.TIMER, this.onTimer, this);
this.timer.start();
}
}
private moveEnd(e: egret.TouchEvent) {
if (this.timer != null) {
this.timer.stop();
this.timer = null;
}
}
private onTimer(e: egret.TimerEvent) {
this.head = this.snake.getHead();
if (this.hit(this.head, this.food))
this.onEat();
this.snake.move(this.moveEvent, this.during);
}

private hit(a, b) {
return (new egret.Rectangle(a.x + this.snake.x, a.y + this.snake.y, a.width, a.height))
.intersects(new egret.Rectangle(b.x, b.y, b.width, b.height));
}
}

目录结构如下:
这里写图片描述

OK!大功告成,你现在可以指引着彩虹蛇在宇宙遨游啦,试着给它添加计分器吧!


推荐阅读
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • poj 3352 Road Construction ... [详细]
  • 2018 HDU 多校联合第五场 G题:Glad You Game(线段树优化解法)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6356在《Glad You Game》中,Steve 面临一个复杂的区间操作问题。该题可以通过线段树进行高效优化。具体来说,线段树能够快速处理区间更新和查询操作,从而大大提高了算法的效率。本文详细介绍了线段树的构建和维护方法,并给出了具体的代码实现,帮助读者更好地理解和应用这一数据结构。 ... [详细]
  • iOS snow animation
    CTSnowAnimationView.hCTMyCtripCreatedbyalexon1614.Copyright©2016年ctrip.Allrightsreserved.# ... [详细]
  • 题目描述:给定一个区间,支持两种操作:1. 将位置a的值修改为b;2. 查询区间[a, b]内的子序列的最大和,其中子序列中相邻的元素必须具有不同的奇偶性。 ... [详细]
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
  • 本文介绍如何使用OpenCV和线性支持向量机(SVM)模型来开发一个简单的人脸识别系统,特别关注在只有一个用户数据集时的处理方法。 ... [详细]
  • 本文详细介绍了在 CentOS 7 系统中配置 fstab 文件以实现开机自动挂载 NFS 共享目录的方法,并解决了常见的配置失败问题。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 本文介绍了如何利用 `matplotlib` 库中的 `FuncAnimation` 类将 Python 中的动态图像保存为视频文件。通过详细解释 `FuncAnimation` 类的参数和方法,文章提供了多种实用技巧,帮助用户高效地生成高质量的动态图像视频。此外,还探讨了不同视频编码器的选择及其对输出文件质量的影响,为读者提供了全面的技术指导。 ... [详细]
  • ### 优化后的摘要本文对 HDU ACM 1073 题目进行了详细解析,该题属于基础字符串处理范畴。通过分析题目要求,我们可以发现这是一道较为简单的题目。代码实现中使用了 C++ 语言,并定义了一个常量 `N` 用于字符串长度的限制。主要操作包括字符串的输入、处理和输出,具体步骤涉及字符数组的初始化和字符串的逆序操作。通过对该题目的深入探讨,读者可以更好地理解字符串处理的基本方法和技巧。 ... [详细]
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • 本文详细介绍了如何使用Python的多进程技术来高效地分块读取超大文件,并将其输出为多个文件。通过这种方式,可以显著提高读取速度和处理效率。 ... [详细]
  • 本文提出了一种基于栈结构的高效四则运算表达式求值方法。该方法能够处理包含加、减、乘、除运算符以及十进制整数和小括号的算术表达式。通过定义和实现栈的基本操作,如入栈、出栈和判空等,算法能够准确地解析并计算输入的表达式,最终输出其计算结果。此方法不仅提高了计算效率,还增强了对复杂表达式的处理能力。 ... [详细]
author-avatar
QEWERTGF_978
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有