2010年1月31日 星期日

QT4.6 2D戰略遊戲開發框架








































計算角色移動力公式:
























/////////////////滑鼠控制,計算在框框內,產生移動路徑//////////////////////////////////
void QGame_move_line_rpg::set_move_rpg_to_location(QPoint p)
{

this->clear_rpg_move_label();//先清除label
int x=this->get_move_obj_x();
int y=this->get_move_obj_y();
int disx=p.x()-x;
int disy=p.y()-y;
int stepx=disx/50;
int stepxx=stepx;
if(stepx<0)stepx=-stepx;//+
if(stepx>rpg.move_ability){stepx=rpg.move_ability;} //最大只能到角色移動力x
int stepy=disy/50;
int stepyy=stepy;
if(stepy<0)stepy=-stepy+1;//+
if(stepy>rpg.move_ability-stepx ){stepy=rpg.move_ability+1-stepx;}//最大只能到角色移動力y
// if(move_label_list->size()==0)
// {
for(int i=1;i<stepx+1;i++)
{
int st=i; //正x方向
QPixmap image1;
if(disx<0){st=-i;}//負x方向

QPoint sp(x+st*50,y);
image1=QPixmap(":/new/prefix1/icon/linev.png").scaled(50,50);//線
/////正x軸
if(i==stepx and stepy<2 and st > 0)
{
image1=QPixmap(":/new/prefix1/icon/liner.png").scaled(50,50);//右鍵頭
}
if(stepx!=rpg.move_ability){//若最大就不要顯示轉角
if(i==stepx and stepyy>=2 and st > 0)
{
image1=QPixmap(":/new/prefix1/icon/linerd.png").scaled(50,50);//右下轉彎
}
if(i==stepx and stepyy<=-1 and st > 0){
image1=QPixmap(":/new/prefix1/icon/lineru.png").scaled(50,50);//右上轉彎
}
}
/////負x軸
if(i==stepx and stepy<2 and st < 0){
image1=QPixmap(":/new/prefix1/icon/linel.png").scaled(50,50);//左箭頭
}
if(stepx!=rpg.move_ability){//若最大就不要顯示轉角
if(i==stepx and stepyy<=-1 and st < 0){
image1=QPixmap(":/new/prefix1/icon/linelu.png").scaled(50,50);//左上
}
if(i==stepx and stepyy>=2 and st < 0){
image1=QPixmap(":/new/prefix1/icon/lineld.png").scaled(50,50);//左下
}
}


QGame_move_line *a1=new QGame_move_line(sp,sp,1,500,"KEEPWHENDSTOP",image1,parentt);
move_label_list->append(a1);
if(i==stepx)rpg_move_point=sp;//RPG移動點

}

for(int j=1;j<stepy;j++)
{
int st=j;
QPixmap image1;
if(disy<0){st=-j;}//負y方向
QPoint sp(x+stepxx*50,y+st*50);
image1=QPixmap(":/new/prefix1/icon/lineh.png").scaled(50,50);
if(j==stepy-1 and stepyy>0){ image1=QPixmap(":/new/prefix1/icon/lined.png").scaled(50,50);}
if(j==stepy-1 and stepyy<0){ image1=QPixmap(":/new/prefix1/icon/lineu.png").scaled(50,50);}




QGame_move_line *a1=new QGame_move_line(sp,sp,1,500,"KEEPWHENDSTOP",image1,parentt);
move_label_list->append(a1);
if(j==stepy-1)rpg_move_point=sp;//RPG移動點
}

// }
}
//移動RPG到指定位置
void QGame_move_line_rpg::move_rpg_to_location()
{
this->move_obj->setEndValue(rpg_move_point);
this->move_obj->start();
}

void QGame_move_line_rpg::clear_rpg_move_label()
{
for(int i=0;i<move_label_list->size();i++)
{
move_label_list->at(i)->clear_move_obj();
move_label_list->removeAt(i);;
}
}

A.目前根據滑鼠所在位置,顯示移動路徑,並將改角色移動到箭頭位置
原理:加入滑鼠事件,計算當前到mose的x到移動物要放多少圖片(當然這是用QGame_move_line來產生),在計算y軸的將他全加到QList,每次mouse清聽到移動事件,先清空QList.

