def testBasic(self): sp1 = scene.Sphere((123456, 123456, 123456), 90000) sp2 = scene.Sphere((234567, 234567, 234567), 90000) self.tree.insert(sp1, 0) self.tree.insert(sp2, 1) sp3 = scene.Sphere((179011, 179011, 179011), 10000) self.assertEqual(self.tree.intersect(sp3, True), []) tmpResult = self.tree.intersect(sp3, False) tmpResult.sort() self.assertEqual(tmpResult, [0, 1]) self.tree.delete(0) self.assertEqual(self.tree.intersect(sp3, False), [1])
def testAgainstNaiveImpl(self): number = 100 sqr = lambda x: x * x rand = myrand.MyRand() sp = [] for i in range(number): sp.append(scene.Sphere( (rand.rand() % 800000 + 100000, rand.rand() % 800000 + 100000, rand.rand() % 800000 + 100000), rand.rand() % 100000)) self.tree.insert(sp[i], i) for i in range(number): temp = [] for j in range(number): if sqr(sp[i].center[0] - sp[j].center[0]) + sqr(sp[i].center[1] - sp[j].center[1]) + sqr( sp[i].center[2] - sp[j].center[2]) < sqr(sp[i].radius): temp.append(j) treeResult = self.tree.intersect(sp[i], True) treeResult.sort() self.assertEqual(treeResult, temp) temp = [] for j in range(number): if sqr(sp[i].center[0] - sp[j].center[0]) + sqr(sp[i].center[1] - sp[j].center[1]) + sqr( sp[i].center[2] - sp[j].center[2]) < sqr(sp[i].radius + sp[j].radius): temp.append(j) treeResult = self.tree.intersect(sp[i], False) treeResult.sort() self.assertEqual(treeResult, temp)
def addNewPlayer(self, playerId: int, aiId: int, pos: tuple, radius: int): sphere = scene.Sphere(pos, radius) self._scene.insert(sphere, playerId) newStatus = PlayerStatus() newStatus.health = int((radius / 100)**3) newStatus.maxHealth = newStatus.health newStatus.aiId = aiId self._players[playerId] = newStatus
def playerMove(self, playerId: int): oldPos = self._scene.getObject(playerId).center r = self._scene.getObject(playerId).radius speed = self._players[playerId].speed newPos = tuple(oldPos[i] + speed[i] for i in range(3)) if self.outsideMap(newPos, r): newPos2 = list(newPos) for i in range(3): if newPos2[i] + r > self._mapSize: newPos2[i] = self._mapSize - r elif newPos[i] - r < 0: newPos2[i] = r newPos = tuple(newPos2) newSphere = scene.Sphere(newPos, r) self._scene.modify(newSphere, playerId) self._changeList.append( self.makeChangeJson(playerId, self._players[playerId].aiId, newSphere.center, newSphere.radius))
def healthChange(self, playerId: int, delta: int): player = self._players.get(playerId) if player is None: return if player.death: return player.healthChange(delta) if delta < 0: self._damage -= delta newHealth = player.health if newHealth < player.maxHealth // 4: self.playerDie(playerId) else: newRadius = (newHealth**(1 / 3)) * 100 newSphere = scene.Sphere( self._scene.getObject(playerId).center, newRadius) self._scene.modify(newSphere, playerId) self._changedPlayer.add(playerId)
def nutrientMove(self, playerId: int): if playerId == 0: return sphere = self._scene.getObject(playerId) if self._players[0].death == False: bosssphere = self._scene.getObject(0) pos = tuple( self._rand.randIn(self._mapSize - 2 * sphere.radius) + sphere.radius for _ in range(3)) if self._players[0].death == False: while self.dis(pos, bosssphere.center) < bosssphere.radius: pos = tuple( self._rand.randIn(self._mapSize - 2 * sphere.radius) + sphere.radius for _ in range(3)) newSphere = scene.Sphere(pos, sphere.radius) self._scene.modify(newSphere, playerId) self._players[playerId].nutrientMove = 2 self._players[playerId].tnutrientMove = 6 self._changeList.append( self.makeChangeJson(playerId, self._players[playerId].aiId, pos, newSphere.radius, 1))
def shortAttackDone(self, playerId: int): player = self._players.get(playerId) if player is None: return if player.death: player.shortAttackCasting = -1 return if player.shortAttackCasting != 0: return skillLevel = self._players[playerId].skillsLV['shortAttack'] damage = 500 + 200 * (skillLevel - 1) if 1 < skillLevel < 5: damage += 100 attackRange = 1100 + 300 * skillLevel if skillLevel == 5: attackRange -= 100 # 创建虚拟球体,找到所有受到影响的物体。受到影响的判定为:相交 virtualSphere = scene.Sphere( self.getCenter(playerId), attackRange + self._scene.getObject(playerId).radius) for objId in self._scene.intersect(virtualSphere): if self._players.get(objId) is not None and objId != playerId: newdamage = damage if player.dashTime != 0: newdamage *= (1 + (player.skillsLV["dash"] + 2) * 0.1 + 0.05) if self._players[objId].shieldLevel >= 5: newdamage *= 0.7 elif self._players[objId].shieldTime != 0: newdamage *= (self._players[objId].skillsLV['shield'] + 2) newdamage /= 10 self.healthChange(objId, -newdamage) self._changeList.append( self.makeSkillHitJson('shortAttack', playerId, objId)) if skillLevel == 5: # self._players[playerId].shieldTime = 30 self._players[playerId].shieldLevel = 35 self._changeList.append(self.makeSkillCastJson(playerId, 'shield')) player.shortAttackCasting = -1
def getFieldJson(self, aiId: int): def makeObjectJson(objId, aiId, objType, pos, r, longAttackCasting=-1, shortAttackCasting=-1, shieldTime=-1): return '{"id":%d,"ai_id":%d,"type":"%s","pos":[%.10f,%.10f,%.10f],"r":%.10f,"longattackcasting":%d,"shortattackcasting":%d,"shieldtime":%d}' \ % (objId, aiId, objType, pos[0], pos[1], pos[2], r, longAttackCasting,shortAttackCasting, shieldTime) objectDict = {} if aiId == -1: for playerId in self._players: if self._players[playerId].death: continue sphere = self._scene.getObject(playerId) objectDict[playerId] = \ makeObjectJson(playerId, self._players[playerId].aiId, "player", sphere.center, sphere.radius, self._players[playerId].longAttackCasting, self._players[playerId].shortAttackCasting,self._players[playerId].shieldTime) for objectId in self._objects: status = self._objects[objectId] sphere = self._scene._objs[objectId] objectDict[objectId] = makeObjectJson(objectId, -2, status.type, sphere.center, sphere.radius) # 规定营养产生处的ID为4000000+i,该ID暂无意义 for i, pos in enumerate(self._nutrientFlushPos): nutrientId = 4000000 + i objectDict[nutrientId] = makeObjectJson( nutrientId, -2, 'source', pos, 0) else: visionSpheres = [ scene.Sphere( self._scene.getObject(playerId).center, self._players[playerId].vision + self._scene.getObject(playerId).radius) for playerId in self._players.keys() if self._players[playerId].aiId == aiId and self._players[playerId].death == False ] visibleLists = [ self._scene.intersect(vs, False) for vs in visionSpheres ] for objectId in [i for ls in visibleLists for i in ls]: if objectDict.get(objectId) is not None: continue sphere = self._scene._objs[objectId] if self._players.get(objectId) is not None: objectDict[objectId] = \ makeObjectJson(objectId, self._players[objectId].aiId, 'player', sphere.center, sphere.radius, self._players[objectId].longAttackCasting, self._players[objectId].shortAttackCasting,self._players[objectId].shieldTime) else: objType = self._objects.get(objectId).type objectDict[objectId] = makeObjectJson( objectId, -2, objType, sphere.center, sphere.radius) for i, pos in enumerate(self._nutrientFlushPos): if any( sum((vs.center[i] - pos[i])**2 for i in range(3)) < vs.radius**2 for vs in visionSpheres): nutrientId = 4000000 + i objectDict[nutrientId] = makeObjectJson( nutrientId, -2, 'source', pos, 0) return '{"ai_id":%d,"objects":[%s]}' % (aiId, ','.join( objectDict.values()))
def update(self): # 初始化返回给平台的变化信息的json List self._changeList = [] self._changedPlayer = set() if self._time == 5000: tempId = 0 tempMax = 0 for playerId in self._players: if self._players[playerId].aiId == -2: continue if self._players[playerId].health > tempMax: tempMax = self._players[playerId].health tempId = self._players[playerId].aiId self.gameEnd(tempId, 1) # 1、结算技能效果 for playerId in self._rand.shuffle(list(self._castSkills.keys())): if self._gameEnd: break if self._players.get(playerId) is None: continue if self._players[playerId].death: continue skillInfo = self._castSkills[playerId] skillName = skillInfo.name if skillName == 'shortAttack': self.shortAttackSet(playerId) elif skillName == 'longAttack': self.longAttackSet(playerId, skillInfo.player) elif skillName == 'dash': self.dash(playerId) elif skillName == 'shield': self.shield(playerId) elif skillName == 'visionUp': self.visionUp(playerId) elif skillName == 'healthUp': self.healthUp(playerId) for playerId, player in self._players.items(): if self._gameEnd: break if player.death: continue # 远程攻击蓄力到时间后结算远程攻击效果 if player.longAttackCasting == 0: self.longAttackDone(playerId) # 近程攻击蓄力到时间后结算远程攻击效果 if player.shortAttackCasting == 0: self.shortAttackDone(playerId) # 冲刺状态时间到后恢复原始速度 if player.dashTime == 0: player.speedLimit = 100 self._castSkills.clear() # 2、移动所有物体(包括玩家,远程子弹,目标生物) for playerId, player in self._players.items(): if self._gameEnd: break if player.death: continue if playerId == 0: player.speed = tuple( (self._rand.randIn(20 * 1000000) / 1000000) - 10 + self._players[1].speed[x] / 2 + self._players[2].speed[x] / 2 for x in range(3)) if player.stopTime == 0: self.playerMove(playerId) # 3、判断相交,结算吃、碰撞、被击中等各种效果 for playerId in self._rand.shuffle(list(self._players.keys())): if self._gameEnd: break player = self._players.get(playerId) if player is None: continue if player.death: continue sphere = self._scene.getObject(playerId) # 玩家(包括目标生物)可食用的物体对其产生效果,包括食用食饵、营养源、目标生物、以及其他玩家AI insideList = self._scene.intersect(sphere, True) eatableList = [ objId for objId in insideList if 1.2 * self._scene._objs[objId].radius < sphere.radius ] for eatenId in eatableList: eatenPlayer = self._players.get(eatenId) if eatenPlayer is not None: if (eatenPlayer.shieldTime == 0 or eatenPlayer.skillsLV["shield"] < 4 ) and eatenPlayer.shieldLevel < 5: #self.healthChange(playerId, eatenPlayer.health // 2) #self.healthChange(eatenId, -eatenPlayer.health) self._changeList.append(self.makeDeleteJson(eatenId)) if player.aiId == -2: self.gameEnd(1 - eatenPlayer.aiId, 2) else: self.gameEnd(self._players[playerId].aiId, 3) continue objType = self._objects[eatenId].type if objType == "food": self._changeList.append(self.makeDeleteJson(eatenId)) self.healthChange(playerId, 40) self.objectDelete(eatenId) self._foodCount -= 1 elif objType == "nutrient": self._changeList.append(self.makeDeleteJson(eatenId)) player.ability += 5 self.nutrientMove(playerId) self.objectDelete(eatenId) if playerId == 0: continue # 玩家接触到的物体对其产生效果,包括受到刺球伤害及子弹伤害 touchList = self._scene.intersect(sphere, False) for touchedId in touchList: if self._players.get(touchedId) is not None: continue objType = self._objects[touchedId].type if objType == "spike": if self._players[playerId].tnutrientMove > 0: self.objectDelete(touchedId) continue if (self._players[playerId].shieldTime == 0 or self._players[playerId].skillsLV["shield"] < 5 ) and self._players[playerId].shieldLevel < 5: damage = self._players[playerId].health // 3 if damage > 2000: damage = 2000 self.healthChange(playerId, -damage) self.objectDelete(touchedId) # 4、随机产生新的食物等,暂且每回合1个食饵,且上限为1000个。每隔100-110回合刷新一个营养源; # 食饵ID为1000000+食物编号, 营养源ID为2000000+营养源位置编号 if self._time == 0: foodPerTick = 150 else: foodPerTick = 10 for _ in range(foodPerTick): if self._gameEnd: break if self._foodCount > 300: break center = tuple(self._rand.randIn(self._mapSize) for _ in range(3)) food = scene.Sphere(center) foodId = 1000000 + self._foodCountAll self._objects[foodId] = ObjectStatus("food") self._scene.insert(food, foodId) self._foodCountAll += 1 self._changeList.append(self.makeChangeJson(foodId, -2, center, 0)) center2 = tuple(self._mapSize - x for x in center) food = scene.Sphere(center2) foodId = 1000000 + self._foodCountAll self._objects[foodId] = ObjectStatus("food") self._scene.insert(food, foodId) self._foodCountAll += 1 self._foodCount += 2 self._changeList.append(self.makeChangeJson( foodId, -2, center2, 0)) spikenum = 0 if self._time % 10 == 0: spikenum += 1 for _ in range(spikenum): if self._gameEnd: break if self._spikeCount >= 50: break center = tuple(self._rand.randIn(self._mapSize) for _ in range(3)) while self.inplayer(center): center = tuple( self._rand.randIn(self._mapSize) for _ in range(3)) spike = scene.Sphere(center) spikeId = 2001000 + self._spikeCountAll self._objects[spikeId] = ObjectStatus("spike") self._scene.insert(spike, spikeId) self._spikeCountAll += 1 self._spikeCount += 1 self._changeList.append(self.makeChangeJson( spikeId, -2, center, 0)) if self._nutrientFlushTime == 0: pos = self._rand.randIn(len(self._nutrientFlushPos) >> 1) << 1 nutrientId1 = int(2000000 + pos) nutrientId2 = int(2000000 + pos + 1) time = 0 while (self._objects.get(nutrientId1) is not None) and (self._objects.get(nutrientId2) is not None): pos = self._rand.randIn(len(self._nutrientFlushPos) >> 1) << 1 nutrientId1 = int(2000000 + pos) nutrientId2 = int(2000000 + pos + 1) time += 1 if time > 10: break if time <= 10: if self._objects.get(nutrientId1) is None: nutrient = scene.Sphere(self._nutrientFlushPos[pos]) self._objects[nutrientId1] = ObjectStatus("nutrient") self._scene.insert(nutrient, nutrientId1) if self._objects.get(nutrientId2) is None: nutrient = scene.Sphere(self._nutrientFlushPos[pos + 1]) self._objects[nutrientId2] = ObjectStatus("nutrient") self._scene.insert(nutrient, nutrientId2) self._nutrientFlushTime = self._rand.randIn(100) + 10 else: self._nutrientFlushTime -= 1 # 5、时间+1 # 所有技能冷却时间 -1, 护盾持续时间 -1, 营养源刷新时间 -1, 瞬移发动后时间 +1 self._time += 1 for playerId, player in self._players.items(): if self._gameEnd: break if player.death: continue if player.shieldTime > 0: player.shieldTime -= 1 if player.skillsLV['shield'] > 2 and player.skillsLV[ 'healthUp'] == 5: self.healthChange(playerId, 5 * player.skillsLV['shield'] - 5) if player.shieldLevel > 0: player.shieldLevel -= 1 if player.stopTime > 0: player.stopTime -= 1 if player.longAttackCasting > 0: player.longAttackCasting -= 1 if player.shortAttackCasting > 0: player.shortAttackCasting -= 1 if player.dashTime > 0: player.dashTime -= 1 if player.nutrientMove > 0: player.nutrientMove -= 1 if player.tnutrientMove > 0: player.tnutrientMove -= 1 for skillName in self._players[playerId].skillsCD.keys(): if player.skillsCD[skillName] > 0: player.skillsCD[skillName] -= 1 for playerId in self._players: if self._players[playerId].death == False: # 确保只生成未死亡的玩家的变化信息 self._changeList.append(self.newMakePlayerJson(playerId)) #判断是否为测试赛 if self._gameType != 0: #测试赛1,如果选手移动则成功 if (self._gameType == 1): for playerId in self._players: if (self._players[playerId].aiId != 0): continue if self._players[playerId].speed != (0, 0, 0): self.testGameEnd(10) # 调用回调函数,向平台传回变化信息 self._callback("[" + ",".join(self._changeList) + "]")