JustWeEngine
本项目是基于开源项目JustWeEngine进行ohos化的移植和开发的,可以通过项目标签以及github地址(https://github.com/lfkdsk/JustWeEngine )追踪到原项目版本
项目介绍
- 项目名称:JustWeEngine
- 所属系列:ohos的第三方组件适配移植
- 功能:JustWeEngine是托管在Gitee 的一个开源的Ohos原生开发框架,可以让Ohos的开发人员非常便捷,无需切换语言和编译器的制作Ohos原生游戏
- 项目移植状态:完成
- 调用差异:无
- 原项目基线版本:v1.13
- 编程语言:Java
效果展示
安装教程
方法1.
- 编译har包JustWeEngine.har。
- 启动 DevEco Studio,将编译的har包,导入工程目录“entry->libs”下。
- 在moudle级别下的build.gradle文件中添加依赖,在dependences标签中增加对libs目录下har包的引用。
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
- ……
- }
4.在导入的har包上点击右键,选择“Add as Library”对包进行引用,选择需要引用的模块,并点击“OK”即引用成功。
方法2.
1.在工程的build.gradle的allprojects中,添加HAR所在的Maven仓地址(等maven发布后进行修改)
- repositories {
- maven {
- url 'https://s01.oss.sonatype.org/content/repositories/releases/'
- }
- }
2.在应用模块的build.gradle的dependencies闭包中,添加如下代码:(等maven发布后进行修改)
- dependencies {
- implementation 'io.github.dzsf:just-we-engine:1.0.1'
- }
使用说明
1.基础功能
- 1.1继承引擎核心类
- 1.2绘制文字
- 1.3绘制图片
- 1.4使用精灵
- 1.5使用按钮
2.动画系统
- 2.1绑定在BaseSub物品及精灵基类上的动画类
- 2.2绑定在Button上的动画类
3.物体分组碰撞检测和死亡判定
4.屏幕扫描模式
5.工具类
6.音频系统
- 6.1播放短音效
- 6.2播放音频
- 6.3通过短音效编曲
进阶应用
7.使用网络
8.使用状态机精灵
9.CrashHandler崩溃守护
10.使用蓝牙
- 10.1开启、关闭服务
- 10.2扫描设备
- 10.3发送消息
11.SQLite数据库
- 11.1创建表
- 11.2增删查改
基础功能
继承引擎核心类:
由于框架全部使用SurfaceView进行绘制,不使用诸如Button、Layout等原生控件,所以应该首先新建类继承引擎核心类Engine,负责游戏的流程,注释中已有明确的标明功能。
- public class MainAbility extends Engine implements Runnable, Component.TouchEventListener, Component.DrawTask {
- // 一般在构造函数完成变量的初始化
- public MainAbility() {
- }
- public void onStart(Intent intent) {
- // 调用初始化方法
- init();
- }
- // 载入一些UI参数和设置屏幕放向,默认背景色,设定屏幕的扫描方式等
- public void init() {
- // 初始化UI默认参数,必须调用该方法,其中有一些用于多机型适配的参数需要初始化
- UIdefaultData.init(this);
- }
- // 通常用于精灵,背景,图片等物体的设置和载入
- public void load() {
- }
- // draw 和 update 在线程中进行不断的循环刷新
- // draw 负责绘制 update 负责更新数据和对象信息
- public void draw() {
- }
- public void update() {
- }
- // 将touch 事件传回 功能和所设定的屏幕扫描方式有关
- public void touch(TouchEvent event) {
- }
- // 将碰撞事件传回 传回精灵和物品的基类
- // 用于处理碰撞事件 默认使用矩形碰撞
- public void collision(BaseSub baseSub) {
- }
- }
绘制文字:
使用GamePrinter进行文字绘制,除此以外还有多种方法绘制:
- @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从一个大的图片中取出对应位置的图片。
- /**
- * 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也可以继承该类使用,BaseSprite封装了很多方法供各种动画使用,这些功能很多都是需要结合动画系统来使用的,动画系统会在后面介绍。
新建精灵:
1.简单初始化:
- sprite = new BaseSprite(this);
2.初始化连续帧动画:
连续帧的初始化需要连续的帧图片。
- GameTexture texture = new GameTexture(this);
- texture.loadFromAsset("resources/base/graphic/flare.png");
- // 长宽以及列数
- sprite = new BaseSprite(this, 96, 96, 8);
- sprite.setTexture(texture);
- sprite.setPosition(100, 100);
- sprite.setDipScale(100, 100);
- // 帧切换动画是关键
- sprite.addAnimation(new FrameAnimation(0, 63, 1));
- addToSpriteGroup(sprite);
3.使用从大图取出的多帧图片:
- // 新建图片资源(此图为上图的大图)
- GameTexture texture = new GameTexture(this);
- texture.loadFromAsset("resources/base/graphic/shoot.png");
- // 初始化设定模式和长宽
- ship = new BaseSprite(this, 100, 124, FrameType.COMMON);
- // 设定资源
- ship.setTexture(texture);
- // 从大图中取出两帧
- ship.addRectFrame(0, 100, 100, 124);
- ship.addRectFrame(167, 361, 100, 124);
- ship.addAnimation(new FrameAnimation(0, 1, 1));
4.一些重要的其他设定:
- // 图片资源
- ship.setTexture(texture);
- // 大图取帧模式
- ship.addRectFrame(0, 100, 100, 124);
- // 设定位置
- ship.setPosition(x, y);
- // 设置dp大小
- ship.setDipScale(96, 96);
- // 设定dp位置
- ship.setDipPosition(x, y);
- // 设定透明度
- ship.setAlpha(...);
- // 只有将精灵添加到SpriteGroup中框架才会自行绘制,否则需要手动调用
- addToSpriteGroup(ship);
- ...
使用按钮:
使用的按钮可以继承BaseButton进行拓展,也可以直接使用TextureButton和TextButton进行使用。
Button设定功能的方式和原生一样,通过设定接口回调的方式进行:
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick() {
- Log.e("button", "onClick");
- }
- });
TextureButton:
- TextureButton button;
- // 初始化并设定名字
- button = new TextureButton(this, "logo");
- texture = new GameTexture(this);
- texture.loadFromAsset("resources/base/graphic/logo.jpg");
- // 添加图片资源
- button.setTexture(texture);
- // button的接口回调,不是View的那个接口
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick() {
- Log.e("button", "onClick");
- }
- });
- button.setPosition(200, 300);
- button.setDipScale(100, 150);
- // 添加到ButtonGroup进行绘制和处理
- addToButtonGroup(button);
结合PicUtil中的各种Bitmap处理方法可以很容易的做出各种样式的Button。
TextButton:
TextButton button;
- TextButton button;
- button = new TextButton(this, "logo");
- button.setText("刘丰恺");
- addToButtonGroup(button);
- // 余略见源码
- ...
动画系统
目前的动画系统可以使用已经封装好的继承了BaseAnimation的动画,也可以继承BaseAnim进行自我定义动画类进行使用。
绑定在BaseSub物品及精灵基类上的动画类
AnimType中保存了Animation的应用类型。
绑定动画分为两类,ListAnimation和FixedAnimation,ListAnimation将动画存储到固定的一个List中,用于重复更新的动画,
而FixedAnimation存储在Map中,使用名字进行调用,用于点击或者非自动更新的动画。
比如前面精灵类动画的就是添加到ListAnimation。
下面的这种写法就是FixedAnimation,这个动画是飞机入场,因为只使用了一次,所以使用了FixedAnimation。
- ship.addfixedAnimation("start",
- new MoveAnimation(UIdefaultData.centerInHorizontalX - ship.getWidthWithScale() / 2,
- UIdefaultData.screenHeight - 2 * ship.getHeightWidthScale(), new Float2(10, 10)));
绑定在Button上的动画类
BaseButtonAnimation是BaseButton的动画类继承了BaseAnim的动画基类,通过提供Button的状态,设定Button的动画。
为Button设定放缩动画:
- // 设定中心放缩
- button.setZoomCenter(true);
- // 三个参数 初始值/放大值/帧数
- button.setAnimation(new ZoomCenterButtonAnim(10, 30, 3));
为Button设定颜色动画:
- // 初始颜色 / 按下颜色
- button.setAnimation(
- new ColorAnimation(UIdefaultData.colorAccent,
- UIdefaultData.colorPressed));
物体分组碰撞检测和死亡判定
使用设置ID和Name进行物体分组,通过物体分组,框架核心类会对对象进行分类处理。
- final int SHIP = 0;
- ship.setName("SHIP");
- ship.setIdentifier(SHIP);
只要使用了addToSpriteGroup(sprite)的精灵对象就会自动进行碰撞检测,而对碰撞检测的结果会从
collision中进行发回。
- @Override
- public void collision(BaseSub baseSub) {
- // 获取与之碰撞的对象
- BaseSprite other = (BaseSprite) baseSub.getOffender();
- // 获取ID分组处理
- if (baseSub.getIdentifier() == BULLET &&
- other.getIdentifier() == ENEMY) {
- // 设定死亡
- other.setAlive(false);
- // 回收
- removeFromSpriteGroup(other);
- addToRecycleGroup(other);
- }
- }
其中getOffender()获得与之碰撞的对象,通过getIdentifier()获取设定的对象分组,实行逻辑判断。
开启Debug模式会看见碰撞线。
屏幕扫描模式
屏幕扫描模式是用来优先响应屏幕点击、Button点击、和多点触控而设的,放置在不同情况下都能优化屏幕的刷新。
- // 检测单一移动
- SINGLE,
- // 检测Button
- BUTTON,
- // 多点检测
- FULL,
- // 单击+Button
- SINGLE_BUTTON
并且通过如下方式进行设置:
- super.setTouchMode(TouchMode.BUTTON);
工具类
- NetUtils 网络状态工具类
- PicUtils 图片处理工具类
- ServiceUtils 服务工具类
- ImageHelper 图型处理类
- DisplayUtils 数据转换类
- SpUtils Sp简化工具类(可存储list和map)
- ValidatorsUtils 正则表达式处理类
音频系统
播放短音效
播放短音效,首先初始化SoundManager用以加载音效。
- // 接收实例和Manager的尺寸
- SoundManager manager = new SoundManager(this, 5);
- // 从assets加载音频 同时加载路径也会作为音效名进行存储
- manager.addSound("resource/rawfile/open.mid");
- // 通过加载名进行播放
- manager.play("resource/rawfile/open.mid");
完成以上步骤就可以播放了,当然尽量只向其中放置较短的音效,如背景音乐的长音频,请见播放音频。
- public void removeSound(String musicName) // 移除
- public void play(String musicName, float volume) // 播放 + 音量
- public boolean containSoundID(int soundID) // 判断音频是否存在
- public int getSoundID(String soundName) // 获取ID
- ...
播放音频
播放音频适合例如背景音乐一样的音乐。
- // 传入两个参数 上下文和文件名
- MusicPlayer player = new MusicPlayer(this, "resources/rawfile/open.mp3");
- player.play();
以上的就能实现播放了,下面还有一些其他的方法。
- public void dispose() // 清理
- public void setLooping(boolean isLooping) // 是否循环
- public void setVolume(float volume) // 设定音量
- ...
通过短音效编曲
从SoundManager中导入多段音频,快速播放达成音效的效果。
- 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();进行播放。
使用网络
网络的使用可参考JustWe-WebServer中的介绍。
按照介绍操作就可以通过:
- 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");
- }
- });
这样的简单方式绑定路由,而get/post数据可以直接使用http协议的get和post进行。
使用状态机精灵
- // 为状态机添加一个任务
- 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));
可以通过上述的addState方法为状态机精灵添加一个任务,只有当第一个参数接口回调的返回值为真的时候,
才会去运行第二个参数提供的指令,如果返回为假则会运行第二项状态的判断。
状态的优先级由加入顺序提供。
CrashHandler崩溃守护
CrashHandler用于处理游戏的意外崩溃事件,初始化推荐在Application中进行。
CrashHandler可以自动保存机型和异常日志,以便让开发者找到问题所在。
- CrashHandler.getInstance().init(this);
使用以上语句即可自动保存错误日志。
还可以:
- CrashHandler.getInstance().setRestartActivity(MainActivity.class); // 重启的Activity
- // 添加崩溃回调
- CrashHandler.getInstance().addCrashListener(new AfterCrashListener() {
- @Override
- public void AfterCrash() { // 设定保存项目
- ...
- }
- });
使用蓝牙
开启、关闭服务
使用蓝牙需要新建BlueToothServer对象,传入上下文和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() + "");
- }
- });
- // 使用如下语句进行初始化
- blueToothServer.init();
服务初始化之后如未打开蓝牙,系统会自动提示应用要求蓝牙开启。
通过MessageBack接口可以接收到发送、接收、以及扫描设备信息,采取对应操作就可以获得数据。
关闭服务时请使用blueToothServer.unBindService();关闭服务。
扫描设备
使用blueToothServer.doDiscovery();进行设备扫描,返回结果在OnMessageBack()接口的
getDevice()方法接收。
使用blueToothServer.ensureDiscoverable();允许被扫描。
使用blueToothServer.getPairedDevices();返回已配对的设备列表。
发送消息
在配对成功之后就可以使用blueToothServer.sendMessage(String msg);发送消息了。
同时,消息的接收也可以从getMessage()接口中获得。
SQLite数据库
SQLite使用了IOC的模式。
创建表
新建的创建表需要继承Node并且写出注解类。
- // 表名
- @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;
- }
- }
- // 通过这种方式获取数据库 表名
- 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);
- ...
相关资料
项目地址:https://gitee.com/openneusoft/just-we-engine
IDE官方下载地址:https://developer.harmonyos.com/cn/develop/deveco-studio