C++代码训练之坦克大战(2)

这一篇中,我们继续继续进行我们的坦克大战。

位置信息数据结构

在游戏设计过程中,需要记录大量的位置信息,如果仅仅使用(x,y)坐标很容易出错。这一篇中,我们先定义两个简单的数据结构用来保存点和矩形的信息。

在项目中新建Model目录,创建下面四个文件:

代码如下:

Point.h

#ifndef __POINT_H__
#define __POINT_H__

class Point
{
public:
    Point(int x = 0, int y = 0) : m_x(x), m_y(y){};
    ~Point(){};

    Point& operator=(const Point &p)
    {
        m_x = p.m_x;
        m_y = p.m_y;

        return *this;
    }

    void Set(int x, int y);

    void SetX(int x);
    void SetY(int y);

    int GetX();
    int GetY();

private:
    int m_x;
    int m_y;
};

#endif

这个头文件创建了一个Point类,有两个成员变量m_x,m_y用来记录一个点的横、纵坐标。一组public方法用来完成给对象赋值和读取坐标值的操作。

这里我们用到了C++的运算符重载功能,将“=”功能进行重载,方便我们用一个Point对象给另一个Point对象赋值,同时也能够使我们将Point作为参数进行传递。

Point.cpp

#include "Point.h"

void Point::Set(int x, int y)
{
    m_x = x;
    m_y = y;
}

void Point::SetX(int x)
{
    m_x = x;
}

void Point::SetY(int y)
{
    m_y = y;
}

int Point::GetX()
{
    return m_x;
}

int Point::GetY()
{
    return m_y;
}

这个文件中是对Point类的实现,大家一看就明白。

这里需要强调的是,在类的封装过程中有一个非常重要的原则是不允许将成员变量用public的方法暴露在外。如果类的外部代码能够直接对类成员变量进行修改的话,程序将很不安全。正确的方法是像我们这样实现一组Get和Set方法进行管理。这样虽然代码量多了一些,但对后期维护带来的帮助是不可估量的。

Rect.h

#ifndef __RECTANGLE_H__
#define __RECTANGLE_H__

#include "Point.h"

class Rect
{
public:
    Rect(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0) : m_startPoint(x1, y1), m_endPoint(x2, y2){};
    Rect(const Point p1, const Point p2) : m_startPoint(p1), m_endPoint(p2){};
    ~Rect(){};

    Rect& operator=(const Rect &rect)
    {
        m_startPoint = rect.GetStartPoint();
        m_endPoint = rect.GetEndPoint();

        return *this;
    }

    void Set(const Point pStart, const Point pEnd);
    void Set(int x1, int y1, int x2, int y2);

    void SetStartPoint(const Point p);
    void SetEndPoint(const Point p);

    Point GetStartPoint() const;
    Point GetEndPoint() const;

    int GetWidth();
    int GetHeight();

private:
    void Check();

    Point m_startPoint;
    Point m_endPoint;
};

#endif

Rect类是用来定义矩形的,它的成员变量是两个Point对象,分别表示矩形的左上角和右下角。这里我们强行规定m_startPoint表示左上角,m_endPoint表示右下角。如果创建对象时两个点顺序反了,Check()函数会自动把它们调整过来。

这里需要注意,GetStartPoint()和GetEndPoint()两个函数都通过const修饰,表示返回值不能被修改。为什么要这么实现呢,因为这个函数的结果将会传进EasyX接口中,而这些接口大部分都要求参数是const的,如果这里不做修饰,在传参时会报错。

Rect.cpp

#include "Rect.h"

void Rect::Set(Point pStart, Point pEnd)
{
    m_startPoint = pStart;
    m_endPoint = pEnd;
}

void Rect::Set(int x1, int y1, int x2, int y2)
{
    m_startPoint.Set(x1, y1);
    m_endPoint.Set(x2, y2);
}

void Rect::SetStartPoint(Point p)
{
    m_startPoint = p;
}

void Rect::SetEndPoint(Point p)
{
    m_endPoint = p;
}

