Yesterday I had the amazing idea to create a game where you play as a ghost and you have to take over people’s bodies to solve puzzles. One of my problems is that I have no programming experience exept from what I learned from the forums and from little projects I made myself. I know it’s hard to make good games and that it takes a lot of time but I still want to give it a shot. Another problem is that for some reason when I put down multiple npc’s I can’t take over bodies or leave bodies. If you’re willing to share a solution, please don’t make it too complicated as I don’t want any code in my project that I don’t understand!
Here’s the code:
--# controls
controls = class()
function controls:init(x,y,subject,speed)
-- you can accept and set parameters here
self.x = x
self.y = y
self.moveleft=false
self.moveright=false
self.movedown=false
self.moveup=false
self.subject = subject
self.speed = speed
self.leftsize=50
self.rightsize=50
self.downsize=50
self.upsize=-50
end
function controls:draw()
-- Codea does not automatically call this method
sprite("Cargo Bot:Command Left", self.x-50, self.y,self.leftsize)
sprite("Cargo Bot:Command Right", self.x+50, self.y,self.rightsize)
sprite("Cargo Bot:Command Grab",self.x, self.y-50, self.downsize)
sprite("Cargo Bot:Command Grab", self.x, self.y+50, self.upsize)
if self.moveleft==true then
self.subject.x=self.subject.x-self.speed
self.leftsize=60
end
if self.moveright==true then
self.subject.x=self.subject.x+self.speed
self.rightsize=60
end
if self.movedown==true then
self.subject.y=self.subject.y-self.speed
self.downsize=60
end
if self.moveup==true then
self.subject.y=self.subject.y+self.speed
self.upsize=-60
end
if self.subject.x<=0 then
self.subject.x=0
end
if self.subject.x>=WIDTH then
self.subject.x=WIDTH
end
if self.subject.y<=0 then
self.subject.y=0
end
if self.subject.y>=HEIGHT then
self.subject.y=HEIGHT
end
end
function controls:touched(touch)
-- Codea does not automatically call this method
--dpad
if touch.x<=self.x-25 and touch.x>=self.x-75 and touch.y<=self.y+25 and touch.y>=self.y-25 then
self.moveleft=true
end
if touch.x<=self.x+75 and touch.x>=self.x+25 and touch.y<=self.y+25 and touch.y>=self.y-25 then
self.moveright=true
end
if touch.x<=self.x+25 and touch.x>=self.x-25 and touch.y<=self.y-25 and touch.y>=self.y-75 then
self.movedown=true
end
if touch.x<=self.x+25 and touch.x>=self.x-25 and touch.y<=self.y+75 and touch.y>=self.y+25 then
self.moveup=true
end
if touch.state==ENDED then
self.moveleft=false
self.moveright=false
self.movedown=false
self.moveup=false
self.leftsize=50
self.rightsize=50
self.downsize=50
self.upsize=-50
end
end
--# Ghost
Ghost = class()
function Ghost:init(x,y)
-- you can accept and set parameters here
self.x = x
self.y = y
self.tint = color(255, 255, 255, 152)
end
function Ghost:draw()
-- Codea does not automatically call this method
tint(self.tint)
sprite("Planet Cute:Character Boy",self.x,self.y)
noTint()
end
function Ghost:touched(touch)
-- Codea does not automatically call this method
end
--# Main
--Made by G_nex
displayMode(FULLSCREEN)
function setup()
ghost=Ghost(WIDTH/2, HEIGHT/2)
npc={}
npc[1]=NPC(600, 600,"Planet Cute:Character Pink Girl",ghost)
npc[2]=NPC(300, HEIGHT-300,"Planet Cute:Character Cat Girl",ghost)
npc[3]=NPC(800, 200, "Planet Cute:Character Horn Girl", ghost)
dpad=controls(150,150,ghost,5)
music("Game Music One:Nothingness",true)
end
function draw()
background(13, 210, 20, 255)
for i=1,#npc do
npc[i]:draw()
end
ghost:draw()
--dpad
dpad:draw()
end
function touched(touch)
--classes
dpad:touched(touch)
for i=1,#npc do
npc[i]:touched(touch)
end
end
--# NPC
NPC = class()
function NPC:init(x,y,img,aff)
-- you can accept and set parameters here
self.x = x
self.y = y
self.img = img
self.aff = aff
self.takeover=false
self.takenover=false
end
function NPC:draw()
-- Codea does not automatically call this method
sprite(self.img,self.x,self.y)
if self.aff.x<self.x+50 and self.aff.x>self.x-50 and self.aff.y<self.y+50 and self.aff.y>self.y-50 then
self.takeover=ask
else
self.takeover=false
end
if self.takeover==ask and dpad.subject==self.aff then
fill(255, 255, 255, 255)
rect(self.x+50, self.y, 150, 75)
fill(0, 0, 0, 255)
fontSize(20)
textWrapWidth(500)
font("Copperplate")
text("Take body?", self.x+125, self.y+37)
end
if self.takeover==ask and dpad.subject==self then
fill(255, 255, 255, 255)
rect(self.x-200, self.y, 150, 75)
fill(0, 0, 0, 255)
text("Leave body?", self.x-125, self.y+37)
end
if self.takenover==1 then
dpad.subject=self
end
if self.takenover==2 then
dpad.subject=self.aff
end
end
function NPC:touched(touch)
-- Codea does not automatically call this method
if self.takeover==ask and touch.x<=self.x+200 and touch.x>=self.x+50 and touch.y<=self.y+75 and touch.y>=self.y then
self.takenover=1
end
if self.takeover==ask and touch.x<=self.x-50 and touch.x>=self.x-200 and touch.y<=self.y+75 and touch.y>=self.y then
self.takenover=2
end
end
I know it’s kind of messy but I just found out how classes work so don’t expect me to write everything super short but if it would help someone, you can use it for your own projects.
By the way, the game works properly when there’s only one npc
It looks like you need to change takenover to self.takenover in th npc class init function. Right now their global variables so the program can’t tell which npc is taken over.
Thanks, I don’t know how I missed that though but now I’m having another problem ~X(
Well, I’ll try to fix it myself before I ask for help again.
I don’t like to ask it but could anyone help me with my other problem? Somehow the buttons act weird after 1 npc and I can’t figure out why it does that… I edited the code above with the updated version.
Don’t be afraid to help
(I really want to continue the game as soon as I can.)
@G_nex I know you’re in a hurry, so instead of trying to figure out why your code isn’t working, it was faster to write another version of what I think you’re doing to give you some other ideas. I didn’t go into the detail you did. When the ghost and other sprites overlap, I put some text (switch) at the top of the screen. Tap it once to switch which sprite will then move. Only the ghost can switch with another sprite.
displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_ANY)
function setup()
speed=2 -- speed to move
dirX=0 -- x direction
dirY=0 -- y direction
str=""
switch=false
spriteMode(CENTER)
tab={} -- table of sprites
-- x position, y position, sprite, ghost
tab[1]=xx(300,100,"Planet Cute:Star",true)
tab[2]=xx(500,200,"Planet Cute:Character Cat Girl",false)
tab[3]=xx(400,300,"Planet Cute:Character Horn Girl",false)
tab[4]=xx(500,400,"Planet Cute:Character Pink Girl",false)
tab[5]=xx(600,500,"Planet Cute:Character Princess Girl",false)
end
function draw()
background(40, 40, 50)
fill(255)
for a,b in pairs(tab) do -- draw sprites in table
b:draw()
end
-- movement arrows
sprite("Cargo Bot:Command Left",100,150)
sprite("Cargo Bot:Command Right",200,150)
sprite("Cargo Bot:Command Grab",150,200,-50)
sprite("Cargo Bot:Command Grab",150,100)
switch=false
text(str,WIDTH/2,HEIGHT-50)
str=""
end
function touched(t)
if t.state==BEGAN then
if t.x>75 and t.x<125 and t.y>125 and t.y<175 then
dirX=-speed -- move left
end
if t.x>175 and t.x<225 and t.y>125 and t.y<175 then
dirX=speed -- move right
end
if t.x>125 and t.x<175 and t.y>175 and t.y<225 then
dirY=speed -- move up
end
if t.x>125 and t.x<175 and t.y>75 and t.y<125 then
dirY=-speed -- move down
end
if t.y>HEIGHT-150 then -- switch bodies
switch=true
end
end
if t.state==ENDED then -- set x,y directions to 0
dirX=0
dirY=0
end
end
xx=class() -- no name class
function xx:init(x,y,sp,sel)
self.x=x -- current x position
self.y=y -- current y position
self.sp=sp -- sprite to draw
self.sel=sel -- which sprite is selected and moves
if sel then
self.ghost=true -- ghost sprite
else
self.ghost=false -- not ghost sprite
end
end
function xx:draw()
sprite(self.sp,self.x,self.y)
if self.sel then -- move selected sprite
self.x=self.x+dirX -- move in x direction
self.y=self.y+dirY -- move in y direction
end
if not self.ghost then -- check for overlap with ghost
if math.abs(tab[1].x-self.x)<25 and math.abs(tab[1].y-self.y)<25 then
str="switch bodies"
if switch then
if tab[1].sel then -- switch from ghost to sprite
tab[1].sel=false
self.sel=true
else
tab[1].sel=true -- switch from sprite to ghost
self.sel=false
end
end
end
end
end
@G_nex Make the change I show below in the function NPC:draw(). Also, you’re mixing values. Some places you set an initial value to false, then you set it later on to some number. Also, you use the variable “ask”, but it’s never set to anything, so it’s nil. You need to go thru your code and find those kind of things, or you’re going to have more trouble finding errors as the code gets bigger.
function NPC:draw()
...
...
if self.takenover==2 then
dpad.subject=self.aff
self.takenover=false -- add this line
end
@G_nex - what @dave1707 points out suggests that you may be rushing your code and writing too much at a time. This makes it very difficult to find errors.
Try making very small changes and testing them properly before carrying on. This is actually a lot quicker overall.
@Ignatz Making small changes also helps for debugging, sometimes I’ve written a lot of code and pressed the play button to find there’s an error in the ton of code I just wrote, and it tends to not tell me what line, or the line number can be incorrect.
@TheSkyCoder - yes, that’s exactly the point I was trying to make.
@dave1707 Thanks for helping’ I said from the beginning my code was messy, but for now I’ll take a break in writing new code and try to fix the current one.
@Ignatz @SkyTheCoder Thanks for the tip. These kind of small tips really make a big difference at the end.