Qt游戏编程

您所在的位置:网站首页 用图形做飞机 Qt游戏编程

Qt游戏编程

2024-07-12 13:47:58| 来源: 网络整理| 查看: 265

源码下载:http://download.csdn.net/detail/hao_zong_yin/9890778

效果图:

这篇文章记录了我用一周的时间从零Qt基础到制作出飞机大战的过程。

Qt相比MFC封装好了大量函数,而且非常有条理。飞机大战的实现主要用到了Qt的信号与槽机制、事件响应机制、计时器、随机数、QPainter绘图以及最关键的图形视图框架,在做飞机大战之前,建议掌握以下内容:

1.了解信号与槽机制,熟练使用connect函数

2.了解Qt时间响应机制,并学会响应鼠标、键盘事件

3.学会用QTimer控制时间

4.学会生成随机数(本文制作的游戏基本全部使用随机数控制,如果要制作高质量游戏的话建议结合计时器自己写各物体的行为)

5.学会使用QPainter绘图

6.最关键的一点,一定要熟练掌握图形视图框架,这是本文游戏编程的核心

7.多百度,多参考帮助文档

这里强力推荐Qt社区的快速入门教程,上面的内容在基础篇基本全部包含,而且Qt社区有大量的下载资源:

http://www.qter.org/portal.php?mod=view&aid=26

建议下载Qt5版本,并下载版本新一点的Qt creator,网上很多下载教程与下载资源,这里不再啰嗦

当完成了上面全部内容后,就可以正式开始了:

PS:游戏逻辑我会放在最后介绍,当然读者也可以跳到下面及时参考游戏逻辑的代码

根据面向对象的思想,我们应该有一个飞行物体的抽象类,为游戏中的所有飞行物体提供一个接口,飞行物体有飞机和子弹,而飞机有分为玩家飞机和敌机,子弹也分为玩家子弹和敌机子弹,所以还要建飞机抽象类和子弹抽象类继承飞行物体抽象类,对于飞机类,编写玩家飞机实体类和敌机实体类来继承实现飞机抽象类,对于子弹类,编写玩家子弹实体类和敌机子弹实体类继承实现子弹抽象类,现在,读者便可以编写各式各样的飞机子弹了,编写完成后只要继承相应的玩家飞机、敌机、玩家子弹、敌机子弹类就可以了。为了更好的实现各式各样的飞机子弹,我们创建飞机工厂和子弹工厂,在工厂中创造我们需要的物体。

大体思路说完以后,我们来说说这几个类的具体实现。

先看最核心的的类——飞行物体抽象类,所有飞行物体都应该有大小、速度、图片,以及动画函数、碰撞检测函数和摧毁函数,然后编写飞机抽象类,飞机都有血量,而且都会发射子弹,还要有一个函数负责给飞机减血,之后编写子弹抽象类,子弹是飞机大战中最终要的元素,除了各式各样的图片外,还应该朝不同方向发射,这就需要一个角度。

对于实体类,首先要实现基类中的纯虚函数。对于玩家飞机,我们应该为其添加键盘控制,并在实现发射子弹函数时通过子弹工厂装填玩家子弹,对于敌机,为了游戏性读者应该会添加各式各样的杂鱼、BOSS来继承敌机类,这就需要我们为每种类型的敌机都添加其属于自己的子弹、动画效果,为了实现各种移动我们应该为其添加一个角度,便于在飞机工厂中及时控制。建各式各样的飞机飞行效果。玩家子弹、敌机子弹同理编写各式各样的子类,配合子弹工厂实现各种效果。

这里绘图,动画,碰撞检测函数系统都封装好了,完成了准备工作的读者应该可以熟练掌握。

除此之外游戏还有好多其他元素,比如各种补充包,我们可以写一个supply类继承飞行物体类,然后编写子类实现各种补充包。玩家技能则可以看做特殊的子弹继承子弹类,在子弹工厂中创造出来。动态效果的话可以用一组图片通过不断变换来实现,还有更多丰富功能请读者自行添加......

