介绍 “雨淋”是一款最初使用Adobe Flash开发的单人游戏(你可以试试谷歌一下“世界上最简单的Flash游戏”)。它相当流行,并且已经被移植到Android平台上。在谷歌Play和亚马逊应用商店有许多克隆游戏,包括Coloroid, PaintIT, Splash!和洪水填充,举几个例子。 虽然确切的游戏规则可能有所不同,但所有这些游戏都是单人游戏。《Zyan Drench》是对双人游戏的一次尝试,并引入了两种新的游戏模式:电脑对战和网络游戏模式。本文描述了使用c#语言Xamarin构建Android版本的游戏。Android平台(独立版)及网络游戏自言通信框架。 游戏概述 《雨》是一款很容易上手,但解释起来有点难的益智游戏。游戏一开始是一个15x15的棋盘,棋盘上随机分布着像素块。从左上角的像素开始,你必须用一种颜色填充(淋)整个面板。您可以通过将左上角的像素设置为一个新颜色来实现这一点。当你将像素的颜色变成与相邻像素相同的颜色时,你将扩展湿透区域: 最初的淋水游戏是单人游戏,有15x15的棋盘和每级30步的限制。一些游戏实现允许选择不同的棋盘大小,限制通常是棋盘大小的两倍,大多数实现使用6种颜色。我们的单人游戏将使用相同的参数来向后兼容。 双人模式 让游戏适合两名玩家是很简单的:如果第一个玩家从左上角的像素开始,那么对手就会从相反的角落开始。游戏依次进行,直到整个棋盘涂上两种颜色。淋湿的像素比对手多的玩家获胜: 被禁止的颜色 在单人游戏模式下,使用相同颜色两次是没有意义的,因为该颜色的所有相邻像素都已经被捕获。双玩家模式又增加了一个限制:你不能吃掉对手的像素,因此你不能使用与对手相同的颜色。在每个回合,有两种颜色不能使用:你当前的颜色和你对手的颜色。我们称它们为禁忌色。 游戏开发 为了给游戏建模,我们需要一个棋盘,它是一个二维的像素数组。每个像素都有一个颜色,我们可以使用从0到5的整数对其进行编码。为了显示板子,我们需要为这些数字分配任何不同的颜色(即。,创建调色板): 隐藏,复制Code

public class DrenchGame
{
public const int BoardSize = 15; public const int ColorCount = 6; private int[,] Board = new int[BoardSize, BoardSize]; private Color[] Palette = new[] { Color.Red, Color.Green, ... }; public void NewGame()
{
// randomize the board
} public void MakeMove(int color)
{
// flood fill the board starting from the top-left pixel
} public void CheckIfStopped()
{
// check if the whole board is drenched
}
}

淋水游戏有很多不同的游戏模式:单人,双人,对战电脑(有几个技能级别)和基于网络的游戏。所有这些游戏都有相同的游戏规则:设置新颜色,扩大淋湿区域,为新游戏随机棋盘,等等。让我们将所有这些细节提取到一个表示板的单独类中。 DrenchBoard 下面是一个类,我们将使用它来表示一个板。像计算机屏幕一样,像素位置由它的X和Y坐标决定,其中(0,0)是左上角。索引器用于访问单个像素的颜色:this[x, y]。为了方便起见,我们将封装坐标(就像perl语言中的数组索引一样),以便这个[-1,-1]的意思与这个[BoardSize -1, BoardSize -1]相同。 委员会将进行扩大受潮地区所需的所有计算。每个玩家都试图从自己的位置开始喷洒棋盘,这就是SetColor(x, y, color)获取x和y坐标的原因。下面讨论SetColor的具体算法: 隐藏,收缩,复制Code