Point Rect::GetStartPoint() const
{
    return m_startPoint;
}

Point Rect::GetEndPoint() const
{
    return m_endPoint;
}

int Rect::GetWidth()
{
    return m_endPoint.GetX() - m_startPoint.GetX();
}

int Rect::GetHeight()
{
    return m_endPoint.GetY() - m_startPoint.GetY();
}    

void Rect::Check()
{
    if (m_startPoint.GetX() > m_endPoint.GetX() || m_startPoint.GetY() > m_endPoint.GetY())
    {
        Point p = m_startPoint;
        m_startPoint = m_endPoint;
        m_endPoint = p;
    }
}

这个文件中实现了Rect类的成员函数。

主战坦克升级

Tank.h

首先,我们对Tank类进行修改,新增一部分功能,代码如下:

#ifndef __TANK_H__
#define __TANK_H__

#include "Graphic.h"

enum Dir { UP, DOWN, LEFT, RIGHT };

class Tank
{
public:
    // 绘图
    virtual void Display() = 0;

    // 移动
    virtual void Move() = 0;

protected:
    virtual void CalculateSphere() = 0;

    Point m_pos;
    Rect m_rectSphere; // 势力范围

    COLORREF m_color;

    Dir m_dir;

    int m_step;
};

#endif

我们把坐标用Point对象m_pos表示,又添加了一个新属性m_rectSphere,它是一个Rect对象,用来记录坦克的形状范围。之前我们的坦克总是用一组坐标来表示,这个坐标是坦克的中心点,所有跟坦克相关的行为都通过这个点来计算位置,实现起来有些复杂,有了这个Rect对象,相当于我们记录了这个坦克所在的矩形的位置,这样在绘制坦克时更容易计算坐标。

MainTank.h

#ifndef __MAIN_TANK__
#define __MAIN_TANK__

#include "Tank.h"

class MainTank : public Tank
{
public:
    MainTank()
    {
        m_pos.Set(300, 300);

        this->CalculateSphere();

        m_color = YELLOW;
        m_dir = Dir::UP;
        m_step = 2;
    }

    ~MainTank(){}

    // 设置行驶方向
    void SetDir(Dir dir);
    void Display();
    void Move();

protected:
    void CalculateSphere();

    // 绘制坦克主体
    void DrawTankBody();
};

#endif

这个文件中没有太大的修改,只是在成员变量初始化时做了一些调整。主战坦克的颜色改成了黄色,初始化后调用CalculateSphere()函数计算出矩形位置。

MainTank.cpp

#include "MainTank.h"

void MainTank::SetDir(Dir dir)
{
    m_dir = dir;
}

void MainTank::DrawTankBody()
{
    fillrectangle(m_pos.GetX() - 6, m_pos.GetY() - 6, m_pos.GetX() + 6, m_pos.GetY() + 6);

    switch (m_dir)
    {
    case UP:
    case DOWN:
        fillrectangle(m_rectSphere.GetStartPoint().GetX(), m_rectSphere.GetStartPoint().GetY(),
            m_rectSphere.GetStartPoint().GetX() + 4, m_rectSphere.GetEndPoint().GetY());
        fillrectangle(m_rectSphere.GetEndPoint().GetX() - 4, m_rectSphere.GetStartPoint().GetY(),
            m_rectSphere.GetEndPoint().GetX(), m_rectSphere.GetEndPoint().GetY());
        break;
    case LEFT:
    case RIGHT:
        fillrectangle(m_rectSphere.GetStartPoint().GetX(), m_rectSphere.GetStartPoint().GetY(),
            m_rectSphere.GetEndPoint().GetX(), m_rectSphere.GetStartPoint().GetY() + 4);
        fillrectangle(m_rectSphere.GetStartPoint().GetX(), m_rectSphere.GetEndPoint().GetY() - 4,
            m_rectSphere.GetEndPoint().GetX(), m_rectSphere.GetEndPoint().GetY());
        break;
    default:
        break;
    }
}

