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

Chrome小恐龙游戏源码探究八奔跑的小恐龙

文章首发于我的GitHub博客前言上一篇文章:《Chrome小恐龙游戏源码探究七—昼夜模式交替》实现了游戏昼夜模式的交替,这一篇文章中,将实现:1、小恐龙的绘制2、键盘对小恐龙的控

文章首发于我的
GitHub 博客

前言

上一篇文章:《Chrome 小恐龙游戏源码探究七 — 昼夜模式交替》实现了游戏昼夜模式的交替,这一篇文章中,将实现:1、小恐龙的绘制 2、键盘对小恐龙的控制 3、页面失焦后,重新聚焦会重置小恐龙的状态

绘制静态的小恐龙

定义小恐龙类 Trex

/**
* 小恐龙类
* @param {HTMLCanvasElement} canvas 画布
* @param {Object} spritePos 图片在雪碧图中的坐标
*/
function Trex(canvas, spritePos) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.spritePos = spritePos;
this.xPos = 0;
this.yPos = 0;
this.groundYPos = 0; // 小恐龙在地面上时的 y 坐标
this.currentFrame = 0; // 当前的动画帧
this.currentAnimFrames = []; // 存储当前状态的动画帧在雪碧图中的 x 坐标
this.blinkDelay = 0; // 眨眼间隔的时间(随 机)
this.blinkCount = 0; // 眨眼次数
this.animStartTime = 0; // 小恐龙眨眼动画开始时间
this.timer = 0; // 计时器
this.msPerFrame = 1000 / FPS; // 帧率
this.status = Trex.status.WAITING; // 当前的状态
this.cOnfig= Trex.config;
this.jumping = false; // 是否跳跃
this.ducking = false; // 是否闪避(俯身)
this.jumpVelocity = 0; // 跳跃的速度
this.reachedMinHeight = false; // 是否达到最低高度
this.speedDrop = false; // 是否加速下降
this.jumpCount = 0; // 跳跃的次数
this.jumpspotX = 0; // 跳跃点的 x 坐标
this.init();
}

相关的配置参数:

Trex.cOnfig= {
GRAVITY: 0.6, // 引力
WIDTH: 44, // 站立时的宽度
HEIGHT: 47,
WIDTH_DUCK: 59, // 俯身时的宽度
HEIGHT_DUCK: 25,
MAX_JUMP_HEIGHT: 30, // 最大跳跃高度
MIN_JUMP_HEIGHT: 30, // 最小跳跃高度
SPRITE_WIDTH: 262, // 站立的小恐龙在雪碧图中的总宽度
DROP_VELOCITY: -5, // 下落的速度
INITIAL_JUMP_VELOCITY: -10, // 初始跳跃速度
SPEED_DROP_COEFFICIENT: 3, // 下落时的加速系数(越大下落的越快)
INTRO_DURATION: 1500, // 开场动画的时间
START_X_POS: 50, // 开场动画结束后,小恐龙在 canvas 上的 x 坐标
};
Trex.BLINK_TIMING = 7000; // 眨眼最大间隔的时间
// 小恐龙的状态
Trex.status = {
CRASHED: 'CRASHED', // 撞到障碍物
DUCKING: 'DUCKING', // 正在闪避(俯身)
JUMPING: 'JUMPING', // 正在跳跃
RUNNING: 'RUNNING', // 正在奔跑
WAITING: 'WAITING', // 正在等待(未开始游戏)
};
// 为不同的状态配置不同的动画帧
Trex.animFrames = {
WAITING: {
frames: [44, 0],
msPerFrame: 1000 / 3
},
RUNNING: {
frames: [88, 132],
msPerFrame: 1000 / 12
},
CRASHED: {
frames: [220],
msPerFrame: 1000 / 60
},
JUMPING: {
frames: [0],
msPerFrame: 1000 / 60
},
DUCKING: {
frames: [264, 323],
msPerFrame: 1000 / 8
},
};

补充本篇文章中会用到的一些数据:

Runner.cOnfig= {
// ...
BOTTOM_PAD: 10, // 小恐龙距 canvas 底部的距离
MAX_BLINK_COUNT: 3, // 小恐龙的最大眨眼次数
};
Runner.spriteDefinition = {
LDPI: {
// ...
TREX: {x: 848, y: 2}, // 小恐龙
},
};

