用java做坦克游戲_第1頁
用java做坦克游戲_第2頁
用java做坦克游戲_第3頁
用java做坦克游戲_第4頁
用java做坦克游戲_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第一次課一、要做的工作產(chǎn)生一個(gè)800*600的窗口,背景色為綠色。窗口可以被關(guān)閉,但不允許改變大小2、在窗口里畫出一個(gè)紅色的圓代表坦克3、讓坦克動(dòng)起來改變坦克的位置就相當(dāng)于坦克移動(dòng)了,因此首先需要把坦克的位置描述改為變量每重畫一次坦克就動(dòng)一次,讓坦克不斷的動(dòng)就要不斷的重畫,我們用線程來控制二、知識(shí)點(diǎn)1、使用eclipse建立項(xiàng)目,創(chuàng)建包和類的方法2、變量命名規(guī)則:所有命名要求見名知義;類名首字母大小,變量和方法首字母小寫;駝峰標(biāo)識(shí)〔比方類名:TankWar〕3、事件機(jī)制事件包括三個(gè)方面:監(jiān)聽器類,注冊(cè)事件,覆蓋方法監(jiān)聽器類經(jīng)常寫成內(nèi)部類〔包括匿名內(nèi)部類〕或是類本身實(shí)現(xiàn)事件接口事件接口包括actionListener接口、窗口事件接口、鼠標(biāo)事件接口、鍵盤事件接口等等使用事件接口要求把接口的所有方法都寫出,但不一定都實(shí)現(xiàn)窗口事件和鼠標(biāo)鍵盤事件接口還提供了較為簡(jiǎn)潔的適配器類3、匿名內(nèi)部類類可以分為如下幾種:主類:包含主方法的類內(nèi)部類:在一個(gè)類內(nèi)部定義的類為內(nèi)部類實(shí)例內(nèi)部類:在一個(gè)類內(nèi)部獨(dú)立存在,不屬于類的成員變量和方法靜態(tài)內(nèi)部類:用static修飾的實(shí)例內(nèi)部類局部?jī)?nèi)部類:在一個(gè)類的方法內(nèi)定義的類匿名內(nèi)部類:沒有名字的局部?jī)?nèi)部類外部類:包含內(nèi)部類的類,外部類也可能是其他類的內(nèi)部類頂層類:不是任何類的內(nèi)部類為頂層類設(shè)計(jì)內(nèi)部類的主要目標(biāo)是“封裝”。頂層類只能用public修飾或者不修飾〔即默認(rèn)修飾方式〕,內(nèi)部類可以用public,protected,private,默認(rèn)四種方式修飾,局部?jī)?nèi)部類只能用默認(rèn)修飾局部?jī)?nèi)部類和匿名內(nèi)部類只在方法內(nèi)可見,即該類只為該方法提供服務(wù)實(shí)例內(nèi)部類只在一個(gè)類內(nèi)可見,只為該類提供服務(wù)4、利用eclipse重寫父類的方法在eclipse中單擊右鍵,源代碼,生成覆蓋方法。此時(shí)會(huì)列出當(dāng)前類的所有父類,當(dāng)前類可以直接繼承父類的方法。5、圖形的重畫機(jī)制在frame上畫出的圖形每次刷新時(shí)會(huì)重畫,重畫的過程是:系統(tǒng)自動(dòng)調(diào)用repaint方法,repaint調(diào)用update方法,update調(diào)用paint方法,從而完成重畫。6、多線程見第17課詳細(xì)講解三、小注1、我們使用的Frame組件,沒有使用JFrame,因?yàn)镴Frame在后續(xù)畫圖時(shí)不好用,到時(shí)舉例看第二次課要做的工作讓坦克在鍵盤的控制下向四個(gè)方向移動(dòng)我們已經(jīng)寫好一個(gè)坦克并且能夠控制其移動(dòng),如果要求在加入一個(gè)坦克該如何實(shí)現(xiàn)?把坦克做成一個(gè)獨(dú)立的類,把和坦克自身相關(guān)的屬性和方法都寫到坦克類中,然后在tankclient類中生成tank類的對(duì)象,然后用tanke類的對(duì)象調(diào)用坦克類的方法類完成各種功能讓坦克在鍵盤的控制下向八個(gè)方向移動(dòng)如何做出八個(gè)方向?通過四個(gè)方向鍵組合出八個(gè)方向,比方上、右同時(shí)按下是一個(gè)方向。四個(gè)布爾變量代表四個(gè)方向鍵的按下情況,組合出八個(gè)方向,八個(gè)方向用枚舉類型表示。4、優(yōu)化代碼:把一些可能會(huì)改變的值定義成常量知識(shí)點(diǎn)鍵盤事件適配器鍵盤控制坦克移動(dòng)就要使用鍵盤事件,事件三要素:監(jiān)聽器類〔監(jiān)聽接口還是適配器類?寫成內(nèi)部類還是匿名內(nèi)部類?〕,注冊(cè)事件,覆蓋方法〔keypress,keytyped,keyreleased用哪個(gè)方法〕鍵盤代碼如何獲取鍵盤按鍵代碼:e.getKeyCode()Switch語句:格式,case后能跟什么樣的變量?沒有break會(huì)怎樣?加入鍵盤事件后可否去掉多線程?面向?qū)ο缶幊趟枷耄阂磺薪詾閷?duì)象。對(duì)項(xiàng)目進(jìn)行抽象,形成假設(shè)干個(gè)類,然后生成對(duì)象來實(shí)現(xiàn)程序功能把坦克抽象成一個(gè)類,把坦克的屬性描述為成員變量,把坦克的行為描述為方法。這樣就把坦克相關(guān)的屬性和方法都封裝到一個(gè)類中,屬性一般設(shè)計(jì)為私有,通過set和get方法訪問,方法一般為public,供對(duì)象調(diào)用,從而實(shí)現(xiàn)各種功能。構(gòu)造方法構(gòu)造方法用來描述一個(gè)對(duì)象剛生成時(shí)的狀態(tài)。調(diào)用構(gòu)造方法才能生成對(duì)象。一個(gè)類必須有構(gòu)造方法,構(gòu)造方法有三種情況super(xxx): 第一句調(diào)用父類的構(gòu)造方法this(xxx): 第一句調(diào)用本類的其他構(gòu)造方法super(): 第一句沒有調(diào)用任何其他的構(gòu)造方法,系統(tǒng)會(huì)自動(dòng)加上這句,去調(diào)用父類的無參構(gòu)造方法〔如果父類沒有無參構(gòu)造方法,那么子類會(huì)出錯(cuò)〕任何一個(gè)構(gòu)造方法必然屬于上述三者之一。任何一個(gè)類都必須提供一個(gè)空的構(gòu)造方法枚舉類型Tiger中的一個(gè)重要新特性是枚舉構(gòu)造,它是一種新的類型,允許用常量來表示特定的數(shù)據(jù)片斷,而且全部都以類型安全的形式來表示。Java代碼的兩個(gè)基本的構(gòu)造塊是類和接口。現(xiàn)在Tiger又引入了枚舉,一般簡(jiǎn)稱它為enum。這個(gè)新類型允許您表示特定的數(shù)據(jù)點(diǎn),這些數(shù)據(jù)點(diǎn)只接受分配定義枚舉enumDirection{U,D,R,L,RU,RD,LU,LD,STOP};在這里,我使用了新的關(guān)鍵字enum,為enum提供了一個(gè)名稱,并指定了允許的值。然后,Direction就變成了一個(gè)枚舉類型,使用枚舉類型privateDirectiondirection=Direction.STOP;用以前定義過的類型〔Direction〕建立一個(gè)新的枚舉〔direction〕之后,您就可以像使用其他成員變量一樣使用它了。當(dāng)然,枚舉只能分配枚舉值中的一個(gè)〔例如,U,D,R等〕小注注意把坦克做成類后,程序的改變。第三次課要做的工作添加子彈類新建一個(gè)Missile類作為子彈類設(shè)計(jì)子彈類的屬性和方法要求子彈能夠根據(jù)某個(gè)方向移動(dòng)在主類中畫出一個(gè)子彈,進(jìn)行測(cè)試要求按下ctrl鍵讓坦克打出子彈,并且讓子彈沿著坦克移動(dòng)的方向運(yùn)動(dòng)在坦克的keyPress方法中加入ctrl鍵響應(yīng),產(chǎn)生一顆子彈。寫一個(gè)attack方法,在此處生成一個(gè)Missile對(duì)象。在ctrl響應(yīng)中調(diào)用該方法問題:上述方案無法打出子彈,因?yàn)闆]有畫出子彈,兩個(gè)地方可以調(diào)用draw方法畫出子彈,tank類里的paint方法,tankwar1里的paint方法。我們?cè)趖anjwar1里做,因?yàn)楸M量把所有對(duì)象都定義到tankwar1里,這樣好管理。在tankwar1中定義一個(gè)子彈引用,在tank中生成子彈對(duì)象,那么如何把tank中的子彈對(duì)象傳遞到tankwar1中。讓tank持有tankwar1的引用,然后把tankwar1的對(duì)象傳遞給坦克里的tankwar1的引用。記住這種傳遞對(duì)象的方法。子彈從坦克中心打出坦克的位置是x,y,又知道坦克和子彈的半徑,由此求出子彈的位置。坦克停止時(shí)也能打出子彈子彈是根據(jù)坦克的方向飛行的,所以當(dāng)坦克停止時(shí)子彈也就停止了。如何讓坦克停止時(shí)也能打出子彈呢,就是想方法記錄坦克剛剛的行動(dòng)方向。我們用一個(gè)炮筒方向來記錄坦克的移動(dòng)方向。給坦克增加一個(gè)屬性ptDir,代表炮筒方向炮筒用一條直線來表示,這條直線根據(jù)坦克的移動(dòng)方向來畫出。即坦克向右走時(shí)就畫一條向右的線,向左走就畫一條向左的線,停止時(shí)就保留上一次的方向。子彈的發(fā)射方向跟據(jù)炮筒方向來定知識(shí)點(diǎn)枚舉類型的用法枚舉就是用enum定義一個(gè)新的數(shù)據(jù)類型,該類型的取值范圍是幾個(gè)常量,用該類型可以定義變量,變量的取值就在限定在上述的常量中在Tank中我們定義了一個(gè)枚舉類型Direction,在Missile中我們用該類型定義個(gè)變量dir,該變量是一個(gè)枚舉類型變量,可取Direction枚舉類型中列舉的常量之一。A類中定義的變量如何獲得B類中生成的對(duì)象。在A中定義好要獲取的對(duì)象的引用,然后讓B持有A的引用,在B中生成對(duì)象賦給A的引用畫線的方法小注第四次課:要做的工作:打出多發(fā)子彈創(chuàng)建容器——集合框架每次按下ctrl鍵都往容器中加入一個(gè)子彈逐一畫出每發(fā)子彈刪掉子彈:當(dāng)子彈飛出窗口時(shí)要?jiǎng)h掉,如果不刪掉那么容器中的子彈會(huì)越來越多,最后會(huì)導(dǎo)致內(nèi)存崩潰。如何判斷子彈飛出邊界?找出四個(gè)邊界從容器中remove一個(gè)子彈,此處又涉及到在Missile類中持有TankWar的對(duì)象問題。坦克的邊界問題,讓坦克不能走出邊界注意上邊界有標(biāo)題欄,需要考慮?;貞浺郧暗墓ぷ?,適當(dāng)加注釋知識(shí)點(diǎn)集合框架——見第17課范型:在生命集合變量和創(chuàng)建集合對(duì)象時(shí),可以使用“<>”標(biāo)記指定集合的范型,即指定集合中元素的類型。類的繼承與接口的實(shí)現(xiàn)小注注意import不同包下同名類的引發(fā)的問題。例如我們程序中使用List類,引入語句里有importjava.awt.*;和importjava.util.*,此時(shí)使用List就會(huì)出現(xiàn)問題,因?yàn)樯鲜鰞蓚€(gè)包中都有List類,此時(shí)eclipse不知道該使用哪個(gè),所以出錯(cuò)。應(yīng)該明確指明importjava.util.List;就可以了。迭代器的問題在創(chuàng)建迭代器之后,除非通過迭代器自身的remove或add方法從結(jié)構(gòu)上對(duì)列表進(jìn)行修改,否則在任何時(shí)間以任何方式對(duì)列表進(jìn)行修改,迭代器都會(huì)拋出ConcurrentModificationException第五次課要做的工作加入一個(gè)敵方坦克是否需要?jiǎng)?chuàng)建敵方坦克類?加入一個(gè)標(biāo)記坦克好壞的變量,然后修改構(gòu)造方法在主類中創(chuàng)建敵方坦克用顏色區(qū)分?jǐn)澄姨箍宋曳教箍税l(fā)出炮彈擊毀敵方坦克是誰擊毀敵方坦克,我方坦克還是炮彈?如何檢測(cè)炮彈是否擊中坦克?炮彈和坦克都有一個(gè)外切矩形,如果這兩個(gè)矩形相交則證明炮彈擊中坦克,否則沒有擊中。用Rectangle類可以獲取外切矩形,分別獲得子彈和坦克的外切矩形,然后用該類的intersects方法判斷矩形是否相交Missile類中加入hitTank方法,該方法有無參數(shù)?有無返回值?hitTank方法中擊中坦克后應(yīng)該有哪些反應(yīng)?坦克消失:不再重畫坦克就可以了,因此每次重畫坦克之前先判斷坦克是否已經(jīng)死了,死了則直接返回不再重畫。所以坦克應(yīng)該加入一個(gè)標(biāo)記生死的變量。子彈消失:不再重畫子彈并且從容器中remove掉。與處理坦克方式類似,需注意remove掉子彈時(shí)不能引發(fā)異常。小問題:擊斃坦克后,向相同位置發(fā)射炮彈,炮彈仍然會(huì)消失,因?yàn)槲覀冸m然不再重畫坦克,但是坦克仍然在原來位置上存在。什么時(shí)候有誰來調(diào)用hitTank方法知識(shí)點(diǎn)Rectangle類:Rectangle指定了坐標(biāo)空間中的一個(gè)區(qū)域,通過Rectangle對(duì)象的左上頂點(diǎn)的坐標(biāo)〔x,y〕、寬度和高度可以定義這個(gè)區(qū)域。構(gòu)造方法:Rectangle(int

x,int

y,int

width,int

height)