void MainTank::Display()
{
    COLORREF fill_color_save = getfillcolor();
    COLORREF color_save = getcolor();

    setfillcolor(m_color);
    setcolor(m_color);

    DrawTankBody();

    switch (m_dir)
    {
    case UP:
        line(m_pos.GetX(), m_pos.GetY(), m_pos.GetX(), m_pos.GetY() - 15);
        break;
    case DOWN:
        line(m_pos.GetX(), m_pos.GetY(), m_pos.GetX(), m_pos.GetY() + 15);
        break;
    case LEFT:
        line(m_pos.GetX(), m_pos.GetY(), m_pos.GetX() - 15, m_pos.GetY());
        break;
    case RIGHT:
        line(m_pos.GetX(), m_pos.GetY(), m_pos.GetX() + 15, m_pos.GetY());
        break;
    default:
        break;
    }

    setcolor(color_save);
    setfillcolor(fill_color_save);
}

void MainTank::Move()
{
    switch (m_dir)
    {
    case UP:
        m_pos.SetY(m_pos.GetY() - m_step);
        if (m_pos.GetY() < Graphic::GetBattleGround().GetStartPoint().GetY())
            m_pos.SetY(Graphic::GetBattleGround().GetEndPoint().GetY() - 1);
        break;
    case DOWN:
        m_pos.SetY(m_pos.GetY() + m_step);
        if (m_pos.GetY() > Graphic::GetBattleGround().GetEndPoint().GetY())
            m_pos.SetY(Graphic::GetBattleGround().GetStartPoint().GetY() + 1);
        break;
    case LEFT:
        m_pos.SetX(m_pos.GetX() - m_step);
        if (m_pos.GetX() < Graphic::GetBattleGround().GetStartPoint().GetX())
            m_pos.SetX(Graphic::GetBattleGround().GetEndPoint().GetX() - 1);
        break;
    case RIGHT:
        m_pos.SetX(m_pos.GetX() + m_step);
        if (m_pos.GetX() > Graphic::GetBattleGround().GetEndPoint().GetX())
            m_pos.SetX(Graphic::GetBattleGround().GetStartPoint().GetX() + 1);
        break;
    default:
        break;
    }

    CalculateSphere();
}

void MainTank::CalculateSphere()
{
    switch (m_dir)
    {
    case UP:
    case DOWN:
        m_rectSphere.Set(m_pos.GetX() - 13, m_pos.GetY() - 10, m_pos.GetX() + 13, m_pos.GetY() + 10);
        break;
    case LEFT:
    case RIGHT:
        m_rectSphere.Set(m_pos.GetX() - 10, m_pos.GetY() - 13, m_pos.GetX() + 10, m_pos.GetY() + 13);
        break;
    default:
        break;
    }
}

这个文件修改较多,是不是有些眼花缭乱了。

  • DrawTankBody()

这个函数的参数被拿掉了,在这里我们通过坦克当前方向来判断它的形状。

在绘制履带时,我们利用了m_rectSphere的位置坐标,虽然看起来代码变多了,但只有一个数字4是无意义的,它代表履带的宽度。如果这个宽度需要经常调整的话,我们还可以考虑把它用一个成员变量管理起来。

在判断坦克形状时,我们利用了switch的一个特性,通过故意少写break关键字,让两个判断结果公用一段代码,这个早已经讲过,这里不多说了。

  • Display()

之前我们用setfillcolor设置了填充颜色,这里我们加入了setcolor,这样画出来的坦克边框也是我们设置的颜色。

  • Move()

这个函数中,比较奇怪的是出现了一个没见过的函数Graphic::GetBattleGround()。我们今天要给坦克划定一个运行区域,不能让它满屏幕行驶了,这个后面再说。

这里要注意,每移动一次都需要调用CalculateSphere()方法重新计算坦克区域。

  • CalculateSphere()

这个很简单,计算出左上角和右下角的Point位置即可。

更新画布

