add bullet type, supply

This commit is contained in:
VisualGMQ 2022-08-04 00:14:17 +08:00
parent 05d3e8ace8
commit 2753f02a6e
24 changed files with 540 additions and 69 deletions

7
.gitignore vendored
View File

@ -5,8 +5,7 @@ install
TODO.txt TODO.txt
.cache .cache
compile_flags.txt compile_flags.txt
game/shader
game/*.dll
game/*.dll.a
game/*.exe
*.zip *.zip
game/*.dll
game/*.exe
game/shader

View File

@ -18,7 +18,7 @@ include(cmake/FindSTB.cmake)
# hazel-core # hazel-core
aux_source_directory(src HAZEL_SRC) aux_source_directory(src HAZEL_SRC)
add_library(${HAZEL_CORE_NAME} SHARED ${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_include_directories(${HAZEL_CORE_NAME} PUBLIC .)
target_compile_features(${HAZEL_CORE_NAME} PUBLIC c_std_11) target_compile_features(${HAZEL_CORE_NAME} PUBLIC c_std_11)
target_precompile_headers(${HAZEL_CORE_NAME} PUBLIC hazel/pch.h) target_precompile_headers(${HAZEL_CORE_NAME} PUBLIC hazel/pch.h)

View File

@ -5,6 +5,7 @@
#include "hazel/hazel.h" #include "hazel/hazel.h"
#include "hazel/renderer.h" #include "hazel/renderer.h"
#include "hazel/sound.h"
static int LuaBridge_RenderSetClearColor(lua_State* L) { static int LuaBridge_RenderSetClearColor(lua_State* L) {
float r = luaL_checknumber(L, 1); float r = luaL_checknumber(L, 1);
@ -145,16 +146,29 @@ static int LuaBridge_GetWindowSize(lua_State* L) {
return 2; return 2;
} }
static int LuaBridge_HideCursor() { static int LuaBridge_HideCursor(lua_State* L) {
Hazel_HideCursor(); Hazel_HideCursor();
return 0; return 0;
} }
static int LuaBridge_ShowCursor() { static int LuaBridge_ShowCursor(lua_State* L) {
Hazel_ShowCursor(); Hazel_ShowCursor();
return 0; 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[] = { static const struct luaL_Reg libhazel[] = {
{"RenderSetClearColor", LuaBridge_RenderSetClearColor}, {"RenderSetClearColor", LuaBridge_RenderSetClearColor},
{"RenderSetDrawColor", LuaBridge_RenderSetDrawColor}, {"RenderSetDrawColor", LuaBridge_RenderSetDrawColor},
@ -176,6 +190,8 @@ static const struct luaL_Reg libhazel[] = {
{"HideCursor", LuaBridge_HideCursor}, {"HideCursor", LuaBridge_HideCursor},
{"ShowCursor", LuaBridge_ShowCursor}, {"ShowCursor", LuaBridge_ShowCursor},
{"SayHello", LuaBridge_SayHello}, {"SayHello", LuaBridge_SayHello},
{"LoadSound", LuaBridge_LoadSound},
{"PlaySound", LuaBridge_PlaySound},
{NULL, NULL}, {NULL, NULL},
}; };

View File

@ -462,4 +462,19 @@ end
_M.Time = Time _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 return _M

View File

@ -1,14 +1,14 @@
[important] [important]
[x] 加上1MGames标志 [x] 加上1MGames标志
[ ] 角色走路动画 [x] 增加音效
[ ] 角色受伤特效
[x] 角色无敌时闪烁 [x] 角色无敌时闪烁
[ ] 新增多个枪类型 [x] 新增多个枪类型
[ ] 右上角显示分数 [x] 右上角显示分数
[ ] 玩家积分榜
[FIXME]
[ ] Component的Update顺序是随机的
[optional] [optional]
[ ] 怪物从土里爬出来(新增怪物类型) [ ] 怪物从土里爬出来(新增怪物类型)
[ ] 掉落宝物(掉落子弹,加分道具)
[ ] 多把武器切换 [ ] 多把武器切换

View File

@ -8,7 +8,7 @@ local _M = {}
---@field col number ---@field col number
---@field time number ---@field time number
---@param tilesheet Texture ---@param tilesheet TileSheet
---@param frames table<Frame> ---@param frames table<Frame>
---@param onEndCallback function ---@param onEndCallback function
function _M.CreateAnimation(tilesheet, frames, onEndCallback) function _M.CreateAnimation(tilesheet, frames, onEndCallback)
@ -42,6 +42,8 @@ function _M.GetCurFrame(self)
end end
end end
---@return TileSheet
---@param self Animation
function _M.GetTilesheet(self) function _M.GetTilesheet(self)
return self.tilesheet return self.tilesheet
end end

View File

@ -2,6 +2,13 @@ local _M = {}
_M.ShowLicenseTime = 2.5 _M.ShowLicenseTime = 2.5
_M.SoundName = {
Shoot = "SHOOT",
PlayerHurt = "PLAYER_HURT",
MonsterHurt = "MONSTER_HURT",
GameOver = "GAMEOVER",
}
_M.TileSize = 32 _M.TileSize = 32
_M.PlayerInfo = { _M.PlayerInfo = {
velocity = 250, velocity = 250,
@ -18,6 +25,12 @@ _M.RoleColliBox = {
x = 9, x = 9,
y = 0, y = 0,
} }
_M.SupplyColliBox = {
w = 32,
h = 32,
x = 9,
y = 0,
}
_M.MonsterBirthInterval = 1 _M.MonsterBirthInterval = 1
_M.MonsterBirthInitNum = 1 _M.MonsterBirthInitNum = 1
_M.Invincible = 1 _M.Invincible = 1
@ -39,16 +52,55 @@ _M.MonsetHpBarInfo= {
_M.GunInfo = { _M.GunInfo = {
cooldown = 0.1 cooldown = 0.1
} }
_M.BulletType = {
Normal = 1,
Ice = 2,
Fire = 3,
}
_M.BulletInfo = { _M.BulletInfo = {
[_M.BulletType.Normal] = {
damage = 10, damage = 10,
velocity = 500, 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 = { _M.RoleState = {
damage = 10, Normal = 1,
velocity = 500, 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 return _M

View File

@ -13,9 +13,15 @@ _M.StartHintTexture = nil
---@type Texture ---@type Texture
_M.LicensTexture = nil _M.LicensTexture = nil
---@type Texture
_M.NumberTexture = nil
---@type TileSheet ---@type TileSheet
_M.Tilesheet = nil _M.Tilesheet = nil
---@type TileSheet
_M.NumberTilesheet = nil
---@type Entity ---@type Entity
_M.PlayerEntity = nil _M.PlayerEntity = nil
@ -57,4 +63,12 @@ _M.Animations = {
EnemyWalkLeft = nil, EnemyWalkLeft = nil,
} }
---@type number
_M.KillNum = 0
---@type number
_M.Score = 0
---@type table<Entity>
_M.SupplyList = {}
return _M return _M

View File

@ -4,6 +4,8 @@ local math = require "math"
local vmath = require "vmath" local vmath = require "vmath"
local content = require "content" local content = require "content"
local timer = require "timer" local timer = require "timer"
local animation = require "animation"
local helpfuncs = require "helpfunc"
---@class ECS ---@class ECS
local _M = {} local _M = {}
@ -29,7 +31,7 @@ function Entity.SetComponent(self, component)
end end
---@return Component|nil ---@return Component|nil
---@param type string ---@param type number
function Entity.GetComponent(self, type) function Entity.GetComponent(self, type)
if not type then if not type then
return nil return nil
@ -102,17 +104,20 @@ end
---@class ComponentType ---@class ComponentType
local ComponentType = { local ComponentType = {
Transform = "Transform", Transform = 1,
Image = "Image", Controller = 2,
Controller = "Controller", RoleProp = 3,
RoleProp = "RoleProp", HpShow = 4,
HpShow = "HpShow", Gun = 5,
Gun = "Gun", Bullet = 6,
Bullet = "Bullet", Direction = 7,
Direction = "Direction", AI = 8,
AI = "AI", ColliBox = 9,
ColliBox = "ColliBox", Invincible = 10,
Invincible = "Invincible", Animator = 11,
State = 12,
Supply = 13,
Image = 14,
} }
_M.ComponentType = ComponentType _M.ComponentType = ComponentType
@ -215,6 +220,8 @@ function _M.CreateControllerComponent()
---@type TransformComponent ---@type TransformComponent
local transform = self:GetParent():GetComponent(ComponentType.Transform) local transform = self:GetParent():GetComponent(ComponentType.Transform)
---@type AnimatorComponent
local animator = self:GetParent():GetComponent(ComponentType.Animator)
local elapseTime = hazel.Time.GetElapseTime() local elapseTime = hazel.Time.GetElapseTime()
if hazel.IsKeyPressing(hazel.Key.A) then if hazel.IsKeyPressing(hazel.Key.A) then
transform.position.x = transform.position.x - speed * elapseTime transform.position.x = transform.position.x - speed * elapseTime
@ -379,6 +386,10 @@ function _M.CreateAIComponent()
---@param self AIComponent ---@param self AIComponent
o.Update = function(self) o.Update = function(self)
local state = self:GetParent():GetComponent(ComponentType.State):GetState()
if state == constants.RoleState.Ice then
return
end
---@type DirectionComponent ---@type DirectionComponent
local direction = self:GetParent():GetComponent(ComponentType.Direction) local direction = self:GetParent():GetComponent(ComponentType.Direction)
@ -407,31 +418,50 @@ end
---@field speed Point ---@field speed Point
---@return GunComponent ---@return GunComponent
---@param damage number ---@param type number
---@param velocity number ---@param bulletNum number|nil
function _M.CreateGunComponent(damage, velocity) function _M.CreateGunComponent(type, bulletNum)
local o = { isActive = true, name = ComponentType.Gun, damage = damage, canShoot = true, velocity = velocity, parent = nil } local o = { isActive = true, name = ComponentType.Gun, type = type, canShoot = true, parent = nil }
o.cdTimer = timer.CreateTimer(constants.GunInfo.cooldown, -1, function() o.bulletNum = constants.BulletInfo[type or constants.BulletType.Normal].initNum
o.cdTimer = timer.CreateTimer(constants.BulletInfo[type].cooldown, -1, function()
o.canShoot = true o.canShoot = true
end) 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 self GunComponent
---@param dir Point ---@param dir Point
o.Fire = function(self, dir) o.Fire = function(self, dir)
if not self.canShoot then if not self.canShoot or self.bulletNum == 0 then
return return
end end
hazel.Sound.Play(constants.SoundName.Shoot)
---@type Point ---@type Point
local position = self:GetParent():GetComponent(ComponentType.Transform).position local position = self:GetParent():GetComponent(ComponentType.Transform).position
local playerCenterX = position.x + constants.TileSize / 2 local playerCenterX = position.x + constants.TileSize / 2
local playerCenterY = position.y + constants.TileSize / 2 local playerCenterY = position.y + constants.TileSize / 2
local ndir = vmath.Normalize(dir) 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), local bullet = _M.CreateBullet(hazel.CreatePos(playerCenterX - constants.TileSize / 2, playerCenterY - constants.TileSize / 2),
self.damage, constants.BulletInfo[type].damage,
hazel.CreatePos(ndir.x * self.velocity, ndir.y * self.velocity)) hazel.CreatePos(ndir.x * velocity, ndir.y * velocity),
self.type)
table.insert(content.BulletList, bullet) table.insert(content.BulletList, bullet)
self.canShoot = false 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 end
---@param self GunComponent ---@param self GunComponent
@ -450,9 +480,14 @@ end
---@return BulletComponent ---@return BulletComponent
---@param damage number ---@param damage number
---@param speed Point ---@param speed Point
function _M.CreateBulletComponent(damage, speed) ---@param type number
local o = { isActive = true, name = ComponentType.Bullet, damage = damage, speed = speed, parent = nil } function _M.CreateBulletComponent(damage, speed, type)
local o = { isActive = true, name = ComponentType.Bullet, damage = damage, type = type, speed = speed, parent = nil }
---@param self BulletComponent ---@param self BulletComponent
o.GetType = function(self)
return self.type
end
o.Update = function(self) o.Update = function(self)
local position = self:GetParent():GetComponent(ComponentType.Transform).position local position = self:GetParent():GetComponent(ComponentType.Transform).position
local elapseTime = hazel.Time.GetElapseTime() local elapseTime = hazel.Time.GetElapseTime()
@ -474,16 +509,150 @@ function _M.CreateColliBoxComponent(rect)
end 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 ---@return Entity
---@param pos Point ---@param pos Point
---@param damage number ---@param damage number
---@param speed Point ---@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 ---@type Entity
local entity = _M.CreateEntity("Bullet") local entity = _M.CreateEntity("Bullet")
entity:SetComponent(_M.CreateTransformComponent(pos, hazel.CreateSize(constants.TileSize, constants.TileSize))) 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)) 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)) entity:SetComponent(_M.CreateColliBoxComponent(constants.BulletColliBox))
return entity return entity
end end
@ -496,9 +665,10 @@ 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.CreateGunComponent(constants.BulletType.Fire))
entity:SetComponent(_M.CreateColliBoxComponent(constants.RoleColliBox)) entity:SetComponent(_M.CreateColliBoxComponent(constants.RoleColliBox))
entity:SetComponent(_M.CreateInvincibleComponent(constants.Invincible)) entity:SetComponent(_M.CreateInvincibleComponent(constants.Invincible))
entity:SetComponent(_M.CreateStateComponent())
return entity return entity
end end
@ -512,6 +682,20 @@ function _M.CreateMonster(pos)
entity:SetComponent(_M.CreateHpShowComponent(hazel.CreateSize(constants.MonsetHpBarInfo.width, constants.MonsetHpBarInfo.height))) entity:SetComponent(_M.CreateHpShowComponent(hazel.CreateSize(constants.MonsetHpBarInfo.width, constants.MonsetHpBarInfo.height)))
entity:SetComponent(_M.CreateDirectionComponent(5)) entity:SetComponent(_M.CreateDirectionComponent(5))
entity:SetComponent(_M.CreateColliBoxComponent(constants.RoleColliBox)) 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 return entity
end end

View File

@ -462,4 +462,21 @@ end
_M.Time = Time _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 return _M

31
game/helpfunc.lua Normal file
View File

@ -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

View File

@ -5,6 +5,7 @@ local content = require "content"
local vmath = require "vmath" local vmath = require "vmath"
local timer = require "timer" local timer = require "timer"
local animation = require "animation" local animation = require "animation"
local helpfunc = require "helpfunc"
local function drawCurosr() local function drawCurosr()
hazel.Renderer.SetDrawColor(1, 0, 0, 1) hazel.Renderer.SetDrawColor(1, 0, 0, 1)
@ -70,6 +71,13 @@ local function updateMonster()
end end
end end
local function updateSupply()
---@param v Entity
for _, v in pairs(content.SupplyList) do
v:Update()
end
end
local function collisionDeal() local function collisionDeal()
---@type Rect ---@type Rect
local playerBox = content.PlayerEntity:GetComponent(ECS.ComponentType.ColliBox).rect local playerBox = content.PlayerEntity:GetComponent(ECS.ComponentType.ColliBox).rect
@ -96,13 +104,18 @@ local function collisionDeal()
if vmath.IsRectIntersect(playerColliBox, monsterColliBox) then if vmath.IsRectIntersect(playerColliBox, monsterColliBox) then
---@type InvincibleComponent ---@type InvincibleComponent
local playerInvincible = content.PlayerEntity:GetComponent(ECS.ComponentType.Invincible) local playerInvincible = content.PlayerEntity:GetComponent(ECS.ComponentType.Invincible)
if not playerInvincible:IsInvincibleState() then if playerInvincible and not playerInvincible:IsInvincibleState() then
---@type RolePropComponent ---@type RolePropComponent
local playerRoleProp = content.PlayerEntity:GetComponent(ECS.ComponentType.RoleProp) local playerRoleProp = content.PlayerEntity:GetComponent(ECS.ComponentType.RoleProp)
local oldHp = playerRoleProp.hp
playerRoleProp.hp = playerRoleProp.hp - monsterRoleProp.damage playerRoleProp.hp = playerRoleProp.hp - monsterRoleProp.damage
hazel.Sound.Play(constants.SoundName.PlayerHurt)
if playerRoleProp:IsDie() then 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.Controller)
content.PlayerEntity:RemoveComponent(ECS.ComponentType.Gun)
content.PlayerEntity:RemoveComponent(ECS.ComponentType.Direction) content.PlayerEntity:RemoveComponent(ECS.ComponentType.Direction)
content.PlayerEntity:RemoveComponent(ECS.ComponentType.HpShow) content.PlayerEntity:RemoveComponent(ECS.ComponentType.HpShow)
---@type ImageComponent ---@type ImageComponent
@ -127,17 +140,53 @@ local function collisionDeal()
if vmath.IsRectIntersect(bulletColliBox, monsterColliBox) then if vmath.IsRectIntersect(bulletColliBox, monsterColliBox) then
content.BulletList[kb] = nil content.BulletList[kb] = nil
local damage = bullet:GetComponent(ECS.ComponentType.Bullet).damage local damage = bullet:GetComponent(ECS.ComponentType.Bullet).damage
monsterRoleProp.hp = monsterRoleProp.hp - damage local oldHp = monsterRoleProp.hp
if monsterRoleProp:IsDie() then local bulletType = bullet:GetComponent(ECS.ComponentType.Bullet):GetType()
monster:RemoveComponent(ECS.ComponentType.Direction) if bulletType == constants.BulletType.Ice then
monster:RemoveComponent(ECS.ComponentType.AI) monster:GetComponent(ECS.ComponentType.State):IntoIce()
monster:RemoveComponent(ECS.ComponentType.HpShow) elseif bulletType == constants.BulletType.Fire then
monster:RemoveComponent(ECS.ComponentType.ColliBox) monster:GetComponent(ECS.ComponentType.State):IntoFire()
---@type ImageComponent
local image = monster:GetComponent(ECS.ComponentType.Image)
image.row = 4
image.col = 2
end 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 end
end end
@ -167,8 +216,11 @@ local function showStartHint()
end end
local function initGame() local function initGame()
content.KillNum = 0
content.Score = 0
content.BulletList = {} content.BulletList = {}
content.MonsterList = {} content.MonsterList = {}
content.SupplyList = {}
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.GameState = content.GameStateEnum.WaitStart content.GameState = content.GameStateEnum.WaitStart
@ -227,13 +279,56 @@ local function createAnimation(row, time)
end) end)
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() 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.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, 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() initGame()
@ -276,6 +371,17 @@ function GameLoop()
hazel.Renderer.DrawTexture(content.LicensTexture, nil, dstrect) hazel.Renderer.DrawTexture(content.LicensTexture, nil, dstrect)
end 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 ---@type RolePropComponent
local playerRoleInfo = content.PlayerEntity:GetComponent(ECS.ComponentType.RoleProp) local playerRoleInfo = content.PlayerEntity:GetComponent(ECS.ComponentType.RoleProp)
if not playerRoleInfo or playerRoleInfo.hp <= 0 then if not playerRoleInfo or playerRoleInfo.hp <= 0 then
@ -285,13 +391,14 @@ function GameLoop()
end end
end end
if content.GameState == content.GameStateEnum.WaitStart or content.GameState == content.GameStateEnum.Gaming then if content.GameState == content.GameStateEnum.Gaming then
drawFloors() ---@type GunComponent
updateMonster() local gun = content.PlayerEntity:GetComponent(ECS.ComponentType.Gun)
content.PlayerEntity:Update() local x = hazel.GetCanvaSize().x - 128
updateBullet() drawNum(content.Score, x, 32)
collisionDeal() if gun then
drawCurosr() drawNum(gun:GetBulletNum(), x, 80)
end
end end
if content.GameState == content.GameStateEnum.WaitStart then if content.GameState == content.GameStateEnum.WaitStart then

BIN
game/resources/gameover.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
game/resources/numbers.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

BIN
game/resources/shoot.wav Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -8,6 +8,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <stdio.h>
#include "log.h" #include "log.h"
#include "glhelper.h" #include "glhelper.h"

13
hazel/sound.h Normal file
View File

@ -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

17
src/sound.c Normal file
View File

@ -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);
}
}

View File

@ -1,9 +1,12 @@
#include "hazel/hazel.h" #include "hazel/hazel.h"
#include "hazel/renderer.h" #include "hazel/renderer.h"
#include "hazel/sound.h"
Hazel_Texture* texture = NULL; Hazel_Texture* texture = NULL;
void GameStart() { void GameStart() {
Hazel_LoadSound("test/resources/2.wav", "MUSIC1");
Hazel_PlaySound("MUSIC1");
texture = Hazel_LoadTexture("test/resources/player.png"); texture = Hazel_LoadTexture("test/resources/player.png");
Hazel_TextureSetColor(texture, 0, 1, 0); Hazel_TextureSetColor(texture, 0, 1, 0);
Hazel_TextureSetAlpha(texture, 0.3); Hazel_TextureSetAlpha(texture, 0.3);

BIN
test/resources/1.wav Normal file

Binary file not shown.

BIN
test/resources/2.wav Normal file

Binary file not shown.