当前位置:  编程技术>移动开发
本页文章导读:
    ▪施用AppWidget进行广播更新        使用AppWidget进行广播更新                     使用AppWidget进行广播   android.appwidget包中定义的类: 1、        AppWidgetProvider:定义了AppWidget的基本操作,需要通过子类进行设置; 2、 .........
    ▪ Defender Game 游戏实践(一) 基本游戏场景实现        Defender Game 游戏实践(1) 基本游戏场景实现    在网上看到 郑州|boy 这个博客,里面有几篇文章,记录了其用cocos2d-x这个游戏引擎编写的一个游戏,十分不错,所以这段时间,依样画葫芦.........
    ▪ 手机安全卫士开发系列(七)——知识点整理(2)       手机安全卫士开发系列(7)——知识点整理(2)六、  安装新的apk /** * 安装apk * @param file */ private void install(File file){ Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setDa.........

[1]施用AppWidget进行广播更新
    来源: 互联网  发布时间: 2014-02-18
使用AppWidget进行广播更新

 

 

 

 

 

 

 

 

 

 

使用AppWidget进行广播

 

android.appwidget包中定义的类:

1、        AppWidgetProvider:定义了AppWidget的基本操作,需要通过子类进行设置;

2、        AppWidgetProviderInfo:AppWidget组件的元数据提供者,例如:组件的大小、更新的时间等;

3、        AppWidgetHostView:创建AppWidget的View显示,些为真正的View,与之对应的还有一个RemoteView;

4、        AppWidgetHost:监听AppWidget的服务以及创建AppWidgetHostView

5、        AppWidgetManager:用于更新相应的AppWidget。

 

将本程序安装后,按Home键回到手机桌面,长按桌面后出现上下文对话框,此时选择“窗口小部件”,接着找到我们安装的程序,

我这里的程序名称为“桌面显示组件”,这样在我们的手机桌面上就出现了程序的快捷方式,我们一按此快捷方式就可以进行更新了。

 

  本列子说明了如何进行按钮的更新,但是一般不会对按钮进行更新,本列子只为说明更新的方法。

 

 

在res/drawable-hdpi下加入一张名为button和一张名为button2的图片以供使用。

 

 

 

定义一个继承AppWidgetProvider的类MyAppWidget,代码如下:

 

package com.li.appwidget;

 

import android.annotation.SuppressLint;

import android.app.PendingIntent;

import android.appwidget.AppWidgetManager;

import android.appwidget.AppWidgetProvider;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.widget.RemoteViews;

 

@SuppressLint("ParserError")

public class MyAppWidget extends AppWidgetProvider {

 

  @Override

  public void onReceive(Context context, Intent intent) {

    if("com.li.action.MYAPPWIDGET_UPDATE".equals(intent.getAction())){

       RemoteViews remote = new RemoteViews(context.getPackageName(),

            R.layout.liyewen_appwidget);

       remote.setImageViewResource(R.id.img, R.drawable.button2);

       remote.setTextViewText(R.id.but, "按钮被更新了");  //更新按钮上的文字

       AppWidgetManager appWidgetManager = AppWidgetManager

            .getInstance(context);

       ComponentName componentName = new ComponentName(

            context,MyAppWidget.class);

       appWidgetManager.updateAppWidget(componentName, remote);

     }

     else{

       super.onReceive(context, intent);

    }

  }

 

  @Override

  public void onUpdate(Context context, AppWidgetManager appWidgetManager,

       int[] appWidgetIds) {

       Intent intent = new Intent();

       intent.setAction("com.li.action.MYAPPWIDGET_UPDATE");

       PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,

            intent, PendingIntent.FLAG_UPDATE_CURRENT);

       RemoteViews remote = new RemoteViews(context.getPackageName(),

            R.layout.liyewen_appwidget);

       remote.setOnClickPendingIntent(R.id.but, pendingIntent);

       appWidgetManager.updateAppWidget(appWidgetIds, remote);

     }

}

 

 

 

 

 

 

 

在res下新建xml文件夹,并在xml下新建一个资源配置文件liyewen_appwidget.xml,

此文件用于读取AppWidgetProvider的配置信息,代码如下:

 

<appwidget-provider

    xmlns:android="http://schemas.android.com/apk/res/android"

    android:minHeight="80dp"

    android:minWidth="300dp"

    android:updatePeriodMillis="6000"

    android:initialLayout="@layout/liyewen_appwidget">

 

 

</appwidget-provider>

 

 

 

 

 

 

在layout文件夹中新建布局文件liyewen_appwidget.xml

此布局文件用于以后桌面组件的显示,代码如下:

 

<RelativeLayout 

    xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:gravity="center_horizontal">

  <ImageView

      android:id="@+id/img"

      android:layout_width="160dp"

      android:layout_height="40dp"

      android:src="/blog_article/@drawable/button/index.html"/>

  <Button

      android:id="@+id/but"

      android:layout_width="160dp"

      android:layout_height="40dp"

      android:background="#00000000"

      android:text="按我更新按钮"

      android:textColor="#ffffff"/>

</RelativeLayout >

 

 

 

 

 

 

 

修改AndroidManifest.xml文件,将之前在res/xml文件夹中配置的文件定义在广播之中。

增加的部分为:

 

<receiver android:name=".MyAppWidget">

            <intent-filter >

                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>

            </intent-filter>

            <intent-filter >

                <action android:name="com.li.action.MYAPPWIDGET_UPDATE"/>

            </intent-filter>

            <meta-data

                android:name="android.appwidget.provider"

                android:resource="@xml/liyewen_appwidget"/>

</receiver>

 

 

 

 

