前言
这近在跟APP对接接口,在等待对接的空隙中,让我想起了被我遗忘的HybridApp技术 ionic ,于是就有了今天这篇新手级的教程。
当初使用的是ionic 3 ,现在升级到了ionic 6.x。变化比较大,支持Angular、Vue、React或其它任意JS框架,它甚至可以使用简单的脚本独立使用,无需任何前端框架
有关 ionic 的使用本文不详细描述,请查阅官网地址:https://ionicframework.com/docs
安卓调试环境
几年前写过一篇ionic 3 的安卓调试环境配置,但是不适合现在 ionic 6.x
1、安装 Android Studio
2、安装 Android SDK,基本上勾上API Level 16 以上的就行了
3、配置环境变量
Key | Value |
---|---|
ANDROID_SDK_ROOT | C:\Users\18228\AppData\Local\Android\Sdk(Android SDK 安装目录) |
Path | %ANDROID_SDK_ROOT%\tools\bin |
Path | %ANDROID_SDK_ROOT%\platform-tools |
Path | %ANDROID_SDK_ROOT%\emulator |
4、验证安装
执行adb ,如果不报错,则配置成功
PS: (此步骤不是必须)一般情况,以前配置可以完成 Android 调试打包,如果有以上配置还是无法调试安卓,安装 JDK 1.8 +,然后配置对应的环境变量
JAVA_HOME = C:\Program Files\Java\jdk1.8.0_171 (JDK 安装目录)
PATH = %JAVA_HOME%\jre\bin
安卓手机环境(不是必须,H5也能调测)
准备一台安卓手机进行真机运行,启动开发者模式,打开USB 调试,打开USB 安装
ionic 环境安装
使用 npm 安装 Ionic CLI,使用 ionic 验证
npm install -g @ionic/cli
编写ionic 项目
使用初始化一个angular 的 ionic tabs 项目
ionic start
等待完成之后会,会在文件夹创建一个以项目名为文件夹的项目。主体结构如下,此处不就一一介绍了。
现在切到文件夹根目录,执行下面命令就可以在web中运行
ionic serve
效果如下图
引入游戏框架
Phaser 是一个开源的桌面和移动 HTML5 2D 游戏开发框架,支持 JavaScript 和 TypeScript。
使用npm 安装
npm i phaser
修改 tsconfig.json 的编译选项,添加一下两处修改
{
...
"compilerOptions":{
...
"lib": ["es2018", "dom","scripthost"],
"allowSyntheticDefaultImports": true, //允许默认从没有默认导出的模块导入。这不会影响代码发出,只会影响类型检查。
...
}
...
}
接下来正片开始,编写一个简单游戏,修改tab1.page.html 页面如下
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Tab 1
</ion-title>
</ion-toolbar>
</ion-header>
<!-- 添加游戏页面容器元素 game -->
<ion-content>
<div id="game"></div>
</ion-content>
修改tab1.page.ts , 详细讲解查看注释,主要是利用Phaser 框架新建静态场景和动态角色,添加触碰按钮,控制角色移动。
import { Component, OnInit } from '@angular/core';
import Phaser from 'phaser';
let player;
let platforms;
class GameScene extends Phaser.Scene {
constructor(config) {
super(config);
}
preload() {
// 引入本地文件到游戏容器中
this.load.image('sky', 'assets/sky.png');
this.load.image('ground', 'assets/platform.png');
this.load.image('left', 'assets/left.png');
this.load.image('turn', 'assets/turn.png');
this.load.image('right', 'assets/right.png');
this.load.spritesheet('dude', 'assets/dude.png', { frameWidth: 32, frameHeight: 48 });
}
create() {
// 使用图片,这里使用sky 作为背景
this.add.image(400, 100, 'sky');
// 构建静态物理游戏场景组
platforms = this.physics.add.staticGroup();
// 创建一个新的游戏对象并将其添加到该组中,缩放以适应游戏的宽度
platforms.create(window.innerWidth - 20, 400, 'ground').setScale(2).refreshBody();
// 新建玩家
player = this.physics.add.sprite(100, 250, 'dude');
player.setBounce(0.2); //设置这个身体的反弹值。弹跳是身体与另一个物体碰撞时的恢复量或弹性。值为 1 意味着它将在回弹后保持其全速。值为 0 表示它根本不会反弹
player.setCollideWorldBounds(true); //设置这个身体是否与边界碰撞。
// 创建左转动画效果
this.anims.create({
key: 'left',
frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3 }),
frameRate: 10,
repeat: -1
});
// 创建上动画效果
this.anims.create({
key: 'turn',
frames: [{ key: 'dude', frame: 4 }],
frameRate: 20
});
// 创建右动画效果
this.anims.create({
key: 'right',
frames: this.anims.generateFrameNumbers('dude', { start: 5, end: 8 }),
frameRate: 10,
repeat: -1
});
this.physics.add.collider(player, platforms);//Arcade Physics Collider 将在每一步自动检查两个对象之间的碰撞或重叠。如果发生碰撞或重叠,它将调用给定的回调
// cursors = this.input.keyboard.createCursorKeys(); 创建键盘键
// 用为作为App,没有键盘,需要定义上、左、右三个按钮来操控人物行动,同事监听事件触发上面定义的相对应动画及行走距离
const button = this.add.sprite(200, 500, 'turn')
.setInteractive()
.on('pointerdown', () => {
player.setVelocityX(0);
player.anims.play('turn');
player.setVelocityY(-330);
});
const rightButton = this.add.sprite(300, 500, 'right')
.setInteractive()
.on('pointerdown', () => {
player.setVelocityX(160);
player.anims.play('right', true);
})
.on('pointerup', () => {
player.setVelocityX(0);
});
const leftButton = this.add.sprite(100, 500, 'left')
.setInteractive()
.on('pointerdown', () => {
player.setVelocityX(-160);
player.anims.play('left', true);
})
.on('pointerup', () => {
player.setVelocityX(0);
});
}
update() {
}
}
@Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page implements OnInit {
phaserGame: Phaser.Game;
config: Phaser.Types.Core.GameConfig;
winH = window.innerHeight;
winW = window.innerWidth;
constructor() {
this.config = {
type: Phaser.AUTO,
width: this.winW,
height: this.winH,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 300 },
debug: false
}
},
parent: 'game',
scene: GameScene
};
}
ngOnInit(): void {
this.phaserGame = new Phaser.Game(this.config);
}
}
web 页面运行如下
真机调试(仅Android)
前面说到安卓手机环境配置,现在我们打开配置,连接USB,输入一下命令,查看是否读到设备
adb devices
如下图所示,已读到设备。
设备调整后,代码需要添加编译成Android 源码操作,执行一下命令,第一次执行需要一些时间。
ionic capacitor add android
执行成功后,根目录多了一个android 文件夹,这就是编译后的android 源码,可以直接在Android Studio 中运行
ionic 6 版本真机调试,需要在 android\app\src\main\AndroidManifest.xml 中application 节点下添加 android:usesCleartextTraffic=“true” 属性。不然真机会找不到网页
查看capacitor.config.json 文件,可以修改appId 、appName 等属性;同时,可以看到真机运行依赖www web文件夹,所以我们需要先build 出www文件夹
运行以下命令
npm run build
执行自动生成了www 发布文件
接下来就是执行命令,真机调试了,执行这个命令需要等待几分钟,同时注意手机是否有弹框提示确认安装。
ionic capacitor run android -l --external
本次只是简单讲解怎么使用ionic开发游戏,至于游戏的画面的兼容性,这些都是没有考虑在内的,更多的资料可以查阅 ionic 、Phaser ,
最后,看一下真机的运行效果(Redmi note 9 5G):
ionic app