鴻蒙開(kāi)源第三方組件—游戲框架JustWeEngine
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
JustWeEngine
本項(xiàng)目是基于開(kāi)源項(xiàng)目JustWeEngine進(jìn)行ohos化的移植和開(kāi)發(fā)的,可以通過(guò)項(xiàng)目標(biāo)簽以及github地址(https://github.com/lfkdsk/JustWeEngine )追蹤到原項(xiàng)目版本
項(xiàng)目介紹
- 項(xiàng)目名稱(chēng):JustWeEngine
- 所屬系列:ohos的第三方組件適配移植
- 功能:JustWeEngine是托管在Gitee 的一個(gè)開(kāi)源的Ohos原生開(kāi)發(fā)框架,可以讓Ohos的開(kāi)發(fā)人員非常便捷,無(wú)需切換語(yǔ)言和編譯器的制作Ohos原生游戲
- 項(xiàng)目移植狀態(tài):完成
- 調(diào)用差異:無(wú)
- 原項(xiàng)目基線(xiàn)版本:v1.13
- 編程語(yǔ)言:Java
效果展示
安裝教程
方法1.
- 編譯har包JustWeEngine.har。
- 啟動(dòng) DevEco Studio,將編譯的har包,導(dǎo)入工程目錄“entry->libs”下。
- 在moudle級(jí)別下的build.gradle文件中添加依賴(lài),在dependences標(biāo)簽中增加對(duì)libs目錄下har包的引用。
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
- ……
- }
4.在導(dǎo)入的har包上點(diǎn)擊右鍵,選擇“Add as Library”對(duì)包進(jìn)行引用,選擇需要引用的模塊,并點(diǎn)擊“OK”即引用成功。
方法2.
1.在工程的build.gradle的allprojects中,添加HAR所在的Maven倉(cāng)地址(等maven發(fā)布后進(jìn)行修改)
- repositories {
- maven {
- url 'https://s01.oss.sonatype.org/content/repositories/releases/'
- }
- }
2.在應(yīng)用模塊的build.gradle的dependencies閉包中,添加如下代碼:(等maven發(fā)布后進(jìn)行修改)
- dependencies {
- implementation 'io.github.dzsf:just-we-engine:1.0.1'
- }
使用說(shuō)明
1.基礎(chǔ)功能
- 1.1繼承引擎核心類(lèi)
- 1.2繪制文字
- 1.3繪制圖片
- 1.4使用精靈
- 1.5使用按鈕
2.動(dòng)畫(huà)系統(tǒng)
- 2.1綁定在BaseSub物品及精靈基類(lèi)上的動(dòng)畫(huà)類(lèi)
- 2.2綁定在Button上的動(dòng)畫(huà)類(lèi)
3.物體分組碰撞檢測(cè)和死亡判定
4.屏幕掃描模式
5.工具類(lèi)
6.音頻系統(tǒng)
- 6.1播放短音效
- 6.2播放音頻
- 6.3通過(guò)短音效編曲
進(jìn)階應(yīng)用
7.使用網(wǎng)絡(luò)
8.使用狀態(tài)機(jī)精靈
9.CrashHandler崩潰守護(hù)
10.使用藍(lán)牙
- 10.1開(kāi)啟、關(guān)閉服務(wù)
- 10.2掃描設(shè)備
- 10.3發(fā)送消息
11.SQLite數(shù)據(jù)庫(kù)
- 11.1創(chuàng)建表
- 11.2增刪查改
基礎(chǔ)功能
繼承引擎核心類(lèi):
由于框架全部使用SurfaceView進(jìn)行繪制,不使用諸如Button、Layout等原生控件,所以應(yīng)該首先新建類(lèi)繼承引擎核心類(lèi)Engine,負(fù)責(zé)游戲的流程,注釋中已有明確的標(biāo)明功能。
- public class MainAbility extends Engine implements Runnable, Component.TouchEventListener, Component.DrawTask {
- // 一般在構(gòu)造函數(shù)完成變量的初始化
- public MainAbility() {
- }
- public void onStart(Intent intent) {
- // 調(diào)用初始化方法
- init();
- }
- // 載入一些UI參數(shù)和設(shè)置屏幕放向,默認(rèn)背景色,設(shè)定屏幕的掃描方式等
- public void init() {
- // 初始化UI默認(rèn)參數(shù),必須調(diào)用該方法,其中有一些用于多機(jī)型適配的參數(shù)需要初始化
- UIdefaultData.init(this);
- }
- // 通常用于精靈,背景,圖片等物體的設(shè)置和載入
- public void load() {
- }
- // draw 和 update 在線(xiàn)程中進(jìn)行不斷的循環(huán)刷新
- // draw 負(fù)責(zé)繪制 update 負(fù)責(zé)更新數(shù)據(jù)和對(duì)象信息
- public void draw() {
- }
- public void update() {
- }
- // 將touch 事件傳回 功能和所設(shè)定的屏幕掃描方式有關(guān)
- public void touch(TouchEvent event) {
- }
- // 將碰撞事件傳回 傳回精靈和物品的基類(lèi)
- // 用于處理碰撞事件 默認(rèn)使用矩形碰撞
- public void collision(BaseSub baseSub) {
- }
- }
繪制文字:
使用GamePrinter進(jìn)行文字繪制,除此以外還有多種方法繪制:
- @Override
- public void draw() {
- Canvas canvas = getCanvas();
- GameTextPrinter printer = new GameTextPrinter(canvas);
- printer.drawText("哈哈哈", 100, 100);
- }
繪制圖片:
建議圖片存放在Resources中:
- GameTexture texture = new GameTexture(this);
- texture.loadFromAsset("resources/base/graphic/shoot.png")
- texture.draw(canvas, 100, 100);
另外也可使用loadFromAssetStripFrame從一個(gè)大的圖片中取出對(duì)應(yīng)位置的圖片。
- /**
- * get bitmap from a big bitmap
- *
- * @param filename
- * @param x
- * @param y
- * @param width
- * @param height
- * @return
- */
- public boolean loadFromAssetStripFrame(String filename,
- int x, int y,
int width, int height)
PicUtils中提供了在Bitmap處理中很有用的各種特效和壓縮方法,大家可以一試。
使用精靈:
使用精靈可以使用BaseSprite也可以繼承該類(lèi)使用,BaseSprite封裝了很多方法供各種動(dòng)畫(huà)使用,這些功能很多都是需要結(jié)合動(dòng)畫(huà)系統(tǒng)來(lái)使用的,動(dòng)畫(huà)系統(tǒng)會(huì)在后面介紹。
新建精靈:
1.簡(jiǎn)單初始化:
- sprite = new BaseSprite(this);
2.初始化連續(xù)幀動(dòng)畫(huà):
連續(xù)幀的初始化需要連續(xù)的幀圖片。
- GameTexture texture = new GameTexture(this);
- texture.loadFromAsset("resources/base/graphic/flare.png");
- // 長(zhǎng)寬以及列數(shù)
- sprite = new BaseSprite(this, 96, 96, 8);
- sprite.setTexture(texture);
- sprite.setPosition(100, 100);
- sprite.setDipScale(100, 100);
- // 幀切換動(dòng)畫(huà)是關(guān)鍵
- sprite.addAnimation(new FrameAnimation(0, 63, 1));
- addToSpriteGroup(sprite);
3.使用從大圖取出的多幀圖片:
- // 新建圖片資源(此圖為上圖的大圖)
- GameTexture texture = new GameTexture(this);
- texture.loadFromAsset("resources/base/graphic/shoot.png");
- // 初始化設(shè)定模式和長(zhǎng)寬
- ship = new BaseSprite(this, 100, 124, FrameType.COMMON);
- // 設(shè)定資源
- ship.setTexture(texture);
- // 從大圖中取出兩幀
- ship.addRectFrame(0, 100, 100, 124);
- ship.addRectFrame(167, 361, 100, 124);
- ship.addAnimation(new FrameAnimation(0, 1, 1));
4.一些重要的其他設(shè)定:
- // 圖片資源
- ship.setTexture(texture);
- // 大圖取幀模式
- ship.addRectFrame(0, 100, 100, 124);
- // 設(shè)定位置
- ship.setPosition(x, y);
- // 設(shè)置dp大小
- ship.setDipScale(96, 96);
- // 設(shè)定dp位置
- ship.setDipPosition(x, y);
- // 設(shè)定透明度
- ship.setAlpha(...);
- // 只有將精靈添加到SpriteGroup中框架才會(huì)自行繪制,否則需要手動(dòng)調(diào)用
- addToSpriteGroup(ship);
- ...
使用按鈕:
使用的按鈕可以繼承BaseButton進(jìn)行拓展,也可以直接使用TextureButton和TextButton進(jìn)行使用。
Button設(shè)定功能的方式和原生一樣,通過(guò)設(shè)定接口回調(diào)的方式進(jìn)行:
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick() {
- Log.e("button", "onClick");
- }
- });
TextureButton:
- TextureButton button;
- // 初始化并設(shè)定名字
- button = new TextureButton(this, "logo");
- texture = new GameTexture(this);
- texture.loadFromAsset("resources/base/graphic/logo.jpg");
- // 添加圖片資源
- button.setTexture(texture);
- // button的接口回調(diào),不是View的那個(gè)接口
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick() {
- Log.e("button", "onClick");
- }
- });
- button.setPosition(200, 300);
- button.setDipScale(100, 150);
- // 添加到ButtonGroup進(jìn)行繪制和處理
- addToButtonGroup(button);
結(jié)合PicUtil中的各種Bitmap處理方法可以很容易的做出各種樣式的Button。
TextButton:
TextButton button;
- TextButton button;
- button = new TextButton(this, "logo");
- button.setText("劉豐愷");
- addToButtonGroup(button);
- // 余略見(jiàn)源碼
- ...
動(dòng)畫(huà)系統(tǒng)
目前的動(dòng)畫(huà)系統(tǒng)可以使用已經(jīng)封裝好的繼承了BaseAnimation的動(dòng)畫(huà),也可以繼承BaseAnim進(jìn)行自我定義動(dòng)畫(huà)類(lèi)進(jìn)行使用。
綁定在BaseSub物品及精靈基類(lèi)上的動(dòng)畫(huà)類(lèi)
AnimType中保存了Animation的應(yīng)用類(lèi)型。
綁定動(dòng)畫(huà)分為兩類(lèi),ListAnimation和FixedAnimation,ListAnimation將動(dòng)畫(huà)存儲(chǔ)到固定的一個(gè)List中,用于重復(fù)更新的動(dòng)畫(huà),
而FixedAnimation存儲(chǔ)在Map中,使用名字進(jìn)行調(diào)用,用于點(diǎn)擊或者非自動(dòng)更新的動(dòng)畫(huà)。
比如前面精靈類(lèi)動(dòng)畫(huà)的就是添加到ListAnimation。
下面的這種寫(xiě)法就是FixedAnimation,這個(gè)動(dòng)畫(huà)是飛機(jī)入場(chǎng),因?yàn)橹皇褂昧艘淮?,所以使用了FixedAnimation。
- ship.addfixedAnimation("start",
- new MoveAnimation(UIdefaultData.centerInHorizontalX - ship.getWidthWithScale() / 2,
- UIdefaultData.screenHeight - 2 * ship.getHeightWidthScale(), new Float2(10, 10)));
綁定在Button上的動(dòng)畫(huà)類(lèi)
BaseButtonAnimation是BaseButton的動(dòng)畫(huà)類(lèi)繼承了BaseAnim的動(dòng)畫(huà)基類(lèi),通過(guò)提供Button的狀態(tài),設(shè)定Button的動(dòng)畫(huà)。
為Button設(shè)定放縮動(dòng)畫(huà):
- // 設(shè)定中心放縮
- button.setZoomCenter(true);
- // 三個(gè)參數(shù) 初始值/放大值/幀數(shù)
- button.setAnimation(new ZoomCenterButtonAnim(10, 30, 3));
為Button設(shè)定顏色動(dòng)畫(huà):
- // 初始顏色 / 按下顏色
- button.setAnimation(
- new ColorAnimation(UIdefaultData.colorAccent,
- UIdefaultData.colorPressed));
物體分組碰撞檢測(cè)和死亡判定
使用設(shè)置ID和Name進(jìn)行物體分組,通過(guò)物體分組,框架核心類(lèi)會(huì)對(duì)對(duì)象進(jìn)行分類(lèi)處理。
- final int SHIP = 0;
- ship.setName("SHIP");
- ship.setIdentifier(SHIP);
只要使用了addToSpriteGroup(sprite)的精靈對(duì)象就會(huì)自動(dòng)進(jìn)行碰撞檢測(cè),而對(duì)碰撞檢測(cè)的結(jié)果會(huì)從
collision中進(jìn)行發(fā)回。
- @Override
- public void collision(BaseSub baseSub) {
- // 獲取與之碰撞的對(duì)象
- BaseSprite other = (BaseSprite) baseSub.getOffender();
- // 獲取ID分組處理
- if (baseSub.getIdentifier() == BULLET &&
- other.getIdentifier() == ENEMY) {
- // 設(shè)定死亡
- other.setAlive(false);
- // 回收
- removeFromSpriteGroup(other);
- addToRecycleGroup(other);
- }
- }
其中g(shù)etOffender()獲得與之碰撞的對(duì)象,通過(guò)getIdentifier()獲取設(shè)定的對(duì)象分組,實(shí)行邏輯判斷。
開(kāi)啟Debug模式會(huì)看見(jiàn)碰撞線(xiàn)。
屏幕掃描模式
屏幕掃描模式是用來(lái)優(yōu)先響應(yīng)屏幕點(diǎn)擊、Button點(diǎn)擊、和多點(diǎn)觸控而設(shè)的,放置在不同情況下都能優(yōu)化屏幕的刷新。
- // 檢測(cè)單一移動(dòng)
- SINGLE,
- // 檢測(cè)Button
- BUTTON,
- // 多點(diǎn)檢測(cè)
- FULL,
- // 單擊+Button
- SINGLE_BUTTON
并且通過(guò)如下方式進(jìn)行設(shè)置:
- super.setTouchMode(TouchMode.BUTTON);
工具類(lèi)
- NetUtils 網(wǎng)絡(luò)狀態(tài)工具類(lèi)
- PicUtils 圖片處理工具類(lèi)
- ServiceUtils 服務(wù)工具類(lèi)
- ImageHelper 圖型處理類(lèi)
- DisplayUtils 數(shù)據(jù)轉(zhuǎn)換類(lèi)
- SpUtils Sp簡(jiǎn)化工具類(lèi)(可存儲(chǔ)list和map)
- ValidatorsUtils 正則表達(dá)式處理類(lèi)
音頻系統(tǒng)
播放短音效
播放短音效,首先初始化SoundManager用以加載音效。
- // 接收實(shí)例和Manager的尺寸
- SoundManager manager = new SoundManager(this, 5);
- // 從assets加載音頻 同時(shí)加載路徑也會(huì)作為音效名進(jìn)行存儲(chǔ)
- manager.addSound("resource/rawfile/open.mid");
- // 通過(guò)加載名進(jìn)行播放
- manager.play("resource/rawfile/open.mid");
完成以上步驟就可以播放了,當(dāng)然盡量只向其中放置較短的音效,如背景音樂(lè)的長(zhǎng)音頻,請(qǐng)見(jiàn)播放音頻。
- public void removeSound(String musicName) // 移除
- public void play(String musicName, float volume) // 播放 + 音量
- public boolean containSoundID(int soundID) // 判斷音頻是否存在
- public int getSoundID(String soundName) // 獲取ID
- ...
播放音頻
播放音頻適合例如背景音樂(lè)一樣的音樂(lè)。
- // 傳入兩個(gè)參數(shù) 上下文和文件名
- MusicPlayer player = new MusicPlayer(this, "resources/rawfile/open.mp3");
- player.play();
以上的就能實(shí)現(xiàn)播放了,下面還有一些其他的方法。
- public void dispose() // 清理
- public void setLooping(boolean isLooping) // 是否循環(huán)
- public void setVolume(float volume) // 設(shè)定音量
- ...
通過(guò)短音效編曲
從SoundManager中導(dǎo)入多段音頻,快速播放達(dá)成音效的效果。
- SoundManager manager = new SoundManager(this, 5);
- manager.addSound("resources/rawfile/media/1.mid");
- manager.addSound("resources/rawfile/media/2.mid");
- SoundPlayer player = new SoundPlayer(manager, 500, 16);
- player.addSound("resources/rawfile/media/1.mid");
- player.addSound("resources/rawfile/media/2.mid");
- ...
使用player.play();進(jìn)行播放。
使用網(wǎng)絡(luò)
網(wǎng)絡(luò)的使用可參考JustWe-WebServer中的介紹。
按照介紹操作就可以通過(guò):
- server.apply("/lfk", new OnWebStringResult() {
- @Override
- public String OnResult() {
- return "=======";
- }
- });
- server.apply("/main", new OnWebFileResult() {
- @Override
- public File returnFile() {
- return new File(WebServerDefault.WebServerFiles+"/"+"welcome.html");
- }
- });
這樣的簡(jiǎn)單方式綁定路由,而get/post數(shù)據(jù)可以直接使用http協(xié)議的get和post進(jìn)行。
使用狀態(tài)機(jī)精靈
- // 為狀態(tài)機(jī)添加一個(gè)任務(wù)
- sprite.addState(new StateFinder() {
- @Override
- public boolean isContent(BaseSub baseSub) {
- return Math.abs(zom.s_position.x - baseSub.s_position.x) > 50;
- }
- }, new FrameAnimation(0, 63, 1));
可以通過(guò)上述的addState方法為狀態(tài)機(jī)精靈添加一個(gè)任務(wù),只有當(dāng)?shù)谝粋€(gè)參數(shù)接口回調(diào)的返回值為真的時(shí)候,
才會(huì)去運(yùn)行第二個(gè)參數(shù)提供的指令,如果返回為假則會(huì)運(yùn)行第二項(xiàng)狀態(tài)的判斷。
狀態(tài)的優(yōu)先級(jí)由加入順序提供。
CrashHandler崩潰守護(hù)
CrashHandler用于處理游戲的意外崩潰事件,初始化推薦在Application中進(jìn)行。
CrashHandler可以自動(dòng)保存機(jī)型和異常日志,以便讓開(kāi)發(fā)者找到問(wèn)題所在。
- CrashHandler.getInstance().init(this);
使用以上語(yǔ)句即可自動(dòng)保存錯(cuò)誤日志。
還可以:
- CrashHandler.getInstance().setRestartActivity(MainActivity.class); // 重啟的Activity
- // 添加崩潰回調(diào)
- CrashHandler.getInstance().addCrashListener(new AfterCrashListener() {
- @Override
- public void AfterCrash() { // 設(shè)定保存項(xiàng)目
- ...
- }
- });
使用藍(lán)牙
開(kāi)啟、關(guān)閉服務(wù)
使用藍(lán)牙需要新建BlueToothServer對(duì)象,傳入上下文和MessageBack接口。
- blueToothServer = new BlueToothServer(this, new OnMessageBack() {
- @Override
- public void getMessage(String msg) {
- Log.e("L", msg);
- }
- @Override
- public void sendMessage(String msg) {
- Log.e("L", msg);
- }
- @Override
- public void getDevice(ArrayList<String> msg) {
- Log.e("L", msg.size() + "");
- }
- });
- // 使用如下語(yǔ)句進(jìn)行初始化
- blueToothServer.init();
服務(wù)初始化之后如未打開(kāi)藍(lán)牙,系統(tǒng)會(huì)自動(dòng)提示應(yīng)用要求藍(lán)牙開(kāi)啟。
通過(guò)MessageBack接口可以接收到發(fā)送、接收、以及掃描設(shè)備信息,采取對(duì)應(yīng)操作就可以獲得數(shù)據(jù)。
關(guān)閉服務(wù)時(shí)請(qǐng)使用blueToothServer.unBindService();關(guān)閉服務(wù)。
掃描設(shè)備
使用blueToothServer.doDiscovery();進(jìn)行設(shè)備掃描,返回結(jié)果在OnMessageBack()接口的
getDevice()方法接收。
使用blueToothServer.ensureDiscoverable();允許被掃描。
使用blueToothServer.getPairedDevices();返回已配對(duì)的設(shè)備列表。
發(fā)送消息
在配對(duì)成功之后就可以使用blueToothServer.sendMessage(String msg);發(fā)送消息了。
同時(shí),消息的接收也可以從getMessage()接口中獲得。
SQLite數(shù)據(jù)庫(kù)
SQLite使用了IOC的模式。
創(chuàng)建表
新建的創(chuàng)建表需要繼承Node并且寫(xiě)出注解類(lèi)。
- // 表名
- @TableName(tableName = "lfkdsk")
- public class User extends Node {
- // 主鍵自增 INTEGER型
- @LabelName(autoincrement = true,
- type = LabelName.Type.INTEGER,
- columnName = "name",
- generatedId = true)
- private int name;
- // TEXT型 欄名為user_name
- @LabelName(type = LabelName.Type.TEXT,
- columnName = "user_name")
- private String user_name;
- // 自增主鍵所以只需要提供其他信息
- public User(String user_name) {
- super(user_name);
- this.user_name = user_name;
- }
- public User(int name, String user_name) {
- super(name, user_name);
- this.name = name;
- this.user_name = user_name;
- }
- public int getName() {
- return name;
- }
- public void setName(int name) {
- this.name = name;
- }
- public String getUser_name() {
- return user_name;
- }
- public void setUser_name(String user_name) {
- this.user_name = user_name;
- }
- }
- // 通過(guò)這種方式獲取數(shù)據(jù)庫(kù) 表名
- private DataBase dataBase = DataBase.initAndOpen("user", User.class);
增刪查改
- // add
- database.insert(User user);
- // find
- database.get(int position);
- // delete
- database.delete(int position);
- // update
- database.update(User user);
- ...
相關(guān)資料
項(xiàng)目地址:https://gitee.com/openneusoft/just-we-engine
IDE官方下載地址:https://developer.harmonyos.com/cn/develop/deveco-studio
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)