Python: Classes that "talk" to each other - python

I'm a college student. I'm in my second comp sci class and we haven't got much past simply making classes and functions within them so I haven't really been able to make much use of the complicated jargon I've found on the internet.
I'm making a roach infestation sim, and I need to be able to have a "roach" class be able to detect where a "food" class is in a window. My teacher told me that my best shot might be to make another mastermind-like class that is a middle man between the two, but I don't really know how that would work. Can anyone help me out? I'm using Python through Calico. Here's what I have of the roach class (EDIT: guess I should show the main() etc too):
class Roach:
def __init__(self, win, placex, placey):
self.timer = 320 + (10 *(int(10 *random.random())))
self.speed = 0.2
self.heading = 360
self.win = win
self.x = placex
self.y = placey
self.body = self.makeBody()
self.body.draw(self.win)
def __str__(self):
t = "Roach at ("+str(self.x)+","+str(self.y)+")"
return t
def makeBody(self):
body = Rectangle((-5,-5),(5,5))
body.setFill(Color('Brown'))
body.moveTo(self.x,self.y)
return body
def move(self, win):
self.x = self.x + self.speed *sin(self.heading)
self.y = self.y + self.speed *cos(self.heading)
self.body.moveTo(self.x,self.y)
self.avoid(win)
def avoid(self, win):
Border = False
if self.x >= win.getWidth():
self.setHeading(random.randrange(91, 269))
self.x = win.getWidth() - 1
Border = True
elif self.x <= 0:
self.setHeading(random.randrange(271, 449))
self.x = 1
Border = True
elif self.y >= win.getHeight():
self.setHeading(random.randrange(1, 179))
self.y = win.getHeight() - 1
Border = True
elif self.y <= 0:
self.setHeading(random.randrange(181, 359))
self.y = 1
Border = True
return Border
#Getters
def getSpeed(self):
return self.speed
def getHeading(self):
return self.heading
def getX(self):
return self.x
def getY(self):
return self.y
#Setters
def setSpeed(self, speed):
self.speed = speed
def setHeading(self, heading):
self.heading = heading
self.body.rotateTo(self.heading)
def setX(self, x):
self.x = x
def setY(self, y):
self.y = y
def main():
win = Window(400, 400)
win.setBackground(Color("White"))
Rpop = []
Wpop = []
i = 320
menu(win, Rpop, Wpop)
while getKeyPressed() != 'Escape':
for roach in Rpop:
if roach.avoid(win) == True:
roach.avoid(win)
elif i % roach.timer == 0:
roach.setHeading(360*random.random())
roach.move(win)
if getKeyPressed() == 'm':
menu(win, Rpop, Wpop)
i = i + 1
def menu(win, Rpop, Wpop):
while getKeyPressed() != 's':
if getKeyPressed() == 'r':
Rpop.append(Roach(win,getMouseNow()[0],getMouseNow()[1]))
if getKeyPressed() == 'w':
point1 = getMouse()
dot1 = Circle((point1[0],point1[1]), 3)
dot1.draw(win)
point2 = getMouse()
dot2 = Circle((point2[0],point2[1]), 3)
dot2.draw(win)
Wpop.append(Wall(win, point1[0], point1[1], point2[0], point2[1]))
return
main()
Sorry for the lack of comments and likely juvenile programming. Thank you so much.

Here's a sort of rough outline of how you might use an additional "Master" class to allow two other classes to communicate as is alluded to in the OP:
class Master():
...
def is_food_there(self, coords):
for food_instance in self.food_instances:
if coords == food_instance.coords:
return True
class Food():
def __init__(self, master_instance):
self.coords = ###some coordinates or whatever
master_instance.food_instances.append(self) ### register this food with master
class Roach():
def __init__(self, master_instance):
self.master_instance = master_instance
...
def move(self, newlocation):
if( self.master_instance.is_food_there(newlocation) ): ### check with master for food coords
###do something
The idea is that the we have a Master class which is essentially a container for a list of Food instances, and Roach class knows which Master instance it belongs to, so it can access that master's "is_food_there" function which in turn looks through the Food instances that belong to it. The Master class is "the man in the middle" in this example.

Related