整个AndroidManifest.xml文件为(我用的SDK是最新的,所以AndroidManifest.xml文件会有些不同):

 

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.li.appwidget"

    android:versionCode="1"

    android:versionName="1.0" >

 

    <uses-sdk

        android:minSdkVersion="8"

        android:targetSdkVersion="15" />

 

    <application

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name=".MyAppWidgetDemo"

            android:label="@string/title_activity_my_app_widget_demo" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

 

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

        <receiver android:name=".MyAppWidget">

            <intent-filter >

                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>

            </intent-filter>

            <intent-filter >

                <action android:name="com.li.action.MYAPPWIDGET_UPDATE"/>

            </intent-filter>

            <meta-data

                android:name="android.appwidget.provider"

                android:resource="@xml/liyewen_appwidget"/>

        </receiver>

    </application>

</manifest>

 

 

 

 

 

主Activity(MyAppWidgetDemo.java)的代码如下:

 

 

package com.li.appwidget;

 

import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;

import android.view.MenuItem;

import android.support.v4.app.NavUtils;

 

public class MyAppWidgetDemo extends Activity {

 

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

    }

 

}

 

 

 

主布局文件main.xml不用做任何修改

 

 



 

 


    
[2] Defender Game 游戏实践(一) 基本游戏场景实现
    来源: 互联网  发布时间: 2014-02-18
Defender Game 游戏实践(1) 基本游戏场景实现

    在网上看到 郑州|boy 这个博客,里面有几篇文章,记录了其用cocos2d-x这个游戏引擎编写的一个游戏,十分不错,所以这段时间,依样画葫芦,依次学习一下。

由于博主开发的平台是在win32,而且屏幕分辨率也是800*480。我的目标是:按照博主的代码思路,将这个游戏在iphone这个平台下进行代码重构,其中在学习的过程中也进行一定的修改。

我的开发环境:xcode4.6.3 ; cocos2d-x 2.1.4。

本人会根据博主的介绍,加之理解,在代码编写的过程中,写几篇博文记录一下学习历程,以飨读者,也欢迎读者指责。

下面再次注明:博文中介绍到的游戏是通过  点击打开链接  得到,尊重原著。


下面第一篇介绍的内容是博主 系列介绍文章的(一)到(四)篇的内容。本人根据在学习过程中的一些历程分点记录。


资源下载:  项目程序下载(1~4)    注意:其中的资源已是最终版所需要的全部资源,所以在以后的新建文件中只需在代码中直接使用即可,不用再添加资源了。


一、BaseLayer层基类

作者在这个项目中使用到一个BaseLayer层基类,这个类基础自CCLayer,其中只是实现了几个层类中常用的方法。以后层类都是继承自这个BaseLayer类。

cocos2d::CCSize getWinSize();// 
	cocos2d::CCPoint getWinOrigin();// 
	cocos2d::CCPoint getWinCenter();// 
	cocos2d::CCPoint ScreenAdaptation(float x, float y);//在位置设置的时候,进行的屏幕适配

这些方法看名字就知道是什么内容了,在后面的层类中可以方便使用。


二、LoadingLayer游戏资源加载场景

在这个类中实现的是加载游戏所需要的图片等资源,并且加载的过程以进度条的方式进行显示。

实现的效果如下:


关于在游戏开始就进行游戏资源的预加载是一般游戏的通常做法,这样可以优化游戏的速度。通常加载的大部分内容都是图片资源,下面介绍一下这里加载图片资源的方法:

这里加载图片使用到的是 addImageAsync 方法,异步将图片资源加载进  CCTextureCache  中,加载完毕后,调用回调方法,通知进度条向前显示。

例如:

CCTextureCache::sharedTextureCache()->addImageAsync("welcomebg.png",this,callfuncO_selector(LoadingLayer::loadCallBack));

其中的loadCallBack方法介绍有关进度条的显示的。

void LoadingLayer::loadCallBack(CCObject* ped){
	loadingNum++;
    CCProgressTimer* pt=(CCProgressTimer*)this->getChildByTag(1);
	float now=pt->getPercentage();
	pt->setPercentage(100/totalNum+now);
	if(loadingNum<totalNum){
		
	}else{
		goWelcomeLayer(); //资源加载完毕后,跳转到welcome场景
	}
}

当资源加载完毕后,就要跳转场景到welcome场景了。


三、WelComeGameLayer 游戏欢迎场景



这个场景中主要处理的内容是背景音乐的播放和暂停;至于开始按键和开发者按键则是处理简单的视图跳转,比较简单。

首先,我们得知道游戏中背景音乐播放和禁止的逻辑。

1、采用 CCUserDefault 持久化保存用户对背景音乐播放与否的设置;

2、使用 CCMenuItemToggle 开关控件处理背景音乐播放和禁止的选择;

在创建背景音乐开关控件CCMenuItemToggle的时候要读取CCUserDefault中保存的值,根据true或者false进行不同的处理 。

关键代码如下:

CCMenuItemToggle* pVedioTo=NULL;

// 如果存档中保存的是false
		if(!CCUserDefault::sharedUserDefault()->getBoolForKey("isplay")){
			pVedioTo=CCMenuItemToggle::createWithTarget(this,menu_selector(WelComeGameLayer::vedioOnAndOffCallBack),pitemVoff,pitemVon,NULL);
            CCUserDefault::sharedUserDefault()->setBoolForKey("isplay",false);
            CCUserDefault::sharedUserDefault()->flush();
		}else {
			pVedioTo=CCMenuItemToggle::createWithTarget(this,menu_selector(WelComeGameLayer::vedioOnAndOffCallBack),pitemVon,pitemVoff,NULL);
            CCUserDefault::sharedUserDefault()->setBoolForKey("isplay",true);
            CCUserDefault::sharedUserDefault()->flush();
		}