之前的画布颜色太深,我们要做修改。另外,我们后面需要在窗口上显示游戏信息,因此,要在右边留出一部分空间。我们给坦克划定一个新的区域,让它们在里面行驶。

Graphic.h

#ifndef __GRAPHIC_H__
#define __GRAPHIC_H__

#include <graphics.h>

#include "model/Rect.h"

#define SCREEN_WIDTH    1024
#define SCREEN_HEIGHT    768

#define BATTLE_GROUND_X1 5
#define BATTLE_GROUND_Y1 5
#define BATTLE_GROUND_X2 800
#define BATTLE_GROUND_Y2 (SCREEN_HEIGHT - BATTLE_GROUND_Y1)

class Graphic
{
public:
    static void Create();
    static void Destroy();

    static void DrawBattleGround();

    static int GetScreenWidth();
    static int GetScreenHeight();

    static Rect GetBattleGround();

private:
    static Rect m_rectScreen;
    static Rect m_rectBattleGround;
};

#endif

文件中通过一组宏来定义战场区域的位置。另外通过m_rectBattleGround这个Rect对象来保存。

细心的读者应该发现了,我们在引用Rect类时用了下面这句话:

#include "model/Rect.h"

Rect.h文件的路径需要加上model目录,否则找不到。需要说明的是这个目录指的是项目文件夹下真实存在的model目录。如果你用的是VS,"Solution Explorer"中新建的文件夹是逻辑目录,不需要加载include路径中。

简单说,include后面写的路径是给编译器看的,它只认Windows资源管理器中看到的路径,与IDE中的逻辑路径无关。

Graphic.cpp

#include "Graphic.h"

Rect Graphic::m_rectScreen;
Rect Graphic::m_rectBattleGround;

void Graphic::Create()
{
    m_rectScreen.Set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    initgraph(SCREEN_WIDTH, SCREEN_WIDTH);
    setbkcolor(DARKGRAY);

    m_rectBattleGround.Set(BATTLE_GROUND_X1, BATTLE_GROUND_Y1, BATTLE_GROUND_X2, BATTLE_GROUND_Y2);
}

void Graphic::Destroy()
{
    closegraph();
}

void Graphic::DrawBattleGround()
{
    rectangle(m_rectBattleGround.GetStartPoint().GetX(), m_rectBattleGround.GetStartPoint().GetY(),
        m_rectBattleGround.GetEndPoint().GetX(), m_rectBattleGround.GetEndPoint().GetY());
}

int Graphic::GetScreenWidth()
{
    return SCREEN_WIDTH;
}

int Graphic::GetScreenHeight()
{
    return SCREEN_HEIGHT;
}

Rect Graphic::GetBattleGround()
{
    return m_rectBattleGround;
}

代码在创建画布是,重新指定了背景颜色。DrawBattleGround()函数在屏幕上画出了战场的范围。

main.cpp

主函数中,我们只需要再循环中添加一个DrawBattleGround函数的调用即可。

if (!skip)
{
    cleardevice();

    Graphic::DrawBattleGround();

    mainTank.Move();
    mainTank.Display();
}

好了,运行一下程序,看看效果吧。

敌人坦克

屏幕上只有一个自己的坦克看着有些孤单,我们再添加上些敌人的坦克。

新建文件EnemyTank.h和EnemyTank.cpp。实现一个敌人坦克类。

EnemyTank.h

#ifndef __ENEMY_TANK__
#define __ENEMY_TANK__

#include "Tank.h"

class EnemyTank : public Tank
{
public:
    EnemyTank()
    {
        RandomTank();
    }

    ~EnemyTank(){}

    void Display();
    void Move();

protected:
    void CalculateSphere();
    void RandomTank();
};

#endif

有了Tank这个抽象类,所有的坦克都从它继承就好了。除了抽象类中继承的函数之外,我们加了一个RandomTank()用来随机地在战场区域生成一个坦克。

EnemyTank.cpp

#include "EnemyTank.h"

