From 4528f15357e4c2484e56f17d8589fba34211c7ac Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Sat, 4 Nov 2023 09:40:13 -0600 Subject: [PATCH 01/55] Keep working on `main.py` --- main.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main.py b/main.py index eb43bc8..a93934f 100644 --- a/main.py +++ b/main.py @@ -6,8 +6,16 @@ from src import One, Two, Three, Four, Menu + class Main: """ Main object for the game, though most of the interface is operated by the src-stored objects. """ + + def __init__(self): + pass + + +if __name__ == "__main__": + Main() From 31bdf4983802acff6486e77b3e77aeae18c6437e Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Sun, 5 Nov 2023 20:36:07 -0600 Subject: [PATCH 02/55] Add art (mobs/npcs) --- resource.pyxres | Bin 1516 -> 1793 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resource.pyxres b/resource.pyxres index ca49dd3f117f486acebf7f600cc0f89509a7d62c..e50c877cc5435fa741d87de2f822c4d6860b00b4 100644 GIT binary patch delta 1176 zcmV;J1ZVr~3xN)hcLu0&o&$>ok$oV4n_Zf!IuJ$Q9nHockl~2H{D*L>QVAfo*W)AE zdx>4-JAEFql2nRl1DPiAFG_cWc;g@dyZFpih; z@)n1PgY|xLtoJTtq?rM?h_@*-W_U%`DxLvZz=x5)MSQCReDr+^;NYwReyjs(ngP8F__YqGC9vIH$Fvv-2@}rm$@J=$fvvt1CGH2j{eT{GFS* zd5c5D;gKmb;F`g~IjsjEe~|@>z&u~C{>H&smcY<7 zvG?yHA|kr~=+`9>3UF{XyFh-r-^an@@HPYLSpp0HUkB8i1Pfp4fQom2f!xuQ>_5kK z7f4jK3zTiInPdNdi9^JpY5~pvjQly`S_gO*tgH?Q0YB6M_NuB5NK4?a8o(nWu64k& z1Zt@RJOL(rzi-~-TOCka4p?BV1G;V)E`EC%hOV=-uiURX`uCO7#X3E7e%lQu6)7KwEL!1L#F-M%! zEcc$q@W=lu?Fz6NFs<9*w9bGy2e_WG&U-95ua4QD2mzA|m_oq54)Bipme=3c8Bp34 zkd}ab=x<9PQlZs;fqX`u^8?_Ajvv{5t3N?IV-6 z!LkdK{_pC5y!6)*-?xv<>Dw>#aSpQd_8EUJ@O+{UT!4Q#j!pDGj>tcZzO!SX-j2lb zKR&y*?Ve~WF>s3S!})EAUK4xB6*3~-nS?P4h3C_U-z40BIvk&q_1nMnW&QV%40O3; zIgaUiEK}f?uC|gX-~#UUvQBz%0ey| z#0$&K)z7^BY0%>Oi;vx=S4|SM>Ld0L5QR`835Y@{QHg-pI^epk z1L9CLKMCa}5T!8cSpxA|%Yd@~=XxMN3olc@zg1}6pp0000{5L@T~ delta 874 zcmV-w1C{)N4(tn%cLw4!=(BbNk$oV4nn9YPFc5|Jp5_4xdK@#r{f{uIR6=ZM+s`F= z?{AzUi&@m4P$`2zrc1nyLuSnM8JwKUcGseOm%JIaRA7Ha@O8_UQ3iz@QXlVsJOu)B&KtnYk7r`(4 zfR=WF%y)f2Lp31tp$~Xurc4okf|GNpiLS=mXq6&X%jeWhUA(4J6L4}aFJFJxZtV^+ zcnr@>SpnA!PR^wsfc!r5y~lnNP*y-Y0#+B$hdy3!qdx+VO~ATdulB*o*&cz=b-wrS zB0R#=e?ICX;0kbZUUq@}?S3DF#c)^w?K}b-fA<0H7Qw=YKA_=UASarCiv9aocY#Dx zyFl6Yy4CmpA2E0gO$+G$nEBpg?E|a|Hr5BYfG_%h_}5e)kRE~GdH{>?So?tO5oo0k zumYH{{k}WKLm$vu4cK7q1Ewj2!ET2TrYW9%<-FR+?<1EXCLJcbokEl`;F`C^5+nK8 zXFL7bkIzhc1g61$@-QTS4VJj=3advm5EJ#&znb`u@u|6lDV};x^S^)d6wf~6D#$b6 zd$g}Z@#rs6j)3>$Q*#v1kA1wbMfiM|6X5&LaT}+?ua7|7+{ZBncr@Z%rwR9r@2}$q zj>V5f&}KdkOH2adi=fE`#C88NZsEnqej7|bfE#P9E55FPZQR0ti;=|+`Rz8}9QuG% z^YTAwIlPP;5D?RjsoQPL-VCJTf5jH<4N$52k5m9&$Bh)h^z%p8;O78WtRC02$}Ll$ ze*a%(+yHR}EOi@P>I(34fNPJs?y=RpHdcSa1uQ0DaRK{2z!J4B?{Tjypo|+JJp%Ei ze|!YI6vp0n9OD->eRxc*PI)m}`kp#IKdA_oT_6=f+y6$Z{w0=)uWNokJ~L?>EW1F- zf7b`(N59Vaetc#wlVAnJlfVUJlfVTX0{;P%CkBxQ;xp*8b_A2Y20aE61poj5094_x AMF0Q* From 40ec00ce65a2049d54d55e2d11228d5c54e612bf Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Sun, 5 Nov 2023 20:48:27 -0600 Subject: [PATCH 03/55] More code additions, mostly TODO stuff --- main.py | 11 ++++++++++- src/__init__.py | 16 +++++++++++----- src/menu.py | 13 +++++++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 src/menu.py diff --git a/main.py b/main.py index a93934f..7c60a51 100644 --- a/main.py +++ b/main.py @@ -12,10 +12,19 @@ class Main: Main object for the game, though most of the interface is operated by the src-stored objects. """ + situation = None def __init__(self): - pass + pyxel.load("resource.pyxres") + self.situation = Menu() + + def update(self): + self.situation.update() + + def draw(self): + self.situation.draw() if __name__ == "__main__": + pyxel.init(128, 128, "Diddi and Eli") Main() diff --git a/src/__init__.py b/src/__init__.py index e49ccec..1c3012f 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,9 +1,15 @@ "Extra code/tools for the game." -__all__ = ("One", "Two", "Three", "Four") +from . import menu # , one, two, three, four, five, six + +__all__ = ("One", "Two", "Three", "Four", "Five", "Six", "Menu") # TODO: fixme -- these four objects should be Python classes -One = None -Two = None -Three = None -Four = None +One = None # one.One +Two = None # two.Two +Three = None # three.Three +Four = None # four.Four +Five = None # five.Five +Six = None # six.Six +# NOTE: Below I have the already-linked objects +Menu = menu.Menu diff --git a/src/menu.py b/src/menu.py new file mode 100644 index 0000000..a9194c0 --- /dev/null +++ b/src/menu.py @@ -0,0 +1,13 @@ +import pyxel + +class Menu: + "Menu window." + + def __init__(self): + pass + + def update(self): + "Pyxel-like 'update' function." + + def draw(self): + "Pyxel-like 'draw' function." From f57dc6370565b0ab7a69d044d608479441fe9b62 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Mon, 6 Nov 2023 17:04:00 -0600 Subject: [PATCH 04/55] Initial design of the main menu --- main.py | 1 + resource.pyxres | Bin 1793 -> 2770 bytes src/baseclasses.py | 25 +++++++++++++++++++++++++ src/menu.py | 15 ++++++++++++++- 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/baseclasses.py diff --git a/main.py b/main.py index 7c60a51..5f68539 100644 --- a/main.py +++ b/main.py @@ -17,6 +17,7 @@ class Main: def __init__(self): pyxel.load("resource.pyxres") self.situation = Menu() + pyxel.run(self.update, self.draw) def update(self): self.situation.update() diff --git a/resource.pyxres b/resource.pyxres index e50c877cc5435fa741d87de2f822c4d6860b00b4..02780079856f9bacd9e42857544f9da0b30445c5 100644 GIT binary patch delta 1015 zcmZqVyCk|nldYbaMTCKYfdhyY85%=(>>$E=@b8>7kCvVP&pvu{#-(h}(O6a6mLtE+KhG%Mckf%#fz;mR z?fZooepo!de>k3#p{D2Kw} z_GU)>^0%iOPXFRPP{bY5vW08zZdd#@ Date: Mon, 6 Nov 2023 17:48:56 -0600 Subject: [PATCH 05/55] More additions to the menu --- src/menu.py | 13 ++++++++++++- src/tools.py | 7 +++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/tools.py diff --git a/src/menu.py b/src/menu.py index 7758440..ba1cd60 100644 --- a/src/menu.py +++ b/src/menu.py @@ -1,6 +1,7 @@ import pyxel from .baseclasses import BaseLevel +from .tools import draw_text class Menu(BaseLevel): "Menu window." @@ -15,12 +16,22 @@ def update(self): self.check_quit() if self.stage == "main": if pyxel.btnp(pyxel.KEY_1): - self.stage = "level" + self.stage = "start" elif pyxel.btnp(pyxel.KEY_2): self.stage = "players" def draw(self): "Pyxel-like 'draw' function." + # Clear the screen pyxel.cls(0) # NOTE: Tilemap 0 is the menu tilemap, ok? pyxel.bltm(0, 0, 0, 0, 0, 128, 128) + # Draw a "menu window" + pyxel.rectb(20, 30, 88, 70, 7) + # Main design + if self.stage == "main": + draw_text("== Diddi and Eli ==", 23, 33) + draw_text("[1] Start", 23, 45) + draw_text("[2] Player mode", 23, 53) + # Always remind the users how to quit + draw_text("- Press Q to quit -", 23, 90) diff --git a/src/tools.py b/src/tools.py new file mode 100644 index 0000000..eb4e810 --- /dev/null +++ b/src/tools.py @@ -0,0 +1,7 @@ +"Physics/graphics tools used across the source code." + +import pyxel + +def draw_text(text, x, y): + pyxel.text(x, y, text, 1) + pyxel.text(x+1, y, text, 7) From fdb9a09cb812ea63456576d0471be107d40e4f73 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 8 Nov 2023 09:02:24 -0600 Subject: [PATCH 06/55] Almost finish the menu interface --- src/baseclasses.py | 6 ++++-- src/menu.py | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index 76f51fc..d5cad56 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -6,8 +6,10 @@ class BaseLevel(ABC): "Base level." - tilemap = 0 - players = None + tilemap = 0 # Tilemap used by the level + players = None # Amount of players involved + finished = False # Have we finished today? Can we go home now? + next = "" # Where should we go after finishing def __init__(self): pass diff --git a/src/menu.py b/src/menu.py index ba1cd60..2643c15 100644 --- a/src/menu.py +++ b/src/menu.py @@ -7,6 +7,7 @@ class Menu(BaseLevel): "Menu window." stage = "main" player_choice = 0 + player_choice_text = {0: "[1] Single (Diddi)", 1: "[2] Single (Eli)", 2: "[3] Multiplayer"} def __init__(self): pass @@ -19,6 +20,23 @@ def update(self): self.stage = "start" elif pyxel.btnp(pyxel.KEY_2): self.stage = "players" + elif self.stage == "start": + # Just get into the next window + self.finished = True + self.next = "one" + elif self.stage == "players": + if pyxel.btnp(pyxel.KEY_1): + # Option 1 - singleplayer, Diddi + self.player_choice = 0 + elif pyxel.btnp(pyxel.KEY_2): + # Option 2 - singleplayer, Eli + self.player_choice = 1 + elif pyxel.btnp(pyxel.KEY_3): + # Option 3 - local co-op (Diddi and Eli) + self.player_choice = 2 + elif pyxel.btnp(pyxel.KEY_R): + # Return to menu + self.stage = "main" def draw(self): "Pyxel-like 'draw' function." @@ -33,5 +51,14 @@ def draw(self): draw_text("== Diddi and Eli ==", 23, 33) draw_text("[1] Start", 23, 45) draw_text("[2] Player mode", 23, 53) + # Players selection + if self.stage == "players": + draw_text("== Select mode ==", 23, 33) + for k, v in self.player_choice_text.items(): + if k == self.player_choice: + draw_text(v + " <-", 23, 45+(8*k)) + else: + draw_text(v, 23, 45+(8*k)) + draw_text("- Press R to return -", 23, 82) # Always remind the users how to quit draw_text("- Press Q to quit -", 23, 90) From bc0f0863ab344c81c67234fb2c97f2372989c3a4 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 8 Nov 2023 18:49:45 -0600 Subject: [PATCH 07/55] Connect `Menu` with level one (still a WIP) --- main.py | 7 +++++-- src/__init__.py | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index 5f68539..19c34a9 100644 --- a/main.py +++ b/main.py @@ -4,7 +4,7 @@ import pyxel -from src import One, Two, Three, Four, Menu +from src import stages_list class Main: @@ -16,11 +16,14 @@ class Main: def __init__(self): pyxel.load("resource.pyxres") - self.situation = Menu() + self.situation = stages_list["menu"] pyxel.run(self.update, self.draw) def update(self): self.situation.update() + # If the situation "ends", jump into the next one + if self.situation.finished: + self.situation = stages_list[self.situation.next] def draw(self): self.situation.draw() diff --git a/src/__init__.py b/src/__init__.py index 1c3012f..4c1af95 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -2,9 +2,9 @@ from . import menu # , one, two, three, four, five, six -__all__ = ("One", "Two", "Three", "Four", "Five", "Six", "Menu") +__all__ = ("stages_list") -# TODO: fixme -- these four objects should be Python classes +# TODO: fixme -- these objects should be Python classes One = None # one.One Two = None # two.Two Three = None # three.Three @@ -13,3 +13,14 @@ Six = None # six.Six # NOTE: Below I have the already-linked objects Menu = menu.Menu + +# Below there's a dictionary with all the objects for further use +stages_list = { + "one": One, + "two": Two, + "three": Three, + "four": Four, + "five": Five, + "six": Six, + "menu": Menu, +} From 1b4a610e3ea66c430f79488018b79991ffc075c6 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 8 Nov 2023 19:32:12 -0600 Subject: [PATCH 08/55] Develop the art of level 1 (and begin with section 2) --- resource.pyxres | Bin 2770 -> 4363 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resource.pyxres b/resource.pyxres index 02780079856f9bacd9e42857544f9da0b30445c5..389d938fb476225f1c7e6ed387cf2dc35c04663a 100644 GIT binary patch literal 4363 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 From eb5fec763efc3a051cade02678281f7f28e67c92 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Mon, 13 Nov 2023 16:30:56 -0600 Subject: [PATCH 09/55] Add WIP skeleton of the first level --- main.py | 4 ++++ src/__init__.py | 4 ++-- src/baseclasses.py | 8 ++++++++ src/one.py | 27 +++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/one.py diff --git a/main.py b/main.py index 19c34a9..cbc6815 100644 --- a/main.py +++ b/main.py @@ -22,8 +22,12 @@ def __init__(self): def update(self): self.situation.update() # If the situation "ends", jump into the next one + # Also, keep memory of your player choice :) if self.situation.finished: + tmp = self.situation.player_choice self.situation = stages_list[self.situation.next] + self.situation.player_choice = tmp + del(tmp) # we have to remove 'tmp' ASAP def draw(self): self.situation.draw() diff --git a/src/__init__.py b/src/__init__.py index 4c1af95..ca30a81 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,11 +1,10 @@ "Extra code/tools for the game." -from . import menu # , one, two, three, four, five, six +from . import menu, one # , two, three, four, five, six __all__ = ("stages_list") # TODO: fixme -- these objects should be Python classes -One = None # one.One Two = None # two.Two Three = None # three.Three Four = None # four.Four @@ -13,6 +12,7 @@ Six = None # six.Six # NOTE: Below I have the already-linked objects Menu = menu.Menu +One = one.One # Below there's a dictionary with all the objects for further use stages_list = { diff --git a/src/baseclasses.py b/src/baseclasses.py index d5cad56..9f0bf08 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -7,6 +7,7 @@ class BaseLevel(ABC): "Base level." tilemap = 0 # Tilemap used by the level + player_choice = 0 # 0 is Diddi, 1 is Eli, and 2 is multiplayer players = None # Amount of players involved finished = False # Have we finished today? Can we go home now? next = "" # Where should we go after finishing @@ -17,6 +18,13 @@ def __init__(self): def check_quit(self): if pyxel.btnp(pyxel.KEY_Q): pyxel.quit() + + def check_reset(self): + if pyxel.btnp(pyxel.KEY_R): + self.finished = True + self.next = "menu" + return True + return False @abstractmethod def update(self): diff --git a/src/one.py b/src/one.py new file mode 100644 index 0000000..a89157b --- /dev/null +++ b/src/one.py @@ -0,0 +1,27 @@ +import pyxel + +from .baseclasses import BaseLevel +from .tools import draw_text + + +class One(BaseLevel): + """ + Level One: Onion Plateau + + A mostly plain, onion-filled plateau. It's the + easiest level in the game, so it doesn't contain + a lot of enemies or tricky spots. + """ + + def __init__(self): + pass + + def update(self): + "Pyxel-like 'update' function." + self.check_quit() + if self.check_reset(): + return None + + def draw(): + "pyxel-like 'update' function." + pyxel.cls(0) From 7483c2b2aaa04cc87ac7be98514b92059bf961ad Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Mon, 13 Nov 2023 16:34:06 -0600 Subject: [PATCH 10/55] More style tweaks to the first level's appearance --- resource.pyxres | Bin 4363 -> 4368 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resource.pyxres b/resource.pyxres index 389d938fb476225f1c7e6ed387cf2dc35c04663a..a58efe56c184a09967df95cd13e8a8608f2c7d7c 100644 GIT binary patch delta 1333 zcmeBHnxM3yj*D%%f6X#>*2zEE6zUD%-i;1=lqKPCvD|I)JH7nR^KX0%37@{gLGO=8 z$@v_#L|6XA>urJoTdvNiZ%7FaDcI$PL#&;QN%$Lg@sE*q%$iPzpw27 z>yN)SWjesHobStd{tI?Bljq*#IAHdF|F!=W-{#KFmbDjHzVEx)_wA2mZ*Uw)_rABs zdf%J-3~P3OzBa@9_WWP>e$R}5zrtYdzIk`w?npcHXAi@gO7{OhHf6uxQ$Ni%*<$OR zr|)a$eV1GI`MiW%`-5}VD|g=Q;XiPx`Mub+nx5|;i?Zv1D&2Ip*TgPgT=a62a?H-j zGyk5u!La5p&)+$^{@K@Srq#bP0vfkHcW>R!wXdVhuD3rhyPaBQaGm|Zr^uIgUf(~x zKHh#^dfv{T#*b#5)|*{?dsiw*q511YzbtI!Yrp>4)%HBI`}RGx;-@*>2d*_|<}J7Q z{@M1OPxSVeSBmPt@2D-7TRwg9`nb616*IT}ICVQE?EEK&9?RyqxPN#2HXomx`Pyu5 z)H}KD@4r0$W#+%0{m;|%81LuPZ@!mVW@|fvX~X}w=Jr{9yKgBl-uVA*w!G>4cqSX) z`h9m9W^*#M+*M~dpvS?`Qd`T=aQ8+zLtlO9_m^iFX7_R*uv~oZ-@N+30|n3Pg##EK z9H0F^^ubofAAd}0e>PUV)c?W4&=&n~JHu(_g4xWW3<*09zcRo6u9Sg`fv0>&LD>Gk zyWeF0`zXNJ@Q{x??*9A7kIjJ0X)FoyiUJH0dAmBxpOT^)#-Qt5qKWG0xGH<;q z*UwoAU*7D!mdhbHK}B6~!>gLUD!c#H^N)A_G_SPwf8KsDGV9H@Yv;tiRm40KD7Ffh zHDvJ4uYdph-@9ak_W4x|%hFHX5Z*IYRlAg*{Z7GIv&*~(@{6-s|2?UdW=u%-kAL>- z*YEd#;@@BAsArJgv2}6$`US~9RHZiyHauMx$NZxzM9#`ezjUWkUhFqR`}YT=HwZRl z7su_{9aHvZZo_*2TT;R9zoVzu&U<-XGw{OY*PH(xG=jTCQ4UA{=( zcxxa}?EdG+u5ccBd)(~F&p%}!uh!rGUA|}T^&QX8r-+^Z!?5P=%lzCD@AdbKlUK1P zyy$uLw6-iaM+@ZLC=2OZzF>PS+`jePK3GFr;BXZ`Ou%K zo{Qm6msu&oI)%p9dEH)^q Date: Tue, 14 Nov 2023 13:06:43 -0600 Subject: [PATCH 11/55] Ensure all classes are initialized correctly --- main.py | 5 +++-- src/tools.py | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index cbc6815..0ac4b20 100644 --- a/main.py +++ b/main.py @@ -5,6 +5,7 @@ import pyxel from src import stages_list +from src.tools import init_class class Main: @@ -16,7 +17,7 @@ class Main: def __init__(self): pyxel.load("resource.pyxres") - self.situation = stages_list["menu"] + self.situation = init_class(stages_list["menu"]) pyxel.run(self.update, self.draw) def update(self): @@ -25,7 +26,7 @@ def update(self): # Also, keep memory of your player choice :) if self.situation.finished: tmp = self.situation.player_choice - self.situation = stages_list[self.situation.next] + self.situation = init_class(stages_list[self.situation.next]) self.situation.player_choice = tmp del(tmp) # we have to remove 'tmp' ASAP diff --git a/src/tools.py b/src/tools.py index eb4e810..16a3034 100644 --- a/src/tools.py +++ b/src/tools.py @@ -5,3 +5,6 @@ def draw_text(text, x, y): pyxel.text(x, y, text, 1) pyxel.text(x+1, y, text, 7) + +def init_class(obj): + return obj() From fcf3e546fe51f79f7a9365f064565cecae60167d Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 14 Nov 2023 13:08:31 -0600 Subject: [PATCH 12/55] Fix a mistake in `One.draw` --- src/one.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/one.py b/src/one.py index a89157b..50a587a 100644 --- a/src/one.py +++ b/src/one.py @@ -22,6 +22,6 @@ def update(self): if self.check_reset(): return None - def draw(): + def draw(self): "pyxel-like 'update' function." pyxel.cls(0) From 6200655ae0c559910e43bfdadae6bbc8e32c9ded Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 14 Nov 2023 13:17:01 -0600 Subject: [PATCH 13/55] Prepare character classes (players, mobs, NPCs, etc) --- src/characters.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/characters.py diff --git a/src/characters.py b/src/characters.py new file mode 100644 index 0000000..bd13f9a --- /dev/null +++ b/src/characters.py @@ -0,0 +1,43 @@ +""" +Submodule containing all the characters and their physics, +including the main players (Diddi, Eli), the mobs (onions, +slimehorns, robots, etc), coins, and NPCs. +""" + +import pyxel + +# === Players === + + +class Player1: + "Diddi, Player 1, operated using WASD keys." + + +class Player2: + "Eli, Player 2, operated with arrow keys." + + +# === Mobs === + + +class Onion: + "Mobs who just walk but can fall from cliffs." + +class Robot(Onion): + "Mobs who walk, without falling from cliffs, making then harder to defeat." + +class Slimehorn1: + "Mobs that stick to a surface (Down)." + variant = False + +class Slimehorn2: + "Mobs that stick to a surface (Up)." + variant = False + +class Slimehorn3: + "Mobs that stick to a surface (Left)." + variant = False + +class Slimehorn4: + "Mobs that stick to a surface (Right)." + variant = False From 00f6bc10665db589d804296e0e894bcccda5fd11 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 14 Nov 2023 16:57:06 -0600 Subject: [PATCH 14/55] Prepare variable configs for both Diddi and Eli --- src/characters.py | 65 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/src/characters.py b/src/characters.py index bd13f9a..6ae6ff0 100644 --- a/src/characters.py +++ b/src/characters.py @@ -6,15 +6,74 @@ import pyxel +# === Tool functions (physics, data, etc) +# TODO: fixme! + # === Players === class Player1: - "Diddi, Player 1, operated using WASD keys." + """ + Diddi, Player 1, operated using WASD keys. + """ + + def __init__(self, x=0, y=0): + self.x = x + self.y = y + self.initial_setup() + + def initial_setup(self): + """ + Main variable configurations, which + differentiate from Diddi and Eli. + """ + self.key_up = pyxel.KEY_W + self.key_left = pyxel.KEY_A + self.key_bullet = pyxel.KEY_S + self.key_right = pyxel.KEY_D + self.imagebank = [ + (8, 0), # Right, normal + (16, 0), # Right, walking (1) + (24, 0), # Right, walikng (2) + (32, 0), # Right, jumping + (8, 8), # Left, normal + (16, 8), # Left, walking (1) + (24, 8), # Left, walikng (2) + (32, 8), # Left, jumping + ] + self.icon = (0, 16) + +class Player2(Player1): + """ + Eli, Player 2, operated with arrow keys. + + NOTE: this class is inherited from Diddi + (Player1) as it uses most of its structure. + However, some variables have changed (see + 'Player2.initial_setup'). + """ -class Player2: - "Eli, Player 2, operated with arrow keys." + def initial_setup(self): + """ + Main variable configurations, which + differentiate from Diddi and Eli. + """ + self.key_up = pyxel.KEY_UP + self.key_left = pyxel.KEY_LEFT + self.key_bullet = pyxel.KEY_DOWN + self.key_right = pyxel.KEY_UP + self.imagebank = [ + (8, 16), # Right, normal + (16, 16), # Right, walking (1) + (24, 16), # Right, walikng (2) + (32, 16), # Right, jumping + (8, 24), # Left, normal + (16, 24), # Left, walking (1) + (24, 24), # Left, walikng (2) + (32, 24), # Left, jumping + ] + self.icon = (0, 24) # === Mobs === From e087c0a416075eae572ac1cf6eb057f31ef1b683 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 14 Nov 2023 19:22:03 -0600 Subject: [PATCH 15/55] Add some physics/graphics functions for the player classes --- src/characters.py | 111 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 4 deletions(-) diff --git a/src/characters.py b/src/characters.py index 6ae6ff0..6fcb3e3 100644 --- a/src/characters.py +++ b/src/characters.py @@ -4,10 +4,65 @@ slimehorns, robots, etc), coins, and NPCs. """ +import random + import pyxel # === Tool functions (physics, data, etc) -# TODO: fixme! +# (Some of these were borrowed from another +# project of mine, 'abandon-the-ship') + +# TODO: Verify these functions can be invoked +# from the level classes. Otherwise, we'll +# have to adapt the player's code or come +# up with a different solution. + +SCROLL_BORDER_X = 80 +WALL_TILE_X = 4 +TILES_FLOOR = [ + (40, 0), # Grass - Up + (40, 8), # Grass - Down + (48, 0), # Ice - Up + (48, 8), # Ice - Down + (56, 0), # Purple bricks + (56, 8), # Red bricks + (40, 16), # Sand - Up + (40, 24), # Sand - Down + (48, 16), # White struct 1 + (48, 24), # White struct 2 + (56, 16), # Dirt - Up + (56, 24), # Dirt - Down + (0, 64), # Gate (L, 1) + (0, 72), # Gate (L, 2) + (8, 64), # Gate (R, 1) + (8, 72), # Gate (R, 2) + (56, 64), # Button support (H) + (56, 72), # Button support (v) +] +scroll_x = 0 + +def adjust_x(real_x): + return scroll_x + real_x + + +def get_tile(tile_x, tile_y): + return pyxel.tilemap(1).pget(tile_x, tile_y) + + +def detect_collision(x, y, dy): + x1 = x // 8 + y1 = y // 8 + x2 = (x + 8 - 1) // 8 + y2 = (y + 8 - 1) // 8 + for yi in range(y1, y2 + 1): + for xi in range(x1, x2 + 1): + if get_tile(xi, yi)[0] >= WALL_TILE_X: + return True + if dy > 0 and y % 8 == 1: + for xi in range(x1, x2 + 1): + if get_tile(xi, y1 + 1) in TILES_FLOOR: + return True + return False # === Players === @@ -16,16 +71,25 @@ class Player1: """ Diddi, Player 1, operated using WASD keys. """ + alive = True def __init__(self, x=0, y=0): self.x = x self.y = y + self.dx = 0 + self.dy = 0 + self.prev_x = self.x + self.prev_y = self.y + self.r_facing = True + self.shoot = False + self.is_falling = False + self.active = False self.initial_setup() - + def initial_setup(self): """ Main variable configurations, which - differentiate from Diddi and Eli. + differentiate between Diddi and Eli. """ self.key_up = pyxel.KEY_W self.key_left = pyxel.KEY_A @@ -42,6 +106,45 @@ def initial_setup(self): (32, 8), # Left, jumping ] self.icon = (0, 16) + + def get_image_combo(self): + if self.r_facing: + # Our player is facing to the right + if self.is_falling or self.prev_y > self.y: + # Jumping/falling + return self.imagebank[3] + if self.prev_x == self.x: + # We're static + return self.imagebank[0] + # We're walking + return random.choice(self.imagebank[1:3]) + else: + # Our player is left-facing + if self.is_falling or self.prev_y > self.y: + # Jumping/falling + return self.imagebank[7] + if self.prev_x == self.x: + # We're static + return self.imagebank[4] + # We're walking + return random.choice(self.imagebank[5:7]) + + def update(self): + "Update and react to key controls." + if pyxel.btnp(self.key_bullet): + # TODO: fixme! + pass + if pyxel.btnp(self.key_left): + # TODO: fixme! + self.r_facing = False + elif pyxel.btnp(self.key_right): + # TODO: fixme! + self.r_facing = True + + def draw(self): + "Draw the character." + combo = self.get_image_combo() + pyxel.blt(self.x, self.y, 0, combo[0], combo[1], 8, 8, 0) class Player2(Player1): @@ -57,7 +160,7 @@ class Player2(Player1): def initial_setup(self): """ Main variable configurations, which - differentiate from Diddi and Eli. + differentiate between Diddi and Eli. """ self.key_up = pyxel.KEY_UP self.key_left = pyxel.KEY_LEFT From 063bbd09242db78d9154e102afa601fca9160442 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 15 Nov 2023 15:08:54 -0600 Subject: [PATCH 16/55] More code additions related to characters --- src/characters.py | 53 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/characters.py b/src/characters.py index 6fcb3e3..f540eb8 100644 --- a/src/characters.py +++ b/src/characters.py @@ -13,9 +13,9 @@ # project of mine, 'abandon-the-ship') # TODO: Verify these functions can be invoked -# from the level classes. Otherwise, we'll +# from the level classes. Otherwise, will we # have to adapt the player's code or come -# up with a different solution. +# up with a different solution?? SCROLL_BORDER_X = 80 WALL_TILE_X = 4 @@ -72,6 +72,7 @@ class Player1: Diddi, Player 1, operated using WASD keys. """ alive = True + bullets = [] def __init__(self, x=0, y=0): self.x = x @@ -128,12 +129,30 @@ def get_image_combo(self): return self.imagebank[4] # We're walking return random.choice(self.imagebank[5:7]) + + def get_scroll_x(self): + """ + This is just a 'bridge' between a player class and a + level class, where 'scroll_x' is vital but not directly present. + """ + return scroll_x + + def check_bullets(self): + for i in self.bullets: + if not i.alive: + # TODO: Kill this object + pass def update(self): "Update and react to key controls." + self.check_bullets() if pyxel.btnp(self.key_bullet): - # TODO: fixme! - pass + if self.r_facing: + # Send a bullet to the right + self.bullets.append(Bullet(self.x, self.y)) + else: + # Send a bullet to the left + self.bullets.append(Bullet(self.x, self.y, False)) if pyxel.btnp(self.key_left): # TODO: fixme! self.r_facing = False @@ -182,24 +201,40 @@ def initial_setup(self): # === Mobs === -class Onion: +class BaseMob: + "Simple base for all the mobs." + alive = False + +class Onion(BaseMob): "Mobs who just walk but can fall from cliffs." class Robot(Onion): "Mobs who walk, without falling from cliffs, making then harder to defeat." -class Slimehorn1: +class Slimehorn1(BaseMob): "Mobs that stick to a surface (Down)." variant = False -class Slimehorn2: +class Slimehorn2(BaseMob): "Mobs that stick to a surface (Up)." variant = False -class Slimehorn3: +class Slimehorn3(BaseMob): "Mobs that stick to a surface (Left)." variant = False -class Slimehorn4: +class Slimehorn4(BaseMob): "Mobs that stick to a surface (Right)." variant = False + + +# === Coins/bullets === + + +class Bullet: + "A bullet send by either Diddi or Eli and may damage enemies." + alive = False + +class Coin: + "A coin that gives you points to brag about." + alive = False From abd87db457a8f2f9d09b381e092e14565b7eada2 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 15 Nov 2023 15:33:23 -0600 Subject: [PATCH 17/55] Finish the art of level 2, and start with level 3 --- resource.pyxres | Bin 4368 -> 4822 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resource.pyxres b/resource.pyxres index a58efe56c184a09967df95cd13e8a8608f2c7d7c..4037c98fe2f547ba9012926ee51e653afd3057b8 100644 GIT binary patch delta 1804 zcmb`Ie^AnQ7{@<|iq%eZwVCVE+Fka;L}o*B6twfQR_5;1)6@!^IkUtJQACq3uG_pV z#jO@*SL)78?G$Y(Oq9?(bA_QDDj>f!4+zPm2oR7jTepAq*KXeV{P}*K=U&gRyXWUm zr?z!5*ZO0-8tl(}0YD(UK@hk$8xRaFsMGSB(l`9@oE|q+ef>x_yuNSe^&`c8D9LZ1 z%|H>kB>6?;Mk3zmBu;d~3+MCqSfa}ai*9H*7gv;VG-qAe?%J4PTKT;_zKvF!{o!Jd zI5UA{MBHeIN!nBr9)X?@N%&*#CM66HQuo+E2tykOwj^s2T*|3#g?4LuM&)+m)lE`0v4xHltK zVkjB4{4Sh3?HId77r^o8JKz@Ncy{y{{hrThFVjGxLNj}lJ>LHwY*W)Q`){DvK za^33|87XXAhC5_%{44*PRiHcnol93qIPGRfTQ^;b5EmTG3Jj-+7nOasi*-a{a|g2~ z^W~2aD(>lo2Xny0PH{RDapAOWxUoOa^XNuulAV9XF=BYoP?r6BUjDaAqjL%^J3^3a z=2OnPl@&tx#uF8S#M|F8)uWF};*(34&v`gQ62e`Egtnfn@{|{eL(#b>dxf<*rD-FY z%Mh8{E3Gjc>mV-_xAuxgC|D62UkJI4yD&61TArTDoxJK<`;OlG6y=(ucGrh!5^~+= z__2=C=32!mHY#3LFq;)S{*ao{FWL?5!1GSv43qWs8HVYFC^{5YD)31yC7fj|4mTsI zMn+GI&%nOZ0=P+3_oLBgp#OEAJ+(qB%Ew-uc_gvae95JauLF@UE)DA}FDYm|o)8eFI_dl`S{G0W5-*=>-P8|I-1jJY`ig zpp_Q9s&wE7t!!MYOb-LlN|v?i^nm#E|9>hgq6=W?K|4Aa;rq|ayCx1G`BDSH-}V<2 C0oMHh delta 1329 zcmcbnIzeee9T(ej|C(j&tdoDRDbyRjy&E0$C`-cOV!7MocY67s=im4k5$gAt`S~+{=Ea^r{N?qVHKm!c(djMGIn!?*m07mRmM!7! zul(A(*Ylch{=LF%U|+0v_u%3+l>zyQ?bhogjqftlm@k(*P#w2jkb$lGhr#^%e_z@E z*B^gv%5;EXIp3G_{1@zMCeOXealq{V{%ij$zRjJTEo(2ZeBXDo@7o{C-rzWp?tO2M z^}aXv8P@Fnd~JsH?fJj%{hk^Beucr@ee>?V-H~?Y&mM*~mF)k2Y|4JWr+%7kvc=Xr zPv6(h`!2Wa^LYuk_6O&zSMI#q!++pX^Lw#tH9g-y7G>81Rl4bHuZdm0xaj33<(Qq5 zXZ}5RgJI2Ip1*T+{j;yvOsjuo1T=1Y?%ukcYhOp1U2lJ2c00Aq;5z$*PmwS0yuN>W zeZ2j;^t_!vjUUZAtv9>)_O4WrLi5*)ep%Sc*M9x8tL=Ga_w9RX#ZPm%4_s@`%v)~p z{j=>mpXlu`uN2jP-%(pEw|x5I^>K02D`sx{aq4zT*!fQkJ(kUJasTf4Z9YCX^R?OB zsCRPP-+y`h%gld0`=6)jG2YLo-+V8#%+_`S(}w?V&F!=JcHdH9yz&3rY15f#mg0TI6 zcfZO0_fdec;UOP)-2L~DADaQ0(^wMZ6$Kb1@_ZTYwLf_6&XBM{m+{7RhS@*oH!Aor zV4`|VA-amxV{;T8T~LoDOz3Dm!$=SR$*Ju8%m#niHx~&?GQ!Hmi9+^lYxo&}0000L Bzs>*v From 3d93bb4edcf060daf81e0fc346d3b85b69298ada Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Thu, 16 Nov 2023 14:20:38 -0600 Subject: [PATCH 18/55] Finish the art behind level 3 --- resource.pyxres | Bin 4822 -> 5135 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resource.pyxres b/resource.pyxres index 4037c98fe2f547ba9012926ee51e653afd3057b8..e5dc8cae19eac37b2dec33c461301ec8fa6f24a1 100644 GIT binary patch delta 1472 zcmV;x1wZ=MC66euehLPH<(lpW2$T2*Ab&CK-D^_YNEn9E|6Yv(0h0Z1Y)EBN7@<~o z>tac~=Tv=FgRx~@A8ZKBFob#?p5EuVGEddzybM2z(`#;7OJ@svtd}{(+=f(V3_$Pl z_kQlR>tIel=>e!u&D;*&O3y*v!wFAZv(4lN;A*B0;E~U51b~gbjOOd-AAj+WpMTc~ z02`RP(7zs_bGXRKYy@DLKkxO&Uwv!Sqjs@R-S#oZJMjr@1mLTdZ{FSC_iq6Dc3zLE z$JK88Jf-EX3sb9uPg1kre7^wndOQ?Y z?_*upKW^!=+Gc$S_E|4;f>|Gc`L9Z)Z-C9ee;qHU_PF|2#Gd=MO=(@1JZ|Z-`lc_c zufwmqkAA%`;n%RlzT0G0&awb3y_jkzMd|ZrJeiiR)70aR*uI+A;rHD~zklB!@q1X} zk=tatr#%4Md#^Fb${ zIes1=fU~*kdhg-jlhHhW&VL<%`+utYR+yH@&ixbNt=IV~YWr`y=Q+iRZl-6u0JNL{ zdz?sXE#0oGd(`$FcygQi+%`LKEz4P>{M_|d1K-8ew!Y20I-0uQ$H(iBNy*QReve@6 zBo|Fa0D5=&$Nk4AVf%?T_ZxgY>u^O=5i9M>&-=UexXgdNrJo!99)H2u122q}Y5!e- z-V?3#`K4Mm=t^3?BCpxsrTfi2-;(v8p5H_5mC3SsHrvi^=>6te=>*$b+Xk(FJFwRu zGpSwhQ~PsnTU+ikxBSxaYyDdeJD-^5F>{;w&TK7ZC^WE=*`hPY)o9oZ5;ZEoH23zmO^;+_O1^T;Q<%|7(J$gSLFQ>G9t^1+; zxYEmPFUJGs)^X=!L(so*TfDz4e^YL1y;^Q-{kXQxt^1|+d?tEs3m)`z&>XXqN*CnP z+gd*s0P}#k4R6DH&VvWc z`Toy9TW#Fb@>uWneLuebzc0uCeFZ1G00n^W7rbF!Pd6>idtR`Oa)*~ z1jdhFySx)!e1F#uz}!EV?O&O;3$1hk&0SzqA5Tr|@}}2o9GUs;{jN#@SbEV4z)1t} z_utDuZybTIAsBxZ9^da{<}c>jy3MVBi=O*_7gHBw%du^J75DkLmOk!#b@t#3?Ci5F z03R3s^K1mxt=!iOyJwl>^_W|~lIdlY-fGM*E5(xIvw!6AEz8&0J=!1gQr z)O_FZdd!^+C8cFeJx^^}N7?$Dj=kRls2!W7%ebF4Kcxttz5tXj{^)iSrO9UdHbNKr*ut4_*S3Fb^mM*lqX^ avvLs`0S1EQn(hV&laUfX2CEVP0001hmMt3q delta 1160 zcmV;31b6$7DApygehLmSu%GwM1^@s70R#XS0F&So8Gr5FS#G0R6o%1vM#GJjN@e~N zyD61Qb_fT~p)ufpEond4aRV4WH|hF5)UW>SYi=|1HhVko{eQ)2HFaA{XA65QmpR3B zeX27Cp!N3mzVEfmU`{{j0hpgTQyX|IEf4A*PPpTmZ6-GWS2Oki9(mtJ0NB|3V19o6 z`3L{-et(Ssuz|4y{pSO84j0*(jQ}k3=e_>$*>`SQ%pL4w=iTRcC*FaL0Q^+*;oak9 z{|2CKGIiN4tlY`Wd1u=Iw0;l0WXa3g zmha_{U8Z&8-IsO!^_JdN-K-D6KFeiJFzW*_{j5~_0BrjG>+p8wt~dXT*mBvrDJ|=g z>n**lwrPv%um1PLso!6>@Vj4P-*qx8XITK29!zsPMd|Bj+?kdx)7bTnSid>H`p<_` zpMPK1`0ST><~o_?sSm(5&!E%SFYPpE+?kdx)7bTnSikYd^*$e82mJIauG;y}oOinZ zOb?_0oPYVvOHFsG1rmVsFTZ)I`TiE*qrVwraz+4*37%sDa3)t?_CF5XdCc`k0Is^+ z|7@|$2km_3_<4Q+&gQDiy@!K$M)UkRcYgpLe^mFQFg4em`Vrx+m-#B@w%>O5bBZ0^ zjL&ufsM!Jb*pb#+x?WfJto1u^=Qi`xZT7&`+|C;1`<{O_@G8dE^<(1I(b(ngr`JCw zC0qR-!O%$#nv4LnZuI-*hdW{YjyClhd@ajxMPm^wZOiZ5yY_LJKE0)_eve@2iGK%1 z%GCcZKQ-p| z+kw6Qn91A$Kej!m*0ts`Q@3Aw{A&M}!_GUVdCqhbU)=wFb;}*~E&x+MF5CXWUEP6J z`ao~$)A_N}bD!w@w4VUW1Mv6f8D;5PdVKD^w0>H{#gY*Wh*FKSr;?g#&EG6Ks2 zFg(D&AEdR{A1=q#@|BF=mPxk;yo~k${5<%}5m*<1QWTC3fVT#`jJ5!j5B~88Y#)I7 z87{{d0U%u0w|(2L<)wT5v$X)gA-Y2kQUQQN34j0)OaKIcV15^~K@esFlQ0n@1G@fy av#Syr0R}LzpZCoMlgbl6267Pq000059dAwm From 4890fb3342ca80c1eee6d5d6c39da406e7484ac9 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Thu, 16 Nov 2023 15:59:00 -0600 Subject: [PATCH 19/55] Keep working on character physics and level protocols --- src/baseclasses.py | 2 +- src/characters.py | 78 +++++++++++++++++++++++++++++++++++++++------- src/menu.py | 3 -- src/one.py | 3 -- 4 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index 9f0bf08..fd96429 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -13,7 +13,7 @@ class BaseLevel(ABC): next = "" # Where should we go after finishing def __init__(self): - pass + pyxel.camera() # TODO: is this safe to do here?? def check_quit(self): if pyxel.btnp(pyxel.KEY_Q): diff --git a/src/characters.py b/src/characters.py index f540eb8..ec2da8c 100644 --- a/src/characters.py +++ b/src/characters.py @@ -3,19 +3,19 @@ including the main players (Diddi, Eli), the mobs (onions, slimehorns, robots, etc), coins, and NPCs. """ +# (Some of the functions/protocols were borrowed from +# another project of mine, 'abandon-the-ship') +# +# TODO: Get sure everything here can be invoked +# from the level classes. Otherwise, will we +# have to adapt the player's code, or even come +# up with a different solution??? import random import pyxel # === Tool functions (physics, data, etc) -# (Some of these were borrowed from another -# project of mine, 'abandon-the-ship') - -# TODO: Verify these functions can be invoked -# from the level classes. Otherwise, will we -# have to adapt the player's code or come -# up with a different solution?? SCROLL_BORDER_X = 80 WALL_TILE_X = 4 @@ -44,11 +44,9 @@ def adjust_x(real_x): return scroll_x + real_x - def get_tile(tile_x, tile_y): return pyxel.tilemap(1).pget(tile_x, tile_y) - def detect_collision(x, y, dy): x1 = x // 8 y1 = y // 8 @@ -64,6 +62,37 @@ def detect_collision(x, y, dy): return True return False +def is_wall(x, y): + tile = get_tile(x // 8, y // 8) + return tile in TILES_FLOOR or tile[0] >= WALL_TILE_X + +def push_back(x, y, dx, dy): + abs_dx = abs(dx) + abs_dy = abs(dy) + if abs_dx > abs_dy: + sign = 1 if dx > 0 else -1 + for _ in range(abs_dx): + if detect_collision(x + sign, y, dy): + break + x += sign + sign = 1 if dy > 0 else -1 + for _ in range(abs_dy): + if detect_collision(x, y + sign, dy): + break + y += sign + else: + sign = 1 if dy > 0 else -1 + for _ in range(abs_dy): + if detect_collision(x, y + sign, dy): + break + y += sign + sign = 1 if dx > 0 else -1 + for _ in range(abs_dx): + if detect_collision(x + sign, y, dy): + break + x += sign + return x, y, dx, dy + # === Players === @@ -146,6 +175,13 @@ def check_bullets(self): def update(self): "Update and react to key controls." self.check_bullets() + if not self.alive: + # NOTE: Why not putting 'self.check_bullets' after this block? + # Well, what if, during multiplayer mode, one of the character + # shoots a bullet and dies before such bullets finish their journey? + return + global scroll_x + self.prev_y = self.y if pyxel.btnp(self.key_bullet): if self.r_facing: # Send a bullet to the right @@ -154,11 +190,31 @@ def update(self): # Send a bullet to the left self.bullets.append(Bullet(self.x, self.y, False)) if pyxel.btnp(self.key_left): - # TODO: fixme! + # Move to the left + self.dx = -2 self.r_facing = False elif pyxel.btnp(self.key_right): - # TODO: fixme! + # Move to the right + self.dx = 2 self.r_facing = True + self.dy = min(self.dy + 1, 3) + if pyxel.btnp(self.key_up) and not self.is_falling: + # Jump (instead of the fly-ish mechanics from previous games) + self.dy = -8 # TODO: Adjust this in order to achieve realistic jumps + # Now operate the movement + self.x, self.y, self.dx, self.dy = push_back(self.x, self.y, self.dx, self.dy) + if self.x < scroll_x: + self.x = scroll_x + if self.y < 0: + self.y = 0 + self.dx = int(self.dx * 0.8) + self.is_falling = self.y > self.prev_y + # And finally, move the screen forward if needed + if self.x > scroll_x + SCROLL_BORDER_X: + # The 'scroll_x' stuff is located here, but may also happen + # in 'Player2.update' in either Eli-mode or multiplayer mode. + last_scroll_x = scroll_x + scroll_x = min(self.x - SCROLL_BORDER_X, 240 * 8) def draw(self): "Draw the character." diff --git a/src/menu.py b/src/menu.py index 2643c15..371a833 100644 --- a/src/menu.py +++ b/src/menu.py @@ -9,9 +9,6 @@ class Menu(BaseLevel): player_choice = 0 player_choice_text = {0: "[1] Single (Diddi)", 1: "[2] Single (Eli)", 2: "[3] Multiplayer"} - def __init__(self): - pass - def update(self): "Pyxel-like 'update' function." self.check_quit() diff --git a/src/one.py b/src/one.py index 50a587a..c2b0fd0 100644 --- a/src/one.py +++ b/src/one.py @@ -13,9 +13,6 @@ class One(BaseLevel): a lot of enemies or tricky spots. """ - def __init__(self): - pass - def update(self): "Pyxel-like 'update' function." self.check_quit() From f620e7c0523cc3ad5199d94808ca6f8967082e34 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Fri, 17 Nov 2023 13:09:36 -0600 Subject: [PATCH 20/55] Establish the initial connections between level classes and `src/characters` --- src/baseclasses.py | 10 ++++++++++ src/characters.py | 15 ++++++++++++++- src/one.py | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index fd96429..0253209 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -3,6 +3,7 @@ import pyxel from abc import ABC, abstractmethod +from .characters import * class BaseLevel(ABC): "Base level." @@ -14,6 +15,7 @@ class BaseLevel(ABC): def __init__(self): pyxel.camera() # TODO: is this safe to do here?? + # self.create_characters() def check_quit(self): if pyxel.btnp(pyxel.KEY_Q): @@ -25,6 +27,14 @@ def check_reset(self): self.next = "menu" return True return False + + def create_characters(self): + if self.player_choice == 0: + self.player = [Player1(0, 0)] + elif self.player_choice == 1: + self.player = [Player2(0, 0)] + elif self.player_choice == 2: + self.player = [Player1(0, 0), Player2(0, 10)] @abstractmethod def update(self): diff --git a/src/characters.py b/src/characters.py index ec2da8c..4b98ced 100644 --- a/src/characters.py +++ b/src/characters.py @@ -15,7 +15,20 @@ import pyxel -# === Tool functions (physics, data, etc) +# === Tool functions (physics, data, etc) === + +__all__ = ( + "Player1", + "Player2", + "Onion", + "Robot", + "Slimehorn1", + "Slimehorn2", + "Slimehorn3", + "Slimehorn4", + "Bullet", + "Coin" +) SCROLL_BORDER_X = 80 WALL_TILE_X = 4 diff --git a/src/one.py b/src/one.py index c2b0fd0..12597ca 100644 --- a/src/one.py +++ b/src/one.py @@ -1,6 +1,7 @@ import pyxel from .baseclasses import BaseLevel +from .characters import * from .tools import draw_text From 1e1b204c8cebca675e8c7ee2ab36a6a1332a940f Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Mon, 20 Nov 2023 16:58:07 -0600 Subject: [PATCH 21/55] Make some art style fixes, and finish with level 4 --- resource.pyxres | Bin 5135 -> 5725 bytes src/characters.py | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resource.pyxres b/resource.pyxres index e5dc8cae19eac37b2dec33c461301ec8fa6f24a1..2713760cc81bfb0cbe2270a9ee465db9d1cdd284 100644 GIT binary patch literal 5725 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 diff --git a/src/characters.py b/src/characters.py index 4b98ced..8035905 100644 --- a/src/characters.py +++ b/src/characters.py @@ -41,8 +41,8 @@ (56, 8), # Red bricks (40, 16), # Sand - Up (40, 24), # Sand - Down - (48, 16), # White struct 1 - (48, 24), # White struct 2 + (48, 16), # Box 1 + (48, 24), # Box 2 (56, 16), # Dirt - Up (56, 24), # Dirt - Down (0, 64), # Gate (L, 1) From 7fe68d3a88b99ebbe18e1a1077611bd229c0b9f2 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Mon, 20 Nov 2023 16:59:40 -0600 Subject: [PATCH 22/55] Remove references to level 6, we'll only run 5 --- src/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/__init__.py b/src/__init__.py index ca30a81..ea2e82e 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,6 +1,6 @@ "Extra code/tools for the game." -from . import menu, one # , two, three, four, five, six +from . import menu, one # , two, three, four, five __all__ = ("stages_list") @@ -9,7 +9,6 @@ Three = None # three.Three Four = None # four.Four Five = None # five.Five -Six = None # six.Six # NOTE: Below I have the already-linked objects Menu = menu.Menu One = one.One @@ -21,6 +20,5 @@ "three": Three, "four": Four, "five": Five, - "six": Six, "menu": Menu, } From f8806778121a3501c8a27c722f1008b089c44a24 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 21 Nov 2023 13:14:23 -0600 Subject: [PATCH 23/55] More interactions between character classes and level classes --- src/baseclasses.py | 11 +++++++++++ src/characters.py | 18 ++++++++++++------ src/one.py | 3 ++- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index 0253209..8f2dc03 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -35,6 +35,17 @@ def create_characters(self): self.player = [Player2(0, 0)] elif self.player_choice == 2: self.player = [Player1(0, 0), Player2(0, 10)] + + def update_template(self): + "Some update actions that should happen in (almost) every instance." + for p in self.player: + p.update() + for b in p.bullets: + b.update() + + def draw_template(self): + "Some drawing actions that should happen in (almost) every instance." + pyxel.cls(0) @abstractmethod def update(self): diff --git a/src/characters.py b/src/characters.py index 8035905..70893bc 100644 --- a/src/characters.py +++ b/src/characters.py @@ -3,8 +3,11 @@ including the main players (Diddi, Eli), the mobs (onions, slimehorns, robots, etc), coins, and NPCs. """ -# (Some of the functions/protocols were borrowed from -# another project of mine, 'abandon-the-ship') + +# Some of the functions/protocols were borrowed from +# another project of mine, 'abandon-the-ship'. To be +# honest, "Diddi and Eli" can be considered a spiritual +# successor to "Abandon the ship!"... # # TODO: Get sure everything here can be invoked # from the level classes. Otherwise, will we @@ -180,10 +183,13 @@ def get_scroll_x(self): return scroll_x def check_bullets(self): - for i in self.bullets: - if not i.alive: - # TODO: Kill this object - pass + "Control bullets." + kills = list() + for i in range(len(self.bullets)): + if not self.bullets[i].alive: + kills.append(i) + for k in kills.sort(reverse=True): + self.bullets.pop(k) def update(self): "Update and react to key controls." diff --git a/src/one.py b/src/one.py index 12597ca..ce817a3 100644 --- a/src/one.py +++ b/src/one.py @@ -19,7 +19,8 @@ def update(self): self.check_quit() if self.check_reset(): return None + self.update_template() def draw(self): "pyxel-like 'update' function." - pyxel.cls(0) + self.draw_template() From 65d266a39c134325ebc2ea258194a697b914e390 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 21 Nov 2023 13:21:44 -0600 Subject: [PATCH 24/55] Provide code for both `Bullet` and `Coin` classes --- src/characters.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/characters.py b/src/characters.py index 70893bc..b30586b 100644 --- a/src/characters.py +++ b/src/characters.py @@ -307,9 +307,43 @@ class Slimehorn4(BaseMob): class Bullet: - "A bullet send by either Diddi or Eli and may damage enemies." + "A bullet send by either Diddi or Eli, which may damage enemies." alive = False + def __init__(self, x, y, r_facing=True): + self.x = x + self.y = y + self.r_facing = r_facing + self.alive = True + + def update(self): + if not self.alive: + return + if self.r_facing: + self.x += 2 + else: + self.x -= 2 + + def draw(self): + if not self.alive: + return + pyxel.rect(self.x, self.y, 4, 2, 11) + + class Coin: "A coin that gives you points to brag about." alive = False + + def __init__(self, x, y): + self.x = x + self.y = y + self.alive = True + + def update(self): + # We won't do anything at all here! + pass + + def draw(self): + if not self.alive: + pass + pyxel.blt(self.x, self.y, 0, 0, 8, 8, 8, 0) From 8744469a1596a9032ac9904914e3176377292c1f Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 21 Nov 2023 13:50:03 -0600 Subject: [PATCH 25/55] Finish all the level art! --- resource.pyxres | Bin 5725 -> 6261 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resource.pyxres b/resource.pyxres index 2713760cc81bfb0cbe2270a9ee465db9d1cdd284..ef6ffc25fefa37e80dd0ba5364f20f4c703838d6 100644 GIT binary patch delta 3241 zcmc(idsx!<7so$L8KD0RIAGIlM0JN>?=BBlm)ka4x>e*D!(s}Ob^eYaF5F^{ga|*mO6C$Fp z7v+jOit}s&#b#8s^uh)?te%FZOrp{Pmo^PQ6NV}JJ5PpxK5hPOrt2n`T8#;HR!K)D zO$?`wLf26(Kce{a;#H1wYd&1p{7gbg}x`o&xkfaUannR ztxt*?(r_}F%D+u6gz&{Uj~kM2A|B=$=%736v<^3%o+F^|kA9hQK$g@}Gw&&lB|>fb zt;{XCEJ}q&M7rGe_%yjb0E;N?6kgQs*mx)gfjhs~OZ&F4f{~$ExYfr0lSago-*T)n z_UKc{ulf7$yNX39x%hIQv?$eFKTs>tsTn=`l-cm zW7&MvJ4Nz=i3&x-j39N*yWwhnoZ^$a{P$*kPR^=^eHQX2lwiBkdN@fr<*ky{De1G1 zds!Y|iEAS7u`}P^&Wu{d6A@)vBf#80m@gPE-rV~oI4rKokS|$iXgOLOvr#_LvsYG` zGT;kM;Nwd=3N;<(E&{yqp6-3C!*;F%+d@^k=+ZFP0)m|8iFmm+bC`hPi4!c#*@B2h z*dY+ocN}4-oA_<4EiKI_NF3+8YxiR6&Sp>VqHaYOy>9aR4rnG@WxpG3_aZTW< zGX1~>Mn1Sr3isRLEU*SjlRYbpL<<4+P;YrqB*W!l?Mg6KvN#nH!Pl2d2lS9bh3&Ob zGiuM}OX#QQ7bumORiN(@elek$QgUXje0)Cx!TYJ;_Aa2OU7GD$H)&%uR+fm7`^_Wl z#4LX;)?O9n9`8))s+rw9KHm~N`*mc!3fyUxz=xtI+pYIU5MG6uBu5n!Ay-c&{k8ZM zw$HK7%bh<@43g1n!xRo6Ak3uQ7Oq>pFhWC!{Kc~OhgVnwtvIo`jTNw$Yudy}J z()B`0TV)#{gZet&UCDg&1tcIKK{^r`aVstU_II7YeNzB0mBQNW;iV-K z2S<;zqNFJpCIJi>>NLCH+^SvNB!hdUa+6!zUJ^!VU3kF<=hkWBR15Bx-;M>63caetB+_Vrqcm~J*mKKT$7h-!c}aqM&#WYFHSxN7$LXv z%q52i2s^Z?FuB0>mnzAFSuDLvobpUaFn+H)C9RR8C%u|RmQZQgwL}vl@#s&=BXtOM zYm=vvIWD~wTLn#yW*sMKC{l=tOGLA!GZJp;MRLB)TA;UVxNZBQeIb@$ubt*}Y0_jB zW=xL}RMH1!0iW)a8XC~-sq|q(g7`Xyx76&r)g~|cW3#{oY(viQlr+A-LaY{#R@uHj zhf`!M&ryo17{$Lb1p%vDNSA+Kol-E=`lJG(>&yWU*BnwrP@sHWe;7xZpWY}6FRDwv zA)K$)Vh^wsRRdp~M4-jS2?Tr9LD}ZCiODhUAK!ciu4SHZy&>9BC-q_vHu}{`9|;0o zd1GlJ9m-y+7T-LUzN#wp!Hh^`nQ*>V2`Ne89 zoN4KvDI-u76JIRg$oEGzujj`ER<<(L@4DkVFe9PV{HG(V$iXhs6T06fL7J1YYj9#+ z<6zDyW>v3DLYXG`w$>}T!c zjqy+h`G>O2&**WCk}L>+kY9}-T}ExifBFgWl_q*@MrKN#%0O8Hp}BsdL=_G@fzQ5g z0rG1y(QF!$pJh(%<(ZUstaAzdbOXH&hW;M6rm04?m`Pnr^w#M5GPRGl~TS1Ecbg; zlOV7KPmB#a)K*lcvJ6q`9yK(YUo)7&TXwKpdJKN-2t3WeF@pVb@S^a>x>gE8zCNx{RCVkIQP^vQn2g&n>Z2<~2!r=6VFo zGtmtr4nXr&IAU_UHAMK`CW3C{_M9kRw6ecr@4c!1${uwP=`y349fYtuAJiK7K*?i1 zk5PF0YPWH5w$(W2#UQm%qO9@EY&_Kl@n(9)no_WQRORrM&R5zySB=f}r{=7Z*fZa6!zC!}4 zGaOhP1mNe7qW^pl`Zu5-F`>Wb@XvSp5%eP_^e@i-KNWr8|9=<$0h&zEFFNc6gKtB8 W3g|E^B<#Qc$jTLXW280sV1EIp@xev_ delta 2693 zcmchZdsNbC8pnSaWm?%xGt;JK*|u%d-7MXbz?>#+HSdiih&W>&6GAN&6~y1qoSkN- zNw&$$ZUwXvni+VBOCYzJ(k53)O==*;E=r1si9m?JG-pqLv}g9OJ*Vft?{hxyIiL4= z-alST(BS5l@4OeBxGm%T)%zUXdo5@hMbT zc+>ayvS7s6M0Q;A)&3a=JKf*XE@q0x(5;aJYJpIgf12Egd)QS?pu>VBE^MAd6MA(J zO#%2#95N&dK9Q97<*5KPDOn7gqR#G^v9Y%>lu@}@FKC}O6OeX~PlGPUQkR`v1C)5v zeIQOndFe^((?CY57gVmVbeQKW?CiXzNd5vxAKyfg1{7zk1Gdt9Ue-1PuPJxInc*{s zF}x6Cc8!{f3$jr1*MA{u(l3I{qE`geyy3E;-bx$C^!=AP;#q#z>=;|X_i;i^%Xt$=2nqoS_(6Uuy=}BjXkCg#nyXex zO~Q1=6HSq2z!H&vf!rAI&;m;U4{ekIDWEG1A5Rop*FL)^rF}s#oF7s1h}Szlv+Q(I z$p#%gWDdbSuB9cR)e_(^;vX2sGep)0a%OM+SG8Z4i|C&m{2&!8^`s@ zkd2Q1sU~UrI-uH{*9ljO?Vh<9QB-v;l2sn7wGCG=q5>3frG{(*?=B~mC+L&u%??lH zlSGfeTa^g51T-Rm9yj;3EMc7tZxhsat1cDI3AH_2!z37<(c@CXyv<{@JF5qCn+1-d zLYqe6NzNVM)pf_EsVKE+{s0m^PxVy}UbhJy6=SC9cq|cd?nbYE;V3!yXs}1d%q372 zZu;6%l_CLO;QOoAV!d1YTIWioR8@@ATI>4dWdXdPc;$)>1MXC)_cw}X+b?GZg#E~j zdO@rz&XH@ZYCb4-9pr90S7f;+a97*io`3vUyUR^g5ReJ=M zx*oi-eP!GtBl;At?mj~VrX#0E*02#G9*Csj*Q;|4eFal2BViE5O3^BYo6}iUKQHqGnQ$0%7yulLEd4>PPN#Mo1U7uTmgUp$g8D)B5 zNqK5{Vs0Z2*-yz6S;e-Sd||_7L)P8T6sr%>cOT%u#AJ+#1iLhuu&v(#&Rp9V;sscw zf5)EGXUu4pCABtc~ph3V)sEJn&d6Uv(s7)iyxA`bBHtr`>q(S~Wju1Wa$Nk)Xj@0_b9FD z29IItlp;jt?0(M7NI4T~C!~_~_ zJwwD+`$k6_Fq$|bj^1WTKBwl)y%eXmSDF1vDXp>LiG`$|vg~mAaW4?+qX`@_+FdMRmNu%M)XK#&Plt4f>^rJaiYtW|@~Lw* z#*THs(4S!~`!7&MtsPtqXL2eP>hGNY2#sW$o!DzKUy^tk5U7T6oHk)yDnXka1K?K8Dw8KBLfot$3Is()e!fx$fBqN~Ze6V}pAo(1pQ9Ldcl|?qt zZ;}HLE30ijP!}TF^Josm#E+V1q29jLf#lzrirU5!u4QT za=x?wnU&CWomw$62d(jIw)K9 z&GDwx_;#7ov`m^iHKueu{}k}^Y%2_+);a~RZ9BanJAcS3?75XQuG1&^Q?$XsrhC}G zHT#!^>R^@Tq~_fyq7z@bTw(9N~E-M4!Svz(M~ zB%P-rUD0l?`%la~w&m@i+(b_1PVOGEjZmC{9K}H)XOMWI#nu;!Az}J<=nk|KMd4nM zyr4dG6D* Date: Tue, 21 Nov 2023 18:38:06 -0600 Subject: [PATCH 26/55] Set up methods for both `Onion` and `Robot` classes --- src/characters.py | 58 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/characters.py b/src/characters.py index b30586b..144bd57 100644 --- a/src/characters.py +++ b/src/characters.py @@ -5,8 +5,10 @@ """ # Some of the functions/protocols were borrowed from -# another project of mine, 'abandon-the-ship'. To be -# honest, "Diddi and Eli" can be considered a spiritual +# another project of mine, "Abandon the ship!", which +# is based in Pyxel example #10, "Platformer". +# +# To be honest, "Diddi and Eli" can be considered a spiritual # successor to "Abandon the ship!"... # # TODO: Get sure everything here can be invoked @@ -280,11 +282,57 @@ class BaseMob: "Simple base for all the mobs." alive = False + def __init__(self, x, y): + self.x = x + self.y = y + self.dx = 0 + self.dy = 0 + self.alive = True + + def update(self): + pass + + def draw(self): + pass + class Onion(BaseMob): - "Mobs who just walk but can fall from cliffs." + "Mobs that just walk but can fall from cliffs." + direction = -1 + + def update(self): + self.dx = self.direction + if self.direction < 0 and is_wall(self.x - 1, self.y + 4): + self.direction = 1 + elif self.direction > 0 and is_wall(self.x + 8, self.y + 4): + self.direction = -1 + self.x, self.y, self.dx, self.dy = push_back(self.x, self.y, self.dx, self.dy) + + def draw(self): + u = 16 if self.direction < 0 else 24 + v = random.choice([48, 56]) + pyxel.blt(self.x, self.y, 0, u, v, 8, 8, 0) -class Robot(Onion): - "Mobs who walk, without falling from cliffs, making then harder to defeat." +class Robot(BaseMob): + "Mobs that walk, without falling from cliffs, making then harder to defeat." + direction = -1 + + def update(self): + self.dx = self.direction + if is_wall(self.x, self.y + 8) or is_wall(self.x + 7, self.y + 8): + if self.direction < 0 and ( + is_wall(self.x - 1, self.y + 4) or not is_wall(self.x - 1, self.y + 8) + ): + self.direction = 1 + elif self.direction > 0 and ( + is_wall(self.x + 8, self.y + 4) or not is_wall(self.x + 7, self.y + 8) + ): + self.direction = -1 + self.x, self.y, self.dx, self.dy = push_back(self.x, self.y, self.dx, self.dy) + + def draw(self): + u = 0 if self.direction < 0 else 8 + v = random.choice([48, 56]) + pyxel.blt(self.x, self.y, 0, u, v, 8, 8, 0) class Slimehorn1(BaseMob): "Mobs that stick to a surface (Down)." From 59aeb0e33bc3b51a43532ae453438fb5622ab0fc Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 21 Nov 2023 19:11:27 -0600 Subject: [PATCH 27/55] Compose some music for all the game (excluding the menu) --- resource.pyxres | Bin 6261 -> 7999 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resource.pyxres b/resource.pyxres index ef6ffc25fefa37e80dd0ba5364f20f4c703838d6..90480948f8fa4025ff50567a18580459338481c8 100644 GIT binary patch delta 1783 zcmajfUr19?90%|-H^(Gr`%_J$2Uk-HQ}6CMn{Tqv(zsJc_);w_RB*a96wCE;vdkxm zGye55Ckj`!7Je_1A&0Q z*Z;sD+6s;M!+PYClC8mlyGw_dad{_YA0y8rk%-RlCK{dU zn_6GrI5FKf-Dd>)qnG)4c}yLR%)G_qOj)+~j8hGe zj|67w4*suhjEOt05*JAySnXZ)L@kwfvhy`3N93N!9nmX$QtpkdIhZZ-s;RQUq$)g~ zfdm7ZFa1#N&}Mv>KFwL51aD|>RF45Yg#Z92 z7M4{3;=F801!&5K%O!|dSXC8z?w`A8WW}439|Dwsv9KfxpIIR^jMAWq_&Xs2 zqsWmNC6X{iXu!~M!^+-Ai55}t9>NfT>EcM+KLi*A8Zb!QctzC^7eruSIC6kx2n;;Y z5jQkoSP-HKX1KdWi6o)}4Hy?*$72;jG2EoUP&u^R_^M(kh6^LZiK4xVcF0en7;QW? cN0Vd2jaC(djW%5$zs=0PAss?v>_&us0}@8HRsaA1 delta 33 jcmdmQ_tjv7u=wUpQhtmgtZWQGzzT$Zj0_Bd;vgOXkUj-# From 6cde762bcd94bafd5b3bc29e2144fc77e0e17c5c Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 22 Nov 2023 17:33:46 -0600 Subject: [PATCH 28/55] Work on `Slimehorn...` mob classes --- src/characters.py | 37 +++++++++++++++++++++++++++++-------- src/one.py | 4 ++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/characters.py b/src/characters.py index 144bd57..af5b4ad 100644 --- a/src/characters.py +++ b/src/characters.py @@ -334,21 +334,42 @@ def draw(self): v = random.choice([48, 56]) pyxel.blt(self.x, self.y, 0, u, v, 8, 8, 0) -class Slimehorn1(BaseMob): +class SlimehornBase(BaseMob): + "Base class for slimehorns (see below)." + imgs = [tuple(), tuple()] + + def __init__(self, x, y, variant=False): + self.x = self.x + self.y = y + self.variant = variant + + def update(self): + # TODO: By now, Slimehorns won't move. + # Let's try to give them some action + # in a future version! + pass + + def draw(self): + if not self.alive: + return + combo = self.imgs[0] if self.variant else self.imgs[1] + pyxel.blt(self.x, self.y, 0, combo[0], combo[2], 8, 8, 0) + +class Slimehorn1(SlimehornBase): "Mobs that stick to a surface (Down)." - variant = False + imgs = [(32, 48), (48, 48)] -class Slimehorn2(BaseMob): +class Slimehorn2(SlimehornBase): "Mobs that stick to a surface (Up)." - variant = False + imgs = [(32, 56), (48, 56)] -class Slimehorn3(BaseMob): +class Slimehorn3(SlimehornBase): "Mobs that stick to a surface (Left)." - variant = False + imgs = [(40, 48), (56, 48)] -class Slimehorn4(BaseMob): +class Slimehorn4(SlimehornBase): "Mobs that stick to a surface (Right)." - variant = False + imgs = [(40, 56), (56, 56)] # === Coins/bullets === diff --git a/src/one.py b/src/one.py index ce817a3..9a80afa 100644 --- a/src/one.py +++ b/src/one.py @@ -14,6 +14,10 @@ class One(BaseLevel): a lot of enemies or tricky spots. """ + def __init__(self): + BaseLevel.__init__(self) + pyxel.playm(0, loop=True) + def update(self): "Pyxel-like 'update' function." self.check_quit() From 9777737ae6cd5d2fada506572f145bdf49a1e992 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 22 Nov 2023 17:47:43 -0600 Subject: [PATCH 29/55] Add further interactions between characters and level classes --- src/baseclasses.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index 8f2dc03..fa4fc53 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -12,10 +12,13 @@ class BaseLevel(ABC): players = None # Amount of players involved finished = False # Have we finished today? Can we go home now? next = "" # Where should we go after finishing + lost = False # Did we die?? + enemies = list() # The list with enemies/mobs def __init__(self): - pyxel.camera() # TODO: is this safe to do here?? - # self.create_characters() + # WARNING: is this safe to do here, or should we run these per instance? + pyxel.camera() + self.create_characters() def check_quit(self): if pyxel.btnp(pyxel.KEY_Q): @@ -38,10 +41,24 @@ def create_characters(self): def update_template(self): "Some update actions that should happen in (almost) every instance." + anyone_here = False for p in self.player: p.update() for b in p.bullets: b.update() + for e in self.enemies: + # TODO: Check if a bullet hit a mob. + pass + for e in self.enemies: + # TODO: Check if a mob hit the player. + pass + if p.alive: + anyone_here = True + if not anyone_here: + self.lost = True + return + for e in self.enemies: + e.update() def draw_template(self): "Some drawing actions that should happen in (almost) every instance." @@ -54,3 +71,7 @@ def update(self): @abstractmethod def draw(self): pass + + @abstractmethod + def create_characters(self): + pass From 156b3f525a5f42f03c1db30aa93a21c79d3346d3 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 22 Nov 2023 17:57:35 -0600 Subject: [PATCH 30/55] Compose music for the menu --- resource.pyxres | Bin 7999 -> 8417 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resource.pyxres b/resource.pyxres index 90480948f8fa4025ff50567a18580459338481c8..7735ea9df670684bde0483983748f895df87497a 100644 GIT binary patch delta 386 zcmdmQ_t0@er6lJ}MzgH~3=9mClP`+PsF)iYcrY_DTbxWik;-)B*fNFyZ)O$|pfm>% zD>C>?8hXo3J}a)EY+<~`z{kYLYzxDo6a{X_rXvkTF_k|nR|*`Oar%Y`Sli?WvQm?K zq(mmqm7LF7@B6}tZ*rrQ{Nw~F*2#+`B_`KMnF%19{r)MB`(y_x1$I;84G)YAo^M_$ z<;ctncOKAwvB}?M6(&1Ku<4iwcr!BTF{3#Qs6-#642WT1N#pv-2W2G~EhgWR)na6v zEGRENSw>Eq(Fx3o2eO($EKwtL13~VcY$zwjcm%BSshlqB=t@Bj=LK2_ i3Pn+v#Xx#VqdQoKxM_elD;r2c1PEPN85r87K|BCLYgQ@% delta 165 zcmaFpxZiF=rQ~FOslzNSOB2f`M@lQO8yg!uG%|QF*+E)#a;Sp9!2Rn>(c~ zm?wM6OHIBlCp>wB6zk+_d2OaOl9Lss#U}3qGT(xkx<&!sj7)mWA`A=+96+qd05X^t s$PxfzQ6PqaC5?JgV9hQH+Dv&;lM59jMOfKDvVuTZ$-=;}K?=kJ04lyEnE(I) From 4bf378343586ce3cee65e8373afab1796eb88b2d Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 28 Nov 2023 10:03:00 -0600 Subject: [PATCH 31/55] Simplify the storage of level classes (now saved at module `src.levels`) --- src/__init__.py | 4 ++-- src/{one.py => levels.py} | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) rename src/{one.py => levels.py} (89%) diff --git a/src/__init__.py b/src/__init__.py index ea2e82e..08fa495 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,6 +1,6 @@ "Extra code/tools for the game." -from . import menu, one # , two, three, four, five +from . import menu, levels __all__ = ("stages_list") @@ -11,7 +11,7 @@ Five = None # five.Five # NOTE: Below I have the already-linked objects Menu = menu.Menu -One = one.One +One = levels.One # Below there's a dictionary with all the objects for further use stages_list = { diff --git a/src/one.py b/src/levels.py similarity index 89% rename from src/one.py rename to src/levels.py index 9a80afa..e97efdd 100644 --- a/src/one.py +++ b/src/levels.py @@ -1,3 +1,5 @@ +"Library containing all the level classes, which honestly are pretty simple." + import pyxel from .baseclasses import BaseLevel From cc705b49b6a68fd8f067d1fde2d3afefc9d1db3f Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 28 Nov 2023 21:07:54 -0600 Subject: [PATCH 32/55] Add a WIP strategy for spawning mobs internally --- src/baseclasses.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/baseclasses.py b/src/baseclasses.py index fa4fc53..5f8b418 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -2,6 +2,8 @@ import pyxel +import math + from abc import ABC, abstractmethod from .characters import * @@ -13,6 +15,7 @@ class BaseLevel(ABC): finished = False # Have we finished today? Can we go home now? next = "" # Where should we go after finishing lost = False # Did we die?? + enemy_templates = dict() # Coordinates to spawn enemies, unique for each subclass enemies = list() # The list with enemies/mobs def __init__(self): @@ -39,6 +42,15 @@ def create_characters(self): elif self.player_choice == 2: self.player = [Player1(0, 0), Player2(0, 10)] + def spawn(self): + left_x = math.ceil(left_x / 8) + right_x = math.floor(right_x / 8) + for x in range(left_x, right_x + 1): + for y in range(16): + if (x*8, y*8) in self.enemy_template: + mobclass = self.enemy_templates[(x*8, y*8)] + self.enemies.append(mobclass(x * 8, y * 8)) + def update_template(self): "Some update actions that should happen in (almost) every instance." anyone_here = False From e6e6e24cea451800c21b55a7a2e0ef27577fa781 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 28 Nov 2023 21:15:04 -0600 Subject: [PATCH 33/55] Set up main/linting requirements (and introduce ruff) --- requirements.txt | 1 + test-requirements.txt | 1 + 2 files changed, 2 insertions(+) create mode 100644 requirements.txt create mode 100644 test-requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ab6c31e --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pyxel==1.9.18 \ No newline at end of file diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..c11b9a6 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1 @@ +ruff==0.1.6 \ No newline at end of file From 61edd2f6f9882d585e2f7d3a9748af7f0c02711c Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 28 Nov 2023 21:15:22 -0600 Subject: [PATCH 34/55] Set up a minimal noxfile for linting --- noxfile.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 noxfile.py diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 0000000..a976872 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,18 @@ +import nox + +files = ( + "main.py", + "noxfile.py", + "src/__init__.py", + "src/baseclasses.py", + "src/characters.py", + "src/levels.py", + "src/menu.py", + "src/tools.py" +) + +@nox.session +def format(session: nox.Session): + session.install("-r", "requirements.txt") + session.install("-r", "test-requirements.txt") + session.run("ruff", "check", *files, "--fix") From df55cdaf89a9ed60ac049bbd3740783e486f2e53 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Tue, 28 Nov 2023 21:16:22 -0600 Subject: [PATCH 35/55] Run linters for the first time (several errors found) --- src/levels.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/levels.py b/src/levels.py index e97efdd..1bfa918 100644 --- a/src/levels.py +++ b/src/levels.py @@ -4,7 +4,6 @@ from .baseclasses import BaseLevel from .characters import * -from .tools import draw_text class One(BaseLevel): From e825f94da9c62c9403616b741e7b4ededeec9853 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 10:50:24 -0600 Subject: [PATCH 36/55] Add a `lint` nox session --- noxfile.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index a976872..6360e4d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -13,6 +13,14 @@ @nox.session def format(session: nox.Session): + "Format the codebase." session.install("-r", "requirements.txt") session.install("-r", "test-requirements.txt") - session.run("ruff", "check", *files, "--fix") + session.run("ruff", "check", *files, "--fix") # TODO: ignore certain rules? + +@nox.session +def lint(session: nox.Session): + "Lint the codebase." + session.install("-r", "requirements.txt") + session.install("-r", "test-requirements.txt") + session.run("ruff", "check", *files) # TODO: ignore certain rules? From 5942dc0c2cce2f6a28c8b96e3920a374fb8697e1 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 11:00:06 -0600 Subject: [PATCH 37/55] Further attempts to make level classes work --- src/baseclasses.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index 5f8b418..61f0b9b 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -7,6 +7,18 @@ from abc import ABC, abstractmethod from .characters import * + +# TODO: Only use the variables stored at "src/characters", +# or only use variables from here. +SCROLL_BORDER_X = 80 +scroll_x = 0 + + +def update_scroll_x(player): + # FIXME: We should get rid of this func + scroll_x = player.get_scroll_x() + + class BaseLevel(ABC): "Base level." tilemap = 0 # Tilemap used by the level @@ -19,7 +31,7 @@ class BaseLevel(ABC): enemies = list() # The list with enemies/mobs def __init__(self): - # WARNING: is this safe to do here, or should we run these per instance? + # NOTE: is this safe to do here, or should we run these per instance? pyxel.camera() self.create_characters() @@ -71,6 +83,15 @@ def update_template(self): return for e in self.enemies: e.update() + # NOTE: Only player 1 (Diddi, when multiplayer) will move the screen + # TODO: On multiplayer mode, allow both players to move the screen?? + update_scroll_x(self.player[0]) + player_x = self.player[0].x + if player_x > scroll_x + SCROLL_BORDER_X: + # Move the screen if needed + last_scroll_x = scroll_x + scroll_x = min(self.x - SCROLL_BORDER_X, 240 * 8) + self.spawn(last_scroll_x + 128, scroll_x + 127) def draw_template(self): "Some drawing actions that should happen in (almost) every instance." From 712242fef0914aab2392d913a3d4a62722960145 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 11:08:03 -0600 Subject: [PATCH 38/55] Set up some of the level drawing strategies --- src/baseclasses.py | 18 ++++++++++++++++-- src/levels.py | 4 +++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index 61f0b9b..f2d858c 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -29,23 +29,30 @@ class BaseLevel(ABC): lost = False # Did we die?? enemy_templates = dict() # Coordinates to spawn enemies, unique for each subclass enemies = list() # The list with enemies/mobs + draw_v = 0 # The 'v' parameter used in 'pyxel.bltm', during level drawing def __init__(self): # NOTE: is this safe to do here, or should we run these per instance? pyxel.camera() self.create_characters() - def check_quit(self): + def check_quit(self) -> None: if pyxel.btnp(pyxel.KEY_Q): pyxel.quit() - def check_reset(self): + def check_reset(self) -> bool: if pyxel.btnp(pyxel.KEY_R): self.finished = True self.next = "menu" return True return False + def check_anyone_alive(self) -> bool: + for p in self.player: + if p.alive: + return True + return False + def create_characters(self): if self.player_choice == 0: self.player = [Player1(0, 0)] @@ -96,6 +103,13 @@ def update_template(self): def draw_template(self): "Some drawing actions that should happen in (almost) every instance." pyxel.cls(0) + if self.check_anyone_alive(): + pyxel.camera() + pyxel.bltm(0, 0, 1, scroll_x, self.draw_v, 128, 128, 0) + pyxel.camera(scroll_x, self.draw_v) # test: self.draw_v or 0? + self.player.draw() + for i in self.enemies: + i.draw() @abstractmethod def update(self): diff --git a/src/levels.py b/src/levels.py index 1bfa918..3707ede 100644 --- a/src/levels.py +++ b/src/levels.py @@ -22,10 +22,12 @@ def __init__(self): def update(self): "Pyxel-like 'update' function." self.check_quit() - if self.check_reset(): + if self.check_reset() or self.finished: return None self.update_template() def draw(self): "pyxel-like 'update' function." + if self.finished: + return None self.draw_template() From 6e5bf16e02cdcbc809ebb665f0699b9d4ab6515d Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 11:15:07 -0600 Subject: [PATCH 39/55] Add a few docs for newcommers --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index ab5d838..166fb45 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,28 @@ # Diddi and Eli _Diddi and Eli: a platformer game with scaling challenges._ + +## How to play + +Using Python `>=3.7` and [Pyxel](https://github.com/kitao/pyxel) at a +[recommended version](./requirements.txt), clone or download this +repository and run `main.py` to start the game. + +To win, you'll have to clear five courses, each one harder than the previous +one. Once you reach the final course, defeat the evil **Scaler** to win! + +## Game controls + +- Menu controls + - 1: Start game. + - 2: Select player mode. +- In-game controls (player 1) + - W: Jump + - A: Move to the left + - S: Shoot a bullet + - D: Move to the right +- In-game controls (player 2) + - Up key: Jump + - Left key: Move to the left + - Down key: Shoot a bullet + - Right key: Move to the right \ No newline at end of file From 98f0726a969eb6296dc832724ea643b6cb256a69 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 11:16:21 -0600 Subject: [PATCH 40/55] Fix a crash in `menu.Menu` --- src/baseclasses.py | 4 ---- src/menu.py | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index f2d858c..15429f9 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -118,7 +118,3 @@ def update(self): @abstractmethod def draw(self): pass - - @abstractmethod - def create_characters(self): - pass diff --git a/src/menu.py b/src/menu.py index 371a833..d9f8218 100644 --- a/src/menu.py +++ b/src/menu.py @@ -9,6 +9,9 @@ class Menu(BaseLevel): player_choice = 0 player_choice_text = {0: "[1] Single (Diddi)", 1: "[2] Single (Eli)", 2: "[3] Multiplayer"} + def create_characters(self): + pass + def update(self): "Pyxel-like 'update' function." self.check_quit() @@ -59,3 +62,4 @@ def draw(self): draw_text("- Press R to return -", 23, 82) # Always remind the users how to quit draw_text("- Press Q to quit -", 23, 90) + From 99d32b53ad06fdfbbd4b0f737eae04e5b68d4149 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 11:22:46 -0600 Subject: [PATCH 41/55] Style tweaks to the README + add a credits section --- README.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 166fb45..bedcc2c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ # Diddi and Eli -_Diddi and Eli: a platformer game with scaling challenges._ +[![Nox](https://img.shields.io/badge/%F0%9F%A6%8A-Nox-D85E00.svg)](https://github.com/wntrblm/nox) +[![License](https://img.shields.io/github/license/DiddiLeija/diddi-and-eli)](https://github.com/DiddiLeija/diddi-and-eli) +[![GitHub](https://img.shields.io/github/v/release/DiddiLeija/diddi-and-eli?logo=github&sort=semver)](https://github.com/DiddiLeija/diddi-and-eli) +[![GitHub Repo stars](https://img.shields.io/github/stars/DiddiLeija/diddi-and-eli?style=social)](https://github.com/DiddiLeija/diddi-and-eli) +[![GitHub forks](https://img.shields.io/github/forks/DiddiLeija/diddi-and-eli?style=social)](https://github.com/DiddiLeija/diddi-and-eli) + +[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G3AL6D6) + +> **Diddi and Eli: a platformer game with scaling challenges.** ## How to play @@ -25,4 +33,15 @@ one. Once you reach the final course, defeat the evil **Scaler** to win! - Up key: Jump - Left key: Move to the left - Down key: Shoot a bullet - - Right key: Move to the right \ No newline at end of file + - Right key: Move to the right + +## Credits + +This game is a successor to one of my previous titles, +["Abandon the ship!"](https://github.com/DiddiLeija/abandon-the-ship), which was +based on a platformer example bundled within the [Pyxel](https://github.com/kitao/pyxel) +project. + +Thanks to all those who contributed with feedback when I was developing the game. + +Copyright (c) 2023 Diego Ramirez. From 4d58d74d5da54b3ea25ef5e28db94fa34cf2eff3 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 11:39:47 -0600 Subject: [PATCH 42/55] Fix player/level crashes --- src/baseclasses.py | 37 ++++++++++++++++++------------------- src/characters.py | 17 +++++++++++------ 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index 15429f9..cd57ae2 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -8,17 +8,6 @@ from .characters import * -# TODO: Only use the variables stored at "src/characters", -# or only use variables from here. -SCROLL_BORDER_X = 80 -scroll_x = 0 - - -def update_scroll_x(player): - # FIXME: We should get rid of this func - scroll_x = player.get_scroll_x() - - class BaseLevel(ABC): "Base level." tilemap = 0 # Tilemap used by the level @@ -31,6 +20,11 @@ class BaseLevel(ABC): enemies = list() # The list with enemies/mobs draw_v = 0 # The 'v' parameter used in 'pyxel.bltm', during level drawing + # TODO: Only use the variables stored at "src/characters", + # or only use variables from here. + SCROLL_BORDER_X = 80 + scroll_x = 0 + def __init__(self): # NOTE: is this safe to do here, or should we run these per instance? pyxel.camera() @@ -53,6 +47,10 @@ def check_anyone_alive(self) -> bool: return True return False + def update_scroll_x(self, player): + # FIXME: We should get rid of this func + self.scroll_x = player.get_scroll_x() + def create_characters(self): if self.player_choice == 0: self.player = [Player1(0, 0)] @@ -92,22 +90,23 @@ def update_template(self): e.update() # NOTE: Only player 1 (Diddi, when multiplayer) will move the screen # TODO: On multiplayer mode, allow both players to move the screen?? - update_scroll_x(self.player[0]) + self.update_scroll_x(self.player[0]) player_x = self.player[0].x - if player_x > scroll_x + SCROLL_BORDER_X: + if player_x > self.scroll_x + self.SCROLL_BORDER_X: # Move the screen if needed - last_scroll_x = scroll_x - scroll_x = min(self.x - SCROLL_BORDER_X, 240 * 8) - self.spawn(last_scroll_x + 128, scroll_x + 127) + last_scroll_x = self.scroll_x + self.scroll_x = min(self.x - self.SCROLL_BORDER_X, 240 * 8) + self.spawn(last_scroll_x + 128, self.scroll_x + 127) def draw_template(self): "Some drawing actions that should happen in (almost) every instance." pyxel.cls(0) if self.check_anyone_alive(): pyxel.camera() - pyxel.bltm(0, 0, 1, scroll_x, self.draw_v, 128, 128, 0) - pyxel.camera(scroll_x, self.draw_v) # test: self.draw_v or 0? - self.player.draw() + pyxel.bltm(0, 0, 1, self.scroll_x, self.draw_v, 128, 128, 0) + pyxel.camera(self.scroll_x, self.draw_v) # test: self.draw_v or 0? + for p in self.player: + p.draw() for i in self.enemies: i.draw() diff --git a/src/characters.py b/src/characters.py index af5b4ad..e2aec11 100644 --- a/src/characters.py +++ b/src/characters.py @@ -111,6 +111,9 @@ def push_back(x, y, dx, dy): x += sign return x, y, dx, dy +def reset_scroll_x() -> None: + scroll_x = 0 + # === Players === @@ -132,6 +135,7 @@ def __init__(self, x=0, y=0): self.shoot = False self.is_falling = False self.active = False + reset_scroll_x() self.initial_setup() def initial_setup(self): @@ -178,10 +182,8 @@ def get_image_combo(self): return random.choice(self.imagebank[5:7]) def get_scroll_x(self): - """ - This is just a 'bridge' between a player class and a - level class, where 'scroll_x' is vital but not directly present. - """ + # NOTE: This is just a 'bridge' between a player class and a + # level class, where 'scroll_x' is vital but not directly present. return scroll_x def check_bullets(self): @@ -190,8 +192,11 @@ def check_bullets(self): for i in range(len(self.bullets)): if not self.bullets[i].alive: kills.append(i) - for k in kills.sort(reverse=True): - self.bullets.pop(k) + try: + for k in kills.sort(reverse=True): + self.bullets.pop(k) + except TypeError: + pass def update(self): "Update and react to key controls." From 35855ff4392d05a667d8608e890e218ccfec1e8f Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 11:41:43 -0600 Subject: [PATCH 43/55] Set up a funding button --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..b8103ce --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +ko-fi: diddileija \ No newline at end of file From 53ac6400d0014e13a3e17a2c78b73976a1c86aad Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 11:49:27 -0600 Subject: [PATCH 44/55] Add `.ruff_cache` to the gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 68bc17f..8c6a8cf 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ htmlcov/ .coverage .coverage.* .cache +.ruff_cache nosetests.xml coverage.xml *.cover From bd5ba287d64396c3836b259a41191b829dae2c38 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 11:50:17 -0600 Subject: [PATCH 45/55] Add `.ruff_cache/` to the gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8c6a8cf..68654c1 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,7 @@ htmlcov/ .coverage .coverage.* .cache -.ruff_cache +.ruff_cache/ nosetests.xml coverage.xml *.cover From 93a8a369f460c40f17f879f5cbb205b9898ca061 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 11:55:15 -0600 Subject: [PATCH 46/55] Improve the player movements --- src/characters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/characters.py b/src/characters.py index e2aec11..915a30c 100644 --- a/src/characters.py +++ b/src/characters.py @@ -215,11 +215,11 @@ def update(self): else: # Send a bullet to the left self.bullets.append(Bullet(self.x, self.y, False)) - if pyxel.btnp(self.key_left): + if pyxel.btn(self.key_left): # Move to the left self.dx = -2 self.r_facing = False - elif pyxel.btnp(self.key_right): + elif pyxel.btn(self.key_right): # Move to the right self.dx = 2 self.r_facing = True From 11ce258bb7cabbe6323cec8f456bda05cfc5a4b4 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 12:06:59 -0600 Subject: [PATCH 47/55] Players now die after falling from a cliff --- src/characters.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/characters.py b/src/characters.py index 915a30c..066c7a9 100644 --- a/src/characters.py +++ b/src/characters.py @@ -134,6 +134,7 @@ def __init__(self, x=0, y=0): self.r_facing = True self.shoot = False self.is_falling = False + self.jumping = False self.active = False reset_scroll_x() self.initial_setup() @@ -241,6 +242,9 @@ def update(self): # in 'Player2.update' in either Eli-mode or multiplayer mode. last_scroll_x = scroll_x scroll_x = min(self.x - SCROLL_BORDER_X, 240 * 8) + if self.y >= 120: + # We fell down! + self.alive = False def draw(self): "Draw the character." From 7349bf4e2117a140035217d5c797b1f2c6c086d5 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 12:09:40 -0600 Subject: [PATCH 48/55] Further simplify level classes --- src/baseclasses.py | 2 ++ src/levels.py | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index cd57ae2..4dcfdbd 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -19,6 +19,7 @@ class BaseLevel(ABC): enemy_templates = dict() # Coordinates to spawn enemies, unique for each subclass enemies = list() # The list with enemies/mobs draw_v = 0 # The 'v' parameter used in 'pyxel.bltm', during level drawing + music_vol = 0 # TODO: Only use the variables stored at "src/characters", # or only use variables from here. @@ -29,6 +30,7 @@ def __init__(self): # NOTE: is this safe to do here, or should we run these per instance? pyxel.camera() self.create_characters() + pyxel.playm(0, loop=True) def check_quit(self) -> None: if pyxel.btnp(pyxel.KEY_Q): diff --git a/src/levels.py b/src/levels.py index 3707ede..ff495bf 100644 --- a/src/levels.py +++ b/src/levels.py @@ -15,10 +15,6 @@ class One(BaseLevel): a lot of enemies or tricky spots. """ - def __init__(self): - BaseLevel.__init__(self) - pyxel.playm(0, loop=True) - def update(self): "Pyxel-like 'update' function." self.check_quit() From 068b281d0dd38dfa4ce4fd3dfa524153598324f6 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 17:07:29 -0600 Subject: [PATCH 49/55] General behaviour/operations improvements --- main.py | 5 ++--- resource.pyxres | Bin 8417 -> 8419 bytes src/baseclasses.py | 27 ++++++++++++++------------- src/menu.py | 1 + src/tools.py | 4 ++-- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/main.py b/main.py index 0ac4b20..19739b8 100644 --- a/main.py +++ b/main.py @@ -17,7 +17,7 @@ class Main: def __init__(self): pyxel.load("resource.pyxres") - self.situation = init_class(stages_list["menu"]) + self.situation = init_class(stages_list["menu"], None) pyxel.run(self.update, self.draw) def update(self): @@ -26,8 +26,7 @@ def update(self): # Also, keep memory of your player choice :) if self.situation.finished: tmp = self.situation.player_choice - self.situation = init_class(stages_list[self.situation.next]) - self.situation.player_choice = tmp + self.situation = init_class(stages_list[self.situation.next], tmp) del(tmp) # we have to remove 'tmp' ASAP def draw(self): diff --git a/resource.pyxres b/resource.pyxres index 7735ea9df670684bde0483983748f895df87497a..7c4b785c7503eb0f4bbc3b522f40d44ad0724529 100644 GIT binary patch delta 49 zcmaFp_}Fnns5EC{+R|NlUS^f(0i}loy@6NkNmXQyM7G005Q0 B4oLt2 delta 47 tcmaFt_|S1fs5IyMr#$Yw3=9kcljEcnH#bU4vLXpBR None: if pyxel.btnp(pyxel.KEY_Q): @@ -72,7 +74,6 @@ def spawn(self): def update_template(self): "Some update actions that should happen in (almost) every instance." - anyone_here = False for p in self.player: p.update() for b in p.bullets: @@ -83,10 +84,10 @@ def update_template(self): for e in self.enemies: # TODO: Check if a mob hit the player. pass - if p.alive: - anyone_here = True - if not anyone_here: + if not self.check_anyone_alive(): self.lost = True + pyxel.playm(6) + self.startup() return for e in self.enemies: e.update() diff --git a/src/menu.py b/src/menu.py index d9f8218..6611b9a 100644 --- a/src/menu.py +++ b/src/menu.py @@ -8,6 +8,7 @@ class Menu(BaseLevel): stage = "main" player_choice = 0 player_choice_text = {0: "[1] Single (Diddi)", 1: "[2] Single (Eli)", 2: "[3] Multiplayer"} + music_vol = 5 def create_characters(self): pass diff --git a/src/tools.py b/src/tools.py index 16a3034..0e907b6 100644 --- a/src/tools.py +++ b/src/tools.py @@ -6,5 +6,5 @@ def draw_text(text, x, y): pyxel.text(x, y, text, 1) pyxel.text(x+1, y, text, 7) -def init_class(obj): - return obj() +def init_class(obj, popt): + return obj(popt) From cdc833beda8d9f0e93b711e72187bcce7cc0b20e Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Wed, 29 Nov 2023 17:12:53 -0600 Subject: [PATCH 50/55] Make all player modes available, and fix some issues --- main.py | 2 +- src/baseclasses.py | 7 +++++-- src/characters.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index 19739b8..8372fc9 100644 --- a/main.py +++ b/main.py @@ -17,7 +17,7 @@ class Main: def __init__(self): pyxel.load("resource.pyxres") - self.situation = init_class(stages_list["menu"], None) + self.situation = init_class(stages_list["menu"], 0) pyxel.run(self.update, self.draw) def update(self): diff --git a/src/baseclasses.py b/src/baseclasses.py index 7228e6e..c01e77c 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -12,7 +12,7 @@ class BaseLevel(ABC): "Base level." tilemap = 0 # Tilemap used by the level player_choice = 0 # 0 is Diddi, 1 is Eli, and 2 is multiplayer - players = None # Amount of players involved + player = list() # Amount of players involved finished = False # Have we finished today? Can we go home now? next = "" # Where should we go after finishing lost = False # Did we die?? @@ -20,11 +20,14 @@ class BaseLevel(ABC): enemies = list() # The list with enemies/mobs draw_v = 0 # The 'v' parameter used in 'pyxel.bltm', during level drawing music_vol = 0 + SCROLL_BORDER_X = 80 + scroll_x = 0 def __init__(self, player_choice): # pyxel.camera() self.player_choice = player_choice - self.startup() + self.create_characters() + pyxel.playm(self.music_vol, loop=True) def startup(self): # FIXME: Only use the variables stored at "src/characters", diff --git a/src/characters.py b/src/characters.py index 066c7a9..aeee639 100644 --- a/src/characters.py +++ b/src/characters.py @@ -270,7 +270,7 @@ def initial_setup(self): self.key_up = pyxel.KEY_UP self.key_left = pyxel.KEY_LEFT self.key_bullet = pyxel.KEY_DOWN - self.key_right = pyxel.KEY_UP + self.key_right = pyxel.KEY_RIGHT self.imagebank = [ (8, 16), # Right, normal (16, 16), # Right, walking (1) From b2f4e26c055ba71b17fedd9b0912879850427fbe Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Thu, 30 Nov 2023 11:10:29 -0600 Subject: [PATCH 51/55] Enable player bullets --- src/baseclasses.py | 4 +++- src/characters.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index c01e77c..f60c708 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -10,7 +10,7 @@ class BaseLevel(ABC): "Base level." - tilemap = 0 # Tilemap used by the level + # tilemap = 0 player_choice = 0 # 0 is Diddi, 1 is Eli, and 2 is multiplayer player = list() # Amount of players involved finished = False # Have we finished today? Can we go home now? @@ -113,6 +113,8 @@ def draw_template(self): pyxel.camera(self.scroll_x, self.draw_v) # test: self.draw_v or 0? for p in self.player: p.draw() + for b in p.bullets: + b.draw() for i in self.enemies: i.draw() diff --git a/src/characters.py b/src/characters.py index aeee639..b672c48 100644 --- a/src/characters.py +++ b/src/characters.py @@ -212,10 +212,10 @@ def update(self): if pyxel.btnp(self.key_bullet): if self.r_facing: # Send a bullet to the right - self.bullets.append(Bullet(self.x, self.y)) + self.bullets.append(Bullet(self.x+6, self.y+3)) else: # Send a bullet to the left - self.bullets.append(Bullet(self.x, self.y, False)) + self.bullets.append(Bullet(self.x, self.y+3, False)) if pyxel.btn(self.key_left): # Move to the left self.dx = -2 From 3056f0f6134b3ad4ff5f7a7f4bbeee9a87607162 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Thu, 30 Nov 2023 11:28:17 -0600 Subject: [PATCH 52/55] Try out a method to detect collisions between bullets/players with mobs --- src/baseclasses.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index f60c708..317b1ea 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -82,11 +82,12 @@ def update_template(self): for b in p.bullets: b.update() for e in self.enemies: - # TODO: Check if a bullet hit a mob. - pass + if b.x in range(e.x, e.x+9) and b.y in range(e.y, e.y+9): + e.alive = False for e in self.enemies: - # TODO: Check if a mob hit the player. - pass + if e.alive: + if e.x in range(p.x, p.x+9) and e.y in range(p.y, p.y+9): + p.alive = False if not self.check_anyone_alive(): self.lost = True pyxel.playm(6) From 045a3b59442af617829ae9c993dcb8ab6b1fb514 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Thu, 30 Nov 2023 11:41:40 -0600 Subject: [PATCH 53/55] Set up some sounds in case you fail --- main.py | 1 + resource.pyxres | Bin 8419 -> 8710 bytes src/levels.py | 6 ++++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index 8372fc9..555cedf 100644 --- a/main.py +++ b/main.py @@ -25,6 +25,7 @@ def update(self): # If the situation "ends", jump into the next one # Also, keep memory of your player choice :) if self.situation.finished: + pyxel.camera(0, 0) tmp = self.situation.player_choice self.situation = init_class(stages_list[self.situation.next], tmp) del(tmp) # we have to remove 'tmp' ASAP diff --git a/resource.pyxres b/resource.pyxres index 7c4b785c7503eb0f4bbc3b522f40d44ad0724529..113d791ef828f08eaf7e7d5545fef79fcb493214 100644 GIT binary patch delta 243 zcmaFt*ygfoX#!H4JERXY^McJ~ zU|`S(VzJ2)@(Pn3B-j`&CtJ&FF~v$vR+JW-Tr025G!Mc&0A${WFqsv!nG~eK3fzFq zL=aPaa+iV@(_*lwm}!7FBaUutu1b(sUqleHD3CNnAsPre|{IyqKBo5=~tl@Xh~0LW~HFdqY% nM<7f!MQtWlX|RG!Ak!Vp6gLg Date: Thu, 30 Nov 2023 11:44:08 -0600 Subject: [PATCH 54/55] Remove a disturbing line For a strange reason, VSCode didn't allow me to do it locally. --- main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/main.py b/main.py index 555cedf..8372fc9 100644 --- a/main.py +++ b/main.py @@ -25,7 +25,6 @@ def update(self): # If the situation "ends", jump into the next one # Also, keep memory of your player choice :) if self.situation.finished: - pyxel.camera(0, 0) tmp = self.situation.player_choice self.situation = init_class(stages_list[self.situation.next], tmp) del(tmp) # we have to remove 'tmp' ASAP From d6bf95014163be912cdd7df3c788aaa31fc8e3a5 Mon Sep 17 00:00:00 2001 From: Diego Ramirez Date: Thu, 30 Nov 2023 12:09:26 -0600 Subject: [PATCH 55/55] Try out some level connecticity strategies --- src/baseclasses.py | 5 +++-- src/levels.py | 1 + src/menu.py | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/baseclasses.py b/src/baseclasses.py index 317b1ea..3e94345 100644 --- a/src/baseclasses.py +++ b/src/baseclasses.py @@ -24,9 +24,10 @@ class BaseLevel(ABC): scroll_x = 0 def __init__(self, player_choice): - # pyxel.camera() + pyxel.camera(0, self.draw_v) self.player_choice = player_choice self.create_characters() + self.spawn(0, 128) pyxel.playm(self.music_vol, loop=True) def startup(self): @@ -66,7 +67,7 @@ def create_characters(self): elif self.player_choice == 2: self.player = [Player1(0, 0), Player2(0, 10)] - def spawn(self): + def spawn(self, left_x, right_x): left_x = math.ceil(left_x / 8) right_x = math.floor(right_x / 8) for x in range(left_x, right_x + 1): diff --git a/src/levels.py b/src/levels.py index 1077076..b80fc49 100644 --- a/src/levels.py +++ b/src/levels.py @@ -14,6 +14,7 @@ class One(BaseLevel): easiest level in the game, so it doesn't contain a lot of enemies or tricky spots. """ + enemy_template = {(21*8, 8*8): Onion} def update(self): "Pyxel-like 'update' function." diff --git a/src/menu.py b/src/menu.py index 6611b9a..4f85d34 100644 --- a/src/menu.py +++ b/src/menu.py @@ -7,6 +7,7 @@ class Menu(BaseLevel): "Menu window." stage = "main" player_choice = 0 + enemy_template = dict() player_choice_text = {0: "[1] Single (Diddi)", 1: "[2] Single (Eli)", 2: "[3] Multiplayer"} music_vol = 5 @@ -43,6 +44,7 @@ def draw(self): "Pyxel-like 'draw' function." # Clear the screen pyxel.cls(0) + pyxel.camera(self.scroll_x, self.draw_v) # TODO: Is this a good idea? # NOTE: Tilemap 0 is the menu tilemap, ok? pyxel.bltm(0, 0, 0, 0, 0, 128, 128) # Draw a "menu window"