对于游戏逻辑,其实应该读者自己编写,我这里只提供了一个关卡的模板space,space应该具有一个update函数不断刷屏,配合系统提供的advance函数实现移动,同时用step变量来判断隔多久生成敌人、补充包,并用level判断一次生成多少个敌人,然后就是一些开始游戏、暂停游戏、游戏结束之类的逻辑以及显示界面了(这里我没有实现得分显示之类的,本来我想用QGraohicsTextItem实现的,结果发现确实dll而runtime error!)

说了这么多,该上代码了:

全局变量:

#ifndef GLOBAL_H #define GLOBAL_H //此代码仅是一个模板,元素比较单一,但功能接口比较全,各种类型都可以通过在相应的工厂中改变参数实现,或是继承强大的基类实现 //游戏效果可以在全局变量中便捷的控制,添加新元素时注意添加相应的全局变量 //某些细节可能不条理,可以进行适当地调整 //代码中间很少加注释,参考度娘 #include //Name #define BLOODSUPPLYNAME 1 #define BOMBSUPPLYNAME 2 #define BULLETSUPPLYNAME 3 #define PLAYERPLANENAME 4 #define ENEMYPLANENAME 5 #define PLAYERBULLETNAME 6 #define ENEMYBULLETNAME 7 #define BOMBNAME 8 //Size #define SCENEWIDTH 1000 #define SCENEHEIGHT 1000 #define BLOODSUPPLYSIZE 30 #define BOMBSUPPLYSIZE 30 #define BULLETSUPPLYSIZE 30 #define PLAYERPLANESIZE 40 #define FISHSIZE 100 #define BOSSSIZE 200 #define PLAYERBULLETSIZE 20 #define FISHBULLETSIZE1 20 #define FISHBULLETSIZE2 20 #define FISHBULLETSIZE3 20 #define BOSSBULLETSIZE1 80 #define BOSSBULLETWIDTH2 200 #define BOSSBULLETHEIGHT2 40 #define BOSSBULLETSIZE3 200 #define BOSSBULLETWIDTH4 200 #define BOSSBULLETHEIGHT4 200 #define BOMBSIZE 800 //Speed #define BLOODSUPPLYSPEED 20 #define BOMBSUPPLYSPEED 20 #define BULLETSUPPLYSPEED 20 #define PLAYERPLANESPEED 10 #define FISHSPEED 10 #define BOSSSPEED 2 #define PLAYERBULLETSPEED 50 #define FISHBULLETSPEED1 20 #define FISHBULLETSPEED2 20 #define FISHBULLETSPEED3 20 #define BOSSBULLETSPEED1 5 #define BOSSBULLETSPEED2 20 #define BOSSBULLETSPEED3 20 #define BOSSBULLETSPEED4 5 #define BOMBSPEED 10 //UpdateTime, 因为包含一些内部逻辑, 直接改动可能会有错误, 改之前确保理解advance函数中step的意义 const int PLAYERSHOOTSTEP = 5; const int BOSSSHOOTSTEP = 20; const int FISHSHOOTSTEP = 20; const int BOMBPIXSTEP = 10; const int BOSSPIXSTEP = 10; //Score #define FISHSCORE 10 #define BOSSSCORE 1000 //Hp #define FISHHP 10 #define BOSSHP 1000 //UP(上限) #define PLAYERPLANEBLOOD 3 #define PLAYERPLANEBOMB 3 #define PLAYERPLANEBULLET 3 //只实现了boss的动态、玩家的动态和炸弹动态,背景滚动和爆炸效果同理,这里懒得写了 //想要改变动态效果的话注意图片数量,然后自行在飞机、子弹工厂以及控制台中进行相应的改变 const QString background = ":/image/background/background.jpeg"; const QString bloodsupplypix = ":/image/bloodsupply/bloodsupply.png"; const QString bomb0 = ":image/bomb/bomb0.png"; const QString bomb1 = ":image/bomb/bomb1.png"; const QString bombsupplypix = ":/image/bombsupply/bombsupply.png"; const QString boss0 = ":/image/enemyplane/boss0.png"; const QString boss1 = ":/image/enemyplane/boss1.png"; const QString boss2 = ":/image/enemyplane/boss2.png"; const QString boss3 = ":/image/enemyplane/boss3.png"; const QString bossbullet0 = ":/image/enemybullet/bossbullet0.png"; const QString bossbullet1 = ":/image/enemybullet/bossbullet1.png"; const QString bossbullet2 = ":/image/enemybullet/bossbullet2.png"; const QString bossbullet3 = ":/image/enemybullet/bossbullet3.png"; const QString bulletsupplypix = ":/image/bulletsupply/bulletsupply.png"; const QString fish0 = ":/image/enemyplane/fish0.png"; const QString fish1 = ":/image/enemyplane/fish1.png"; const QString fish2 = ":/image/enemyplane/fish2.png"; const QString fishbullet0 = ":/image/enemybullet/fishbullet0.png"; const QString fishbullet1 = ":/image/enemybullet/fishbullet1.png"; const QString fishbullet2 = ":/image/enemybullet/fishbullet2.png"; const QString playerbullet0 = ":/image/playerbullet/playerbullet0.png"; const QString playerbullet1 = ":/image/playerbullet/playerbullet1.png"; const QString playerbullet2 = ":/image/playerbullet/playerbullet2.png"; const QString playerplane0 = ":/image/PlayerPlane/playerplane0.png"; const QString playerplane1 = ":/image/PlayerPlane/playerplane1.png"; const QString playerplane2 = ":/image/PlayerPlane/playerplane2.png"; const QString playerplane3 = ":/image/PlayerPlane/playerplane3.png"; #endif // GLOBAL_H