void EnemyTank::RandomTank()
{
    m_pos.SetX(rand() % Graphic::GetBattleGround().GetWidth());
    m_pos.SetY(rand() % Graphic::GetBattleGround().GetHeight());
    m_color = WHITE;
    m_dir = (Dir)(Dir::UP + (rand() % 4));
    m_step = 2;
}

void EnemyTank::Display()
{
    COLORREF fill_color_save = getfillcolor();
    COLORREF color_save = getcolor();

    setfillcolor(m_color);
    setcolor(m_color);

    fillrectangle(m_pos.GetX() - 6, m_pos.GetY() - 6, m_pos.GetX() + 6, m_pos.GetY() + 6);

    fillrectangle(m_rectSphere.GetStartPoint().GetX(), m_rectSphere.GetStartPoint().GetY(),
        m_rectSphere.GetStartPoint().GetX() + 4, m_rectSphere.GetStartPoint().GetY() + 4);
    fillrectangle(m_rectSphere.GetEndPoint().GetX() - 4, m_rectSphere.GetStartPoint().GetY(),
        m_rectSphere.GetEndPoint().GetX(), m_rectSphere.GetStartPoint().GetY() + 4);

    fillrectangle(m_rectSphere.GetStartPoint().GetX(), m_rectSphere.GetEndPoint().GetY() - 4,
        m_rectSphere.GetStartPoint().GetX() + 4, m_rectSphere.GetEndPoint().GetY());
    fillrectangle(m_rectSphere.GetEndPoint().GetX() - 4, m_rectSphere.GetEndPoint().GetY() - 4,
        m_rectSphere.GetEndPoint().GetX(), m_rectSphere.GetEndPoint().GetY());

    switch (m_dir)
    {
    case UP:
        line(m_pos.GetX(), m_pos.GetY(), m_pos.GetX(), m_pos.GetY() - 15);
        break;
    case DOWN:
        line(m_pos.GetX(), m_pos.GetY(), m_pos.GetX(), m_pos.GetY() + 15);
        break;
    case LEFT:
        line(m_pos.GetX(), m_pos.GetY(), m_pos.GetX() - 15, m_pos.GetY());
        break;
    case RIGHT:
        line(m_pos.GetX(), m_pos.GetY(), m_pos.GetX() + 15, m_pos.GetY());
        break;
    default:
        break;
    }

    setcolor(color_save);
    setfillcolor(fill_color_save);
}

void EnemyTank::Move()
{
    switch (m_dir)
    {
    case UP:
        m_pos.SetY(m_pos.GetY() - m_step);
        if (m_pos.GetY() < Graphic::GetBattleGround().GetStartPoint().GetY())
            m_pos.SetY(Graphic::GetBattleGround().GetEndPoint().GetY() - 1);
        break;
    case DOWN:
        m_pos.SetY(m_pos.GetY() + m_step);
        if (m_pos.GetY() > Graphic::GetBattleGround().GetEndPoint().GetY())
            m_pos.SetY(Graphic::GetBattleGround().GetStartPoint().GetY() + 1);
        break;
    case LEFT:
        m_pos.SetX(m_pos.GetX() - m_step);
        if (m_pos.GetX() < Graphic::GetBattleGround().GetStartPoint().GetX())
            m_pos.SetX(Graphic::GetBattleGround().GetEndPoint().GetX() - 1);
        break;
    case RIGHT:
        m_pos.SetX(m_pos.GetX() + m_step);
        if (m_pos.GetX() > Graphic::GetBattleGround().GetEndPoint().GetX())
            m_pos.SetX(Graphic::GetBattleGround().GetStartPoint().GetX() + 1);
        break;
    default:
        break;
    }

    CalculateSphere();
}

void EnemyTank::CalculateSphere()
{
    switch (m_dir)
    {
    case UP:
    case DOWN:
        m_rectSphere.Set(m_pos.GetX() - 13, m_pos.GetY() - 10, m_pos.GetX() + 13, m_pos.GetY() + 10);
        break;
    case LEFT:
    case RIGHT:
        m_rectSphere.Set(m_pos.GetX() - 10, m_pos.GetY() - 13, m_pos.GetX() + 10, m_pos.GetY() + 13);
        break;
    default:
        break;
    }
}