B.碰撞敵人產生攻擊選項
只要一偵測到碰撞敵人,就在上下左右個產生一個QLabel(當然這是用QGame_move_line來產生)

C.戰略遊戲,要有AI計算(從沒試過),這部份有些難,努力中,還不曉得能寫出來AI這部份

D.定義角色的能力,使用typedef struct簡單明瞭

typedef struct
{
int move_ability; //移動力
int life; //生命
int attack; //攻擊力
int defense; //防禦力
}rpg_ability;

rpg_ability rpg;
E.來看看使用這個框架,如何簡單就產生一隻會移動的角色,只要一行
//攻擊10,防禦8,生命20,移動力4
body=new QGame_move_line_rpg(10,8,20,4,pstart,pend,1,10,"KEEPWHENDSTOP",birdimg,this);


read more...

2010年1月26日 星期二

定義電感和NMOS ON NWELL的SUBCKT

有時非得要自己加一些SUBCKT
電感和NMOS ON NWELL,在Calibre都是沒預先DIVCE TPYE,subcket加法要使用2次,這樣就能讓LVS對上netlist type

.SUBCKT SPIRAL_SYM 2 3 BULK
X0 2 3 BULK spiral_s3_std w=3e-05 s=3e-06 nr=1.5 rad=3e-05 lay=6 $X=-155370 $Y=39380 $D=73
.ENDS
.SUBCKT spiral_s3_std PLUS MINUS BULK
.ENDS

.SUBCKT MOSCAP_RF PLUS MINUS BULK
X0 PLUS MINUS BULK moscap_rf18 w=WR L=LR M=BR
.ENDS

.SUBCKT moscap_rf18 PLUS MINUS BULK
.ENDS

calibre 定義moscap_rf18這個device,一般電容會以C開頭,下面並不是以C開頭,就是以SUBCKT的型態了,因此netlist就要用X開頭(subcket)

DEVICE moscap_rf18 vargt_rf poly(PLUS) tndiff(MINUS) nxwell(B) NETLIST MODEL nmoscap [
property W,L
W=(perimeter_coincide(vargt_rf, tndiff ) + perimeter_inside(vargt_rf, tndiff)) / 2
L=area(vargt_rf) / W

]
TRACE PROPERTY moscap_rf18 w w 0
TRACE PROPERTY moscap_rf18 l l 0


read more...

2010年1月22日 星期五

QT4.6自製遊戲開發框架(續)

自制的QGgame_move_line類,已經能偵測許多種碰撞測試,例如碰撞後停止,爆炸,力回饋.......,移動物能自動隨機發射(上下左右)子彈,或被動發射子彈,目前還有很多要加的項目,譬如自動朝一移動物發射子彈,移動物能變換方向,最終會以GNU GPL授權方式,公開源碼,目前還在測試階段,等告一段落就會釋出.

碰撞測試我採用的是矩形碰撞
當2個矩形產生碰撞,一矩形的4頂點的其中一點必定在另一矩形內,當然還要反過來,這樣就簡單的做出碰撞判斷,那如何子彈碰到移動物,移動物會爆炸,QGgame_move_line隨機產生了許多子彈,QGgame_move_line必須讓所有子彈都時時刻刻發出矩形信號(SIGNAL),QGgame_move_line寫一個接收矩形的信號槽(SLOT),讓這2矩形做碰撞測試,若是成立QGgame_move_line就會被kill掉,原理大概就這樣,很多的運算都是直接封裝在QGgame_move_line類,這樣才能顯示這QGgame_move_line的強大.
當然我不是用QTimer或QThread來讓子彈都時時刻刻發出矩形信號,假若是這樣做CPU會LOAD太重.

目睹一下只要使用QGgame_move_line類,幾十行程是就能做出下面遊戲畫面了

soot_game.cpp
------------------------------------------------------------------------------


#include "shoot.h"
#include "ui_shoot.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////shoot game開發框架,利用此框架可輕鬆開發射擊遊戲,發揮你的想像力做出更棒的遊戲////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
shoot::shoot(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::shoot)
{

ui->setupUi(this);
newgv=new QGraphicsView(this);
ui->gridLayout_3->addWidget(newgv);
newgv->setStyleSheet("background-color: rgb(85, 170, 0);");

//birdimg=QPixmap(":/new/prefix1/icon/body.png").scaled(30,30);

//pstart.setX(240);pstart.setY(430);
//pend.setX(240);pend.setY(430);
start_movie();
score=0;
is_game_over=true;

}