3、当在场景跳转的时候,应该是不会游戏背景音乐的播放或者禁止的;(例如说:现在背景音乐播放,跳转到另一个场景,再跳转回来,那么背景音乐播放是一直持续的,没有任何的变化。------我曾经在这个问题上纠结修改了好久才解决!!) 关于这个问题,我发现原作者的处理是和我的不一样的,我在代码中做了修改。

下面通过代码简单看看我的修改处理:

//播放背景音乐
        if (CCUserDefault::sharedUserDefault()->getBoolForKey("isplay",true)) {
            if (!CocosDenshion::SimpleAudioEngine::sharedEngine()->isBackgroundMusicPlaying()) {
                CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("dt.mp3", true);
                CCUserDefault::sharedUserDefault()->setBoolForKey("isplay",true);
                //注意在set之后要调用flush进行保存
                CCUserDefault::sharedUserDefault()->flush();

            }
        }
        //如果不需要播放背景音乐,那么也播放,只不过立即暂停
        else
        {
            CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("dt.mp3", true);
            //立即暂停背景音乐
            CocosDenshion::SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
            CCUserDefault::sharedUserDefault()->setBoolForKey("isplay",false);
            //注意在set之后要调用flush进行保存
            CCUserDefault::sharedUserDefault()->flush();
        }

这部分代码我是放在init中的,也就说每一次进入这个场景都会执行。对于if中的内容相信都应该可以理解,对于else中的内容可能就有点难理解了,为什么当CCUserDefault存储中为false,即不播放背景音乐的时候,也要播放,只不过是立即停止呢?

没错,这就是关键的处理了!!

这样做呢就把播放和暂停分成了两类处理resume和pause背景音乐,而不必考虑stop背景音乐,否则你会发现很难区分pause和stop,所以这样巧妙的简化的处理,使问题得到解决。

四、屏幕适配的问题

在文章开始的时候我就说到原作者实现的屏幕分辨率是800*480,而我是在iphone下进行代码的重构,所以不可避免的要进行一些屏幕的适配问题。

前面我有一篇文章是关于这个问题的:Cocos2d-x 关于在iOS平台真机测试的一些注意 

处理这个问题也比较简单:

(1)在AppDelegate文件中的  applicationDidFinishLaunching  方法中添加下面的代码(注意要放在 pDirector->setOpenGLView(pEGLView); 后面。):

 CCSize designSize = CCSizeMake(480, 320);
    CCEGLView::sharedOpenGLView()->setDesignResolutionSize(designSize.width, designSize.height, kResolutionShowAll);

(2)由于使用到的图片资源都是来自作者提供,所以我们在使用的过程中也要适配到当前的分辨率中,处理的方法就是在X和Y轴分别按需要进行比例调整。

譬如说,我们要使用到的welcome场景的背景图片,我们可以分别对X和Y轴的比例进行缩放。

CCTexture2D* texturebg=  CCTextureCache::sharedTextureCache()->textureForKey("welcomebg.png");
		CCSprite* pSpriteBg=CCSprite::createWithTexture(texturebg);
        //图片适配
        float scalex = 480/texturebg->getContentSize().width;
        float scaley = 320/texturebg->getContentSize().height;
        pSpriteBg->setScaleX(scalex);
        pSpriteBg->setScaleY(scaley);

五、AboutCoderLayer 开发者介绍场景



这个场景十分简单,没有什么好说的。

不过,这里就讲一下作者在编写这个项目过程中编码的一个习惯吧!作者喜欢将问题细化成一个个模块,然后分别用一个个方法解决实现。我们一这个AboutCoderLayer类为例,在init方法中出现了一个 setUpdateView 方法,在这个方法中处理一些初始化的内容。(这样的处理相信读者已经在代码中已经见到过了。)个人觉得这种处理不错,分模块实现层次感好,而且在debug中也比较方便。

--------------------------------------------/   分割线   /-------------------------------------------------------------

前面的介绍相信都是很小儿科吧!下面开始进入游戏界面,也就是在welcome欢迎场景中点击开始进入的场景。


六、制作武器系统



在上面大家已经看到我们的武器系统了,一把弓里面装了一些弓箭,它可以旋转调整角度,然后发射。

实现这样的一个武器系统要用到两个类:BulletSprite 和 WeaponSprite,第一个类就是处理弓箭的(武器系统中的主角),第二个类就是处理整个武器系统的。

(1)、关于BulletSprite 弓箭类,这个类继承 CCSprite。

1、BulletSprite的静态创建方法,显然我们自定义一个精灵类,自然也要实现其创建方法。不过我们可以参考CCSprite中的方法,依样画葫芦来实现。我们可以在CCSprite类中看到:

CCSprite* CCSprite::createWithTexture(CCTexture2D *pTexture)
{
    CCSprite *pobSprite = new CCSprite();
    if (pobSprite && pobSprite->initWithTexture(pTexture))
    {
        pobSprite->autorelease();
        return pobSprite;
    }
    CC_SAFE_DELETE(pobSprite);
    return NULL;
}

那么我们也可以照样实现,下面就是BulletSprite类中的创建方法实现(几乎一样吧!!):

BulletSprite* BulletSprite::createWithTexture(cocos2d::CCTexture2D *pTexture)
{
    BulletSprite* pobSprite = new BulletSprite();
    if (pobSprite && pobSprite->initWithTexture(pTexture)) {
        pobSprite->autorelease();
        return pobSprite;
    }
    CC_SAFE_DELETE(pobSprite);
    return NULL;
}

