Hello, considering the following:
Trying to remake Vampire Survivors and a fun project
I have a character class
Characters have effects that are applied to a target. In this example my target = player
I have a character that is an instance of that class. Let's call him "Antonio"
I have a "run", Antonio is copied into run.player
I set player to be run.player
My problem is that I have to initiate the character class and Antonio before I create "player". But player is not yet created so player referenced on the character class is nil.
I hope this makes sense, I have a workaround but it feels clunky and I'm wondering if there are other solutions.
Here is my code before the workaround:
character = {} character.__index = character function character:new(name) local o = setmetatable({}, character) o.name = name o.x = 0 o.y = 0 o.sp_scale = 1 o.w = 16 o.h = 16 o.effects = effects o.original_invincibility_frames = 10 o.invincibility_frames = 0 o.max_health = 100 o.health = 20 o.recovery = 0 o.armor = 0 o.move_speed = 1 o.might = 1 o.weapon_projectile_speed = 0 o.weapon_duration = 0 o.weapon_area = 0 o.weapon_cooldown = 0 o.weapon_projectiles_amount = 0 o.revival = 0 o.magnet = 0 o.luck = 0 o.growth = 0 o.greed = 0 o.curse = 0 o.reroll = 0 o.skip = 0 o.banish = 0 return o end function character:set_effects(effects) self.effects = effects end function character:apply_effects(level) local effects = self.effects for _, effect in pairs(effects) do if level % effect.level_increment == 0 and level <= effect.max_level_increment then local target = effect.target if effect.mode == "percent" then target[effect.stat] += (target[effect.stat] or 0) * effect.value else target[effect.stat] = (target[effect.stat] or 0) + effect.value end end end end antonio = character:new("antonio") antonio.recovery = 0.5 antonio:set_effects( { { description="Gains 10% Might every 2 Levels", stat = "might", value = 1, target = player, -- here is the problem, player doesn't exist level_increment = 2, max_level_increment = 10, mode = "percent" }, { description="Gains 0.5 Recovery every 1 level", stat = "recovery", value = 0.5, target = player, level_increment = 1, max_level_increment = 5 } } ) function _init() t = 0 run = {} run.player = {} run.level = 1 add(run.player, deepcopy(antonio)) player = run.player[1] end function _update() if t % 60 == 0 then player.health += player.recovery end if btnp(4) then run.level += 1 player:apply_effects(run.level) end t += 1 end function _draw() local y = 0 cls(0) for entry in all(run.player) do for k, v in pairs(entry) do if type(v) == "number" then print(k..":"..v, 0, y) y += 8 end end end local y = 0 print("Level: "..run.level, 240, y) end function deepcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[deepcopy(orig_key)] = deepcopy(orig_value) end setmetatable(copy, getmetatable(orig)) else -- for numbers, strings, booleans, etc copy = orig end return copy end |
And here is my code with the workaround, in short, once player is created I go and apply player as the target of the effects: player:update_effects_target(player)
character = {} character.__index = character function character:new(name) local o = setmetatable({}, character) o.name = name o.x = 0 o.y = 0 o.sp_scale = 1 o.w = 16 o.h = 16 o.effects = effects o.original_invincibility_frames = 10 o.invincibility_frames = 0 o.max_health = 100 o.health = 20 o.recovery = 0 o.armor = 0 o.move_speed = 1 o.might = 1 o.weapon_projectile_speed = 0 o.weapon_duration = 0 o.weapon_area = 0 o.weapon_cooldown = 0 o.weapon_projectiles_amount = 0 o.revival = 0 o.magnet = 0 o.luck = 0 o.growth = 0 o.greed = 0 o.curse = 0 o.reroll = 0 o.skip = 0 o.banish = 0 return o end function character:set_effects(effects) self.effects = effects end function character:update_effects_target(target) for _, effect in pairs(self.effects) do effect.target = target end end function character:apply_effects(level) local effects = self.effects for _, effect in pairs(effects) do if level % effect.level_increment == 0 and level <= effect.max_level_increment then local target = effect.target if effect.mode == "percent" then target[effect.stat] += (target[effect.stat] or 0) * effect.value else target[effect.stat] = (target[effect.stat] or 0) + effect.value end end end end antonio = character:new("antonio") antonio.recovery = 0.5 antonio:set_effects( { { description="Gains 10% Might every 2 Levels", stat = "might", value = 1, target = player, -- here is the problem, player doesn't exist level_increment = 2, max_level_increment = 10, mode = "percent" }, { description="Gains 0.5 Recovery every 1 level", stat = "recovery", value = 0.5, target = player, level_increment = 1, max_level_increment = 5 } } ) function _init() t = 0 run = {} run.player = {} run.level = 1 add(run.player, deepcopy(antonio)) player = run.player[1] player:update_effects_target(player) end function _update() if t % 60 == 0 then player.health += player.recovery end if btnp(4) then run.level += 1 player:apply_effects(run.level) end t += 1 end function _draw() local y = 0 cls(0) for entry in all(run.player) do for k, v in pairs(entry) do if type(v) == "number" then print(k..":"..v, 0, y) y += 8 end end end local y = 0 print("Level: "..run.level, 240, y) end function deepcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[deepcopy(orig_key)] = deepcopy(orig_value) end setmetatable(copy, getmetatable(orig)) else -- for numbers, strings, booleans, etc copy = orig end return copy end |
Hello,
For fun, I'm building a Vampire Survivors style game. There will be a lot of mobs on screen, so I've built a grid partitioning system and each weapon only checks for collisions with mobs nearby.
The grid size is 30, so that's a 16 x 9 grid.
My question is this, currently, I'm initialising the grid on every frame and re-populating all the mob positions into their grids.
Should I move to initialising just once and updating mob positions in the grid on every frame? I'm not sure whether that will actually be quicker because I will have to delete the mob from one grid position and add it to another.
Also, that seems hard to implement :-)
Thanks in advance
Russ
Knuckle Dice v1.3
Knuckle Dice is an attempt to recreate Knuckle Bones from Cult of the Lamb. This is my first programming project ever so there's no AI yet - it's two player only to begin with.
In the future I will try to add:
- CPU AI (DONE)
- I want to experiment with perfect information. In other words, remove the randomness and tell the player exactly what the opponent is about to play.
Controls
- z to start/restart
- x to play a dice
Rules/Game Logic
- Maximum 3 dice in one column
- Playing a die in a column that matches dice in the opposing player's column removes all instances of that dice
- When nine dice are played by either player the game ends
Scoring
- You receive points equivalent to the die played multiplied by the number of instances of that dice. (e.g a 5 played twice in one column will give you twenty points - 2*(5+5)
- The player with the most points wins
v1.1 Updates
- Changed GFX to more of a 1bit style
v1.3 Updates
- Now it's a single player game with some rudimentary AI for P2