飞行物体抽象类

#ifndef FLYER_H #define FLYER_H #include #include "global.h" typedef enum {UP, DOWN, LEFT, RIGHT} CHECK_FLAG; typedef QList QPixmaps; class Flyer : public QGraphicsObject { Q_OBJECT public: Flyer(qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0) : QGraphicsObject(parent), m_w(w), m_h(h), m_speed(speed), m_pixpos(0), m_step(0) { for (int i = 0; i < pixs.size(); i++) { QPixmap temp(pixs.at(i)), t; t = temp.scaled(m_w, m_h, Qt::KeepAspectRatioByExpanding); m_pixs.append(t); } scene->addItem(this); } virtual ~Flyer() {} virtual int name() const = 0; virtual void posLost() = 0; virtual void doCollide() = 0; virtual void fall() = 0; bool checkPos(CHECK_FLAG flag) { bool ok = false; switch (flag) { case UP: if (scenePos().ry() >= -m_h) ok = true; break; case DOWN: if (scenePos().ry() = -m_w) ok = true; break; case RIGHT: if (scenePos().rx() width() - m_w)/2, scene->height() - m_h); setFlag(QGraphicsItem::ItemIsFocusable); } PlayerPlane::~PlayerPlane() { } QRectF PlayerPlane::boundingRect() const { return m_pixs.at(0).rect(); } QPainterPath PlayerPlane::shape() const { QPainterPath path; path.addRect(boundingRect()); return path; } void PlayerPlane::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); painter->drawPixmap(0, 0, m_pixs.at(m_pixpos)); } int PlayerPlane::name() const { return PLAYERPLANENAME; } void PlayerPlane::advance(int) { m_step++; if (m_step % PLAYERSHOOTSTEP == 0) { shoot(); } if (m_step == PLAYERSHOOTSTEP * 10) m_step = 0; if (W && checkPos(UP)) { m_pixpos = 0; QPointF pos = scenePos(); pos.ry() -= m_speed; setPos(pos); } if (S && checkPos(DOWN)) { m_pixpos = 1; QPointF pos = scenePos(); pos.ry() += m_speed; setPos(pos); } if (A && checkPos(LEFT)) { m_pixpos = 2; QPointF pos = scenePos(); pos.rx() -= m_speed; setPos(pos); } if (D && checkPos(RIGHT)) { m_pixpos = 3; QPointF pos = scenePos(); pos.rx() += m_speed; setPos(pos); } if (!W && !S && !A && !D) m_pixpos = 0; doCollide(); } void PlayerPlane::posLost() { } void PlayerPlane::doCollide() { foreach (QGraphicsItem *t, collidingItems()) { if (t->type() != UnFlyer::TYPE) { Flyer *flyer = static_cast(t); switch (flyer->name()) { case ENEMYPLANENAME: strike(); if (m_blood == 0) { m_bomb = 0; m_bullet = 0; fall(); } break; case ENEMYBULLETNAME: flyer->fall(); strike(); if (m_blood == 0) { m_bomb = 0; m_bullet = 0; fall(); } break; case BLOODSUPPLYNAME: flyer->fall(); if (m_blood < PLAYERPLANEBLOOD) { m_blood++; //emit sig_blood(m_blood); } break; case BOMBSUPPLYNAME: flyer->fall(); if (m_bomb < PLAYERPLANEBOMB) { m_bomb++; //emit sig_bomb(m_bomb); } break; case BULLETSUPPLYNAME: flyer->fall(); if (m_bullet < PLAYERPLANEBULLET) { m_bullet++; } break; } } } } void PlayerPlane::fall() { setFlag(QGraphicsItem::ItemIsMovable, false); setFlag(QGraphicsItem::ItemIsFocusScope, false); setVisible(false); deleteLater(); emit sig_fall(); } void PlayerPlane::strike() { //m_blood--; //emit sig_blood(m_blood); } void PlayerPlane::shoot() { BulletFactory::PlayerBullets bullets = BulletFactory::pcreator(m_bullet, scene()); QPointF pos = scenePos(); pos.rx() += m_w / 2 - PLAYERBULLETSIZE / 2; foreach (PlayerBullet* bullet, bullets) { bullet->setPos(pos); } if (bomb && m_bomb > 0) { bomb = false; //m_bomb--; BulletFactory::Bombs bombs = BulletFactory::bcreator(1, scene()); pos = scenePos(); pos.rx() += m_w / 2 - BOMBSIZE / 2; pos.ry() -= BOMBSIZE / 2; foreach (Bomb* bomb, bombs) { bomb->setPos(SCENEWIDTH / 2 - BOMBSIZE / 2, SCENEHEIGHT - BOMBSIZE); } } } void PlayerPlane::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_W: event->accept(); W = true; break; case Qt::Key_S: event->accept(); S = true; break; case Qt::Key_A: event->accept(); A = true; break; case Qt::Key_D: event->accept(); D = true; break; case Qt::Key_Space: event->accept(); bomb = true; break; default: event->ignore(); break; } } void PlayerPlane::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_W: event->accept(); W = false; break; case Qt::Key_S: event->accept(); S = false; break; case Qt::Key_A: event->accept(); A = false; break; case Qt::Key_D: event->accept(); D = false; break; case Qt::Key_Space: event->accept(); bomb = false; break; default: event->ignore(); break; } } 敌机

