add start logo; player now flash when hurted
This commit is contained in:
parent
5504ce68d2
commit
a86f0719fb
|
@ -0,0 +1,14 @@
|
||||||
|
[important]
|
||||||
|
[x] 加上1MGames标志
|
||||||
|
|
||||||
|
[ ] 角色走路动画
|
||||||
|
[ ] 角色受伤特效
|
||||||
|
[x] 角色无敌时闪烁
|
||||||
|
[ ] 新增多个枪类型
|
||||||
|
[ ] 右上角显示分数
|
||||||
|
[ ] 玩家积分榜
|
||||||
|
|
||||||
|
[optional]
|
||||||
|
[ ] 怪物从土里爬出来(新增怪物类型)
|
||||||
|
[ ] 掉落宝物(掉落子弹,加分道具)
|
||||||
|
[ ] 多把武器切换
|
|
@ -1,5 +1,7 @@
|
||||||
local _M = {}
|
local _M = {}
|
||||||
|
|
||||||
|
_M.ShowLicenseTime = 2.5
|
||||||
|
|
||||||
_M.TileSize = 32
|
_M.TileSize = 32
|
||||||
_M.PlayerInfo = {
|
_M.PlayerInfo = {
|
||||||
velocity = 250,
|
velocity = 250,
|
||||||
|
|
|
@ -10,8 +10,8 @@ _M.RestartHintTexture = nil
|
||||||
---@type Texture
|
---@type Texture
|
||||||
_M.StartHintTexture = nil
|
_M.StartHintTexture = nil
|
||||||
|
|
||||||
---@type boolean
|
---@type Texture
|
||||||
_M.IsStartGame = false
|
_M.LicensTexture = nil
|
||||||
|
|
||||||
---@type TileSheet
|
---@type TileSheet
|
||||||
_M.Tilesheet = nil
|
_M.Tilesheet = nil
|
||||||
|
@ -22,6 +22,14 @@ _M.PlayerEntity = nil
|
||||||
---@type table<Entity>
|
---@type table<Entity>
|
||||||
_M.BulletList = {}
|
_M.BulletList = {}
|
||||||
|
|
||||||
|
_M.GameStateEnum = {
|
||||||
|
ShowLogo = 1,
|
||||||
|
WaitStart = 2,
|
||||||
|
Gaming = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
_M.GameState = _M.GameStateEnum.ShowLogo
|
||||||
|
|
||||||
---@type table<Entity>
|
---@type table<Entity>
|
||||||
_M.MonsterList = {}
|
_M.MonsterList = {}
|
||||||
|
|
||||||
|
|
106
game/ecs.lua
106
game/ecs.lua
|
@ -3,6 +3,7 @@ local constants = require "constants"
|
||||||
local math = require "math"
|
local math = require "math"
|
||||||
local vmath = require "vmath"
|
local vmath = require "vmath"
|
||||||
local content = require "content"
|
local content = require "content"
|
||||||
|
local timer = require "timer"
|
||||||
|
|
||||||
---@class ECS
|
---@class ECS
|
||||||
local _M = {}
|
local _M = {}
|
||||||
|
@ -203,7 +204,6 @@ end
|
||||||
---@class ControllerComponent:Component
|
---@class ControllerComponent:Component
|
||||||
|
|
||||||
---@return ControllerComponent
|
---@return ControllerComponent
|
||||||
---@param speed number
|
|
||||||
function _M.CreateControllerComponent()
|
function _M.CreateControllerComponent()
|
||||||
local o = { isActive = true, name = ComponentType.Controller, parent = nil }
|
local o = { isActive = true, name = ComponentType.Controller, parent = nil }
|
||||||
|
|
||||||
|
@ -229,6 +229,12 @@ function _M.CreateControllerComponent()
|
||||||
transform.position.y = transform.position.y + speed * elapseTime
|
transform.position.y = transform.position.y + speed * elapseTime
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local canvaSize = hazel.GetCanvaSize()
|
||||||
|
if transform.position.x < 0 then transform.position.x = 0 end
|
||||||
|
if transform.position.x + transform.size.x > canvaSize.x then transform.position.x = canvaSize.x - transform.size.x end
|
||||||
|
if transform.position.y < constants.PlayerHpBarInfo.height then transform.position.y = constants.PlayerHpBarInfo.height end
|
||||||
|
if transform.position.y + transform.size.y > canvaSize.y then transform.position.y = canvaSize.y - transform.size.y end
|
||||||
|
|
||||||
---@type Point
|
---@type Point
|
||||||
local mousePos = hazel.GetGameMousePos()
|
local mousePos = hazel.GetGameMousePos()
|
||||||
|
|
||||||
|
@ -239,6 +245,14 @@ function _M.CreateControllerComponent()
|
||||||
---@type Point
|
---@type Point
|
||||||
local mouseDir = hazel.CreatePos(mousePos.x - playerCenterX, mousePos.y - playerCenterY)
|
local mouseDir = hazel.CreatePos(mousePos.x - playerCenterX, mousePos.y - playerCenterY)
|
||||||
self:GetParent():GetComponent(ComponentType.Direction):SetDir(mouseDir)
|
self:GetParent():GetComponent(ComponentType.Direction):SetDir(mouseDir)
|
||||||
|
|
||||||
|
if hazel.GetMouseButtonState(hazel.MouseButton.Left) == hazel.InputState.Press then
|
||||||
|
---@type GunComponent
|
||||||
|
local gun = self:GetParent():GetComponent(ComponentType.Gun)
|
||||||
|
if gun then
|
||||||
|
gun:Fire(vmath.Normalize(mouseDir))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return _M.CreateComponent(o)
|
return _M.CreateComponent(o)
|
||||||
|
@ -250,26 +264,54 @@ end
|
||||||
---@return InvincibleComponent
|
---@return InvincibleComponent
|
||||||
---@param time number
|
---@param time number
|
||||||
function _M.CreateInvincibleComponent(time)
|
function _M.CreateInvincibleComponent(time)
|
||||||
local o = { isActive = true, name = ComponentType.Invincible, cooldown = time, timeCountDown = time, parent = nil }
|
local o = { isActive = true, name = ComponentType.Invincible, isInvincible = false, parent = nil }
|
||||||
|
o.flashTimer = nil
|
||||||
|
---@type Timer
|
||||||
|
o.cdTimer = timer.CreateTimer(time, 1, function ()
|
||||||
|
o.isInvincible = false
|
||||||
|
end)
|
||||||
|
o.cdTimer:Stop()
|
||||||
|
|
||||||
---@return boolean
|
---@return boolean
|
||||||
---@param self InvincibleComponent
|
---@param self InvincibleComponent
|
||||||
o.IsInvincibleState = function(self)
|
o.IsInvincibleState = function(self)
|
||||||
return self.timeCountDown > 0
|
return self.cdTimer:IsRunning()
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param self InvincibleComponent
|
---@param self InvincibleComponent
|
||||||
o.IntoInvincible = function(self)
|
o.IntoInvincible = function(self)
|
||||||
if self.timeCountDown <= 0 then
|
if self.isInvincible then
|
||||||
self.timeCountDown = self.cooldown
|
return
|
||||||
end
|
end
|
||||||
|
self.isInvincible = true
|
||||||
|
self.cdTimer:Rewind()
|
||||||
|
self.cdTimer:Start()
|
||||||
|
self.flashTimer = timer.CreateTimer(0.1, time / 0.1,
|
||||||
|
function()
|
||||||
|
---@type ImageComponent
|
||||||
|
local image = o:GetParent():GetComponent(ComponentType.Image)
|
||||||
|
if image then
|
||||||
|
if image:IsActive() then
|
||||||
|
image:Disable()
|
||||||
|
else
|
||||||
|
image:Enable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
function()
|
||||||
|
---@type ImageComponent
|
||||||
|
local image = o:GetParent():GetComponent(ComponentType.Image)
|
||||||
|
if image then
|
||||||
|
image:Enable()
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param self InvincibleComponent
|
---@param self InvincibleComponent
|
||||||
o.Update = function(self)
|
o.Update = function(self)
|
||||||
self.timeCountDown = self.timeCountDown - hazel.Time.GetElapseTime()
|
self.cdTimer:Update()
|
||||||
if self.timeCountDown < 0 then
|
if self.flashTimer then
|
||||||
self.timeCountDown = 0
|
self.flashTimer:Update()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -368,34 +410,39 @@ end
|
||||||
---@param damage number
|
---@param damage number
|
||||||
---@param velocity number
|
---@param velocity number
|
||||||
function _M.CreateGunComponent(damage, velocity)
|
function _M.CreateGunComponent(damage, velocity)
|
||||||
local o = { isActive = true, name = ComponentType.Gun, damage = damage, timeCounter = 0, parent = nil }
|
local o = { isActive = true, name = ComponentType.Gun, damage = damage, canShoot = true, velocity = velocity, parent = nil }
|
||||||
|
o.cdTimer = timer.CreateTimer(constants.GunInfo.cooldown, -1, function()
|
||||||
|
o.canShoot = true
|
||||||
|
end)
|
||||||
|
|
||||||
|
---@param self GunComponent
|
||||||
|
---@param dir Point
|
||||||
|
o.Fire = function(self, dir)
|
||||||
|
if not self.canShoot then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
---@type Point
|
||||||
|
local position = self:GetParent():GetComponent(ComponentType.Transform).position
|
||||||
|
local playerCenterX = position.x + constants.TileSize / 2
|
||||||
|
local playerCenterY = position.y + constants.TileSize / 2
|
||||||
|
local ndir = vmath.Normalize(dir)
|
||||||
|
local bullet = _M.CreateBullet(hazel.CreatePos(playerCenterX - constants.TileSize / 2, playerCenterY - constants.TileSize / 2),
|
||||||
|
self.damage,
|
||||||
|
hazel.CreatePos(ndir.x * self.velocity, ndir.y * self.velocity))
|
||||||
|
table.insert(content.BulletList, bullet)
|
||||||
|
|
||||||
|
self.canShoot = false
|
||||||
|
end
|
||||||
|
|
||||||
---@param self GunComponent
|
---@param self GunComponent
|
||||||
o.Update = function(self)
|
o.Update = function(self)
|
||||||
if self.timeCounter < constants.GunInfo.cooldown then
|
self.cdTimer:Update()
|
||||||
self.timeCounter = self.timeCounter + hazel.Time.GetElapseTime()
|
|
||||||
end
|
|
||||||
if self.timeCounter >= constants.GunInfo.cooldown then
|
|
||||||
self.timeCounter = constants.GunInfo.cooldown
|
|
||||||
end
|
|
||||||
if hazel.GetMouseButtonState(hazel.MouseButton.Left) == hazel.InputState.Press and self.timeCounter >= constants.GunInfo.cooldown then
|
|
||||||
self.timeCounter = self.timeCounter - constants.GunInfo.cooldown
|
|
||||||
---@type Point
|
|
||||||
local position = self:GetParent():GetComponent(ComponentType.Transform).position
|
|
||||||
---@type Point
|
|
||||||
local mousePos = hazel.GetGameMousePos()
|
|
||||||
local playerCenterX = position.x + constants.TileSize / 2
|
|
||||||
local playerCenterY = position.y + constants.TileSize / 2
|
|
||||||
local nMouseDir = vmath.Normalize(hazel.CreatePos(mousePos.x - playerCenterX, mousePos.y - playerCenterY))
|
|
||||||
|
|
||||||
local bullet = _M.CreateBullet(hazel.CreatePos(playerCenterX - constants.TileSize / 2, playerCenterY - constants.TileSize / 2), self.damage, hazel.CreatePos(nMouseDir.x * velocity, nMouseDir.y * velocity))
|
|
||||||
table.insert(content.BulletList, bullet)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return _M.CreateComponent(o)
|
return _M.CreateComponent(o)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---@class BulletComponent:Component
|
---@class BulletComponent:Component
|
||||||
---@field damage number
|
---@field damage number
|
||||||
---@field speed Point
|
---@field speed Point
|
||||||
|
@ -449,6 +496,7 @@ function _M.CreatePlayer(pos)
|
||||||
entity:SetComponent(_M.CreateImageComponent(content.Tilesheet, 0, 0))
|
entity:SetComponent(_M.CreateImageComponent(content.Tilesheet, 0, 0))
|
||||||
entity:SetComponent(_M.CreateRolePropComponent(constants.PlayerInfo.hp, constants.PlayerInfo.velocity))
|
entity:SetComponent(_M.CreateRolePropComponent(constants.PlayerInfo.hp, constants.PlayerInfo.velocity))
|
||||||
entity:SetComponent(_M.CreateDirectionComponent(0))
|
entity:SetComponent(_M.CreateDirectionComponent(0))
|
||||||
|
entity:SetComponent(_M.CreateGunComponent(constants.BulletInfo.damage, constants.BulletInfo.velocity))
|
||||||
entity:SetComponent(_M.CreateColliBoxComponent(constants.RoleColliBox))
|
entity:SetComponent(_M.CreateColliBoxComponent(constants.RoleColliBox))
|
||||||
entity:SetComponent(_M.CreateInvincibleComponent(constants.Invincible))
|
entity:SetComponent(_M.CreateInvincibleComponent(constants.Invincible))
|
||||||
return entity
|
return entity
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
local hazel = require "hazel"
|
local hazel = require "hazel"
|
||||||
local ECS = require "ecs"
|
local ECS = require "ecs"
|
||||||
local constants = require "constants"
|
local constants = require "constants"
|
||||||
local math = require "math"
|
|
||||||
local content = require "content"
|
local content = require "content"
|
||||||
local vmath = require "vmath"
|
local vmath = require "vmath"
|
||||||
|
local timer = require "timer"
|
||||||
|
|
||||||
local function drawCurosr()
|
local function drawCurosr()
|
||||||
hazel.Renderer.SetDrawColor(1, 0, 0, 1)
|
hazel.Renderer.SetDrawColor(1, 0, 0, 1)
|
||||||
|
@ -170,7 +170,7 @@ local function initGame()
|
||||||
content.MonsterList = {}
|
content.MonsterList = {}
|
||||||
content.PlayerEntity = ECS.CreatePlayer(hazel.CreatePos(constants.TileSize * 16, constants.TileSize * 13))
|
content.PlayerEntity = ECS.CreatePlayer(hazel.CreatePos(constants.TileSize * 16, constants.TileSize * 13))
|
||||||
content.MonsterBirthNum = constants.MonsterBirthInitNum
|
content.MonsterBirthNum = constants.MonsterBirthInitNum
|
||||||
content.IsStartGame = false
|
content.GameState = content.GameStateEnum.WaitStart
|
||||||
end
|
end
|
||||||
|
|
||||||
local function generateMonster()
|
local function generateMonster()
|
||||||
|
@ -205,15 +205,26 @@ local function generateMonster()
|
||||||
content.MonsterBirthCountDown = constants.MonsterBirthInterval
|
content.MonsterBirthCountDown = constants.MonsterBirthInterval
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type Timer
|
||||||
|
local showLicenseTimer = nil
|
||||||
|
|
||||||
function GameStart()
|
function GameStart()
|
||||||
hazel.SetWindowIcon("resources/icon.png")
|
hazel.SetWindowIcon("resources/icon.png")
|
||||||
content.Texture = hazel.LoadTexture("resources/tilesheet.png")
|
content.Texture = hazel.LoadTexture("resources/tilesheet.png")
|
||||||
content.RestartHintTexture = hazel.LoadTexture("resources/RestartHint.png")
|
content.RestartHintTexture = hazel.LoadTexture("resources/RestartHint.png")
|
||||||
|
content.LicensTexture = hazel.LoadTexture("resources/License.png")
|
||||||
content.StartHintTexture = hazel.LoadTexture("resources/StartHint.png")
|
content.StartHintTexture = hazel.LoadTexture("resources/StartHint.png")
|
||||||
content.Tilesheet = hazel.CreateTileSheet(content.Texture, 3, 10)
|
content.Tilesheet = hazel.CreateTileSheet(content.Texture, 3, 10)
|
||||||
|
|
||||||
initGame()
|
initGame()
|
||||||
|
|
||||||
|
content.GameState = content.GameStateEnum.ShowLogo
|
||||||
|
|
||||||
|
showLicenseTimer = timer.CreateTimer(constants.ShowLicenseTime, 1, function()
|
||||||
|
content.GameState = content.GameStateEnum.WaitStart
|
||||||
|
showLicenseTimer = nil
|
||||||
|
end)
|
||||||
|
|
||||||
hazel.HideCursor()
|
hazel.HideCursor()
|
||||||
generateFloors()
|
generateFloors()
|
||||||
end
|
end
|
||||||
|
@ -221,14 +232,21 @@ end
|
||||||
function GameLoop()
|
function GameLoop()
|
||||||
hazel.Time.RecordElapseTime()
|
hazel.Time.RecordElapseTime()
|
||||||
|
|
||||||
|
if showLicenseTimer then
|
||||||
|
showLicenseTimer:Update()
|
||||||
|
end
|
||||||
|
|
||||||
hazel.Renderer.SetClearColor(0, 0, 0, 1)
|
hazel.Renderer.SetClearColor(0, 0, 0, 1)
|
||||||
hazel.Renderer.Clear()
|
hazel.Renderer.Clear()
|
||||||
|
|
||||||
drawFloors()
|
if content.GameState == content.GameStateEnum.ShowLogo then
|
||||||
updateMonster()
|
local dstrect = hazel.CreateRect(0, 0, 0, 0)
|
||||||
content.PlayerEntity:Update()
|
dstrect.w = content.LicensTexture.w * 5
|
||||||
updateBullet()
|
dstrect.h = content.LicensTexture.h * 5
|
||||||
collisionDeal()
|
dstrect.x = (hazel.GetCanvaSize().x - dstrect.w) / 2
|
||||||
|
dstrect.y = (hazel.GetCanvaSize().y - dstrect.h) / 2
|
||||||
|
hazel.Renderer.DrawTexture(content.LicensTexture, nil, dstrect)
|
||||||
|
end
|
||||||
|
|
||||||
---@type RolePropComponent
|
---@type RolePropComponent
|
||||||
local playerRoleInfo = content.PlayerEntity:GetComponent(ECS.ComponentType.RoleProp)
|
local playerRoleInfo = content.PlayerEntity:GetComponent(ECS.ComponentType.RoleProp)
|
||||||
|
@ -239,12 +257,20 @@ function GameLoop()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not content.IsStartGame then
|
if content.GameState == content.GameStateEnum.WaitStart or content.GameState == content.GameStateEnum.Gaming then
|
||||||
|
drawFloors()
|
||||||
|
updateMonster()
|
||||||
|
content.PlayerEntity:Update()
|
||||||
|
updateBullet()
|
||||||
|
collisionDeal()
|
||||||
|
drawCurosr()
|
||||||
|
end
|
||||||
|
|
||||||
|
if content.GameState == content.GameStateEnum.WaitStart then
|
||||||
showStartHint()
|
showStartHint()
|
||||||
if hazel.GetMouseButtonState(hazel.MouseButton.Left) == hazel.InputState.Press then
|
if hazel.GetMouseButtonState(hazel.MouseButton.Left) == hazel.InputState.Press then
|
||||||
content.IsStartGame = true
|
content.GameState = content.GameStateEnum.Gaming
|
||||||
content.PlayerEntity:SetComponent(ECS.CreateControllerComponent())
|
content.PlayerEntity:SetComponent(ECS.CreateControllerComponent())
|
||||||
content.PlayerEntity:SetComponent(ECS.CreateGunComponent(constants.BulletInfo.damage, constants.BulletInfo.velocity))
|
|
||||||
content.PlayerEntity:SetComponent(ECS.CreateHpShowComponent(hazel.CreateSize(constants.PlayerHpBarInfo.width, constants.PlayerHpBarInfo.height)))
|
content.PlayerEntity:SetComponent(ECS.CreateHpShowComponent(hazel.CreateSize(constants.PlayerHpBarInfo.width, constants.PlayerHpBarInfo.height)))
|
||||||
|
|
||||||
for _, v in pairs(content.MonsterList) do
|
for _, v in pairs(content.MonsterList) do
|
||||||
|
@ -253,13 +279,11 @@ function GameLoop()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if content.IsStartGame then
|
if content.GameState == content.GameStateEnum.Gaming then
|
||||||
for i = 0, content.MonsterBirthNum do
|
for i = 0, content.MonsterBirthNum do
|
||||||
generateMonster()
|
generateMonster()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
drawCurosr()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameQuit()
|
function GameQuit()
|
||||||
|
@ -267,4 +291,5 @@ function GameQuit()
|
||||||
hazel.DestroyTexture(content.Texture)
|
hazel.DestroyTexture(content.Texture)
|
||||||
hazel.DestroyTexture(content.RestartHintTexture)
|
hazel.DestroyTexture(content.RestartHintTexture)
|
||||||
hazel.DestroyTexture(content.StartHintTexture)
|
hazel.DestroyTexture(content.StartHintTexture)
|
||||||
|
hazel.DestroyTexture(content.LicensTexture)
|
||||||
end
|
end
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 831 B |
|
@ -0,0 +1,59 @@
|
||||||
|
local hazel = require "hazel"
|
||||||
|
|
||||||
|
---@class Timer
|
||||||
|
local _M = {}
|
||||||
|
|
||||||
|
---@param interval number seconds
|
||||||
|
---@param loop number -1 means infinite loop
|
||||||
|
---@param callback function|nil a no param, no return value callback function
|
||||||
|
---@param onStopFunc function|nil a no param, no return value callback function called when timer stop
|
||||||
|
function _M.CreateTimer(interval, loop, callback, onStopFunc)
|
||||||
|
local o = {isStart = true, interval = interval, totleLoop = loop, loop = loop, callback = callback, onStopFunc = onStopFunc, counter = 0}
|
||||||
|
setmetatable(o, {__index = _M})
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param self Timer
|
||||||
|
function _M.Rewind(self)
|
||||||
|
self.loop = self.totleLoop
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param self Timer
|
||||||
|
function _M.Start(self)
|
||||||
|
self.isStart = true
|
||||||
|
end
|
||||||
|
|
||||||
|
---@return boolean
|
||||||
|
---@param self Timer
|
||||||
|
function _M.IsRunning(self)
|
||||||
|
return self.isStart
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param self Timer
|
||||||
|
function _M.Stop(self)
|
||||||
|
self.isStart = false
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param self Timer
|
||||||
|
function _M.Update(self)
|
||||||
|
if self.loop == 0 then
|
||||||
|
if self:IsRunning() then
|
||||||
|
if self.onStopFunc then
|
||||||
|
self.onStopFunc()
|
||||||
|
end
|
||||||
|
self:Stop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if self:IsRunning() then
|
||||||
|
self.counter = self.counter + hazel.Time.GetElapseTime()
|
||||||
|
while self.counter >= self.interval do
|
||||||
|
self.counter = self.counter - self.interval
|
||||||
|
self.loop = self.loop - 1
|
||||||
|
if self.callback then
|
||||||
|
self.callback()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return _M
|
Reference in New Issue