2、关于这个弓箭类,其实现中主要就是一个弓箭运动函数的实现---myMove()。其实现也是比较简单的:根据武器系统的旋转角度,用cos和sin函数计算旋转角度再乘以速度获得x轴和y轴的移动距离,然后改变位置。

//弓箭运动
void BulletSprite::myMove()
{
    CCPoint cp=getMovePoint();
	float x=cp.x+this->getPositionX();
	float y=cp.y+this->getPositionY();
	this->setPosition(ccp(x,y));
}
CCPoint BulletSprite::getMovePoint()
{
    // 这里使用了 三角函数 主要是为了计算当前弓箭所移动的位置
	float temhud= (this->getLastRoto()*M_PI)/180; //这里使用到math.h中的M_PI    
    
	float tex= std::cos(temhud)*this->moveSpeed;
	float tey= std::sin(temhud)*this->moveSpeed;
    
	tex=std::fabs(tex);// x 方向不存在负数
	return ccp(tex,-tey);
}


**注意:由于武器系统会选择,所以要涉及到角度和弧度的问题。

①当使用三角函数计算时,使用的是弧度;

②当武器系统或者弓箭旋转rotate时,使用到的是角度。

关于二者的转换:

弧度=角度乘以π后再除以180

角度=弧度除以π再乘以180


(2)关于 WeaponSprite 武器系统类,这个类也是继承自CCSprite。

关于这个类,代码就不贴了,下面讲一下这个类中一些方法的执行顺序和作用:

1、我们在 DefenderGameLayer 这个场景的初始化方法中,可以看到场景好一个武器系统实例后,

pweapon->initIdleBulletSpool(this);

2、initIdleBulletSpool  这个方法初始化了50支弓箭(包括弓箭的一些属性设置)供发射使用,初始化后,

this->schedule(schedule_selector(WeaponSprite::loade),1); 表示接着初始化武器系统上的5个弓箭,而且弓箭加载的时间间隔是1秒,那么当连续发射弓箭时,弓箭发射的时间至少也是1秒(这里的至少,后面会解释)。

3、在loade方法中实际调用的是 loadedBullet 方法,这里就是处理将5支弓箭添加到武器上。

3.1  要往武器上添加弓箭首先肯定是要获取到弓箭啦,getIdleBullet 这个方法就是用于获取弓箭的。这个方法是比较重要的,代码中我已经添加了注释。

在作者提供的代码中个人发现了一个问题:

//这里似乎有点问题
            //batchNode->addChild(pbullet,2);
            //空闲弓箭不够,那么这里就是新增加弓箭,那么就是应该添加到空闲弓箭数组的,而非bathnode,其实这里就是类似回收一个弓箭
            //所以这里做一些改动
            this->pIdleBulletsPool->addObject(pbullet);


3.2  关于loadedBullet方法中,有这几行代码:

for(int i=0;i<this->loadedArray->count();i++){
				this->loadedArray->removeObjectAtIndex(0);
				i--;
			}

咋一看,还不是很明白是神马意思!其实就是要清除loadeArray这一个数组中的所有内容。其完全等价于:this->loadedArray->removeAllObjects();

4、还有一个重要的方法是:

//让弓箭随着主武器旋转
void WeaponSprite::rotateLoadedBullets()
{
    // 获取当前武器旋转的角度
	float mainWeapon= this->hudu*180/M_PI;
	
	if(this->loadedArray){
        
		if(this->loadedArray->count()>0){
			for(int i=0;i<this->loadedArray->count();i++){
                
                BulletSprite* pbul=(BulletSprite*)loadedArray->objectAtIndex(i);
                float temr=pbul->getFirstRoto();
                pbul->setRotation(temr+mainWeapon);
                // 设置最后当前武器最后一次的旋转角度
                pbul->setLastRoto(temr+mainWeapon);
			}
		}
	}
}

5、弓箭的释放

讲到这里武器系统差不多都准备好了,就差如何发射的问题了。那弓箭是在哪里释放发射的呢?我们看到 DefenderGameLayer 文件中,在这个游戏场景界面中,可以接受触摸事件,显然在这里处理有关弓箭的发射;我们注意到在WeaponSprite类中有一个属性canrun,

//这里canrun变量表征是否可以往武器系统中的弓箭是否可以加载到运行中的弓箭,这也决定了弓箭能否发射!!
    CC_SYNTHESIZE(bool, canrun, Canrun);


在DefenderGameLayer的 touchbegan 和 touchmoved 两个方法中都有 pweapon->setCanrun(true);  而在WeaponSprite加载弓箭的时候,有这个canrun属性的判断:

void WeaponSprite::loadedBullet(int cout)
{
    if (this->loadedArray->count()!=cout){
        
		CCArray* tem=this->getIdleBullet(cout);//获取指定数目cout的弓箭
        
		for(int i=0;i<tem->count();i++){
            BulletSprite* pbul=(BulletSprite*)tem->objectAtIndex(i);
            this->loadedArray->addObject(pbul);
		}
	}
    
	// 如果武器停止旋转,表示可以发射 需要把在枪膛中的弓箭添加到发射弓箭中
	if(this->canrun){
        
        //如果有上膛弓箭,则加载到运行弓箭数组上,并且清除上膛弓箭数组
		if(this->loadedArray->count()>0){
            
			this->pRunBulletsPool->addObjectsFromArray(this->loadedArray);
            //清除loadedArray数组
//			for(int i=0;i<this->loadedArray->count();i++){
//				this->loadedArray->removeObjectAtIndex(0);
//				i--;
//			}
            //以上注释部分等价于
            this->loadedArray->removeAllObjects();
            
		}
	}
}

原来,我们touch不松开屏幕就可以实现每间隔1秒的加载弓箭呢!!

但是还是没有说到弓箭的发射呀???别急!!!