这个文件实在没什么可讲的,基本都用的之前提到的方法。随机生成坦克用到了星空中随机产生星星的方法,相信大家都能看懂。

main.cpp

最后是main函数,代码如下:

#define MAX_TANKS 10

void main()
{
    srand((unsigned)time(NULL));

    Graphic::Create();

    MainTank mainTank;

    Tank* pTank[MAX_TANKS];

    for (int i = 0; i < MAX_TANKS; i++)
    {
        pTank[i] = new EnemyTank();
    }

    bool loop = true;
    bool skip = false;
    while (loop)
    {
        if (kbhit())
        {
            int key = getch();

            switch (key)
            {
            // Up
            case 72:
                mainTank.SetDir(Dir::UP);
                break;
            // Down
            case 80:
                mainTank.SetDir(Dir::DOWN);
                break;
            // Left
            case 75:
                mainTank.SetDir(Dir::LEFT);
                break;
            // Right
            case 77:
                mainTank.SetDir(Dir::RIGHT);
                break;
            case 224: // 方向键高8位
                break;
            // Esc
            case 27:
                loop = false;
                break;
            // Space
            case 32:
                break;
            // Enter
            case 13:
                if (skip)
                    skip = false;
                else
                    skip = true;
                break;
            default:
                break;
            }
        }

        if (!skip)
        {
            cleardevice();

            Graphic::DrawBattleGround();

            mainTank.Move();
            mainTank.Display();

            for (int i = 0; i < MAX_TANKS; i++)
            {
                pTank[i]->Move();
                pTank[i]->Display();
            }
        }

        Sleep(200);
    }

    for (int i = 0; i < MAX_TANKS; i++)
    {
        delete pTank[i];
    }

    Graphic::Destroy();
}

与之前相比,添加了下面这几个内容:

  • 新建了一个宏MAX_TANKS用来设置坦克的数量
  • 用一个指针数组保存每个坦克的指针
  • 循环创建坦克,这里用了new的方法把坦克对象创建在堆空间中
  • 每次擦屏之后,遍历指针数组,绘制出每个坦克。调用的是Move()和Display()方法。
  • 退出程序前,释放每一个坦克所占的堆空间。

注意:C++中依然是new和delete成对出现,有申请就要有释放。否则会出现内存泄露。

下面运行一下代码,看看我们今天的成果。

是不是一下热闹了很多呢?

学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入学习交流群
639368839,我们一起学C/C++!

时间: 2024-11-11 07:45:27

C++代码训练之坦克大战(2)的相关文章

坦克大战中的坦克

临近期末考试,给大家整一个轻松一些的代码 做个坦克大战中的坦克 当然要想做成小游戏还是要努努力呀~ 祝大家考个好成绩 import java.awt.Color;import java.awt.Font;import java.awt.Frame;import java.awt.Graphics;import java.awt.event.KeyEvent;import java.awt.event.KeyListener; import javax.swing.JFrame;import ja

C++代码之坦克大战(1)

对坦克大战情有独钟是因为大学时候第一次参加程序设计比赛就做的这个游戏.当时用的语言是Java,那个比赛让我悟出了面向对象的强大之处,我也是从那时开始接触设计模式的.对我而言,坦克大战有着非同寻常的意义,所以一定要带大家用C++实现一下. 坦克大战 我们依然使用EasyX在控制台程序中制作这个游戏程序.这一篇的主要任务是在屏幕上画出一个白色的主战坦克,可以通过方向键控制它的前进方向.效果如下: 下面我们正式开始. 画布类 在这个工程中,我们将EasyX画布相关的功能封装在一个Graphic类中,创

坦克大战(版本2.5-版本2.9)