shoot::~shoot()
{
delete ui;


}

void shoot::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}

void shoot::on_pushButton_pressed()
{

if(is_game_over){//清除畫面,開始GAME
newgv->deleteLater();
newgv=new QGraphicsView(this);
ui->gridLayout_3->addWidget(newgv);
newgv->setStyleSheet("background-color: rgb(85, 170, 0);");
birdimg=QPixmap(":/new/prefix1/icon/body.png").scaled(30,30);
pstart.setX(240);pstart.setY(430);
pend.setX(240);pend.setY(430);
bulletimg=QPixmap(":/new/prefix1/icon/bullet1.png").scaled(20,40);
//body會發射子彈向上,但不是自動(NOAUTO)
body=new QGame_move_line(bulletimg,"UP","NOAUTO",pstart,pend,1,2000,"KEEPWHENDSTOP",birdimg,newgv);
connect(body,SIGNAL(kill_move()),this,SLOT(game_over()));//body被delete發出信號連到GAME OVER
timer = new QTimer;
timer->start(6000);
this->plan_gen();

connect(timer, SIGNAL(timeout()), this, SLOT(plan_gen()));//一定要用this
is_game_over=false;
}



}
void shoot::game_over()
{

is_game_over=true;
QPixmap gimg=QPixmap(":/new/prefix1/icon/gameover.png").scaled(200,30);
pstart.setX(180);pstart.setY(220);
pend.setX(180);pend.setY(220);
ga=new QGame_move_line(pstart,pend,1,2000,"KEEPWHENDSTOP",gimg,newgv);//產生GAME OVER圖片

disconnect(timer, SIGNAL(timeout()), this, SLOT(plan_gen()));//一定要用this

}
void shoot::keyPressEvent(QKeyEvent* event)
{
if(!is_game_over){


if(body->get_move_obj_x()<540)
{
if(event->key()==Qt::Key_L){body->move_obj_distance("RIGHT",300);} //L鍵往右,故意設大一點300有持續移動,像在駕駛賽車
}
if(body->get_move_obj_x()>0 )
{
if(event->key()==Qt::Key_J){body->move_obj_distance("LEFT",-300);}//J鍵往左,故意設大一點300有持續移動,像在駕駛賽車
}
//按下S鍵,發射子彈
if(this->body->get_bullet_number()<5)//最多5顆
{
if(event->key()==Qt::Key_S){this->body->add_one_bullet();}//或者emit
}
}
}
void shoot::keyReleaseEvent( QKeyEvent* event )//可用此鬆開key就暫停賽車移動
{
if(!is_game_over){
if(event->key()==Qt::Key_L)body->set_move_stop(); //放開L鍵,停止body移動
if(event->key()==Qt::Key_J)body->set_move_stop(); //放開J鍵,停止body移動
}

}
void shoot::plan_gen()
{
int d=qrand()%100;
int loop_no=qrand()%10+1;
int speed=qrand()%2000+1000;
//move1 移動2次,來回移動,會自動掉子彈的直昇機
birdimg=QPixmap(":/new/prefix1/icon/plan.png").scaled(50,50); //直昇機圖
bulletimg=QPixmap(":/new/prefix1/icon/bullet.png").scaled(20,40);//子彈圖
if(qrand()%100 >50)
{
pstart.setX(0);pstart.setY(60+d);//移動開始點
pend.setX(560);pend.setY(60+d); //移動結束點
}else
{
pstart.setX(560);pstart.setY(60+d);//移動開始點
pend.setX(0);pend.setY(60+d); //移動結束點
}
//產生會自動掉向下子彈的直昇機(DOWN,AUTO),移動2次,一直重複移動
move1=new QGame_move_line(bulletimg,"DOWN","AUTO",pstart,pend,loop_no,speed,"RETURN",birdimg,newgv);
//plan_gen_connect();
connect(move1,SIGNAL(move_obj_qrect(QRect)),body,SLOT(collision_boom(QRect)));//這是直昇機撞到機台,這裡沒作用
//connect(body,SIGNAL(move_obj_qrect(QRect)),move1,SLOT(bullet_collision(QRect)));//機台連到子彈
//connect(move1,SIGNAL(emit_bullet_collision()),body,SLOT(clear_move_obj()));//子彈連到機台
connect(move1,SIGNAL(bullet_obj_qrect(QRect)),body,SLOT(collision_boom(QRect)));//子彈連到機台,子彈碰撞機台,機台消失
connect(body,SIGNAL(bullet_obj_qrect(QRect)),move1,SLOT(collision_boom(QRect)));//子彈連到直昇機,子彈碰撞直昇機,直昇機消失
connect(move1,SIGNAL(kill_move()),this,SLOT(gain_score()));//得分

}
void shoot::start_movie()//開頭動畫
{

QPixmap gimg=QPixmap(":/new/prefix1/icon/play1.png").scaled(200,30);
pstart.setX(180);pstart.setY(220);
pend.setX(180);pend.setY(220);
ga=new QGame_move_line(pstart,pend,1,2000,"KEEPWHENDSTOP",gimg,newgv);//產生GAME OVER圖片






int d=qrand()%100;
int loop_no=qrand()%10+1;
int speed=qrand()%2000+1000;
//move1 移動2次,來回移動,會自動掉子彈的直昇機
birdimg=QPixmap(":/new/prefix1/icon/plan.png").scaled(50,50); //直昇機圖
bulletimg=QPixmap(":/new/prefix1/icon/bullet.png").scaled(20,40);//子彈圖
if(qrand()%100 >50)
{
pstart.setX(0);pstart.setY(60+d);//移動開始點
pend.setX(560);pend.setY(60+d); //移動結束點
}else
{
pstart.setX(560);pstart.setY(60+d);//移動開始點
pend.setX(0);pend.setY(60+d); //移動結束點
}
//產生會自動掉向下子彈的直昇機(DOWN,AUTO),移動2次,一直重複移動
move1=new QGame_move_line(bulletimg,"DOWN","AUTO",pstart,pend,loop_no,speed,"RETURN",birdimg,newgv);


}