我们还是看到DefenderGameLayer的init方法中:

this->schedule(schedule_selector(DefenderGameLayer::detectd),0.1f);//方法调用的间隔是0.1s

void DefenderGameLayer::detectd(float tim)
{
    WeaponSprite* pweapon=(WeaponSprite*) this->getChildByTag(2);
    
    if(pweapon->getRunBulletsPool()){
        
        CCArray* tem=CCArray::create();
        
        for(int i=0;i<pweapon->getRunBulletsPool()->count();i++){
            
            BulletSprite* pbu=(BulletSprite*) pweapon->getRunBulletsPool()->objectAtIndex(i);
            
            //判断弓箭是否移动出屏幕范围,如果是的话,进行回收;否则,让弓箭移动
            if (pbu->boundingBox().getMinX()>=getWinSize().width||pbu->boundingBox().getMinY()<0||pbu->boundingBox().getMinY()>=getWinSize().height){
                pweapon->recoverIdleBullet(pbu);
                tem->addObject(pbu);
            }else {
                bool isp = this->monsterSystem->collisionDetection(pbu);//攻击和怪兽的碰撞检测
                //发生碰撞,说明弓箭射到怪兽
                if (isp) {
                    pweapon->recoverIdleBullet(pbu);
                    tem->addObject(pbu);
                }else//没有发生碰撞,说明弓箭没有射到怪兽
                {
                    pbu->myMove();// 调用移动方法
                }
            }
        }
        //清除运行出屏幕的那些弓箭
        for(int j=0;j<tem->count();j++){
            pweapon->getRunBulletsPool()->removeObject(tem->objectAtIndex(j),false);
        }
        tem->removeAllObjects();
    }
}

我们注意到中间部分的代码,

bool isp = this->monsterSystem->collisionDetection(pbu);//攻击和怪兽的碰撞检测
                //发生碰撞,说明弓箭射到怪兽
                if (isp) {
                    pweapon->recoverIdleBullet(pbu);
                    tem->addObject(pbu);
                }else//没有发生碰撞,说明弓箭没有射到怪兽
                {
                    pbu->myMove();// 调用移动方法
                }

没错,这里就是发射弓箭,让弓箭运动了。由于是每0.1秒调用 detectd() ,所以前面说到弓箭至少1秒发射一次中的至少应该理解了吧! 就是有可能还要加上0.1秒的发射间隔。

差不多,需要讲解注意的就是这些了,详细的内容请参看代码加以理解。


七、实现怪兽系统




怪兽系统可以产生怪兽(赌徒),这些怪兽头顶有一个血条,这些怪兽从右往左走,收到弓箭弓箭后,血条会减少,直到死亡。怪兽可以执行奔跑动画,攻击动画和死亡动画。

这部分内容的实现包括两个类: MonsterSprite 和 MonsterSystem 。

(1)MonsterSprite 怪兽类,这个类继承CCSprite。其实很类似前面的弓箭类。具体就不介绍了,看看下面的类头文件估计就知道是什么内容了。

class MonsterSprite:public cocos2d::CCSprite{
public:
	MonsterSprite(void);
	~MonsterSprite(void);
    
	void moveRun();// 移动函数
    
	CC_SYNTHESIZE(float,hurt,Hurt);//伤害值
	CC_SYNTHESIZE(float,defense,Defense);//防御值
	CC_SYNTHESIZE(float,speed,Speed);//移动速度
	CC_SYNTHESIZE(float,maxRemoving,maxRemoving);// 移动的最大距离
	CC_SYNTHESIZE(float,blood,Blood);// 怪物气血值
	CC_SYNTHESIZE(int,monType,MonType);// 怪物类型
	CC_SYNTHESIZE(int,monState,MonState);// 怪物状态 1 静止状态  2 行动状态 3 攻击状态 4 死亡状态
	CC_SYNTHESIZE(cocos2d::CCRect,attackRange,AttackRange);// 接受攻击的范围
	CC_SYNTHESIZE(int, gold,Gold);// 怪物携带金币数量
    
	void runAnimation();// 执行奔跑动画
	void deathAnimation();// 执行死亡动画
	void attackAnimation();// 执行攻击动画
    
	void fallBlood(float hurt);// 这个是接受攻击 主要改变 该怪物的气血值 和血条的显示
    
	// 第一个参数的意思是 加载的plist 文件的名字 第二个是 plist 对应的图片纹理 第三个是图片的通用名字 第四个走路动画图片数,第五个是攻击动画的图片数  第六个是死亡动画的图片数
	// 在这里贴别说明一点为了达到动画的通用性 我们规定 plist 中的图片命名格式是这样的 pic-1编号 是跑步图片 pic-2编号是 攻击图片 pic-x编号是死亡图片
	static MonsterSprite* createWithMonsterRul(const char* filename,cocos2d::CCTexture2D* ccTexture2D,const char* pic,int runcount,int attackcount,int deathcout );
    
	void setMonsterSystemUtils(MonsterSystem* monsterSystem);
    
	cocos2d::CCRect converNowRect();// 这个方法是把最初设计的攻击范围 转化到当前 界面的坐标系中的矩形
protected:
	cocos2d::CCArray* runArray;//奔跑动画序列帧
	cocos2d::CCArray* deathArray;//死亡动画序列帧
	cocos2d::CCArray* attackArray;//攻击动画序列帧
    
	cocos2d::CCProgressTimer* bloodBwlid;// 这个是血条
    
	virtual void deathAnimationCallBack(cocos2d::CCNode* pSed);// 死亡动画回调函数
	virtual void attackAnimationCallBack(cocos2d::CCNode* pSed);// 攻击动画回调函数
	virtual void runAnimationCallBack(cocos2d::CCNode* pSed);//奔跑动画回调函数
    