#ifndef ENEMYPLANE_H #define ENEMYPLANE_H #include "flightvehicle.h" #include "bulletfactory.h" class EnemyPlane : public FlightVehicle { public: EnemyPlane(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0); ~EnemyPlane(); QRectF boundingRect() const; QPainterPath shape() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); int name() const; void posLost(); void strike(); protected: qreal m_angle, x_speed, y_speed; }; #endif // ENEMYPLANE_H #include "enemyplane.h" EnemyPlane::EnemyPlane(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent): FlightVehicle(blood, w, h, speed, pixs, scene, parent), m_angle(angle), x_speed(::cos(m_angle / ROTATE) * m_speed), y_speed(::sin(m_angle / ROTATE) * m_speed) { } EnemyPlane::~EnemyPlane() { } QRectF EnemyPlane::boundingRect() const { return m_pixs.at(0).rect(); } QPainterPath EnemyPlane::shape() const { QPainterPath path; path.addRect(boundingRect()); return path; } void EnemyPlane::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); painter->drawPixmap(0, 0, m_pixs.at(m_pixpos)); } int EnemyPlane::name() const { return ENEMYPLANENAME; } void EnemyPlane::posLost() { setVisible(false); deleteLater(); } void EnemyPlane::strike() { m_blood--; } 敌机——杂鱼

