“人脑计算机”——Shakuntala Devi

 

    今天一早打开谷歌,就看到下图这个特别的logo,点击进去,了解了这个被人称为“人脑计算机”的计算天才Shakuntala Devi。

shakuntala-devis-84th-birthday-5315657683959808-hp.gif

    夏琨塔拉·戴维1939年出生在印度的班加罗尔,父亲是名驯狮人,她3岁与父亲一起玩扑克魔术时,开始了与她数字的亲密关系。

    她被誉为“人类计算器”和“印度数学女巫”,孩童时代,戴维就在迈索尔大学和安纳马莱大学展示了她的数学天赋。

    她的天才在《吉尼斯世界纪录》被多次提到,如她心算出一个201位数的23次方根,还有她在几秒内算出332,812,557的立方根。

    2006年,她出版了《漫游数字仙境》一书,讲述了一个对数字着迷的女孩的故事。

 

 

SurfaceView游戏框架编程步骤小结

1.实现带有实现Callback接口监听的SurfaceView

(1)实例化SurfaceHolder

(2)paint为SurfaceView添加状态监听

(3)实例化画笔paint

(4)设置画笔颜色

(5)重写Callback接口的三个用于监听的函数

(6)定义绘图函数

    lockCanvas

    drawText

    unlockCanvasAndPost

(7)修改MainActivity来让其显示SurfaceView视图

    setContentView

(8)重写onTouchEvent方法,实现触屏监听。

 

2.用刷屏来更新画布

(1)图形覆盖法

(2)颜色填充法

(3)背景图片法

 

3.添加多线程

(1)实现Runnable接口

(2)定义一个布尔值的成员变量作为线程标识符

(3)控制帧频

(4)使用try-catch增强程序的健壮性

为SurfaceView视图添加线程

      游戏中有些时候需要固定一个时间去刷新画布,例如背景动态的浮云、流水等等,这些元素不会与玩家交互,但它却是动态的。因此游戏中会有一个线程在不停地重绘画布,实时更新游戏背景动态元素的状态。除此之外,游戏中还有其他的逻辑需要不断更新,例如游戏中钱币的更新等等。

public class MySurfaceView extends SurfaceView implementsCallback, Runnable {

...

// 声明一个线程对象

private Thread thread;

// 线程标示符

private boolean threadFlag;

public MySurfaceView(Contextcontext) {

super(context);

// 实例holder

holder = this.getHolder();

// 为SurfaceView添加状态监听

holder.addCallback(this);

// 实例画笔

paint = new Paint();

// 设置画笔颜色为白色

paint.setColor(Color.WHITE);

// 设置焦点

setFocusable(true);

}

@Override

public void surfaceCreated(SurfaceHolder holder) {

// 初始化屏幕尺寸

SCREEN_W = this.getWidth();

SCREEN_H = this.getHeight();

// 在SurfaceView创建时修改线程标识符为真,表名线程启动

threadFlag = true;

myDraw();

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

}

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

threadFlag = false;

}

/**

* 自定义绘图函数

*/

public void myDraw() {

...

}

@Override

public boolean onTouchEvent(MotionEvent event) {

textX = (int)event.getX();

textY = (int)event.getY();

myDraw();

return true;

}

/**

* 功能:封装游戏逻辑

*/

public void logic() {

;

}

@Override