	virtual bool setUpdateView();
    
	static MonsterSprite* createWithSpriteFrame(cocos2d::CCSpriteFrame *pSpriteFrame);
    
	MonsterSystem* monsterSystem;
    
	void myload(float tim);
    
};

注意:当两个头文件相互引用的时候,要注意头文件的前置声明。否则会遇到一些莫名其妙的问题的!!!例如在这个类,就需要: class MonsterSystem;


(2)MonsterSystem 怪兽系统类。

这个类主要就是根据MonsterSprite 怪兽类产生怪兽添加到游戏界面中。

typedef struct MonsterUtils{
	float initBlood;// 初始化气血
	float initSpeed;// 初始化速度
	float defend;// 怪物的防御力
	float hurt;// 怪物的伤害值
	char* monsName;// 在设置怪物的时候的通用名字
	char* picName;// 怪物的图片
	char* fileName;// 怪物所对应的plist 文件的名字
	int   type;// 怪物类型
	int   runCount;// 奔跑动画张数
	int   actCount;// 攻击动画张数
	int   detCount;// 死亡动画张数
	float maxRun;// 最大移动距离
	char* attackRangeRec;//是在怪物身上划定一个受到的攻击范围 这样可以让不规则的 图片 看起来受到攻击的时候更逼真一点 字符串的 格式是这样的{{x,y},{w, h}}
	int  gold;// 怪物携带金币数量 当怪物死后 增加金币
} Monster;

class DefenderGameLayer;

// 此类是生产和销毁系统
class MonsterSystem{
    
public:
	MonsterSystem();
	~MonsterSystem();
    
	cocos2d::CCArray* getIdleMonsterArry();// 用来保存空闲的怪物
	cocos2d::CCArray* getRunMonsterArray();// 用来保存正在奔跑中的怪物
    
	void addMonster(int type,int count);// 用于主线程调用来源源不断的产生怪物
    
	void setDefenderGameLayer(DefenderGameLayer* defenderGameLayer);
    
	bool collisionDetection(BulletSprite* bulletsSprite);// 传入弓箭 检测是否和怪物发生碰撞
    
	void recoverMonster(MonsterSprite* monsterSprite);// 回收怪物
    
private:
	cocos2d::CCArray* idleMonsterArry;// 用来保存空闲的怪物
	cocos2d::CCArray* runMonsterArray;// 用来保存正在奔跑中的怪物
    
    MonsterSprite* productMonster(int type);//根据类型来产生响应的怪物的数量
    
	DefenderGameLayer* defenderGameLayer;// 游戏主类
    
	void addDefenderGameLayer(MonsterSprite* monsterSprite);// 把奔跑中的怪物添加到 主界面里面
    
	Monster dutu;// 每次添加新的怪物都需要在这里添加一个 并且在构造方法里面初始化
};

看到头文件大致也可以知道要处理的内容了吧!

下面我就介绍一下其中的关键部分:

1、其中用到一个结构体包含了怪兽的一些基本属性,方便使用。

2、在前面弓箭发射运动之前都要检测弓箭和怪兽是否发生碰撞的检测,就是调用这个类中的 collisionDetection 方法,在这个方法中传入弓箭,检测是否和怪物发生碰撞,如果发射碰撞,就是说怪兽被打中了,那么就要对怪兽头上的血条进行掉血的处理,调用的方法是怪兽类的 fallBlood 方法。

// 这个是接受攻击 主要改变 该怪物的气血值和血条的显示
void MonsterSprite::fallBlood(float hurted)
{
    // 按照 一点防御 能抵挡10%的伤害 来计算
	float temp= this->bloodBwlid->getPercentage()*this->getBlood()/100;// 得到真正属于的气血值
	float cha=temp-(hurted-this->getDefense()*0.1); // 获取 受伤后以后的气血
        
	if(cha<=0){
		this->bloodBwlid->setPercentage(0);
		this->deathAnimation();
	}else {
		this->bloodBwlid->setPercentage(cha/this->blood*100);
	}
}

首先,从代码中知道,一个怪兽的血值是:100,伤害值是10,防御值是1;弓箭的伤害值是10.

这段代码说,一点防御可以抵挡10%的伤害,那么也就是说,弓箭射中怪兽,其伤害也就是 10 * (100% - 10%) = 9,那么每一次都是血值减少 9 。然后再根据剩下血值的比例设置血条,如果血值为0,则怪兽执行死亡动画。


3、怪兽系统差不多搞定了,那么现在就可以向 DefenderGameLayer  游戏场景中添加怪兽了。

this->monsterSystem = new MonsterSystem();
        monsterSystem->setDefenderGameLayer(this);
        this->monsterSystem->addMonster(1, 2);
        this->schedule(schedule_selector(DefenderGameLayer::releaseMonster),1);

void DefenderGameLayer::releaseMonster(float tim){
    this->monsterSystem->addMonster(1,2);
}

每隔一秒向游戏场景添加两只怪兽,不过现在武器系统的攻击能力有限,估计打不死那么多的怪兽,而且源源不断产生这么 多,机子估计也受不了!不怕,后面的程序还会改进的!敬请期待!




    
[3] 手机安全卫士开发系列(七)——知识点整理(2)
    来源: 互联网  发布时间: 2014-02-18
手机安全卫士开发系列(7)——知识点整理(2)

六、  安装新的apk

	/**
	 * 安装apk
	 * @param file
	 */
	private void install(File file){
		Intent intent = new Intent();
		intent.setAction(Intent.ACTION_VIEW);
		intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
		finish();
		startActivity(intent);
	}