#ifndef FISH_H #define FISH_H #include "enemyplane.h" #include "randomizer.h" class Fish : public EnemyPlane { public: Fish(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0); ~Fish(); void advance(int); void doCollide(); void fall(); void shoot(); }; #endif // FISH_H #include "fish.h" Fish::Fish(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent): EnemyPlane(angle, blood, w, h, speed, pixs, scene, parent) { } Fish::~Fish() { } void Fish::advance(int) { m_step++; if (m_step % FISHSHOOTSTEP == 0) { shoot(); } if (m_step == FISHSHOOTSTEP * 10) m_step = 0; QPointF pos = scenePos(); if (!checkPos(DOWN) || !checkPos(LEFT) || !checkPos(RIGHT)) { posLost(); return; } if (!checkPos(UP)) { y_speed = -y_speed; } pos.ry() += y_speed; pos.rx() += x_speed; setPos(pos); doCollide(); } void Fish::doCollide() { foreach (QGraphicsItem *t, collidingItems()) { if (t->type() != UnFlyer::TYPE) { Flyer *flyer = static_cast(t); if (flyer->name() == PLAYERBULLETNAME) { flyer->fall(); strike(); if (m_blood == 0) fall(); } if (flyer->name() == BOMBNAME) { m_blood = 0; fall(); } } } } void Fish::fall() { setVisible(false); deleteLater(); emit sig_score(FISHSCORE); } void Fish::shoot() { int temp = Randomizer::creat(3); if (temp == 0) temp = 3; BulletFactory::EnemyBullets bullets = BulletFactory::ecreator(temp, scene()); QPointF pos = scenePos(); pos.rx() += m_w - FISHBULLETSIZE1; pos.ry() += m_h; foreach (EnemyBullet* bullet, bullets) { bullet->setPos(pos); } } 敌机——BOSS

