win8 开发之旅(14) 飞机游戏制作揭秘

先看看这个游戏的类结构的介绍

类结构 

公共类层:

子弹帮助类、 BulletHepler,公共帮助类、 CommonHelper,图片帮助类、ImageHelper,精灵工厂类、SpriteFactory。

游戏元素层:

 公有元素有精灵类、Sprite,精灵实体类、ModelSprite,英雄实体类、HeroSprite,游戏结束类、GameOver;

旗下又包括了Bullet层,Daoju层,Effect层,Enemy层。

Bullet层有一个基类BulletSprite,子弹精灵类。其他是具体的实现类EnemyBulletSprite、敌人子弹类,HeroCircleBulletSprite、英雄圆形子弹类,HeroNomalBulletSprite、英雄普通子弹类,LightningBulletSprite、闪电子弹类。

Daoju层有一个基类Support,道具类。其他是具体的实现类AddLife、加血的道具,CircleBullet、球形子弹道具,Clear、清空道具,LightningBullet、闪电子弹道具,PelletBullent、球形子弹道具,

Bomb层有一个类Bomb,爆炸效果类。

Enemy层有一个基类BaseEnemy、敌人基类,其他是具体实现类FristBoss、大佬怪类,HelicopterEnemy、直升飞机怪物类,NomalEnemy、普通敌人类,UFOEnemy、UFO敌人类。

相应枚举部分:

EnemyType、敌人枚举类型,HeroState、英雄状态和英雄子弹的枚举,SupportType、道具枚举,UserKeyDir、用户方向枚举。