激活系统的安装的组件 intent();

设置数据 和数据的类型

setDataAndType();

setData();

setType();

详细关于Android中打开各种文件的intent:          http://blog.csdn.net/dawanganban/article/details/11265363

 

七.  对话框 创建 AlertDialog.buidler

builder.create().show();

八.  Handler message 子线程里面通知主线程ui更新

 

	private Handler handler = new Handler(){

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			// 判断服务器版本号 和客户端的版本号 是否相同
			if (isNeedUpdate(versiontext)) {
				Log.i(TAG, "弹出来升级对话框");
				showUpdataDialog();
			}
		}
		
	};
		// 让当前的activity延时两秒钟 检查更新
		new Thread(){

			@Override
			public void run() {
				super.run();
				try {
					sleep(2000);
					handler.sendEmptyMessage(0);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
		}.start();


九、  GridView ListView adapter  - > BaseAdapter

   

十、.Xml ->定义一个背景颜色  shape  (参考api文件)

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <stroke
        android:width="0.5dip"
        android:color="#ff505050" />

    <corners android:radius="2dip" >
    </corners>

	<gradient android:startColor="#ff404040"
	    android:centerColor="#ff383838"
	    android:endColor="#ff404040"
	    />
</shape>

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http......

<corners........ 定义几何图形的弧度

<gradient...... 定义使用渐变颜色填充

<padding..... 定义几何形状的内边距

<size......        定义几何形状大小

<solid......     定义使用单色填充

<stroke......   定义为几何形状绘制边框

 

十一、Xml -> selector 颜色选择器 根据当前控件的状态显示不同颜色.

    

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/button_background" android:state_enabled="true" android:state_window_focused="false"/>
    <item android:drawable="@drawable/button_background_selected" android:state_pressed="true"/>
    <item android:drawable="@drawable/button_background" android:state_focused="true"/>
    <item android:drawable="@drawable/button_background"/>

</selector>

十二、.Sharedpreference 的使用

SharedPreference是Android提供的一种轻量级的数据存储方式,主要用来存储一些简单的配置信息,例如,默认欢迎语,登录用户名和密码等。其以键值对的方式存储,使得我们能很方便进行读取和存入。
     SharedPreference 文件保存在/data/data/<package name>/shared_prefs 路径下(如/data/data/com.android.alarmclock/shared_prefs/com.android.text_preferences.xml),通过cat命令可以查看文件,如:

     通过Activity自带的getSharedPreferences方法,可以得到SharedPreferences对象。
     public abstract SharedPreferences getSharedPreferences (String name, int mode);
     name:表示保存后 xml 文件的名称
     mode:表示 xml 文档的操作权限模式(私有,可读,可写),使用0或者MODE_PRIVATE作为默认的操作权限模式。 
     1.数据读取:
     通过SharedPreferences对象的键key可以获取到对应key的键值。对于不同类型的键值有不同的函数:getBoolean,getInt,getFloat,getLong.
     public abstract String getString (String key, String defValue);
     2.数据存入:
     数据的存入是通过SharedPreferences对象的编辑器对象Editor来实现的。通过编辑器函数设置键值,然后调用commit()提交设置,写入xml文件。
     public abstract SharedPreferences.Editor edit ();
     public abstract SharedPreferences.Editor putString (String key, String value);
     public abstract boolean commit ();

[xhtml] view plaincopy
  • <?xml version="1.0" encoding="utf-8"?>  
  • <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  •     android:orientation="vertical"  
  •     android:layout_width="fill_parent"  
  •     android:layout_height="fill_parent">  
  •       
  •     <TextView    
  •         android:id="@+id/textview"  
  •         android:layout_width="fill_parent"   
  •         android:layout_height="wrap_content"   
  •         android:text="@string/hello"/>  
  •       
  • </LinearLayout>  
  • [c-sharp] view plaincopy
  • package com.android.test;  
  • import android.app.Activity;  
  • import android.content.SharedPreferences;  
  • import android.os.Bundle;  
  • import android.preference.PreferenceManager;  
  • import android.widget.TextView;  
  • public class TestSharedPreferences extends Activity {  
  •     /** Called when the activity is first created. */  
  •     @Override  
  •     public void onCreate(Bundle savedInstanceState) {  
  •         super.onCreate(savedInstanceState);  
  •         setContentView(R.layout.main);  
  •           
  •         SharedPreferences mSharedPreferences = getSharedPreferences("TestSharedPreferences", 0);  
  • //        SharedPreferences mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);  
  •           
  •         int counter = mSharedPreferences.getInt("counter", 0);  
  •           
  •         TextView mTextView = (TextView)findViewById(R.id.textview);  
  •         mTextView.setText("This app has been started " + counter + " times.");  
  •           
  •         SharedPreferences.Editor mEditor = mSharedPreferences.edit();  
  •         mEditor.putInt("counter", ++counter);  
  •         mEditor.commit();  
  •           
  •     }  
  • }  
  • 说明:

  • SharedPreferences的获取有两种方法:一是上面提到的通过Activity自带(本质来讲是Context的)的getSharedPreferences方法,可以得到SharedPreferences对象。这种方法的好处是可以指定保存的xml文件名。另一种是通过PreferenceManager.getSharedPreferences(Context)获取SharedPreferences对象。这种方法不能指定保存的xml文件名,文件名使用默认的:<package name>+"_preferences.xml"的形式,不过如果在一个包里面采用这种方式需要保存多个这样的xml文件,可能会乱掉。建议采用第一种指定xml文件名的形式。
  • 数据的存入必须通过SharedPreferences对象的编辑器对象Editor来实现,存入(put)之后与写入数据库类似一定要commit。

  • 十三、自定义对话框的写法

    定义一个样式文件 重写了系统的一些默认配置

    name="android:windowBackground">@drawable/title_background

    name="android:windowNoTitle">true</item>

    十四.Md5的编码和加密 (不可逆的加密算法)

    package cn.itcast.mobilesafe.util;
    
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    public class MD5Encoder {
    
    	public static String encode(String pwd) {
    		try {
    			MessageDigest  digest = MessageDigest.getInstance("MD5");
    			byte[]  bytes = digest.digest(pwd.getBytes());
    			StringBuffer sb = new  StringBuffer();
    			for(int i = 0;i<bytes.length;i++){
    				String s = Integer.toHexString(0xff&bytes[i]);
    				
    				if(s.length()==1){
    					sb.append("0"+s);
    				}else{
    					sb.append(s);
    				}
    			}
    			
    			return sb.toString();
    		} catch (NoSuchAlgorithmException e) {
    			e.printStackTrace();
    			throw new RuntimeException("buhuifasheng");
    		}
    	}
    }


    十五.style的使用

    十六.更改activity切换的动画效果

    overridePendingTransition(R.anim.alpha_in,R.anim.alpha_out);

    Activity的切换动画指的是从一个activity跳转到另外一个activity时的动画。
    它包括两个部分:
    一部分是第一个activity退出时的动画;
    另外一部分时第二个activity进入时的动画;
    在Android的2.0版本之后,有了一个函数来帮我们实现这个动画。这个函数就是YoverridePendingTransition
    j这个函数有两个参数,一个参数是第一个activity退出时的动画,另外一个参数则是第二个activity进入时的动画。

    这里需要特别说明的是,关于overridePendingTransition这个函数,有两点需要主意

    1.它必需紧挨着startActivity()或者finish()函数之后调用"
    ````2.它只在android2.0以及以上版本上适用  

    常见的效果:

    淡入淡出效果

    overridePendingTransition(R.anim.fade, R.anim.hold);
    放大淡出效果
    overridePendingTransition(R.anim.my_scale_action,R.anim.my_alpha_action);
    转动淡出效果
    overridePendingTransition(R.anim.scale_rotate,R.anim.my_alpha_action);
    转动淡出效果
    overridePendingTransition(R.anim.scale_translate_rotate,R.anim.my_alpha_action);
    左上角展开淡出效果
    overridePendingTransition(R.anim.scale_translate,R.anim.my_alpha_action);
    压缩变小淡出效果
    overridePendingTransition(R.anim.hyperspace_in,R.anim.hyperspace_out);
    右往左推出效果
    overridePendingTransition(R.anim.push_left_in,R.anim.push_left_out);
    下往上推出效果
    overridePendingTransition(R.anim.push_up_in,R.anim.push_up_out);
    左右交错效果
    overridePendingTransition(R.anim.slide_left,R.anim.slide_right);
    放大淡出效果
    overridePendingTransition(R.anim.wave_scale,R.anim.my_alpha_action);
    缩小效果
    overridePendingTransition(R.anim.zoom_enter,R.anim.zoom_exit);
    上下交错效果
    overridePendingTransition(R.anim.slide_up_in,R.anim.slide_down_out); 

    十七.获取新打开的activity的返回值

    StartactivityforResult();

    SetResultData();

    OnActivityResult();

    十八.DeviceAdmin的技术 2.2版本支持 ->wipedata() setpwd();

    不能直接被卸载 在设备管理器里面取消激活

    十九 .checkbox的状态 状态变更的监听器

    二十、.gps 单态类 , gps wifi 基站

    获取系统服务LOCATION_SERVICE ->locationManager 

    记得把权限加到清单文件

    二十一 .广播接受者

    有序广播 ->1.一般的有序广播 abortbroadcast()  (-1000~1000)

    2.指定了接受者的有序广播setResult();

     

    无序的广播

    二十二. 短信内容的处理

    Object[] pdus = (Object[])intent.getExtras().get("pdus");

     


        
    最新技术文章:
    ▪Android开发之登录验证实例教程
    ▪Android开发之注册登录方法示例
    ▪Android获取手机SIM卡运营商信息的方法
    ▪Android实现将已发送的短信写入短信数据库的...
    ▪Android发送短信功能代码
    ▪Android根据电话号码获得联系人头像实例代码
    ▪Android中GPS定位的用法实例
    ▪Android实现退出时关闭所有Activity的方法
    ▪Android实现文件的分割和组装
    ▪Android录音应用实例教程
    ▪Android双击返回键退出程序的实现方法
    ▪Android实现侦听电池状态显示、电量及充电动...
    ▪Android获取当前已连接的wifi信号强度的方法
    ▪Android实现动态显示或隐藏密码输入框的内容
    ▪根据USER-AGENT判断手机类型并跳转到相应的app...
    ▪Android Touch事件分发过程详解
    ▪Android中实现为TextView添加多个可点击的文本
    ▪Android程序设计之AIDL实例详解
    ▪Android显式启动与隐式启动Activity的区别介绍
    ▪Android按钮单击事件的四种常用写法总结
    ▪Android消息处理机制Looper和Handler详解
    ▪Android实现Back功能代码片段总结
    ▪Android实用的代码片段 常用代码总结
    ▪Android实现弹出键盘的方法
    ▪Android中通过view方式获取当前Activity的屏幕截...
    ▪Android提高之自定义Menu(TabMenu)实现方法
    ▪Android提高之多方向抽屉实现方法
    ▪Android提高之MediaPlayer播放网络音频的实现方法...
    ▪Android提高之MediaPlayer播放网络视频的实现方法...
    ▪Android提高之手游转电视游戏的模拟操控
     


    站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3