#ifndef BOSS_H #define BOSS_H #include "enemyplane.h" class Boss : public EnemyPlane { public: Boss(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0); ~Boss(); void advance(int); void doCollide(); void fall(); void shoot(); private: int flag;//特殊控制boss图片变换 }; #endif // BOSS_H #include "boss.h" Boss::Boss(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent): EnemyPlane(angle, blood, w, h, speed, pixs, scene, parent), flag(1) { } Boss::~Boss() { } void Boss::advance(int) { m_step++; if (m_step % BOSSPIXSTEP == 0) { if (flag == 1 && m_pixpos == m_pixs.size() - 1) flag = -1; else if (flag == -1 && m_pixpos == 0) flag = 1; m_pixpos += flag; m_step = 0; } if (m_step % BOSSSHOOTSTEP == 0) { shoot(); } if (m_step == BOSSSHOOTSTEP * 1000) m_step = 0; QPointF pos = scenePos(); if (!checkPos(UP) || !checkPos(DOWN)) { y_speed = -y_speed; } if (!checkPos(LEFT) || !checkPos(RIGHT)) { x_speed = -x_speed; } pos.ry() += y_speed; pos.rx() += x_speed; setPos(pos); doCollide(); } void Boss::doCollide()//Boss免疫大招 { foreach (QGraphicsItem *t, collidingItems()) { if (t->type() != UnFlyer::TYPE) { Flyer *flyer = static_cast(t); if (flyer->name() == PLAYERBULLETNAME) { flyer->fall(); strike(); if (m_blood == 0) fall(); } } } } void Boss::fall() { setVisible(false); deleteLater(); emit sig_score(BOSSSCORE); } void Boss::shoot() { int temp;//这里temp的值应该在工厂中有宏定义,从而增强可读性,懒得写了 if (1.0 * BOSSHP * 3 / 4 < m_blood && m_blood = 1) { QPixmaps t; t.append(QPixmap(playerbullet0)); temp.append(new PlayerBullet(90, PLAYERBULLETSIZE, PLAYERBULLETSIZE, PLAYERBULLETSPEED, t, scene)); } if (flag >= 2) { QPixmaps t; t.append(QPixmap(playerbullet1)); for (int i = 0; i < 2; i++) { temp.append(new PlayerBullet(80 + 20 * i, PLAYERBULLETSIZE, PLAYERBULLETSIZE, PLAYERBULLETSPEED, t, scene)); } } if (flag >= 3) { QPixmaps t; t.append(QPixmap(playerbullet2)); for (int i = 0; i < 2; i++) { temp.append(new PlayerBullet(40 + 20 * i, PLAYERBULLETSIZE, PLAYERBULLETSIZE, PLAYERBULLETSPEED, t, scene)); } for (int i = 0; i < 2; i++) { temp.append(new PlayerBullet(120 + 20 * i, PLAYERBULLETSIZE, PLAYERBULLETSIZE, PLAYERBULLETSPEED, t, scene)); } } //可以继续添加,让玩家变得更变态 return temp; } BulletFactory::EnemyBullets BulletFactory::ecreator(uint flag, QGraphicsScene *scene) { EnemyBullets temp; QPixmaps t, t1, t2; switch (flag) { case 0: break; case 1: t.append(QPixmap(fishbullet0)); temp.append(new EnemyBullet(90, FISHBULLETSIZE1, FISHBULLETSIZE1, FISHBULLETSPEED1, t, scene)); break; case 2: t.append(QPixmap(fishbullet1)); for (int i = 0; i < 3; i++) { temp.append(new EnemyBullet(80 + 10 * i, FISHBULLETSIZE2, FISHBULLETSIZE2, FISHBULLETSPEED2, t, scene)); } break; case 3: t.append(QPixmap(fishbullet2)); for (int i = 0; i < 4; i++) { temp.append(new EnemyBullet(0 + 90 * i, FISHBULLETSIZE3, FISHBULLETSIZE3, FISHBULLETSPEED3, t, scene)); } break; case 4: t.append(QPixmap(bossbullet0)); for (int i = 0; i < 8; i++) { temp.append(new EnemyBullet(0 + 45 * i, BOSSBULLETSIZE1, BOSSBULLETSIZE1, BOSSBULLETSPEED1, t, scene)); } break; case 5: t1.append(QPixmap(bossbullet0)); for (int i = 0; i < 12; i++) { temp.append(new EnemyBullet(0 + 30 * i, BOSSBULLETSIZE1, BOSSBULLETSIZE1, BOSSBULLETSPEED1, t1, scene)); } t2.append(QPixmap(bossbullet1)); temp.append(new EnemyBullet(90, BOSSBULLETWIDTH2, BOSSBULLETHEIGHT2, BOSSBULLETSPEED2, t2, scene)); break; case 6: t1.append(QPixmap(bossbullet0)); for (int i = 0; i < 12; i++) { temp.append(new EnemyBullet(0 + 30 * i, BOSSBULLETSIZE1, BOSSBULLETSIZE1, BOSSBULLETSPEED1, t1, scene)); } t2.append(QPixmap(bossbullet2)); temp.append(new EnemyBullet(90, BOSSBULLETSIZE3, BOSSBULLETSIZE3, BOSSBULLETSPEED3, t2, scene)); break; case 7: t1.append(QPixmap(bossbullet0)); for (int i = 0; i < 36; i++) { temp.append(new EnemyBullet(0 + 10 * i, BOSSBULLETSIZE1, BOSSBULLETSIZE1, BOSSBULLETSPEED1, t1, scene)); } t2.append(QPixmap(bossbullet2)); temp.append(new EnemyBullet(90, BOSSBULLETSIZE3, BOSSBULLETSIZE3, BOSSBULLETSPEED3, t2, scene)); break; //推荐继续添加子弹,尤其是可以根据时间变化的子弹(用m_step控制) } return temp; }

太长了。。。。。。附加功能和游戏逻辑另写一篇:

http://blog.csdn.net/hao_zong_yin/article/details/74560842



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