add bullet type, supply
This commit is contained in:
parent
05d3e8ace8
commit
2753f02a6e
|
@ -5,8 +5,7 @@ install
|
|||
TODO.txt
|
||||
.cache
|
||||
compile_flags.txt
|
||||
game/shader
|
||||
game/*.dll
|
||||
game/*.dll.a
|
||||
game/*.exe
|
||||
*.zip
|
||||
game/*.dll
|
||||
game/*.exe
|
||||
game/shader
|
||||
|
|
|
@ -18,7 +18,7 @@ include(cmake/FindSTB.cmake)
|
|||
# hazel-core
|
||||
aux_source_directory(src HAZEL_SRC)
|
||||
add_library(${HAZEL_CORE_NAME} SHARED ${HAZEL_SRC})
|
||||
target_link_libraries(${HAZEL_CORE_NAME} PUBLIC glad glfw stb_image)
|
||||
target_link_libraries(${HAZEL_CORE_NAME} PUBLIC glad glfw stb_image "winmm")
|
||||
target_include_directories(${HAZEL_CORE_NAME} PUBLIC .)
|
||||
target_compile_features(${HAZEL_CORE_NAME} PUBLIC c_std_11)
|
||||
target_precompile_headers(${HAZEL_CORE_NAME} PUBLIC hazel/pch.h)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "hazel/hazel.h"
|
||||
#include "hazel/renderer.h"
|
||||
#include "hazel/sound.h"
|
||||
|
||||
static int LuaBridge_RenderSetClearColor(lua_State* L) {
|
||||
float r = luaL_checknumber(L, 1);
|
||||
|
@ -145,16 +146,29 @@ static int LuaBridge_GetWindowSize(lua_State* L) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
static int LuaBridge_HideCursor() {
|
||||
static int LuaBridge_HideCursor(lua_State* L) {
|
||||
Hazel_HideCursor();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int LuaBridge_ShowCursor() {
|
||||
static int LuaBridge_ShowCursor(lua_State* L) {
|
||||
Hazel_ShowCursor();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int LuaBridge_LoadSound(lua_State* L) {
|
||||
const char* filename = luaL_checkstring(L, 1);
|
||||
const char* soundName = luaL_checkstring(L, 2);
|
||||
Hazel_LoadSound(filename, soundName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int LuaBridge_PlaySound(lua_State* L) {
|
||||
const char* soundName = luaL_checkstring(L, 1);
|
||||
Hazel_PlaySound(soundName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct luaL_Reg libhazel[] = {
|
||||
{"RenderSetClearColor", LuaBridge_RenderSetClearColor},
|
||||
{"RenderSetDrawColor", LuaBridge_RenderSetDrawColor},
|
||||
|
@ -176,6 +190,8 @@ static const struct luaL_Reg libhazel[] = {
|
|||
{"HideCursor", LuaBridge_HideCursor},
|
||||
{"ShowCursor", LuaBridge_ShowCursor},
|
||||
{"SayHello", LuaBridge_SayHello},
|
||||
{"LoadSound", LuaBridge_LoadSound},
|
||||
{"PlaySound", LuaBridge_PlaySound},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -462,4 +462,19 @@ end
|
|||
|
||||
_M.Time = Time
|
||||
|
||||
local Sound = {}
|
||||
|
||||
---@param filename string
|
||||
---@param name string
|
||||
function Sound.LoadSound(filename, name)
|
||||
libhazel.Load(filename, name);
|
||||
end
|
||||
|
||||
---@param name string
|
||||
function Sound.Play(name)
|
||||
libhazel.PlaySound( name);
|
||||
end
|
||||
|
||||
_M.Sound = Sound
|
||||
|
||||
return _M
|
||||
|
|
12
game/TODO.md
12
game/TODO.md
|
@ -1,14 +1,14 @@
|
|||
[important]
|
||||
[x] 加上1MGames标志
|
||||
|
||||
[ ] 角色走路动画
|
||||
[ ] 角色受伤特效
|
||||
[x] 增加音效
|
||||
[x] 角色无敌时闪烁
|
||||
[ ] 新增多个枪类型
|
||||
[ ] 右上角显示分数
|
||||
[ ] 玩家积分榜
|
||||
[x] 新增多个枪类型
|
||||
[x] 右上角显示分数
|
||||
|
||||
[FIXME]
|
||||
[ ] Component的Update顺序是随机的
|
||||
|
||||
[optional]
|
||||
[ ] 怪物从土里爬出来(新增怪物类型)
|
||||
[ ] 掉落宝物(掉落子弹,加分道具)
|
||||
[ ] 多把武器切换
|
|
@ -8,7 +8,7 @@ local _M = {}
|
|||
---@field col number
|
||||
---@field time number
|
||||
|
||||
---@param tilesheet Texture
|
||||
---@param tilesheet TileSheet
|
||||
---@param frames table<Frame>
|
||||
---@param onEndCallback function
|
||||
function _M.CreateAnimation(tilesheet, frames, onEndCallback)
|
||||
|
@ -42,6 +42,8 @@ function _M.GetCurFrame(self)
|
|||
end
|
||||
end
|
||||
|
||||
---@return TileSheet
|
||||
---@param self Animation
|
||||
function _M.GetTilesheet(self)
|
||||
return self.tilesheet
|
||||
end
|
||||
|
|
|
@ -2,6 +2,13 @@ local _M = {}
|
|||
|
||||
_M.ShowLicenseTime = 2.5
|
||||
|
||||
_M.SoundName = {
|
||||
Shoot = "SHOOT",
|
||||
PlayerHurt = "PLAYER_HURT",
|
||||
MonsterHurt = "MONSTER_HURT",
|
||||
GameOver = "GAMEOVER",
|
||||
}
|
||||
|
||||
_M.TileSize = 32
|
||||
_M.PlayerInfo = {
|
||||
velocity = 250,
|
||||
|
@ -18,6 +25,12 @@ _M.RoleColliBox = {
|
|||
x = 9,
|
||||
y = 0,
|
||||
}
|
||||
_M.SupplyColliBox = {
|
||||
w = 32,
|
||||
h = 32,
|
||||
x = 9,
|
||||
y = 0,
|
||||
}
|
||||
_M.MonsterBirthInterval = 1
|
||||
_M.MonsterBirthInitNum = 1
|
||||
_M.Invincible = 1
|
||||
|
@ -39,16 +52,55 @@ _M.MonsetHpBarInfo= {
|
|||
_M.GunInfo = {
|
||||
cooldown = 0.1
|
||||
}
|
||||
|
||||
_M.BulletType = {
|
||||
Normal = 1,
|
||||
Ice = 2,
|
||||
Fire = 3,
|
||||
}
|
||||
|
||||
_M.BulletInfo = {
|
||||
[_M.BulletType.Normal] = {
|
||||
damage = 10,
|
||||
velocity = 500,
|
||||
cooldown = 0.1,
|
||||
initNum = -1,
|
||||
},
|
||||
[_M.BulletType.Ice] = {
|
||||
damage = 5,
|
||||
velocity = 400,
|
||||
cooldown = 0.1,
|
||||
initNum = 100,
|
||||
},
|
||||
[_M.BulletType.Fire] = {
|
||||
damage = 7,
|
||||
velocity = 600,
|
||||
cooldown = 0.1,
|
||||
fireDamage = 1,
|
||||
initNum = 100,
|
||||
},
|
||||
}
|
||||
_M.GunInfo = {
|
||||
cooldown = 0.1
|
||||
|
||||
_M.BulletEffectTime = {
|
||||
IceTime = 2,
|
||||
FireTime = 2,
|
||||
}
|
||||
_M.BulletInfo = {
|
||||
damage = 10,
|
||||
velocity = 500,
|
||||
_M.RoleState = {
|
||||
Normal = 1,
|
||||
Ice = 2,
|
||||
Fire = 3,
|
||||
}
|
||||
_M.SupplyFalldownKillNum = 120
|
||||
|
||||
_M.SupplyType = {
|
||||
IceGun = 1,
|
||||
FireGun = 2,
|
||||
HpRecover = 3,
|
||||
}
|
||||
_M.SupplyItem = {
|
||||
[_M.SupplyType.IceGun] = { num = 100 },
|
||||
[_M.SupplyType.FireGun] = { num = 100 },
|
||||
[_M.SupplyType.HpRecover] = { recover = 50},
|
||||
}
|
||||
|
||||
return _M
|
||||
|
|
|
@ -13,9 +13,15 @@ _M.StartHintTexture = nil
|
|||
---@type Texture
|
||||
_M.LicensTexture = nil
|
||||
|
||||
---@type Texture
|
||||
_M.NumberTexture = nil
|
||||
|
||||
---@type TileSheet
|
||||
_M.Tilesheet = nil
|
||||
|
||||
---@type TileSheet
|
||||
_M.NumberTilesheet = nil
|
||||
|
||||
---@type Entity
|
||||
_M.PlayerEntity = nil
|
||||
|
||||
|
@ -57,4 +63,12 @@ _M.Animations = {
|
|||
EnemyWalkLeft = nil,
|
||||
}
|
||||
|
||||
---@type number
|
||||
_M.KillNum = 0
|
||||
---@type number
|
||||
_M.Score = 0
|
||||
|
||||
---@type table<Entity>
|
||||
_M.SupplyList = {}
|
||||
|
||||
return _M
|
234
game/ecs.lua
234
game/ecs.lua
|
@ -4,6 +4,8 @@ local math = require "math"
|
|||
local vmath = require "vmath"
|
||||
local content = require "content"
|
||||
local timer = require "timer"
|
||||
local animation = require "animation"
|
||||
local helpfuncs = require "helpfunc"
|
||||
|
||||
---@class ECS
|
||||
local _M = {}
|
||||
|
@ -29,7 +31,7 @@ function Entity.SetComponent(self, component)
|
|||
end
|
||||
|
||||
---@return Component|nil
|
||||
---@param type string
|
||||
---@param type number
|
||||
function Entity.GetComponent(self, type)
|
||||
if not type then
|
||||
return nil
|
||||
|
@ -102,17 +104,20 @@ end
|
|||
|
||||
---@class ComponentType
|
||||
local ComponentType = {
|
||||
Transform = "Transform",
|
||||
Image = "Image",
|
||||
Controller = "Controller",
|
||||
RoleProp = "RoleProp",
|
||||
HpShow = "HpShow",
|
||||
Gun = "Gun",
|
||||
Bullet = "Bullet",
|
||||
Direction = "Direction",
|
||||
AI = "AI",
|
||||
ColliBox = "ColliBox",
|
||||
Invincible = "Invincible",
|
||||
Transform = 1,
|
||||
Controller = 2,
|
||||
RoleProp = 3,
|
||||
HpShow = 4,
|
||||
Gun = 5,
|
||||
Bullet = 6,
|
||||
Direction = 7,
|
||||
AI = 8,
|
||||
ColliBox = 9,
|
||||
Invincible = 10,
|
||||
Animator = 11,
|
||||
State = 12,
|
||||
Supply = 13,
|
||||
Image = 14,
|
||||
}
|
||||
|
||||
_M.ComponentType = ComponentType
|
||||
|
@ -215,6 +220,8 @@ function _M.CreateControllerComponent()
|
|||
|
||||
---@type TransformComponent
|
||||
local transform = self:GetParent():GetComponent(ComponentType.Transform)
|
||||
---@type AnimatorComponent
|
||||
local animator = self:GetParent():GetComponent(ComponentType.Animator)
|
||||
local elapseTime = hazel.Time.GetElapseTime()
|
||||
if hazel.IsKeyPressing(hazel.Key.A) then
|
||||
transform.position.x = transform.position.x - speed * elapseTime
|
||||
|
@ -379,6 +386,10 @@ function _M.CreateAIComponent()
|
|||
|
||||
---@param self AIComponent
|
||||
o.Update = function(self)
|
||||
local state = self:GetParent():GetComponent(ComponentType.State):GetState()
|
||||
if state == constants.RoleState.Ice then
|
||||
return
|
||||
end
|
||||
---@type DirectionComponent
|
||||
local direction = self:GetParent():GetComponent(ComponentType.Direction)
|
||||
|
||||
|
@ -407,31 +418,50 @@ end
|
|||
---@field speed Point
|
||||
|
||||
---@return GunComponent
|
||||
---@param damage number
|
||||
---@param velocity number
|
||||
function _M.CreateGunComponent(damage, velocity)
|
||||
local o = { isActive = true, name = ComponentType.Gun, damage = damage, canShoot = true, velocity = velocity, parent = nil }
|
||||
o.cdTimer = timer.CreateTimer(constants.GunInfo.cooldown, -1, function()
|
||||
---@param type number
|
||||
---@param bulletNum number|nil
|
||||
function _M.CreateGunComponent(type, bulletNum)
|
||||
local o = { isActive = true, name = ComponentType.Gun, type = type, canShoot = true, parent = nil }
|
||||
o.bulletNum = constants.BulletInfo[type or constants.BulletType.Normal].initNum
|
||||
o.cdTimer = timer.CreateTimer(constants.BulletInfo[type].cooldown, -1, function()
|
||||
o.canShoot = true
|
||||
end)
|
||||
|
||||
o.SetType = function(self, type)
|
||||
self.type = type or constants.BulletType.Normal
|
||||
self.bulletNum = constants.BulletInfo[self.type].initNum
|
||||
end
|
||||
|
||||
o.GetBulletNum = function(self)
|
||||
return self.bulletNum
|
||||
end
|
||||
|
||||
---@param self GunComponent
|
||||
---@param dir Point
|
||||
o.Fire = function(self, dir)
|
||||
if not self.canShoot then
|
||||
if not self.canShoot or self.bulletNum == 0 then
|
||||
return
|
||||
end
|
||||
hazel.Sound.Play(constants.SoundName.Shoot)
|
||||
---@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 velocity = constants.BulletInfo[type].velocity
|
||||
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))
|
||||
constants.BulletInfo[type].damage,
|
||||
hazel.CreatePos(ndir.x * velocity, ndir.y * velocity),
|
||||
self.type)
|
||||
table.insert(content.BulletList, bullet)
|
||||
|
||||
self.canShoot = false
|
||||
hazel.Sound.Play(constants.SoundName.Shoot)
|
||||
self.bulletNum = self.bulletNum - 1
|
||||
|
||||
if self.bulletNum == 0 then
|
||||
self:SetType(constants.BulletType.Normal)
|
||||
end
|
||||
end
|
||||
|
||||
---@param self GunComponent
|
||||
|
@ -450,9 +480,14 @@ end
|
|||
---@return BulletComponent
|
||||
---@param damage number
|
||||
---@param speed Point
|
||||
function _M.CreateBulletComponent(damage, speed)
|
||||
local o = { isActive = true, name = ComponentType.Bullet, damage = damage, speed = speed, parent = nil }
|
||||
---@param type number
|
||||
function _M.CreateBulletComponent(damage, speed, type)
|
||||
local o = { isActive = true, name = ComponentType.Bullet, damage = damage, type = type, speed = speed, parent = nil }
|
||||
---@param self BulletComponent
|
||||
o.GetType = function(self)
|
||||
return self.type
|
||||
end
|
||||
|
||||
o.Update = function(self)
|
||||
local position = self:GetParent():GetComponent(ComponentType.Transform).position
|
||||
local elapseTime = hazel.Time.GetElapseTime()
|
||||
|
@ -474,16 +509,150 @@ function _M.CreateColliBoxComponent(rect)
|
|||
end
|
||||
|
||||
|
||||
---@class SupplyComponent:Component
|
||||
---@field rect Rect
|
||||
|
||||
---@return SupplyComponent
|
||||
---@param type number
|
||||
function _M.CreateSupplyComponent(type)
|
||||
local o = { isActive = true, name = ComponentType.Supply, type = type, parent = nil }
|
||||
o.Update = function(self) end
|
||||
return _M.CreateComponent(o)
|
||||
end
|
||||
|
||||
|
||||
---@class StateComponent:Component
|
||||
---@field rect Rect
|
||||
|
||||
---@return StateComponent
|
||||
---@param state number|nil
|
||||
function _M.CreateStateComponent(state)
|
||||
local o = { isActive = true, name = ComponentType.State, state = state or constants.RoleState.Normal, parent = nil }
|
||||
---@type Animation
|
||||
o.fireAnimation = animation.CreateAnimation(content.Tilesheet, {
|
||||
{row = 10, col = 2, time = 0.2},
|
||||
{row = 11, col = 0, time = 0.2},
|
||||
}, function()
|
||||
o.fireAnimation:Rewind()
|
||||
o.fireAnimation:Play()
|
||||
end)
|
||||
o.GetState = function(self)
|
||||
return self.state
|
||||
end
|
||||
o.IntoIce = function(self)
|
||||
self.state = constants.RoleState.Ice
|
||||
self.cdTimer = timer.CreateTimer(constants.BulletEffectTime.IceTime, 1, function()
|
||||
if self.state == constants.RoleState.Ice then
|
||||
self.state = constants.RoleState.Normal
|
||||
end
|
||||
end)
|
||||
end
|
||||
o.IntoFire = function(self)
|
||||
self.state = constants.RoleState.Fire
|
||||
self.fireAnimation:Play()
|
||||
self.cdTimer = timer.CreateTimer(constants.BulletEffectTime.FireTime, 1, function()
|
||||
self.fireAnimation:Stop()
|
||||
if self.state == constants.RoleState.Fire then
|
||||
self.state = constants.RoleState.Normal
|
||||
end
|
||||
end)
|
||||
end
|
||||
---@param self StateComponent
|
||||
o.Update = function(self)
|
||||
self.fireAnimation:Update()
|
||||
if self.fireAnimation:IsPlaying() then
|
||||
local frame = self.fireAnimation:GetCurFrame()
|
||||
---@type Point
|
||||
local position = self:GetParent():GetComponent(ComponentType.Transform).position
|
||||
self.fireAnimation:GetTilesheet():Draw(frame.col, frame.row, hazel.CreateRect(position.x, position.y, constants.TileSize, constants.TileSize))
|
||||
end
|
||||
if self.state == constants.RoleState.Ice then
|
||||
local position = self:GetParent():GetComponent(ComponentType.Transform).position
|
||||
content.Tilesheet:Draw(2, 9, hazel.CreateRect(position.x, position.y, constants.TileSize, constants.TileSize))
|
||||
elseif self.state == constants.RoleState.Fire then
|
||||
---@type RolePropComponent
|
||||
local roleProp = self:GetParent():GetComponent(ComponentType.RoleProp)
|
||||
local oldHp = roleProp.hp
|
||||
roleProp.hp = roleProp.hp - constants.BulletInfo[constants.BulletType.Fire].fireDamage
|
||||
if oldHp > 0 and roleProp.hp <= 0 then
|
||||
content.Score = content.Score + 1
|
||||
helpfuncs.IncKillNum()
|
||||
end
|
||||
end
|
||||
if self.cdTimer then
|
||||
self.cdTimer:Update()
|
||||
end
|
||||
end
|
||||
return _M.CreateComponent(o)
|
||||
end
|
||||
|
||||
---@class AnimatorComponent:Component
|
||||
---@field Play function
|
||||
---@field Stop function
|
||||
---@field Pause function
|
||||
---@field Rewind function
|
||||
---@field SetAnimation function
|
||||
---@field GetAnimation function
|
||||
|
||||
---@param ani Animation
|
||||
function _M.CreateAnimatorComponent(ani)
|
||||
local o = { isActive = true, name = ComponentType.Animator, ani = ani, parent = nil }
|
||||
|
||||
o.Play = function(self) self.ani:Play() end
|
||||
o.Pause = function(self) self.ani:Pause() end
|
||||
o.Rewind = function(self) self.ani:Rewind() end
|
||||
o.Stop = function(self)
|
||||
self.ani:Stop()
|
||||
self.ani:Rewind()
|
||||
end
|
||||
o.SetAnimation = function(self, ani)
|
||||
if self.ani then
|
||||
self.ani:Stop()
|
||||
self.ani:Rewind()
|
||||
self.ani = ani
|
||||
end
|
||||
end
|
||||
o.GetAnimation = function(self) return self.ani end
|
||||
|
||||
---@param self AnimatorComponent
|
||||
o.Update = function(self)
|
||||
if not self.ani then
|
||||
return
|
||||
end
|
||||
self.ani:Update()
|
||||
---@type ImageComponent
|
||||
local image = self:GetParent():GetComponent(ComponentType.Image)
|
||||
if image then
|
||||
local frame = self.ani:GetCurFrame()
|
||||
if frame then
|
||||
image.row = frame.row
|
||||
image.col = frame.col
|
||||
image.tilesheet = self.ani:GetTilesheet()
|
||||
end
|
||||
end
|
||||
end
|
||||
return _M.CreateComponent(o)
|
||||
end
|
||||
|
||||
|
||||
---@return Entity
|
||||
---@param pos Point
|
||||
---@param damage number
|
||||
---@param speed Point
|
||||
function _M.CreateBullet(pos, damage, speed)
|
||||
---@param type number|nil
|
||||
function _M.CreateBullet(pos, damage, speed, type)
|
||||
type = type or constants.BulletType.Normal
|
||||
---@type Entity
|
||||
local entity = _M.CreateEntity("Bullet")
|
||||
entity:SetComponent(_M.CreateTransformComponent(pos, hazel.CreateSize(constants.TileSize, constants.TileSize)))
|
||||
entity:SetComponent(_M.CreateBulletComponent(damage, speed))
|
||||
entity:SetComponent(_M.CreateBulletComponent(damage, speed, type))
|
||||
if type == constants.BulletType.Normal then
|
||||
entity:SetComponent(_M.CreateImageComponent(content.Tilesheet, 1, 4))
|
||||
elseif type == constants.BulletType.Ice then
|
||||
entity:SetComponent(_M.CreateImageComponent(content.Tilesheet, 0, 10))
|
||||
elseif type == constants.BulletType.Fire then
|
||||
entity:SetComponent(_M.CreateImageComponent(content.Tilesheet, 1, 10))
|
||||
end
|
||||
entity:SetComponent(_M.CreateColliBoxComponent(constants.BulletColliBox))
|
||||
return entity
|
||||
end
|
||||
|
@ -496,9 +665,10 @@ function _M.CreatePlayer(pos)
|
|||
entity:SetComponent(_M.CreateImageComponent(content.Tilesheet, 0, 0))
|
||||
entity:SetComponent(_M.CreateRolePropComponent(constants.PlayerInfo.hp, constants.PlayerInfo.velocity))
|
||||
entity:SetComponent(_M.CreateDirectionComponent(0))
|
||||
entity:SetComponent(_M.CreateGunComponent(constants.BulletInfo.damage, constants.BulletInfo.velocity))
|
||||
entity:SetComponent(_M.CreateGunComponent(constants.BulletType.Fire))
|
||||
entity:SetComponent(_M.CreateColliBoxComponent(constants.RoleColliBox))
|
||||
entity:SetComponent(_M.CreateInvincibleComponent(constants.Invincible))
|
||||
entity:SetComponent(_M.CreateStateComponent())
|
||||
return entity
|
||||
end
|
||||
|
||||
|
@ -512,6 +682,20 @@ function _M.CreateMonster(pos)
|
|||
entity:SetComponent(_M.CreateHpShowComponent(hazel.CreateSize(constants.MonsetHpBarInfo.width, constants.MonsetHpBarInfo.height)))
|
||||
entity:SetComponent(_M.CreateDirectionComponent(5))
|
||||
entity:SetComponent(_M.CreateColliBoxComponent(constants.RoleColliBox))
|
||||
entity:SetComponent(_M.CreateStateComponent())
|
||||
return entity
|
||||
end
|
||||
|
||||
|
||||
---@return Entity
|
||||
---@param type number
|
||||
---@param pos Point
|
||||
function _M.CreateSupply(type, pos)
|
||||
local entity = _M.CreateEntity("supply")
|
||||
entity:SetComponent(_M.CreateTransformComponent(pos, hazel.CreateSize(constants.TileSize, constants.TileSize)))
|
||||
entity:SetComponent(_M.CreateImageComponent(content.Tilesheet, 1, 11))
|
||||
entity:SetComponent(_M.CreateColliBoxComponent(constants.SupplyColliBox))
|
||||
entity:SetComponent(_M.CreateSupplyComponent(type))
|
||||
return entity
|
||||
end
|
||||
|
||||
|
|
|
@ -462,4 +462,21 @@ end
|
|||
|
||||
_M.Time = Time
|
||||
|
||||
|
||||
local Sound = {}
|
||||
|
||||
---@param filename string
|
||||
---@param name string
|
||||
function Sound.Load(filename, name)
|
||||
libhazel.LoadSound(filename, name);
|
||||
end
|
||||
|
||||
---@param name string
|
||||
function Sound.Play(name)
|
||||
libhazel.PlaySound( name);
|
||||
end
|
||||
|
||||
_M.Sound = Sound
|
||||
|
||||
|
||||
return _M
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
---@class helpfunc
|
||||
|
||||
---@type helpfunc
|
||||
_M = {}
|
||||
|
||||
local constants = require "constants"
|
||||
---@type Content
|
||||
local content = require "content"
|
||||
---@type hazel
|
||||
local hazel = require "hazel"
|
||||
|
||||
_M.GenerateSupply = function()
|
||||
local type = math.random(1, 3)
|
||||
local canvaSize = hazel.GetCanvaSize()
|
||||
---@type Entity
|
||||
---@type ECS
|
||||
local ECS = require "ecs"
|
||||
local supply = ECS.CreateSupply(type,
|
||||
hazel.CreatePos(math.random(0, canvaSize.x - constants.TileSize),
|
||||
math.random(0, canvaSize.y - constants.TileSize)))
|
||||
table.insert(content.SupplyList, supply)
|
||||
end
|
||||
|
||||
_M.IncKillNum = function()
|
||||
content.KillNum = content.KillNum + 1
|
||||
if content.KillNum % constants.SupplyFalldownKillNum == 0 then
|
||||
_M.GenerateSupply()
|
||||
end
|
||||
end
|
||||
|
||||
return _M
|
147
game/main.lua
147
game/main.lua
|
@ -5,6 +5,7 @@ local content = require "content"
|
|||
local vmath = require "vmath"
|
||||
local timer = require "timer"
|
||||
local animation = require "animation"
|
||||
local helpfunc = require "helpfunc"
|
||||
|
||||
local function drawCurosr()
|
||||
hazel.Renderer.SetDrawColor(1, 0, 0, 1)
|
||||
|
@ -70,6 +71,13 @@ local function updateMonster()
|
|||
end
|
||||
end
|
||||
|
||||
local function updateSupply()
|
||||
---@param v Entity
|
||||
for _, v in pairs(content.SupplyList) do
|
||||
v:Update()
|
||||
end
|
||||
end
|
||||
|
||||
local function collisionDeal()
|
||||
---@type Rect
|
||||
local playerBox = content.PlayerEntity:GetComponent(ECS.ComponentType.ColliBox).rect
|
||||
|
@ -96,13 +104,18 @@ local function collisionDeal()
|
|||
if vmath.IsRectIntersect(playerColliBox, monsterColliBox) then
|
||||
---@type InvincibleComponent
|
||||
local playerInvincible = content.PlayerEntity:GetComponent(ECS.ComponentType.Invincible)
|
||||
if not playerInvincible:IsInvincibleState() then
|
||||
if playerInvincible and not playerInvincible:IsInvincibleState() then
|
||||
---@type RolePropComponent
|
||||
local playerRoleProp = content.PlayerEntity:GetComponent(ECS.ComponentType.RoleProp)
|
||||
local oldHp = playerRoleProp.hp
|
||||
playerRoleProp.hp = playerRoleProp.hp - monsterRoleProp.damage
|
||||
hazel.Sound.Play(constants.SoundName.PlayerHurt)
|
||||
if playerRoleProp:IsDie() then
|
||||
content.PlayerEntity:RemoveComponent(ECS.ComponentType.Invincible)
|
||||
if oldHp > 0 then
|
||||
hazel.Sound.Play(constants.SoundName.GameOver)
|
||||
end
|
||||
content.PlayerEntity:RemoveComponent(ECS.ComponentType.Controller)
|
||||
content.PlayerEntity:RemoveComponent(ECS.ComponentType.Gun)
|
||||
content.PlayerEntity:RemoveComponent(ECS.ComponentType.Direction)
|
||||
content.PlayerEntity:RemoveComponent(ECS.ComponentType.HpShow)
|
||||
---@type ImageComponent
|
||||
|
@ -127,17 +140,53 @@ local function collisionDeal()
|
|||
if vmath.IsRectIntersect(bulletColliBox, monsterColliBox) then
|
||||
content.BulletList[kb] = nil
|
||||
local damage = bullet:GetComponent(ECS.ComponentType.Bullet).damage
|
||||
monsterRoleProp.hp = monsterRoleProp.hp - damage
|
||||
if monsterRoleProp:IsDie() then
|
||||
monster:RemoveComponent(ECS.ComponentType.Direction)
|
||||
monster:RemoveComponent(ECS.ComponentType.AI)
|
||||
monster:RemoveComponent(ECS.ComponentType.HpShow)
|
||||
monster:RemoveComponent(ECS.ComponentType.ColliBox)
|
||||
---@type ImageComponent
|
||||
local image = monster:GetComponent(ECS.ComponentType.Image)
|
||||
image.row = 4
|
||||
image.col = 2
|
||||
local oldHp = monsterRoleProp.hp
|
||||
local bulletType = bullet:GetComponent(ECS.ComponentType.Bullet):GetType()
|
||||
if bulletType == constants.BulletType.Ice then
|
||||
monster:GetComponent(ECS.ComponentType.State):IntoIce()
|
||||
elseif bulletType == constants.BulletType.Fire then
|
||||
monster:GetComponent(ECS.ComponentType.State):IntoFire()
|
||||
end
|
||||
monsterRoleProp.hp = monsterRoleProp.hp - damage
|
||||
|
||||
hazel.Sound.Play(constants.SoundName.MonsterHurt)
|
||||
if monsterRoleProp:IsDie() then
|
||||
if oldHp > 0 then
|
||||
content.Score = content.Score + 1
|
||||
helpfunc.IncKillNum()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param v Entity
|
||||
for i, v in pairs(content.SupplyList) do
|
||||
---@type Point
|
||||
local supplyPos = v:GetComponent(ECS.ComponentType.Transform).position
|
||||
---@type Rect
|
||||
local supplyBox = v:GetComponent(ECS.ComponentType.ColliBox).rect
|
||||
---@type Rect
|
||||
local supplyColliBox = hazel.CreateRect(supplyPos.x + supplyBox.x, supplyPos.y + supplyBox.y, supplyBox.w, supplyBox.h)
|
||||
if vmath.IsRectIntersect(supplyColliBox, playerColliBox) then
|
||||
content.SupplyList[i] = nil
|
||||
---@type GunComponent
|
||||
local gun = content.PlayerEntity:GetComponent(ECS.ComponentType.Gun)
|
||||
local type = v:GetComponent(ECS.ComponentType.Supply).type
|
||||
print(type)
|
||||
if type == constants.SupplyType.HpRecover then
|
||||
---@type RolePropComponent
|
||||
local roleProp = content.PlayerEntity:GetComponent(ECS.ComponentType.RoleProp)
|
||||
roleProp.hp = roleProp.hp + constants.SupplyItem[type].recover
|
||||
if roleProp.hp > constants.PlayerInfo.hp then
|
||||
roleProp.hp = constants.PlayerInfo.hp
|
||||
end
|
||||
elseif type == constants.SupplyType.IceGun then
|
||||
gun:SetType(constants.BulletType.Ice)
|
||||
gun.bulletNum = gun.bulletNum + constants.SupplyItem[type].num
|
||||
elseif type == constants.SupplyType.FireGun then
|
||||
gun:SetType(constants.BulletType.Fire)
|
||||
gun.bulletNum = gun.bulletNum + constants.SupplyItem[type].num
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -167,8 +216,11 @@ local function showStartHint()
|
|||
end
|
||||
|
||||
local function initGame()
|
||||
content.KillNum = 0
|
||||
content.Score = 0
|
||||
content.BulletList = {}
|
||||
content.MonsterList = {}
|
||||
content.SupplyList = {}
|
||||
content.PlayerEntity = ECS.CreatePlayer(hazel.CreatePos(constants.TileSize * 16, constants.TileSize * 13))
|
||||
content.MonsterBirthNum = constants.MonsterBirthInitNum
|
||||
content.GameState = content.GameStateEnum.WaitStart
|
||||
|
@ -227,13 +279,56 @@ local function createAnimation(row, time)
|
|||
end)
|
||||
end
|
||||
|
||||
---@param num number
|
||||
---@param x number
|
||||
---@param y number
|
||||
local function drawNum(num, x, y)
|
||||
if num < 0 then
|
||||
content.NumberTilesheet:Draw(10, 0, hazel.CreateRect(x, y, 32, 32))
|
||||
return
|
||||
end
|
||||
local scoreStr = tostring(num)
|
||||
for i = 1, #scoreStr do
|
||||
local col = tonumber(string.sub(scoreStr, i, i))
|
||||
if col == -1 then
|
||||
col = 10
|
||||
end
|
||||
content.NumberTilesheet:Draw(col, 0, hazel.CreateRect(x + (i - 1) * 32, y, 32, 32))
|
||||
end
|
||||
end
|
||||
|
||||
local function updateRoles()
|
||||
---@param monster Entity
|
||||
for _, monster in pairs(content.MonsterList) do
|
||||
---@type RolePropComponent
|
||||
local roleProp = monster:GetComponent(ECS.ComponentType.RoleProp)
|
||||
if roleProp and roleProp:IsDie() then
|
||||
monster:RemoveComponent(ECS.ComponentType.Direction)
|
||||
monster:RemoveComponent(ECS.ComponentType.AI)
|
||||
monster:RemoveComponent(ECS.ComponentType.HpShow)
|
||||
monster:RemoveComponent(ECS.ComponentType.ColliBox)
|
||||
monster:RemoveComponent(ECS.ComponentType.State)
|
||||
---@type ImageComponent
|
||||
local image = monster:GetComponent(ECS.ComponentType.Image)
|
||||
image.row = 4
|
||||
image.col = 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function GameStart()
|
||||
hazel.SetWindowIcon("resources/icon.png")
|
||||
content.Texture = hazel.LoadTexture("resources/tilesheet.png")
|
||||
content.RestartHintTexture = hazel.LoadTexture("resources/RestartHint.png")
|
||||
content.LicensTexture = hazel.LoadTexture("resources/License.png")
|
||||
content.StartHintTexture = hazel.LoadTexture("resources/StartHint.png")
|
||||
content.Tilesheet = hazel.CreateTileSheet(content.Texture, 3, 10)
|
||||
content.Tilesheet = hazel.CreateTileSheet(content.Texture, 3, 12)
|
||||
content.NumberTexture = hazel.LoadTexture("resources/numbers.png")
|
||||
content.NumberTilesheet = hazel.CreateTileSheet(content.NumberTexture, 11, 1)
|
||||
hazel.Sound.Load("resources/gameover.wav", constants.SoundName.GameOver)
|
||||
hazel.Sound.Load("resources/player_hurt.wav", constants.SoundName.PlayerHurt)
|
||||
hazel.Sound.Load("resources/monster_hurt.wav", constants.SoundName.MonsterHurt)
|
||||
hazel.Sound.Load("resources/shoot.wav", constants.SoundName.Shoot)
|
||||
|
||||
initGame()
|
||||
|
||||
|
@ -276,6 +371,17 @@ function GameLoop()
|
|||
hazel.Renderer.DrawTexture(content.LicensTexture, nil, dstrect)
|
||||
end
|
||||
|
||||
if content.GameState == content.GameStateEnum.WaitStart or content.GameState == content.GameStateEnum.Gaming then
|
||||
drawFloors()
|
||||
updateSupply()
|
||||
updateMonster()
|
||||
content.PlayerEntity:Update()
|
||||
updateBullet()
|
||||
collisionDeal()
|
||||
drawCurosr()
|
||||
updateRoles()
|
||||
end
|
||||
|
||||
---@type RolePropComponent
|
||||
local playerRoleInfo = content.PlayerEntity:GetComponent(ECS.ComponentType.RoleProp)
|
||||
if not playerRoleInfo or playerRoleInfo.hp <= 0 then
|
||||
|
@ -285,13 +391,14 @@ function GameLoop()
|
|||
end
|
||||
end
|
||||
|
||||
if content.GameState == content.GameStateEnum.WaitStart or content.GameState == content.GameStateEnum.Gaming then
|
||||
drawFloors()
|
||||
updateMonster()
|
||||
content.PlayerEntity:Update()
|
||||
updateBullet()
|
||||
collisionDeal()
|
||||
drawCurosr()
|
||||
if content.GameState == content.GameStateEnum.Gaming then
|
||||
---@type GunComponent
|
||||
local gun = content.PlayerEntity:GetComponent(ECS.ComponentType.Gun)
|
||||
local x = hazel.GetCanvaSize().x - 128
|
||||
drawNum(content.Score, x, 32)
|
||||
if gun then
|
||||
drawNum(gun:GetBulletNum(), x, 80)
|
||||
end
|
||||
end
|
||||
|
||||
if content.GameState == content.GameStateEnum.WaitStart then
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 279 B |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 7.6 KiB |
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "glhelper.h"
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef __HAZEL_SOUND_H__
|
||||
#define __HAZEL_SOUND_H__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dllexport.h"
|
||||
#include "windows.h"
|
||||
#include "mmsystem.h"
|
||||
|
||||
DLLEXPORT void Hazel_LoadSound(const char* filename, const char* name);
|
||||
DLLEXPORT void Hazel_PlaySound(const char* name);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,17 @@
|
|||
#include "hazel/sound.h"
|
||||
|
||||
void Hazel_LoadSound(const char* filename, const char* name) {
|
||||
char buf[1024] = {0};
|
||||
snprintf(buf, sizeof(buf), "OPEN %s ALIAS %s", filename, name);
|
||||
if (mciSendString(TEXT(buf), NULL, 0, NULL)) {
|
||||
ENGINE_LOG_ERROR("load sound %s (alias %s) failed", filename, name);
|
||||
}
|
||||
}
|
||||
|
||||
void Hazel_PlaySound(const char* name) {
|
||||
char buf[1024] = {0};
|
||||
snprintf(buf, sizeof(buf), "PLAY %s FROM 0", name);
|
||||
if (mciSendString(TEXT(buf), NULL, 0, NULL)) {
|
||||
ENGINE_LOG_ERROR("play sound %s failed", name);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
#include "hazel/hazel.h"
|
||||
#include "hazel/renderer.h"
|
||||
#include "hazel/sound.h"
|
||||
|
||||
Hazel_Texture* texture = NULL;
|
||||
|
||||
void GameStart() {
|
||||
Hazel_LoadSound("test/resources/2.wav", "MUSIC1");
|
||||
Hazel_PlaySound("MUSIC1");
|
||||
texture = Hazel_LoadTexture("test/resources/player.png");
|
||||
Hazel_TextureSetColor(texture, 0, 1, 0);
|
||||
Hazel_TextureSetAlpha(texture, 0.3);
|
||||
|
|
Binary file not shown.
Binary file not shown.
Reference in New Issue