@puerts/cli
Version:
PureTS is a quick scaffold tool, which can be used in the project.
310 lines (285 loc) • 16.4 kB
text/typescript
import ue = CS.UnityEngine; // 是用来协助进行类型检查和声明的,在运行时是完全不存在
import Ticker from './Core/Ticker';
const { GameObject, Time, Vector2, Vector3, RenderMode, Camera, Canvas, CanvasRenderer, MeshFilter, Mesh,
MeshRenderer, Light, LightType, FontStyle, Quaternion, UI, CameraClearFlags, Resources, EventSystems,
RectTransform, TextAnchor, LightmapBakeType} = CS.UnityEngine;
const {CanvasScaler,Slider} = CS.UnityEngine.UI;
const {$typeof} = puer;
namespace Game {
interface GameOption {
/** 每秒最大渲染帧数限制 */
maxFps?:number,
/**是否为线上*/
online?:boolean
}
interface GameObj {
object:ue.GameObject,
components?:{
camera?:ue.Camera,
canvas?:ue.Canvas,
canvaslScale?:ue.UI.CanvasScaler,
graphicRaycaster?:ue.UI.GraphicRaycaster
eventSystem?:ue.EventSystems.EventSystem,
standaloneInputModule?:ue.EventSystems.StandaloneInputModule,
text?:ue.UI.Text,
rectTransform?:ue.RectTransform,
slider?:ue.UI.Slider
}
}
interface RandomizeMatrix {
position:[number,number,number],
scale:[number,number,number],
rotaion:[number,number,number]
}
export class App{
private _maxFps:number; // 最大帧
private ticker:Ticker; // 轮循执行器
public static mainCamera:ue.GameObject; // 主相机
public static uiCamera:ue.GameObject; // Ui相机
public static uiCanvas:ue.GameObject; // Ui画布
public static eventSystem:ue.GameObject; // Ui事件系统
public static stage:ue.GameObject; // 舞台节点
private cubeList:ue.GameObject[] = []; // 保存 Cube 列表
private cubeCont:number = 100; // 记录 Cube 数量
private speed:number = 1; // 记录 Cube 速度
/**
* 构造方法
* @param option 游戏启动参数
*/
constructor(option?:GameOption){
if(option){
for(let key in option){
this[key] = option[key];
};
};
if(!this.maxFps){
this.maxFps = 60;
};
if(!this.maxFps){
this.maxFps = 60;
};
this.ticker = new Ticker(this.maxFps);
}
/**
* 应用启动入口
*/
async init():Promise<void>{
this.ticker.start(); // 启动轮循执行器
const mainCameraObj = this.createMainCamera();
App.mainCamera = mainCameraObj.object; // 创建主相机
const uiCameraObj = this.createUiCamera();
App.uiCamera = uiCameraObj.object; // 创建UI相机
const canvasObj = this.createCanas(uiCameraObj.components.camera);
App.uiCanvas = canvasObj.object; // 创建UI画布
const eventSystemObj = this.createEventSystem();
App.eventSystem = eventSystemObj.object; // 创建UI事件系统
App.stage = new GameObject("Stage"); // 创建舞台,内容全在舞台上
const speedTextObj = this.createUiText('TextSpeed'); // 速度文本
const countTextObj = this.createUiText('TextCount'); // 数量文本
countTextObj.components.rectTransform.anchoredPosition = new Vector2(0,-40); // 调整显示位置稍微向下偏移一点
const timers = {}; // 用于保存计时器,防抖之用
const updateSpeed = (val:number)=>{ // 更新速度方法
this.speed = val;
speedTextObj.components.text.text = `Speed:${val.toFixed(3)}`
};
updateSpeed(this.speed); // 速度首次初始化
const updateCount = (val:number)=>{ // 更新数量方法
val = ~~val; // 取整
if(val === this.cubeList.length){return;}; // 值与当前列表的数量一样则无需处理
this.cubeCont = val; // 记录最新数量
countTextObj.components.text.text = `Count:${this.cubeCont}`; // 更新提示文字
clearTimeout(timers['updateCount']); // 防抖处理
timers['updateCount'] = setTimeout(() => { // 防抖处理
this.cubeList = this.createCubeList();
}, 200);
};
updateCount(this.cubeCont); // 数量首次初始化
const speedSlideObj = this.createUiSlider('SliderSpeed',updateSpeed); // 创建调节速度的Slide
speedSlideObj.components.slider.minValue = this.speed; // 最小值为默认初始值
speedSlideObj.components.slider.maxValue = this.speed + 100 - this.speed; // 最大值100
const countSlideObj = this.createUiSlider('SliderCount',updateCount); // 创建调节数量的Slide
countSlideObj.components.rectTransform.anchoredPosition = new Vector2(0,80); // 调整显示位置稍微向下偏移一点
countSlideObj.components.slider.minValue = this.cubeCont; // 最小值为默认初始值
countSlideObj.components.slider.maxValue = this.cubeCont + 20000 - this.cubeCont; // 最大值3000
const update = (deltaTime:number,performance:number)=>{ // 更新方法(当热重载开启时,修改该方法即时生效)
for(let i=0,len=this.cubeList.length; i<len; i++){
const cube = this.cubeList[i];
const r = Vector3.op_Multiply(new Vector3(1,1,0), deltaTime / 100 * this.speed);
cube.transform.Rotate(r);
};
};
Ticker.add(update); // 添加轮循执行方法,这里的 deltaTime 为 ms(实际生产中不建议这么写,update 可以放在对象上也同样能实现热重载)
}
/**
* 创建 Text Ui
* @param name string 对象名称
* @returns GameObj
*/
createUiText(name:string):GameObj{
const object:ue.GameObject = new GameObject(name);
object.transform.SetParent(App.uiCanvas.transform,false);
object.AddComponent($typeof(CanvasRenderer));
const text:ue.UI.Text = object.AddComponent($typeof(UI.Text)) as ue.UI.Text;
text.font = Resources.Load("Fonts/Arial") as ue.Font;
text.alignment = TextAnchor.MiddleCenter;
text.fontSize = 24;
text.fontStyle = FontStyle.Bold;
// text.text = `${speed}`;
const rectTransform:ue.RectTransform = object.GetComponent($typeof(RectTransform)) as ue.RectTransform;
rectTransform.localPosition = new Vector3(0,423,0);
rectTransform.anchorMin = new Vector2(0,1);
rectTransform.anchorMax = new Vector2(1,1);
rectTransform.anchoredPosition = new Vector2(0,0);
rectTransform.sizeDelta = new Vector2(0,120);
rectTransform.pivot = new Vector2(0.5,1);
return {object,components:{text,rectTransform}};
}
/**
* 创建 Slider Ui
* @param name string 对象名称
* @param call function Ui事件触发方法
* @returns GameObj
*/
createUiSlider(name:string,call:ue.Events.UnityAction$1<number>):GameObj{
const object:ue.GameObject = GameObject.Instantiate(Resources.Load("Prefabs/Slider")) as ue.GameObject;
object.name = name;
const rectTransform:ue.RectTransform = object.GetComponent($typeof(RectTransform)) as ue.RectTransform;
const slider:ue.UI.Slider = object.GetComponent($typeof(Slider)) as ue.UI.Slider;
slider.minValue = 1;
slider.maxValue = 10;
// slider.wholeNumbers = true;
slider.onValueChanged.AddListener(call); // 为 UI 添加事件绑定
rectTransform.transform.localPosition = new Vector3(0,160,0);
rectTransform.transform.localScale = new Vector3(2,2,2);
rectTransform.sizeDelta = new Vector2(120,20);
object.transform.SetParent(App.uiCanvas.transform,false);
return {object,components:{slider,rectTransform}};
}
/**
* 创建随机矩阵
* @returns RandomizeMatrix
*/
createRandomizeMatrix():RandomizeMatrix{
const position:RandomizeMatrix['position'] = [
Math.random() * 20 - 10,
Math.random() * 20 - 10,
Math.random() * 20 - 10,
];
const scaleVal = Math.random() * 1;
const scale:RandomizeMatrix['scale'] = [scaleVal,scaleVal,scaleVal];
const rotaion:RandomizeMatrix['rotaion'] = [
Math.random() * 90 * Math.PI,
Math.random() * 90 * Math.PI,
Math.random() * 90 * Math.PI
];
return {position,scale,rotaion};
}
/**
* 创建Cube列表
* @returns ue.GameObject[]
*/
createCubeList():ue.GameObject[]{
for(let i=0,len=this.cubeList.length; i<len; i++){ // 销毁已有的
GameObject.Destroy(this.cubeList[i]);
// CS.UnityEngine.Object.DestroyImmediate(this.cubeList[i]);
};
const result:ue.GameObject[] = [];
for(let i=0; i<this.cubeCont; i++){
const cube:ue.GameObject = this.createCube(`Cube${i}`);
result.push(cube);
};
return result;
}
/**
* 创建Cube
* @param name string cube名称
* @returns ue.GameObject
*/
createCube(name:string):ue.GameObject{
const object:ue.GameObject = new GameObject(name);
object.transform.SetParent(App.stage.transform);
const cube_mf:ue.MeshFilter = object.AddComponent($typeof(MeshFilter)) as ue.MeshFilter;
cube_mf.mesh = Resources.GetBuiltinResource($typeof(Mesh),"Cube.fbx") as ue.Mesh;
const cube_mr:ue.MeshRenderer = object.AddComponent($typeof(MeshRenderer)) as ue.MeshRenderer;
const cube_t = Resources.Load("Textures/PuertsLogo") as ue.Texture;
cube_mr.material.SetFloat('_Metallic',0.8);
cube_mr.material.SetFloat('_Glossiness',0.78);
cube_mr.material.SetTexture('_MainTex',cube_t);
const randomizeMatrix = this.createRandomizeMatrix();
object.transform.localPosition = new Vector3(...randomizeMatrix.position);
object.transform.localRotation = Quaternion.Euler(...randomizeMatrix.rotaion);
// object.transform.localScale = new Vector3(...randomizeMatrix.scale);
object.transform.SetParent(App.stage.transform);
return object;
}
set maxFps(val:number){
this._maxFps = val;
}
get maxFps():number{
return this._maxFps;
}
/**
* 创建主相机
* @returns ue.GameObject
*/
createMainCamera():GameObj{
const object:ue.GameObject = new GameObject("Main Camera");
let camera:ue.Camera = object.AddComponent($typeof(Camera)) as ue.Camera;
camera.clearFlags = CameraClearFlags.Skybox;
camera.cullingMask = ~(1 << 5); // 主相机渲染除UI的所有层(https://gameinstitute.qq.com/community/detail/126782)
camera.nearClipPlane = 2;
camera.farClipPlane = 40;
camera.transform.Rotate(20,0,0);
camera.transform.localScale = new Vector3(0.5,0.5,0.5);
camera.transform.localPosition = new Vector3(0,7,-20);
return {object,components:{camera}};
}
/**
* 创建UI相机
* @returns object
*/
createUiCamera():GameObj{
const object:ue.GameObject = new GameObject("Ui Camera");
object.transform.position = new Vector3(-10,0,0);
const camera:ue.Camera = object.AddComponent($typeof(Camera)) as ue.Camera;
camera.clearFlags = CameraClearFlags.Depth;
camera.cullingMask = 1 << 5; // UI相机仅渲染UI层
camera.orthographic = true;
camera.nearClipPlane = 5;
camera.farClipPlane = 15;
return {object,components:{camera}};
}
/**
* 创建Ui画布
*/
createCanas(cameraComponent:ue.Camera):GameObj{
const object:ue.GameObject = new GameObject("Canvas");
object.layer = 5; // 设置属于UI层
const canvas:ue.Canvas = object.AddComponent($typeof(Canvas)) as ue.Canvas;
canvas.renderMode = RenderMode.ScreenSpaceCamera;
canvas.worldCamera = cameraComponent;
canvas.planeDistance = 10;
const canvaslScale:ue.UI.CanvasScaler = object.AddComponent($typeof(CanvasScaler)) as ue.UI.CanvasScaler;
canvaslScale.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
canvaslScale.referenceResolution = new Vector2(428,926);
canvaslScale.matchWidthOrHeight = 1;
const graphicRaycaster = object.AddComponent($typeof(UI.GraphicRaycaster)) as ue.UI.GraphicRaycaster;
return {object,components:{canvas,canvaslScale,graphicRaycaster}};
}
/**
* 创建UI事件系统
* @returns object
*/
createEventSystem():GameObj{
const object:ue.GameObject = new GameObject("EventSystem");
const eventSystem = object.AddComponent($typeof(EventSystems.EventSystem)) as ue.EventSystems.EventSystem;
const standaloneInputModule = object.AddComponent($typeof(EventSystems.StandaloneInputModule)) as ue.EventSystems.StandaloneInputModule;
return {object,components:{eventSystem,standaloneInputModule}};
}
}
}
(()=>{
const app = new Game.App({maxFps:60,online:false});
app.init();
})()
export default Game.App;