void shoot::gain_score()
{
score++;
ui->label_2->setText(QString::number(score));

}











read more...

2010年1月5日 星期二

利用Qt 4.6強大的QPropertyAnimation功能,來自製2D遊戲開發框架

我又對qgame_move這個類,寫了幾個功能
1.能指定要移動幾次
2.或是重複一直移動
3.目前移動完成會消失(當然我想移動完成不消失會在寫進去,現在還沒寫)

我是用QPropertyAnimation的finished()信號來完成,這是當完成移動後會發出finished()信號
move_obj->start(QAbstractAnimation:: KeepWhenStopped );
move_obj->start(QAbstractAnimation::DeleteWhenStopped);
這2個差別就是當QPropertyAnimation完成移動後,是否保留或是刪除,若是要寫能重複移動就要用
move_obj->start(QAbstractAnimation:: KeepWhenStopped );

來看看下面簡單幾行使用qgame_move這個類,幾行程式,就讓圖片產生不同移動狀態,是不是傻眼了.

mainwindow.cpp
====================================================
QPixmap birdimg=QPixmap(":/new/prefix1/Star.bmp").scaled(40,40);
//move1 移動一次,移動物消失
QPoint p1(0, 360);
QPoint p2(310, 180);
QGame_move *a1=new QGame_move(p1,p2,1,"DELETE",birdimg,ui->graphicsView);
//move2 移動5次,移動物消失
QPoint p3(620, 360);
QPoint p4(310, 180);
QGame_move *a2=new QGame_move(p3,p4,5,"DELETE",birdimg,ui->graphicsView);
//move3 重複移動
QPoint p5(0, 0);
QPoint p6(310, 180);
QGame_move *a3=new QGame_move(p5,p6,1,"LOOP",birdimg,ui->graphicsView);

qgame_move.h
=====================================================
#ifndef QGAME_MOVE_H
#define QGAME_MOVE_H
#include <QWidget>
#include <QObject>
#include <QLabel>
#include <QPixmap>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>
#include <QParallelAnimationGroup>
#include <QTimer>
#include <QAbstractAnimation>