public class DrenchBoard
{
// skipped: BoardSize, ColorCount and Board (same as above) public void Randomize()
{
// assign a random color to every pixel of the board
} public void SetColor(int x, int y, int color)
{
// flood fill algorithm (discussed below)
} public bool CheckAllColors(param int[] allowedColors)
{
// check if all pixels have one of the allowed colors
} public int this[int x, int y]
{
get
{
// wrap coordinate values so that Board[-1, -1]
// means the right-bottom corner
if (x < 0)
x = BoardSize - x;
if (y < 0)
y = BoardSize - y; // return the color of a pixel given its coordinates
return Board[x, y];
}
}
}

为了表示板中的单个位置,我创建了点结构:new Point(x, y)。这个结构被洪水填充算法使用。该算法以一组点进行运算,并优化比较点结构,实现了iequatable>& lt; / point> & lt; point>接口: 隐藏,复制Code

public struct Point: IEquatable<Point>
{
private int x, y; public Point(int x, int y)
{
this.x = x;
this.y = y;
}
...
}

洪水填充算法 我不是计算机图形学的专家,但是填充看起来并不是一件困难的事情,所以我编造了我自己的算法,如下所示。对于每个像素,我检查它的四个相邻像素,并记住那些具有相同颜色的像素。递归地重复这个过程,我最终得到一个与初始像素颜色相同的有限的相邻像素集。最后,我遍历这些像素,将它们全部设置为新颜色。 在实现这个简单算法时,我将递归转换为迭代,以消耗更少的堆栈内存,并使用计划进行处理的点队列。但事实证明,当处理大量像素时,Queue类的行为相当缓慢。 然后我意识到顺序或处理像素根本不重要,于是用HashSet替换了队列。这神奇地解决了所有的性能问题!哈希et的性能并不依赖于设置的大小,所以它处理数百项的速度和处理少数项的速度一样快。下面是我完成的完整的洪水填充算法: 隐藏,收缩,复制Code

public void SetColor(int x, int y, int newColor)
{
var color = Board[x, y];
if (color == newColor)
{
return 1;
} var points = new HashSet<Point>();
var queue = new HashSet<Point>();
queue.Add(new Point(x, y)); var adjacents = new[] { new Point(-1, 0), new Point(0, -1), new Point(0, 1), new Point(1, 0) };
while (queue.Any())
{
var point = queue.First();
queue.Remove(point);
points.Add(point);
Board[point.X, point.Y] = newColor; // process adjacent points of the same color
foreach (var delta in adjacents)
{
var newX = point.X + delta.X;
var newY = point.Y + delta.Y; // skip invalid point
if (newX < 0 || newX > BoardSize - 1 || newY < 0 || newY > BoardSize - 1)
{
continue;
} // skip pixels of other colors
if (Board[newX, newY] != color)
{
continue;
} // skip already processed point
var newPoint = new Point(newX, newY);
if (points.Contains(newPoint))
{
continue;
} // schedule the point for processing
queue.Add(newPoint);
}
}
}

使用提供的DrenchBoard类游戏编程非常简单: 隐藏,复制Code

class SomeKindOfDrenchGame
{
public void NewGame()
{
Board.Randomize();
} public void MakeMove(int newColor)
{
Board.SetColor(0, 0, newColor);
}
}

IDrenchGame接口 遵循DRY(不要重复自己)原则,我们希望我们的应用程序处理所有游戏模式使用相同的UI,看起来像一个像素板下面有几个彩色按钮: 玩家通过触摸彩色按钮来移动。禁止颜色的按钮被禁用。随着游戏的进行,UI会更新面板上的当前状态文本。这对于所有的游戏模式都是常见的,所以我们可以将它们描述为一个界面。实际的游戏界面可能有点复杂,但我们总是可以添加更多的方法和属性,因为我们需要: 隐藏,复制Code

public interface IDrenchGame
{
DrenchBoard Board { get; } void NewGame(); void MakeMove(int color); bool IsStopped { get; } string CurrentStatus { get; } IEnumerable<int> ForbiddenColors { get; } event EventHandler GameChanged; event EventHandler GameStopped;
}

为了使事情更简单,我们将为所有游戏模式创建一个基本抽象类。子类将根据游戏规则重写MakeMove和CheckIfStopped方法: 隐藏,收缩,复制Code