構(gòu)造一個(gè)新的Rectangle,其左上角被指定為〔x,y〕,而其寬度和高度由同名稱的參數(shù)指定其他方法:intersects(\o"java.awt中的類"Rectangle

r)

確定此Rectangle是否與指定Rectangle相交。Get,Set方法這兩個(gè)方法提供了對(duì)一個(gè)類的私有變量訪問的途徑。一個(gè)類提供變量和方法,方法一般是公有的,變量是私有的,即變量不允許外界擅自訪問,如要訪問必須使用類自身的set,get方法。小注第六課:加入爆炸效果要做的工作爆炸類:子彈擊中坦克產(chǎn)生一個(gè)爆炸的效果,這個(gè)效果我們用一個(gè)逐漸變大然后變小的圓來表示。我們把爆炸也抽象為一個(gè)類。該類所具有屬性和方法有哪些?爆炸地點(diǎn)x,y;爆炸是有生命的live,畫出爆炸的方法寫完爆炸類后先測(cè)試一下,在主類生成一個(gè)爆炸類對(duì)象,看能否畫出爆炸效果可能同時(shí)會(huì)有多出發(fā)生爆炸,因此我們把爆炸對(duì)象放入一個(gè)容器中,然后不斷從容器中取出爆炸對(duì)象然后畫出爆炸何時(shí)死?爆炸之后從容器中remove調(diào)整爆炸的出現(xiàn)位置,讓圓有同一個(gè)圓心:每次畫圓都是以x,y為左上角點(diǎn),調(diào)整x,y的位置即可給爆炸添加聲音知識(shí)點(diǎn)數(shù)組作為圓的半徑由于要畫出一系列大小不一的圓來顯示爆炸效果,因此用數(shù)組來作為圓半徑集合框架調(diào)試錯(cuò)誤,設(shè)置一處錯(cuò)誤調(diào)試〔去掉子彈類生成對(duì)象時(shí)的tw參數(shù)〕。此時(shí)每次調(diào)用hitTank都會(huì)出現(xiàn)空指針錯(cuò)誤。調(diào)試找出該錯(cuò)誤。圖片處理Java中能識(shí)別的圖片有g(shù)if和jpg兩種格式,用圖片主要有兩個(gè)場(chǎng)合:圖形界面中即在組件中使用,比方按鈕上加一個(gè)圖標(biāo),標(biāo)簽組件加一個(gè)圖片等。此時(shí)需要首先獲得一個(gè)ImageIcon對(duì)象〔ImageIcon類能根據(jù)URL、文件名或字節(jié)數(shù)組創(chuàng)建一個(gè)圖像〕,然后用組件的setIcon方法加入。ImageIconimage=newImageIcon〔”圖片路徑”〕;jButton.setIcon(image);圖形處理中圖片不是加到組件上,而是畫在某個(gè)地方,比方畫到窗口〔Frame或JFrame〕內(nèi)。此時(shí)先獲得一個(gè)Image對(duì)象〔Image類是一個(gè)抽象類,不能實(shí)例化,我們可以借助ImageIcon來得到一個(gè)Image對(duì)象〕Imageimage=newImageIcon〔”圖片路徑”〕.getImage(); 得到了一個(gè)圖片對(duì)象后,接下來,如何把該圖片畫出來?使用Graphics類提供的drawImage()方法,它能完成將Image對(duì)象中的圖像顯示在屏幕的特定位置上,就象顯示文本一樣方便。 drawImage()方法的調(diào)用格式如下: booleandrawImage(Imageimg,intx,inty,ImageObserverobserver)其中img參數(shù)就是要顯示的Image對(duì)象。x和y參數(shù)是該圖像左上角的坐標(biāo)值。observer參數(shù)則是一個(gè)ImageObserver接口〔interface〕,它用來跟蹤圖像文件裝載是否已經(jīng)完成的情況,通常我們都將該參數(shù)置為this,即傳遞本對(duì)象的引用去實(shí)現(xiàn)這個(gè)接口。在paint方法中,下句則會(huì)畫出一個(gè)image圖片。 g.drawImage(image,20,10,this);注:路徑問題 圖片路徑分為絕對(duì)路徑和相對(duì)路徑絕對(duì)路徑:ImageIconimage=newImageIcon〔””〕; 相對(duì)路徑:ImageIconimage=newImageIcon〔””〕; 相對(duì)路徑中的image文件夾在eclipse中建立〔項(xiàng)目右鍵建立一個(gè)文件夾〕,然后把圖片文件放入該文件夾聲音處理原來,Applet包中提供了AudioClip類處理程序,現(xiàn)在applet已經(jīng)被淘汰,而且應(yīng)用程序不支持AudioClip類,所以該類也基本不再使用?,F(xiàn)在,理類。importsun.audio.*;importsun.audio.*;importjava.io.*;publicclassSound{ publicstaticvoidmain(Stringargs[]) { try{ FileInputStreamfileau=newFileInputStream("d://2.wav"); AudioStreamas=newAudioStream(fileau); AudioPlayer.player.start(as); } catch(Exceptione){} }}小注爆炸效果用gif圖片來表示第六課補(bǔ)充:IO操作,見第十七章第七課:要做的工作生成多輛坦克多輛坦克需要放到一個(gè)容器內(nèi),所以先做一個(gè)容器New出多輛敵方坦克,然后加到容器中。該語句寫在哪個(gè)方法合適畫出多輛坦克,從容器中依次取出坦克,然后調(diào)用paint方法畫出擊斃坦克原來擊斃的是一輛坦克〔調(diào)用hitTank〔enemy〕有針對(duì)性的擊斃〕,現(xiàn)在坦克都放在容器中,而且是多輛,如何擊斃?把容器的坦克都取出來,依次hitTank〔〕,子彈和誰相交就擊斃誰??梢詫懸粋€(gè)hitTanks方法,依次取出坦克后調(diào)用hitTank方法。讓敵方坦克自己移動(dòng)坦克每次重畫都會(huì)調(diào)用move方法,move方法會(huì)根據(jù)坦克的方向改變x,y的值,因此我們只要不斷改變敵方坦克的方向就可以了不斷改變敵方坦克的方向需要隨機(jī)的變換方向,用Random類實(shí)現(xiàn)。隨機(jī)數(shù)和方向如何建立聯(lián)系?如何控制走隨機(jī)步數(shù)后改變一次方向?讓敵方坦克發(fā)炮彈我方坦克發(fā)炮彈是通過ctrl鍵,每次按下ctrl鍵就調(diào)用fire方法發(fā)出一發(fā)炮彈,敵方坦克什么時(shí)候發(fā)出炮彈?隨機(jī)發(fā)炮彈——把fire方法的調(diào)用寫入隨機(jī)移動(dòng)的代碼塊內(nèi)就可以了。此時(shí)發(fā)現(xiàn)敵方坦克會(huì)發(fā)出炮彈了,但是會(huì)炸掉自己,因?yàn)榕趶椫灰吞箍讼嘟痪蜁?huì)炸毀,如何做到敵方坦克不打自己?坦克區(qū)分好壞,讓子彈也區(qū)分好壞,這樣再打的時(shí)候判斷一下坦克和子彈都好或者都?jí)木筒淮?,否則打敵方坦克無法擊毀我方坦克,為什么?知識(shí)點(diǎn)構(gòu)造方法重載,好坦克用一個(gè)構(gòu)造方法,壞坦克用另一個(gè),因?yàn)閴奶箍诵枰覀冎付ㄋ某跏挤较?。?gòu)造方法里寫一個(gè)對(duì)象剛生成時(shí)具有的特性。構(gòu)造方法的三種形式Random類:首先生成一個(gè)Random對(duì)象:Randomr=newRandom();然后調(diào)用方法產(chǎn)生隨機(jī)數(shù):intrn=r.nextInt(10);,rn就是0到9之間的一個(gè)隨機(jī)數(shù)字另:Math.random()方法:返回帶正號(hào)的double值,大于或等于0.0,小于1.0。枚舉類:枚舉類有一個(gè)values方法,以數(shù)組的方式返回一個(gè)枚舉類型的所有常量。Direction[]dirs=dir.values();,dirs就是一個(gè)數(shù)組,每個(gè)數(shù)組分量就代表一個(gè)枚舉里的方向常量,即一個(gè)方向。小注第八課:要做的工作用坦克圖片代替圓形表示的坦克坦克可以朝八個(gè)方向走,所以需要八個(gè)方向的坦克圖片各一張畫出坦克圖片需要用到哪個(gè)方法?這個(gè)方法寫到什么地方?每個(gè)方向都需要一張圖片,共八張。我們使用數(shù)組來存放這八張圖片數(shù)組定義改成靜態(tài)的可以嗎?靜態(tài)的和原來的有什么區(qū)別?用hashmap建立圖片和字符之間的聯(lián)系讓坦克不能相互穿越坦克相交時(shí)停下,然后改變方向即可知識(shí)點(diǎn)eclipse中如何引入圖片?項(xiàng)目上單擊右鍵新建文件夾,然后再磁盤目錄里找到該文件夾,把圖片考入?;蛘?,把圖片直接拖放到eclipse中該文件夾下數(shù)組的初始化〔1〕Int[]x=newint[5];然后for循環(huán)初始化〔2〕Int[]x=newint[]{1,2,3,4,5}聲明同時(shí)初始化〔3〕Int[]x={1,2,3,4,5}聲明同時(shí)初始化〔4〕Staticintx;Static{x=newint[]{1,2};}Static的用法修飾成員變量表示靜態(tài)變量〔類變量〕靜態(tài)變量在內(nèi)存中只有一個(gè)拷貝,在加載類的過程中完成對(duì)其的內(nèi)存分配Java不提供全局變量,靜態(tài)變量可以代替全局變量。靜態(tài)變量可以被類的所有實(shí)例對(duì)象共享通過類名直接訪問靜態(tài)變量修飾成員方法表示靜態(tài)方法〔類方法〕在加載類的過程中完成對(duì)其的內(nèi)存分配靜態(tài)方法可以訪問靜態(tài)變量和靜態(tài)方法,不可訪問實(shí)例變量和實(shí)例方法通過類名直接訪問靜態(tài)方法修飾代碼塊表示靜態(tài)代碼塊類中可以有靜態(tài)代碼塊,它不存在于任何方法中,在加載類時(shí)會(huì)執(zhí)行靜態(tài)代碼塊小注第九課:要做的工作、敵方坦克不可互相穿越敵方坦克相遇時(shí)就停下,然后轉(zhuǎn)換方向再走知識(shí)點(diǎn)小注第十課、網(wǎng)絡(luò)見教案第19課第十一課、聊天室程序基本原理C/S結(jié)構(gòu)包括兩個(gè)方面服務(wù)器和客戶端,因此我們要寫兩個(gè)程序,一個(gè)運(yùn)行在服務(wù)器,一個(gè)運(yùn)行在客戶端。服務(wù)器運(yùn)行后等待客戶端連入,客戶端根據(jù)服務(wù)器的IP和端口連入,這樣服務(wù)器和客戶端就建立了一個(gè)連接,而且可以有多個(gè)客戶端連入服務(wù)器。每個(gè)客戶端的發(fā)言都發(fā)送給服務(wù)器,服務(wù)器接收后然后轉(zhuǎn)發(fā)給所有連入的客戶端,這樣每個(gè)客戶端就都能收到其他客戶端發(fā)出的信息了。這就是C/S結(jié)構(gòu)聊天室的工作過程。其實(shí)現(xiàn)主要使用如下兩種技術(shù):Socket:網(wǎng)絡(luò)套接字,讓兩個(gè)應(yīng)用程序通過一個(gè)雙向的網(wǎng)絡(luò)通信鏈接實(shí)現(xiàn)數(shù)據(jù)交換。即服務(wù)器和客戶端的應(yīng)用程序各有一個(gè)Socket,這兩個(gè)Socket把服務(wù)器和客戶端的程序連接起來并交換數(shù)據(jù)。多線程:因?yàn)橐粋€(gè)服務(wù)器要連入多個(gè)客戶端,因此服務(wù)器程序需要為每個(gè)客戶端開辟一個(gè)線程,專為該客戶服務(wù)。此外,客戶端不僅要發(fā)送信息給服務(wù)器,還要不斷接收服務(wù)器轉(zhuǎn)發(fā)過來的信息,因此也需要開辟一個(gè)線程專門負(fù)責(zé)接收服務(wù)器的信息。程序?qū)崿F(xiàn)服務(wù)器端建一個(gè)ChartServer類,在該類中,首先定義一個(gè)ServerSocket,并指明端口號(hào),然后不斷偵聽接收客戶端的請(qǐng)求,收到請(qǐng)求則把客戶端傳來的Socket放入一個(gè)HashSet中保存,并啟動(dòng)一個(gè)線程負(fù)責(zé)該客戶,在線程中接收客戶的信息并轉(zhuǎn)發(fā)給HashSet中所有的客戶。代碼如下://服務(wù)器端程序//服務(wù)器端程序publicclassChartServer{ privateHashSet<Socket>clients=newHashSet<Socket>();//存放客戶端Socket publicChartServer(){ try{ ServerSocketss=newServerSocket(6666);//建立Socket while(true){ Sockets=ss.accept(); //等待并接收客戶端請(qǐng)求 clients.add(s);//把收到的客戶端Socket保存 newServerThread(s,clients).start();//啟動(dòng)一個(gè)線程接收該客戶信息 } }catch(IOExceptione){ e.printStackTrace(); } } //線程,負(fù)責(zé)接收客戶信息并轉(zhuǎn)發(fā)給其他客戶 classServerThreadextendsThread{ privateSockets; privateHashSetclients; publicServerThread(Sockets,HashSetclients){ this.s=s; this.clients=clients; } publicvoidrun(){ try{ BufferedReaderbr=newBufferedReader(newInputStreamReader(s.getInputStream())); while(true){ sendMessage(br.readLine()+"\n"); } }catch(IOExceptione){ e.printStackTrace(); } } //給每個(gè)客戶發(fā)送一份信息 privatevoidsendMessage(Stringstr){ Iteratorit=clients.iterator(); while(it.hasNext()){ Sockettemp=(Socket)it.next(); try{ PrintWriterpw=newPrintWriter(temp.getOutputStream()); pw.println(str); pw.flush(); }catch(IOExceptione){ e.printStackTrace(); } } } } publicstaticvoidmain(String[]args){ newChartServer(); }}客戶端聊天室客戶端建一個(gè)ChartClient類作為客戶端程序。運(yùn)行后如下列圖:聊天室客戶端//客戶端程序publicclassChartClientextendsJFrame{ privateJTextAreajta; privateJTextFieldjtf; privateJButtonjb;//客戶端程序publicclassChartClientextendsJFrame{ privateJTextAreajta; privateJTextFieldjtf; privateJButtonjb; privateJLabelname; privateSockets; privatePrintWriterpw; privateBufferedReaderbr; privateDateFormatformat; privateDatedate=newDate(); //構(gòu)造方法,建立界面,初始化工作 publicChartClient(){ this.setSize(300,350); this.setTitle("聊天室"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jta=newJTextArea(15,20); jtf=newJTextField(15); jb=newJButton("發(fā)送"); name=newJLabel(""); JPaneljp=newJPanel(); jp.setLayout(newFlowLayout()); jp.add(name); jp.add(jtf); jp.add(jb); jb.addActionListener(newSendMessage()); this.setLayout(newBorderLayout())

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論