电影网站模板html,北京 网站建设 招标信息,网站设计代码,wordpress 用户验证前面我们的攻击手段比较单一#xff0c;虽然已经分出了 EnemyT1 / EnemyT2 / EnemyT3#xff0c; 但里面还是基本一样的。这回#xff0c;我们尝试实现一些新的攻击方法#xff0c;实现一些新的算法。 1、前面我们小飞机EnemyT1 的攻击方式是垂直向下发射子弹。
那么大飞机… 前面我们的攻击手段比较单一虽然已经分出了 EnemyT1 / EnemyT2 / EnemyT3 但里面还是基本一样的。这回我们尝试实现一些新的攻击方法实现一些新的算法。 1、前面我们小飞机EnemyT1 的攻击方式是垂直向下发射子弹。
那么大飞机EnemyT2的攻击手段就更高级一些我们让它能够瞄准玩家射击。
大飞机EnemyT2发射子弹是EnemyT2类的私有方法想要让他能够瞄准玩家就要知道玩家在哪里。还记得前面我们做的数据仓库么。这回用上了。
我们修改EnemyT2的createBulletObject函数
void EnemyT2::createBulletObject(PlaneObject_t *target) {BulletObject_t *but1 new BulletObject_t();but1-x baseInfo.x - PlaneXYScale;but1-y baseInfo.y PlaneXYScale * 2;but1-visiable 1;int sum abs(target-x - but1-x) abs(target-y - but1-y);but1-speedX 300 * (target-x - but1-x) / sum;but1-speedY 300 * (target-y - but1-y) / sum;getRainbowColor(but1-color, 200);ListPushBack(enemyBulletList, (LTDataType) but1);
}uint8_t EnemyT2::tick(uint32_t t) {。。。if (fireTimer.tick(t)) {if (((PlaneObject_t*) DataBulk::GetInstance()-data1)-visiable)createBulletObject((PlaneObject_t*) DataBulk::GetInstance()-data1);if (((PlaneObject_t*) DataBulk::GetInstance()-data2)-visiable)createBulletObject((PlaneObject_t*) DataBulk::GetInstance()-data2);}。。。
}注意确定子弹方向的算法 int sum abs(target-x - but1-x) abs(target-y - but1-y); but1-speedX 300 * (target-x - but1-x) / sum; but1-speedY 300 * (target-y - but1-y) / sum; 300是子弹速度。 简单通过相似三角形来确定方向和速度不是很精确但也足够用了。如果要精确的话需要用三角函数算分速度太复杂没必要。 2、Boss肯定要更强大我们要让他同时向多个方向发射散弹同时发射一颗能追踪的导弹。
先给他发射散弹
void EnemyT3::createBulletObject(int speedX) {PlaneObject_t *but1 new PlaneObject_t();but1-x baseInfo.x - PlaneXYScale * 2;but1-y baseInfo.y PlaneXYScale;but1-speedX speedX;but1-speedY 300 - abs(speedX);but1-visiable 1;but1-color 0xe01000;ListPushBack(enemyBulletList, (LTDataType) but1);
}uint8_t EnemyT3::tick(uint32_t t) {animationStoryBoard-tick(t);if (fireTimer.tick(t)) {createBulletObject(-120);createBulletObject(-70);createBulletObject(-30);createBulletObject(0);createBulletObject(30);createBulletObject(70);createBulletObject(120);}for (ListNode *node animationList-next; node ! animationList; node node-next) {if (((Animation*) node-data)-isValid) {((Animation*) node-data)-tick(t);}}return 0;
}追踪导弹不是直线运动所以要单独一个链表 enemyRocketList单独的算法
class BulletManager {
public:BulletManager();virtual ~BulletManager();uint8_t tick(uint32_t t);void init();uint8_t show(void);ListNode *player1BulletList;ListNode *player2BulletList;ListNode *enemyBulletList;ListNode *enemyRocketList;
private:void tickOnce(ListNode *list, uint32_t t);void showOnce(ListNode *list);void destoryOnce(ListNode *list);void tickRocket(uint32_t t);
};void BulletManager::tickRocket(uint32_t t) {for (ListNode *cur enemyRocketList-next; cur ! enemyRocketList; cur cur-next) {PlaneObject_t *bullet (PlaneObject_t*) (cur-data);PlaneObject_t *target bullet-tag 1 ? Player1BaseInfo : Player2BaseInfo;int sum abs(target-x - bullet-x) abs(target-y - bullet-y);bullet-speedX 50 * (target-x - bullet-x) / sum;bullet-speedY 50 * (target-y - bullet-y) / sum;bullet-x bullet-speedX * t;bullet-y bullet-speedY * t;}
}uint8_t BulletManager::tick(uint32_t t) {tickOnce(player1BulletList, t);tickOnce(player2BulletList, t);tickOnce(enemyBulletList, t);tickRocket(t);return 0;
}然后发射导弹
void EnemyT3::createRocketObject(int target) {PlaneObject_t *but1 new PlaneObject_t();but1-x baseInfo.x - PlaneXYScale * 2;but1-y baseInfo.y PlaneXYScale;but1-visiable 1;but1-color 0xe01000;but1-tag target;ListPushBack(EnemyRocketList, (LTDataType) but1);
}
uint8_t EnemyT3::tick(uint32_t t) {animationStoryBoard-tick(t);if (fireTimer.tick(t)) {
。。。if (Player1BaseInfo-visiable)createRocketObject(1);if (Player2BaseInfo-visiable)createRocketObject(2);}
。。。return 0;
}
补充为了方法把数据的地址都在DataBulk里面管起来。
void Plane::init() {backGroundStar.init();bulletManager.init();player1.init(1);player1.bulletList bulletManager.player1BulletList;enemyManager.init();DataBulk::GetInstance()-data1 (intptr_t) player1.baseInfo;DataBulk::GetInstance()-data2 (intptr_t) player2.baseInfo;DataBulk::GetInstance()-data3 (intptr_t) bulletManager.player1BulletList;DataBulk::GetInstance()-data4 (intptr_t) bulletManager.player2BulletList;DataBulk::GetInstance()-data5 (intptr_t) bulletManager.enemyBulletList;DataBulk::GetInstance()-data6 (intptr_t) bulletManager.enemyRocketList;}添加宏
PlaneDef.h
#define Player1BaseInfo ((PlaneObject_t*)DataBulk::GetInstance()-data1)
#define Player2BaseInfo ((PlaneObject_t*)DataBulk::GetInstance()-data2)
#define Player1BulletList ((ListNode*)DataBulk::GetInstance()-data3)
#define Player2BulletList ((ListNode*)DataBulk::GetInstance()-data4)
#define EnemyBulletList ((ListNode*)DataBulk::GetInstance()-data5)
#define EnemyRocketList ((ListNode*)DataBulk::GetInstance()-data6)
最后给导弹就上生命周期
typedef struct {int x;int y;int color;int speedX;int speedY;uint8_t visiable 0;uint8_t width;uint8_t height;int life 0x7fffffff;int tag;
} PlaneObject_t;
void BulletManager::tickRocket(uint32_t t) {for (ListNode *cur enemyRocketList-next; cur ! enemyRocketList; cur cur-next) {PlaneObject_t *bullet (PlaneObject_t*) (cur-data);bullet-life - t;if (bullet-life 0) {bullet-visiable 0;continue;}PlaneObject_t *target bullet-tag 1 ? Player1BaseInfo : Player2BaseInfo;int sum abs(target-x - bullet-x) abs(target-y - bullet-y);bullet-speedX 50 * (target-x - bullet-x) / sum;bullet-speedY 50 * (target-y - bullet-y) / sum;bullet-x bullet-speedX * t;bullet-y bullet-speedY * t;}
}三种敌机都有了足够的差异化了不同的形状不同的飞行方式不同的攻击方式甚至击毁效果都不一样。不枉我们把它们区分为3个不同的类。 下面再来考虑玩家的攻击方式。
原来只有子弹我们给他加上炸弹和激光。
子弹击中就没有了而炸弹和激光属于范围攻击模式其伤害是持续性的而且与时间有关系。先做炸弹。
设定炸弹效果为半径7的圆碰撞检测销毁敌方子弹对敌机持续造成 time * 1 的伤害。每玩家只有一个在生效。
先在像素屏驱动里面补充一个单片机上常用的画圆方法Bresenham算法。具体原理不再赘述可自行网上搜索。 不用三角函数的函数就是好函数。 void ws2812_Fill_Circle(uint16_t x0, uint16_t y0, uint8_t r, uint32_t color) {int x 0, y r, d;d 3 - 2 * r;while (x y) {ws2812_fill(x0 - x, y0 - y, x * 2, 1, (color 0xff0000) 16,(color 0xff00) 8, color 0xff);ws2812_fill(x0 - x, y0 y - 1, x * 2, 1, (color 0xff0000) 16,(color 0xff00) 8, color 0xff);ws2812_fill(x0 - y, y0 - x, 1, x * 2, (color 0xff0000) 16,(color 0xff00) 8, color 0xff);ws2812_fill(x0 y - 1, y0 - x, 1, x * 2, (color 0xff0000) 16,(color 0xff00) 8, color 0xff);if (d 0) {d d 4 * x 6;} else {d d 4 * (x - y) 10;y--;}x;}ws2812_fill(x0 - y, y0 - y, y * 2, y * 2, (color 0xff0000) 16,(color 0xff00) 8, color 0xff);
}1、定义一个结构 EffectObject_t 保存效果信息
typedef struct {int type;int x;int y;int life 0x7fffffff;
} EffectObject_t;
2、在玩家类里面加上爆炸效果 effectObject
class PlanePlayer {
public:PlanePlayer();~PlanePlayer();void init(uint8_t id);uint8_t tick(uint32_t t, uint8_t b1);uint8_t show(void);uint8_t hitDetect(int x, int y, int damage);uint8_t hitEffectDetect(int x, int y, int r);
。。。EffectObject_t *effectObject NULL;int HP;
private:
。。。
};
3、在plane.cpp里面加上 爆炸效果的碰撞检测遍历
void Plane::checkEffectCollision(uint32_t t, PlanePlayer *player) {if (player-effectObject NULL)return;for (ListNode *enemy enemyManager.enemyList-next;enemy ! enemyManager.enemyList; enemy enemy-next) {EnemyBase *ene (EnemyBase*) enemy-data;if (ene-explodeState)continue;uint8_t res player-hitEffectDetect(ene-baseInfo.x, ene-baseInfo.y,(ene-baseInfo.width ene-baseInfo.height) / 3);if (res) {ene-HP - res * t;ene-hurt();}}for (ListNode *enemyBul bulletManager.enemyBulletList-next;enemyBul ! bulletManager.enemyBulletList; enemyBul enemyBul-next) {PlaneObject_t *bul (PlaneObject_t*) enemyBul-data;uint8_t res player-hitEffectDetect(bul-x, bul-y, 1);if (res) {bul-visiable 0;}}for (ListNode *enemyBul bulletManager.enemyRocketList-next;enemyBul ! bulletManager.enemyRocketList; enemyBul enemyBul-next) {PlaneObject_t *bul (PlaneObject_t*) enemyBul-data;uint8_t res player-hitEffectDetect(bul-x, bul-y, 1);if (res) {bul-visiable 0;}}
} 注意敌机、敌方子弹、敌方导弹都有可能被爆炸摧毁。 4、在玩家类里加上碰撞检测
uint8_t PlanePlayer::hitEffectDetect(int x, int y, int r) {switch (effectObject-type) {case 1: {int a (x - effectObject-x) / 100;int b (y - effectObject-y) / 100;int c (r 10) * 100;return (a * a b * b c * c) ? 1 : 0;}}return 0;
}
5、显示玩家的顺手显示爆炸效果
uint8_t PlanePlayer::show(void) {if (effectObject ! NULL) {ws2812_Fill_Circle(effectObject-x / PlaneXYScale,effectObject-y / PlaneXYScale, 10, 0x801000);}for (uint8_t y 0; y 5; y) {for (uint8_t x 0; x 5; x) {if (PlaneSharp[y][x])ws2812_pixel(x baseInfo.x / PlaneXYScale - 2,y baseInfo.y / PlaneXYScale - 2,(baseInfo.color 16) 0xff,(baseInfo.color 8) 0xff, baseInfo.color 0xff);}}return 0;
}TODO其实爆炸小时不应该和显示玩家纠结在一起。如果有多种特殊武器还是单独写个函数显示为好。 好了对于激光来说激光要跟随玩家移动。增加激光特效只要增加碰撞检测和显示两部分就行了。
激光的碰撞检测
uint8_t PlanePlayer::hitEffectDetect(int x, int y, int r) {switch (effectObject-type) {case 1: {int a (x - effectObject-x) / 100;int b (y - effectObject-y) / 100;int c (r 10) * 100;return (a * a b * b c * c) ? 1 : 0;}case 2:return (x / PlaneXYScale baseInfo.x / PlaneXYScale) ? 1 : 0;}return 0;
} 激光的显示
uint8_t PlanePlayer::show(void) {if (effectObject ! NULL) {if (effectObject-type 1) {ws2812_Fill_Circle(effectObject-x / PlaneXYScale,effectObject-y / PlaneXYScale, 10, 0x801000);} else {ws2812_fill(baseInfo.x / PlaneXYScale, 0, 1,baseInfo.y / PlaneXYScale, 0, 100, 200);}}for (uint8_t y 0; y 5; y) {for (uint8_t x 0; x 5; x) {if (PlaneSharp[y][x])ws2812_pixel(x baseInfo.x / PlaneXYScale - 2,y baseInfo.y / PlaneXYScale - 2,(baseInfo.color 16) 0xff,(baseInfo.color 8) 0xff, baseInfo.color 0xff);}}return 0;
}比较一下加一个激光特效只要两行代码。0到1不容易1到2快的飞起。 最后在玩家操作里面加上炸弹和激光
uint8_t PlanePlayer::tick(uint32_t t, uint8_t b1) {
。。。if (effectObject NULL) {if (b1 KEY_BUTTON_D) {effectObject new EffectObject_t();effectObject-x baseInfo.x;effectObject-y (baseInfo.y 25 * PlaneXYScale) ?baseInfo.y - 25 * PlaneXYScale : 0;effectObject-type 1;effectObject-life 4000;} else if (b1 KEY_BUTTON_A) {effectObject new EffectObject_t();effectObject-x baseInfo.x;effectObject-y baseInfo.y;effectObject-type 2;effectObject-life 4000;}} else {effectObject-life - t;if (effectObject-life 0) {delete effectObject;effectObject NULL;}}。。。return 0;
}看看效果 STM32学习笔记十七WS2812制作像素游戏屏-飞行射击 STM32学习笔记十九WS2812制作像素游戏屏-飞行射击游戏9探索道具系统