public abstract class DrenchGameBase
{
public virtual DrenchBoard Board { get; private set; } public virtual void NewGame()
{
Board.Randomize();
} public virtual void SetColor(int x, int y, int color)
{
Board.SetColor(x, y, color);
OnGameChanged();
} public abstract MakeMove(int color); protected abstract CheckIfStopped(); public virtual bool IsStopped { get; protected set; } public virtual string CurrentStatus { get; protected set; } public virtual IEnumerable<int> ForbiddenColors { get; protected set; } public event EvenHandler GameChanged; protected void OnGameChanged()
{
var gameChanged = GameChanged;
if (gameChanged != null)
gameChanged(this, EventArgs.Empty);
} public static IEnumerable<int> Enumerate(params int[] colors)
{
// utility method to return an IEnumerable<int>
return colors;
}
}

SinglePlayerGame和TwoPlayerGame 使用提供的DrenchGameBase类,创建特定的游戏模式非常容易。重写MakeMove和CheckIfStopped方法,我们可以控制游戏如何进行。基类使用Board实例执行所有计算。这里是完整的源代码为单机游戏: 隐藏,收缩,复制Code

public class SinglePlayerGame : DrenchGameBase
{
public const int MaxMoves = 30; public override void NewGame()
{
base.NewGame(); CurrentMove = 1;
ForbiddenColors = Enumerate(Board[0, 0]);
CurrentStatus = string.Format("{0} moves left. Good luck!", MaxMoves);
OnGameChanged();
} public override void MakeMove(int value)
{
CurrentMove++;
CurrentStatus = string.Format("Move {0} out of {1}", CurrentMove, MaxMoves);
ForbiddenColors = Enumerable.Repeat(value, 1); // set the new color
SetColor(0, 0, value);
} protected override void CheckIfStopped()
{
var allowedColor = Board[0, 0];
var success = Board.CheckAllColors(allowedColor);
if (success || CurrentMove > MaxMoves)
{
var result = success ? "won" : "lost";
OnGameStopped(true, "You have {0} the game!", result);
}
}
}

两个playergame保持对当前玩家的跟踪,以便每次调用MakeMove时交替地在顶层或右下角像素上绘制。CheckIfStopped检查所有像素是否都有这两种颜色中的一种。 组装Android应用程序 让我们使用提供的游戏类来构建一个运行的Android应用程序。典型的应用程序由几个与用户交互的活动(屏幕)组成。每个活动都包含几个合并到层次结构中的视图来创建用户界面。我不会深入探讨Android应用程序结构的细节,因为已经有很多关于这个主题的好文章,所以我只关注一些细节。 我们的主要游戏活动将使用TableLayout创建董事会和一组按钮。按钮是在布局设计器中创建的,而板子是通过编程方式构建的,因此很容易随时更改板子的大小。董事会屏幕的布局如下所示(大部分跳过的细节): 隐藏,复制Code

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android">
<!-- Stub view for the board -->
<TableLayoutandroid:id="@+id/boardTable"android:stretchColumns="*">
<TableRowandroid:id="@+id/tableRow0">
</TableRow>
</TableLayout>
<!-- Buttons panel -->
<TableLayoutandroid:id="@+id/buttonsTable"android:stretchColumns="*">
<TableRowandroid:id="@+id/tableRow1">
<Buttonandroid:id="@+id/button0"/>
<Buttonandroid:id="@+id/button1"/>
<Buttonandroid:id="@+id/button2"/>
</TableRow>
<TableRowandroid:id="@+id/tableRow2">
<Buttonandroid:id="@+id/button3"/>
<Buttonandroid:id="@+id/button4"/>
<Buttonandroid:id="@+id/button5"/>
</TableRow>
</TableLayout>
</LinearLayout>

下面是在OnCreate方法中执行的用block填充董事会表的代码: 隐藏,复制Code