TypeError: unbound method collide() must be called with Enemy instance as first argument (got type instance instead) in processing 3.5.4 [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I am getting this error whilst trying to add collision to a game and I have gotten this error for now all I want is for the game to print yes when the target is hit if there better way to detect collision I'm all ears. anything helps.
TypeError: unbound method collide() must be called with Enemy instance as first argument (got type instance instead)
This error comes from this code
Enemy.collide(Bullets)
this is the entire code ~200 lines
import math
class Spacey(object):
def __init__(self,x,y,siz,col):
self.x = x
self.y = y
self.siz = siz
self.col = col
self.body_angle = -90
self.enabled = True
def see(self):
self.move()
self.render()
def show(self):
stroke(250)
point(self.x,self.y)
def move(self):
if(keyPressed and key == CODED):
if(keyCode == LEFT):
self.x += (sin(radians(self.body_angle))*2)
if(keyCode == RIGHT):
self.x -= (sin(radians(self.body_angle))*2)
if(keyCode == UP):
self.y += (sin(radians(self.body_angle))*2)
if(keyCode == DOWN):
self.y -= (sin(radians(self.body_angle))*2)
if(keyCode == SHIFT and self.enabled):
bullet_repeat = Bullets(self.x,self.y,5,stroke(113,195,0))
bullet.append(bullet_repeat)
self.enabled = False
else:
self.enabled = True
def render(self):
pushMatrix()
translate(self.x,self.y)
stroke(113,195,0)
strokeWeight(3)
fill(177,255,72)
beginShape()
vertex(self.x,self.y-40)
vertex(self.x-40,self.y+40)
vertex(self.x+40,self.y+40)
vertex(self.x,self.y-40)
endShape()
popMatrix()
class Bullets(object):
def __init__ (self,x,y,siz,col):
self.x = x
self.y = y
self.startX = int(x)
self.startY = y
self.siz = int(siz)
self.col = col
self.sx = x
def sx():
return int(self.x)
def siza(self):
return int(self.siz)
def colo():
stroke(113,195,0)
def see(self):
self.move()
self.render()
self.sx()
def show(self):
stroke(250)
point(self.x,self.y)
def move(self):
self.y = self.y - 5
for bullets in bullet:
if ((self.x-self.startX)**2 + (self.y-self.startY)**2) > 1000000000:
bullet.remove(bullets)
def render(self):
pushMatrix()
translate(self.x,self.y)
stroke(113,195,0)
beginShape()
circle(self.x,self.y+10,5)
endShape(CLOSE)
popMatrix()
class Enemy(object):
def __init__(self,x,y,siz,col):
self.x = int(x)
self.y = y
self.speed = 2
self.health = 1000
self.siz = int(siz)
self.col = col
def see(self):
self.move()
self.render()
def move(self):
spd = 2
bts = True
for i in range(0, 2, 500):
self.x += 2
if self.x == 500:
self.x = 2
def health(self):
healthy = 20
if collide == True:
health -= 1
if healthy == 0:
next_level()
healthy += 100
def render(self):
pushMatrix()
translate(self.x,self.y)
stroke(113,195,0)
strokeWeight(3)
fill(177,255,72)
beginShape()
vertex(self.x,self.y-40)
vertex(self.x-40,self.y+40)
vertex(self.x+40,self.y+40)
vertex(self.x,self.y-40)
endShape()
popMatrix()
def collide(self,other):
if(self.x + self.siz / 2 >= Bullets.sx() - Bullets.siz / 2 and self.x - self.siz / 2 <= Bullets.sx() + Bullets.siz / 2
and self.y + self.siz / 2 >= Bullets.y - Bullets.siza / 2 and self.y - self.siz / 2 <= Bullets.y + Bullets.siza / 2):
print("YES")
def get_accuracy():
for i in bullet:
accuracy = hitcount / bcount
if accuracy >= 90:
return 'AMAZING'
if accuracy >= 50:
return 'GOOD'
if accuracy >= 10:
return 'OKAY'
if accuracy < 10:
print('NOT GOOD')
spacey = Spacey(250,400, 20,color(113,195,0))
enemy = Enemy(0,20,20,color(113,195,0))
bullet = []
collidesss = []
levels = [1,2,3,4,5,6,7]
def reset():
spacey = spacey(250,400)
enemy = enemy(0,20)
def setup():
size(1000,1000)
def draw():
global bcount, hitcount
background(0,14,47)
for bullet_repeat in bullet:
bullet_repeat.see()
spacey.see()
enemy.see()
for i in bullet:
Enemy.collide(Bullets)
hitcount = 0
bcount = 0
for bullet_repeat in bullet:
bcount += 1
fill(255)
textSize(30)
text(bcount,920,950,)
text('Bullets shot:',730,950,)
This is now edited from the original
The code
for i in bullet:
Enemy.collide(Bullets)
should be
for i in bullet:
enemy.collide(Bullets)
Enemy is the class, enemy is an instance of the class.
In Python, class names are conventionally written with capital first letter, whereas instances/variables are written with lower case first letters.

Remove object particle with kivy condition

What I want is two things:
count the number of enemies on the screen. And remove all enemies from the screen with a contion.
The second chose is to allow enemies to shoot randomly
class Enemy(Particle):
active = False
tex_name = 'ufo'
v = 0
def reset(self, created=False):
self.active = False
self.x = -100
self.y = -100
self.v = 0
def advance(self, nap):
if self.active:
if self.check_hit():
self.reset()
return
self.x -= 200 * nap
if self.x < -50:
self.reset()
return
self.y += self.v * nap
if self.y <= 0:
self.v = abs(self.v)
elif self.y >= self.parent.height:
self.v = -abs(self.v)
elif self.parent.spawn_delay <= 0:
self.active = True
self.x = self.parent.width + 50
self.y = self.parent.height * random()
self.v = randint(-100, 100)
self.parent.spawn_delay += 1
def check_hit(self):
if math.hypot(self.parent.player_x - self.x,
self.parent.player_y - self.y) < 60:
return True
for b in self.parent.bullets:
if not b.active:
continue
if math.hypot(b.x - self.x, b.y - self.y) < 30:
b.reset()
return True
What I want is two things:
count the number of enemies on the screen. And remove all enemies from the screen with a contion.
The second chose is to allow enemies to shoot randomly
You can accomplish the first two of your questions by modifying the PSWidget class. By adding two attributes enemy_count and killall to the class:
class PSWidget(Widget):
indices = []
vertices = []
particles = []
enemy_count = 0
killall = False
And using those attributes in the update_glsl() method:
def update_glsl(self, nap):
self.enemy_count = 0 # initialize enemy count
for p in self.particles:
if isinstance(p, Enemy) and p.active:
if self.killall:
p.reset() # kill this enemy
else:
self.enemy_count += 1 # increment enemy count
p.advance(nap)
p.update()
self.canvas.clear()
with self.canvas:
Mesh(fmt=self.vfmt, mode='triangles',
indices=self.indices, vertices=self.vertices,
texture=self.texture)
# reset killall
self.killall = False
So, anytime you want the count of active enemies, just use the enemy_count attribute of the PSWidget instance. And whenever you want to kill all the active enemies, just set the killall attribute of the PSWidget instance.
As far as your third question, show us your attempt at coding that.
If you are using an answer that I gave in another question, where I suggested using the on_enter() method to start the game updates, then you can use on_leave() to stop the updates. The game movements are faster every time you enter MainScreen because more updates are scheduled on each entry. Here is a modified MainScreen that handles that handles that issue:
class MainScreen(Screen):
started = BooleanProperty(False)
def on_enter(self, *args):
if not self.started:
self.ids.game.initialize()
self.started = True
self.update_event = Clock.schedule_interval(self.ids.game.update_glsl, 1.0/60.0)
def on_leave(self, *args):
if self.update_event is not None:
self.update_event.cancel()

Flickering command prompt screen while making a text based game in python

I am making a text based game and i tried to implement a basic game loop where the map is just being drawn and cleared. However the result is just a flickering mess. When i read through articles about how frames per seocond work, they just say that its how often the computer blits new frames in a second. Now what i dont understand is how do actual game game-libraries like pygame achieve this, while my game running on terminal cannot. This is that my loop looks like:
while True:
game_map.draw()
os.system("cls")
I am certain that python is able to go through this loop enough times so that the flickering is not noticeable. Is there some kind of a limit to refresh rate in command promt? And is there a way to fix this? Thanks in advance. The following is the code i have so far in case there might be something relevant to the question.
import os
import keyboard
class Map:
def __init__(self):
self.map = [[" " for i in range(34)]for i in range(40)]
def update(self, thing, x, y):
self.map[y][x] = thing
def draw(self):
for layer in self.map:
print(layer)
game_map = Map()
class Player:
def __init__(self):
self.x = 1
self.y = 38
self.player = input("Enter your nickname: ").upper()
try:
self.player = self.player[0]
except:
pass
def draw(self):
game_map.update(self.player, self.x, self.y)
def move(self):
if keyboard.is_pressed("RIGHT"):
self.x += 1
game_map.map[self.y][self.x - 1] = " "
if keyboard.is_pressed("LEFT"):
self.x -= 1
game_map.map[self.y][self.x + 1] = " "
if keyboard.is_pressed("UP"):
self.y -= 1
game_map.map[self.y + 1][self.x] = " "
if keyboard.is_pressed("DOWN"):
self.y += 1
game_map.map[self.y - 1][self.x] = " "
def boundries(self):
if self.x >= 33:
self.x = 33
if self.x <= 0:
self.x = 0
if self.y <= 38:
self.y = 38
if self.y >= 39:
self.y = 38
player = Player()
class Bullet:
def __init__(self):
self.x = player.x
self.y = player.y
self.bullet = "*"
class Game:
def __init__(self):
self.bullets = []
def generate_bullet(self):
if keyboard.is_pressed("w"):
self.bullets.append(Bullet())
def shoot(self):
if self.bullets:
for bullet in game.bullets:
game_map.map[bullet.y - 1][bullet.x] = bullet.bullet
game_map.map[bullet.y + 1][bullet.x] = " "
bullet.y -= 1
if bullet.y <= 1:
game_map.map[1][bullet.x] = " "
game_map.map[0][bullet.x] = " "
def bullet_boundries(self):
for b in self.bullets:
if b.x >= 33:
self.bullets.remove(b)
if b.x <= 0:
self.bullets.remove(b)
if b.y <= 0:
self.bullets.remove(b)
if b.y >= 39:
self.bullets.remove(b)
game = Game()
while True:
game_map.draw()
os.system("cls")
player.draw()
player.move()
player.boundries()
game.generate_bullet()
game.shoot()
game.bullet_boundries()

Python turtle class compute length

I am making some kind of a ripoff of turtle module for drawing.
This is what i have so far:
class Turtle:
def __init__(self):
self.x = drawer.maxX / 2
self.y = drawer.maxY / 2
self.angle = 0
self.pen_active = True
self.pause = 0
self.body = drawer.circle(0, 0, 5, drawer.green, 3)
self.head = drawer.circle(0, 0, 3, drawer.green, 3)
self.length = 0
self.update()
def set_pause(self, n):
self.pause = n
def no_pause(self):
self.set_pause(0)
def hide(self):
self.body.hide()
self.head.hide()
def show(self):
self.body.show()
self.head.show()
def update(self):
self.body.setPos(self.x, self.y)
phi = radians(90 - self.angle)
self.head.setPos(self.x + 5 * cos(phi), self.y + 5 * sin(phi))
drawer.wait(self.pause)
def pen_up(self):
self.pen_active = False
def pen_down(self):
self.pen_active = True
def fly(self, x, y, angle):
self.x = x
self.y = y
self.angle = angle
self.update()
def forward(self, a):
phi = radians(90 - self.angle)
nx = self.x + a * cos(phi)
ny = self.y + a * sin(phi)
if self.pen_active:
drawer.line(self.x, self.y, nx, ny)
self.x = nx
self.y = ny
self.update()
def backward(self, a):
self.forward(-a)
def turn(self, phi):
self.angle += phi
self.update()
def left(self):
self.turn(-90)
def right(self):
self.turn(90)
def length(self):
pass
Now i am trying to write a method to compute the length of the line drawn but i don't know how to do it. The line is drawn when the pen is down and the turtle is going forwards or backwards. If the turtle flys or turns around the line is not drawn. Any ideas.
And thank your for all your help.
If I understand correctly, you want to maintain a record of the length of all the forward and backward movements your Turtle makes from the time it is created.
This is pretty easy, you just need to be a bit careful with your variable names. Currently you're using length both as an instance variable (to hold the running length sum) and as a method name. The former will shadow the latter, so you probably want two different names.
If we rename the instance variable to _length, you can make it work like this:
class Turtle:
def __init__(self):
# unmodified stuff omitted
self._length = 0
# unmodified methods skipped
def forward(self, a):
# all the current stuff
self._length += abs(a) # absolute value to count backing up as movement
def length():
return self._length
You may decide you don't need the trivial length method, in which case you can go back to using self.length as your instance variable name (and just access the attribute when you want the value).

Python object orientated not changing values in init function

Hi I'm in the process of making a game and I've hit a stumbling block this is part of my code below:
class player(object):
def __init__(self):
self.x = 10
self.y = 10
self.amount = 5
self.answer = 0
def move(self):
self.x += self.amount
self.y += self.amount
while True:
player().move()
print player().x
Its probably a really basic mistake but whatever the move() function does it doesn't ever seem to change value of self.x or self.y can someone poke me in the right direction please! Thanks, I realise I'm probably missing something very basic, I don't have much experience with OO
player().move() # create a player and move it
print player().x # create another player and print its x
What you meant is:
aplayer = player()
aplayer.move()
print aplayer.x
PS: The common practice is to capitalize class names:
class Player(object):
def __init__(self):
self.x = 10
self.y = 10
self.amount = 5
self.answer = 0
def move(self):
self.x += self.amount
self.y += self.amount
player = Player()
player.move()
print player.x
This way it's easy to differentiate between classes and objects.
Ok. what the other person said is that you need to set the "Player" as a variable such as George, then call George.move()
so
class Player(object):
def __init__(self):
self.x = 10
self.y = 10
self.amount = 5
self.answer = 0
def move(self):
self.x += self.amount
self.y += self.amount
While True:
george = Player()
george.move()
print george.x
that should work. and you can change "george" to anything you want, just make sure it is consistent.

Categories

Resources