然后来看下 Trex 原型链上的方法。我们首先来绘制静态的小恐龙:

Trex.prototype = {
// 初始化小恐龙
init: function() {
// 获取小恐龙站在地面上时的 y 坐标
this.groundYPos = Runner.defaultDimensions.HEIGHT - this.config.HEIGHT -
Runner.config.BOTTOM_PAD;
this.yPos = this.groundYPos; // 小恐龙的 y 坐标初始化
this.draw(0, 0); // 绘制小恐龙的第一帧图片
},
/**
* 绘制小恐龙
* @param {Number} x 当前帧相对于第一帧的 x 坐标
* @param {Number} y 当前帧相对于第一帧的 y 坐标
*/
draw: function(x, y) {
// 在雪碧图中的坐标
var sourceX = x + this.spritePos.x;
var sourceY = y + this.spritePos.y;
// 在雪碧图中的宽高
var sourceWidth = this.ducking && this.status != Trex.status.CRASHED ?
this.config.WIDTH_DUCK : this.config.WIDTH;
var sourceHeight = this.config.HEIGHT;
// 绘制到 canvas 上时的高度
var outputHeight = sourceHeight;
// 躲避状态.
if (this.ducking && this.status != Trex.status.CRASHED) {
this.ctx.drawImage(
Runner.imageSprite,
sourceX, sourceY,
sourceWidth, sourceHeight,
this.xPos, this.yPos,
this.config.WIDTH_DUCK, outputHeight
);
} else {
// 躲闪状态下撞到障碍物
if (this.ducking && this.status == Trex.status.CRASHED) {
this.xPos++;
}
// 奔跑状态
this.ctx.drawImage(
Runner.imageSprite,
sourceX, sourceY,
sourceWidth, sourceHeight,
this.xPos, this.yPos,
this.config.WIDTH, outputHeight
);
}
this.ctx.globalAlpha = 1;
},
};

前面进入街机模式那一章中,用到了 Trex 类中的数据,临时定义了 Trex 类,别忘了将其删除。

接下来需要通过 Runner 类调用 Trex 类。添加属性用于存储小恐龙类的实例:

function Runner(containerSelector, opt_config) {
// ...
+ this.tRex = null; // 小恐龙
}

初始化小恐龙类:

Runner.prototype = {
init: function () {
// ...
+ // 加载小恐龙类
+ this.tRex = new Trex(this.canvas, this.spriteDef.TREX);
},
};

这样在游戏初始化时就绘制出了静态的小恐龙,如图:

《Chrome 小恐龙游戏源码探究八 -- 奔跑的小恐龙》

实现眨眼效果

游戏初始化之后,小恐龙会随机眨眼睛。默认的是最多只能眨三次。下面将实现这个效果。

添加更新小恐龙的方法:

Trex.prototype = {
/**
* 更新小恐龙
* @param {Number} deltaTime 间隔时间
* @param {String} opt_status 小恐龙的状态
*/
update: function(deltaTime, opt_status) {
this.timer += deltaTime;
// 更新状态的参数
if (opt_status) {
this.status = opt_status;
this.currentFrame = 0;
this.msPerFrame = Trex.animFrames[opt_status].msPerFrame;
this.currentAnimFrames = Trex.animFrames[opt_status].frames;
if (opt_status == Trex.status.WAITING) {
this.animStartTime = getTimeStamp(); // 设置眨眼动画开始的时间
this.setBlinkDelay(); // 设置眨眼间隔的时间
}
}
if (this.status == Trex.status.WAITING) {
// 小恐龙眨眼
this.blink(getTimeStamp());
} else {
// 绘制动画帧
this.draw(this.currentAnimFrames[this.currentFrame], 0);
}
if (this.timer >= this.msPerFrame) {
// 更新当前动画帧,如果处于最后一帧就更新为第一帧,否则更新为下一帧
this.currentFrame = this.currentFrame ==
this.currentAnimFrames.length - 1 ? 0 : this.currentFrame + 1;
// 重置计时器
this.timer = 0;
}
},
// 设置眨眼间隔的时间
setBlinkDelay: function() {
this.blinkDelay = Math.ceil(Math.random() * Trex.BLINK_TIMING);
},
// 小恐龙眨眼
blink: function (time) {
var deltaTime = time - this.animStartTime; // 间隔时间大于随机获取的眨眼间隔时间才能眨眼
if (deltaTime >= this.blinkDelay) {
this.draw(this.currentAnimFrames[this.currentFrame], 0);
// 正在眨眼
if (this.currentFrame == 1) {
console.log('眨眼');
this.setBlinkDelay(); // 重新设置眨眼间隔的时间
this.animStartTime = time; // 更新眨眼动画开始的时间
this.blinkCount++; // 眨眼次数加一
}
}
},
};