版本2.5 功能:添加“血块”步骤:        1)添加blood类        2)添加必要的方法:eat方法等        3)让blood对象固定轨迹运动, 并在一定时间后消失 具体代码实现: 新增的blood类: 1 import java.awt.Color; 2 import java.awt.Graphics; 3 import java.awt.Rectangle; 4 5 //模拟血块,坦克吃了可以补血 6 public class Blood { 7 int x, y

脚本游戏之四: 坦克大战源码注释(待续。。。)

要点: 1.echo的高级用法,主要包括:颜色.位置定位输出等 2.trap 信号捕捉, kill 发送信号 3.捕捉用户输入,控制后台进程 参考:坦克大战 文章结尾的几段代码 总体: 多个进程后台并行运行, 前端一个段接受用户输入的代码,根据用户输入通过发送信号控制后台进程. 几乎每一个组件都是一个后台运行的函数. #!/bin/bash # BY: LingYi # DATE: 2016.02.23 #place temporary files tmpdir='/tmp' #u:up d:d

Java__线程---基础知识全面实战---坦克大战系列为例

今天想将自己去年自己编写的坦克大战的代码与大家分享一下,主要面向学习过java但对java运用并不是很熟悉的同学,该编程代码基本上涉及了java基础知识的各个方面,大家可以通过练习该程序对自己的java进行一下实战. 每个程序版本代码中,都附有相关注释,看完注释大家就可以对本程序设计有个很明显的思路.真的很有趣,想对java重新温习的同学完全不必再对厚厚的java基础书籍进行阅读了,在跟着本次代码练习并分析后,大家一定会对java各方面基础知识 尤其是线程的知识有更深一步的了解!!! 本次坦克大

【跟我一起学Unity3D】做一个2D的90坦克大战之地图编辑器

从10月20号到现在,Unity3D也学了10天了,对于Unity3D也有了一个大致的了解,有必要做一个小游戏来检测一下自己的学习成果了.经过两天的努力,终于总算是做出来了一个可以玩的坦克大战了.首先讲讲我的设计目标: 1.地图编辑器 2.道具系统 3.简单AI系统 4.计分器 其中,最重要的就是地图编辑器了,其次到AI系统,其他几个都挺简单的. ---------------------------------------------------------------------------

Java坦克大战游戏源代码

转载自: http://blog.csdn.net/java_cxrs/article/details/3860870 经过几天的练习和研究终于自己能写出坦克大战游戏了,写完这个程序后感觉收获了很多东西,对JAVA的知识又有了一定的增长,接下来还准备继续写几个小项目来练习J2SE 由于代码太长就不发在博客里了,我上传到了资源下载里,有需要的朋友大家可以去下载 下载地址:http://download.csdn.net/source/988654

H5坦克大战之【玩家控制坦克移动2】

周一没有看圣诞大战,这几天比较忙也没有看赛后的报道,今天就先不扯NBA,随便扯扯自己.昨天在电脑里找东西的时候翻到以前兼职健身教练时的照片,思绪一下子回到学生时代,脑子久久换不过来.现在深深觉得健身和写代码真的是两个极端,一个往死里做(做动作),一个往死里坐(坐椅子),现在的体重和巅峰时期足足差了6公斤,以前80公斤5*10的卧推变成了现在5*20的下斜俯卧撑,唉...掉了的块和体重里可都藏着我写过的代码啊!这里给大家送点小福利,珍藏版的卫平-布莱恩特奉上: 好了不扯,接着上一篇H5坦克大战之[

H5坦克大战之【玩家控制坦克移动】

自从威少砍下45+11+11的大号三双之后,网上出现了各种各样的神级段子,有一条是这样的: 威少:Hey,哥们,最近过得咋样! 浓眉:对方开启了好友验证,请先添加对方为好友 威少:...... JRS:2333333 看到了一条比赛当天的数据统计:威少45+11+11,杜少32+8+3,伊巴卡19+11+2,雷吉杰克逊17+3+6,哈登16+6+16,雷霆管理层真应该改名雷锋管理层了,现在对雷霆管理层的每日一轮都是JRS们的常态了. 好了,不扯,接着上一篇博客(H5坦克大战之画出坦克http:/