Hello,
I'm a beginner programmer, trying to figure out good practice. To be honest, I get a lot of joy out of refactoring code even though I know it's more important to create something of value. Seems to give my brain comfort.
I've been creating a card game and realised that one of my challenges is that I have a card object that has some game logic associated with it but I'm also mixing up a bunch of presentation information on that card. It's getting messy.
Which got me thinking about trying to separate concerns. Wondering what the community's view is on an approach like below?
The general idea here is that a card needs to know nothing about its presentation (but is linked to its presentation). It's a bidirectional link, a card_view is related to its card.
Obviously, in a game where there are not a lot of objects, this might be overkill.
function _init() renderer = Renderer:new() animator = Animator:new() deck = {} x_offset, y_offset, i = 0, 0, 0 for i=1, 10 do local card = Card:new(i, "Hearts") local card_view = CardView:new{ card=card, x=15, y=200, target_x=15+x_offset, target_y=106} card.view = card_view renderer:add_drawable(card_view) animator:add_moveable(card_view) add(deck, card) x_offset+=38 end end function _update() if btnp(5) and i<#deck then deck[#deck-i].view.moving = true i+=1 end animator:animate_entities() end function _draw() cls(27) renderer:draw_entities() end Card = {} Card.__index = Card function Card:new(rank, suit) local self = setmetatable({}, CardView) self.name = "Card" self.rank = rank self.suit = suit self.view = nil return self end function Card:update() --lots of game logic to go here end CardView = {} CardView.__index = CardView function CardView:new(options) local self = setmetatable({}, CardView) self.name = "Card View" self.card = options.card self.x = options.x self.y = options.y self.start_x = options.x self.start_y = options.y self.target_x = options.target_x self.target_y = options.target_y self.sp = 1 self.moving = false return self end function CardView:_dist(x1, y1, x2, y2) return sqrt((x2 - x1)^2 + (y2 - y1)^2) end function CardView:update() if self.moving then local dx = self.target_x - self.x local dy = self.target_y - self.y local remaining_distance = sqrt(dx*dx + dy*dy) local total_distance = self:_dist(self.start_x, self.start_y, self.target_x, self.target_y) local traveled_distance = total_distance - remaining_distance if remaining_distance > 1 then local progress = traveled_distance / total_distance -- Move the self self.x += dx * 0.2 self.y += dy * 0.2 -- Check if 85% of the journey is complete if progress >= 0.85 and not self.revealed then self.sp = 2 self.revealed = true end else self.x = self.target_x self.y = self.target_y self.moving = false end end end function CardView:draw() spr(self.sp, self.x, self.y) if self.revealed then print(self.card.suit, self.x+2, self.y+4, 8) print(self.card.rank, self.x+2, self.y+12, 8) end end Renderer = {} Renderer.__index = Renderer function Renderer:new() local self = setmetatable({}, Renderer) self.drawables = {} return self end function Renderer:add_drawable(drawable, zIndex) if type(drawable.draw) ~= "function" then error("No draw function for "..drawable.name) end drawable.zIndex = zIndex or 0 -- Default to 0 if no zIndex is provided local index = #self.drawables + 1 -- Find the correct position to insert based on zIndex for i=1,#self.drawables do if self.drawables[i].zIndex > drawable.zIndex then index = i break end end -- Insert drawable at the found position for i = #self.drawables + 1, index + 1, -1 do self.drawables[i] = self.drawables[i-1] end self.drawables[index] = drawable end function Renderer:draw_entities() for _, drawable in ipairs(self.drawables) do if type(drawable.draw) ~= "function" then error("No draw function for "..drawable.name) end drawable:draw() end end Animator = {} Animator.__index = Animator function Animator:new() local self = setmetatable({}, Animator) self.moveables = {} return self end function Animator:add_moveable(moveable) add(self.moveables, moveable) end function Animator:animate_entities() for _, moveable in ipairs(self.moveables) do moveable:update() end end |
[Please log in to post a comment]