// Create board tiles
var colors = Palette;
for (var j = 0; j < BoardSize; j++)
{
tableRow = new TableRow(BaseContext);
tableRow.LayoutParameters = new TableLayout.LayoutParams(
TableLayout.LayoutParams.WrapContent,
TableLayout.LayoutParams.WrapContent, 1f);
table.AddView(tableRow); for (var i = 0; i < BoardSize; i++)
{
var button = new Button(BaseContext);
button.LayoutParameters = new TableRow.LayoutParams(i);
button.LayoutParameters.Width = 1;
button.LayoutParameters.Height = ViewGroup.LayoutParams.MatchParent;
button.SetBackgroundColor(colors[(i + j * 2) % 6]);
tableRow.AddView(button); Tiles[i, j] = button;
}
}

每个块由一个按钮视图表示。创建具有相同重力值的行确保所有的行具有相同的高度,设置android:stretchColumns="*"使列具有相同的宽度,这正是我们需要的像素板。 注意:Android设备支持不同的屏幕大小和宽高比,这就是为什么块不可能总是完美的正方形。 处理设备旋转 在Android中,Activity对象可以在Android想创建和销毁时创建和销毁。例如,当您旋转设备时,将从头重新创建当前活动,您必须加载布局并重新创建板。这意味着您不能简单地将当前游戏实例存储在活动中。当前的游戏实例必须放在其他地方。 自定义应用程序类 看起来安全存储它的最简单方法是创建一个自定义应用程序类。应用程序实例在流程的整个生命周期中都存在,并且通过Application属性对所有活动都可用。唯一需要注意的是application类是从Java代码创建的,所以它必须是一个特殊的构造函数,看起来像这样: 隐藏,复制Code

public CustomApplication(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}

我需要跨不同活动共享的所有实例都可以作为application类的属性发布: 隐藏,复制Code

public IDrenchGame DrenchGame { get; set; }

从活动中访问应用程序实例如下所示: 隐藏,复制Code

private CustomApplication App { get { return (CustomApplication)Application; } }

...
var currentGame = App.DrenchGame;

Game实例使用GameChanged和GameStopped等事件与棋盘活动交互。Activity订阅这些事件在OnResume和unsubsribes从他们在OnPause方法: 隐藏,复制Code

protected override void OnResume()
{
base.OnResume(); DrenchGame.GameChanged += UpdateTiles;
DrenchGame.GameStopped += StopGame;
} protected override void OnPause()
{
base.OnPause(); DrenchGame.GameChanged -= UpdateTiles;
DrenchGame.GameStopped -= StopGame;
}

取消游戏事件订阅是非常重要的:活动事件处理程序将防止活动实例被垃圾收集,并将造成内存泄漏。 开始一个游戏和显示一个棋盘活动 当一个游戏被创建的时候,唯一要做的事情就是开始与用户交互的活动。 隐藏,复制Code

App.DrenchGame = new SinglePlayerGame(); // or any other game class!
StartActivity(typeof(DrenchBoardActivity));

我们可以创建带有不同选项的主菜单:单人游戏,双人游戏,对战Android等等。菜单项的每个处理程序都将以相同的方式工作,唯一的区别是创建游戏类。 添加及rk支持 多人网络游戏模式需要远程玩家之间的特殊同步。例如,两个玩家应该有同一个棋盘来玩。除非双方都准备好了,否则游戏不能开始。如果其中一名玩家退出游戏,游戏将无法继续进行,依此类推。我们的IDrenchGame接口不足以处理所有这些:我们需要额外的方法和事件。 为了节省网络带宽,我们不会在每个回合发送整个游戏状态。相反,每个团队将维护自己的淋板实例,我们只会为每个移动和游戏状态更新发送轻量级事件。 IDrenchGameServer接口 在IDrenchGame界面添加新成员是没有意义的。特定于网络的方法和事件对当地的比赛没有意义。相反,让我们引入一个新的界面来与游戏服务器互操作,扩展IDrenchGame: 隐藏,复制Code