代码我已经发布,可见做这样一个win8游戏并不难。今天讲准备工作,也就是所需要的开发工具。代码编写调试:VS2012,美术工具:美图秀秀(http://xiuxiu.web.meitu.com)。这是最简陋的开发工具,但已足够。最好再有Photoshop,NotePad++或UltraEdit等等你喜欢的文本编辑工具。

 

游戏代码分两部分,公共部分,元素部分。先说公共部分:包括两个部分,帮助类部分和工厂类部分。帮助类主要是将一些主要的逻辑的,工具的源代码封装在3个不同的帮助类中(子弹帮助类、 BulletHepler,公共帮助类、 CommonHelper,图片帮助类、ImageHelper)。而工厂类部分主要是用于产生了各种各样的游戏元素。这样在游戏元素类的部分只需要调用这个层封装各种各样的方法,就能够完成一个游戏的组装。

公共层的3个帮助类是:

①游戏的基本帮助类——主要完成一些游戏主要逻辑的判断

/// <summary>
/// 基本的帮助类
/// 用于帮助游戏的逻辑的处理
/// </summary>
public class CommonHelper
{
/// 检测两个精灵是否发生了碰撞
public static bool CheckHit(Sprite.Sprite spriteOne, Sprite.Sprite spriteTwo);

//获取主页

public static MainPage GetMain();

/// 添加精灵岛canvas中差不多

public static void AddToGetMianCanvas(Sprite.Sprite sprite);

}

这是一个涉及游戏具体逻辑的类,它主要用用于①检测两个精灵是否发生了碰撞,②获取了主页的相应的信息,③把相应的游戏的每个元素添加到画布上,用于游戏渲染。 

我们这里是如何完成一个简单的碰撞的检测的了,这里等效于判断两个元素的坐标的距离是不是小于两个圆心直接的距离,小于就相交,反之,就不相交。用数学公式来表示:(x1-x2)²+(y1-y2)²<(r2+r1)².相应的源代码如下:

 

//检测的条件是(x1-x2)^2+(y1-y2)^2<(r1+r2)^2
if ((Math.Pow((spriteOne.X - spriteTwo.X), 2) + Math.Pow((spriteOne.Y - spriteTwo.Y), 2)) < Math.Pow((spriteOne.Radius + spriteTwo.Radius), 2))
{
return true;
}
//不碰撞就返回了假
return false;

那我们在看看是如何获取其运行的主页面的了,这里,本来在silverlight中用App.Current...可获取,但是,你要知道这在win8 app 中不支持。没辙,我们这里用了一个全局变量来传递mainpage ,相应源代码如下:

        return (MainPage.main as MainPage);

又怎么吧元素添加到画布中,我们上个方法中获取的主页 中有个公开的画布的属性,用add方法添加到画布中去是不是就可以了。相应的源代码如下:

 

//添加精灵
GetMain().sprites.Add(sprite);
//添加到子控件中
GetMain().appCanvas.Children.Add(sprite)

②照片的助手类——用于处理相应的图片的信息。

 

/// <summary>
/// 动画的帮助类
/// </summary>
public class ImageHelper

{

/// 对图片进行裁剪的方法  

public static List<WriteableBitmap> GetImageSplit(string imgpath, int count,Action<List<WriteableBitmap>> actions);

}

本来这个方法是基于WriteableBitmap这个类的Render方法进行大图片裁剪的,但是涉及win8微软可能从考虑提高显卡性能的关系,也罢这个类彻底的干掉了。我想到的方法,用

美图秀秀处理图片的方法。但是,我还是把源代码贴在这里,这针对普通的silverlight程序还是起效的。源代码如下:

 

Image img = new Image();
BitmapImage bitmap = new BitmapImage(new Uri(imgpath));
img.Source = bitmap;
img.ImageOpened += (sender, e) =>
{
for (int i = 0; i < count; i++)
{
int height = bitmap.PixelHeight;
int weight = bitmap.PixelWidth / count;
WriteableBitmap write = BitmapFactory.New(weight,height);
//write.r(img, new TranslateTransform() { X = weight * -1 * i, Y = 0 });
write.Invalidate();
bits.Add(write);
}
CommonHelper.GetMain().appCanvas.Children.Remove(img);
//eventhander(bits, null);

actions(bits);
};
CommonHelper.GetMain().appCanvas.Children.Add(img);

img.Visibility = Visibility.Collapsed;

return bits;

③BulletHelper——游戏子弹处理的逻辑类

public class BulletHepler
{
/// <summary>
/// 当前精灵的实体
/// </summary>
private ModelSprite model;
/// <summary>
/// 构造函数
/// 用于数据的初始化
/// </summary>
/// <param name="sprite"></param>
public BulletHepler(ModelSprite sprite);

/// <summary>
/// 英雄进行开火的方法
/// </summary>
public void HeroWork();

/// <summary>
/// 英雄的子弹开火的方法
/// </summary>
public void NormalEnemyWork();

构造函数传递是能发子弹实体的类,如敌人,英雄等等。进行当前信息的初始化。

说一说英雄发子弹的方法,这个进行开火的方法。判断英雄发子弹不同的类型,①一个是普通的类型,初始化为相应的x轴的速度,y轴的速度,初始化为x,y坐标。这样子就有普通子弹的类型。将他添加到页面上。还有②一个圆形子弹,就是循环给初始化普通的子弹添加到泛型数组中。③光球子弹,是以sin,cos形式发出的。源代码如下:

//普通的子弹
case SpriteBullet.Normal:
//英雄普通的子弹的类
HeroNomalBulletSprite herob = new HeroNomalBulletSprite();
//x坐标等于传进来的对象x坐标
herob.X = model.X+30;
//y坐标等于传进来的对象的y坐标

herob.Y = model.Y;
//x上的速度等于0
herob.Vx = 0;
//y上的速度等于-3
herob.Vy = -3;
//添加到页面上
CommonHelper.AddToGetMianCanvas(herob);

break;
//球形的子弹的类型
case SpriteBullet.Pellet:
//循环的添加
for (int i = -1; i < 2; i++)
{
//英雄的普通子弹的类型
HeroNomalBulletSprite herox = new HeroNomalBulletSprite();
//x坐标等于传进来的对象的x坐标
herox.X = model.X+30;
//y坐标等于传进来的对象的y坐标
herox.Y = model.Y;
//其速度等于一个I值
herox.Vx = i;
//其y的速度等于一个-3的值
herox.Vy = -3;
//添加到页面上
CommonHelper.AddToGetMianCanvas(herox);
}
break;
//圆形子弹的类型
case SpriteBullet.Circle:
//x坐标
double x = 0;
//只要小于二分支π
while (!(x > Math.PI * 2))
{
//英雄的圆圈的对象
HeroCircleBulletSprite herox = new HeroCircleBulletSprite();
//x坐标
herox.X = model.X+30;
//y坐标
herox.Y = model.Y;
//x方向上的速度
herox.Vx = Math.Sin(x) * 3;
//y方向上的速度
herox.Vy = Math.Cos(x) * 3;
//添加到页面上
CommonHelper.AddToGetMianCanvas(herox);
//x累加
x += 2 * Math.PI / 5;
}
break;
//光子弹的
case SpriteBullet.Lightning:
//光子弹
LightningBulletSprite big = new LightningBulletSprite();
//光子弹的x坐标等于传进来的对象的x坐标的值
big.X = model.X;
//y坐标的值等于传进来y的值减高度
big.Y = model.Y - big.SpriteHeight;
//x坐标等于0
big.Vx = 0;
//y坐标等于-3
big.Vy = -3;
//添加到控件上
CommonHelper.AddToGetMianCanvas(big);
break;

而 敌人的子弹开火的方法,与英雄的子弹发出的方法一样的。此处略去n个字。

3个帮助类,说完了。说一说精灵的工厂类,这个精灵工厂类,与传统的工厂类是一模一样。就是传递给不同参数,产生了不同精灵的对象。再初始化相应的x,y坐标,x轴速度,y轴速度。代码如下:

public class SpriteFactory
{

/// <summary>
/// 创建老怪
/// </summary>
/// <param name="enemyType">老怪的类型</param>
/// <returns></returns>
public static BaseEnemy CreateEnemy(EnemyType enemyType)
{
///随机函数
Random rd = new Random(DateTime.Now.Millisecond);
//基本敌人的对象
BaseEnemy enemy = null;
//创建不同的敌人的对象
switch (enemyType)
{
//直升飞机的敌人
case EnemyType.Helicopter:
enemy = new HelicopterEnemy();
break;
//普通的敌人
case EnemyType.Normal:
enemy = new NomalEnemy();
break;
//ufo敌人
case EnemyType.UFO:
enemy = new UFOEnemy();
break;
}
//敌人的x坐标
enemy.X = (rd.Next(0, 800 - enemy.Radius));
//敌人的y坐标
enemy.Y = -enemy.Radius;
//敌人的x轴上的速度
enemy.Vx = 0;
//敌人的y轴上的速度
enemy.Vy = 3;
//返回建造的enemy的对象
return enemy;
}
//参加相应的道具对象
public static Support CreateSupport(SupportType supportType)
{
//随机函数
Random rd = new Random(DateTime.Now.Millisecond);
//道具对象
Support support = null;
//创建不同的道具的对象
switch (supportType)
{
//加血的道具
case SupportType.AddLife:
support=new AddLife();
break;
//原性子弹的道具
case SupportType.CircleBullet:
support = new CircleBullet();
break;
//球星子弹的道具
case SupportType.PelletBullet:
support = new PelletBullet();
break;
//广石化的道具
case SupportType.Lightning:
support = new LightningBullet();
break;
//晴空的道
case SupportType.Clear:
support = new Clear();
break;
}

//x的坐标
support.X = (rd.Next(0, 800 - support.Radius));
//y的坐标
support.Y = -support.Radius;
//x的速度
support.Vx = rd.Next(0, 10);
//y的速度
support.Vy = 3;
//返回道具的对象
return support;
}

//创建了大老怪
public static FristBoss CreateBoss()
{
//随机函数
Random rd = new Random(DateTime.Now.Millisecond);
//的老怪的对象
FristBoss boss = new FristBoss();
//x的坐标
boss.X = (rd.Next(0, 800 - boss.Radius));
//y的坐标
boss.Y = -boss.Radius;
//返回了大老怪的对象
return boss;
}

}

上述的这些源代码是只是一个公共层的类概述和源代码简介。

说一说游戏元素层,这些层的是产生游戏核心元素——游戏元素的类。

这些游戏的类由于好多源代码和思路是大同小异的,这里只需要讲明白3个类。一个是所有这些类的基类——sprite,一个能活动的游戏元素的基类——Modelsprite,一个子弹的类。

①sprite类——这个类是所有的游戏元素的基类,它定义了这些游戏元素公有的属性,方法。他的结构如下:

public abstract class Sprite : Canvas
{
/// <summary>
/// x的坐标 进行精灵的x坐标定位
/// </summary>
public double X

/// <summary>
/// y的坐标 进行精灵的y坐标定位
/// </summary>
public double Y

/// <summary>
/// x方向上的速度
/// </summary>
public double Vx { get; set; }
/// <summary>
/// y方向上的速度
/// </summary>
public double Vy { get; set; }
/// <summary>
/// 他所经过的半径区域
/// </summary>
public int Radius;
/// <summary>
/// 相应精灵的图片
/// </summary>
public Image SpriteImg;
/// <summary>
/// 精灵的宽度
/// </summary>
private int spriteWidth;
/// <summary>
/// 精灵的高度
/// </summary>
private int spriteHeight;


/// <summary>
/// 构造函数
/// </summary>
public Sprite();

/// <summary>
/// 移去相应的元素
/// </summary>
public virtual void Remove();

/// <summary>
/// 进行了更新的操作
/// </summary>
public abstract void Update();

}

通过这样结构,我们可以知道他有x,y坐标,vx,vy的属性 这些都是用于定位于使飞机移动下来所必备的属性。而Image属性,是这些类背景图片又是哪一张。至于Remove操作,是使某个元素消亡以后,他从界面上移去的方法。至于说到所谓的更新操作,这个使飞机位于不同的位置。其中源代码如下:

public abstract class Sprite : Canvas
{
/// <summary>
/// x的坐标 进行精灵的x定位
/// </summary>
public double X
{

get { return Canvas.GetLeft(this); }
set { Canvas.SetLeft(this, value); }
}
/// <summary>
/// y的坐标 进行精灵的y定位
/// </summary>
public double Y
{
get { return Canvas.GetTop(this); }
set { Canvas.SetTop(this, value); }
}
/// <summary>
/// x方向上的速度
/// </summary>
public double Vx { get; set; }
/// <summary>
/// y方向上的速度
/// </summary>
public double Vy { get; set; }
/// <summary>
/// 他所经过的半径区域
/// </summary>
public int Radius;
/// <summary>
/// 相应精灵的图片
/// </summary>
public Image SpriteImg;
/// <summary>
/// 精灵的宽度
/// </summary>
private int spriteWidth;
/// <summary>
/// 精灵的高度
/// </summary>
private int spriteHeight;
/// <summary>
/// 精灵的宽度
/// </summary>
public int SpriteWidth
{
get { return spriteWidth; }
set
{
spriteWidth = value;
SpriteImg.Width = value;
Canvas.SetLeft(SpriteImg,value/2-1);
}
}
/// <summary>
/// 精灵的高度
/// </summary>
public int SpriteHeight
{
get { return spriteHeight; }
set
{
spriteHeight = value;
SpriteImg.Height = value;
Canvas.SetTop(SpriteImg,value/2-1);
}
}
/// <summary>
/// 构造函数
/// </summary>
public Sprite()
{
SpriteImg = new Image();
this.Children.Add(SpriteImg);
}
/// <summary>
/// 移去相应的元素
/// </summary>
public virtual void Remove()
{
//canvas的对象
Canvas canva = CommonHelper.GetMain().appCanvas;
if (canva.Children.Contains(this))
{
//移去对象
(this.Parent as Canvas).Children.Remove(this);

}
//包含相应的对象
if (CommonHelper.GetMain().sprites.Contains(this))
{
//移去对象
CommonHelper.GetMain().sprites.Remove(this);
}
}
/// <summary>
/// 进行了更新的操作
/// </summary>
public abstract void Update();
}

②ModelSprite——基本的神灵的基本类,这是所有的英雄精灵类,各种各样的敌人精灵类都继承与他。他的架构如下:

/// <summary>
///基本的精灵的类
/// </summary>
public class ModelSprite : Sprite
{
/// <summary>
/// 最大的生命值
/// </summary>
private int maxlife;
/// <summary>
/// 最大的速度
/// </summary>
public int speed = 5;
/// <summary>
/// 最大的生命值(属性)
/// </summary>
public int MaxLife
{
//只读
get { return maxlife; }
//属性
set
{
maxlife = value;
}
}
/// <summary>
/// 精灵的子弹(属性)
/// </summary>
public SpriteBullet Bullet { get; set; }
/// <summary>
/// 精灵的更新状态(属性)
/// </summary>
public SpriteState State { get; set; }

/// <summary>
/// 进行更新的操作
/// </summary>
public override void Update()
/// <summary>

/// 构造函数 进行了初始化的工作

/// </summary>
public ModelSprite();

}

他包括这个最大生命值,最大运行的速度这些属性,update方法, 判断这个精灵生命值是不是小于0,就将他从界面上移去,并且把的坐标改变。

③BulletSprite——子弹的精灵基类,所有子弹继承与他。这包含了一个DPS——每秒钟刷新的频率。   他继承与精灵类。

后记

程序,乐趣无穷。在一篇文不加点情况下,一篇win8的飞机游戏介绍文章诞生了。

源码位置:http://51aspx.com/Code/Win8Fly

原文地址:https://www.cnblogs.com/manuosex/p/2743316.html