然后将小恐龙初始更新为等待状态:

Trex.prototype = {
init: function () {
// ...
this.update(0, Trex.status.WAITING); // 初始为等待状态
},
};

最后在 Runnerupdate 方法中调用 Trexupdate 方法来实现小恐龙眨眼:

Runner.prototype = {
update: function () {
// ...
// 游戏变为开始状态或小恐龙还没有眨三次眼
- if (this.playing) {
+ if (this.playing || (!this.activated &&
+ this.tRex.blinkCount + this.tRex.update(deltaTime);
// 进行下一次更新
this.scheduleNextUpdate();
}
},
};

效果如下:

《Chrome 小恐龙游戏源码探究八 -- 奔跑的小恐龙》

可以看到,眨眼的代码逻辑触发了 3 次,但是实际小恐龙只眨眼了 1 次。这就是前面说的,小恐龙默认最多只能眨三次眼。具体原因如下:

先来看下 Trexupdate 方法中的这段代码:

if (this.timer >= this.msPerFrame) {
// 更新当前动画帧,如果处于最后一帧就更新为第一帧,否则更新为下一帧
this.currentFrame = this.currentFrame ==
this.currentAnimFrames.length - 1 ? 0 : this.currentFrame + 1;
// 重置计时器
this.timer = 0;
}

这段代码会将当前动画帧不断更新为下一帧。对于小恐龙来说就是不断切换睁眼闭眼这两帧。如果当前帧为 “睁眼”,那么执行 blink 函数后小恐龙还是睁眼,也就是说实际小恐龙没眨眼;同理,只有当前帧为 “闭眼” 时,执行 blink 函数后,小恐龙才会真正的眨眼。

至于这样做的目的,就是为了防止小恐龙不停的眨眼睛。例如,将 blink 函数修改为:

// 小恐龙眨眼
blink: function () {
this.draw(this.currentAnimFrames[this.currentFrame], 0);
},

这样小恐龙会不停的眨眼睛。所以需要对其进行限制,这里 Chrome 开发人员的做法就是:设置一个间隔时间,当小恐龙眨眼的间隔时间大于这个设置的间隔时间,并且当前动画帧为 “闭眼” 时,才允许小恐龙眨眼睛。然后每次眨完眼后,重新设置眨眼间隔(默认设置为 0~7 秒),就实现了小恐龙的随机眨眼。

小恐龙的开场动画

下面来实现小恐龙对键盘按键的响应。

首先,当触发游戏彩蛋后,小恐龙会跳跃一次,并向右移动 50 像素(默认设置的是 50 像素)。

添加让小恐龙开始跳跃的方法:

Trex.prototype = {
// 开始跳跃
startJump: function(speed) {
if (!this.jumping) {
// 更新小恐龙为跳跃状态
this.update(0, Trex.status.JUMPING);
// 根据游戏的速度调整跳跃的速度
this.jumpVelocity = this.config.INITIAL_JUMP_VELOCITY - (speed / 10);
this.jumping = true;
this.reachedMinHeight = false;
this.speedDrop = false;
}
},
};

进行调用:

Runner.prototype = {
onKeyDown: function (e) {
if (!this.crashed && !this.paused) {
if (Runner.keyCodes.JUMP[e.keyCode]) {
e.preventDefault();

// ...
+ // 开始跳跃
+ if (!this.tRex.jumping && !this.tRex.ducking) {
+ this.tRex.startJump(this.currentSpeed);
+ }
}
}
},
};

这样,按下空格键后,小恐龙仍然会静止在地面上。接下来还需要更新动画帧才能实现小恐龙的奔跑动画。

添加更新小恐龙动画帧的方法:

Trex.prototype = {
// 更新小恐龙跳跃时的动画帧
updateJump: function(deltaTime) {
var msPerFrame = Trex.animFrames[this.status].msPerFrame; // 获取当前状态的帧率
var framesElapsed = deltaTime / msPerFrame;
// 加速下落
if (this.speedDrop) {
this.yPos += Math.round(this.jumpVelocity *
this.config.SPEED_DROP_COEFFICIENT * framesElapsed);
} else {
this.yPos += Math.round(this.jumpVelocity * framesElapsed);
}
// 跳跃的速度受重力的影响,向上逐渐减小,然后反向
this.jumpVelocity += this.config.GRAVITY * framesElapsed;
// 达到了最低允许的跳跃高度
if (this.yPos this.reachedMinHeight = true;
}
// 达到了最高允许的跳跃高度
if (this.yPos this.endJump(); // 结束跳跃
}
// 重新回到地面,跳跃完成
if (this.yPos > this.groundYPos) {
this.reset(); // 重置小恐龙的状态
this.jumpCount++; // 跳跃次数加一
}
},
// 跳跃结束
endJump: function() {
if (this.reachedMinHeight &&
this.jumpVelocity this.jumpVelocity = this.config.DROP_VELOCITY; // 下落速度重置为默认
}
},
// 重置小恐龙状态
reset: function() {
this.yPos = this.groundYPos;
this.jumpVelocity = 0;
this.jumping = false;
this.ducking = false;
this.update(0, Trex.status.RUNNING);
this.speedDrop = false;
this.jumpCount = 0;
},
};

其中 minJumpHeight 的属性值为:

Trex.prototype = {
init: function() {
+ // 最低跳跃高度
+ this.minJumpHeight = this.groundYPos - this.config.MIN_JUMP_HEIGHT; // ...
},
}

然后进行调用:

Runner.prototype = {
update: function () {
// ...
if (this.playing) {
this.clearCanvas();
+ if (this.tRex.jumping) {
+ this.tRex.updateJump(deltaTime);
+ }
this.runningTime += deltaTime;
var hasObstacles = this.runningTime > this.config.CLEAR_TIME;
// 刚开始 this.playingIntro 未定义 !this.playingIntro 为真
- if (!this.playingIntro) {
+ if (this.tRex.jumpCount == 1 && !this.playingIntro) {
this.playIntro(); // 执行开场动画
}
// ...
}
// ...
},
};

这样在按下空格键后,小恐龙就会跳跃一次并进行奔跑动画。如图:

《Chrome 小恐龙游戏源码探究八 -- 奔跑的小恐龙》

下面来实现效果:小恐龙第一次跳跃后,向右移动 50 像素。

修改 Trexupdate 方法。当判断到正在执行开场动画时,移动小恐龙:

Trex.prototype = {
update: function(deltaTime, opt_status) {
this.timer += deltaTime;
// 更新状态的参数
if (opt_status) {
// ...
}
// 正在执行开场动画,将小恐龙向右移动 50 像素
+ if (this.playingIntro && this.xPos + this.xPos += Math.round((this.config.START_X_POS /
+ this.config.INTRO_DURATION) * deltaTime);
+ }
// ...
},
};

可以看出当 playingIntro 属性为 true 时,小恐龙就会向右移动。所以需要通过控制这个属性的值来控制小恐龙第一次跳跃后的移动。

修改 Runner 上的 playIntro 方法,将小恐龙标记为正在执行开场动画:

Runner.prototype = {
playIntro: function () {
if (!this.activated && !this.crashed) {
+ this.tRex.playingIntro = true; // 小恐龙执行开场动画
// ...
}
},
};

然后需要在开始游戏后也就是执行 startGame 方法时,结束小恐龙的开场动画:

Runner.prototype = {
startGame: function () {
this.setArcadeMode(); // 进入街机模式+ this.tRex.playingIntro = false; // 小恐龙的开场动画结束 // ...
},
};

效果如下:

《Chrome 小恐龙游戏源码探究八 -- 奔跑的小恐龙》

可以很明显的看到,小恐龙在第一次跳跃后向右移动了一段距离(默认 50 像素)。

使用键盘控制小恐龙

在这个游戏中,当按下 键后,如果小恐龙正在跳跃,就会快速下落,如果小恐龙在地上,就会进入躲闪状态,下面来实现这些效果。

加速下落:

Trex.prototype = {
// 设置小恐龙为加速下落,立即取消当前的跳跃
setSpeedDrop: function() {
this.speedDrop = true;
this.jumpVelocity = 1;
},
};

设置小恐龙是否躲闪:

Trex.prototype = {
// 设置小恐龙奔跑时是否躲闪
setDuck: function(isDucking) {
if (isDucking && this.status != Trex.status.DUCKING) { // 躲闪状态
this.update(0, Trex.status.DUCKING);
this.ducking = true;
} else if (this.status == Trex.status.DUCKING) { // 奔跑状态
this.update(0, Trex.status.RUNNING);
this.ducking = false;
}
},
};

onKeyDown 方法中调用:

Runner.prototype = {
onKeyDown: function () {
if (!this.crashed && !this.paused) {
if (Runner.keyCodes.JUMP[e.keyCode]) {
// ...
+ } else if (this.playing && Runner.keyCodes.DUCK[e.keyCode]) {
+ e.preventDefault();
+
+ if (this.tRex.jumping) {
+ this.tRex.setSpeedDrop(); // 加速下落
+ } else if (!this.tRex.jumping && !this.tRex.ducking) {
+ this.tRex.setDuck(true); // 进入躲闪状态
+ }
+ }
}
},
};

这样就实现了前面所说的效果。但是小恐龙进入躲闪状态后,如果松开按键并不会重新站起来。因为现在还没有定义松开键盘按键时响应的事件。下面来定义:

Runner.prototype = {
onKeyUp: function(e) {
var keyCode = String(e.keyCode);
if (Runner.keyCodes.DUCK[keyCode]) { // 躲避状态
this.tRex.speedDrop = false;
this.tRex.setDuck(false);
}
},
};

然后调用,修改 handleEvent 方法:

Runner.prototype = {
handleEvent: function (e) {
return (function (eType, events) {
switch (eType) {
// ...
+ case events.KEYUP:
+ this.onKeyUp(e);
+ break;
default:
break;
}
}.bind(this))(e.type, Runner.events);
},
};

效果如下:

《Chrome 小恐龙游戏源码探究八 -- 奔跑的小恐龙》

第一次跳是正常下落,第二次跳是加速下落

处理小恐龙的跳跃

小恐龙的跳跃分为大跳和小跳,如图:

《Chrome 小恐龙游戏源码探究八 -- 奔跑的小恐龙》

要实现这个效果,只需要在 键被松开时,立即结束小恐龙的跳跃即可。

修改 onKeyUp 方法:

Runner.prototype = {
onKeyUp: function(e) {
var keyCode = String(e.keyCode);
+ var isjumpKey = Runner.keyCodes.JUMP[keyCode];
+ if (this.isRunning() && isjumpKey) { // 跳跃
+ this.tRex.endJump();
} else if (Runner.keyCodes.DUCK[keyCode]) { // 躲避状态
this.tRex.speedDrop = false;
this.tRex.setDuck(false);
}
},
};

其中 isRunning 方法定义如下:

Runner.prototype = {
// 是否游戏正在进行
isRunning: function() {
return !!this.raqId;
},
};

这样就实现了小恐龙的大跳和小跳。

最后是要实现的效果是:如果页面失焦时,小恐龙正在跳跃,就重置小恐龙的状态(也就是会立即回到地面上)。这个效果实现很简单,直接调用前面定义的 reset 方法即可:

Runner.prototype = {
play: function () {
if (!this.crashed) {
// ...
+ this.tRex.reset();
}
},
};

效果如下:

《Chrome 小恐龙游戏源码探究八 -- 奔跑的小恐龙》

查看添加或修改的代码,
戳这里

Demo 体验地址:https://liuyib.github.io/blog/demo/game/google-dino/dino-gogogo/

上一篇下一篇
Chrome 小恐龙游戏源码探究七 — 昼夜模式交替 Chrome 小恐龙游戏源码探究九 — 游戏碰撞检测

推荐阅读
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
author-avatar
佩人永雪3
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有