Logika mapek w grze cRPG Django/Python
Prace nad "Wyspą Mrozu" posuwają się do przodu. Obecnie implementuję poszczególne elementy mapy, po której porusza się postać. System zakłada wykorzystanie mini-map podzielonych na kwadratowe klocki (tile) we współrzędnych x,y...
Oto przykład mapy z naniesioną siatką:
class BigTile(models.Model):
"""
Model minimap złożonych z tilów
"""
name = models.CharField(max_length=255, verbose_name='Nazwa')
img = models.ImageField(upload_to='ice/bigtiles/', verbose_name='Grafika')
size = models.IntegerField(default=100, verbose_name='Rozmiar Klocka')
movable_tiles = models.TextField(verbose_name=u'Obszary Ruchu')
entry_tiles = models.TextField(verbose_name=u'Obszary Wejścia/Wyjścia')
spawn_tiles = models.TextField(blank=True, verbose_name=u'Obszary Spawnowania')
action_tiles = models.TextField(blank=True, verbose_name=u'Obszary Zdarzeń')
char_locations = models.TextField(blank=True, verbose_name=u'Lokacje NPC')
class Meta:
verbose_name = u'BigTile'
verbose_name_plural = u'8. BigTile'
db_table = 'ice_bigtile'
def __str__(self):
return self.name
def __unicode__(self):
return self.name
class BigTileCopy(models.Model):
"""
Model kopii minimap dla danego usera/questa
"""
mapa = models.ForeignKey(BigTile, verbose_name=u'Mapa rodzic')
movable_tiles = models.TextField(verbose_name=u'Obszary Ruchu')
entry_tiles = models.TextField(verbose_name=u'Obszary Wejścia/Wyjścia')
spawn_tiles = models.TextField(blank=True, verbose_name=u'Obszary Spawnowania')
action_tiles = models.TextField(blank=True, verbose_name=u'Obszary Zdarzeń')
char_locations = models.TextField(blank=True, verbose_name=u'Lokacje postaci i przeciwników')
class Meta:
verbose_name = u'BigTile Kopia'
verbose_name_plural = u'9a. BigTile Kopie'
db_table = 'ice_bigtilecopy'
def __str__(self):
return str(self.mapa)
def __unicode__(self):
return unicode(self.mapa)
class QuestCopy(models.Model):
"""
Model kopii questu dla danego usera
"""
quest = models.ForeignKey(Quest, verbose_name=u'Quest')
char = models.ForeignKey(Character, verbose_name=u'Postać')
maps = models.ManyToManyField(BigTileCopy, verbose_name='Mapy/Stan dla usera', related_name='maps')
current_map = models.ForeignKey(BigTileCopy, verbose_name=u'Obecna mapa', related_name='current_map')
class Meta:
verbose_name = u'Quest'
verbose_name_plural = u'9b. Questy Kopie'
db_table = 'ice_questcopy'
def __str__(self):
return str(self.quest)
def __unicode__(self):
return unicode(self.quest)
{"1": ["3,0", "4,0", "2,1", "3,1", "4,1", "2,2", "3,2", "4,2", "5,2", "2,3", "3,3", "4,3", "5,3", "6,3", "2,4", "3,4", "4,4", "5,4", "2,5", "3,5", "4,5", "5,5"]}
Przykładowo mając pośrodku mapy zamknięte drzwi - po jednej stronie byłby jeden obszar ruchu, a po drugiej stronie - drugi. Postać może poruszać się tylko w obrębie własnego obszaru ruchu. Po otworzeniu drzwi pola z drugiego obszaru zostałyby dołączone do pierwszego i postać mogłaby przejść dalej (Modele-kopie umożliwiają tu bezproblemową edycję JSONów dla danego questu/gracza).
Podobnie to wygląda dla innych pól, ale o tym później. Poruszanie zrobione jest w dość prosty sposób. Mapa wyświetlana jest jako tło diva. Natomiast postacie i inne elementy orientowane są w przestrzeni DIVa za pomocą absolutnej pozycji. Lokacja 3,0 odpowiada left/top 3*rozmiar tila,0*rozmiar tila. Wokół postaci (sąsiadujące tile) rysowane są przeźroczyste grafiki z zielonym obramowaniem oznaczające pola na jakie postać może przejść (uwzględniając czy współrzędne są w obszarze ruchu). Kliknięcie w takie pole wysyła żądanie AJAXem do Django w celu zwalidowania ruchu i zmiany pozycji postaci. Zwracane są nowe grafiki i koordynaty dla awatara postaci i umieszczane w tym DIVie:
<div style="background-image:url(/site_media/ice/bigtiles/room_.png); background-repeat:no-repeat;width:576px;height:576px;position:relative;" id="map">
<img src="/site_media/ice/good.png" class="good" alt="2,3" style="position:absolute;left:144px;top:216px;" />
<img src="/site_media/ice/good.png" class="good" alt="3,3" style="position:absolute;left:216px;top:216px;" />
<img src="/site_media/ice/good.png" class="good" alt="3,4" style="position:absolute;left:216px;top:288px;" />
<img src="/site_media/ice/good.png" class="good" alt="3,5" style="position:absolute;left:216px;top:360px;" />
<img src="/site_media/ice/good.png" class="good" alt="2,5" style="position:absolute;left:144px;top:360px;" />
<img src="/site_media/ice/action.png" title="Skrzynia" alt="1" style="position:absolute;left:72px;top:288px;" class="action" />
<img src="/site_media/ice/token4.png" title="Czesiek" alt="Czesiek" style="position:absolute;left:149px;top:296px;" />
<img src="/site_media/ice/token3.png" title="Ubogi rozbójnik" alt="Ubogi rozbójnik" style="position:absolute;left:365px;top:368px;" />
</div>

$(document).ready(function(){
// Update character position
$(".good").live("click", function(){
$.ajax({
url: "/ice/qmap_update/{{ qc.id }}/?move_on="+this.alt,
cache: false,
success: function(html){
$("#map").html(html);
}
});
});
// Show action tile content
$(".action").live("click", function(){
$.ajax({
url: "/ice/qmap_update/{{ qc.id }}/?action_on="+this.alt,
cache: false,
success: function(html){
// tutaj ladnie to trzeba będzie wyświetlić...
// $("#map").html(html);
alert(html);
}
});
});
});
Comment article