class QGame_move : public QWidget {
Q_OBJECT
public:
QGame_move(QPoint startp,QPoint endp,int loop_count,QString end_style,QPixmap image,QWidget *parent = 0);
private:
QPropertyAnimation *move_obj;
QLabel *move_obj_label;
public slots:
void clear_move_obj();
void loop_move_obj();
};

#endif // QGAME_MOVE_H


qgame_move.cpp
=====================================================
#include "qgame_move.h"

QGame_move::QGame_move(QPoint startp,QPoint endp,int loop_count,QString end_style,QPixmap image,QWidget *parent) :
QWidget(parent)
{
int i=0;
if(end_style=="DELETE")i=1;
if(end_style=="LOOP")i=2;

move_obj_label=new QLabel(parent);
move_obj_label->setPixmap(image);
move_obj=new QPropertyAnimation(move_obj_label, "pos");
move_obj->setDuration(2000);
move_obj->setStartValue(startp); //起始點
move_obj->setEndValue(endp); //結束點
move_obj->start(QAbstractAnimation:: KeepWhenStopped ); //動畫開始
//move_obj->start(QAbstractAnimation::DeleteWhenStopped);//動畫開始
move_obj->setDirection( QAbstractAnimation::Forward); //向前
//anim1->setDirection( QAbstractAnimation::Backward); //這各用移動完成信號能造成來回移動
move_obj->setLoopCount(loop_count); //重複幾次
switch(i)
{
case 1:connect(move_obj,SIGNAL(finished()),this,SLOT(clear_move_obj()));break;//當物件移動完成信號連結到信號曹清除
case 2:connect(move_obj,SIGNAL(finished()),this,SLOT(loop_move_obj()));break; //當物件移動完成信號連結到信號曹再一次開始移動
}
//anim1->setDirection(QAbstractAnimation::DeleteWhenStopped);

}
void QGame_move::clear_move_obj() //清除移動物件
{
this->move_obj_label->clear();
} //再一次開始移動
void QGame_move::loop_move_obj()
{
this->move_obj->start(QAbstractAnimation:: KeepWhenStopped );
}


這4個例子畫面都從qgame_move類就造出不同動畫,當然還可變化出更多動畫(qgame_move類我又寫進了一些功能,才有下面變化)
類似青蛙過街的畫面:

類似賽車畫面:




類似俄羅斯方塊





(射擊遊戲)



read more...

2010年1月4日 星期一

Qt 4.6強大的QPropertyAnimation功能

我借用QPropertyAnimation寫了一個qgame_move的類(我會在對這個類增強),請看下面簡單的幾行就產生了2個不同的移動圖片,用qt來寫遊戲應該就更簡單了,這是Qt4.6的新功能(是從對岸博客看到的)

QPixmap birdimg=QPixmap(":/new/prefix1/Star.bmp").scaled(40,40);
QPoint p1(0, 360);//開始點
QPoint p2(310, 180);//結束點
QGame_move *a=new QGame_move(p1,p2,birdimg,ui->graphicsView);//動畫產生

QPoint p3(0, 0);
QPoint p4(310, 180);
QGame_move *a1=new QGame_move(p3,p4,birdimg,ui->graphicsView);





qgame_move.h
----------------------------------------------------------------
#ifndef QGAME_MOVE_H
#define QGAME_MOVE_H
#include <QWidget>
#include <QObject>
#include <QLabel>
#include <QPixmap>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>
#include <QParallelAnimationGroup>
#include <QTimer>

class QGame_move : public QWidget {
Q_OBJECT
public:
QGame_move(QPoint startp,QPoint endp,QPixmap image,QWidget *parent = 0);
};

#endif // QGAME_MOVE_H
-----------------------------------------------------------------------------


qgame_move.cpp
-------------------------------------------------------------------------------

#include "qgame_move.h"

QGame_move::QGame_move(QPoint startp,QPoint endp,QPixmap image,QWidget *parent) :
QWidget(parent)
{
QLabel *bird_1=new QLabel(parent);
bird_1->setPixmap(image);
QPropertyAnimation *anim1=new QPropertyAnimation(bird_1, "pos");
anim1->setDuration(2000);
anim1->setStartValue(startp);
anim1->setEndValue(endp);
anim1->start();
}


read more...