From 2753f02a6e2f081da76b893ce84abd71f9c0149d Mon Sep 17 00:00:00 2001
From: VisualGMQ <2142587070@qq.com>
Date: Thu, 4 Aug 2022 00:14:17 +0800
Subject: [PATCH] add bullet type, supply
---
.gitignore | 5 +-
CMakeLists.txt | 2 +-
binding/lua/bridge.c | 20 ++-
binding/lua/hazel_bind.lua | 15 ++
game/TODO.md | 14 +-
game/animation.lua | 4 +-
game/constants.lua | 68 +++++++--
game/content.lua | 14 ++
game/ecs.lua | 236 ++++++++++++++++++++++++++++----
game/hazel.lua | 17 +++
game/helpfunc.lua | 31 +++++
game/main.lua | 149 +++++++++++++++++---
game/resources/gameover.wav | Bin 0 -> 65026 bytes
game/resources/monster_hurt.wav | Bin 0 -> 17764 bytes
game/resources/numbers.png | Bin 0 -> 279 bytes
game/resources/player_hurt.wav | Bin 0 -> 10188 bytes
game/resources/shoot.wav | Bin 0 -> 10736 bytes
game/resources/tilesheet.png | Bin 5571 -> 7767 bytes
hazel/pch.h | 1 +
hazel/sound.h | 13 ++
src/sound.c | 17 +++
test/main.c | 3 +
test/resources/1.wav | Bin 0 -> 269918 bytes
test/resources/2.wav | Bin 0 -> 36614 bytes
24 files changed, 540 insertions(+), 69 deletions(-)
create mode 100644 game/helpfunc.lua
create mode 100644 game/resources/gameover.wav
create mode 100644 game/resources/monster_hurt.wav
create mode 100644 game/resources/numbers.png
create mode 100644 game/resources/player_hurt.wav
create mode 100644 game/resources/shoot.wav
create mode 100644 hazel/sound.h
create mode 100644 src/sound.c
create mode 100644 test/resources/1.wav
create mode 100644 test/resources/2.wav
diff --git a/.gitignore b/.gitignore
index f2bfc24..079b991 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,8 +5,7 @@ install
TODO.txt
.cache
compile_flags.txt
-game/shader
+*.zip
game/*.dll
-game/*.dll.a
game/*.exe
-*.zip
\ No newline at end of file
+game/shader
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ba97bfd..c1b8e18 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
diff --git a/binding/lua/bridge.c b/binding/lua/bridge.c
index 39700cb..9c1006c 100644
--- a/binding/lua/bridge.c
+++ b/binding/lua/bridge.c
@@ -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},
};
diff --git a/binding/lua/hazel_bind.lua b/binding/lua/hazel_bind.lua
index bb97e6e..ac26b1f 100644
--- a/binding/lua/hazel_bind.lua
+++ b/binding/lua/hazel_bind.lua
@@ -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
diff --git a/game/TODO.md b/game/TODO.md
index da2c85b..a3422ac 100644
--- a/game/TODO.md
+++ b/game/TODO.md
@@ -1,14 +1,14 @@
[important]
[x] 加上1MGames标志
-[ ] 角色走路动画
-[ ] 角色受伤特效
+[x] 增加音效
[x] 角色无敌时闪烁
-[ ] 新增多个枪类型
-[ ] 右上角显示分数
-[ ] 玩家积分榜
+[x] 新增多个枪类型
+[x] 右上角显示分数
+
+[FIXME]
+[ ] Component的Update顺序是随机的
[optional]
[ ] 怪物从土里爬出来(新增怪物类型)
-[ ] 掉落宝物(掉落子弹,加分道具)
-[ ] 多把武器切换
\ No newline at end of file
+[ ] 多把武器切换
diff --git a/game/animation.lua b/game/animation.lua
index 51864aa..d157608 100644
--- a/game/animation.lua
+++ b/game/animation.lua
@@ -8,7 +8,7 @@ local _M = {}
---@field col number
---@field time number
----@param tilesheet Texture
+---@param tilesheet TileSheet
---@param frames table
---@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
diff --git a/game/constants.lua b/game/constants.lua
index 050257c..11b466e 100644
--- a/game/constants.lua
+++ b/game/constants.lua
@@ -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.BulletInfo = {
- damage = 10,
- velocity = 500,
-}
-_M.GunInfo = {
- cooldown = 0.1
+
+_M.BulletType = {
+ Normal = 1,
+ Ice = 2,
+ Fire = 3,
}
+
_M.BulletInfo = {
- damage = 10,
- velocity = 500,
+ [_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.BulletEffectTime = {
+ IceTime = 2,
+ FireTime = 2,
+}
+_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
diff --git a/game/content.lua b/game/content.lua
index c8cd263..9ca6b76 100644
--- a/game/content.lua
+++ b/game/content.lua
@@ -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
+_M.SupplyList = {}
+
return _M
\ No newline at end of file
diff --git a/game/ecs.lua b/game/ecs.lua
index df5e811..3ee6adb 100644
--- a/game/ecs.lua
+++ b/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.CreateImageComponent(content.Tilesheet, 1, 4))
+ 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
diff --git a/game/hazel.lua b/game/hazel.lua
index bb97e6e..a199fc2 100644
--- a/game/hazel.lua
+++ b/game/hazel.lua
@@ -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
diff --git a/game/helpfunc.lua b/game/helpfunc.lua
new file mode 100644
index 0000000..7d0a2d5
--- /dev/null
+++ b/game/helpfunc.lua
@@ -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
\ No newline at end of file
diff --git a/game/main.lua b/game/main.lua
index 353a578..5af8d48 100644
--- a/game/main.lua
+++ b/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
@@ -320,4 +427,4 @@ function GameQuit()
hazel.DestroyTexture(content.RestartHintTexture)
hazel.DestroyTexture(content.StartHintTexture)
hazel.DestroyTexture(content.LicensTexture)
-end
+end
\ No newline at end of file
diff --git a/game/resources/gameover.wav b/game/resources/gameover.wav
new file mode 100644
index 0000000000000000000000000000000000000000..231ae0b4c6de267f29d1c740120789b9165e6805
GIT binary patch
literal 65026
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
aBhYdLT8===5okFAEk~f`2>kyaf&T^@3>U=!
literal 0
HcmV?d00001
diff --git a/game/resources/monster_hurt.wav b/game/resources/monster_hurt.wav
new file mode 100644
index 0000000000000000000000000000000000000000..a8078ed33457cd19b9061823f3eea98b2a130573
GIT binary patch
literal 17764
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
literal 0
HcmV?d00001
diff --git a/game/resources/player_hurt.wav b/game/resources/player_hurt.wav
new file mode 100644
index 0000000000000000000000000000000000000000..bc3f3bfe1b172d12aba686c3aa2059f4ddcfe1fd
GIT binary patch
literal 10188
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
literal 0
HcmV?d00001
diff --git a/game/resources/shoot.wav b/game/resources/shoot.wav
new file mode 100644
index 0000000000000000000000000000000000000000..9c8f421e25b5b821c2fa8ec706b86d092512a367
GIT binary patch
literal 10736
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 24W!8
z*VEwn^xQYv5N$|6K*W9FR=duQN5^s4bm~fF~V^GLO==6K^npu!x}H+UrqmNI)&$&
zpKHE|u$Hivd~9}Zb_!?d7KmM9m%2^eHpe~3t?*EI6nhnWjqw@d^Rn;Dz8*b2dY(oX
zrirGBHsC*q`9HfvyF}mM3kaF90JAU!<1hrh;RWFVu7M2cxQz=qf*n|o`Iw4P2tkK$
zhfsFkA|&Eh#NczxK^XeN>ErY%!+o5=b}U2~0-^WTd#B)Me2ysyfYM9p^*c6T6l!|Z
z^f-mLP~=(U8HN#EBf3_1uI@BfviA7L1p+nd`9a2elYIo`lPaCuub
z(s30+E^fz4yoXmY1VLzbwYyAELg)>XaUJJz0{gKOTd@Hv@G(AwFe}eMINrqTcnuTr
zDui$0_hh_*sdxvoFc-pog!_GtDD1`&oWDVZvDVSoaP{F|}iAM<$MS9_tj|5p{pME6`nm?h15Qpt}Oy73i)&cLlmD&|QJ<
R3UpVXy8_)6`2ViJ{{k?=F=YS%
literal 0
HcmV?d00001
diff --git a/game/resources/tilesheet.png b/game/resources/tilesheet.png
index 79975105515a6cd8e079db3c4edeca144e135602..e23f347e70f0b9f85bf6effa641d8775ecf219e9 100644
GIT binary patch
literal 7767
zcmaiZXIN89wD#U1Ktc_ngF=8%M5=&D55+_1kzS-IDE$CZl@^*bDIy?J15%|+M-2gK
zas&|+lp>)hy@?d1eepiu{e6GU>@{mjVHG
z9!5jynO3_pQ5w+SR96eA8@aFw0DLTZI-2Go4x9G&D|aR>=7R5D(W`#KoM7RlH#J6(
zS7%7D9JKZhlSRNh3{?uS5(-fZy4@vY?ZRfZSXFb);>KQ#9P6TW7RN$Nxvl8YN4$`H
zM46%TM}7C_sRc=X8Sk=Mwr!TXMwCOhTPBoT=R!w_$2~IVp&yiv+YbNK*1!2MwOo^b
z+QcDcqqKaav@>m9RI*bWZS%_U%}4rsr|VXy=hcqtGjtpgcJ{=LiGkFXuI}J#-h!)~
z@jfi?d7%GM^9e=4XQEjbUtq&(oleLd4Z;RFrh5i`R;)ms=u*&abbGwC(bfa~UPTrJ
zdytrj3yPo