public interface IDrenchGameServer : IDrenchGame
{
void Join(); // join the remote game void Leave(); // leave the remote game bool IsReady { get; } // both players are ready event EventHandler GameStarted; event EventHandler<MoveEventArgs> Moved; // other player made a move
}

使用此接口假定采用以下协议: 建立连接与idrenchgameserver订阅事件GameStarted和移动电话连接方法开始一个新游戏调用移动方法,让你的移动处理移动事件应对对手的移动处理gamestop事件(从IDrenchGame继承)停止当前游戏叫NewGame(也继承了IDrehchGame)开始一个新游戏,如果你想中止当前的游戏,所以服务器可以停止调用离开方法从服务器断开事件服务器退订 DrenchGameServer和DrenchGameClient 让我们创建两个特殊的游戏类来实现上面列出的协议。对于这些类,我决定重用我的TwoPlayerGame类,它已经实现了双人游戏模式所需的一切。 我的两个类都使用了TwoPlayerGame的私有实例来本地管理游戏状态。例如,IsStopped和CurrentStatus属性直接从InnerGame实例中获取: 隐藏,复制Code

public class DrenchGameServer : DrenchGameBase, IDrenchGameServer
{
public DrenchGameServer()
{
InnerGame = new TwoPlayerGame();
} private TwoPlayerGame InnerGame { get; private set; } public override bool IsStopped
{
get { return InnerGame.IsStopped; }
protected set { ... }
} public override string CurrentStatus
{
get { return InnerGame.CurrentStatus; }
protected set { ... }
}
}

实现服务器特定的方法Join和Leave非常容易。所有我们需要做的是确保Join方法只能被调用一次(我们总是对单一对手发挥): 隐藏,复制Code

public void Join()
{
if (IsReady)
{
// this exception will travel across the wire to the client
throw new InvalidOperationException("Second player " +
"already joined the game. Try another server.");
} IsReady = true;
OnGameStarted();
} public void Leave()
{
IsReady = false;
IsStopped = true;
OnGameStopped(false, "Second player has left the game.");
}

除了本地的内部游戏实例外,DrenchGameClient类还持有对远程IDrenchGameServer的引用。它连接到服务器,复制板数据,订阅服务器事件,并调用Join方法: 隐藏,复制Code

public class DrenchGameClient : DrenchGameBase
{
public DrenchGameClient(IDrenchGameServer server)
{
Server = server;
InnerGame.Board.CopyFromFlipped(Server.Board);
InnerGame.SkipMove();
UpdateStatus();
JoinServer();
} public async void JoinServer()
{
await Task.Factory.StartNew(() =>
{
Server.GameStarted += ServerGameStarted;
Server.GameStopped += ServerGameStopped;
Server.Moved += ServerMoved;
Server.Join();
});
}
...
}

注意,JoinServer方法是异步的。由于网络延迟,远程调用比本地调用慢1000倍。为了确保我们的游戏不会冻结UI,我们需要异步执行远程调用。请注意Xamarin的stable branch。Android仍然不支持异步/等待模式,所以你需要框架的最新beta版本来编译这段代码。 另一个有趣的地方是,DrenchGameClient是如何采取行动的。它所做的唯一事情是调用服务器的方法并处理服务器的事件。游戏客户端不改变其内部游戏的状态:它完全由远程服务器控制。注意,MakeMove方法也是异步的,因为它涉及一个远程调用: 隐藏,复制Code

public override async void MakeMove(int value)
{
await Task.Factory.StartNew(() => Server.MakeMove(value));
} private void ServerMoved(object sender, MoveEventArgs e)
{
InnerGame.MakeMove(e.Color);
UpdateStatus();
}

托管DrenchGameServer 为了实现游戏服务器的网络共享,我们采用了Zyan通信框架。这个库不需要对我们的类进行任何额外处理,因此我们可以按原样发布DrenchGameServer实例。下面的图表概述了Zyan应用程序的典型架构(注意,除了ZyanComponentHost和ZyanConnection类之外,这些内部内容不会出现在我们的应用程序代码中)。青色框表示Zyan库类,黄色框表示应用程序代码: 要启动服务器,我们需要创建一个带有TCP协议的ZyanComponentHost实例。游戏服务器和zyan主机实例将存储在我们自定义应用类的属性中,就像其他共享实例一样: 隐藏,复制Code

