這是我參與更文挑戰的第6天,活動詳情查看: 更文挑戰canvas
上一章介紹了Oasis裏的座標系,本篇文章就介紹如何將一個2D遊戲的場景佈置出來api
Sprite 是 2D 圖形對象,用於角色、道具、子彈以及一些其餘 2D 遊戲要素。這些圖形是從 Texture2D 得到的。Sprite 類主要標識應用於特定Sprite的圖像部分。而後 Entity 上的 SpriteRenderer 組件可使用此信息來實際顯示圖形。markdown
咱們先加載一個素材看看效果async
// 加載紋理資源
const groundTexture: Texture2D = await engine.resourceManager.load(textureList[0])
// 建立精靈實體
const groundEntity = rootEntity.createChild('groundSprite')
const groundRenderer = groundEntity.addComponent(SpriteRenderer)
const groundsprite = new Sprite(engine, groundTexture)
groundRenderer.sprite = groundsprite
// 設置實體座標
const groundScreenpoint = new Vector3(0, 0)
const groundWorldpoint = new Vector3()
cameramash.screenToWorldPoint(groundScreenpoint, groundWorldpoint)
groundEntity.transform.position = groundWorldpoint
複製代碼
若是仔細觀察的話能夠發如今屏幕的左上角有1/4個方塊,爲方便觀察咱們使用 groundEntity.transform.scale = new Vector3(5, 5)
將素材放大5倍。oop
咱們將實體的位置設置在屏幕(0, 0)上,而Oasis裏默認的模型座標原點在中心點上,因此此時只能看到1/4個方塊。若是咱們想要看到整個素材就須要設置座標爲 (groundEntity.width / 2, groundEntity.height / 2)。而咱們可使用 sprite.pivot 來從新設置模型座標的原點。post
詳情介紹能夠查看官網的精靈資源(注:rect方法在V0.4版本中爲region)ui
咱們這裏將左上角設置爲原點,即可以看到一個完整的方塊url
groundsprite.pivot = new Vector2(0, 1)
spa
我這裏的引用素材大小爲48*48 然而,渲染後的內容明顯小於素材實際大小3d
這是由於在Sprite下面有一個pixelsPerUnit參數,咱們先來看一下官網對這個參數的介紹
The number of pixels in the sprite that correspond to one unit in world space.(對應世界空間中一個單位的精靈中的像素數。)
我對這個介紹的理解是:
在世界座標下,一個單位的長度對應多少屏幕像素點。
使用如下代碼能夠求出一個單位的長度對應多少屏幕像素點
const worldPoint = new Vector3(0, 0, 0)
const screenOut = new Vector4()
cameramash.worldToScreenPoint(worldPoint, screenOut)
const worldPoint1 = new Vector3(1, 0, 0)
const screenOut1 = new Vector4()
cameramash.worldToScreenPoint(worldPoint1, screenOut1)
console.log(`pixelsPerUnit:${screenOut1.x - screenOut.x}`) // 128
複製代碼
咱們可使用console.log(Sprite.pixelsPerUnit)來查看是否也爲128
console.log(groundsprite.pixelsPerUnit) // 128
複製代碼
咱們將pixelsPerUnit設置爲10 能夠看到素材相較與pixelsPerUnit爲128時大了不少
groundsprite.pixelsPerUnit = 10
複製代碼
因此,能夠得出一個簡單的結論:在世界座標下,若是一個單位的長度對應更多的屏幕像素則圖片會變得更小;反之更大。即,
pixelsPerUnit 數字越大,圖片越小。
因此就能夠將素材經過pixelsPerUnit調整到合適的大小,這裏將pixelsPerUnit調整爲50
groundsprite.pixelsPerUnit = 50
在遊戲場景中,素材的大小應該能夠隨着用戶屏幕的寬高自適應調整,因此精靈的寬高須要經過屏幕計算而來。
這裏渲染了兩排,每排25個精靈
// 獲取canvas的寬
const canvasX = engine.canvas.width
// 肯定須要25個精靈後,用Canvas的寬除以每一個精靈的寬再除以25獲得每一個精靈須要縮放的倍數
const scaleTimes = canvasX / 25 / groundTexture.width
// 最後經過transform.scale設置實體的變換
groundEntity.transform.scale = new Vector3(scaleTimes, scaleTimes)
複製代碼
這樣不管用戶顯示器的寬度爲多少,都可以按比例顯示大小,再經過兩個while循環渲染出來
兩排地面完整代碼
// 獲取精靈材質
const groundTexture: Texture2D = await engine.resourceManager.load(textureList[0])
// 設置初始行列變量
let i = 0
let j = 0
// 計算縮放比例
const scaleTimes = canvasX / 25 / groundTexture.width
// 雙循環渲染
while (j < 2) {
while (i < 25) {
// 建立精靈實體
const groundEntity = rootEntity.createChild(`groundSprite_${i}`)
const groundRenderer = groundEntity.addComponent(SpriteRenderer)
const groundsprite = new Sprite(engine, groundTexture)
// 設置模型中心爲左上角
groundsprite.pivot = new Vector2(0, 1)
// 設置pixelsPerUnit值爲50
groundsprite.pixelsPerUnit = 50
groundRenderer.sprite = groundsprite
// 計算實體屏幕座標系X,Y軸位置
const pointX = groundTexture.width * i * scaleTimes
const pointY = canvasY - groundTexture.height * scaleTimes * (j + 1)
// 轉換爲世界座標
const screenpoint = new Vector3(pointX, pointY)
const out = new Vector3()
cameramash.screenToWorldPoint(screenpoint, out)
// 設置位置和縮放
groundEntity.transform.position = out
groundEntity.transform.scale = new Vector3(scaleTimes, scaleTimes)
i++
}
i = 0
j++
}
複製代碼
再經過一樣的方法添加3朵雲和一個角色,設置一下背景顏色
一個基本的場景佈置就完成了
import {
Camera,
WebGLEngine,
Vector2,
Vector3,
Texture2D,
SpriteRenderer,
Sprite,
AssetType,
BackgroundMode
} from 'oasis-engine'
export async function createOasis (): Promise<void> {
// 初始化Engine
const engine = new WebGLEngine('canvas')
engine.canvas.resizeByClientSize()
// 獲取場景根實體
const scene = engine.sceneManager.activeScene
const rootEntity = scene.createRootEntity('root')
scene.background.mode = BackgroundMode.SolidColor
scene.background.solidColor.setValue(0.76, 0.76, 0.74, 1)
// 獲取Canvas寬高
const canvasX = engine.canvas.width
const canvasY = engine.canvas.height
// 建立一個相機實體
const cameraEntity = rootEntity.createChild('camera_entity')
const cameramash = cameraEntity.addComponent(Camera)
cameraEntity.transform.position = new Vector3(0, 0, 20)
cameramash.isOrthographic = true
// 建立資源
const textureList = [
{
url: require('../assets/ground.png'),
type: AssetType.Texture2D
}, {
url: require('../assets/cloud.png'),
type: AssetType.Texture2D
}, {
url: require('../assets/i1.png'),
type: AssetType.Texture2D
}
]
// 建立地面實體
const groundTexture: Texture2D = await engine.resourceManager.load(textureList[0])
let i = 0
let j = 0
const scaleTimes = canvasX / 25 / groundTexture.width
while (j < 2) {
while (i < 25) {
const groundEntity = rootEntity.createChild(`groundSprite_${i}`)
const groundRenderer = groundEntity.addComponent(SpriteRenderer)
const groundsprite = new Sprite(engine, groundTexture)
groundsprite.pivot = new Vector2(0, 1)
groundsprite.pixelsPerUnit = 50
groundRenderer.sprite = groundsprite
const pointX = groundTexture.width * i * scaleTimes
const pointY = canvasY - groundTexture.height * scaleTimes * (j + 1)
const screenpoint = new Vector3(pointX, pointY)
const out = new Vector3()
cameramash.screenToWorldPoint(screenpoint, out)
groundEntity.transform.position = out
groundEntity.transform.scale = new Vector3(scaleTimes, scaleTimes)
i++
}
i = 0
j++
}
// 建立角色實體
const roleTexture: Texture2D = await engine.resourceManager.load(textureList[2])
const roleEntity = rootEntity.createChild('roleSprite')
const roleRenderer = roleEntity.addComponent(SpriteRenderer)
const rolesprite = new Sprite(engine, roleTexture)
rolesprite.pivot = new Vector2(0, 1)
rolesprite.pixelsPerUnit = 50
roleRenderer.sprite = rolesprite
const roleX = groundTexture.height * scaleTimes * 5
const roleY = canvasY - groundTexture.height * scaleTimes * 2 - roleTexture.height * scaleTimes
const rolepoint = new Vector3(roleX, roleY)
const roleout = new Vector3()
cameramash.screenToWorldPoint(rolepoint, roleout)
roleEntity.transform.position = roleout
roleEntity.transform.scale = new Vector3(scaleTimes, scaleTimes)
// 建立雲實體
const cloud1Texture: Texture2D = await engine.resourceManager.load(textureList[1])
let cloudPlace = 0
while (cloudPlace < 3) {
const cloud1Entity = rootEntity.createChild(`cloud1Sprite_${cloudPlace}`)
const cloud1Renderer = cloud1Entity.addComponent(SpriteRenderer)
const cloud1sprite = new Sprite(engine, cloud1Texture)
cloud1sprite.pivot = new Vector2(0, 1)
cloud1sprite.pixelsPerUnit = 50
cloud1Renderer.sprite = cloud1sprite
const cloud1ponintX = canvasX * cloudPlace / 3 + cloud1Texture.width
const cloud1screenpoint = new Vector3(cloud1ponintX, 0)
const cloud1out = new Vector3()
cameramash.screenToWorldPoint(cloud1screenpoint, cloud1out)
cloud1Entity.transform.position = cloud1out
cloudPlace++
}
// 啓動引擎
engine.run()
}
複製代碼
若是能夠的話,能夠點個小小的贊
respect by myself