设计思路:
控制台模式
初始化:
建立画面,初始化数据
游戏过程:
1.获取操作
2.修改数据
3.更新画面
结束:
关闭画面,delete动态分配数据
4.29日
创建游戏背景,实现飞机移动操作,实现子弹飞行
4.30日
实现游戏数据管理,飞机击落动画,随机出现敌机
代码:
见最终版
5.1日
感觉类的编写处理不好,导致有很多重复的代码。决定重构一下。
编写了 FlyingObject Plane Bullet类
实现了hero移动 发射子弹的操作。实现了所有Hero子弹的移动
设计思路(修改版):
1.使用类进行数据的管理和封装
FlyingObject
—Plane(敌机)
—Hero(玩家飞机)
—Bullet(玩家子弹)
SEM(friend Hero,Bullet,Plane) : 屏幕特效展示(坠毁动画,激光)
2.使用控制台完成指令交互
5.2日
实现了随机间隔出现敌机,敌机的飞行
6.1 日
基本完成第一关的实现,个人感觉重复代码较少。
FlyingObject类:
#pragma once #ifndef FLYINGOBJECT_H #define FLYINGOBJECT_H #include<easyx.h> #include<graphics.h> #include<queue> #include<vector> #include<time.h> #include<list> using namespace std; double direction[6][2] = { { 0,-1 },{ 0,1 } ,{ -1,0 },{ 1,0 },{0.5,0.5},{-0.5,0.5} };//上下左右 struct pos { double x, y; }; class FlyingObject { public: FlyingObject() = default; FlyingObject(double x, double y) { p.x = x; p.y = y; speed = 1; Setspeed(1); Setdir(1); } FlyingObject(pos p) { FlyingObject(p.x, p.y); } pos Getpos() { return p; } //virtual void Add() const = 0; double Getspeed() { return speed; } void Setspeed(double _s) { speed = _s; } void Setpos(double x, double y) { p.x = x; p.y = y; } int Getdir() { return dir; } void Setdir(int _d) { dir = _d; } virtual void Move(int) { p.x += direction[dir][0] * speed; p.y += direction[dir][1] * speed; if (p.x >= 550) p.x = 0; else if (p.x < 0) p.x = 510; if (p.y < 0) p.y = 765; else if (p.y > 750) p.y = 0; } void Draw() { putimage(p.x, p.y, &img); } IMAGE img; bool operator==(const FlyingObject& t) { if (((int)t.p.x == (int)p.x) && ((int)t.p.y == (int)p.y)) return true; return false; } private: pos p; double speed; int dir; }; #endif
Plane 类
这个类表示广义敌机(与自己操控的飞机相撞会导致游戏结束的飞机),为了便于管理把敌机发射的子弹也归类于敌机
#pragma once #ifndef PLANE_H #define PLANE_H #include"Bullet.h" using namespace std; class SEM; class Plane : public FlyingObject { public: friend SEM; friend bool Check(); friend void MoveallPlane(int dir); friend void DrawallPlane(); friend class Bullet; using FlyingObject::FlyingObject; void Add() { Plane::L.insert(L.begin(), *this); } virtual void Move(int) override { pos p = Getpos(); int dir = Getdir(); double speed = Getspeed(); p.x += direction[dir][0] * speed; p.y += direction[dir][1] * speed; if (p.x >= 550 || p.x < 0 || p.y < 0 || p.y > 750) { } else Setpos(p.x, p.y); } virtual void shoot(); private: static list<Plane> L; }; list<Plane> Plane::L; void Plane::shoot() { pos tmp = Plane::Getpos(); Bullet b(tmp.x + 15, tmp.y); loadimage(&b.img, _T("D:\bullet1.ico")); b.Bullet::Add(); b.Draw(); } class Hero :public Plane { public: Hero(double _x, double _y) { Setpos(_x, _y); Setspeed(1); loadimage(&img, _T("D:\hero1.ico")); } void Shootlaser()//发射激光 { } virtual void Move(int dir) override { //int dir = Getdir(); pos p = Getpos(); double speed = Getspeed(); p.x += direction[dir][0] * speed; p.y += direction[dir][1] * speed; if (p.x >= 550) p.x = 0; else if (p.x < 0) p.x = 510; if (p.y < 0) p.y = 765; else if (p.y > 750) p.y = 0; Setpos(p.x, p.y); } private: }; void MoveallPlane(int dir); class Boss :public FlyingObject { friend class Plane; public: Boss(double x,double y) { Setpos(x, y); Setspeed(0.0); loadimage(&img, __T("D:\Boss.jpg")); } void Shoot() { Plane P(Getpos().x,Getpos().y); loadimage(&P.img, _T("D:\Bullet3.ico")); P.Setspeed(2); P.Setdir(rand() % 2 + 4); P.Add(); } }; #endif
Bullet类 :
这个类管理玩家自己发射的子弹(与敌人飞机相撞后会导致敌机坠毁的飞行物)
#pragma once #ifndef BULLET_H #define BULLET_H #include"FlyingObject.h" using namespace std; class Bullet : public FlyingObject { public: friend bool Check(); friend void MoveallBullet(int dir); Bullet() = default; Bullet(double x, double y) { Setpos(x, y); Setspeed(1); Setdir(0); } Bullet(pos p) { Bullet(p.x, p.y); } void Add() { this->L.insert(L.begin(), *this); } void DrawAll() { for (auto it = Bullet::L.begin(); it != Bullet::L.end(); it++) { it->Draw(); } } private: static list<Bullet> L; }; list<Bullet> Bullet::L; void Moveall(int dir); #endif
为了便于管理飞机坠毁,激光特效(由于发射子弹是基于FlyingObject类,而激光不属于飞行物品,所以需要特殊管理)
加入SEM类(special effect manager)
#pragma once #ifndef SEM_H #define SEM_H #include"Plane.h" struct node { double x, y; time_t t; }; class SEM { public: friend class Hero; friend bool Check(); void Drawlaser(Hero &h) { putimage(h.Getpos().x+4, h.Getpos().y-575, &Laser); } void Show(Hero &h) { Gettime(); if (Getflag()) { if (Nowt - Lasertime > 1) SetLaserflag(false); else { Drawlaser(h); } } for (auto it = Crash.begin(); it != Crash.end(); ) { if (it->t <= Nowt) { it = Crash.erase(it); } else it++; } for (auto it = Crash.begin(); it != Crash.end(); it++) { putimage(it->x, it->y, &Crasheffect); } } void Add(double _x, double _y) { node tmp; tmp.x = _x, tmp.y = _y; tmp.t = time(NULL)+1; Crash.push_back(tmp); } void Init() { Begt = time(NULL); Nowt = time(NULL); loadimage(&Crasheffect, _T("D:\ashes.ico")); loadimage(&Laser, _T("D:\Laser.bmp")); } IMAGE Crasheffect,Laser; time_t Gettime()//获得游戏开始了多长时间 { Nowt = time(NULL); return Nowt-Begt; } bool Getflag() { return Laserflag; } void SetLaserflag(bool f) { Laserflag = f; } void SetLasertime() { Lasertime = time(NULL); } private: time_t Begt; time_t Nowt; time_t Lasertime; vector<node> Crash; bool Laserflag; }; #endif
main
#include<iostream> #include<list> #include<time.h> #include<easyx.h> #include<graphics.h> #include"stdio.h" #include"math.h" #include "dos.h" #include<windows.h> #include<mmsystem.h> #include<cstdlib> #include"FlyingObject.h" #include"Plane.h" #include"Bullet.h" #include"SEM.h" #define KEY_DOWN(vk_c) (GetAsyncKeyState(vk_c)&0x8000) using namespace std; Hero hero(230, 700); IMAGE background, ash,Enemy[10]; SEM S; Boss boss(157, 0); void MoveallBullet(int dir) { for (auto it = Bullet::L.begin(); it != Bullet::L.end();) { it->Move(dir); if (it->Getpos().y <= 0) it = Bullet::L.erase(it); else it++; } } bool Check() { int d = 30; for (auto it = Plane::L.begin(); it != Plane::L.end(); it++) { auto tbullet = it->Getpos(); auto tpos = hero.Getpos(); if ((tbullet.x - tpos.x<d&&tbullet.x - tpos.x>-d) && (tbullet.y - tpos.y<d&&tbullet.y - tpos.y>-d)) { return false; } } if (S.Getflag()) { for (auto it = Plane::L.begin(); it != Plane::L.end(); ) { pos tp = it->Getpos(), hp = hero.Getpos(); if (abs(tp.x - hp.x) < 20) { S.Add(tp.x, tp.y); it = Plane::L.erase(it); } else it++; } } for (auto it = Bullet::L.begin(); it != Bullet::L.end();) { auto tbullet = it->Getpos(); bool f = false; for (auto k = Plane::L.begin(); k != Plane::L.end();) { auto tpos = k->Getpos(); tpos.x += 24; tpos.y += 24; if ((tbullet.x - tpos.x<d&&tbullet.x - tpos.x>-d) && (tbullet.y - tpos.y<d&&tbullet.y - tpos.y>-d)) { f = true; S.Add(tpos.x, tpos.y); k = Plane::L.erase(k); break; } else k++; } if (!f) it++; else it = Bullet::L.erase(it); } return true; } void DrawallPlane() { for (auto it = Plane::L.begin(); it != Plane::L.end(); it++) { it->Draw(); } } void MoveallPlane(int dir) { for (auto it = Plane::L.begin(); it != Plane::L.end();) { it->Move(dir); if (it->Getpos().y >=768) it = Plane::L.erase(it); else it++; } } void init()//初始化窗口 { S.Init(); loadimage(&Enemy[0], _T("D:\plane1.ico")); loadimage(&Enemy[1], _T("D:\plane2.ico")); loadimage(&Enemy[2], _T("D:\plane3.ico")); loadimage(&Enemy[3], _T("D:\plane4.ico")); srand((unsigned)time(NULL)); initgraph(512, 768); loadimage(&background, _T("D:\background.jpg")); loadimage(&ash, _T("D:\ashes.ico")); putimage(0, 0, &background); BeginBatchDraw(); } void Show()//更新画面 { putimage(0, 0, &background); hero.Draw(); boss.Draw(); Bullet tmp; tmp.DrawAll(); DrawallPlane(); S.Show(hero); FlushBatchDraw(); } void Key_scan()//扫描键盘 { if (KEY_DOWN(VK_UP)) { hero.Move(0); } else if (KEY_DOWN(VK_LEFT)) { hero.Move(2); } else if (KEY_DOWN(VK_RIGHT)) { hero.Move(3); } else if (KEY_DOWN(VK_DOWN)) { hero.Move(1); } else if (KEY_DOWN(VK_RETURN) || KEY_DOWN(VK_SPACE)) { while (KEY_DOWN(VK_RETURN) || KEY_DOWN(VK_SPACE)) { } hero.shoot(); } else if (KEY_DOWN(VK_SHIFT)) { S.SetLaserflag(true); S.SetLasertime(); hero.Shootlaser(); } } bool Update()//更新游戏数据 { MoveallPlane(1); MoveallBullet(0); if (!Check()) return false; if (rand() % 1000 == 0) { Plane tmp(rand() % 512, 0); tmp.img = Enemy[rand() % 4]; tmp.Setspeed(0.2); tmp.Add(); } if (rand() % 1973 == 0) { boss.Shoot(); } return true; } void Gameover() { } int main() { init(); while (1) { Show(); Key_scan(); if (!Update()) { closegraph(); printf("Game Over "); break; } } }