public void StartServer()
{
if (ZyanHost == null)
{
// set up duplex tcp protocol, no security required
var portNumber = Settings.PortNumber;
var authProvider = new NullAuthenticationProvider();
var useEncryption = false;
var protocol = new TcpDuplexServerProtocolSetup(portNumber, authProvider, useEncryption); // start the server
ZyanHost = new ZyanComponentHost(Settings.ZyanHostName, protocol);
} // create server game
var server = new DrenchGameServer();
DrenchGame = server; // register game component, so a client can connect to the server
ZyanHost.RegisterComponent<IDrenchGameServer, DrenchGameServer>(server);
}

注:目前Zyan library Android版本中唯一可用的传输协议是双工TCP协议。 连接到DrenchGameServer 要连接到Zyan component host发布的游戏服务器,需要完成以下步骤: 通过创建ZyanConnection类建立连接为远程idrenchgameserver创建代理创建DrenchGameClient,将服务器代理作为构造函数参数传递 让我们在自定义应用程序类中添加一个方法: 隐藏,复制Code

public IDrenchGameServer ConnectToServer(string hostName)
{
var protocol = new TcpDuplexClientProtocolSetup(encryption: false);
var url = protocol.FormatUrl(host, Settings.PortNumber, Settings.ZyanHostName); var zyanConnection = new ZyanConnection(url, protocol);
return zyanConnection.CreateProxy<IDrenchGameServer>();
}
... // this method is used as follows (note the non-blocking asynchronous call):
var server = await Task.Factory.StartNew(() => App.ConnectToServer(Settings.ServerAddress)); // and now -- already familiar code to start a game:
App.DrenchGame = new DrenchGameClient(server);
StartActivity(typeof(DrenchBoardActivity));

所以,我们刚刚为Android创建了一个支持Wifi的简单多人游戏。尽管本文没有涵盖应用程序的每个小方面,但我希望它展示了所有重要的方面。任何反馈将非常感谢! 另外,游戏已经上传至谷歌游戏应用商店,最新的源代码可以在Codeplex和github上找到。 参考文献 Zyan Drench在谷歌游戏:https://play.google.com/store/apps/detailsallie.Zyan。在CodePlex上下载最新的源代码:https://drench.codeplex.com/ xamarin。Android平台:http://xamarin.com/monoforandroid Zyan通信框架:http://zyan.com.de/ 历史 05.08.2013最初的帖子 本文转载于:http://www.diyabc.com/frontweb/news30452.html