public void run() {

while (threadFlag) {

longstartTime = System.currentTimeMillis();

myDraw();

logic();

long endTime= System.currentTimeMillis();

/*

* 1000ms /60 = 16.67ms 这里,我们采用15,使帧率限制在最大66.7帧

*/

if (endTime -startTime < 15) {

try{

Thread.sleep(15- (endTime - startTime));

} catch(InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

      本类中,有以下注意的地方:

      1.线程标示符

      在代码中“boolean flag;”语句声明一个布尔值,主要用途有:(1)防止重复创建线程。(2)便于销毁线程。

      android手机上都有Home键和Back键,当用户按下这个按键,手机无论执行什么程序,都会返回桌面。从而导致SurfaceView状态的改变。Home和Back的区别在于,在用户按下Back键后再重新进入程序,SurfaceView的生命周期调用如下:surfaceDestroyed→ 构造方法 → surfaceCreated → surfaceChanged。在用户按下Home键后再重新进入程序,surfaceView的生命周期调用是这样的:surfaceDestroyed→ surfaceCreated → surfaceChanged。

      由以上区别可知,当每次按下Back后再返回程序时,SurfaceView都会被重新加载。

      因为这个原因,我们为了避免线程重复创建而出现线程状态异常。最完美的做法就是,线程的初始化和线程的启动都放在视图创建的surfaceCreated中来完成,并且在surfaceDestroyed 中将线程标示符设置为false。这样既可以避免线程已启动异常,同样也可避免线程无线创建的问题。

      2.控制帧频

      由于不同手机不同的性能,处理逻辑和绘图的时间不同,为了尽量使游戏的用户体验一直,我们就要控制帧频,以避免设备性能好游戏就能运行飞快的问题。性能较差的设备,能够做到不丢帧的运行即可。当设备处理完绘图和逻辑之后,如果处理所用时间小于一帧的时间,那么就让它休眠够剩下的时间。

SurfaceView框架之刷屏方式

      View框架不需手动“刷屏”,是因为View类本身提供两种重绘函数,其内部已封装了对画布的刷屏操作。但SurfaceView是自定义的绘图函数,而且每次获取到的Canvas仍然是上次使用过的画布。系统没有刷新画布,也没有重新提供一个画布,因此如果不刷新的话,必会遗留下以前画布的状态。所以,用SurfaceView视图,在得到其画布Canvas之后,应先进行刷屏操作,将画布上的内容全部清空,然后再进行绘图。

      刷屏的方式有以下几种:

      1.覆盖法,即是每次绘图之前,绘制一个等同于屏幕大小的图形覆盖在画布上。

public void myDraw(){

  Canvas canvas = holder.lockCanvas();

  //绘制矩形

  canvas.drawRect(0,0,this.getWidth(),this.getHeight(),paint);

  canvas.drawText("Game",textX,textY,paint);

  holder.unlockCanvasAndPost(canvas);

}

      每次在画布上绘制前都会绘制一个填充的,大小等同于屏幕的矩形覆盖画布,只要这个矩形的颜色等同于拼命默认的颜色,那就等同于将屏幕做了清屏操作。

      2.颜色重绘法,有以下两种情况。

     (1)每次绘图之前,在画布上填充一种颜色。

       canvas.drawColor(Color.Black);

       Canvas类的drawColor(int color)函数是往整个画布中填充一种颜色。

     (2)指定RGB,每次绘图之前,指定RGB来填充画布。

       canvas.drawRGB(0,0,0);

      3.图片覆盖法,每次绘图之前,绘制一张等同于屏幕大小的图片覆盖在画布上。

在画布上绘制图形之前,首先绘制游戏的背景图,并且这张背景图一定要等同于屏幕的大小。

SurfaceView游戏框架学习笔记

SurfaceView学习笔记整理:

      1.创建MySurfaceView类,继承自SurfaceView,此外还要实现android.view.SurfaceHolder.Callback接口。Callback接口需重写surfaceCreated、surfaceChanged、surfaceDestroyed三个函数用于监听SurfaceView的不同状态。

      2.定义SurfaceHolder类的实例,此类提供控制SurfaceView的大小、格式等,主要用于监听SurfaceView的状态。使用SurfaceHolder的lockCanvas()函数来获取SurfaceView的Canvas对象,再通过在Canvas上绘制内容来修改SurfaceView中的数据。

     lockCanvas()函数不仅获取Canvas还对Canvas画布加锁,画布同步加锁机制主要是为了防止SurfaceView在绘制过程中被修改、摧毁等发生的状况改变;与之对应还有一个unlockCanvasAndPost(Canvas canvas)函数用于解锁画布和提交。

     lockCanvas()可以获取当前视图的画布,lockCanvas(Rect rect)传入一个矩形类的实例,用于得到一个自定义大小的画布。

      3.SurfaceView是通过SurfaceHolder来修改其数据,所以在SurfaceView上绘图不再使用onDraw,而是通过SurfaceHolder获取到SurfaceView的Canvas,然后再绘制。

public myDraw(){

Canvas canvas = holder.lockCanvas();

canvas.drawText("Game",10,10,paint);

holder.unlockCanvasAndPost(canvas);

}

      myDraw()中通过SurfaceHolder的lockCanvas()函数得到一个Canvas实例,然后绘制文本,最后解锁并提交画布。

      4.修改MainActivity,显示自定义的SurfaceView试图。

@Override

public void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

//设置全屏

...

//显示自定义的SurfaceView视图

setContentView(new MySurfaceView(this));

}

      5.实现触屏监听

//定义文本的坐标为成员变量

private int textX=10;textY=10;

//修改绘制函数

public void myDraw()

{

 Canvas canvas = holder.lockCanvas();

 canvas.drawText("Game",textX,textY,paint);

 holder.unlockCanvasAndPost(canvas);

}

//完成触屏监听(重写View的触屏监听函数)

@Override

public booblean onTouchEvent(MotionEvent event)

{

  textX=(int)event.getX();

  textY=(int)event.getY();

  myDraw();

  return true;

}

      6.问题:运行程序后,视图中应该只有一个Game文本字样,但是却出现了很多个,问题的原因就是画布没有刷新。

View游戏框架

程序编写步骤:

      1.创建MyView类,继承于View类,在MyView类中重写父类的构造函数、绘图函数onDraw、按

键按下事件函数onKeyDown、按键抬起事件函数onKeyUp、触屏事件函数onTouchEvent。

      2.修改MainActivity活动类,让屏幕显示MyView类,关键代码在onCreate()函数中:

setContentView(new MyView(this))

基础知识整理:

      1.绘图函数onDraw

      绘图首先要有一个画布,而View类正好提供了一个画布实例,它位于View的绘制函数onDraw的参数中。

protected void onDraw(Canvas canvas)

{

  //创建一个画笔的实例

  Paint paint = new Paint();

  //设置画笔的颜色

  paint.setColor(Color.WHITE);

  //绘制文本

  canvas.drawText("Game",10,10,paint);

  super.onDraw(canvas);

}

      注意,上述的  paint.setColor(Color.WHITE);等同于  paint.setColor(0xffffffff);用十六进制表示颜色值的好处是更加灵活。

      画布类Canvas的drawText函数有4个参数。参数一是String类型,指文本信息;参数二与参数三分别指文本绘制在屏幕的X、Y位置坐标(默认绘制文字以文字的左下角为锚点);参数四是画笔实例。

      为程序设置全屏:隐去状态栏部分和程序的标题栏部分。

this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);

this.requestWindowFeature(window.FEATURE_NO_TITLE);

     注意,设置隐藏标题栏需在显示View视图之前完成,否则程序会发生异常。

     关于手机屏幕坐标的问题,无论是横屏还是竖屏,手机最左上角的点永远是(0,0)点;而(0,0)点水平向右是X轴正方向,(0,0)点垂直向下是Y轴的正方向。

     2.按键监听

     游戏中与玩家交互的主要途径就是手机按钮或触屏这两种事件。View视图类中已经封装了这些函数,只需重写按键、触屏监听函数即可获取当前玩家点击的按键或触屏的位置。

     按键监听有onKeyDown和onKeyUp两个函数。触屏监听函数只有onTouchEvent一个。为何触屏函数只有一个?手指按下屏幕和手指离开屏幕是如何监听的?其实触屏监听函数不只是玩家手指按下时触发响应,当手指离开屏幕、手指在屏幕中滑动等动作都可以通过此函数完成监听。

     为了看到动态图像的效果,需要重新绘制画布。View的onDraw函数虽然是绘制函数,但是此函数只是在View视图一开始创建运行的时候执行一遍而已。即使通过按键改变了绘制的文本坐标,所看到的依然是之前的画布,不是最新的画布状态。

     为了重绘画布,View类提供了invalidate函数和postInvalidate()函数,并且这两个函数会再次调用onDraw。两者的区别主要是,invalidate()函数不能在当前线程中循环调用执行,而postInvalidate可以。注意,这里的线程不是系统的主UI线程,而是子线程(自己创建的线程)。

      3.触屏监听

      要让文本随手指移动,那么文本的坐标就永远是玩家手指在手机屏幕上的位置。为了实现该效果,可在触屏监听函数中添加如下代码:

@Override

public boolean onTouchEvent(MotionEvent event)

{

  int x = (int)event.getX();

  int y = (int)event.getY();

  //玩家手指点击屏幕的动作

  if(event.getAction() == MotionEvent.ACCTION_DOWN){

      textX =x;

      textY =y;

      //玩家手指抬起离开屏幕的动作  

  }else if(event.getAction() == MotionEvent.ACTION_MOVE){

      textX =x;

      textY =y;

      //玩家手指在屏幕上移动的动作

  }else if(event.getAction() == MotionEvent.ACTION_MOVE){

      textX =x;

      textY =y;

  }

  //重绘画布

  invalidate();

  //postInvalidate();

  return super.onTouchEvent(event);

}

      为确保当手指在屏幕中进行滑动的时候,坐标随手指移动,需让触屏监听函数的返回值永远为True。修改触屏监听函数:

@Override

public boolean onTouchEvent(MotionEvent event){

    ...

    return true;

}

      触屏监听函数实际上没必要获取用户的动作,因为无论玩家什么动作,都是手指触摸在屏幕上的X、Y坐标的位置,因此可简化程序如下:

@Override

public boolean onTouchEvent(MotionEvent event)

{

  //获取用户手指触屏的X坐标赋值与文本的X坐标

  textX  = (int)event.getX();

  //获取用户手指触屏的Y坐标赋值与文本的Y坐标

  textY  = (int)event.getY();

  //重绘画布

  invalidate();

  //postInvalidate();

  //return super.onTouchEvent(event);

  return true;

}

Android游戏开发基础小结2

      Android游戏开发中,有三种常用视图:View、SurfaceView、GLSurfaceView。这三种视图的含义如下:

      View:显示视图,内置画布,提供图形绘制函数、触屏事件、按键事件函数等。

      SurfaceView:基于View视图进行拓展的视图类,更适用于2D游戏开发。

      GLSurfaceView:基于SurfaceView视图进行再次拓展的视图类,专用于3D游戏开发的视图。

      目前主要做2D游戏开发,因此着重了解View和SurfaceView这两个游戏框架。两者的主要区别如下:

      1.更新画布方面的区别。

      在View视图中对于画布的重新绘制,是通过调用View提供的postInvalidate()与invalidate()这两

个函数来执行的,也就是说画布是由系统主UI进行更新。那么当系统主UI线程更新画布时可能会引发

一些问题,比如更新画面的时间一旦过长,就会造成主UI线程被绘制函数阻塞,这样一来则会引发无

法响应按键、触屏等消息的问题。

      而SurfaceView视图中对于画布的重绘是由一个新的单独线程去执行处理,所以不会出现因主UI线程

阻塞而导致无法响应按键、触屏信息等问题。

      2.视图机制方面的区别。

      View视图没有双缓冲机制,而SurfaceView视图却有。实际上,SurfaceView就是一个由View扩展而

来的更加适合游戏开发的视图类。

      这两个游戏框架各有优点:

      对于游戏画面是属于被动更新的游戏类型,比如棋牌类游戏,应选择View视图比较合适,因为画

布的重绘主要是依赖于按键与触发事件(当玩家有了操作之后画布才需要进行更新)。这样,较之

SurfaceView而言,它减少了因使用SurfaceView需要单独起一个线程来不断更新画布所带来的运行开

销。

      对于是属于主动更新画布的游戏类型,比如RPG、飞行射击等类型的游戏中,很多元素是动态的,

需要不断重绘元素状态,这时再用View就不合适了。因此游戏开发中到底哪种视图更为合适,这取决

于游戏类型、风格和需求。

     总而言之,SurfaceView更适合于游戏开发,因为SurfaceView能适应更多的游戏类型。

中国第一个人站长李兴平给我的启示

 

      今天在网上无意中再次看到李兴平的故事,说到李兴平,IT届的小伙伴们大概没有不知道的,他是

hao123.com的创始人,现在是4399游戏的董事长,业界称它是中国第一个人站长。

      成功的创业者的故事,总是激励人心的。李兴平的故事,我已早有了解。奇怪的是看了几次了,每次

都是一样的感到激励。论学历,李兴平只有高中学历,论工作经验,创办hao123时只有组装出售电脑和网

吧管理员的工作经验。

  据说,正是这个网吧管理员的身份,让李兴平能有机会天天泡在网上,泡在那些打游戏、聊天、上网

的网民中。很快,他发现来网吧的很多人都不知道如何上网,上网后又不知道去哪里找到所需要的内容。

当时的上网费很贵,时间与金钱却往往在茫然不知所措中奢侈地流失。当时的中文网站不仅内容不够丰富

,数量有限,而且要把那些用英文字母表示的网址一个个记下来,并不是一件容易的事情。于是,李兴平

开始做了一个简陋的个人网页,并且在自己的主页上有意识地增加各类网址链接,就是这样积少成多,逐

渐形成了hao123网址大全。

      从李兴平那里我们至少可以得到如下一些启示:

      一、发现需求,满足需求。有需求的地方就有机遇,一旦抓住了把握了这些机遇,就大有成功的可能

了。最起初,李兴平正是由于能发现网民上网方面的需求,并且有心地去满足这样的需求,才有了hao123的

巨大成功。

      二、专注一个领域,主要功能要突出。例如做个网站,可以专注于一个在主题,提供游戏服务就单纯游

戏好了,提供音乐欣赏就单纯音乐欣赏得了,不要什么频道都要反而什么都做不好。

      三、产品简单实用,hao123起初很简单但是很实用。百度CEO李彦宏对此的评价是:“正是由于它的简

单,简单到你无法去超越它。”

 

二维码入驻博客内页

      现在是二维码满天飞的时代。随处可见的二维码,确实为我们提供了一定的便利。本博客的首页早就贴上二维码了,那是利用一个二维码工具预先生成好,然后再摆上去的。当然,不能仅仅满足于此,我要让博客每一个页面都有一个二维码,以便手机方面地访问博客的每一个角落。

      具体做法:找一个提供二维码API的网站,如Google Chart API、快拍二维码(灵动快拍)提供的API、腾讯QQ的API等。在此,我们利用腾讯QQ的二维码API来实现想要的效果,在文章页的适当位置加入以下代码即可:

<img src=”http://mobile.qq.com/qrcode?url=<?php //此处调用内页的网址,例如$this->permalink() ?>” width=”100” height=”100”>

      实现效果见本文末尾自动生成的二维码。有兴趣的读者可以扫一扫看,欢迎拍砖指教!

 

android游戏开发基础小结

      经过前一段时间,自己亲自玩游戏,如:经典打飞机、天天爱消除、天天酷跑等。同时学习游戏开发的基础,对android游戏以及游戏开发有了一些见解。在此仅作小结,以便复习和交流之用。

      对玩家而言,游戏是动态的;于开发人员而言,游戏是静态的。是许多不同的静态画面不停地进行播放,才产生了动态效果。

     做android游戏开发,把以下两点基础率先掌握了吧:

     1.三个重要的类,需要仔细了解:View(视图)、Canvas(画布)、Paint(画笔)。画笔Paint用于在画布Canvas上画各种图形图片之类的东西,视图View用于展现画布上的内容到手机屏幕上。

     2.一个重要的概念——刷屏,我们绘制在画布上的是静态图像,只有不停地展示不同的画布,才能实现动态效果。手机上的画布永远只是一张,因此不可能播放不同的画布,此时便需要对画布进行刷新来达到动态的效果。不断地刷新屏幕,重新绘制画布,这个过程就是“刷屏”。