從0開始的Oasis Engine學習筆記(六) —— 2D場景佈置

這是我參與更文挑戰的第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
複製代碼

image.png

設置模型座標原點

若是仔細觀察的話能夠發如今屏幕的左上角有1/4個方塊,爲方便觀察咱們使用 groundEntity.transform.scale = new Vector3(5, 5)將素材放大5倍。oop

image.png 咱們將實體的位置設置在屏幕(0, 0)上,而Oasis裏默認的模型座標原點在中心點上,因此此時只能看到1/4個方塊。若是咱們想要看到整個素材就須要設置座標爲 (groundEntity.width / 2, groundEntity.height / 2)。而咱們可使用 sprite.pivot 來從新設置模型座標的原點。post

詳情介紹能夠查看官網的精靈資源(注:rect方法在V0.4版本中爲regionui

咱們這裏將左上角設置爲原點,即可以看到一個完整的方塊url

groundsprite.pivot = new Vector2(0, 1)spa

image.png

素材分辨率設置

我這裏的引用素材大小爲48*48 image.png 然而,渲染後的內容明顯小於素材實際大小3d

image.png 這是由於在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
複製代碼

image.png

因此,能夠得出一個簡單的結論:在世界座標下,若是一個單位的長度對應更多的屏幕像素則圖片會變得更小;反之更大。即,

pixelsPerUnit 數字越大,圖片越小。

因此就能夠將素材經過pixelsPerUnit調整到合適的大小,這裏將pixelsPerUnit調整爲50

groundsprite.pixelsPerUnit = 50

自適應縮放

CPT2106242355-982x633.gif 在遊戲場景中,素材的大小應該能夠隨着用戶屏幕的寬高自適應調整,因此精靈的寬高須要經過屏幕計算而來。

這裏渲染了兩排,每排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朵雲和一個角色,設置一下背景顏色

image.png 一個基本的場景佈置就完成了

完整代碼

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()
}

複製代碼

end

若是能夠的話,能夠點個小小的贊 image.png

respect by myself

相關文章
相關標籤/搜索