Zyan Drench,支持Wifi的Android游戏的更多相关文章

  1. 【树莓派】【转】树莓派3装Android 6.0,支持Wi-Fi和蓝牙

    树莓派3装Android 6.0,支持Wi-Fi和蓝牙 相信对于许多树莓派初学者(包括我)来说,Android系统的确是一个不错的选择.但国内这方面资源稀缺,经本人FQ苦寻,找到了老外的树莓派Andr ...

  2. Android游戏开发实践(1)之NDK与JNI开发01

    Android游戏开发实践(1)之NDK与JNI开发01 NDK是Native Developement Kit的缩写,顾名思义,NDK是Google提供的一套原生Java代码与本地C/C++代码&q ...

  3. Android游戏开发实践(1)之NDK与JNI开发02

    Android游戏开发实践(1)之NDK与JNI开发02 承接上篇Android游戏开发实践(1)之NDK与JNI开发01分享完JNI的基础和简要开发流程之后,再来分享下在Android环境下的JNI ...

  4. 八款常见的Android游戏引擎

    原文地址:http://bbs.csdn.net/topics/380203732 1.Angle  Angle是一款专为Android平台设计的,敏捷且适合快速开发的2D游戏引擎,基于OpenGL  ...

  5. Android 游戏教程让人物动起来

    在这里给大家分享Android游戏教程怎样让人物动起来,话不多说了,直接进入正题. 一. 准备工作     首先要准备好要使用的人物动作图和地形图.把它分割成16个不同的动作,循环播放同一行的4个不同 ...

  6. 【读书笔记《Android游戏编程之从零开始》】19.游戏开发基础(游戏音乐与音效)

    在一款游戏中,除了华丽的界面 UI 直接吸引玩家外,另外重要的就是游戏的背景音乐与音效:合适的背景音乐以及精彩的音效搭配会令整个游戏上升一个档次. 在 Android 中.常用于播放游戏背景音乐的类是 ...

  7. 【转】unity开发android游戏(一)搭建Unity安卓开发环境

    http://blog.csdn.net/chenggong2dm/article/details/20654075 1,下载安装Java的JDK: http://www.oracle.com/tec ...

  8. 转 iOS和android游戏纹理优化和内存优化(cocos2d-x)

    iOS和android游戏纹理优化和内存优化(cocos2d-x) (未完成) 1.2d游戏最占内存的无疑是图片资源. 2.cocos2d-x不同平台读取纹理的机制不同.ios下面使用CGImage, ...

  9. 记录一下八款开源 Android 游戏引擎

    记录一下八款开源 Android 游戏引擎 虽然android学了点点,然后现在又没学了(我为啥这么没有恒心呢大哭).以后有时间还是要继续学android的,一定要啊!虽然现在没学android游戏编 ...

随机推荐

  1. Angular(二) - 组件Component

    1. 组件Component示例 2. Component常用的几个选项 3. Component全部的选项 3.1 继承自@Directive装饰器的选项 3.2 @Component自己特有的选项 ...

  2. 当try、catch中有return时,finally中的代码会执行么?

    今天,看到一个面试题: try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗? 我们用代码来验证下: public static void mai ...

  3. 分布式系统监视zabbix讲解五之web监控

    Web 监控 概况 你可以使用 Zabbix 检查几个网站可用性方面. 如果要使用 Web 检测功能,必须在 编译Zabbix 的时候加入 cURL(libcurl) 的支持. 要使用 Web 监控, ...

  4. matlab数字图像简单的加密方法

    图像加密的重要性可想而知,每个人都会有自己的小秘密,通过图像加密的方法可以保护自己的照片等的安全. 一般情况下,图像加密可以分为以下几个步骤: 1.选择图像加密算法 2.根据算法获取秘钥 3.根据保存 ...

  5. python中random库的使用

    基本随机函数 计算机产生随机数是需要随机数种子的,例如 给定一个随机数种子,就能利用梅森旋转算法产生一系列随机序列 每一个数都是随机数,只要随机种子相同,产生的随机数和数之间的关系都是确定的 随机种子 ...

  6. 第3章 01 python数字类型即操作

    浮点数类型 通过round函数比较浮点数之间的比较关系 复数类型 数值运算函数 小结 天天向上的力量 千分之一的力量 千分之五和百分之一的力量 在1的基础上增加天天向上的参数 在1的基础上减去天天向下 ...

  7. 1.2Hadoop概述

  8. session深入探讨

    简介 session(会话),其实是一个容易让人误解的词.它总跟web系统的会话挂钩,利用session,javaweb项目实现了登录状态的控制.坊间流传,关闭浏览器,就是关闭了web系统的会话. 其 ...

  9. powerDesiger的学习

    一:简介 二:建立物理模型(正向工程) 1.创建 (1) file->new Model创建需要的物理模型,设置使用的数据库. 2.物理模型的数据库设计 (1)一个物理模型中可以有好几张数据库表 ...

  10. 虚拟机系列 | JVM运行时数据区

    本文源码:GitHub·点这里 || GitEE·点这里 一.内存与线程 1.内存结构 内存是计算机的重要部件之一,它是外存与CPU进行沟通的桥梁,计算机中所有程序的运行都在内存中进行,内存性能的强弱 ...